LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3231 3918 82.5 %
Date: 2025-12-05 02:43:06 Functions: 306 337 90.8 %

          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 <type_traits>
      31             : 
      32             : #include "cpl_conv.h"
      33             : #include "cpl_error.h"
      34             : #include "cpl_float.h"
      35             : #include "cpl_progress.h"
      36             : #include "cpl_string.h"
      37             : #include "cpl_virtualmem.h"
      38             : #include "cpl_vsi.h"
      39             : #include "gdal.h"
      40             : #include "gdal_abstractbandblockcache.h"
      41             : #include "gdalantirecursion.h"
      42             : #include "gdal_rat.h"
      43             : #include "gdal_rasterband.h"
      44             : #include "gdal_priv_templates.hpp"
      45             : #include "gdal_interpolateatpoint.h"
      46             : #include "gdal_minmax_element.hpp"
      47             : #include "gdalmultidim_priv.h"
      48             : 
      49             : #if defined(__AVX2__) || defined(__FMA__)
      50             : #include <immintrin.h>
      51             : #endif
      52             : 
      53             : /************************************************************************/
      54             : /*                           GDALRasterBand()                           */
      55             : /************************************************************************/
      56             : 
      57             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      58             : 
      59     1572430 : GDALRasterBand::GDALRasterBand()
      60             :     : GDALRasterBand(
      61     1572430 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      62             : {
      63     1571800 : }
      64             : 
      65             : /** Constructor. Applications should never create GDALRasterBands directly.
      66             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      67             :  */
      68     1850070 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      69     1850070 :     : bForceCachedIO(bForceCachedIOIn)
      70             : 
      71             : {
      72     1849380 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                          ~GDALRasterBand()                           */
      76             : /************************************************************************/
      77             : 
      78             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      79             :     instead destroy the GDALDataset. */
      80             : 
      81     1850060 : GDALRasterBand::~GDALRasterBand()
      82             : 
      83             : {
      84     1850070 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      85             :     {
      86         501 :         if (poBandBlockCache)
      87         438 :             poBandBlockCache->DisableDirtyBlockWriting();
      88             :     }
      89     1850070 :     GDALRasterBand::FlushCache(true);
      90             : 
      91     1850070 :     delete poBandBlockCache;
      92             : 
      93     1850070 :     if (static_cast<GIntBig>(nBlockReads) >
      94     1850070 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
      95         229 :         nBand == 1 && poDS != nullptr)
      96             :     {
      97         338 :         CPLDebug(
      98             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
      99         169 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
     100         169 :             poDS->GetDescription());
     101             :     }
     102             : 
     103     1850070 :     InvalidateMaskBand();
     104     1850060 :     nBand = -nBand;
     105             : 
     106     1850060 :     delete m_poPointsCache;
     107     1850070 : }
     108             : 
     109             : /************************************************************************/
     110             : /*                              RasterIO()                              */
     111             : /************************************************************************/
     112             : 
     113             : /**
     114             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     115             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     116             :  *                                void * pData, int nBufXSize, int nBufYSize,
     117             :  *                                GDALDataType eBufType,
     118             :  *                                GSpacing nPixelSpace,
     119             :  *                                GSpacing nLineSpace,
     120             :  *                                GDALRasterIOExtraArg* psExtraArg )
     121             :  * \brief Read/write a region of image data for this band.
     122             :  *
     123             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     124             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     125             :  * automatically takes care of data type translation if the data type
     126             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     127             :  * The method also takes care of image decimation / replication if the
     128             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     129             :  * region being accessed (nXSize x nYSize).
     130             :  *
     131             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     132             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     133             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     134             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     135             :  * Or use nLineSpace and a possibly shifted pData value.
     136             :  *
     137             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     138             :  * writing from unusually organized buffers. This is primarily used
     139             :  * for buffers containing more than one bands raster data in interleaved
     140             :  * format.
     141             :  *
     142             :  * Some formats may efficiently implement decimation into a buffer by
     143             :  * reading from lower resolution overview images. The logic of the default
     144             :  * implementation in the base class GDALRasterBand is the following one. It
     145             :  * computes a target_downscaling_factor from the window of interest and buffer
     146             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     147             :  * It then walks through overviews and will select the first one whose
     148             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     149             :  *
     150             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     151             :  * The relationship between target_downscaling_factor and the select overview
     152             :  * level is the following one:
     153             :  *
     154             :  * target_downscaling_factor  | selected_overview
     155             :  * -------------------------  | -----------------
     156             :  * ]0,       2 / 1.2]         | full resolution band
     157             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     158             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     159             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     160             :  *
     161             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     162             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     163             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     164             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     165             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     166             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     167             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     168             :  *
     169             :  * For highest performance full resolution data access, read and write
     170             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     171             :  * ReadBlock() and WriteBlock() methods.
     172             :  *
     173             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     174             :  * functions.
     175             :  *
     176             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     177             :  * write a region of data.
     178             :  *
     179             :  * @param nXOff The pixel offset to the top left corner of the region
     180             :  * of the band to be accessed. This would be zero to start from the left side.
     181             :  *
     182             :  * @param nYOff The line offset to the top left corner of the region
     183             :  * of the band to be accessed. This would be zero to start from the top.
     184             :  *
     185             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     186             :  *
     187             :  * @param nYSize The height of the region of the band to be accessed in lines.
     188             :  *
     189             :  * @param pData The buffer into which the data should be read, or from which
     190             :  * it should be written. This buffer must contain at least nBufXSize *
     191             :  * nBufYSize words of type eBufType. It is organized in left to right,
     192             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     193             :  * and nLineSpace parameters.
     194             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     195             :  * temporarily modified during the execution of this method (and eventually
     196             :  * restored back to its original content), so it is not safe to use a buffer
     197             :  * stored in a read-only section of the calling program.
     198             :  *
     199             :  * @param nBufXSize the width of the buffer image into which the desired region
     200             :  * is to be read, or from which it is to be written.
     201             :  *
     202             :  * @param nBufYSize the height of the buffer image into which the desired region
     203             :  * is to be read, or from which it is to be written.
     204             :  *
     205             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     206             :  * pixel values will automatically be translated to/from the GDALRasterBand
     207             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     208             :  * to perform data type translation.
     209             :  *
     210             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     211             :  * pData to the start of the next pixel value within a scanline. If defaulted
     212             :  * (0) the size of the datatype eBufType is used.
     213             :  *
     214             :  * @param nLineSpace The byte offset from the start of one scanline in
     215             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     216             :  * eBufType * nBufXSize is used.
     217             :  *
     218             :  * @param psExtraArg Pointer to a GDALRasterIOExtraArg
     219             :  * structure with additional arguments to specify resampling and progress
     220             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     221             :  * configuration option can also be defined to override the default resampling
     222             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     223             :  *
     224             :  * @return CE_Failure if the access fails, otherwise CE_None.
     225             :  */
     226             : 
     227             : /**
     228             :  * \brief Read/write a region of image data for this band.
     229             :  *
     230             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     231             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     232             :  * automatically takes care of data type translation if the data type
     233             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     234             :  * The method also takes care of image decimation / replication if the
     235             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     236             :  * region being accessed (nXSize x nYSize).
     237             :  *
     238             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     239             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     240             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     241             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     242             :  * Or use nLineSpace and a possibly shifted pData value.
     243             :  *
     244             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     245             :  * writing from unusually organized buffers. This is primarily used
     246             :  * for buffers containing more than one bands raster data in interleaved
     247             :  * format.
     248             :  *
     249             :  * Some formats may efficiently implement decimation into a buffer by
     250             :  * reading from lower resolution overview images. The logic of the default
     251             :  * implementation in the base class GDALRasterBand is the following one. It
     252             :  * computes a target_downscaling_factor from the window of interest and buffer
     253             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     254             :  * It then walks through overviews and will select the first one whose
     255             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     256             :  *
     257             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     258             :  * The relationship between target_downscaling_factor and the select overview
     259             :  * level is the following one:
     260             :  *
     261             :  * target_downscaling_factor  | selected_overview
     262             :  * -------------------------  | -----------------
     263             :  * ]0,       2 / 1.2]         | full resolution band
     264             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     265             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     266             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     267             :  *
     268             :  * For highest performance full resolution data access, read and write
     269             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     270             :  * ReadBlock() and WriteBlock() methods.
     271             :  *
     272             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     273             :  * functions.
     274             :  *
     275             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     276             :  * more convenient to use for most common use cases.
     277             :  *
     278             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     279             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     280             :  * instance of this dataset) concurrently from several threads.
     281             :  *
     282             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     283             :  * write a region of data.
     284             :  *
     285             :  * @param nXOff The pixel offset to the top left corner of the region
     286             :  * of the band to be accessed. This would be zero to start from the left side.
     287             :  *
     288             :  * @param nYOff The line offset to the top left corner of the region
     289             :  * of the band to be accessed. This would be zero to start from the top.
     290             :  *
     291             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     292             :  *
     293             :  * @param nYSize The height of the region of the band to be accessed in lines.
     294             :  *
     295             :  * @param[in,out] pData The buffer into which the data should be read, or from
     296             :  * which it should be written. This buffer must contain at least nBufXSize *
     297             :  * nBufYSize words of type eBufType. It is organized in left to right,
     298             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     299             :  * and nLineSpace parameters.
     300             :  *
     301             :  * @param nBufXSize the width of the buffer image into which the desired region
     302             :  * is to be read, or from which it is to be written.
     303             :  *
     304             :  * @param nBufYSize the height of the buffer image into which the desired region
     305             :  * is to be read, or from which it is to be written.
     306             :  *
     307             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     308             :  * pixel values will automatically be translated to/from the GDALRasterBand
     309             :  * data type as needed.
     310             :  *
     311             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     312             :  * pData to the start of the next pixel value within a scanline. If defaulted
     313             :  * (0) the size of the datatype eBufType is used.
     314             :  *
     315             :  * @param nLineSpace The byte offset from the start of one scanline in
     316             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     317             :  * eBufType * nBufXSize is used.
     318             :  *
     319             :  * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
     320             :  * structure with additional arguments to specify resampling and progress
     321             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     322             :  * configuration option can also be defined to override the default resampling
     323             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     324             :  *
     325             :  * @return CE_Failure if the access fails, otherwise CE_None.
     326             :  *
     327             :  * @see GDALRasterBand::ReadRaster()
     328             :  */
     329             : 
     330     4405040 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     331             :                                 int nXSize, int nYSize, void *pData,
     332             :                                 int nBufXSize, int nBufYSize,
     333             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     334             :                                 GSpacing nLineSpace,
     335             :                                 GDALRasterIOExtraArg *psExtraArg)
     336             : 
     337             : {
     338             :     GDALRasterIOExtraArg sExtraArg;
     339     4405040 :     if (psExtraArg == nullptr)
     340             :     {
     341     3805440 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     342     3805440 :         psExtraArg = &sExtraArg;
     343             :     }
     344      599598 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
     345             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     346             :     {
     347           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     348             :                     "Unhandled version of GDALRasterIOExtraArg");
     349           0 :         return CE_Failure;
     350             :     }
     351             : 
     352     4405040 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     353             :                                        nBufYSize);
     354             : 
     355     4389350 :     if (CPL_UNLIKELY(nullptr == pData))
     356             :     {
     357           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     358             :                     "The buffer into which the data should be read is null");
     359           0 :         return CE_Failure;
     360             :     }
     361             : 
     362             :     /* -------------------------------------------------------------------- */
     363             :     /*      Some size values are "noop".  Lets just return to avoid         */
     364             :     /*      stressing lower level functions.                                */
     365             :     /* -------------------------------------------------------------------- */
     366     4389350 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     367             :                      nBufYSize < 1))
     368             :     {
     369           2 :         CPLDebug("GDAL",
     370             :                  "RasterIO() skipped for odd window or buffer size.\n"
     371             :                  "  Window = (%d,%d)x%dx%d\n"
     372             :                  "  Buffer = %dx%d\n",
     373             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     374             : 
     375           2 :         return CE_None;
     376             :     }
     377             : 
     378     4389340 :     if (eRWFlag == GF_Write)
     379             :     {
     380      365887 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     381             :         {
     382           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     383             :                         "An error occurred while writing a dirty block "
     384             :                         "from GDALRasterBand::RasterIO");
     385           0 :             CPLErr eErr = eFlushBlockErr;
     386           0 :             eFlushBlockErr = CE_None;
     387           0 :             return eErr;
     388             :         }
     389      365887 :         if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
     390             :         {
     391           7 :             return CE_Failure;
     392             :         }
     393             :     }
     394             : 
     395             :     /* -------------------------------------------------------------------- */
     396             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     397             :     /*      value assuming a packed buffer.                                 */
     398             :     /* -------------------------------------------------------------------- */
     399     4389320 :     if (nPixelSpace == 0)
     400             :     {
     401     3964080 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     402             :     }
     403             : 
     404     4391110 :     if (nLineSpace == 0)
     405             :     {
     406     3947120 :         nLineSpace = nPixelSpace * nBufXSize;
     407             :     }
     408             : 
     409             :     /* -------------------------------------------------------------------- */
     410             :     /*      Do some validation of parameters.                               */
     411             :     /* -------------------------------------------------------------------- */
     412     4391110 :     if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
     413             :                      nXOff + nXSize > nRasterXSize || nYOff < 0 ||
     414             :                      nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
     415             :     {
     416          15 :         ReportError(CE_Failure, CPLE_IllegalArg,
     417             :                     "Access window out of range in RasterIO().  Requested\n"
     418             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     419             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     420          15 :         return CE_Failure;
     421             :     }
     422             : 
     423     4391090 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     424             :     {
     425           0 :         ReportError(
     426             :             CE_Failure, CPLE_IllegalArg,
     427             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     428             :             eRWFlag);
     429           0 :         return CE_Failure;
     430             :     }
     431     4391090 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     432             :     {
     433           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     434             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     435           2 :         return CE_Failure;
     436             :     }
     437             : 
     438     4391090 :     return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     439             :                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
     440     4367970 :                             nLineSpace, psExtraArg);
     441             : }
     442             : 
     443             : /************************************************************************/
     444             : /*                         RasterIOInternal()                           */
     445             : /************************************************************************/
     446             : 
     447     4362420 : CPLErr GDALRasterBand::RasterIOInternal(
     448             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     449             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     450             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     451             : {
     452             :     /* -------------------------------------------------------------------- */
     453             :     /*      Call the format specific function.                              */
     454             :     /* -------------------------------------------------------------------- */
     455             : 
     456     4362420 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     457             : 
     458             :     CPLErr eErr;
     459     4332290 :     if (bForceCachedIO)
     460          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     461             :                                          pData, nBufXSize, nBufYSize, eBufType,
     462             :                                          nPixelSpace, nLineSpace, psExtraArg);
     463             :     else
     464             :         eErr =
     465     4376240 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     466     4332270 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     467             : 
     468     4376270 :     if (bCallLeaveReadWrite)
     469      600976 :         LeaveReadWrite();
     470             : 
     471     4349560 :     return eErr;
     472             : }
     473             : 
     474             : /************************************************************************/
     475             : /*                            GDALRasterIO()                            */
     476             : /************************************************************************/
     477             : 
     478             : /**
     479             :  * \brief Read/write a region of image data for this band.
     480             :  *
     481             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     482             :  * resolution, progress callback, etc. are needed)
     483             :  *
     484             :  * @see GDALRasterBand::RasterIO()
     485             :  */
     486             : 
     487     3382220 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     488             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     489             :                                 void *pData, int nBufXSize, int nBufYSize,
     490             :                                 GDALDataType eBufType, int nPixelSpace,
     491             :                                 int nLineSpace)
     492             : 
     493             : {
     494     3382220 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     495             : 
     496     3382220 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     497             : 
     498     3379850 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     499             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     500     3320080 :                              nLineSpace, nullptr));
     501             : }
     502             : 
     503             : /************************************************************************/
     504             : /*                            GDALRasterIOEx()                          */
     505             : /************************************************************************/
     506             : 
     507             : /**
     508             :  * \brief Read/write a region of image data for this band.
     509             :  *
     510             :  * @see GDALRasterBand::RasterIO()
     511             :  */
     512             : 
     513       40528 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     514             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     515             :                                   void *pData, int nBufXSize, int nBufYSize,
     516             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     517             :                                   GSpacing nLineSpace,
     518             :                                   GDALRasterIOExtraArg *psExtraArg)
     519             : 
     520             : {
     521       40528 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     522             : 
     523       40528 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     524             : 
     525       40528 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     526             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     527       40526 :                              nLineSpace, psExtraArg));
     528             : }
     529             : 
     530             : /************************************************************************/
     531             : /*                           GetGDTFromCppType()                        */
     532             : /************************************************************************/
     533             : 
     534             : namespace
     535             : {
     536             : template <class T> struct GetGDTFromCppType;
     537             : 
     538             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     539             :     template <> struct GetGDTFromCppType<T>                                    \
     540             :     {                                                                          \
     541             :         static constexpr GDALDataType GDT = eDT;                               \
     542             :     }
     543             : 
     544             : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
     545             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     546             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     547             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     548             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     549             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     550             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     551             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     552             : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
     553             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     554             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     555             : // Not allowed by C++ standard
     556             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     557             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     558             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     559             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     560             : }  // namespace
     561             : 
     562             : /************************************************************************/
     563             : /*                           ReadRaster()                               */
     564             : /************************************************************************/
     565             : 
     566             : // clang-format off
     567             : /** Read a region of image data for this band.
     568             :  *
     569             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     570             :  * for common use cases, like reading a whole band.
     571             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     572             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     573             :  * float, double, std::complex<float|double>.
     574             :  *
     575             :  * 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>&,
     576             :  * and can allocate memory automatically.
     577             :  *
     578             :  * To read a whole band (assuming it fits into memory), as an array of double:
     579             :  *
     580             : \code{.cpp}
     581             :  double* myArray = static_cast<double*>(
     582             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     583             :  // TODO: check here that myArray != nullptr
     584             :  const size_t nArrayEltCount =
     585             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     586             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     587             :  {
     588             :      // do something
     589             :  }
     590             :  VSIFree(myArray)
     591             : \endcode
     592             :  *
     593             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     594             :  *
     595             : \code{.cpp}
     596             :  double* myArray = static_cast<double*>(
     597             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     598             :  // TODO: check here that myArray != nullptr
     599             :  const size_t nArrayEltCount = 128 * 128;
     600             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     601             :  {
     602             :      // do something
     603             :  }
     604             :  VSIFree(myArray)
     605             : \endcode
     606             :  *
     607             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     608             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     609             :  * instance of this dataset) concurrently from several threads.
     610             :  *
     611             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     612             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     613             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     614             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     615             :  * Or use nLineSpace and a possibly shifted pData value.
     616             :  *
     617             :  * @param[out] pData The buffer into which the data should be written.
     618             :  * This buffer must contain at least nBufXSize *
     619             :  * nBufYSize words of type T. It is organized in left to right,
     620             :  * top to bottom pixel order, and fully packed.
     621             :  * The type of the buffer does not need to be the one of GetDataType(). The
     622             :  * method will perform data type translation (with potential rounding, clamping)
     623             :  * if needed.
     624             :  *
     625             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     626             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     627             :  * return in error if it is not. If set to zero, then pData is trusted to be
     628             :  * large enough.
     629             :  *
     630             :  * @param dfXOff The pixel offset to the top left corner of the region
     631             :  * of the band to be accessed. This would be zero to start from the left side.
     632             :  * Defaults to 0.
     633             :  *
     634             :  * @param dfYOff The line offset to the top left corner of the region
     635             :  * of the band to be accessed. This would be zero to start from the top.
     636             :  * Defaults to 0.
     637             :  *
     638             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     639             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     640             :  * dfXSize is set to the band width.
     641             :  *
     642             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     643             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     644             :  * dfYSize is set to the band height.
     645             :  *
     646             :  * @param nBufXSize the width of the buffer image into which the desired region
     647             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     648             :  * then nBufXSize is initialized with dfXSize.
     649             :  *
     650             :  * @param nBufYSize the height of the buffer image into which the desired region
     651             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     652             :  * then nBufYSize is initialized with dfYSize.
     653             :  *
     654             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     655             :  *
     656             :  * @param pfnProgress Progress function. May be nullptr.
     657             :  *
     658             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     659             :  *
     660             :  * @return CE_Failure if the access fails, otherwise CE_None.
     661             :  *
     662             :  * @see GDALRasterBand::RasterIO()
     663             :  * @since GDAL 3.10
     664             :  */
     665             : // clang-format on
     666             : 
     667             : template <class T>
     668          20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     669             :                                   double dfXOff, double dfYOff, double dfXSize,
     670             :                                   double dfYSize, size_t nBufXSize,
     671             :                                   size_t nBufYSize,
     672             :                                   GDALRIOResampleAlg eResampleAlg,
     673             :                                   GDALProgressFunc pfnProgress,
     674             :                                   void *pProgressData) const
     675             : {
     676          20 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     677             :     {
     678           2 :         return CE_Failure;
     679             :     }
     680             : 
     681          18 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     682             :     {
     683          16 :         dfXSize = nRasterXSize;
     684          16 :         dfYSize = nRasterYSize;
     685             :     }
     686           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     687           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     688           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     689           2 :              dfYOff + dfYSize > INT_MAX)
     690             :     {
     691           0 :         return CE_Failure;
     692             :     }
     693             : 
     694             :     GDALRasterIOExtraArg sExtraArg;
     695          18 :     sExtraArg.nVersion = 1;
     696          18 :     sExtraArg.eResampleAlg = eResampleAlg;
     697          18 :     sExtraArg.pfnProgress = pfnProgress;
     698          18 :     sExtraArg.pProgressData = pProgressData;
     699          18 :     sExtraArg.bFloatingPointWindowValidity = true;
     700          18 :     sExtraArg.dfXOff = dfXOff;
     701          18 :     sExtraArg.dfYOff = dfYOff;
     702          18 :     sExtraArg.dfXSize = dfXSize;
     703          18 :     sExtraArg.dfYSize = dfYSize;
     704          18 :     const int nXOff = static_cast<int>(dfXOff);
     705          18 :     const int nYOff = static_cast<int>(dfYOff);
     706          18 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     707          18 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     708          18 :     if (nBufXSize == 0 && nBufYSize == 0)
     709             :     {
     710          17 :         if (static_cast<int>(dfXSize) == dfXSize &&
     711          17 :             static_cast<int>(dfYSize) == dfYSize)
     712             :         {
     713          17 :             nBufXSize = static_cast<int>(dfXSize);
     714          17 :             nBufYSize = static_cast<int>(dfYSize);
     715             :         }
     716             :         else
     717             :         {
     718           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     719             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     720             :                      "dfYSize is not an integer value");
     721           0 :             return CE_Failure;
     722             :         }
     723             :     }
     724          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     725             :     {
     726           0 :         CPLDebug("GDAL",
     727             :                  "RasterIO() skipped for odd window or buffer size.\n"
     728             :                  "  Window = (%d,%d)x%dx%d\n"
     729             :                  "  Buffer = %dx%d\n",
     730             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     731             :                  static_cast<int>(nBufYSize));
     732             : 
     733           0 :         return CE_None;
     734             :     }
     735             : 
     736          18 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     737             :     {
     738           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     739             :                  "Provided array is not large enough");
     740           1 :         return CE_Failure;
     741             :     }
     742             : 
     743          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     744          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     745          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     746             : 
     747          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     748             : 
     749             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     750             :                                    static_cast<int>(nBufXSize),
     751             :                                    static_cast<int>(nBufYSize), eBufType,
     752          17 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     753             : }
     754             : 
     755             : //! @cond Doxygen_Suppress
     756             : 
     757             : #define INSTANTIATE_READ_RASTER(T)                                             \
     758             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     759             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     760             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     761             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     762             :         void *pProgressData) const;
     763             : 
     764             : INSTANTIATE_READ_RASTER(uint8_t)
     765             : INSTANTIATE_READ_RASTER(int8_t)
     766             : INSTANTIATE_READ_RASTER(uint16_t)
     767             : INSTANTIATE_READ_RASTER(int16_t)
     768             : INSTANTIATE_READ_RASTER(uint32_t)
     769             : INSTANTIATE_READ_RASTER(int32_t)
     770             : INSTANTIATE_READ_RASTER(uint64_t)
     771             : INSTANTIATE_READ_RASTER(int64_t)
     772             : INSTANTIATE_READ_RASTER(GFloat16)
     773             : INSTANTIATE_READ_RASTER(float)
     774             : INSTANTIATE_READ_RASTER(double)
     775             : // Not allowed by C++ standard
     776             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     777             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     778             : INSTANTIATE_READ_RASTER(std::complex<float>)
     779             : INSTANTIATE_READ_RASTER(std::complex<double>)
     780             : 
     781             : //! @endcond
     782             : 
     783             : /************************************************************************/
     784             : /*                           ReadRaster()                               */
     785             : /************************************************************************/
     786             : 
     787             : /** Read a region of image data for this band.
     788             :  *
     789             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     790             :  * for common use cases, like reading a whole band.
     791             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     792             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     793             :  * float, double, std::complex<float|double>.
     794             :  *
     795             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     796             :  *
     797             : \code
     798             :  std::vector<double> myArray;
     799             :  if (poBand->ReadRaster(myArray) == CE_None)
     800             :  {
     801             :      // do something
     802             :  }
     803             : \endcode
     804             :  *
     805             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     806             :  *
     807             : \code{.cpp}
     808             :  std::vector<double> myArray;
     809             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     810             :  {
     811             :      // do something
     812             :  }
     813             : \endcode
     814             :  *
     815             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     816             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     817             :  * instance of this dataset) concurrently from several threads.
     818             :  *
     819             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     820             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     821             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     822             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     823             :  * Or use nLineSpace and a possibly shifted pData value.
     824             :  *
     825             :  * @param[out] vData The vector into which the data should be written.
     826             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     827             :  * nBufYSize values. The values in the vector are organized in left to right,
     828             :  * top to bottom pixel order, and fully packed.
     829             :  * The type of the vector does not need to be the one of GetDataType(). The
     830             :  * method will perform data type translation (with potential rounding, clamping)
     831             :  * if needed.
     832             :  *
     833             :  * @param dfXOff The pixel offset to the top left corner of the region
     834             :  * of the band to be accessed. This would be zero to start from the left side.
     835             :  * Defaults to 0.
     836             :  *
     837             :  * @param dfYOff The line offset to the top left corner of the region
     838             :  * of the band to be accessed. This would be zero to start from the top.
     839             :  * Defaults to 0.
     840             :  *
     841             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     842             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     843             :  * dfXSize is set to the band width.
     844             :  *
     845             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     846             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     847             :  * dfYSize is set to the band height.
     848             :  *
     849             :  * @param nBufXSize the width of the buffer image into which the desired region
     850             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     851             :  * then nBufXSize is initialized with dfXSize.
     852             :  *
     853             :  * @param nBufYSize the height of the buffer image into which the desired region
     854             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     855             :  * then nBufYSize is initialized with dfYSize.
     856             :  *
     857             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     858             :  *
     859             :  * @param pfnProgress Progress function. May be nullptr.
     860             :  *
     861             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     862             :  *
     863             :  * @return CE_Failure if the access fails, otherwise CE_None.
     864             :  *
     865             :  * @see GDALRasterBand::RasterIO()
     866             :  * @since GDAL 3.10
     867             :  */
     868             : template <class T>
     869          22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     870             :                                   double dfYOff, double dfXSize, double dfYSize,
     871             :                                   size_t nBufXSize, size_t nBufYSize,
     872             :                                   GDALRIOResampleAlg eResampleAlg,
     873             :                                   GDALProgressFunc pfnProgress,
     874             :                                   void *pProgressData) const
     875             : {
     876          22 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     877             :     {
     878           2 :         return CE_Failure;
     879             :     }
     880             : 
     881          20 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     882             :     {
     883          13 :         dfXSize = nRasterXSize;
     884          13 :         dfYSize = nRasterYSize;
     885             :     }
     886           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     887           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     888           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     889           7 :              dfYOff + dfYSize > INT_MAX)
     890             :     {
     891           0 :         return CE_Failure;
     892             :     }
     893             : 
     894             :     GDALRasterIOExtraArg sExtraArg;
     895          20 :     sExtraArg.nVersion = 1;
     896          20 :     sExtraArg.eResampleAlg = eResampleAlg;
     897          20 :     sExtraArg.pfnProgress = pfnProgress;
     898          20 :     sExtraArg.pProgressData = pProgressData;
     899          20 :     sExtraArg.bFloatingPointWindowValidity = true;
     900          20 :     sExtraArg.dfXOff = dfXOff;
     901          20 :     sExtraArg.dfYOff = dfYOff;
     902          20 :     sExtraArg.dfXSize = dfXSize;
     903          20 :     sExtraArg.dfYSize = dfYSize;
     904          20 :     const int nXOff = static_cast<int>(dfXOff);
     905          20 :     const int nYOff = static_cast<int>(dfYOff);
     906          20 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     907          20 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     908          20 :     if (nBufXSize == 0 && nBufYSize == 0)
     909             :     {
     910          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     911          15 :             static_cast<int>(dfYSize) == dfYSize)
     912             :         {
     913          15 :             nBufXSize = static_cast<int>(dfXSize);
     914          15 :             nBufYSize = static_cast<int>(dfYSize);
     915             :         }
     916             :         else
     917             :         {
     918           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     919             :                      "nBufXSize and nBufYSize must be provided if "
     920             :                      "dfXSize or dfYSize is not an integer value");
     921           1 :             return CE_Failure;
     922             :         }
     923             :     }
     924          19 :     if (nBufXSize == 0 || nBufYSize == 0)
     925             :     {
     926           0 :         CPLDebug("GDAL",
     927             :                  "RasterIO() skipped for odd window or buffer size.\n"
     928             :                  "  Window = (%d,%d)x%dx%d\n"
     929             :                  "  Buffer = %dx%d\n",
     930             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     931             :                  static_cast<int>(nBufYSize));
     932             : 
     933           0 :         return CE_None;
     934             :     }
     935             : 
     936             :     if constexpr (SIZEOF_VOIDP < 8)
     937             :     {
     938             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     939             :         {
     940             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     941             :             return CE_Failure;
     942             :         }
     943             :     }
     944             : 
     945          19 :     if (vData.size() < nBufXSize * nBufYSize)
     946             :     {
     947             :         try
     948             :         {
     949          17 :             vData.resize(nBufXSize * nBufYSize);
     950             :         }
     951           1 :         catch (const std::exception &)
     952             :         {
     953           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     954           1 :             return CE_Failure;
     955             :         }
     956             :     }
     957             : 
     958          18 :     constexpr GSpacing nPixelSpace = sizeof(T);
     959          18 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     960          18 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     961             : 
     962          18 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     963             : 
     964             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
     965             :                                    vData.data(), static_cast<int>(nBufXSize),
     966             :                                    static_cast<int>(nBufYSize), eBufType,
     967          18 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     968             : }
     969             : 
     970             : //! @cond Doxygen_Suppress
     971             : 
     972             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     973             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     974             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     975             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     976             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     977             :         void *pProgressData) const;
     978             : 
     979             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     980             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     981             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     982             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     983             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     984             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     985             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     986             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     987             : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
     988             : INSTANTIATE_READ_RASTER_VECTOR(float)
     989             : INSTANTIATE_READ_RASTER_VECTOR(double)
     990             : // Not allowed by C++ standard
     991             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
     992             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
     993             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
     994             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
     995             : 
     996             : //! @endcond
     997             : 
     998             : /************************************************************************/
     999             : /*                             ReadBlock()                              */
    1000             : /************************************************************************/
    1001             : 
    1002             : /**
    1003             :  * \brief Read a block of image data efficiently.
    1004             :  *
    1005             :  * This method accesses a "natural" block from the raster band without
    1006             :  * resampling, or data type conversion.  For a more generalized, but
    1007             :  * potentially less efficient access use RasterIO().
    1008             :  *
    1009             :  * This method is the same as the C GDALReadBlock() function.
    1010             :  *
    1011             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1012             :  * block oriented data without an extra copy into an application buffer.
    1013             :  *
    1014             :  * The following code would efficiently compute a histogram of eight bit
    1015             :  * raster data.  Note that the final block may be partial ... data beyond
    1016             :  * the edge of the underlying raster band in these edge blocks is of an
    1017             :  * undetermined value.
    1018             :  *
    1019             : \code{.cpp}
    1020             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1021             : 
    1022             :  {
    1023             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1024             : 
    1025             :      CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
    1026             : 
    1027             :      int nXBlockSize, nYBlockSize;
    1028             : 
    1029             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1030             :      int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
    1031             :      int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
    1032             : 
    1033             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1034             : 
    1035             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1036             :      {
    1037             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1038             :          {
    1039             :              int        nXValid, nYValid;
    1040             : 
    1041             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1042             : 
    1043             :              // Compute the portion of the block that is valid
    1044             :              // for partial edge blocks.
    1045             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1046             : 
    1047             :              // Collect the histogram counts.
    1048             :              for( int iY = 0; iY < nYValid; iY++ )
    1049             :              {
    1050             :                  for( int iX = 0; iX < nXValid; iX++ )
    1051             :                  {
    1052             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1053             :                  }
    1054             :              }
    1055             :          }
    1056             :      }
    1057             :  }
    1058             : \endcode
    1059             :  *
    1060             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1061             :  * the left most block, 1 the next block and so forth.
    1062             :  *
    1063             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1064             :  * the top most block, 1 the next block and so forth.
    1065             :  *
    1066             :  * @param pImage the buffer into which the data will be read.  The buffer
    1067             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1068             :  * of type GetRasterDataType().
    1069             :  *
    1070             :  * @return CE_None on success or CE_Failure on an error.
    1071             :  */
    1072             : 
    1073         894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1074             : 
    1075             : {
    1076             :     /* -------------------------------------------------------------------- */
    1077             :     /*      Validate arguments.                                             */
    1078             :     /* -------------------------------------------------------------------- */
    1079         894 :     CPLAssert(pImage != nullptr);
    1080             : 
    1081         894 :     if (!InitBlockInfo())
    1082           0 :         return CE_Failure;
    1083             : 
    1084         894 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1085             :     {
    1086           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1087             :                     "Illegal nXBlockOff value (%d) in "
    1088             :                     "GDALRasterBand::ReadBlock()\n",
    1089             :                     nXBlockOff);
    1090             : 
    1091           0 :         return (CE_Failure);
    1092             :     }
    1093             : 
    1094         894 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1095             :     {
    1096           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1097             :                     "Illegal nYBlockOff value (%d) in "
    1098             :                     "GDALRasterBand::ReadBlock()\n",
    1099             :                     nYBlockOff);
    1100             : 
    1101           0 :         return (CE_Failure);
    1102             :     }
    1103             : 
    1104             :     /* -------------------------------------------------------------------- */
    1105             :     /*      Invoke underlying implementation method.                        */
    1106             :     /* -------------------------------------------------------------------- */
    1107             : 
    1108         894 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1109         894 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1110         894 :     if (bCallLeaveReadWrite)
    1111           4 :         LeaveReadWrite();
    1112         894 :     return eErr;
    1113             : }
    1114             : 
    1115             : /************************************************************************/
    1116             : /*                           GDALReadBlock()                            */
    1117             : /************************************************************************/
    1118             : 
    1119             : /**
    1120             :  * \brief Read a block of image data efficiently.
    1121             :  *
    1122             :  * @see GDALRasterBand::ReadBlock()
    1123             :  */
    1124             : 
    1125          77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1126             :                                  void *pData)
    1127             : 
    1128             : {
    1129          77 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1130             : 
    1131          77 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1132          77 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1133             : }
    1134             : 
    1135             : /************************************************************************/
    1136             : /*                            IReadBlock()                             */
    1137             : /************************************************************************/
    1138             : 
    1139             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1140             :  * ) \brief Read a block of data.
    1141             :  *
    1142             :  * Default internal implementation ... to be overridden by
    1143             :  * subclasses that support reading.
    1144             :  * @param nBlockXOff Block X Offset
    1145             :  * @param nBlockYOff Block Y Offset
    1146             :  * @param pData Pixel buffer into which to place read data.
    1147             :  * @return CE_None on success or CE_Failure on an error.
    1148             :  */
    1149             : 
    1150             : /************************************************************************/
    1151             : /*                            IWriteBlock()                             */
    1152             : /************************************************************************/
    1153             : 
    1154             : /**
    1155             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1156             :  * Write a block of data.
    1157             :  *
    1158             :  * Default internal implementation ... to be overridden by
    1159             :  * subclasses that support writing.
    1160             :  * @param nBlockXOff Block X Offset
    1161             :  * @param nBlockYOff Block Y Offset
    1162             :  * @param pData Pixel buffer to write
    1163             :  * @return CE_None on success or CE_Failure on an error.
    1164             :  */
    1165             : 
    1166             : /**/
    1167             : /**/
    1168             : 
    1169           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1170             :                                    void * /*pData*/)
    1171             : 
    1172             : {
    1173           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1174           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1175             :                     "WriteBlock() not supported for this dataset.");
    1176             : 
    1177           0 :     return (CE_Failure);
    1178             : }
    1179             : 
    1180             : /************************************************************************/
    1181             : /*                             WriteBlock()                             */
    1182             : /************************************************************************/
    1183             : 
    1184             : /**
    1185             :  * \brief Write a block of image data efficiently.
    1186             :  *
    1187             :  * This method accesses a "natural" block from the raster band without
    1188             :  * resampling, or data type conversion.  For a more generalized, but
    1189             :  * potentially less efficient access use RasterIO().
    1190             :  *
    1191             :  * This method is the same as the C GDALWriteBlock() function.
    1192             :  *
    1193             :  * See ReadBlock() for an example of block oriented data access.
    1194             :  *
    1195             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1196             :  * the left most block, 1 the next block and so forth.
    1197             :  *
    1198             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1199             :  * the left most block, 1 the next block and so forth.
    1200             :  *
    1201             :  * @param pImage the buffer from which the data will be written.  The buffer
    1202             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1203             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1204             :  * temporarily modified during the execution of this method (and eventually
    1205             :  * restored back to its original content), so it is not safe to use a buffer
    1206             :  * stored in a read-only section of the calling program.
    1207             :  *
    1208             :  * @return CE_None on success or CE_Failure on an error.
    1209             :  */
    1210             : 
    1211        4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1212             : 
    1213             : {
    1214             :     /* -------------------------------------------------------------------- */
    1215             :     /*      Validate arguments.                                             */
    1216             :     /* -------------------------------------------------------------------- */
    1217        4883 :     CPLAssert(pImage != nullptr);
    1218             : 
    1219        4883 :     if (!InitBlockInfo())
    1220           0 :         return CE_Failure;
    1221             : 
    1222        4883 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1223             :     {
    1224           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1225             :                     "Illegal nXBlockOff value (%d) in "
    1226             :                     "GDALRasterBand::WriteBlock()\n",
    1227             :                     nXBlockOff);
    1228             : 
    1229           0 :         return (CE_Failure);
    1230             :     }
    1231             : 
    1232        4883 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1233             :     {
    1234           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1235             :                     "Illegal nYBlockOff value (%d) in "
    1236             :                     "GDALRasterBand::WriteBlock()\n",
    1237             :                     nYBlockOff);
    1238             : 
    1239           0 :         return (CE_Failure);
    1240             :     }
    1241             : 
    1242        4883 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
    1243             :     {
    1244           0 :         return CE_Failure;
    1245             :     }
    1246             : 
    1247        4883 :     if (eFlushBlockErr != CE_None)
    1248             :     {
    1249           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1250             :                     "An error occurred while writing a dirty block "
    1251             :                     "from GDALRasterBand::WriteBlock");
    1252           0 :         CPLErr eErr = eFlushBlockErr;
    1253           0 :         eFlushBlockErr = CE_None;
    1254           0 :         return eErr;
    1255             :     }
    1256             : 
    1257             :     /* -------------------------------------------------------------------- */
    1258             :     /*      Invoke underlying implementation method.                        */
    1259             :     /* -------------------------------------------------------------------- */
    1260             : 
    1261        4883 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1262        4883 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1263        4883 :     if (bCallLeaveReadWrite)
    1264        4883 :         LeaveReadWrite();
    1265             : 
    1266        4883 :     return eErr;
    1267             : }
    1268             : 
    1269             : /************************************************************************/
    1270             : /*                           GDALWriteBlock()                           */
    1271             : /************************************************************************/
    1272             : 
    1273             : /**
    1274             :  * \brief Write a block of image data efficiently.
    1275             :  *
    1276             :  * @see GDALRasterBand::WriteBlock()
    1277             :  */
    1278             : 
    1279           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1280             :                                   void *pData)
    1281             : 
    1282             : {
    1283           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1284             : 
    1285           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1286           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1287             : }
    1288             : 
    1289             : /************************************************************************/
    1290             : /*                   EmitErrorMessageIfWriteNotSupported()              */
    1291             : /************************************************************************/
    1292             : 
    1293             : /**
    1294             :  * Emit an error message if a write operation to this band is not supported.
    1295             :  *
    1296             :  * The base implementation will emit an error message if the access mode is
    1297             :  * read-only. Derived classes may implement it to provide a custom message.
    1298             :  *
    1299             :  * @param pszCaller Calling function.
    1300             :  * @return true if an error message has been emitted.
    1301             :  */
    1302      639596 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
    1303             :     const char *pszCaller) const
    1304             : {
    1305      639596 :     if (eAccess == GA_ReadOnly)
    1306             :     {
    1307           4 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1308             :                     "%s: attempt to write to dataset opened in read-only mode.",
    1309             :                     pszCaller);
    1310             : 
    1311           4 :         return true;
    1312             :     }
    1313      639592 :     return false;
    1314             : }
    1315             : 
    1316             : /************************************************************************/
    1317             : /*                         GetActualBlockSize()                         */
    1318             : /************************************************************************/
    1319             : /**
    1320             :  * \brief Fetch the actual block size for a given block offset.
    1321             :  *
    1322             :  * Handles partial blocks at the edges of the raster and returns the true
    1323             :  * number of pixels
    1324             :  *
    1325             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1326             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1327             :  * block and so forth.
    1328             :  *
    1329             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1330             :  * the top most block, 1 the next block and so forth.
    1331             :  *
    1332             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1333             :  * the x direction will be stored
    1334             :  *
    1335             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1336             :  * the y direction will be stored
    1337             :  *
    1338             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1339             :  *
    1340             :  */
    1341       52120 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1342             :                                           int *pnXValid, int *pnYValid) const
    1343             : {
    1344      104239 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1345      104237 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1346      104234 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1347       52117 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1348             :     {
    1349           4 :         return CE_Failure;
    1350             :     }
    1351             : 
    1352       52116 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1353       52116 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1354             : 
    1355       52116 :     *pnXValid = nBlockXSize;
    1356       52116 :     *pnYValid = nBlockYSize;
    1357             : 
    1358       52116 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1359             :     {
    1360       50483 :         *pnXValid = nRasterXSize - nXPixelOff;
    1361             :     }
    1362             : 
    1363       52116 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1364             :     {
    1365        3820 :         *pnYValid = nRasterYSize - nYPixelOff;
    1366             :     }
    1367             : 
    1368       52116 :     return CE_None;
    1369             : }
    1370             : 
    1371             : /************************************************************************/
    1372             : /*                           GDALGetActualBlockSize()                   */
    1373             : /************************************************************************/
    1374             : 
    1375             : /**
    1376             :  * \brief Retrieve the actual block size for a given block offset.
    1377             :  *
    1378             :  * @see GDALRasterBand::GetActualBlockSize()
    1379             :  */
    1380             : 
    1381           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1382             :                                           int nYBlockOff, int *pnXValid,
    1383             :                                           int *pnYValid)
    1384             : 
    1385             : {
    1386           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1387             : 
    1388           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1389             :     return (
    1390           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1391             : }
    1392             : 
    1393             : /************************************************************************/
    1394             : /*                     GetSuggestedBlockAccessPattern()                 */
    1395             : /************************************************************************/
    1396             : 
    1397             : /**
    1398             :  * \brief Return the suggested/most efficient access pattern to blocks
    1399             :  *        (for read operations).
    1400             :  *
    1401             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1402             :  * efficient random access (GSBAP_RANDOM) to any block.
    1403             :  * Some drivers for example decompress sequentially a compressed stream from
    1404             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1405             :  * case best performance will be achieved while reading blocks in that order.
    1406             :  * (accessing blocks in random access in such rasters typically causes the
    1407             :  * decoding to be re-initialized from the start if accessing blocks in
    1408             :  * a non-sequential order)
    1409             :  *
    1410             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1411             :  * returned by drivers that expose a somewhat artificial block size, because
    1412             :  * they can extract any part of a raster, but in a rather inefficient way.
    1413             :  *
    1414             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1415             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1416             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1417             :  * most efficient strategy is to read as many pixels as possible in the less
    1418             :  * RasterIO() operations.
    1419             :  *
    1420             :  * The return of this method is for example used to determine the swath size
    1421             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1422             :  *
    1423             :  * @since GDAL 3.6
    1424             :  */
    1425             : 
    1426             : GDALSuggestedBlockAccessPattern
    1427        2415 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1428             : {
    1429        2415 :     return GSBAP_UNKNOWN;
    1430             : }
    1431             : 
    1432             : /************************************************************************/
    1433             : /*                         GetRasterDataType()                          */
    1434             : /************************************************************************/
    1435             : 
    1436             : /**
    1437             :  * \brief Fetch the pixel data type for this band.
    1438             :  *
    1439             :  * This method is the same as the C function GDALGetRasterDataType().
    1440             :  *
    1441             :  * @return the data type of pixels for this band.
    1442             :  */
    1443             : 
    1444     8798830 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1445             : 
    1446             : {
    1447     8798830 :     return eDataType;
    1448             : }
    1449             : 
    1450             : /************************************************************************/
    1451             : /*                       GDALGetRasterDataType()                        */
    1452             : /************************************************************************/
    1453             : 
    1454             : /**
    1455             :  * \brief Fetch the pixel data type for this band.
    1456             :  *
    1457             :  * @see GDALRasterBand::GetRasterDataType()
    1458             :  */
    1459             : 
    1460      905993 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1461             : 
    1462             : {
    1463      905993 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1464             : 
    1465      905993 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1466      905993 :     return poBand->GetRasterDataType();
    1467             : }
    1468             : 
    1469             : /************************************************************************/
    1470             : /*                            GetBlockSize()                            */
    1471             : /************************************************************************/
    1472             : 
    1473             : /**
    1474             :  * \brief Fetch the "natural" block size of this band.
    1475             :  *
    1476             :  * GDAL contains a concept of the natural block size of rasters so that
    1477             :  * applications can organized data access efficiently for some file formats.
    1478             :  * The natural block size is the block size that is most efficient for
    1479             :  * accessing the format.  For many formats this is simple a whole scanline
    1480             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1481             :  *
    1482             :  * However, for tiled images this will typically be the tile size.
    1483             :  *
    1484             :  * Note that the X and Y block sizes don't have to divide the image size
    1485             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1486             :  * See ReadBlock() for an example of code dealing with these issues.
    1487             :  *
    1488             :  * This method is the same as the C function GDALGetBlockSize().
    1489             :  *
    1490             :  * @param pnXSize integer to put the X block size into or NULL.
    1491             :  *
    1492             :  * @param pnYSize integer to put the Y block size into or NULL.
    1493             :  */
    1494             : 
    1495     5400650 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1496             : 
    1497             : {
    1498     5400650 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1499             :     {
    1500       59454 :         ReportError(CE_Failure, CPLE_AppDefined,
    1501       59454 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1502       59454 :                     nBlockYSize);
    1503           4 :         if (pnXSize != nullptr)
    1504           4 :             *pnXSize = 0;
    1505           4 :         if (pnYSize != nullptr)
    1506           4 :             *pnYSize = 0;
    1507             :     }
    1508             :     else
    1509             :     {
    1510     5341200 :         if (pnXSize != nullptr)
    1511     5299890 :             *pnXSize = nBlockXSize;
    1512     5341200 :         if (pnYSize != nullptr)
    1513     5339120 :             *pnYSize = nBlockYSize;
    1514             :     }
    1515     5341200 : }
    1516             : 
    1517             : /************************************************************************/
    1518             : /*                          GDALGetBlockSize()                          */
    1519             : /************************************************************************/
    1520             : 
    1521             : /**
    1522             :  * \brief Fetch the "natural" block size of this band.
    1523             :  *
    1524             :  * @see GDALRasterBand::GetBlockSize()
    1525             :  */
    1526             : 
    1527       41234 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1528             :                                   int *pnYSize)
    1529             : 
    1530             : {
    1531       41234 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1532             : 
    1533       41234 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1534       41234 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1535             : }
    1536             : 
    1537             : /************************************************************************/
    1538             : /*                           InitBlockInfo()                            */
    1539             : /************************************************************************/
    1540             : 
    1541             : //! @cond Doxygen_Suppress
    1542     3651060 : int GDALRasterBand::InitBlockInfo()
    1543             : 
    1544             : {
    1545     3651060 :     if (poBandBlockCache != nullptr)
    1546     3412110 :         return poBandBlockCache->IsInitOK();
    1547             : 
    1548             :     /* Do some validation of raster and block dimensions in case the driver */
    1549             :     /* would have neglected to do it itself */
    1550      238943 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1551             :     {
    1552         301 :         ReportError(CE_Failure, CPLE_AppDefined,
    1553             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1554             :                     nBlockYSize);
    1555           0 :         return FALSE;
    1556             :     }
    1557             : 
    1558      238642 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1559             :     {
    1560           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1561             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1562             :                     nRasterYSize);
    1563           0 :         return FALSE;
    1564             :     }
    1565             : 
    1566      238655 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1567      238917 :     if (nDataTypeSize == 0)
    1568             :     {
    1569         259 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1570           0 :         return FALSE;
    1571             :     }
    1572             : 
    1573             : #if SIZEOF_VOIDP == 4
    1574             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1575             :     {
    1576             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1577             :          * multiplication in other cases */
    1578             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1579             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1580             :         {
    1581             :             ReportError(CE_Failure, CPLE_NotSupported,
    1582             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1583             :                         nBlockYSize);
    1584             :             return FALSE;
    1585             :         }
    1586             :     }
    1587             : #endif
    1588             : 
    1589      238658 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1590      238658 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1591             : 
    1592             :     const char *pszBlockStrategy =
    1593      238658 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1594      239017 :     bool bUseArray = true;
    1595      239017 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1596             :     {
    1597      238977 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1598             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1599             :         {
    1600      238958 :             GUIntBig nBlockCount =
    1601      238958 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1602      238958 :             if (poDS != nullptr)
    1603      238754 :                 nBlockCount *= poDS->GetRasterCount();
    1604      238958 :             bUseArray = (nBlockCount < 1024 * 1024);
    1605             :         }
    1606          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1607             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1608             :         {
    1609           0 :             bUseArray = false;
    1610      238977 :         }
    1611             :     }
    1612          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1613          40 :         bUseArray = false;
    1614           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1615           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1616             :                  pszBlockStrategy);
    1617             : 
    1618      239017 :     if (bUseArray)
    1619      238946 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1620             :     else
    1621             :     {
    1622          71 :         if (nBand == 1)
    1623          26 :             CPLDebug("GDAL", "Use hashset band block cache");
    1624          71 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1625             :     }
    1626      238978 :     if (poBandBlockCache == nullptr)
    1627           0 :         return FALSE;
    1628      238978 :     return poBandBlockCache->Init();
    1629             : }
    1630             : 
    1631             : //! @endcond
    1632             : 
    1633             : /************************************************************************/
    1634             : /*                             FlushCache()                             */
    1635             : /************************************************************************/
    1636             : 
    1637             : /**
    1638             :  * \brief Flush raster data cache.
    1639             :  *
    1640             :  * This call will recover memory used to cache data blocks for this raster
    1641             :  * band, and ensure that new requests are referred to the underlying driver.
    1642             :  *
    1643             :  * This method is the same as the C function GDALFlushRasterCache().
    1644             :  *
    1645             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1646             :  * @return CE_None on success.
    1647             :  */
    1648             : 
    1649     5632180 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1650             : 
    1651             : {
    1652     5749260 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1653      117081 :         poBandBlockCache)
    1654        3197 :         poBandBlockCache->DisableDirtyBlockWriting();
    1655             : 
    1656     5620380 :     CPLErr eGlobalErr = eFlushBlockErr;
    1657             : 
    1658     5620380 :     if (eFlushBlockErr != CE_None)
    1659             :     {
    1660           0 :         ReportError(
    1661             :             eFlushBlockErr, CPLE_AppDefined,
    1662             :             "An error occurred while writing a dirty block from FlushCache");
    1663           0 :         eFlushBlockErr = CE_None;
    1664             :     }
    1665             : 
    1666     5620380 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1667     4813730 :         return eGlobalErr;
    1668             : 
    1669      806655 :     return poBandBlockCache->FlushCache();
    1670             : }
    1671             : 
    1672             : /************************************************************************/
    1673             : /*                        GDALFlushRasterCache()                        */
    1674             : /************************************************************************/
    1675             : 
    1676             : /**
    1677             :  * \brief Flush raster data cache.
    1678             :  *
    1679             :  * @see GDALRasterBand::FlushCache()
    1680             :  */
    1681             : 
    1682         487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1683             : 
    1684             : {
    1685         487 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1686             : 
    1687         487 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1688             : }
    1689             : 
    1690             : /************************************************************************/
    1691             : /*                             DropCache()                              */
    1692             : /************************************************************************/
    1693             : 
    1694             : /**
    1695             : * \brief Drop raster data cache : data in cache will be lost.
    1696             : *
    1697             : * This call will recover memory used to cache data blocks for this raster
    1698             : * band, and ensure that new requests are referred to the underlying driver.
    1699             : *
    1700             : * This method is the same as the C function GDALDropRasterCache().
    1701             : *
    1702             : * @return CE_None on success.
    1703             : * @since 3.9
    1704             : */
    1705             : 
    1706           1 : CPLErr GDALRasterBand::DropCache()
    1707             : 
    1708             : {
    1709           1 :     CPLErr result = CE_None;
    1710             : 
    1711           1 :     if (poBandBlockCache)
    1712           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1713             : 
    1714           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1715             : 
    1716           1 :     if (eFlushBlockErr != CE_None)
    1717             :     {
    1718           0 :         ReportError(
    1719             :             eFlushBlockErr, CPLE_AppDefined,
    1720             :             "An error occurred while writing a dirty block from DropCache");
    1721           0 :         eFlushBlockErr = CE_None;
    1722             :     }
    1723             : 
    1724           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1725           0 :         result = eGlobalErr;
    1726             :     else
    1727           1 :         result = poBandBlockCache->FlushCache();
    1728             : 
    1729           1 :     if (poBandBlockCache)
    1730           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1731             : 
    1732           1 :     return result;
    1733             : }
    1734             : 
    1735             : /************************************************************************/
    1736             : /*                        GDALDropRasterCache()                         */
    1737             : /************************************************************************/
    1738             : 
    1739             : /**
    1740             : * \brief Drop raster data cache.
    1741             : *
    1742             : * @see GDALRasterBand::DropCache()
    1743             : * @since 3.9
    1744             : */
    1745             : 
    1746           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1747             : 
    1748             : {
    1749           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1750             : 
    1751           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1752             : }
    1753             : 
    1754             : /************************************************************************/
    1755             : /*                        UnreferenceBlock()                            */
    1756             : /*                                                                      */
    1757             : /*      Unreference the block from our array of blocks                  */
    1758             : /*      This method should only be called by                            */
    1759             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1760             : /*      the block cache mutex)                                          */
    1761             : /************************************************************************/
    1762             : 
    1763       29654 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1764             : {
    1765             : #ifdef notdef
    1766             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1767             :     {
    1768             :         if (poBandBlockCache == nullptr)
    1769             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1770             :         else
    1771             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1772             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1773             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1774             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1775             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1776             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1777             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1778             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1779             :         poBlock->DumpBlock();
    1780             :         if (GetDataset() != nullptr)
    1781             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1782             :         GDALRasterBlock::Verify();
    1783             :         abort();
    1784             :     }
    1785             : #endif
    1786       29654 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1787       29654 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1788             : }
    1789             : 
    1790             : /************************************************************************/
    1791             : /*                        AddBlockToFreeList()                          */
    1792             : /*                                                                      */
    1793             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1794             : /*      finished with a block about to be free'd, they pass it to that  */
    1795             : /*      method.                                                         */
    1796             : /************************************************************************/
    1797             : 
    1798             : //! @cond Doxygen_Suppress
    1799       29651 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1800             : {
    1801       29651 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1802       29646 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1803             : }
    1804             : 
    1805             : //! @endcond
    1806             : 
    1807             : /************************************************************************/
    1808             : /*                           HasDirtyBlocks()                           */
    1809             : /************************************************************************/
    1810             : 
    1811             : //! @cond Doxygen_Suppress
    1812          17 : bool GDALRasterBand::HasDirtyBlocks() const
    1813             : {
    1814          17 :     return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
    1815             : }
    1816             : 
    1817             : //! @endcond
    1818             : 
    1819             : /************************************************************************/
    1820             : /*                             FlushBlock()                             */
    1821             : /************************************************************************/
    1822             : 
    1823             : /** Flush a block out of the block cache.
    1824             :  * @param nXBlockOff block x offset
    1825             :  * @param nYBlockOff blocky offset
    1826             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1827             :  * @return CE_None in case of success, an error code otherwise.
    1828             :  */
    1829        2311 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1830             :                                   int bWriteDirtyBlock)
    1831             : 
    1832             : {
    1833        2311 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1834           0 :         return (CE_Failure);
    1835             : 
    1836             :     /* -------------------------------------------------------------------- */
    1837             :     /*      Validate the request                                            */
    1838             :     /* -------------------------------------------------------------------- */
    1839        2311 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1840             :     {
    1841           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1842             :                     "Illegal nBlockXOff value (%d) in "
    1843             :                     "GDALRasterBand::FlushBlock()\n",
    1844             :                     nXBlockOff);
    1845             : 
    1846           0 :         return (CE_Failure);
    1847             :     }
    1848             : 
    1849        2311 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1850             :     {
    1851           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1852             :                     "Illegal nBlockYOff value (%d) in "
    1853             :                     "GDALRasterBand::FlushBlock()\n",
    1854             :                     nYBlockOff);
    1855             : 
    1856           0 :         return (CE_Failure);
    1857             :     }
    1858             : 
    1859        2311 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1860        2311 :                                         bWriteDirtyBlock);
    1861             : }
    1862             : 
    1863             : /************************************************************************/
    1864             : /*                        TryGetLockedBlockRef()                        */
    1865             : /************************************************************************/
    1866             : 
    1867             : /**
    1868             :  * \brief Try fetching block ref.
    1869             :  *
    1870             :  * This method will returned the requested block (locked) if it is already
    1871             :  * in the block cache for the layer.  If not, nullptr is returned.
    1872             :  *
    1873             :  * If a non-NULL value is returned, then a lock for the block will have been
    1874             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1875             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1876             :  * severe problems may result.
    1877             :  *
    1878             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1879             :  * the left most block, 1 the next block and so forth.
    1880             :  *
    1881             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1882             :  * the top most block, 1 the next block and so forth.
    1883             :  *
    1884             :  * @return NULL if block not available, or locked block pointer.
    1885             :  */
    1886             : 
    1887    10646000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1888             :                                                       int nYBlockOff)
    1889             : 
    1890             : {
    1891    10646000 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1892      172604 :         return nullptr;
    1893             : 
    1894             :     /* -------------------------------------------------------------------- */
    1895             :     /*      Validate the request                                            */
    1896             :     /* -------------------------------------------------------------------- */
    1897    10473200 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1898             :     {
    1899        1254 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1900             :                     "Illegal nBlockXOff value (%d) in "
    1901             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1902             :                     nXBlockOff);
    1903             : 
    1904           0 :         return (nullptr);
    1905             :     }
    1906             : 
    1907    10472000 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1908             :     {
    1909           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1910             :                     "Illegal nBlockYOff value (%d) in "
    1911             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1912             :                     nYBlockOff);
    1913             : 
    1914           0 :         return (nullptr);
    1915             :     }
    1916             : 
    1917    10472000 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1918             : }
    1919             : 
    1920             : /************************************************************************/
    1921             : /*                         GetLockedBlockRef()                          */
    1922             : /************************************************************************/
    1923             : 
    1924             : /**
    1925             :  * \brief Fetch a pointer to an internally cached raster block.
    1926             :  *
    1927             :  * This method will returned the requested block (locked) if it is already
    1928             :  * in the block cache for the layer.  If not, the block will be read from
    1929             :  * the driver, and placed in the layer block cached, then returned.  If an
    1930             :  * error occurs reading the block from the driver, a NULL value will be
    1931             :  * returned.
    1932             :  *
    1933             :  * If a non-NULL value is returned, then a lock for the block will have been
    1934             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1935             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1936             :  * severe problems may result.
    1937             :  *
    1938             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1939             :  * enable caching.
    1940             :  *
    1941             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1942             :  * the left most block, 1 the next block and so forth.
    1943             :  *
    1944             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1945             :  * the top most block, 1 the next block and so forth.
    1946             :  *
    1947             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1948             :  * but not actually read from the source.  This is useful when it will just
    1949             :  * be completely set and written back.
    1950             :  *
    1951             :  * @return pointer to the block object, or NULL on failure.
    1952             :  */
    1953             : 
    1954    10335600 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1955             :                                                    int nYBlockOff,
    1956             :                                                    int bJustInitialize)
    1957             : 
    1958             : {
    1959             :     /* -------------------------------------------------------------------- */
    1960             :     /*      Try and fetch from cache.                                       */
    1961             :     /* -------------------------------------------------------------------- */
    1962    10335600 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1963             : 
    1964             :     /* -------------------------------------------------------------------- */
    1965             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1966             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1967             :     /*      cache.                                                          */
    1968             :     /* -------------------------------------------------------------------- */
    1969    10336100 :     if (poBlock == nullptr)
    1970             :     {
    1971     3373720 :         if (!InitBlockInfo())
    1972           0 :             return (nullptr);
    1973             : 
    1974             :         /* --------------------------------------------------------------------
    1975             :          */
    1976             :         /*      Validate the request */
    1977             :         /* --------------------------------------------------------------------
    1978             :          */
    1979     3373950 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1980             :         {
    1981         160 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1982             :                         "Illegal nBlockXOff value (%d) in "
    1983             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1984             :                         nXBlockOff);
    1985             : 
    1986           0 :             return (nullptr);
    1987             :         }
    1988             : 
    1989     3373790 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1990             :         {
    1991          14 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1992             :                         "Illegal nBlockYOff value (%d) in "
    1993             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1994             :                         nYBlockOff);
    1995             : 
    1996           0 :             return (nullptr);
    1997             :         }
    1998             : 
    1999     3373780 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    2000     3373740 :         if (poBlock == nullptr)
    2001           0 :             return nullptr;
    2002             : 
    2003     3373740 :         poBlock->AddLock();
    2004             : 
    2005             :         /* We need to temporarily drop the read-write lock in the following */
    2006             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    2007             :          */
    2008             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    2009             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    2010             :          */
    2011             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    2012             :          */
    2013             :         /* called and attempt at taking the lock on T2 (already taken).
    2014             :          * Similarly */
    2015             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    2016             :         /* But this may open the door to other problems... */
    2017     3373800 :         if (poDS)
    2018     3373070 :             poDS->TemporarilyDropReadWriteLock();
    2019             :         /* allocate data space */
    2020     3373760 :         CPLErr eErr = poBlock->Internalize();
    2021     3373950 :         if (poDS)
    2022     3373070 :             poDS->ReacquireReadWriteLock();
    2023     3373760 :         if (eErr != CE_None)
    2024             :         {
    2025           0 :             poBlock->DropLock();
    2026           0 :             delete poBlock;
    2027           0 :             return nullptr;
    2028             :         }
    2029             : 
    2030     3373760 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2031             :         {
    2032           0 :             poBlock->DropLock();
    2033           0 :             delete poBlock;
    2034           0 :             return nullptr;
    2035             :         }
    2036             : 
    2037     3373930 :         if (!bJustInitialize)
    2038             :         {
    2039     2887670 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2040     2887680 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2041     2887510 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2042     2887760 :             if (bCallLeaveReadWrite)
    2043      130218 :                 LeaveReadWrite();
    2044     2887550 :             if (eErr != CE_None)
    2045             :             {
    2046        1161 :                 poBlock->DropLock();
    2047        1161 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2048        1161 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2049             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2050             :                             nXBlockOff, nYBlockOff,
    2051        1161 :                             (nErrorCounter != CPLGetErrorCounter())
    2052        1159 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2053             :                                 : "");
    2054        1161 :                 return nullptr;
    2055             :             }
    2056             : 
    2057     2886390 :             nBlockReads++;
    2058     2886390 :             if (static_cast<GIntBig>(nBlockReads) ==
    2059     2886390 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2060         229 :                         1 &&
    2061         229 :                 nBand == 1 && poDS != nullptr)
    2062             :             {
    2063         169 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2064         169 :                          poDS->GetDescription());
    2065             :             }
    2066             :         }
    2067             :     }
    2068             : 
    2069    10335000 :     return poBlock;
    2070             : }
    2071             : 
    2072             : /************************************************************************/
    2073             : /*                               Fill()                                 */
    2074             : /************************************************************************/
    2075             : 
    2076             : /**
    2077             :  * \brief Fill this band with a constant value.
    2078             :  *
    2079             :  * GDAL makes no guarantees
    2080             :  * about what values pixels in newly created files are set to, so this
    2081             :  * method can be used to clear a band to a specified "default" value.
    2082             :  * The fill value is passed in as a double but this will be converted
    2083             :  * to the underlying type before writing to the file. An optional
    2084             :  * second argument allows the imaginary component of a complex
    2085             :  * constant value to be specified.
    2086             :  *
    2087             :  * This method is the same as the C function GDALFillRaster().
    2088             :  *
    2089             :  * @param dfRealValue Real component of fill value
    2090             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2091             :  *
    2092             :  * @return CE_Failure if the write fails, otherwise CE_None
    2093             :  */
    2094      268881 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2095             : {
    2096             : 
    2097             :     // General approach is to construct a source block of the file's
    2098             :     // native type containing the appropriate value and then copy this
    2099             :     // to each block in the image via the RasterBlock cache. Using
    2100             :     // the cache means we avoid file I/O if it is not necessary, at the
    2101             :     // expense of some extra memcpy's (since we write to the
    2102             :     // RasterBlock cache, which is then at some point written to the
    2103             :     // underlying file, rather than simply directly to the underlying
    2104             :     // file.)
    2105             : 
    2106             :     // Check we can write to the file.
    2107      268881 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
    2108             :     {
    2109           6 :         return CE_Failure;
    2110             :     }
    2111             : 
    2112             :     // Make sure block parameters are set.
    2113      268875 :     if (!InitBlockInfo())
    2114           0 :         return CE_Failure;
    2115             : 
    2116             :     // Allocate the source block.
    2117      268875 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2118      268875 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2119      268875 :     auto blockByteSize = blockSize * elementSize;
    2120             :     unsigned char *srcBlock =
    2121      268875 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2122      268875 :     if (srcBlock == nullptr)
    2123             :     {
    2124           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2125             :                     "GDALRasterBand::Fill(): Out of memory "
    2126             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2127             :                     static_cast<GUIntBig>(blockByteSize));
    2128           0 :         return CE_Failure;
    2129             :     }
    2130             : 
    2131             :     // Initialize the source block.
    2132      268875 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2133      268875 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2134             :                     elementSize, blockSize);
    2135             : 
    2136      268875 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2137             : 
    2138             :     // Write block to block cache
    2139      872406 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2140             :     {
    2141     1501410 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2142             :         {
    2143      897878 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2144      897878 :             if (destBlock == nullptr)
    2145             :             {
    2146           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2147             :                             "GDALRasterBand::Fill(): Error "
    2148             :                             "while retrieving cache block.");
    2149           0 :                 VSIFree(srcBlock);
    2150           0 :                 return CE_Failure;
    2151             :             }
    2152      897878 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2153      897878 :             destBlock->MarkDirty();
    2154      897878 :             destBlock->DropLock();
    2155             :         }
    2156             :     }
    2157             : 
    2158      268875 :     if (bCallLeaveReadWrite)
    2159      267686 :         LeaveReadWrite();
    2160             : 
    2161             :     // Free up the source block
    2162      268875 :     VSIFree(srcBlock);
    2163             : 
    2164      268875 :     return CE_None;
    2165             : }
    2166             : 
    2167             : /************************************************************************/
    2168             : /*                         GDALFillRaster()                             */
    2169             : /************************************************************************/
    2170             : 
    2171             : /**
    2172             :  * \brief Fill this band with a constant value.
    2173             :  *
    2174             :  * @see GDALRasterBand::Fill()
    2175             :  */
    2176      268683 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2177             :                                   double dfImaginaryValue)
    2178             : {
    2179      268683 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2180             : 
    2181      268683 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2182      268683 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2183             : }
    2184             : 
    2185             : /************************************************************************/
    2186             : /*                             GetAccess()                              */
    2187             : /************************************************************************/
    2188             : 
    2189             : /**
    2190             :  * \brief Find out if we have update permission for this band.
    2191             :  *
    2192             :  * This method is the same as the C function GDALGetRasterAccess().
    2193             :  *
    2194             :  * @return Either GA_Update or GA_ReadOnly.
    2195             :  */
    2196             : 
    2197        3040 : GDALAccess GDALRasterBand::GetAccess()
    2198             : 
    2199             : {
    2200        3040 :     return eAccess;
    2201             : }
    2202             : 
    2203             : /************************************************************************/
    2204             : /*                        GDALGetRasterAccess()                         */
    2205             : /************************************************************************/
    2206             : 
    2207             : /**
    2208             :  * \brief Find out if we have update permission for this band.
    2209             :  *
    2210             :  * @see GDALRasterBand::GetAccess()
    2211             :  */
    2212             : 
    2213        2382 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2214             : 
    2215             : {
    2216        2382 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2217             : 
    2218        2382 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2219        2382 :     return poBand->GetAccess();
    2220             : }
    2221             : 
    2222             : /************************************************************************/
    2223             : /*                          GetCategoryNames()                          */
    2224             : /************************************************************************/
    2225             : 
    2226             : /**
    2227             :  * \brief Fetch the list of category names for this raster.
    2228             :  *
    2229             :  * The return list is a "StringList" in the sense of the CPL functions.
    2230             :  * That is a NULL terminated array of strings.  Raster values without
    2231             :  * associated names will have an empty string in the returned list.  The
    2232             :  * first entry in the list is for raster values of zero, and so on.
    2233             :  *
    2234             :  * The returned stringlist should not be altered or freed by the application.
    2235             :  * It may change on the next GDAL call, so please copy it if it is needed
    2236             :  * for any period of time.
    2237             :  *
    2238             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2239             :  *
    2240             :  * @return list of names, or NULL if none.
    2241             :  */
    2242             : 
    2243         262 : char **GDALRasterBand::GetCategoryNames()
    2244             : 
    2245             : {
    2246         262 :     return nullptr;
    2247             : }
    2248             : 
    2249             : /************************************************************************/
    2250             : /*                     GDALGetRasterCategoryNames()                     */
    2251             : /************************************************************************/
    2252             : 
    2253             : /**
    2254             :  * \brief Fetch the list of category names for this raster.
    2255             :  *
    2256             :  * @see GDALRasterBand::GetCategoryNames()
    2257             :  */
    2258             : 
    2259         205 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2260             : 
    2261             : {
    2262         205 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2263             : 
    2264         205 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2265         205 :     return poBand->GetCategoryNames();
    2266             : }
    2267             : 
    2268             : /************************************************************************/
    2269             : /*                          SetCategoryNames()                          */
    2270             : /************************************************************************/
    2271             : 
    2272             : /**
    2273             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2274             :  * \brief Set the category names for this band.
    2275             :  *
    2276             :  * See the GetCategoryNames() method for more on the interpretation of
    2277             :  * category names.
    2278             :  *
    2279             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2280             :  *
    2281             :  * @param papszNames the NULL terminated StringList of category names.  May
    2282             :  * be NULL to just clear the existing list.
    2283             :  *
    2284             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2285             :  * by the driver CE_Failure is returned, but no error message is reported.
    2286             :  */
    2287             : 
    2288             : /**/
    2289             : /**/
    2290             : 
    2291           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2292             : {
    2293           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2294           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2295             :                     "SetCategoryNames() not supported for this dataset.");
    2296             : 
    2297           0 :     return CE_Failure;
    2298             : }
    2299             : 
    2300             : /************************************************************************/
    2301             : /*                        GDALSetCategoryNames()                        */
    2302             : /************************************************************************/
    2303             : 
    2304             : /**
    2305             :  * \brief Set the category names for this band.
    2306             :  *
    2307             :  * @see GDALRasterBand::SetCategoryNames()
    2308             :  */
    2309             : 
    2310           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2311             :                                               CSLConstList papszNames)
    2312             : 
    2313             : {
    2314           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2315             : 
    2316           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2317           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2318             : }
    2319             : 
    2320             : /************************************************************************/
    2321             : /*                           GetNoDataValue()                           */
    2322             : /************************************************************************/
    2323             : 
    2324             : /**
    2325             :  * \brief Fetch the no data value for this band.
    2326             :  *
    2327             :  * If there is no out of data value, an out of range value will generally
    2328             :  * be returned.  The no data value for a band is generally a special marker
    2329             :  * value used to mark pixels that are not valid data.  Such pixels should
    2330             :  * generally not be displayed, nor contribute to analysis operations.
    2331             :  *
    2332             :  * The no data value returned is 'raw', meaning that it has no offset and
    2333             :  * scale applied.
    2334             :  *
    2335             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2336             :  * lossy if the nodata value cannot exactly been represented by a double.
    2337             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2338             :  *
    2339             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2340             :  *
    2341             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2342             :  * is actually associated with this layer.  May be NULL (default).
    2343             :  *
    2344             :  * @return the nodata value for this band.
    2345             :  */
    2346             : 
    2347       13120 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2348             : 
    2349             : {
    2350       13120 :     if (pbSuccess != nullptr)
    2351       13120 :         *pbSuccess = FALSE;
    2352             : 
    2353       13120 :     return -1e10;
    2354             : }
    2355             : 
    2356             : /************************************************************************/
    2357             : /*                      GDALGetRasterNoDataValue()                      */
    2358             : /************************************************************************/
    2359             : 
    2360             : /**
    2361             :  * \brief Fetch the no data value for this band.
    2362             :  *
    2363             :  * @see GDALRasterBand::GetNoDataValue()
    2364             :  */
    2365             : 
    2366      414461 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2367             :                                             int *pbSuccess)
    2368             : 
    2369             : {
    2370      414461 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2371             : 
    2372      414461 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2373      414461 :     return poBand->GetNoDataValue(pbSuccess);
    2374             : }
    2375             : 
    2376             : /************************************************************************/
    2377             : /*                       GetNoDataValueAsInt64()                        */
    2378             : /************************************************************************/
    2379             : 
    2380             : /**
    2381             :  * \brief Fetch the no data value for this band.
    2382             :  *
    2383             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2384             :  *
    2385             :  * If there is no out of data value, an out of range value will generally
    2386             :  * be returned.  The no data value for a band is generally a special marker
    2387             :  * value used to mark pixels that are not valid data.  Such pixels should
    2388             :  * generally not be displayed, nor contribute to analysis operations.
    2389             :  *
    2390             :  * The no data value returned is 'raw', meaning that it has no offset and
    2391             :  * scale applied.
    2392             :  *
    2393             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2394             :  *
    2395             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2396             :  * is actually associated with this layer.  May be NULL (default).
    2397             :  *
    2398             :  * @return the nodata value for this band.
    2399             :  *
    2400             :  * @since GDAL 3.5
    2401             :  */
    2402             : 
    2403           3 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2404             : 
    2405             : {
    2406           3 :     if (pbSuccess != nullptr)
    2407           3 :         *pbSuccess = FALSE;
    2408             : 
    2409           3 :     return std::numeric_limits<int64_t>::min();
    2410             : }
    2411             : 
    2412             : /************************************************************************/
    2413             : /*                   GDALGetRasterNoDataValueAsInt64()                  */
    2414             : /************************************************************************/
    2415             : 
    2416             : /**
    2417             :  * \brief Fetch the no data value for this band.
    2418             :  *
    2419             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2420             :  *
    2421             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2422             :  *
    2423             :  * @since GDAL 3.5
    2424             :  */
    2425             : 
    2426          31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2427             :                                                     int *pbSuccess)
    2428             : 
    2429             : {
    2430          31 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2431             :                       std::numeric_limits<int64_t>::min());
    2432             : 
    2433          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2434          31 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2435             : }
    2436             : 
    2437             : /************************************************************************/
    2438             : /*                       GetNoDataValueAsUInt64()                        */
    2439             : /************************************************************************/
    2440             : 
    2441             : /**
    2442             :  * \brief Fetch the no data value for this band.
    2443             :  *
    2444             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2445             :  *
    2446             :  * If there is no out of data value, an out of range value will generally
    2447             :  * be returned.  The no data value for a band is generally a special marker
    2448             :  * value used to mark pixels that are not valid data.  Such pixels should
    2449             :  * generally not be displayed, nor contribute to analysis operations.
    2450             :  *
    2451             :  * The no data value returned is 'raw', meaning that it has no offset and
    2452             :  * scale applied.
    2453             :  *
    2454             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2455             :  *
    2456             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2457             :  * is actually associated with this layer.  May be NULL (default).
    2458             :  *
    2459             :  * @return the nodata value for this band.
    2460             :  *
    2461             :  * @since GDAL 3.5
    2462             :  */
    2463             : 
    2464           2 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2465             : 
    2466             : {
    2467           2 :     if (pbSuccess != nullptr)
    2468           2 :         *pbSuccess = FALSE;
    2469             : 
    2470           2 :     return std::numeric_limits<uint64_t>::max();
    2471             : }
    2472             : 
    2473             : /************************************************************************/
    2474             : /*                   GDALGetRasterNoDataValueAsUInt64()                  */
    2475             : /************************************************************************/
    2476             : 
    2477             : /**
    2478             :  * \brief Fetch the no data value for this band.
    2479             :  *
    2480             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2481             :  *
    2482             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2483             :  *
    2484             :  * @since GDAL 3.5
    2485             :  */
    2486             : 
    2487          22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2488             :                                                       int *pbSuccess)
    2489             : 
    2490             : {
    2491          22 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2492             :                       std::numeric_limits<uint64_t>::max());
    2493             : 
    2494          22 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2495          22 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2496             : }
    2497             : 
    2498             : /************************************************************************/
    2499             : /*                        SetNoDataValueAsString()                      */
    2500             : /************************************************************************/
    2501             : 
    2502             : /**
    2503             :  * \brief Set the no data value for this band.
    2504             :  *
    2505             :  * Depending on drivers, changing the no data value may or may not have an
    2506             :  * effect on the pixel values of a raster that has just been created. It is
    2507             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2508             :  * the raster to the nodata value.
    2509             :  * In any case, changing an existing no data value, when one already exists and
    2510             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2511             :  * value matched the previous nodata value.
    2512             :  *
    2513             :  * To clear the nodata value, use DeleteNoDataValue().
    2514             :  *
    2515             :  * @param pszNoData the value to set.
    2516             :  * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
    2517             :  *             If the value cannot be exactly represented on the output data
    2518             :  *             type, *pbCannotBeExactlyRepresented will be set to true.
    2519             :  *
    2520             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2521             :  * by the driver, CE_Failure is returned but no error message will have
    2522             :  * been emitted.
    2523             :  *
    2524             :  * @since 3.11
    2525             :  */
    2526             : 
    2527             : CPLErr
    2528         123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
    2529             :                                        bool *pbCannotBeExactlyRepresented)
    2530             : {
    2531         123 :     if (pbCannotBeExactlyRepresented)
    2532         123 :         *pbCannotBeExactlyRepresented = false;
    2533         123 :     if (eDataType == GDT_Int64)
    2534             :     {
    2535           8 :         if (strchr(pszNoData, '.') ||
    2536           3 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2537             :         {
    2538           2 :             char *endptr = nullptr;
    2539           2 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2540           4 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2541           2 :                 GDALIsValueExactAs<int64_t>(dfVal))
    2542             :             {
    2543           0 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
    2544             :             }
    2545             :         }
    2546             :         else
    2547             :         {
    2548             :             try
    2549             :             {
    2550           7 :                 const auto val = std::stoll(pszNoData);
    2551           1 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(val));
    2552             :             }
    2553           2 :             catch (const std::exception &)
    2554             :             {
    2555             :             }
    2556             :         }
    2557             :     }
    2558         118 :     else if (eDataType == GDT_UInt64)
    2559             :     {
    2560           2 :         if (strchr(pszNoData, '.') ||
    2561           1 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2562             :         {
    2563           0 :             char *endptr = nullptr;
    2564           0 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2565           0 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2566           0 :                 GDALIsValueExactAs<uint64_t>(dfVal))
    2567             :             {
    2568           0 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
    2569             :             }
    2570             :         }
    2571             :         else
    2572             :         {
    2573             :             try
    2574             :             {
    2575           1 :                 const auto val = std::stoull(pszNoData);
    2576           1 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
    2577             :             }
    2578           0 :             catch (const std::exception &)
    2579             :             {
    2580             :             }
    2581             :         }
    2582             :     }
    2583         117 :     else if (eDataType == GDT_Float32)
    2584             :     {
    2585          10 :         char *endptr = nullptr;
    2586          10 :         const float fVal = CPLStrtof(pszNoData, &endptr);
    2587          10 :         if (endptr == pszNoData + strlen(pszNoData))
    2588             :         {
    2589          10 :             return SetNoDataValue(double(fVal));
    2590             :         }
    2591             :     }
    2592             :     else
    2593             :     {
    2594         107 :         char *endptr = nullptr;
    2595         107 :         const double dfVal = CPLStrtod(pszNoData, &endptr);
    2596         214 :         if (endptr == pszNoData + strlen(pszNoData) &&
    2597         107 :             GDALIsValueExactAs(dfVal, eDataType))
    2598             :         {
    2599         106 :             return SetNoDataValue(dfVal);
    2600             :         }
    2601             :     }
    2602           5 :     if (pbCannotBeExactlyRepresented)
    2603           5 :         *pbCannotBeExactlyRepresented = true;
    2604           5 :     return CE_Failure;
    2605             : }
    2606             : 
    2607             : /************************************************************************/
    2608             : /*                           SetNoDataValue()                           */
    2609             : /************************************************************************/
    2610             : 
    2611             : /**
    2612             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2613             :  * \brief Set the no data value for this band.
    2614             :  *
    2615             :  * Depending on drivers, changing the no data value may or may not have an
    2616             :  * effect on the pixel values of a raster that has just been created. It is
    2617             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2618             :  * the raster to the nodata value.
    2619             :  * In any case, changing an existing no data value, when one already exists and
    2620             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2621             :  * value matched the previous nodata value.
    2622             :  *
    2623             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2624             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2625             :  * SetNoDataValueAsUInt64() instead.
    2626             :  *
    2627             :  * To clear the nodata value, use DeleteNoDataValue().
    2628             :  *
    2629             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2630             :  *
    2631             :  * @param dfNoData the value to set.
    2632             :  *
    2633             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2634             :  * by the driver, CE_Failure is returned but no error message will have
    2635             :  * been emitted.
    2636             :  */
    2637             : 
    2638             : /**/
    2639             : /**/
    2640             : 
    2641           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2642             : 
    2643             : {
    2644           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2645           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2646             :                     "SetNoDataValue() not supported for this dataset.");
    2647             : 
    2648           0 :     return CE_Failure;
    2649             : }
    2650             : 
    2651             : /************************************************************************/
    2652             : /*                         GDALSetRasterNoDataValue()                   */
    2653             : /************************************************************************/
    2654             : 
    2655             : /**
    2656             :  * \brief Set the no data value for this band.
    2657             :  *
    2658             :  * Depending on drivers, changing the no data value may or may not have an
    2659             :  * effect on the pixel values of a raster that has just been created. It is
    2660             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2661             :  * the raster to the nodata value.
    2662             :  * In any case, changing an existing no data value, when one already exists and
    2663             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2664             :  * value matched the previous nodata value.
    2665             :  *
    2666             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2667             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2668             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2669             :  *
    2670             :  * @see GDALRasterBand::SetNoDataValue()
    2671             :  */
    2672             : 
    2673         994 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2674             :                                             double dfValue)
    2675             : 
    2676             : {
    2677         994 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2678             : 
    2679         994 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2680         994 :     return poBand->SetNoDataValue(dfValue);
    2681             : }
    2682             : 
    2683             : /************************************************************************/
    2684             : /*                       SetNoDataValueAsInt64()                        */
    2685             : /************************************************************************/
    2686             : 
    2687             : /**
    2688             :  * \brief Set the no data value for this band.
    2689             :  *
    2690             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2691             :  *
    2692             :  * Depending on drivers, changing the no data value may or may not have an
    2693             :  * effect on the pixel values of a raster that has just been created. It is
    2694             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2695             :  * the raster to the nodata value.
    2696             :  * In ay case, changing an existing no data value, when one already exists and
    2697             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2698             :  * value matched the previous nodata value.
    2699             :  *
    2700             :  * To clear the nodata value, use DeleteNoDataValue().
    2701             :  *
    2702             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2703             :  *
    2704             :  * @param nNoDataValue the value to set.
    2705             :  *
    2706             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2707             :  * by the driver, CE_Failure is returned but no error message will have
    2708             :  * been emitted.
    2709             :  *
    2710             :  * @since GDAL 3.5
    2711             :  */
    2712             : 
    2713           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2714             : 
    2715             : {
    2716           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2717           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2718             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2719             : 
    2720           0 :     return CE_Failure;
    2721             : }
    2722             : 
    2723             : /************************************************************************/
    2724             : /*                 GDALSetRasterNoDataValueAsInt64()                    */
    2725             : /************************************************************************/
    2726             : 
    2727             : /**
    2728             :  * \brief Set the no data value for this band.
    2729             :  *
    2730             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2731             :  *
    2732             :  * Depending on drivers, changing the no data value may or may not have an
    2733             :  * effect on the pixel values of a raster that has just been created. It is
    2734             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2735             :  * the raster to the nodata value.
    2736             :  * In ay case, changing an existing no data value, when one already exists and
    2737             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2738             :  * value matched the previous nodata value.
    2739             :  *
    2740             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2741             :  *
    2742             :  * @since GDAL 3.5
    2743             :  */
    2744             : 
    2745          23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2746             :                                                    int64_t nValue)
    2747             : 
    2748             : {
    2749          23 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2750             : 
    2751          23 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2752          23 :     return poBand->SetNoDataValueAsInt64(nValue);
    2753             : }
    2754             : 
    2755             : /************************************************************************/
    2756             : /*                       SetNoDataValueAsUInt64()                       */
    2757             : /************************************************************************/
    2758             : 
    2759             : /**
    2760             :  * \brief Set the no data value for this band.
    2761             :  *
    2762             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2763             :  *
    2764             :  * Depending on drivers, changing the no data value may or may not have an
    2765             :  * effect on the pixel values of a raster that has just been created. It is
    2766             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2767             :  * the raster to the nodata value.
    2768             :  * In ay case, changing an existing no data value, when one already exists and
    2769             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2770             :  * value matched the previous nodata value.
    2771             :  *
    2772             :  * To clear the nodata value, use DeleteNoDataValue().
    2773             :  *
    2774             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2775             :  *
    2776             :  * @param nNoDataValue the value to set.
    2777             :  *
    2778             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2779             :  * by the driver, CE_Failure is returned but no error message will have
    2780             :  * been emitted.
    2781             :  *
    2782             :  * @since GDAL 3.5
    2783             :  */
    2784             : 
    2785           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2786             : 
    2787             : {
    2788           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2789           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2790             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2791             : 
    2792           0 :     return CE_Failure;
    2793             : }
    2794             : 
    2795             : /************************************************************************/
    2796             : /*                 GDALSetRasterNoDataValueAsUInt64()                    */
    2797             : /************************************************************************/
    2798             : 
    2799             : /**
    2800             :  * \brief Set the no data value for this band.
    2801             :  *
    2802             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2803             :  *
    2804             :  * Depending on drivers, changing the no data value may or may not have an
    2805             :  * effect on the pixel values of a raster that has just been created. It is
    2806             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2807             :  * the raster to the nodata value.
    2808             :  * In ay case, changing an existing no data value, when one already exists and
    2809             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2810             :  * value matched the previous nodata value.
    2811             :  *
    2812             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2813             :  *
    2814             :  * @since GDAL 3.5
    2815             :  */
    2816             : 
    2817          21 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2818             :                                                     uint64_t nValue)
    2819             : 
    2820             : {
    2821          21 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2822             : 
    2823          21 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2824          21 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2825             : }
    2826             : 
    2827             : /************************************************************************/
    2828             : /*                        DeleteNoDataValue()                           */
    2829             : /************************************************************************/
    2830             : 
    2831             : /**
    2832             :  * \brief Remove the no data value for this band.
    2833             :  *
    2834             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2835             :  *
    2836             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2837             :  * by the driver, CE_Failure is returned but no error message will have
    2838             :  * been emitted.
    2839             :  *
    2840             :  */
    2841             : 
    2842           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2843             : 
    2844             : {
    2845           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2846           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2847             :                     "DeleteNoDataValue() not supported for this dataset.");
    2848             : 
    2849           0 :     return CE_Failure;
    2850             : }
    2851             : 
    2852             : /************************************************************************/
    2853             : /*                       GDALDeleteRasterNoDataValue()                  */
    2854             : /************************************************************************/
    2855             : 
    2856             : /**
    2857             :  * \brief Remove the no data value for this band.
    2858             :  *
    2859             :  * @see GDALRasterBand::DeleteNoDataValue()
    2860             :  *
    2861             :  */
    2862             : 
    2863          53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2864             : 
    2865             : {
    2866          53 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2867             : 
    2868          53 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2869          53 :     return poBand->DeleteNoDataValue();
    2870             : }
    2871             : 
    2872             : /************************************************************************/
    2873             : /*                             GetMaximum()                             */
    2874             : /************************************************************************/
    2875             : 
    2876             : /**
    2877             :  * \brief Fetch the maximum value for this band.
    2878             :  *
    2879             :  * For file formats that don't know this intrinsically, the maximum supported
    2880             :  * value for the data type will generally be returned.
    2881             :  *
    2882             :  * This method is the same as the C function GDALGetRasterMaximum().
    2883             :  *
    2884             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2885             :  * returned value is a tight maximum or not.  May be NULL (default).
    2886             :  *
    2887             :  * @return the maximum raster value (excluding no data pixels)
    2888             :  */
    2889             : 
    2890         538 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2891             : 
    2892             : {
    2893         538 :     const char *pszValue = nullptr;
    2894             : 
    2895         538 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2896             :     {
    2897          47 :         if (pbSuccess != nullptr)
    2898          42 :             *pbSuccess = TRUE;
    2899             : 
    2900          47 :         return CPLAtofM(pszValue);
    2901             :     }
    2902             : 
    2903         491 :     if (pbSuccess != nullptr)
    2904         487 :         *pbSuccess = FALSE;
    2905             : 
    2906         491 :     switch (eDataType)
    2907             :     {
    2908         340 :         case GDT_UInt8:
    2909             :         {
    2910         340 :             EnablePixelTypeSignedByteWarning(false);
    2911             :             const char *pszPixelType =
    2912         340 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2913         340 :             EnablePixelTypeSignedByteWarning(true);
    2914         340 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2915           0 :                 return 127;
    2916             : 
    2917         340 :             return 255;
    2918             :         }
    2919             : 
    2920           1 :         case GDT_Int8:
    2921           1 :             return 127;
    2922             : 
    2923          21 :         case GDT_UInt16:
    2924          21 :             return 65535;
    2925             : 
    2926          24 :         case GDT_Int16:
    2927             :         case GDT_CInt16:
    2928          24 :             return 32767;
    2929             : 
    2930          39 :         case GDT_Int32:
    2931             :         case GDT_CInt32:
    2932          39 :             return 2147483647.0;
    2933             : 
    2934          12 :         case GDT_UInt32:
    2935          12 :             return 4294967295.0;
    2936             : 
    2937           1 :         case GDT_Int64:
    2938           1 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2939             : 
    2940           1 :         case GDT_UInt64:
    2941           1 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2942             : 
    2943           0 :         case GDT_Float16:
    2944             :         case GDT_CFloat16:
    2945           0 :             return 65504.0;
    2946             : 
    2947          30 :         case GDT_Float32:
    2948             :         case GDT_CFloat32:
    2949          30 :             return 4294967295.0;  // Not actually accurate.
    2950             : 
    2951          22 :         case GDT_Float64:
    2952             :         case GDT_CFloat64:
    2953          22 :             return 4294967295.0;  // Not actually accurate.
    2954             : 
    2955           0 :         case GDT_Unknown:
    2956             :         case GDT_TypeCount:
    2957           0 :             break;
    2958             :     }
    2959           0 :     return 4294967295.0;  // Not actually accurate.
    2960             : }
    2961             : 
    2962             : /************************************************************************/
    2963             : /*                        GDALGetRasterMaximum()                        */
    2964             : /************************************************************************/
    2965             : 
    2966             : /**
    2967             :  * \brief Fetch the maximum value for this band.
    2968             :  *
    2969             :  * @see GDALRasterBand::GetMaximum()
    2970             :  */
    2971             : 
    2972         338 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2973             : 
    2974             : {
    2975         338 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2976             : 
    2977         338 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2978         338 :     return poBand->GetMaximum(pbSuccess);
    2979             : }
    2980             : 
    2981             : /************************************************************************/
    2982             : /*                             GetMinimum()                             */
    2983             : /************************************************************************/
    2984             : 
    2985             : /**
    2986             :  * \brief Fetch the minimum value for this band.
    2987             :  *
    2988             :  * For file formats that don't know this intrinsically, the minimum supported
    2989             :  * value for the data type will generally be returned.
    2990             :  *
    2991             :  * This method is the same as the C function GDALGetRasterMinimum().
    2992             :  *
    2993             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2994             :  * returned value is a tight minimum or not.  May be NULL (default).
    2995             :  *
    2996             :  * @return the minimum raster value (excluding no data pixels)
    2997             :  */
    2998             : 
    2999         546 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    3000             : 
    3001             : {
    3002         546 :     const char *pszValue = nullptr;
    3003             : 
    3004         546 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    3005             :     {
    3006          52 :         if (pbSuccess != nullptr)
    3007          47 :             *pbSuccess = TRUE;
    3008             : 
    3009          52 :         return CPLAtofM(pszValue);
    3010             :     }
    3011             : 
    3012         494 :     if (pbSuccess != nullptr)
    3013         490 :         *pbSuccess = FALSE;
    3014             : 
    3015         494 :     switch (eDataType)
    3016             :     {
    3017         343 :         case GDT_UInt8:
    3018             :         {
    3019         343 :             EnablePixelTypeSignedByteWarning(false);
    3020             :             const char *pszPixelType =
    3021         343 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    3022         343 :             EnablePixelTypeSignedByteWarning(true);
    3023         343 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    3024           0 :                 return -128;
    3025             : 
    3026         343 :             return 0;
    3027             :         }
    3028             : 
    3029           1 :         case GDT_Int8:
    3030           1 :             return -128;
    3031             : 
    3032          21 :         case GDT_UInt16:
    3033          21 :             return 0;
    3034             : 
    3035          24 :         case GDT_Int16:
    3036             :         case GDT_CInt16:
    3037          24 :             return -32768;
    3038             : 
    3039          39 :         case GDT_Int32:
    3040             :         case GDT_CInt32:
    3041          39 :             return -2147483648.0;
    3042             : 
    3043          12 :         case GDT_UInt32:
    3044          12 :             return 0;
    3045             : 
    3046           1 :         case GDT_Int64:
    3047           1 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    3048             : 
    3049           1 :         case GDT_UInt64:
    3050           1 :             return 0;
    3051             : 
    3052           0 :         case GDT_Float16:
    3053             :         case GDT_CFloat16:
    3054           0 :             return -65504.0;
    3055             : 
    3056          30 :         case GDT_Float32:
    3057             :         case GDT_CFloat32:
    3058          30 :             return -4294967295.0;  // Not actually accurate.
    3059             : 
    3060          22 :         case GDT_Float64:
    3061             :         case GDT_CFloat64:
    3062          22 :             return -4294967295.0;  // Not actually accurate.
    3063             : 
    3064           0 :         case GDT_Unknown:
    3065             :         case GDT_TypeCount:
    3066           0 :             break;
    3067             :     }
    3068           0 :     return -4294967295.0;  // Not actually accurate.
    3069             : }
    3070             : 
    3071             : /************************************************************************/
    3072             : /*                        GDALGetRasterMinimum()                        */
    3073             : /************************************************************************/
    3074             : 
    3075             : /**
    3076             :  * \brief Fetch the minimum value for this band.
    3077             :  *
    3078             :  * @see GDALRasterBand::GetMinimum()
    3079             :  */
    3080             : 
    3081         348 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    3082             : 
    3083             : {
    3084         348 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    3085             : 
    3086         348 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3087         348 :     return poBand->GetMinimum(pbSuccess);
    3088             : }
    3089             : 
    3090             : /************************************************************************/
    3091             : /*                       GetColorInterpretation()                       */
    3092             : /************************************************************************/
    3093             : 
    3094             : /**
    3095             :  * \brief How should this band be interpreted as color?
    3096             :  *
    3097             :  * GCI_Undefined is returned when the format doesn't know anything
    3098             :  * about the color interpretation.
    3099             :  *
    3100             :  * This method is the same as the C function
    3101             :  * GDALGetRasterColorInterpretation().
    3102             :  *
    3103             :  * @return color interpretation value for band.
    3104             :  */
    3105             : 
    3106         163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    3107             : 
    3108             : {
    3109         163 :     return GCI_Undefined;
    3110             : }
    3111             : 
    3112             : /************************************************************************/
    3113             : /*                  GDALGetRasterColorInterpretation()                  */
    3114             : /************************************************************************/
    3115             : 
    3116             : /**
    3117             :  * \brief How should this band be interpreted as color?
    3118             :  *
    3119             :  * @see GDALRasterBand::GetColorInterpretation()
    3120             :  */
    3121             : 
    3122             : GDALColorInterp CPL_STDCALL
    3123        5728 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    3124             : 
    3125             : {
    3126        5728 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    3127             : 
    3128        5728 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3129        5728 :     return poBand->GetColorInterpretation();
    3130             : }
    3131             : 
    3132             : /************************************************************************/
    3133             : /*                       SetColorInterpretation()                       */
    3134             : /************************************************************************/
    3135             : 
    3136             : /**
    3137             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3138             :  * \brief Set color interpretation of a band.
    3139             :  *
    3140             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3141             :  *
    3142             :  * @param eColorInterp the new color interpretation to apply to this band.
    3143             :  *
    3144             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3145             :  */
    3146             : 
    3147             : /**/
    3148             : /**/
    3149             : 
    3150           3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3151             : 
    3152             : {
    3153           3 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3154           3 :         ReportError(CE_Failure, CPLE_NotSupported,
    3155             :                     "SetColorInterpretation() not supported for this dataset.");
    3156           3 :     return CE_Failure;
    3157             : }
    3158             : 
    3159             : /************************************************************************/
    3160             : /*                  GDALSetRasterColorInterpretation()                  */
    3161             : /************************************************************************/
    3162             : 
    3163             : /**
    3164             :  * \brief Set color interpretation of a band.
    3165             :  *
    3166             :  * @see GDALRasterBand::SetColorInterpretation()
    3167             :  */
    3168             : 
    3169        1859 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3170             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3171             : 
    3172             : {
    3173        1859 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3174             : 
    3175        1859 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3176        1859 :     return poBand->SetColorInterpretation(eColorInterp);
    3177             : }
    3178             : 
    3179             : /************************************************************************/
    3180             : /*                           GetColorTable()                            */
    3181             : /************************************************************************/
    3182             : 
    3183             : /**
    3184             :  * \brief Fetch the color table associated with band.
    3185             :  *
    3186             :  * If there is no associated color table, the return result is NULL.  The
    3187             :  * returned color table remains owned by the GDALRasterBand, and can't
    3188             :  * be depended on for long, nor should it ever be modified by the caller.
    3189             :  *
    3190             :  * This method is the same as the C function GDALGetRasterColorTable().
    3191             :  *
    3192             :  * @return internal color table, or NULL.
    3193             :  */
    3194             : 
    3195         213 : GDALColorTable *GDALRasterBand::GetColorTable()
    3196             : 
    3197             : {
    3198         213 :     return nullptr;
    3199             : }
    3200             : 
    3201             : /************************************************************************/
    3202             : /*                      GDALGetRasterColorTable()                       */
    3203             : /************************************************************************/
    3204             : 
    3205             : /**
    3206             :  * \brief Fetch the color table associated with band.
    3207             :  *
    3208             :  * @see GDALRasterBand::GetColorTable()
    3209             :  */
    3210             : 
    3211        1989 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3212             : 
    3213             : {
    3214        1989 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3215             : 
    3216        1989 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3217        1989 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3218             : }
    3219             : 
    3220             : /************************************************************************/
    3221             : /*                           SetColorTable()                            */
    3222             : /************************************************************************/
    3223             : 
    3224             : /**
    3225             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3226             :  * \brief Set the raster color table.
    3227             :  *
    3228             :  * The driver will make a copy of all desired data in the colortable.  It
    3229             :  * remains owned by the caller after the call.
    3230             :  *
    3231             :  * This method is the same as the C function GDALSetRasterColorTable().
    3232             :  *
    3233             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3234             :  * table (where supported).
    3235             :  *
    3236             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3237             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3238             :  * error is issued.
    3239             :  */
    3240             : 
    3241             : /**/
    3242             : /**/
    3243             : 
    3244           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3245             : 
    3246             : {
    3247           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3248           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3249             :                     "SetColorTable() not supported for this dataset.");
    3250           0 :     return CE_Failure;
    3251             : }
    3252             : 
    3253             : /************************************************************************/
    3254             : /*                      GDALSetRasterColorTable()                       */
    3255             : /************************************************************************/
    3256             : 
    3257             : /**
    3258             :  * \brief Set the raster color table.
    3259             :  *
    3260             :  * @see GDALRasterBand::SetColorTable()
    3261             :  */
    3262             : 
    3263          78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3264             :                                            GDALColorTableH hCT)
    3265             : 
    3266             : {
    3267          78 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3268             : 
    3269          78 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3270          78 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3271             : }
    3272             : 
    3273             : /************************************************************************/
    3274             : /*                       HasArbitraryOverviews()                        */
    3275             : /************************************************************************/
    3276             : 
    3277             : /**
    3278             :  * \brief Check for arbitrary overviews.
    3279             :  *
    3280             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3281             :  * overviews efficiently, such as is the case with OGDI over a network.
    3282             :  * Datastores with arbitrary overviews don't generally have any fixed
    3283             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3284             :  * to get overview data efficiently.
    3285             :  *
    3286             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3287             :  *
    3288             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3289             :  * FALSE.
    3290             :  */
    3291             : 
    3292         274 : int GDALRasterBand::HasArbitraryOverviews()
    3293             : 
    3294             : {
    3295         274 :     return FALSE;
    3296             : }
    3297             : 
    3298             : /************************************************************************/
    3299             : /*                     GDALHasArbitraryOverviews()                      */
    3300             : /************************************************************************/
    3301             : 
    3302             : /**
    3303             :  * \brief Check for arbitrary overviews.
    3304             :  *
    3305             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3306             :  */
    3307             : 
    3308         195 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3309             : 
    3310             : {
    3311         195 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3312             : 
    3313         195 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3314         195 :     return poBand->HasArbitraryOverviews();
    3315             : }
    3316             : 
    3317             : /************************************************************************/
    3318             : /*                          GetOverviewCount()                          */
    3319             : /************************************************************************/
    3320             : 
    3321             : /**
    3322             :  * \brief Return the number of overview layers available.
    3323             :  *
    3324             :  * This method is the same as the C function GDALGetOverviewCount().
    3325             :  *
    3326             :  * @return overview count, zero if none.
    3327             :  */
    3328             : 
    3329     1066480 : int GDALRasterBand::GetOverviewCount()
    3330             : 
    3331             : {
    3332     1723240 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3333      656749 :         poDS->AreOverviewsEnabled())
    3334      656750 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3335             : 
    3336      409735 :     return 0;
    3337             : }
    3338             : 
    3339             : /************************************************************************/
    3340             : /*                        GDALGetOverviewCount()                        */
    3341             : /************************************************************************/
    3342             : 
    3343             : /**
    3344             :  * \brief Return the number of overview layers available.
    3345             :  *
    3346             :  * @see GDALRasterBand::GetOverviewCount()
    3347             :  */
    3348             : 
    3349        3302 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3350             : 
    3351             : {
    3352        3302 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3353             : 
    3354        3302 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3355        3302 :     return poBand->GetOverviewCount();
    3356             : }
    3357             : 
    3358             : /************************************************************************/
    3359             : /*                            GetOverview()                             */
    3360             : /************************************************************************/
    3361             : 
    3362             : /**
    3363             :  * \brief Fetch overview raster band object.
    3364             :  *
    3365             :  * This method is the same as the C function GDALGetOverview().
    3366             :  *
    3367             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3368             :  *
    3369             :  * @return overview GDALRasterBand.
    3370             :  */
    3371             : 
    3372         942 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3373             : 
    3374             : {
    3375        1732 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3376         790 :         poDS->AreOverviewsEnabled())
    3377         790 :         return poDS->oOvManager.GetOverview(nBand, i);
    3378             : 
    3379         152 :     return nullptr;
    3380             : }
    3381             : 
    3382             : /************************************************************************/
    3383             : /*                          GDALGetOverview()                           */
    3384             : /************************************************************************/
    3385             : 
    3386             : /**
    3387             :  * \brief Fetch overview raster band object.
    3388             :  *
    3389             :  * @see GDALRasterBand::GetOverview()
    3390             :  */
    3391             : 
    3392        5641 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3393             : 
    3394             : {
    3395        5641 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3396             : 
    3397        5641 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3398        5641 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3399             : }
    3400             : 
    3401             : /************************************************************************/
    3402             : /*                      GetRasterSampleOverview()                       */
    3403             : /************************************************************************/
    3404             : 
    3405             : /**
    3406             :  * \brief Fetch best sampling overview.
    3407             :  *
    3408             :  * Returns the most reduced overview of the given band that still satisfies
    3409             :  * the desired number of samples.  This function can be used with zero
    3410             :  * as the number of desired samples to fetch the most reduced overview.
    3411             :  * The same band as was passed in will be returned if it has not overviews,
    3412             :  * or if none of the overviews have enough samples.
    3413             :  *
    3414             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3415             :  * and GDALGetRasterSampleOverviewEx().
    3416             :  *
    3417             :  * @param nDesiredSamples the returned band will have at least this many
    3418             :  * pixels.
    3419             :  *
    3420             :  * @return optimal overview or the band itself.
    3421             :  */
    3422             : 
    3423             : GDALRasterBand *
    3424        2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3425             : 
    3426             : {
    3427        2006 :     GDALRasterBand *poBestBand = this;
    3428             : 
    3429        2006 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3430             : 
    3431        4023 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3432             :     {
    3433        2017 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3434             : 
    3435        2017 :         if (poOBand == nullptr)
    3436           0 :             continue;
    3437             : 
    3438             :         const double dfOSamples =
    3439        2017 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3440             : 
    3441        2017 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3442             :         {
    3443        2014 :             dfBestSamples = dfOSamples;
    3444        2014 :             poBestBand = poOBand;
    3445             :         }
    3446             :     }
    3447             : 
    3448        2006 :     return poBestBand;
    3449             : }
    3450             : 
    3451             : /************************************************************************/
    3452             : /*                    GDALGetRasterSampleOverview()                     */
    3453             : /************************************************************************/
    3454             : 
    3455             : /**
    3456             :  * \brief Fetch best sampling overview.
    3457             :  *
    3458             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3459             :  * billion samples.
    3460             :  *
    3461             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3462             :  * @see GDALGetRasterSampleOverviewEx()
    3463             :  */
    3464             : 
    3465           0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3466             :                                                         int nDesiredSamples)
    3467             : 
    3468             : {
    3469           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3470             : 
    3471           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3472           0 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3473           0 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3474             : }
    3475             : 
    3476             : /************************************************************************/
    3477             : /*                    GDALGetRasterSampleOverviewEx()                   */
    3478             : /************************************************************************/
    3479             : 
    3480             : /**
    3481             :  * \brief Fetch best sampling overview.
    3482             :  *
    3483             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3484             :  */
    3485             : 
    3486             : GDALRasterBandH CPL_STDCALL
    3487        2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3488             : 
    3489             : {
    3490        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3491             : 
    3492        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3493        2000 :     return GDALRasterBand::ToHandle(
    3494        4000 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3495             : }
    3496             : 
    3497             : /************************************************************************/
    3498             : /*                           BuildOverviews()                           */
    3499             : /************************************************************************/
    3500             : 
    3501             : /**
    3502             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3503             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3504             :  *
    3505             :  * If the operation is unsupported for the indicated dataset, then
    3506             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3507             :  * CPLE_NotSupported.
    3508             :  *
    3509             :  * WARNING: Most formats don't support per-band overview computation, but
    3510             :  * require that overviews are computed for all bands of a dataset, using
    3511             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3512             :  * is the HFA driver which supports this method.
    3513             :  *
    3514             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3515             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3516             :  * applied.
    3517             :  * @param nOverviews number of overviews to build.
    3518             :  * @param panOverviewList the list of overview decimation factors to build.
    3519             :  * @param pfnProgress a function to call to report progress, or NULL.
    3520             :  * @param pProgressData application data to pass to the progress function.
    3521             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3522             :  *                     key=value pairs, or NULL
    3523             :  *
    3524             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3525             :  */
    3526             : 
    3527             : /**/
    3528             : /**/
    3529             : 
    3530           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3531             :                                       int /*nOverviews*/,
    3532             :                                       const int * /*panOverviewList*/,
    3533             :                                       GDALProgressFunc /*pfnProgress*/,
    3534             :                                       void * /*pProgressData*/,
    3535             :                                       CSLConstList /* papszOptions */)
    3536             : 
    3537             : {
    3538           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3539             :                 "BuildOverviews() not supported for this dataset.");
    3540             : 
    3541           0 :     return (CE_Failure);
    3542             : }
    3543             : 
    3544             : /************************************************************************/
    3545             : /*                             GetOffset()                              */
    3546             : /************************************************************************/
    3547             : 
    3548             : /**
    3549             :  * \brief Fetch the raster value offset.
    3550             :  *
    3551             :  * This value (in combination with the GetScale() value) can be used to
    3552             :  * transform raw pixel values into the units returned by GetUnitType().
    3553             :  * For example this might be used to store elevations in GUInt16 bands
    3554             :  * with a precision of 0.1, and starting from -100.
    3555             :  *
    3556             :  * Units value = (raw value * scale) + offset
    3557             :  *
    3558             :  * Note that applying scale and offset is of the responsibility of the user,
    3559             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3560             :  *
    3561             :  * For file formats that don't know this intrinsically a value of zero
    3562             :  * is returned.
    3563             :  *
    3564             :  * This method is the same as the C function GDALGetRasterOffset().
    3565             :  *
    3566             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3567             :  * returned value is meaningful or not.  May be NULL (default).
    3568             :  *
    3569             :  * @return the raster offset.
    3570             :  */
    3571             : 
    3572         445 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3573             : 
    3574             : {
    3575         445 :     if (pbSuccess != nullptr)
    3576         336 :         *pbSuccess = FALSE;
    3577             : 
    3578         445 :     return 0.0;
    3579             : }
    3580             : 
    3581             : /************************************************************************/
    3582             : /*                        GDALGetRasterOffset()                         */
    3583             : /************************************************************************/
    3584             : 
    3585             : /**
    3586             :  * \brief Fetch the raster value offset.
    3587             :  *
    3588             :  * @see GDALRasterBand::GetOffset()
    3589             :  */
    3590             : 
    3591         399 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3592             : 
    3593             : {
    3594         399 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3595             : 
    3596         399 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3597         399 :     return poBand->GetOffset(pbSuccess);
    3598             : }
    3599             : 
    3600             : /************************************************************************/
    3601             : /*                             SetOffset()                              */
    3602             : /************************************************************************/
    3603             : 
    3604             : /**
    3605             :  * \fn GDALRasterBand::SetOffset(double)
    3606             :  * \brief Set scaling offset.
    3607             :  *
    3608             :  * Very few formats implement this method.   When not implemented it will
    3609             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3610             :  *
    3611             :  * This method is the same as the C function GDALSetRasterOffset().
    3612             :  *
    3613             :  * @param dfNewOffset the new offset.
    3614             :  *
    3615             :  * @return CE_None or success or CE_Failure on failure.
    3616             :  */
    3617             : 
    3618             : /**/
    3619             : /**/
    3620             : 
    3621           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3622             : {
    3623           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3624           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3625             :                     "SetOffset() not supported on this raster band.");
    3626             : 
    3627           0 :     return CE_Failure;
    3628             : }
    3629             : 
    3630             : /************************************************************************/
    3631             : /*                        GDALSetRasterOffset()                         */
    3632             : /************************************************************************/
    3633             : 
    3634             : /**
    3635             :  * \brief Set scaling offset.
    3636             :  *
    3637             :  * @see GDALRasterBand::SetOffset()
    3638             :  */
    3639             : 
    3640          86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3641             :                                        double dfNewOffset)
    3642             : 
    3643             : {
    3644          86 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3645             : 
    3646          86 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3647          86 :     return poBand->SetOffset(dfNewOffset);
    3648             : }
    3649             : 
    3650             : /************************************************************************/
    3651             : /*                              GetScale()                              */
    3652             : /************************************************************************/
    3653             : 
    3654             : /**
    3655             :  * \brief Fetch the raster value scale.
    3656             :  *
    3657             :  * This value (in combination with the GetOffset() value) can be used to
    3658             :  * transform raw pixel values into the units returned by GetUnitType().
    3659             :  * For example this might be used to store elevations in GUInt16 bands
    3660             :  * with a precision of 0.1, and starting from -100.
    3661             :  *
    3662             :  * Units value = (raw value * scale) + offset
    3663             :  *
    3664             :  * Note that applying scale and offset is of the responsibility of the user,
    3665             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3666             :  *
    3667             :  * For file formats that don't know this intrinsically a value of one
    3668             :  * is returned.
    3669             :  *
    3670             :  * This method is the same as the C function GDALGetRasterScale().
    3671             :  *
    3672             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3673             :  * returned value is meaningful or not.  May be NULL (default).
    3674             :  *
    3675             :  * @return the raster scale.
    3676             :  */
    3677             : 
    3678         445 : double GDALRasterBand::GetScale(int *pbSuccess)
    3679             : 
    3680             : {
    3681         445 :     if (pbSuccess != nullptr)
    3682         336 :         *pbSuccess = FALSE;
    3683             : 
    3684         445 :     return 1.0;
    3685             : }
    3686             : 
    3687             : /************************************************************************/
    3688             : /*                         GDALGetRasterScale()                         */
    3689             : /************************************************************************/
    3690             : 
    3691             : /**
    3692             :  * \brief Fetch the raster value scale.
    3693             :  *
    3694             :  * @see GDALRasterBand::GetScale()
    3695             :  */
    3696             : 
    3697         397 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3698             : 
    3699             : {
    3700         397 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3701             : 
    3702         397 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3703         397 :     return poBand->GetScale(pbSuccess);
    3704             : }
    3705             : 
    3706             : /************************************************************************/
    3707             : /*                              SetScale()                              */
    3708             : /************************************************************************/
    3709             : 
    3710             : /**
    3711             :  * \fn GDALRasterBand::SetScale(double)
    3712             :  * \brief Set scaling ratio.
    3713             :  *
    3714             :  * Very few formats implement this method.   When not implemented it will
    3715             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3716             :  *
    3717             :  * This method is the same as the C function GDALSetRasterScale().
    3718             :  *
    3719             :  * @param dfNewScale the new scale.
    3720             :  *
    3721             :  * @return CE_None or success or CE_Failure on failure.
    3722             :  */
    3723             : 
    3724             : /**/
    3725             : /**/
    3726             : 
    3727           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3728             : 
    3729             : {
    3730           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3731           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3732             :                     "SetScale() not supported on this raster band.");
    3733             : 
    3734           0 :     return CE_Failure;
    3735             : }
    3736             : 
    3737             : /************************************************************************/
    3738             : /*                        GDALSetRasterScale()                          */
    3739             : /************************************************************************/
    3740             : 
    3741             : /**
    3742             :  * \brief Set scaling ratio.
    3743             :  *
    3744             :  * @see GDALRasterBand::SetScale()
    3745             :  */
    3746             : 
    3747          87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3748             : 
    3749             : {
    3750          87 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3751             : 
    3752          87 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3753          87 :     return poBand->SetScale(dfNewOffset);
    3754             : }
    3755             : 
    3756             : /************************************************************************/
    3757             : /*                            GetUnitType()                             */
    3758             : /************************************************************************/
    3759             : 
    3760             : /**
    3761             :  * \brief Return raster unit type.
    3762             :  *
    3763             :  * Return a name for the units of this raster's values.  For instance, it
    3764             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3765             :  * units are available, a value of "" will be returned.  The returned string
    3766             :  * should not be modified, nor freed by the calling application.
    3767             :  *
    3768             :  * This method is the same as the C function GDALGetRasterUnitType().
    3769             :  *
    3770             :  * @return unit name string.
    3771             :  */
    3772             : 
    3773         165 : const char *GDALRasterBand::GetUnitType()
    3774             : 
    3775             : {
    3776         165 :     return "";
    3777             : }
    3778             : 
    3779             : /************************************************************************/
    3780             : /*                       GDALGetRasterUnitType()                        */
    3781             : /************************************************************************/
    3782             : 
    3783             : /**
    3784             :  * \brief Return raster unit type.
    3785             :  *
    3786             :  * @see GDALRasterBand::GetUnitType()
    3787             :  */
    3788             : 
    3789        1487 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3790             : 
    3791             : {
    3792        1487 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3793             : 
    3794        1487 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3795        1487 :     return poBand->GetUnitType();
    3796             : }
    3797             : 
    3798             : /************************************************************************/
    3799             : /*                            SetUnitType()                             */
    3800             : /************************************************************************/
    3801             : 
    3802             : /**
    3803             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3804             :  * \brief Set unit type.
    3805             :  *
    3806             :  * Set the unit type for a raster band.  Values should be one of
    3807             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3808             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3809             :  *
    3810             :  * This method is the same as the C function GDALSetRasterUnitType().
    3811             :  *
    3812             :  * @param pszNewValue the new unit type value.
    3813             :  *
    3814             :  * @return CE_None on success or CE_Failure if not successful, or
    3815             :  * unsupported.
    3816             :  */
    3817             : 
    3818             : /**/
    3819             : /**/
    3820             : 
    3821           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3822             : 
    3823             : {
    3824           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3825           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3826             :                     "SetUnitType() not supported on this raster band.");
    3827           0 :     return CE_Failure;
    3828             : }
    3829             : 
    3830             : /************************************************************************/
    3831             : /*                       GDALSetRasterUnitType()                        */
    3832             : /************************************************************************/
    3833             : 
    3834             : /**
    3835             :  * \brief Set unit type.
    3836             :  *
    3837             :  * @see GDALRasterBand::SetUnitType()
    3838             :  *
    3839             :  */
    3840             : 
    3841          96 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3842             :                                          const char *pszNewValue)
    3843             : 
    3844             : {
    3845          96 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3846             : 
    3847          96 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3848          96 :     return poBand->SetUnitType(pszNewValue);
    3849             : }
    3850             : 
    3851             : /************************************************************************/
    3852             : /*                              GetXSize()                              */
    3853             : /************************************************************************/
    3854             : 
    3855             : /**
    3856             :  * \brief Fetch XSize of raster.
    3857             :  *
    3858             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3859             :  *
    3860             :  * @return the width in pixels of this band.
    3861             :  */
    3862             : 
    3863     8285610 : int GDALRasterBand::GetXSize() const
    3864             : 
    3865             : {
    3866     8285610 :     return nRasterXSize;
    3867             : }
    3868             : 
    3869             : /************************************************************************/
    3870             : /*                       GDALGetRasterBandXSize()                       */
    3871             : /************************************************************************/
    3872             : 
    3873             : /**
    3874             :  * \brief Fetch XSize of raster.
    3875             :  *
    3876             :  * @see GDALRasterBand::GetXSize()
    3877             :  */
    3878             : 
    3879       57939 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3880             : 
    3881             : {
    3882       57939 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3883             : 
    3884       57939 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3885       57939 :     return poBand->GetXSize();
    3886             : }
    3887             : 
    3888             : /************************************************************************/
    3889             : /*                              GetYSize()                              */
    3890             : /************************************************************************/
    3891             : 
    3892             : /**
    3893             :  * \brief Fetch YSize of raster.
    3894             :  *
    3895             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3896             :  *
    3897             :  * @return the height in pixels of this band.
    3898             :  */
    3899             : 
    3900     4502800 : int GDALRasterBand::GetYSize() const
    3901             : 
    3902             : {
    3903     4502800 :     return nRasterYSize;
    3904             : }
    3905             : 
    3906             : /************************************************************************/
    3907             : /*                       GDALGetRasterBandYSize()                       */
    3908             : /************************************************************************/
    3909             : 
    3910             : /**
    3911             :  * \brief Fetch YSize of raster.
    3912             :  *
    3913             :  * @see GDALRasterBand::GetYSize()
    3914             :  */
    3915             : 
    3916       56802 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3917             : 
    3918             : {
    3919       56802 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3920             : 
    3921       56802 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3922       56802 :     return poBand->GetYSize();
    3923             : }
    3924             : 
    3925             : /************************************************************************/
    3926             : /*                              GetBand()                               */
    3927             : /************************************************************************/
    3928             : 
    3929             : /**
    3930             :  * \brief Fetch the band number.
    3931             :  *
    3932             :  * This method returns the band that this GDALRasterBand objects represents
    3933             :  * within its dataset.  This method may return a value of 0 to indicate
    3934             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3935             :  * such as GDALRasterBands serving as overviews.
    3936             :  *
    3937             :  * This method is the same as the C function GDALGetBandNumber().
    3938             :  *
    3939             :  * @return band number (1+) or 0 if the band number isn't known.
    3940             :  */
    3941             : 
    3942      150830 : int GDALRasterBand::GetBand() const
    3943             : 
    3944             : {
    3945      150830 :     return nBand;
    3946             : }
    3947             : 
    3948             : /************************************************************************/
    3949             : /*                         GDALGetBandNumber()                          */
    3950             : /************************************************************************/
    3951             : 
    3952             : /**
    3953             :  * \brief Fetch the band number.
    3954             :  *
    3955             :  * @see GDALRasterBand::GetBand()
    3956             :  */
    3957             : 
    3958         208 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3959             : 
    3960             : {
    3961         208 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3962             : 
    3963         208 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3964         208 :     return poBand->GetBand();
    3965             : }
    3966             : 
    3967             : /************************************************************************/
    3968             : /*                             GetDataset()                             */
    3969             : /************************************************************************/
    3970             : 
    3971             : /**
    3972             :  * \brief Fetch the owning dataset handle.
    3973             :  *
    3974             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3975             :  * such as overviews or other "freestanding" bands.
    3976             :  *
    3977             :  * This method is the same as the C function GDALGetBandDataset().
    3978             :  *
    3979             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3980             :  * NULL if this cannot be determined.
    3981             :  */
    3982             : 
    3983     5253630 : GDALDataset *GDALRasterBand::GetDataset() const
    3984             : 
    3985             : {
    3986     5253630 :     return poDS;
    3987             : }
    3988             : 
    3989             : /************************************************************************/
    3990             : /*                         GDALGetBandDataset()                         */
    3991             : /************************************************************************/
    3992             : 
    3993             : /**
    3994             :  * \brief Fetch the owning dataset handle.
    3995             :  *
    3996             :  * @see GDALRasterBand::GetDataset()
    3997             :  */
    3998             : 
    3999         355 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    4000             : 
    4001             : {
    4002         355 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    4003             : 
    4004         355 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4005         355 :     return GDALDataset::ToHandle(poBand->GetDataset());
    4006             : }
    4007             : 
    4008             : /************************************************************************/
    4009             : /*                        ComputeFloat16NoDataValue()                     */
    4010             : /************************************************************************/
    4011             : 
    4012        3014 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    4013             :                                              double dfNoDataValue,
    4014             :                                              int &bGotNoDataValue,
    4015             :                                              GFloat16 &fNoDataValue,
    4016             :                                              bool &bGotFloat16NoDataValue)
    4017             : {
    4018        3014 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    4019             :     {
    4020           1 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4021           1 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    4022             :         {
    4023           1 :             fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    4024           1 :             bGotFloat16NoDataValue = true;
    4025           1 :             bGotNoDataValue = false;
    4026             :         }
    4027             :     }
    4028        3014 : }
    4029             : 
    4030             : /************************************************************************/
    4031             : /*                        ComputeFloatNoDataValue()                     */
    4032             : /************************************************************************/
    4033             : 
    4034        3014 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    4035             :                                            double dfNoDataValue,
    4036             :                                            int &bGotNoDataValue,
    4037             :                                            float &fNoDataValue,
    4038             :                                            bool &bGotFloatNoDataValue)
    4039             : {
    4040        3014 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    4041             :     {
    4042          91 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4043          91 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    4044             :         {
    4045          91 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    4046          91 :             bGotFloatNoDataValue = true;
    4047          91 :             bGotNoDataValue = false;
    4048             :         }
    4049             :     }
    4050        3014 : }
    4051             : 
    4052             : /************************************************************************/
    4053             : /*                        struct GDALNoDataValues                       */
    4054             : /************************************************************************/
    4055             : 
    4056             : /**
    4057             :  * \brief No-data-values for all types
    4058             :  *
    4059             :  * The functions below pass various no-data-values around. To avoid
    4060             :  * long argument lists, this struct collects the no-data-values for
    4061             :  * all types into a single, convenient place.
    4062             :  **/
    4063             : 
    4064             : struct GDALNoDataValues
    4065             : {
    4066             :     int bGotNoDataValue;
    4067             :     double dfNoDataValue;
    4068             : 
    4069             :     bool bGotInt64NoDataValue;
    4070             :     int64_t nInt64NoDataValue;
    4071             : 
    4072             :     bool bGotUInt64NoDataValue;
    4073             :     uint64_t nUInt64NoDataValue;
    4074             : 
    4075             :     bool bGotFloatNoDataValue;
    4076             :     float fNoDataValue;
    4077             : 
    4078             :     bool bGotFloat16NoDataValue;
    4079             :     GFloat16 hfNoDataValue;
    4080             : 
    4081        3106 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    4082        3106 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    4083             :           bGotInt64NoDataValue(false), nInt64NoDataValue(0),
    4084             :           bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
    4085             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    4086        3106 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    4087             :     {
    4088        3106 :         if (eDataType == GDT_Int64)
    4089             :         {
    4090          58 :             int nGot = false;
    4091          58 :             nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
    4092          58 :             bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
    4093          58 :             if (bGotInt64NoDataValue)
    4094             :             {
    4095           6 :                 dfNoDataValue = static_cast<double>(nInt64NoDataValue);
    4096           6 :                 bGotNoDataValue =
    4097           6 :                     nInt64NoDataValue <=
    4098          12 :                         std::numeric_limits<int64_t>::max() - 1024 &&
    4099           6 :                     static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
    4100             :             }
    4101             :             else
    4102          52 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4103             :         }
    4104        3048 :         else if (eDataType == GDT_UInt64)
    4105             :         {
    4106          34 :             int nGot = false;
    4107          34 :             nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
    4108          34 :             bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
    4109          34 :             if (bGotUInt64NoDataValue)
    4110             :             {
    4111           6 :                 dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
    4112           6 :                 bGotNoDataValue =
    4113           6 :                     nUInt64NoDataValue <=
    4114          12 :                         std::numeric_limits<uint64_t>::max() - 2048 &&
    4115           6 :                     static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
    4116             :             }
    4117             :             else
    4118          28 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4119             :         }
    4120             :         else
    4121             :         {
    4122        3014 :             dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4123        3014 :             bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4124             : 
    4125        3014 :             ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4126        3014 :                                     fNoDataValue, bGotFloatNoDataValue);
    4127             : 
    4128        3014 :             ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4129        3014 :                                       hfNoDataValue, bGotFloat16NoDataValue);
    4130             :         }
    4131        3106 :     }
    4132             : };
    4133             : 
    4134             : /************************************************************************/
    4135             : /*                            ARE_REAL_EQUAL()                          */
    4136             : /************************************************************************/
    4137             : 
    4138           0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
    4139             : {
    4140             :     using std::abs;
    4141           0 :     return dfVal1 == dfVal2 || /* Should cover infinity */
    4142           0 :            abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
    4143           0 :                                       abs(dfVal1 + dfVal2) * ulp;
    4144             : }
    4145             : 
    4146             : /************************************************************************/
    4147             : /*                            GetHistogram()                            */
    4148             : /************************************************************************/
    4149             : 
    4150             : /**
    4151             :  * \brief Compute raster histogram.
    4152             :  *
    4153             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    4154             :  *
    4155             :  * For example to compute a simple 256 entry histogram of eight bit data,
    4156             :  * the following would be suitable.  The unusual bounds are to ensure that
    4157             :  * bucket boundaries don't fall right on integer values causing possible errors
    4158             :  * due to rounding after scaling.
    4159             : \code{.cpp}
    4160             :     GUIntBig anHistogram[256];
    4161             : 
    4162             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    4163             :                           GDALDummyProgress, nullptr );
    4164             : \endcode
    4165             :  *
    4166             :  * Note that setting bApproxOK will generally result in a subsampling of the
    4167             :  * file, and will utilize overviews if available.  It should generally
    4168             :  * produce a representative histogram for the data that is suitable for use
    4169             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    4170             :  * much faster than an exactly computed histogram.
    4171             :  *
    4172             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    4173             :  * GDALGetRasterHistogramEx().
    4174             :  *
    4175             :  * @param dfMin the lower bound of the histogram.
    4176             :  * @param dfMax the upper bound of the histogram.
    4177             :  * @param nBuckets the number of buckets in panHistogram.
    4178             :  * @param panHistogram array into which the histogram totals are placed.
    4179             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    4180             :  * mapped into panHistogram[0], and values above will be mapped into
    4181             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4182             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4183             :  * @param pfnProgress function to report progress to completion.
    4184             :  * @param pProgressData application data to pass to pfnProgress.
    4185             :  *
    4186             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4187             :  */
    4188             : 
    4189          45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4190             :                                     GUIntBig *panHistogram,
    4191             :                                     int bIncludeOutOfRange, int bApproxOK,
    4192             :                                     GDALProgressFunc pfnProgress,
    4193             :                                     void *pProgressData)
    4194             : 
    4195             : {
    4196          45 :     CPLAssert(nullptr != panHistogram);
    4197             : 
    4198          45 :     if (pfnProgress == nullptr)
    4199          29 :         pfnProgress = GDALDummyProgress;
    4200             : 
    4201             :     /* -------------------------------------------------------------------- */
    4202             :     /*      If we have overviews, use them for the histogram.               */
    4203             :     /* -------------------------------------------------------------------- */
    4204          45 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4205             :     {
    4206             :         // FIXME: should we use the most reduced overview here or use some
    4207             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4208             :         // does?
    4209           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4210             : 
    4211           0 :         if (poBestOverview != this)
    4212             :         {
    4213           0 :             return poBestOverview->GetHistogram(
    4214             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4215           0 :                 bApproxOK, pfnProgress, pProgressData);
    4216             :         }
    4217             :     }
    4218             : 
    4219             :     /* -------------------------------------------------------------------- */
    4220             :     /*      Read actual data and build histogram.                           */
    4221             :     /* -------------------------------------------------------------------- */
    4222          45 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4223             :     {
    4224           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4225           0 :         return CE_Failure;
    4226             :     }
    4227             : 
    4228             :     // Written this way to deal with NaN
    4229          45 :     if (!(dfMax > dfMin))
    4230             :     {
    4231           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4232             :                     "dfMax should be strictly greater than dfMin");
    4233           5 :         return CE_Failure;
    4234             :     }
    4235             : 
    4236             :     GDALRasterIOExtraArg sExtraArg;
    4237          40 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4238             : 
    4239          40 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4240          40 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4241             :     {
    4242           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4243             :                     "dfMin and dfMax should be finite values such that "
    4244             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4245           5 :         return CE_Failure;
    4246             :     }
    4247          35 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4248             : 
    4249          35 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4250          35 :     GDALRasterBand *poMaskBand = nullptr;
    4251          35 :     if (!sNoDataValues.bGotNoDataValue)
    4252             :     {
    4253          34 :         const int l_nMaskFlags = GetMaskFlags();
    4254          36 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    4255           2 :             GetColorInterpretation() != GCI_AlphaBand)
    4256             :         {
    4257           2 :             poMaskBand = GetMaskBand();
    4258             :         }
    4259             :     }
    4260             : 
    4261          35 :     bool bSignedByte = false;
    4262          35 :     if (eDataType == GDT_UInt8)
    4263             :     {
    4264          26 :         EnablePixelTypeSignedByteWarning(false);
    4265             :         const char *pszPixelType =
    4266          26 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4267          26 :         EnablePixelTypeSignedByteWarning(true);
    4268          26 :         bSignedByte =
    4269          26 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4270             :     }
    4271             : 
    4272          35 :     if (bApproxOK && HasArbitraryOverviews())
    4273             :     {
    4274             :         /* --------------------------------------------------------------------
    4275             :          */
    4276             :         /*      Figure out how much the image should be reduced to get an */
    4277             :         /*      approximate value. */
    4278             :         /* --------------------------------------------------------------------
    4279             :          */
    4280             :         const double dfReduction =
    4281           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4282             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4283             : 
    4284           0 :         int nXReduced = nRasterXSize;
    4285           0 :         int nYReduced = nRasterYSize;
    4286           0 :         if (dfReduction > 1.0)
    4287             :         {
    4288           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4289           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4290             : 
    4291             :             // Catch the case of huge resizing ratios here
    4292           0 :             if (nXReduced == 0)
    4293           0 :                 nXReduced = 1;
    4294           0 :             if (nYReduced == 0)
    4295           0 :                 nYReduced = 1;
    4296             :         }
    4297             : 
    4298           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4299             :                                           nXReduced, nYReduced);
    4300           0 :         if (!pData)
    4301           0 :             return CE_Failure;
    4302             : 
    4303             :         const CPLErr eErr =
    4304           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4305           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4306           0 :         if (eErr != CE_None)
    4307             :         {
    4308           0 :             CPLFree(pData);
    4309           0 :             return eErr;
    4310             :         }
    4311             : 
    4312           0 :         GByte *pabyMaskData = nullptr;
    4313           0 :         if (poMaskBand)
    4314             :         {
    4315             :             pabyMaskData =
    4316           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4317           0 :             if (!pabyMaskData)
    4318             :             {
    4319           0 :                 CPLFree(pData);
    4320           0 :                 return CE_Failure;
    4321             :             }
    4322             : 
    4323           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4324             :                                      pabyMaskData, nXReduced, nYReduced,
    4325           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    4326             :             {
    4327           0 :                 CPLFree(pData);
    4328           0 :                 CPLFree(pabyMaskData);
    4329           0 :                 return CE_Failure;
    4330             :             }
    4331             :         }
    4332             : 
    4333             :         // This isn't the fastest way to do this, but is easier for now.
    4334           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4335             :         {
    4336           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4337             :             {
    4338           0 :                 const int iOffset = iX + iY * nXReduced;
    4339           0 :                 double dfValue = 0.0;
    4340             : 
    4341           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4342           0 :                     continue;
    4343             : 
    4344           0 :                 switch (eDataType)
    4345             :                 {
    4346           0 :                     case GDT_UInt8:
    4347             :                     {
    4348           0 :                         if (bSignedByte)
    4349           0 :                             dfValue =
    4350           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4351             :                         else
    4352           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4353           0 :                         break;
    4354             :                     }
    4355           0 :                     case GDT_Int8:
    4356           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4357           0 :                         break;
    4358           0 :                     case GDT_UInt16:
    4359           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4360           0 :                         break;
    4361           0 :                     case GDT_Int16:
    4362           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4363           0 :                         break;
    4364           0 :                     case GDT_UInt32:
    4365           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4366           0 :                         break;
    4367           0 :                     case GDT_Int32:
    4368           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4369           0 :                         break;
    4370           0 :                     case GDT_UInt64:
    4371           0 :                         dfValue = static_cast<double>(
    4372           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4373           0 :                         break;
    4374           0 :                     case GDT_Int64:
    4375           0 :                         dfValue = static_cast<double>(
    4376           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4377           0 :                         break;
    4378           0 :                     case GDT_Float16:
    4379             :                     {
    4380             :                         using namespace std;
    4381           0 :                         const GFloat16 hfValue =
    4382           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4383           0 :                         if (isnan(hfValue) ||
    4384           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4385           0 :                              ARE_REAL_EQUAL(hfValue,
    4386             :                                             sNoDataValues.hfNoDataValue)))
    4387           0 :                             continue;
    4388           0 :                         dfValue = hfValue;
    4389           0 :                         break;
    4390             :                     }
    4391           0 :                     case GDT_Float32:
    4392             :                     {
    4393           0 :                         const float fValue =
    4394           0 :                             static_cast<float *>(pData)[iOffset];
    4395           0 :                         if (std::isnan(fValue) ||
    4396           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4397           0 :                              ARE_REAL_EQUAL(fValue,
    4398             :                                             sNoDataValues.fNoDataValue)))
    4399           0 :                             continue;
    4400           0 :                         dfValue = double(fValue);
    4401           0 :                         break;
    4402             :                     }
    4403           0 :                     case GDT_Float64:
    4404           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4405           0 :                         if (std::isnan(dfValue))
    4406           0 :                             continue;
    4407           0 :                         break;
    4408           0 :                     case GDT_CInt16:
    4409             :                     {
    4410           0 :                         const double dfReal =
    4411           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4412           0 :                         const double dfImag =
    4413           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4414           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4415           0 :                             continue;
    4416           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4417             :                     }
    4418           0 :                     break;
    4419           0 :                     case GDT_CInt32:
    4420             :                     {
    4421           0 :                         const double dfReal =
    4422           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4423           0 :                         const double dfImag =
    4424           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4425           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4426           0 :                             continue;
    4427           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4428             :                     }
    4429           0 :                     break;
    4430           0 :                     case GDT_CFloat16:
    4431             :                     {
    4432             :                         const double dfReal =
    4433           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4434             :                         const double dfImag =
    4435           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4436           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4437           0 :                             continue;
    4438           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4439           0 :                         break;
    4440             :                     }
    4441           0 :                     case GDT_CFloat32:
    4442             :                     {
    4443           0 :                         const double dfReal =
    4444           0 :                             double(static_cast<float *>(pData)[iOffset * 2]);
    4445           0 :                         const double dfImag = double(
    4446           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1]);
    4447           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4448           0 :                             continue;
    4449           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4450           0 :                         break;
    4451             :                     }
    4452           0 :                     case GDT_CFloat64:
    4453             :                     {
    4454           0 :                         const double dfReal =
    4455           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4456           0 :                         const double dfImag =
    4457           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4458           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4459           0 :                             continue;
    4460           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4461           0 :                         break;
    4462             :                     }
    4463           0 :                     case GDT_Unknown:
    4464             :                     case GDT_TypeCount:
    4465           0 :                         CPLAssert(false);
    4466             :                 }
    4467             : 
    4468           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4469           0 :                     sNoDataValues.bGotNoDataValue &&
    4470           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4471           0 :                     continue;
    4472             : 
    4473             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4474             :                 // finite, the result of the multiplication cannot be NaN
    4475           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4476             : 
    4477           0 :                 if (dfIndex < 0)
    4478             :                 {
    4479           0 :                     if (bIncludeOutOfRange)
    4480           0 :                         panHistogram[0]++;
    4481             :                 }
    4482           0 :                 else if (dfIndex >= nBuckets)
    4483             :                 {
    4484           0 :                     if (bIncludeOutOfRange)
    4485           0 :                         ++panHistogram[nBuckets - 1];
    4486             :                 }
    4487             :                 else
    4488             :                 {
    4489           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4490             :                 }
    4491             :             }
    4492             :         }
    4493             : 
    4494           0 :         CPLFree(pData);
    4495           0 :         CPLFree(pabyMaskData);
    4496             :     }
    4497             :     else  // No arbitrary overviews.
    4498             :     {
    4499          35 :         if (!InitBlockInfo())
    4500           0 :             return CE_Failure;
    4501             : 
    4502             :         /* --------------------------------------------------------------------
    4503             :          */
    4504             :         /*      Figure out the ratio of blocks we will read to get an */
    4505             :         /*      approximate value. */
    4506             :         /* --------------------------------------------------------------------
    4507             :          */
    4508             : 
    4509          35 :         int nSampleRate = 1;
    4510          35 :         if (bApproxOK)
    4511             :         {
    4512           8 :             nSampleRate = static_cast<int>(std::max(
    4513          16 :                 1.0,
    4514           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4515             :             // We want to avoid probing only the first column of blocks for
    4516             :             // a square shaped raster, because it is not unlikely that it may
    4517             :             // be padding only (#6378).
    4518           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4519           1 :                 nSampleRate += 1;
    4520             :         }
    4521             : 
    4522          35 :         GByte *pabyMaskData = nullptr;
    4523          35 :         if (poMaskBand)
    4524             :         {
    4525             :             pabyMaskData = static_cast<GByte *>(
    4526           2 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4527           2 :             if (!pabyMaskData)
    4528             :             {
    4529           0 :                 return CE_Failure;
    4530             :             }
    4531             :         }
    4532             : 
    4533             :         /* --------------------------------------------------------------------
    4534             :          */
    4535             :         /*      Read the blocks, and add to histogram. */
    4536             :         /* --------------------------------------------------------------------
    4537             :          */
    4538          35 :         for (GIntBig iSampleBlock = 0;
    4539         160 :              iSampleBlock <
    4540         160 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4541         125 :              iSampleBlock += nSampleRate)
    4542             :         {
    4543         125 :             if (!pfnProgress(
    4544         125 :                     static_cast<double>(iSampleBlock) /
    4545         125 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4546             :                     "Compute Histogram", pProgressData))
    4547             :             {
    4548           0 :                 CPLFree(pabyMaskData);
    4549           0 :                 return CE_Failure;
    4550             :             }
    4551             : 
    4552         125 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4553         125 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4554             : 
    4555         125 :             int nXCheck = 0, nYCheck = 0;
    4556         125 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4557             : 
    4558         127 :             if (poMaskBand &&
    4559           2 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4560           2 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4561             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    4562           2 :                                      0, nBlockXSize, nullptr) != CE_None)
    4563             :             {
    4564           0 :                 CPLFree(pabyMaskData);
    4565           0 :                 return CE_Failure;
    4566             :             }
    4567             : 
    4568         125 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4569         125 :             if (poBlock == nullptr)
    4570             :             {
    4571           0 :                 CPLFree(pabyMaskData);
    4572           0 :                 return CE_Failure;
    4573             :             }
    4574             : 
    4575         125 :             void *pData = poBlock->GetDataRef();
    4576             : 
    4577             :             // this is a special case for a common situation.
    4578         125 :             if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
    4579          89 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4580          86 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4581             :             {
    4582          86 :                 const GPtrDiff_t nPixels =
    4583          86 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4584          86 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4585             : 
    4586       79640 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4587             :                 {
    4588       79554 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4589           0 :                         continue;
    4590       79554 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4591         512 :                           (pabyData[i] ==
    4592         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4593             :                     {
    4594       79298 :                         panHistogram[pabyData[i]]++;
    4595             :                     }
    4596             :                 }
    4597             : 
    4598          86 :                 poBlock->DropLock();
    4599          86 :                 continue;  // To next sample block.
    4600             :             }
    4601             : 
    4602             :             // This isn't the fastest way to do this, but is easier for now.
    4603         257 :             for (int iY = 0; iY < nYCheck; iY++)
    4604             :             {
    4605       36389 :                 for (int iX = 0; iX < nXCheck; iX++)
    4606             :                 {
    4607       36171 :                     const GPtrDiff_t iOffset =
    4608       36171 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4609             : 
    4610       36171 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4611           2 :                         continue;
    4612             : 
    4613       36169 :                     double dfValue = 0.0;
    4614             : 
    4615       36169 :                     switch (eDataType)
    4616             :                     {
    4617       19716 :                         case GDT_UInt8:
    4618             :                         {
    4619       19716 :                             if (bSignedByte)
    4620           0 :                                 dfValue =
    4621           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4622             :                             else
    4623       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4624       19716 :                             break;
    4625             :                         }
    4626           1 :                         case GDT_Int8:
    4627           1 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4628           1 :                             break;
    4629       16384 :                         case GDT_UInt16:
    4630       16384 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4631       16384 :                             break;
    4632           3 :                         case GDT_Int16:
    4633           3 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4634           3 :                             break;
    4635           0 :                         case GDT_UInt32:
    4636           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4637           0 :                             break;
    4638          60 :                         case GDT_Int32:
    4639          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4640          60 :                             break;
    4641           0 :                         case GDT_UInt64:
    4642           0 :                             dfValue = static_cast<double>(
    4643           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4644           0 :                             break;
    4645           0 :                         case GDT_Int64:
    4646           0 :                             dfValue = static_cast<double>(
    4647           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4648           0 :                             break;
    4649           0 :                         case GDT_Float16:
    4650             :                         {
    4651             :                             using namespace std;
    4652           0 :                             const GFloat16 hfValue =
    4653           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4654           0 :                             if (isnan(hfValue) ||
    4655           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4656           0 :                                  ARE_REAL_EQUAL(hfValue,
    4657             :                                                 sNoDataValues.hfNoDataValue)))
    4658           0 :                                 continue;
    4659           0 :                             dfValue = hfValue;
    4660           0 :                             break;
    4661             :                         }
    4662           3 :                         case GDT_Float32:
    4663             :                         {
    4664           3 :                             const float fValue =
    4665           3 :                                 static_cast<float *>(pData)[iOffset];
    4666           6 :                             if (std::isnan(fValue) ||
    4667           6 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4668           3 :                                  ARE_REAL_EQUAL(fValue,
    4669             :                                                 sNoDataValues.fNoDataValue)))
    4670           0 :                                 continue;
    4671           3 :                             dfValue = double(fValue);
    4672           3 :                             break;
    4673             :                         }
    4674           2 :                         case GDT_Float64:
    4675           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4676           2 :                             if (std::isnan(dfValue))
    4677           0 :                                 continue;
    4678           2 :                             break;
    4679           0 :                         case GDT_CInt16:
    4680             :                         {
    4681           0 :                             double dfReal =
    4682           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4683           0 :                             double dfImag =
    4684           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4685           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4686           0 :                             break;
    4687             :                         }
    4688           0 :                         case GDT_CInt32:
    4689             :                         {
    4690           0 :                             double dfReal =
    4691           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4692           0 :                             double dfImag =
    4693           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4694           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4695           0 :                             break;
    4696             :                         }
    4697           0 :                         case GDT_CFloat16:
    4698             :                         {
    4699             :                             double dfReal =
    4700           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4701             :                             double dfImag =
    4702           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4703           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4704           0 :                                 continue;
    4705           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4706           0 :                             break;
    4707             :                         }
    4708           0 :                         case GDT_CFloat32:
    4709             :                         {
    4710           0 :                             double dfReal = double(
    4711           0 :                                 static_cast<float *>(pData)[iOffset * 2]);
    4712           0 :                             double dfImag = double(
    4713           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1]);
    4714           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4715           0 :                                 continue;
    4716           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4717           0 :                             break;
    4718             :                         }
    4719           0 :                         case GDT_CFloat64:
    4720             :                         {
    4721           0 :                             double dfReal =
    4722           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4723           0 :                             double dfImag =
    4724           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4725           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4726           0 :                                 continue;
    4727           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4728           0 :                             break;
    4729             :                         }
    4730           0 :                         case GDT_Unknown:
    4731             :                         case GDT_TypeCount:
    4732           0 :                             CPLAssert(false);
    4733             :                             CPLFree(pabyMaskData);
    4734             :                             return CE_Failure;
    4735             :                     }
    4736             : 
    4737       36169 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4738       72338 :                         sNoDataValues.bGotNoDataValue &&
    4739           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4740           0 :                         continue;
    4741             : 
    4742             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4743             :                     // and finite, the result of the multiplication cannot be
    4744             :                     // NaN
    4745       36169 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4746             : 
    4747       36169 :                     if (dfIndex < 0)
    4748             :                     {
    4749           1 :                         if (bIncludeOutOfRange)
    4750           1 :                             panHistogram[0]++;
    4751             :                     }
    4752       36168 :                     else if (dfIndex >= nBuckets)
    4753             :                     {
    4754           7 :                         if (bIncludeOutOfRange)
    4755           4 :                             ++panHistogram[nBuckets - 1];
    4756             :                     }
    4757             :                     else
    4758             :                     {
    4759       36161 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4760             :                     }
    4761             :                 }
    4762             :             }
    4763             : 
    4764          39 :             poBlock->DropLock();
    4765             :         }
    4766             : 
    4767          35 :         CPLFree(pabyMaskData);
    4768             :     }
    4769             : 
    4770          35 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4771             : 
    4772          35 :     return CE_None;
    4773             : }
    4774             : 
    4775             : /************************************************************************/
    4776             : /*                       GDALGetRasterHistogram()                       */
    4777             : /************************************************************************/
    4778             : 
    4779             : /**
    4780             :  * \brief Compute raster histogram.
    4781             :  *
    4782             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4783             :  * exceeding 2 billion.
    4784             :  *
    4785             :  * @see GDALRasterBand::GetHistogram()
    4786             :  * @see GDALGetRasterHistogramEx()
    4787             :  */
    4788             : 
    4789           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4790             :                                           double dfMax, int nBuckets,
    4791             :                                           int *panHistogram,
    4792             :                                           int bIncludeOutOfRange, int bApproxOK,
    4793             :                                           GDALProgressFunc pfnProgress,
    4794             :                                           void *pProgressData)
    4795             : 
    4796             : {
    4797           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4798           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4799             : 
    4800           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4801             : 
    4802             :     GUIntBig *panHistogramTemp =
    4803           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4804           0 :     if (panHistogramTemp == nullptr)
    4805             :     {
    4806           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4807             :                             "Out of memory in GDALGetRasterHistogram().");
    4808           0 :         return CE_Failure;
    4809             :     }
    4810             : 
    4811           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4812             :                                        bIncludeOutOfRange, bApproxOK,
    4813           0 :                                        pfnProgress, pProgressData);
    4814             : 
    4815           0 :     if (eErr == CE_None)
    4816             :     {
    4817           0 :         for (int i = 0; i < nBuckets; i++)
    4818             :         {
    4819           0 :             if (panHistogramTemp[i] > INT_MAX)
    4820             :             {
    4821           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4822             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4823             :                          " exceeds maximum 32 bit value",
    4824           0 :                          i, panHistogramTemp[i]);
    4825           0 :                 panHistogram[i] = INT_MAX;
    4826             :             }
    4827             :             else
    4828             :             {
    4829           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4830             :             }
    4831             :         }
    4832             :     }
    4833             : 
    4834           0 :     CPLFree(panHistogramTemp);
    4835             : 
    4836           0 :     return eErr;
    4837             : }
    4838             : 
    4839             : /************************************************************************/
    4840             : /*                      GDALGetRasterHistogramEx()                      */
    4841             : /************************************************************************/
    4842             : 
    4843             : /**
    4844             :  * \brief Compute raster histogram.
    4845             :  *
    4846             :  * @see GDALRasterBand::GetHistogram()
    4847             :  *
    4848             :  */
    4849             : 
    4850          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4851             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4852             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4853             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4854             : 
    4855             : {
    4856          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4857          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4858             : 
    4859          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4860             : 
    4861          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4862             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4863          26 :                                 pProgressData);
    4864             : }
    4865             : 
    4866             : /************************************************************************/
    4867             : /*                        GetDefaultHistogram()                         */
    4868             : /************************************************************************/
    4869             : 
    4870             : /**
    4871             :  * \brief Fetch default raster histogram.
    4872             :  *
    4873             :  * The default method in GDALRasterBand will compute a default histogram. This
    4874             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4875             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4876             :  * stored histogram.
    4877             :  *
    4878             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4879             :  * GDALGetDefaultHistogramEx().
    4880             :  *
    4881             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4882             :  * the histogram.
    4883             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4884             :  * the histogram.
    4885             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4886             :  * in *ppanHistogram.
    4887             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4888             :  * placed. To be freed with VSIFree
    4889             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4890             :  * histogram is available, the method will return CE_Warning
    4891             :  * @param pfnProgress function to report progress to completion.
    4892             :  * @param pProgressData application data to pass to pfnProgress.
    4893             :  *
    4894             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4895             :  * CE_Warning if no default histogram is available.
    4896             :  */
    4897             : 
    4898          27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4899             :                                            int *pnBuckets,
    4900             :                                            GUIntBig **ppanHistogram, int bForce,
    4901             :                                            GDALProgressFunc pfnProgress,
    4902             :                                            void *pProgressData)
    4903             : 
    4904             : {
    4905          27 :     CPLAssert(nullptr != pnBuckets);
    4906          27 :     CPLAssert(nullptr != ppanHistogram);
    4907          27 :     CPLAssert(nullptr != pdfMin);
    4908          27 :     CPLAssert(nullptr != pdfMax);
    4909             : 
    4910          27 :     *pnBuckets = 0;
    4911          27 :     *ppanHistogram = nullptr;
    4912             : 
    4913          27 :     if (!bForce)
    4914           5 :         return CE_Warning;
    4915             : 
    4916          22 :     int nBuckets = 256;
    4917             : 
    4918          22 :     bool bSignedByte = false;
    4919          22 :     if (eDataType == GDT_UInt8)
    4920             :     {
    4921          20 :         EnablePixelTypeSignedByteWarning(false);
    4922             :         const char *pszPixelType =
    4923          20 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4924          20 :         EnablePixelTypeSignedByteWarning(true);
    4925          20 :         bSignedByte =
    4926          20 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4927             :     }
    4928             : 
    4929          22 :     if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
    4930             :     {
    4931          20 :         *pdfMin = -0.5;
    4932          20 :         *pdfMax = 255.5;
    4933             :     }
    4934           2 :     else if (GetRasterDataType() == GDT_Int8)
    4935             :     {
    4936           1 :         *pdfMin = -128 - 0.5;
    4937           1 :         *pdfMax = 127 + 0.5;
    4938             :     }
    4939             :     else
    4940             :     {
    4941             : 
    4942             :         const CPLErr eErr =
    4943           1 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4944           1 :         if (eErr != CE_None)
    4945           0 :             return eErr;
    4946           1 :         if (*pdfMin == *pdfMax)
    4947             :         {
    4948           1 :             nBuckets = 1;
    4949           1 :             *pdfMin -= 0.5;
    4950           1 :             *pdfMax += 0.5;
    4951             :         }
    4952             :         else
    4953             :         {
    4954           0 :             const double dfHalfBucket =
    4955           0 :                 (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4956           0 :             *pdfMin -= dfHalfBucket;
    4957           0 :             *pdfMax += dfHalfBucket;
    4958             :         }
    4959             :     }
    4960             : 
    4961          22 :     *ppanHistogram =
    4962          22 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4963          22 :     if (*ppanHistogram == nullptr)
    4964             :     {
    4965           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4966             :                     "Out of memory in InitBlockInfo().");
    4967           0 :         return CE_Failure;
    4968             :     }
    4969             : 
    4970          22 :     *pnBuckets = nBuckets;
    4971          44 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4972          22 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4973          22 :     if (eErr != CE_None)
    4974             :     {
    4975           0 :         *pnBuckets = 0;
    4976             :     }
    4977          22 :     return eErr;
    4978             : }
    4979             : 
    4980             : /************************************************************************/
    4981             : /*                      GDALGetDefaultHistogram()                       */
    4982             : /************************************************************************/
    4983             : 
    4984             : /**
    4985             :  * \brief Fetch default raster histogram.
    4986             :  *
    4987             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4988             :  * exceeding 2 billion.
    4989             :  *
    4990             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    4991             :  * @see GDALGetRasterHistogramEx()
    4992             :  */
    4993             : 
    4994           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    4995             :                                            double *pdfMin, double *pdfMax,
    4996             :                                            int *pnBuckets, int **ppanHistogram,
    4997             :                                            int bForce,
    4998             :                                            GDALProgressFunc pfnProgress,
    4999             :                                            void *pProgressData)
    5000             : 
    5001             : {
    5002           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5003           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5004           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5005           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5006           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5007             : 
    5008           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    5009           0 :     GUIntBig *panHistogramTemp = nullptr;
    5010           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    5011             :                                               &panHistogramTemp, bForce,
    5012           0 :                                               pfnProgress, pProgressData);
    5013           0 :     if (eErr == CE_None)
    5014             :     {
    5015           0 :         const int nBuckets = *pnBuckets;
    5016           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    5017           0 :         if (*ppanHistogram == nullptr)
    5018             :         {
    5019           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    5020             :                                 "Out of memory in GDALGetDefaultHistogram().");
    5021           0 :             VSIFree(panHistogramTemp);
    5022           0 :             return CE_Failure;
    5023             :         }
    5024             : 
    5025           0 :         for (int i = 0; i < nBuckets; ++i)
    5026             :         {
    5027           0 :             if (panHistogramTemp[i] > INT_MAX)
    5028             :             {
    5029           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    5030             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    5031             :                          " exceeds maximum 32 bit value",
    5032           0 :                          i, panHistogramTemp[i]);
    5033           0 :                 (*ppanHistogram)[i] = INT_MAX;
    5034             :             }
    5035             :             else
    5036             :             {
    5037           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    5038             :             }
    5039             :         }
    5040             : 
    5041           0 :         CPLFree(panHistogramTemp);
    5042             :     }
    5043             :     else
    5044             :     {
    5045           0 :         *ppanHistogram = nullptr;
    5046             :     }
    5047             : 
    5048           0 :     return eErr;
    5049             : }
    5050             : 
    5051             : /************************************************************************/
    5052             : /*                      GDALGetDefaultHistogramEx()                     */
    5053             : /************************************************************************/
    5054             : 
    5055             : /**
    5056             :  * \brief Fetch default raster histogram.
    5057             :  *
    5058             :  * @see GDALRasterBand::GetDefaultHistogram()
    5059             :  *
    5060             :  */
    5061             : 
    5062             : CPLErr CPL_STDCALL
    5063          30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    5064             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    5065             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    5066             : 
    5067             : {
    5068          30 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5069          30 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5070          30 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5071          30 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5072          30 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5073             : 
    5074          30 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5075          30 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    5076          30 :                                        bForce, pfnProgress, pProgressData);
    5077             : }
    5078             : 
    5079             : /************************************************************************/
    5080             : /*                             AdviseRead()                             */
    5081             : /************************************************************************/
    5082             : 
    5083             : /**
    5084             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    5085             :  * \brief Advise driver of upcoming read requests.
    5086             :  *
    5087             :  * Some GDAL drivers operate more efficiently if they know in advance what
    5088             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    5089             :  * an application to notify the driver of the region of interest,
    5090             :  * and at what resolution the region will be read.
    5091             :  *
    5092             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    5093             :  * accelerate access via some drivers.
    5094             :  *
    5095             :  * Depending on call paths, drivers might receive several calls to
    5096             :  * AdviseRead() with the same parameters.
    5097             :  *
    5098             :  * @param nXOff The pixel offset to the top left corner of the region
    5099             :  * of the band to be accessed.  This would be zero to start from the left side.
    5100             :  *
    5101             :  * @param nYOff The line offset to the top left corner of the region
    5102             :  * of the band to be accessed.  This would be zero to start from the top.
    5103             :  *
    5104             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    5105             :  *
    5106             :  * @param nYSize The height of the region of the band to be accessed in lines.
    5107             :  *
    5108             :  * @param nBufXSize the width of the buffer image into which the desired region
    5109             :  * is to be read, or from which it is to be written.
    5110             :  *
    5111             :  * @param nBufYSize the height of the buffer image into which the desired
    5112             :  * region is to be read, or from which it is to be written.
    5113             :  *
    5114             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    5115             :  * pixel values will automatically be translated to/from the GDALRasterBand
    5116             :  * data type as needed.
    5117             :  *
    5118             :  * @param papszOptions a list of name=value strings with special control
    5119             :  * options.  Normally this is NULL.
    5120             :  *
    5121             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    5122             :  * is ignored.
    5123             :  */
    5124             : 
    5125             : /**/
    5126             : /**/
    5127             : 
    5128      113835 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    5129             :                                   int /*nYSize*/, int /*nBufXSize*/,
    5130             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    5131             :                                   char ** /*papszOptions*/)
    5132             : {
    5133      113835 :     return CE_None;
    5134             : }
    5135             : 
    5136             : /************************************************************************/
    5137             : /*                        GDALRasterAdviseRead()                        */
    5138             : /************************************************************************/
    5139             : 
    5140             : /**
    5141             :  * \brief Advise driver of upcoming read requests.
    5142             :  *
    5143             :  * @see GDALRasterBand::AdviseRead()
    5144             :  */
    5145             : 
    5146           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    5147             :                                         int nYOff, int nXSize, int nYSize,
    5148             :                                         int nBufXSize, int nBufYSize,
    5149             :                                         GDALDataType eDT,
    5150             :                                         CSLConstList papszOptions)
    5151             : 
    5152             : {
    5153           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    5154             : 
    5155           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5156           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    5157             :                               nBufYSize, eDT,
    5158           2 :                               const_cast<char **>(papszOptions));
    5159             : }
    5160             : 
    5161             : /************************************************************************/
    5162             : /*                           GetStatistics()                            */
    5163             : /************************************************************************/
    5164             : 
    5165             : /**
    5166             :  * \brief Fetch image statistics.
    5167             :  *
    5168             :  * Returns the minimum, maximum, mean and standard deviation of all
    5169             :  * pixel values in this band.  If approximate statistics are sufficient,
    5170             :  * the bApproxOK flag can be set to true in which case overviews, or a
    5171             :  * subset of image tiles may be used in computing the statistics.
    5172             :  *
    5173             :  * If bForce is FALSE results will only be returned if it can be done
    5174             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    5175             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    5176             :  * returned efficiently, the method will return CE_Warning but no warning will
    5177             :  * be issued. This is a non-standard use of the CE_Warning return value
    5178             :  * to indicate "nothing done".
    5179             :  *
    5180             :  * If bForce is TRUE, and results are quickly available without scanning the
    5181             :  * image, they will be used. If bForce is TRUE and results are not quickly
    5182             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    5183             :  * which will scan the image.
    5184             :  *
    5185             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    5186             :  * of this method.
    5187             :  *
    5188             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    5189             :  * will generally cache statistics in the .pam file allowing fast fetch
    5190             :  * after the first request.
    5191             :  *
    5192             :  * This method is the same as the C function GDALGetRasterStatistics().
    5193             :  *
    5194             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5195             :  * or a subset of all tiles.
    5196             :  *
    5197             :  * @param bForce If FALSE statistics will only be returned if it can
    5198             :  * be done without rescanning the image. If TRUE, statistics computation will
    5199             :  * be forced if pre-existing values are not quickly available.
    5200             :  *
    5201             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5202             :  *
    5203             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5204             :  *
    5205             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5206             :  *
    5207             :  * @param pdfStdDev Location into which to load image standard deviation
    5208             :  * (may be NULL).
    5209             :  *
    5210             :  * @return CE_None on success, CE_Warning if no values returned,
    5211             :  * CE_Failure if an error occurs.
    5212             :  */
    5213             : 
    5214         670 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5215             :                                      double *pdfMax, double *pdfMean,
    5216             :                                      double *pdfStdDev)
    5217             : 
    5218             : {
    5219             :     /* -------------------------------------------------------------------- */
    5220             :     /*      Do we already have metadata items for the requested values?     */
    5221             :     /* -------------------------------------------------------------------- */
    5222        1340 :     if ((pdfMin == nullptr ||
    5223         670 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5224         205 :         (pdfMax == nullptr ||
    5225         205 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5226        1545 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5227         205 :         (pdfStdDev == nullptr ||
    5228         205 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5229             :     {
    5230         205 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5231             :         {
    5232         198 :             if (pdfMin != nullptr)
    5233         198 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5234         198 :             if (pdfMax != nullptr)
    5235         198 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5236         198 :             if (pdfMean != nullptr)
    5237         198 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5238         198 :             if (pdfStdDev != nullptr)
    5239         198 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5240             : 
    5241         198 :             return CE_None;
    5242             :         }
    5243             :     }
    5244             : 
    5245             :     /* -------------------------------------------------------------------- */
    5246             :     /*      Does the driver already know the min/max?                       */
    5247             :     /* -------------------------------------------------------------------- */
    5248         472 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5249             :     {
    5250           1 :         int bSuccessMin = FALSE;
    5251           1 :         int bSuccessMax = FALSE;
    5252             : 
    5253           1 :         const double dfMin = GetMinimum(&bSuccessMin);
    5254           1 :         const double dfMax = GetMaximum(&bSuccessMax);
    5255             : 
    5256           1 :         if (bSuccessMin && bSuccessMax)
    5257             :         {
    5258           0 :             if (pdfMin != nullptr)
    5259           0 :                 *pdfMin = dfMin;
    5260           0 :             if (pdfMax != nullptr)
    5261           0 :                 *pdfMax = dfMax;
    5262           0 :             return CE_None;
    5263             :         }
    5264             :     }
    5265             : 
    5266             :     /* -------------------------------------------------------------------- */
    5267             :     /*      Either return without results, or force computation.            */
    5268             :     /* -------------------------------------------------------------------- */
    5269         472 :     if (!bForce)
    5270         189 :         return CE_Warning;
    5271             :     else
    5272         283 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5273         283 :                                  GDALDummyProgress, nullptr);
    5274             : }
    5275             : 
    5276             : /************************************************************************/
    5277             : /*                      GDALGetRasterStatistics()                       */
    5278             : /************************************************************************/
    5279             : 
    5280             : /**
    5281             :  * \brief Fetch image statistics.
    5282             :  *
    5283             :  * @see GDALRasterBand::GetStatistics()
    5284             :  */
    5285             : 
    5286         318 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5287             :                                            int bForce, double *pdfMin,
    5288             :                                            double *pdfMax, double *pdfMean,
    5289             :                                            double *pdfStdDev)
    5290             : 
    5291             : {
    5292         318 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5293             : 
    5294         318 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5295         318 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5296         318 :                                  pdfStdDev);
    5297             : }
    5298             : 
    5299             : /************************************************************************/
    5300             : /*                         GDALUInt128                                  */
    5301             : /************************************************************************/
    5302             : 
    5303             : #ifdef HAVE_UINT128_T
    5304             : class GDALUInt128
    5305             : {
    5306             :     __uint128_t val;
    5307             : 
    5308        1164 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5309             :     {
    5310        1164 :     }
    5311             : 
    5312             :   public:
    5313         776 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5314             :     {
    5315             :         // Evaluates to just a single mul on x86_64
    5316         776 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5317             :     }
    5318             : 
    5319         388 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5320             :     {
    5321         388 :         return GDALUInt128(val - other.val);
    5322             :     }
    5323             : 
    5324         379 :     operator double() const
    5325             :     {
    5326         379 :         return static_cast<double>(val);
    5327             :     }
    5328             : };
    5329             : #else
    5330             : 
    5331             : #if defined(_MSC_VER) && defined(_M_X64)
    5332             : #include <intrin.h>
    5333             : #endif
    5334             : 
    5335             : class GDALUInt128
    5336             : {
    5337             :     GUIntBig low, high;
    5338             : 
    5339             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5340             :     {
    5341             :     }
    5342             : 
    5343             :   public:
    5344             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5345             :     {
    5346             : #if defined(_MSC_VER) && defined(_M_X64)
    5347             :         GUIntBig highRes;
    5348             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5349             :         return GDALUInt128(lowRes, highRes);
    5350             : #else
    5351             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5352             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5353             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5354             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5355             :         GUIntBig highRes = 0;
    5356             :         const GUIntBig firstLowSecondHigh =
    5357             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5358             :         const GUIntBig firstHighSecondLow =
    5359             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5360             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5361             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5362             :             highRes += static_cast<GUIntBig>(1) << 32;
    5363             :         const GUIntBig firstLowSecondLow =
    5364             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5365             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5366             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5367             :             highRes++;
    5368             :         highRes +=
    5369             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5370             :         return GDALUInt128(lowRes, highRes);
    5371             : #endif
    5372             :     }
    5373             : 
    5374             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5375             :     {
    5376             :         GUIntBig highRes = high - other.high;
    5377             :         GUIntBig lowRes = low - other.low;
    5378             :         if (lowRes > low)  // check for underflow
    5379             :             --highRes;
    5380             :         return GDALUInt128(lowRes, highRes);
    5381             :     }
    5382             : 
    5383             :     operator double() const
    5384             :     {
    5385             :         const double twoPow64 = 18446744073709551616.0;
    5386             :         return high * twoPow64 + low;
    5387             :     }
    5388             : };
    5389             : #endif
    5390             : 
    5391             : /************************************************************************/
    5392             : /*                    ComputeStatisticsInternal()                       */
    5393             : /************************************************************************/
    5394             : 
    5395             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5396             : // not needed.
    5397             : #define static_cast_for_coverity_scan static_cast
    5398             : 
    5399             : // The rationale for below optimizations is detailed in statistics.txt
    5400             : 
    5401             : // Use with T = GByte or GUInt16 only !
    5402             : template <class T, bool COMPUTE_OTHER_STATS>
    5403             : struct ComputeStatisticsInternalGeneric
    5404             : {
    5405         251 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5406             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5407             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5408             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5409             :     {
    5410             :         static_assert(std::is_same<T, GByte>::value ||
    5411             :                           std::is_same<T, GUInt16>::value,
    5412             :                       "bad type for T");
    5413         251 :         if (bHasNoData)
    5414             :         {
    5415             :             // General case
    5416         608 :             for (int iY = 0; iY < nYCheck; iY++)
    5417             :             {
    5418      161753 :                 for (int iX = 0; iX < nXCheck; iX++)
    5419             :                 {
    5420      161269 :                     const GPtrDiff_t iOffset =
    5421      161269 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5422      161269 :                     const GUInt32 nValue = pData[iOffset];
    5423      161269 :                     if (nValue == nNoDataValue)
    5424         319 :                         continue;
    5425      160950 :                     if (nValue < nMin)
    5426          34 :                         nMin = nValue;
    5427      160950 :                     if (nValue > nMax)
    5428          71 :                         nMax = nValue;
    5429             :                     if constexpr (COMPUTE_OTHER_STATS)
    5430             :                     {
    5431      159314 :                         nValidCount++;
    5432      159314 :                         nSum += nValue;
    5433      159314 :                         nSumSquare +=
    5434      159314 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5435      159314 :                             nValue;
    5436             :                     }
    5437             :                 }
    5438             :             }
    5439             :             if constexpr (COMPUTE_OTHER_STATS)
    5440             :             {
    5441          40 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5442             :             }
    5443             :         }
    5444         145 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5445          18 :                  nMax == std::numeric_limits<T>::max())
    5446             :         {
    5447             :             if constexpr (COMPUTE_OTHER_STATS)
    5448             :             {
    5449             :                 // Optimization when there is no nodata and we know we have already
    5450             :                 // reached the min and max
    5451         416 :                 for (int iY = 0; iY < nYCheck; iY++)
    5452             :                 {
    5453             :                     int iX;
    5454        2004 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5455             :                     {
    5456        1600 :                         const GPtrDiff_t iOffset =
    5457        1600 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5458        1600 :                         const GUIntBig nValue = pData[iOffset];
    5459        1600 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5460        1600 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5461        1600 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5462        1600 :                         nSum += nValue;
    5463        1600 :                         nSumSquare += nValue * nValue;
    5464        1600 :                         nSum += nValue2;
    5465        1600 :                         nSumSquare += nValue2 * nValue2;
    5466        1600 :                         nSum += nValue3;
    5467        1600 :                         nSumSquare += nValue3 * nValue3;
    5468        1600 :                         nSum += nValue4;
    5469        1600 :                         nSumSquare += nValue4 * nValue4;
    5470             :                     }
    5471         414 :                     for (; iX < nXCheck; ++iX)
    5472             :                     {
    5473          10 :                         const GPtrDiff_t iOffset =
    5474          10 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5475          10 :                         const GUIntBig nValue = pData[iOffset];
    5476          10 :                         nSum += nValue;
    5477          10 :                         nSumSquare += nValue * nValue;
    5478             :                     }
    5479             :                 }
    5480          12 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5481          12 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5482             :             }
    5483             :         }
    5484             :         else
    5485             :         {
    5486        6021 :             for (int iY = 0; iY < nYCheck; iY++)
    5487             :             {
    5488             :                 int iX;
    5489     1270512 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5490             :                 {
    5491     1264612 :                     const GPtrDiff_t iOffset =
    5492     1264612 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5493     1264612 :                     const GUInt32 nValue = pData[iOffset];
    5494     1264612 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5495     1264612 :                     if (nValue < nValue2)
    5496             :                     {
    5497        2325 :                         if (nValue < nMin)
    5498          51 :                             nMin = nValue;
    5499        2325 :                         if (nValue2 > nMax)
    5500         119 :                             nMax = nValue2;
    5501             :                     }
    5502             :                     else
    5503             :                     {
    5504     1262285 :                         if (nValue2 < nMin)
    5505          67 :                             nMin = nValue2;
    5506     1262285 :                         if (nValue > nMax)
    5507         216 :                             nMax = nValue;
    5508             :                     }
    5509             :                     if constexpr (COMPUTE_OTHER_STATS)
    5510             :                     {
    5511     1257560 :                         nSum += nValue;
    5512     1257560 :                         nSumSquare +=
    5513     1257560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5514     1257560 :                             nValue;
    5515     1257560 :                         nSum += nValue2;
    5516     1257560 :                         nSumSquare +=
    5517     1257560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5518     1257560 :                             nValue2;
    5519             :                     }
    5520             :                 }
    5521        5906 :                 if (iX < nXCheck)
    5522             :                 {
    5523          27 :                     const GPtrDiff_t iOffset =
    5524          27 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5525          27 :                     const GUInt32 nValue = pData[iOffset];
    5526          27 :                     if (nValue < nMin)
    5527          19 :                         nMin = nValue;
    5528          27 :                     if (nValue > nMax)
    5529          20 :                         nMax = nValue;
    5530             :                     if (COMPUTE_OTHER_STATS)
    5531             :                     {
    5532          19 :                         nSum += nValue;
    5533          19 :                         nSumSquare +=
    5534          19 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5535          19 :                             nValue;
    5536             :                     }
    5537             :                 }
    5538             :             }
    5539             :             if constexpr (COMPUTE_OTHER_STATS)
    5540             :             {
    5541          60 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5542          60 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5543             :             }
    5544             :         }
    5545         251 :     }
    5546             : };
    5547             : 
    5548             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5549             : // using 64bit accumulators in internal loops. This also slightly helps in
    5550             : // 64bit mode.
    5551             : template <bool COMPUTE_OTHER_STATS>
    5552             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5553             : {
    5554       13738 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5555             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5556             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5557             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5558             :     {
    5559       13738 :         int nOuterLoops = nXCheck / 65536;
    5560       13738 :         if (nXCheck % 65536)
    5561       13747 :             nOuterLoops++;
    5562             : 
    5563       13738 :         if (bHasNoData)
    5564             :         {
    5565             :             // General case
    5566       23769 :             for (int iY = 0; iY < nYCheck; iY++)
    5567             :             {
    5568       13187 :                 int iX = 0;
    5569       26374 :                 for (int k = 0; k < nOuterLoops; k++)
    5570             :                 {
    5571       13187 :                     int iMax = iX + 65536;
    5572       13187 :                     if (iMax > nXCheck)
    5573       13187 :                         iMax = nXCheck;
    5574       13187 :                     GUInt32 nSum32bit = 0;
    5575       13187 :                     GUInt32 nSumSquare32bit = 0;
    5576       13187 :                     GUInt32 nValidCount32bit = 0;
    5577       13187 :                     GUInt32 nSampleCount32bit = 0;
    5578    20722797 :                     for (; iX < iMax; iX++)
    5579             :                     {
    5580    20709660 :                         const GPtrDiff_t iOffset =
    5581    20709660 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5582    20709660 :                         const GUInt32 nValue = pData[iOffset];
    5583             : 
    5584    20709660 :                         nSampleCount32bit++;
    5585    20709660 :                         if (nValue == nNoDataValue)
    5586    20353516 :                             continue;
    5587      356089 :                         if (nValue < nMin)
    5588         371 :                             nMin = nValue;
    5589      356089 :                         if (nValue > nMax)
    5590         834 :                             nMax = nValue;
    5591             :                         if constexpr (COMPUTE_OTHER_STATS)
    5592             :                         {
    5593       32344 :                             nValidCount32bit++;
    5594       32344 :                             nSum32bit += nValue;
    5595       32344 :                             nSumSquare32bit += nValue * nValue;
    5596             :                         }
    5597             :                     }
    5598             :                     if constexpr (COMPUTE_OTHER_STATS)
    5599             :                     {
    5600         937 :                         nSampleCount += nSampleCount32bit;
    5601         937 :                         nValidCount += nValidCount32bit;
    5602         937 :                         nSum += nSum32bit;
    5603         937 :                         nSumSquare += nSumSquare32bit;
    5604             :                     }
    5605             :                 }
    5606             :             }
    5607             :         }
    5608        3156 :         else if (nMin == 0 && nMax == 255)
    5609             :         {
    5610             :             if constexpr (COMPUTE_OTHER_STATS)
    5611             :             {
    5612             :                 // Optimization when there is no nodata and we know we have already
    5613             :                 // reached the min and max
    5614        2850 :                 for (int iY = 0; iY < nYCheck; iY++)
    5615             :                 {
    5616        2818 :                     int iX = 0;
    5617        5636 :                     for (int k = 0; k < nOuterLoops; k++)
    5618             :                     {
    5619        2818 :                         int iMax = iX + 65536;
    5620        2818 :                         if (iMax > nXCheck)
    5621        2818 :                             iMax = nXCheck;
    5622        2818 :                         GUInt32 nSum32bit = 0;
    5623        2818 :                         GUInt32 nSumSquare32bit = 0;
    5624      177298 :                         for (; iX + 3 < iMax; iX += 4)
    5625             :                         {
    5626      174480 :                             const GPtrDiff_t iOffset =
    5627      174480 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5628      174480 :                             const GUInt32 nValue = pData[iOffset];
    5629      174480 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5630      174480 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5631      174480 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5632      174480 :                             nSum32bit += nValue;
    5633      174480 :                             nSumSquare32bit += nValue * nValue;
    5634      174480 :                             nSum32bit += nValue2;
    5635      174480 :                             nSumSquare32bit += nValue2 * nValue2;
    5636      174480 :                             nSum32bit += nValue3;
    5637      174480 :                             nSumSquare32bit += nValue3 * nValue3;
    5638      174480 :                             nSum32bit += nValue4;
    5639      174480 :                             nSumSquare32bit += nValue4 * nValue4;
    5640             :                         }
    5641        2818 :                         nSum += nSum32bit;
    5642        2818 :                         nSumSquare += nSumSquare32bit;
    5643             :                     }
    5644        2824 :                     for (; iX < nXCheck; ++iX)
    5645             :                     {
    5646           6 :                         const GPtrDiff_t iOffset =
    5647           6 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5648           6 :                         const GUIntBig nValue = pData[iOffset];
    5649           6 :                         nSum += nValue;
    5650           6 :                         nSumSquare += nValue * nValue;
    5651             :                     }
    5652             :                 }
    5653          32 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5654          32 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5655          32 :             }
    5656             :         }
    5657             :         else
    5658             :         {
    5659        8461 :             for (int iY = 0; iY < nYCheck; iY++)
    5660             :             {
    5661        5337 :                 int iX = 0;
    5662       10674 :                 for (int k = 0; k < nOuterLoops; k++)
    5663             :                 {
    5664        5337 :                     int iMax = iX + 65536;
    5665        5337 :                     if (iMax > nXCheck)
    5666        5337 :                         iMax = nXCheck;
    5667        5337 :                     GUInt32 nSum32bit = 0;
    5668        5337 :                     GUInt32 nSumSquare32bit = 0;
    5669      285021 :                     for (; iX + 1 < iMax; iX += 2)
    5670             :                     {
    5671      279684 :                         const GPtrDiff_t iOffset =
    5672      279684 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5673      279684 :                         const GUInt32 nValue = pData[iOffset];
    5674      279684 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5675      279684 :                         if (nValue < nValue2)
    5676             :                         {
    5677        8111 :                             if (nValue < nMin)
    5678         234 :                                 nMin = nValue;
    5679        8111 :                             if (nValue2 > nMax)
    5680         222 :                                 nMax = nValue2;
    5681             :                         }
    5682             :                         else
    5683             :                         {
    5684      271573 :                             if (nValue2 < nMin)
    5685         364 :                                 nMin = nValue2;
    5686      271573 :                             if (nValue > nMax)
    5687         833 :                                 nMax = nValue;
    5688             :                         }
    5689             :                         if constexpr (COMPUTE_OTHER_STATS)
    5690             :                         {
    5691      257546 :                             nSum32bit += nValue;
    5692      257546 :                             nSumSquare32bit += nValue * nValue;
    5693      257546 :                             nSum32bit += nValue2;
    5694      257546 :                             nSumSquare32bit += nValue2 * nValue2;
    5695             :                         }
    5696             :                     }
    5697             :                     if constexpr (COMPUTE_OTHER_STATS)
    5698             :                     {
    5699        2150 :                         nSum += nSum32bit;
    5700        2150 :                         nSumSquare += nSumSquare32bit;
    5701             :                     }
    5702             :                 }
    5703        5337 :                 if (iX < nXCheck)
    5704             :                 {
    5705        1532 :                     const GPtrDiff_t iOffset =
    5706        1532 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5707        1532 :                     const GUInt32 nValue = pData[iOffset];
    5708        1532 :                     if (nValue < nMin)
    5709         117 :                         nMin = nValue;
    5710        1532 :                     if (nValue > nMax)
    5711         101 :                         nMax = nValue;
    5712             :                     if constexpr (COMPUTE_OTHER_STATS)
    5713             :                     {
    5714         321 :                         nSum += nValue;
    5715         321 :                         nSumSquare +=
    5716         321 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5717         321 :                             nValue;
    5718             :                     }
    5719             :                 }
    5720             :             }
    5721             :             if constexpr (COMPUTE_OTHER_STATS)
    5722             :             {
    5723         927 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5724         927 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5725             :             }
    5726             :         }
    5727       13738 :     }
    5728             : };
    5729             : 
    5730             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5731             : {
    5732             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5733             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5734             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5735             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5736             :     {
    5737             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5738             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5739             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5740             :     }
    5741             : };
    5742             : 
    5743             : #if (defined(__x86_64__) || defined(_M_X64)) &&                                \
    5744             :     (defined(__GNUC__) || defined(_MSC_VER))
    5745             : 
    5746             : #include "gdal_avx2_emulation.hpp"
    5747             : 
    5748             : #define ZERO256 GDALmm256_setzero_si256()
    5749             : 
    5750             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5751             : static void
    5752       21346 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5753             :                               // assumed to be aligned on 256 bits
    5754             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5755             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5756             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5757             : {
    5758             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5759             :     GByte
    5760             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5761       21346 :     GByte *paby32ByteAligned =
    5762             :         aby32ByteUnaligned +
    5763       21346 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5764       21346 :     GByte *pabyMin = paby32ByteAligned;
    5765       21346 :     GByte *pabyMax = paby32ByteAligned + 32;
    5766       21346 :     GUInt32 *panSum =
    5767             :         COMPUTE_OTHER_STATS
    5768             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5769             :             : nullptr;
    5770       21346 :     GUInt32 *panSumSquare =
    5771             :         COMPUTE_OTHER_STATS
    5772             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5773             :             : nullptr;
    5774             : 
    5775       21346 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5776             : 
    5777       21346 :     GPtrDiff_t i = 0;
    5778             :     // Make sure that sumSquare can fit on uint32
    5779             :     // * 8 since we can hold 8 sums per vector register
    5780       21346 :     const int nMaxIterationsPerInnerLoop =
    5781             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5782       21346 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5783       21346 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5784       21346 :         nOuterLoops++;
    5785             : 
    5786             :     GDALm256i ymm_min =
    5787       21346 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5788       21346 :     GDALm256i ymm_max = ymm_min;
    5789       21346 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5790             : 
    5791       42692 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5792             :     {
    5793       21346 :         const auto iMax =
    5794       21346 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5795             : 
    5796             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5797       21346 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5798             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5799       21346 :             ZERO256;  // holds 8 uint32 sums
    5800      724785 :         for (; i + 31 < iMax; i += 32)
    5801             :         {
    5802      703439 :             const GDALm256i ymm = GDALmm256_load_si256(
    5803      703439 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5804             :             if (COMPUTE_MIN)
    5805             :             {
    5806      243330 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5807             :             }
    5808             :             if (COMPUTE_MAX)
    5809             :             {
    5810      612140 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5811             :             }
    5812             : 
    5813             :             if constexpr (COMPUTE_OTHER_STATS)
    5814             :             {
    5815             :                 // Extract even-8bit values
    5816             :                 const GDALm256i ymm_even =
    5817      504167 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5818             :                 // Compute square of those 16 values as 32 bit result
    5819             :                 // and add adjacent pairs
    5820             :                 const GDALm256i ymm_even_square =
    5821      504167 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5822             :                 // Add to the sumsquare accumulator
    5823             :                 ymm_sumsquare =
    5824      504167 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5825             : 
    5826             :                 // Extract odd-8bit values
    5827      504167 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5828             :                 const GDALm256i ymm_odd_square =
    5829      504167 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5830             :                 ymm_sumsquare =
    5831      504167 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5832             : 
    5833             :                 // Now compute the sums
    5834      504167 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5835             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5836             :             }
    5837             :         }
    5838             : 
    5839             :         if constexpr (COMPUTE_OTHER_STATS)
    5840             :         {
    5841       10677 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5842             :                                   ymm_sum);
    5843       10677 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5844             :                                   ymm_sumsquare);
    5845             : 
    5846       10677 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5847       10677 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5848       10677 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5849       10677 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5850             :                           panSumSquare[7];
    5851             :         }
    5852             :     }
    5853             : 
    5854             :     if constexpr (COMPUTE_MIN)
    5855             :     {
    5856        8449 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5857             :     }
    5858             :     if constexpr (COMPUTE_MAX)
    5859             :     {
    5860       17334 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5861             :     }
    5862             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5863             :     {
    5864      589281 :         for (int j = 0; j < 32; j++)
    5865             :         {
    5866             :             if constexpr (COMPUTE_MIN)
    5867             :             {
    5868      270368 :                 if (pabyMin[j] < nMin)
    5869        1236 :                     nMin = pabyMin[j];
    5870             :             }
    5871             :             if constexpr (COMPUTE_MAX)
    5872             :             {
    5873      554688 :                 if (pabyMax[j] > nMax)
    5874        1799 :                     nMax = pabyMax[j];
    5875             :             }
    5876             :         }
    5877             :     }
    5878             : 
    5879      234348 :     for (; i < nBlockPixels; i++)
    5880             :     {
    5881      213002 :         const GUInt32 nValue = pData[i];
    5882             :         if constexpr (COMPUTE_MIN)
    5883             :         {
    5884       88326 :             if (nValue < nMin)
    5885           2 :                 nMin = nValue;
    5886             :         }
    5887             :         if constexpr (COMPUTE_MAX)
    5888             :         {
    5889      210227 :             if (nValue > nMax)
    5890        1150 :                 nMax = nValue;
    5891             :         }
    5892             :         if constexpr (COMPUTE_OTHER_STATS)
    5893             :         {
    5894       77203 :             nSum += nValue;
    5895       77203 :             nSumSquare +=
    5896       77203 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5897             :         }
    5898             :     }
    5899             : 
    5900             :     if constexpr (COMPUTE_OTHER_STATS)
    5901             :     {
    5902       10677 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5903       10677 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5904             :     }
    5905       21346 : }
    5906             : 
    5907             : // SSE2/AVX2 optimization for GByte case
    5908             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5909             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5910             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5911             : template <bool COMPUTE_OTHER_STATS>
    5912             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5913             : {
    5914       30262 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5915             :                   // assumed to be aligned on 256 bits
    5916             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5917             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5918             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5919             :                   GUIntBig &nValidCount)
    5920             :     {
    5921       30262 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5922       30262 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5923       11610 :             nMin <= nMax)
    5924             :         {
    5925             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5926             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5927        1492 :             GByte *paby32ByteAligned =
    5928             :                 aby32ByteUnaligned +
    5929        1492 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5930        1492 :             GByte *pabyMin = paby32ByteAligned;
    5931        1492 :             GByte *pabyMax = paby32ByteAligned + 32;
    5932        1492 :             GUInt32 *panSum =
    5933             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5934        1492 :             GUInt32 *panSumSquare =
    5935             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5936             : 
    5937        1492 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5938             : 
    5939        1492 :             GPtrDiff_t i = 0;
    5940             :             // Make sure that sumSquare can fit on uint32
    5941             :             // * 8 since we can hold 8 sums per vector register
    5942        1492 :             const int nMaxIterationsPerInnerLoop =
    5943             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5944        1492 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5945        1492 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5946        1492 :                 nOuterLoops++;
    5947             : 
    5948             :             const GDALm256i ymm_nodata =
    5949        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5950             :             // any non noData value in [min,max] would do.
    5951             :             const GDALm256i ymm_neutral =
    5952        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5953        1492 :             GDALm256i ymm_min = ymm_neutral;
    5954        1492 :             GDALm256i ymm_max = ymm_neutral;
    5955             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5956        1492 :                 GDALmm256_set1_epi16(0xFF);
    5957             : 
    5958        1492 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5959        1492 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5960        1492 :             const bool bComputeMinMax =
    5961        1492 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5962             : 
    5963        2984 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5964             :             {
    5965        1492 :                 const auto iMax =
    5966        1492 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5967             : 
    5968             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5969        1492 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5970             :                 // holds 8 uint32 sums
    5971        1492 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5972             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5973        1492 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5974        1492 :                 const auto iInit = i;
    5975       18982 :                 for (; i + 31 < iMax; i += 32)
    5976             :                 {
    5977       17490 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5978       17490 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5979             : 
    5980             :                     // Check which values are nodata
    5981             :                     const GDALm256i ymm_eq_nodata =
    5982       17490 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    5983             :                     if constexpr (COMPUTE_OTHER_STATS)
    5984             :                     {
    5985             :                         // Count how many values are nodata (due to cmpeq
    5986             :                         // putting 255 when condition is met, this will actually
    5987             :                         // be 255 times the number of nodata value, spread in 4
    5988             :                         // 64 bits words). We can use add_epi32 as the counter
    5989             :                         // will not overflow uint32
    5990        9148 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    5991             :                             ymm_count_nodata_mul_255,
    5992             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    5993             :                     }
    5994             :                     // Replace all nodata values by zero for the purpose of sum
    5995             :                     // and sumquare.
    5996             :                     const GDALm256i ymm_nodata_by_zero =
    5997       17490 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    5998       17490 :                     if (bComputeMinMax)
    5999             :                     {
    6000             :                         // Replace all nodata values by a neutral value for the
    6001             :                         // purpose of min and max.
    6002             :                         const GDALm256i ymm_nodata_by_neutral =
    6003        8720 :                             GDALmm256_or_si256(
    6004             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    6005             :                                 ymm_nodata_by_zero);
    6006             : 
    6007             :                         ymm_min =
    6008        8720 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    6009             :                         ymm_max =
    6010        8720 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    6011             :                     }
    6012             : 
    6013             :                     if constexpr (COMPUTE_OTHER_STATS)
    6014             :                     {
    6015             :                         // Extract even-8bit values
    6016        9148 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    6017             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    6018             :                         // Compute square of those 16 values as 32 bit result
    6019             :                         // and add adjacent pairs
    6020             :                         const GDALm256i ymm_even_square =
    6021        9148 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    6022             :                         // Add to the sumsquare accumulator
    6023             :                         ymm_sumsquare =
    6024        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    6025             : 
    6026             :                         // Extract odd-8bit values
    6027             :                         const GDALm256i ymm_odd =
    6028        9148 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    6029             :                         const GDALm256i ymm_odd_square =
    6030        9148 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    6031             :                         ymm_sumsquare =
    6032        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    6033             : 
    6034             :                         // Now compute the sums
    6035        9148 :                         ymm_sum = GDALmm256_add_epi32(
    6036             :                             ymm_sum,
    6037             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    6038             :                     }
    6039             :                 }
    6040             : 
    6041             :                 if constexpr (COMPUTE_OTHER_STATS)
    6042             :                 {
    6043         186 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    6044         186 :                     GDALmm256_store_si256(
    6045             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    6046             :                         ymm_count_nodata_mul_255);
    6047             : 
    6048         186 :                     nSampleCount += (i - iInit);
    6049             : 
    6050         186 :                     nValidCount +=
    6051         186 :                         (i - iInit) -
    6052         186 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    6053         186 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    6054             :                             255;
    6055             : 
    6056         186 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    6057             :                                           ymm_sum);
    6058         186 :                     GDALmm256_store_si256(
    6059             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    6060             :                         ymm_sumsquare);
    6061         186 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    6062         186 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    6063         186 :                                   panSumSquare[1] + panSumSquare[2] +
    6064         186 :                                   panSumSquare[3] + panSumSquare[4] +
    6065         186 :                                   panSumSquare[5] + panSumSquare[6] +
    6066             :                                   panSumSquare[7];
    6067             :                 }
    6068             :             }
    6069             : 
    6070        1492 :             if (bComputeMinMax)
    6071             :             {
    6072        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    6073             :                                       ymm_min);
    6074        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    6075             :                                       ymm_max);
    6076       47190 :                 for (int j = 0; j < 32; j++)
    6077             :                 {
    6078       45760 :                     if (pabyMin[j] < nMin)
    6079          40 :                         nMin = pabyMin[j];
    6080       45760 :                     if (pabyMax[j] > nMax)
    6081         161 :                         nMax = pabyMax[j];
    6082             :                 }
    6083             :             }
    6084             : 
    6085             :             if constexpr (COMPUTE_OTHER_STATS)
    6086             :             {
    6087         186 :                 nSampleCount += nBlockPixels - i;
    6088             :             }
    6089       34048 :             for (; i < nBlockPixels; i++)
    6090             :             {
    6091       32556 :                 const GUInt32 nValue = pData[i];
    6092       32556 :                 if (nValue == nNoDataValue)
    6093       24923 :                     continue;
    6094        7633 :                 if (nValue < nMin)
    6095           2 :                     nMin = nValue;
    6096        7633 :                 if (nValue > nMax)
    6097          14 :                     nMax = nValue;
    6098             :                 if constexpr (COMPUTE_OTHER_STATS)
    6099             :                 {
    6100        3700 :                     nValidCount++;
    6101        3700 :                     nSum += nValue;
    6102        3700 :                     nSumSquare +=
    6103        3700 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6104        3700 :                         nValue;
    6105             :                 }
    6106        1492 :             }
    6107             :         }
    6108       28770 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    6109             :         {
    6110       14990 :             if (nMin > 0)
    6111             :             {
    6112        2093 :                 if (nMax < 255)
    6113             :                 {
    6114             :                     ComputeStatisticsByteNoNodata<true, true,
    6115        1570 :                                                   COMPUTE_OTHER_STATS>(
    6116             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6117             :                         nSampleCount, nValidCount);
    6118             :                 }
    6119             :                 else
    6120             :                 {
    6121             :                     ComputeStatisticsByteNoNodata<true, false,
    6122         523 :                                                   COMPUTE_OTHER_STATS>(
    6123             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6124             :                         nSampleCount, nValidCount);
    6125             :                 }
    6126             :             }
    6127             :             else
    6128             :             {
    6129       12897 :                 if (nMax < 255)
    6130             :                 {
    6131             :                     ComputeStatisticsByteNoNodata<false, true,
    6132        9408 :                                                   COMPUTE_OTHER_STATS>(
    6133             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6134             :                         nSampleCount, nValidCount);
    6135             :                 }
    6136             :                 else
    6137             :                 {
    6138             :                     ComputeStatisticsByteNoNodata<false, false,
    6139        3489 :                                                   COMPUTE_OTHER_STATS>(
    6140             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6141             :                         nSampleCount, nValidCount);
    6142             :                 }
    6143             :             }
    6144             :         }
    6145       12486 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    6146          33 :                  (nBlockXSize % 32) == 0)
    6147             :         {
    6148        6389 :             for (int iY = 0; iY < nYCheck; iY++)
    6149             :             {
    6150        6356 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    6151        6356 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    6152             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6153          33 :             }
    6154             :         }
    6155             :         else
    6156             :         {
    6157       13747 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    6158             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6159             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6160             :         }
    6161       30262 :     }
    6162             : };
    6163             : 
    6164             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    6165         570 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    6166             :                              GUIntBig i)
    6167             : {
    6168         570 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    6169         570 : }
    6170             : 
    6171             : // AVX2/SSE2 optimization for GUInt16 case
    6172             : template <bool COMPUTE_OTHER_STATS>
    6173             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    6174             : {
    6175        2095 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    6176             :                   // assumed to be aligned on 128 bits
    6177             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    6178             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    6179             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    6180             :                   GUIntBig &nValidCount)
    6181             :     {
    6182        2095 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    6183        2095 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    6184             :         {
    6185        1844 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    6186             : 
    6187        1844 :             GPtrDiff_t i = 0;
    6188             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    6189             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    6190             :             // Furthermore the shift is also needed to use madd_epi16
    6191        1844 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    6192        1844 :             GDALm256i ymm_min = GDALmm256_load_si256(
    6193        1844 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6194        1844 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6195        1844 :             GDALm256i ymm_max = ymm_min;
    6196             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6197        1844 :                 ZERO256;  // holds 4 uint64 sums
    6198             : 
    6199             :             // Make sure that sum can fit on uint32
    6200             :             // * 8 since we can hold 8 sums per vector register
    6201        1844 :             const int nMaxIterationsPerInnerLoop =
    6202             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6203        1844 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6204        1844 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6205        1844 :                 nOuterLoops++;
    6206             : 
    6207        1844 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6208             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6209        1844 :                 GDALmm256_set1_epi32(0xFFFF);
    6210             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6211        1844 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6212             : 
    6213        1844 :             GUIntBig nSumThis = 0;
    6214        3712 :             for (int k = 0; k < nOuterLoops; k++)
    6215             :             {
    6216        1868 :                 const auto iMax =
    6217        1868 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6218             : 
    6219             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6220        1868 :                     ZERO256;  // holds 8 uint32 sums
    6221     1057198 :                 for (; i + 15 < iMax; i += 16)
    6222             :                 {
    6223     1055330 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6224     1055330 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6225             :                     const GDALm256i ymm_shifted =
    6226     1055330 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6227     1055330 :                     if (bComputeMinMax)
    6228             :                     {
    6229     1037292 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6230     1037292 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6231             :                     }
    6232             : 
    6233             :                     if constexpr (COMPUTE_OTHER_STATS)
    6234             :                     {
    6235             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6236             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6237             :                         // is positive, this is OK as we interpret is a uint32.
    6238             :                         const GDALm256i ymm_square =
    6239      188312 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6240      188312 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6241             :                             ymm_sumsquare,
    6242             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6243      188312 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6244             :                             ymm_sumsquare,
    6245             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6246             : 
    6247             :                         // Now compute the sums
    6248      188312 :                         ymm_sum = GDALmm256_add_epi32(
    6249             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6250      188312 :                         ymm_sum = GDALmm256_add_epi32(
    6251             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6252             :                     }
    6253             :                 }
    6254             : 
    6255             :                 if constexpr (COMPUTE_OTHER_STATS)
    6256             :                 {
    6257             :                     GUInt32 anSum[8];
    6258         570 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6259             :                                            ymm_sum);
    6260         570 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6261         570 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6262         570 :                                 anSum[6] + anSum[7];
    6263             :                 }
    6264             :             }
    6265             : 
    6266        1844 :             if (bComputeMinMax)
    6267             :             {
    6268             :                 GUInt16 anMin[16];
    6269             :                 GUInt16 anMax[16];
    6270             : 
    6271             :                 // Unshift the result
    6272        1762 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6273        1762 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6274        1762 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6275             :                                        ymm_min);
    6276        1762 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6277             :                                        ymm_max);
    6278       29954 :                 for (int j = 0; j < 16; j++)
    6279             :                 {
    6280       28192 :                     if (anMin[j] < nMin)
    6281         389 :                         nMin = anMin[j];
    6282       28192 :                     if (anMax[j] > nMax)
    6283         567 :                         nMax = anMax[j];
    6284             :                 }
    6285             :             }
    6286             : 
    6287             :             if constexpr (COMPUTE_OTHER_STATS)
    6288             :             {
    6289             :                 GUIntBig anSumSquare[4];
    6290         570 :                 GDALmm256_storeu_si256(
    6291             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6292         570 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6293             :                               anSumSquare[3];
    6294             : 
    6295             :                 // Unshift the sum of squares
    6296         570 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6297             :                                  static_cast<GUIntBig>(i));
    6298             : 
    6299         570 :                 nSum += nSumThis;
    6300             : 
    6301        1014 :                 for (; i < nBlockPixels; i++)
    6302             :                 {
    6303         444 :                     const GUInt32 nValue = pData[i];
    6304         444 :                     if (nValue < nMin)
    6305           2 :                         nMin = nValue;
    6306         444 :                     if (nValue > nMax)
    6307           2 :                         nMax = nValue;
    6308         444 :                     nSum += nValue;
    6309         444 :                     nSumSquare +=
    6310         444 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6311         444 :                         nValue;
    6312             :                 }
    6313             : 
    6314         570 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6315         570 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6316        1844 :             }
    6317             :         }
    6318             :         else
    6319             :         {
    6320         251 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6321             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6322             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6323             :         }
    6324        2095 :     }
    6325             : };
    6326             : 
    6327             : #endif
    6328             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6329             : // defined(_MSC_VER))
    6330             : 
    6331             : /************************************************************************/
    6332             : /*                          GetPixelValue()                             */
    6333             : /************************************************************************/
    6334             : 
    6335    15432100 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6336             :                                    const void *pData, GPtrDiff_t iOffset,
    6337             :                                    const GDALNoDataValues &sNoDataValues,
    6338             :                                    bool &bValid)
    6339             : {
    6340    15432100 :     bValid = true;
    6341    15432100 :     double dfValue = 0;
    6342    15432100 :     switch (eDataType)
    6343             :     {
    6344     1400770 :         case GDT_UInt8:
    6345             :         {
    6346     1400770 :             if (bSignedByte)
    6347         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6348             :             else
    6349     1400580 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6350     1400770 :             break;
    6351             :         }
    6352         617 :         case GDT_Int8:
    6353         617 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6354         617 :             break;
    6355      200608 :         case GDT_UInt16:
    6356      200608 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6357      200608 :             break;
    6358      114437 :         case GDT_Int16:
    6359      114437 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6360      114437 :             break;
    6361       10454 :         case GDT_UInt32:
    6362       10454 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6363       10454 :             break;
    6364      140108 :         case GDT_Int32:
    6365      140108 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6366      140108 :             break;
    6367          36 :         case GDT_UInt64:
    6368          36 :             dfValue = static_cast<double>(
    6369          36 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6370          36 :             break;
    6371        3244 :         case GDT_Int64:
    6372        3244 :             dfValue = static_cast<double>(
    6373        3244 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6374        3244 :             break;
    6375           8 :         case GDT_Float16:
    6376             :         {
    6377             :             using namespace std;
    6378           8 :             const GFloat16 hfValue =
    6379           8 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6380          14 :             if (isnan(hfValue) ||
    6381           6 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6382           0 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6383             :             {
    6384           2 :                 bValid = false;
    6385           2 :                 return 0.0;
    6386             :             }
    6387           6 :             dfValue = hfValue;
    6388           6 :             return dfValue;
    6389             :         }
    6390    13393800 :         case GDT_Float32:
    6391             :         {
    6392    13393800 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6393    26760800 :             if (std::isnan(fValue) ||
    6394    26635700 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6395    13268800 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6396             :             {
    6397       26879 :                 bValid = false;
    6398       26879 :                 return 0.0;
    6399             :             }
    6400    13367000 :             dfValue = double(fValue);
    6401    13367000 :             return dfValue;
    6402             :         }
    6403      150868 :         case GDT_Float64:
    6404      150868 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6405      150868 :             if (std::isnan(dfValue))
    6406             :             {
    6407           6 :                 bValid = false;
    6408           6 :                 return 0.0;
    6409             :             }
    6410      150862 :             break;
    6411        2692 :         case GDT_CInt16:
    6412        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6413        2692 :             break;
    6414        2692 :         case GDT_CInt32:
    6415        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6416        2692 :             break;
    6417           0 :         case GDT_CFloat16:
    6418           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6419           0 :             if (std::isnan(dfValue))
    6420             :             {
    6421           0 :                 bValid = false;
    6422           0 :                 return 0.0;
    6423             :             }
    6424           0 :             break;
    6425        5812 :         case GDT_CFloat32:
    6426        5812 :             dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
    6427        5812 :             if (std::isnan(dfValue))
    6428             :             {
    6429           0 :                 bValid = false;
    6430           0 :                 return 0.0;
    6431             :             }
    6432        5812 :             break;
    6433        5892 :         case GDT_CFloat64:
    6434        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6435        5892 :             if (std::isnan(dfValue))
    6436             :             {
    6437           0 :                 bValid = false;
    6438           0 :                 return 0.0;
    6439             :             }
    6440        5892 :             break;
    6441           0 :         case GDT_Unknown:
    6442             :         case GDT_TypeCount:
    6443           0 :             CPLAssert(false);
    6444             :             break;
    6445             :     }
    6446             : 
    6447     2293270 :     if (sNoDataValues.bGotNoDataValue &&
    6448      255049 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6449             :     {
    6450        4203 :         bValid = false;
    6451        4203 :         return 0.0;
    6452             :     }
    6453     2034020 :     return dfValue;
    6454             : }
    6455             : 
    6456             : /************************************************************************/
    6457             : /*                         SetValidPercent()                            */
    6458             : /************************************************************************/
    6459             : 
    6460             : //! @cond Doxygen_Suppress
    6461             : /**
    6462             :  * \brief Set percentage of valid (not nodata) pixels.
    6463             :  *
    6464             :  * Stores the percentage of valid pixels in the metadata item
    6465             :  * STATISTICS_VALID_PERCENT
    6466             :  *
    6467             :  * @param nSampleCount Number of sampled pixels.
    6468             :  *
    6469             :  * @param nValidCount Number of valid pixels.
    6470             :  */
    6471             : 
    6472         535 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6473             :                                      GUIntBig nValidCount)
    6474             : {
    6475         535 :     if (nValidCount == 0)
    6476             :     {
    6477          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6478             :     }
    6479         523 :     else if (nValidCount == nSampleCount)
    6480             :     {
    6481         465 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6482             :     }
    6483             :     else /* nValidCount < nSampleCount */
    6484             :     {
    6485          58 :         char szValue[128] = {0};
    6486             : 
    6487             :         /* percentage is only an indicator: limit precision */
    6488          58 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6489          58 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6490             : 
    6491          58 :         if (EQUAL(szValue, "100"))
    6492             :         {
    6493             :             /* don't set 100 percent valid
    6494             :              * because some of the sampled pixels were nodata */
    6495           4 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6496             :         }
    6497             :         else
    6498             :         {
    6499          54 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6500             :         }
    6501             :     }
    6502         535 : }
    6503             : 
    6504             : //! @endcond
    6505             : 
    6506             : #if (defined(__x86_64__) || defined(_M_X64))
    6507             : 
    6508             : #ifdef __AVX2__
    6509             : 
    6510             : #define setzero_si _mm256_setzero_si256
    6511             : #define setzero_ps _mm256_setzero_ps
    6512             : #define set1_ps _mm256_set1_ps
    6513             : #define set1_epi32 _mm256_set1_epi32
    6514             : #define add_epi32 _mm256_add_epi32
    6515             : #define loadu_ps _mm256_loadu_ps
    6516             : #define or_ps _mm256_or_ps
    6517             : #define min_ps _mm256_min_ps
    6518             : #define max_ps _mm256_max_ps
    6519             : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
    6520             : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
    6521             : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
    6522             : #define movemask_ps _mm256_movemask_ps
    6523             : #define add_ps _mm256_add_ps
    6524             : #define sub_ps _mm256_sub_ps
    6525             : #define mul_ps _mm256_mul_ps
    6526             : #define div_ps _mm256_div_ps
    6527             : #define storeu_ps _mm256_storeu_ps
    6528             : #define cvtepi32_ps _mm256_cvtepi32_ps
    6529             : #define cvtsi_si32(x) _mm256_extract_epi32((x), 0)
    6530             : #define blendv_ps _mm256_blendv_ps
    6531             : #ifdef __FMA__
    6532             : #define fmadd_ps _mm256_fmadd_ps
    6533             : #else
    6534             : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
    6535             : #endif
    6536             : 
    6537             : #else
    6538             : 
    6539             : #define setzero_si _mm_setzero_si128
    6540             : #define setzero_ps _mm_setzero_ps
    6541             : #define set1_ps _mm_set1_ps
    6542             : #define set1_epi32 _mm_set1_epi32
    6543             : #define add_epi32 _mm_add_epi32
    6544             : #define loadu_ps _mm_loadu_ps
    6545             : #define or_ps _mm_or_ps
    6546             : #define min_ps _mm_min_ps
    6547             : #define max_ps _mm_max_ps
    6548             : #define cmpeq_ps _mm_cmpeq_ps
    6549             : #define cmpneq_ps _mm_cmpneq_ps
    6550             : #define cmpunord_ps _mm_cmpunord_ps
    6551             : #define movemask_ps _mm_movemask_ps
    6552             : #define add_ps _mm_add_ps
    6553             : #define sub_ps _mm_sub_ps
    6554             : #define mul_ps _mm_mul_ps
    6555             : #define div_ps _mm_div_ps
    6556             : #define storeu_ps _mm_storeu_ps
    6557             : #define cvtepi32_ps _mm_cvtepi32_ps
    6558             : #define cvtsi_si32 _mm_cvtsi128_si32
    6559             : #ifdef __FMA__
    6560             : #define fmadd_ps _mm_fmadd_ps
    6561             : #else
    6562             : #define fmadd_ps(a, b, c) add_ps(mul_ps((a), (b)), (c))
    6563             : #endif
    6564             : 
    6565     2065850 : inline __m128 blendv_ps(__m128 a, __m128 b, __m128 mask)
    6566             : {
    6567             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
    6568             :     return _mm_blendv_ps(a, b, mask);
    6569             : #else
    6570     6197540 :     return _mm_or_ps(_mm_andnot_ps(mask, a), _mm_and_ps(mask, b));
    6571             : #endif
    6572             : }
    6573             : #endif
    6574             : 
    6575             : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6576             : #if defined(__GNUC__)
    6577             : __attribute__((noinline))
    6578             : #endif
    6579             : static int
    6580        4889 : ComputeStatisticsFloat32_SSE2(const float *pafData,
    6581             :                               [[maybe_unused]] float fNoDataValue, int iX,
    6582             :                               int nCount, float &fMin, float &fMax,
    6583             :                               float &fBlockMean, float &fBlockM2,
    6584             :                               int &nBlockValidCount)
    6585             : {
    6586        4889 :     auto vValidCount = setzero_si();
    6587        4889 :     const auto vOne = set1_epi32(1);
    6588        4889 :     [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
    6589             : 
    6590        4889 :     auto vMin_lo = set1_ps(fMin);
    6591        9778 :     auto vMax_lo = set1_ps(fMax);
    6592        4889 :     auto vMean_lo = setzero_ps();
    6593        4889 :     auto vM2_lo = setzero_ps();
    6594             : 
    6595        4889 :     auto vMin_hi = vMin_lo;
    6596        4889 :     auto vMax_hi = vMax_lo;
    6597        4889 :     auto vMean_hi = setzero_ps();
    6598        4889 :     auto vM2_hi = setzero_ps();
    6599             : 
    6600        4889 :     constexpr int VALS_PER_LOOP =
    6601             :         2 * static_cast<int>(sizeof(vOne) / sizeof(float));
    6602      590671 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6603             :     {
    6604      585783 :         const auto vValues_lo = loadu_ps(pafData + iX);
    6605     1171568 :         const auto vValues_hi = loadu_ps(pafData + iX + VALS_PER_LOOP / 2);
    6606             :         // Check if there's at least one NaN in both vectors
    6607      585783 :         auto isNaNOrNoData = cmpunord_ps(vValues_lo, vValues_hi);
    6608             :         if constexpr (HAS_NODATA)
    6609             :         {
    6610             :             isNaNOrNoData =
    6611           0 :                 or_ps(isNaNOrNoData, or_ps(cmpeq_ps(vValues_lo, vNoData),
    6612             :                                            cmpeq_ps(vValues_hi, vNoData)));
    6613             :         }
    6614      585783 :         if (movemask_ps(isNaNOrNoData))
    6615             :         {
    6616           1 :             break;
    6617             :         }
    6618             : 
    6619      585782 :         vValidCount = add_epi32(vValidCount, vOne);
    6620      585782 :         const auto vValidCountFloat32 = cvtepi32_ps(vValidCount);
    6621             : 
    6622      585782 :         vMin_lo = min_ps(vMin_lo, vValues_lo);
    6623      585782 :         vMax_lo = max_ps(vMax_lo, vValues_lo);
    6624      585782 :         const auto vDelta_lo = sub_ps(vValues_lo, vMean_lo);
    6625             :         const auto vNewMean_lo =
    6626     1102213 :             add_ps(vMean_lo, div_ps(vDelta_lo, vValidCountFloat32));
    6627             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6628             :         {
    6629      516429 :             const auto vMinNotSameAsMax_lo = cmpneq_ps(vMin_lo, vMax_lo);
    6630      516429 :             vMean_lo = blendv_ps(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6631             :             const auto vNewM2_lo =
    6632     1032860 :                 fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
    6633      516429 :             vM2_lo = blendv_ps(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6634             :         }
    6635             :         else
    6636             :         {
    6637       69353 :             vMean_lo = vNewMean_lo;
    6638      208059 :             vM2_lo = fmadd_ps(vDelta_lo, sub_ps(vValues_lo, vMean_lo), vM2_lo);
    6639             :         }
    6640             : 
    6641      585782 :         vMin_hi = min_ps(vMin_hi, vValues_hi);
    6642      585782 :         vMax_hi = max_ps(vMax_hi, vValues_hi);
    6643      585782 :         const auto vDelta_hi = sub_ps(vValues_hi, vMean_hi);
    6644             :         const auto vNewMean_hi =
    6645     1102213 :             add_ps(vMean_hi, div_ps(vDelta_hi, vValidCountFloat32));
    6646             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6647             :         {
    6648      516429 :             const auto vMinNotSameAsMax_hi = cmpneq_ps(vMin_hi, vMax_hi);
    6649      516429 :             vMean_hi = blendv_ps(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6650             :             const auto vNewM2_hi =
    6651     1032860 :                 fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
    6652      516429 :             vM2_hi = blendv_ps(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6653             :         }
    6654             :         else
    6655             :         {
    6656       69353 :             vMean_hi = vNewMean_hi;
    6657      208059 :             vM2_hi = fmadd_ps(vDelta_hi, sub_ps(vValues_hi, vMean_hi), vM2_hi);
    6658             :         }
    6659             :     }
    6660        4889 :     const int nValidVectorCount = cvtsi_si32(vValidCount);
    6661        4889 :     if (nValidVectorCount)
    6662             :     {
    6663             :         float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP], afMean[VALS_PER_LOOP],
    6664             :             afM2[VALS_PER_LOOP];
    6665             :         storeu_ps(afMin, vMin_lo);
    6666             :         storeu_ps(afMax, vMax_lo);
    6667             :         storeu_ps(afMean, vMean_lo);
    6668             :         storeu_ps(afM2, vM2_lo);
    6669        4631 :         storeu_ps(afMin + VALS_PER_LOOP / 2, vMin_hi);
    6670        4631 :         storeu_ps(afMax + VALS_PER_LOOP / 2, vMax_hi);
    6671        4631 :         storeu_ps(afMean + VALS_PER_LOOP / 2, vMean_hi);
    6672        4631 :         storeu_ps(afM2 + VALS_PER_LOOP / 2, vM2_hi);
    6673             : 
    6674       41679 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6675             :         {
    6676       37048 :             fMin = std::min(fMin, afMin[i]);
    6677       37048 :             fMax = std::max(fMax, afMax[i]);
    6678       37048 :             const auto nNewValidCount = nBlockValidCount + nValidVectorCount;
    6679       37048 :             if (afMean[i] != fBlockMean)
    6680             :             {
    6681       17864 :                 const float fDelta = afMean[i] - fBlockMean;
    6682       17864 :                 fBlockMean += fDelta * nValidVectorCount / nNewValidCount;
    6683       17864 :                 fBlockM2 += afM2[i] + fDelta * fDelta * nBlockValidCount *
    6684       17864 :                                           nValidVectorCount / nNewValidCount;
    6685             :             }
    6686       37048 :             nBlockValidCount = nNewValidCount;
    6687             :         }
    6688             :     }
    6689             : 
    6690        4889 :     return iX;
    6691             : }
    6692             : 
    6693             : #ifdef __AVX2__
    6694             : 
    6695             : #define setzero_pd _mm256_setzero_pd
    6696             : #define set1_pd _mm256_set1_pd
    6697             : #define loadu_pd _mm256_loadu_pd
    6698             : #define or_pd _mm256_or_pd
    6699             : #define min_pd _mm256_min_pd
    6700             : #define max_pd _mm256_max_pd
    6701             : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
    6702             : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
    6703             : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
    6704             : #define movemask_pd _mm256_movemask_pd
    6705             : #define add_pd _mm256_add_pd
    6706             : #define sub_pd _mm256_sub_pd
    6707             : #define mul_pd _mm256_mul_pd
    6708             : #define div_pd _mm256_div_pd
    6709             : #define storeu_pd _mm256_storeu_pd
    6710             : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
    6711             : #define blendv_pd _mm256_blendv_pd
    6712             : #ifdef __FMA__
    6713             : #define fmadd_pd _mm256_fmadd_pd
    6714             : #else
    6715             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6716             : #endif
    6717             : 
    6718             : #else
    6719             : 
    6720             : #define setzero_pd _mm_setzero_pd
    6721             : #define set1_pd _mm_set1_pd
    6722             : #define loadu_pd _mm_loadu_pd
    6723             : #define or_pd _mm_or_pd
    6724             : #define min_pd _mm_min_pd
    6725             : #define max_pd _mm_max_pd
    6726             : #define cmpeq_pd _mm_cmpeq_pd
    6727             : #define cmpneq_pd _mm_cmpneq_pd
    6728             : #define cmpunord_pd _mm_cmpunord_pd
    6729             : #define movemask_pd _mm_movemask_pd
    6730             : #define add_pd _mm_add_pd
    6731             : #define sub_pd _mm_sub_pd
    6732             : #define mul_pd _mm_mul_pd
    6733             : #define div_pd _mm_div_pd
    6734             : #define storeu_pd _mm_storeu_pd
    6735             : #define cvtsd_f64 _mm_cvtsd_f64
    6736             : #ifdef __FMA__
    6737             : #define fmadd_pd _mm_fmadd_pd
    6738             : #else
    6739             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6740             : #endif
    6741             : 
    6742      103928 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
    6743             : {
    6744             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
    6745             :     return _mm_blendv_pd(a, b, mask);
    6746             : #else
    6747      311784 :     return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
    6748             : #endif
    6749             : }
    6750             : #endif
    6751             : 
    6752             : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6753             : #if defined(__GNUC__)
    6754             : __attribute__((noinline))
    6755             : #endif
    6756             : static int
    6757        1351 : ComputeStatisticsFloat64_SSE2(const double *padfData,
    6758             :                               [[maybe_unused]] double dfNoDataValue, int iX,
    6759             :                               int nCount, double &dfMin, double &dfMax,
    6760             :                               double &dfBlockMean, double &dfBlockM2,
    6761             :                               double &dfBlockValidCount)
    6762             : {
    6763        1351 :     auto vValidCount = setzero_pd();
    6764        1351 :     const auto vOne = set1_pd(1);
    6765        1351 :     [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
    6766             : 
    6767        1351 :     auto vMin_lo = set1_pd(dfMin);
    6768        2702 :     auto vMax_lo = set1_pd(dfMax);
    6769        1351 :     auto vMean_lo = setzero_pd();
    6770        1351 :     auto vM2_lo = setzero_pd();
    6771             : 
    6772        1351 :     auto vMin_hi = vMin_lo;
    6773        1351 :     auto vMax_hi = vMax_lo;
    6774        1351 :     auto vMean_hi = setzero_pd();
    6775        1351 :     auto vM2_hi = setzero_pd();
    6776             : 
    6777        1351 :     constexpr int VALS_PER_LOOP =
    6778             :         2 * static_cast<int>(sizeof(vOne) / sizeof(double));
    6779       43687 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6780             :     {
    6781       42379 :         const auto vValues_lo = loadu_pd(padfData + iX);
    6782       84758 :         const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
    6783             :         // Check if there's at least one NaN in both vectors
    6784       42379 :         auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
    6785             :         if constexpr (HAS_NODATA)
    6786             :         {
    6787             :             isNaNOrNoData =
    6788      103248 :                 or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
    6789             :                                            cmpeq_pd(vValues_hi, vNoData)));
    6790             :         }
    6791       42379 :         if (movemask_pd(isNaNOrNoData))
    6792             :         {
    6793          43 :             break;
    6794             :         }
    6795             : 
    6796       42336 :         vValidCount = add_pd(vValidCount, vOne);
    6797       42336 :         const auto vInvValidCount = div_pd(vOne, vValidCount);
    6798             : 
    6799       42336 :         vMin_lo = min_pd(vMin_lo, vValues_lo);
    6800       42336 :         vMax_lo = max_pd(vMax_lo, vValues_lo);
    6801       42336 :         const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
    6802       68318 :         const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
    6803             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6804             :         {
    6805       25982 :             const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
    6806       25982 :             vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6807             :             const auto vNewM2_lo =
    6808       51964 :                 fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6809       25982 :             vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6810             :         }
    6811             :         else
    6812             :         {
    6813       16354 :             vMean_lo = vNewMean_lo;
    6814       49062 :             vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6815             :         }
    6816             : 
    6817       42336 :         vMin_hi = min_pd(vMin_hi, vValues_hi);
    6818       42336 :         vMax_hi = max_pd(vMax_hi, vValues_hi);
    6819       42336 :         const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
    6820       68318 :         const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
    6821             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6822             :         {
    6823       25982 :             const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
    6824       25982 :             vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6825             :             const auto vNewM2_hi =
    6826       51964 :                 fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6827       25982 :             vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6828             :         }
    6829             :         else
    6830             :         {
    6831       16354 :             vMean_hi = vNewMean_hi;
    6832       49062 :             vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6833             :         }
    6834             :     }
    6835        1351 :     const double dfValidVectorCount = cvtsd_f64(vValidCount);
    6836        1351 :     if (dfValidVectorCount > 0)
    6837             :     {
    6838             :         double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
    6839             :             adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
    6840             :         storeu_pd(adfMin, vMin_lo);
    6841             :         storeu_pd(adfMax, vMax_lo);
    6842             :         storeu_pd(adfMean, vMean_lo);
    6843             :         storeu_pd(adfM2, vM2_lo);
    6844         801 :         storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
    6845         801 :         storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
    6846         801 :         storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
    6847         801 :         storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
    6848             : 
    6849        4005 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6850             :         {
    6851        3204 :             dfMin = std::min(dfMin, adfMin[i]);
    6852        3204 :             dfMax = std::max(dfMax, adfMax[i]);
    6853        3204 :             const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
    6854        3204 :             if (adfMean[i] != dfBlockMean)
    6855             :             {
    6856        1874 :                 const double dfDelta = adfMean[i] - dfBlockMean;
    6857        1874 :                 dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
    6858        1874 :                 dfBlockM2 += adfM2[i] + dfDelta * dfDelta * dfBlockValidCount *
    6859        1874 :                                             dfValidVectorCount /
    6860             :                                             dfNewValidCount;
    6861             :             }
    6862        3204 :             dfBlockValidCount = dfNewValidCount;
    6863             :         }
    6864             :     }
    6865             : 
    6866        1351 :     return iX;
    6867             : }
    6868             : 
    6869             : #endif
    6870             : 
    6871             : /************************************************************************/
    6872             : /*                         ComputeStatistics()                          */
    6873             : /************************************************************************/
    6874             : 
    6875             : /**
    6876             :  * \brief Compute image statistics.
    6877             :  *
    6878             :  * Returns the minimum, maximum, mean and standard deviation of all
    6879             :  * pixel values in this band.  If approximate statistics are sufficient,
    6880             :  * the bApproxOK flag can be set to true in which case overviews, or a
    6881             :  * subset of image tiles may be used in computing the statistics.
    6882             :  *
    6883             :  * Once computed, the statistics will generally be "set" back on the
    6884             :  * raster band using SetStatistics().
    6885             :  *
    6886             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    6887             :  *
    6888             :  * This method is the same as the C function GDALComputeRasterStatistics().
    6889             :  *
    6890             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    6891             :  * or a subset of all tiles.
    6892             :  *
    6893             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    6894             :  *
    6895             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    6896             :  *
    6897             :  * @param pdfMean Location into which to load image mean (may be NULL).
    6898             :  *
    6899             :  * @param pdfStdDev Location into which to load image standard deviation
    6900             :  * (may be NULL).
    6901             :  *
    6902             :  * @param pfnProgress a function to call to report progress, or NULL.
    6903             :  *
    6904             :  * @param pProgressData application data to pass to the progress function.
    6905             :  *
    6906             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    6907             :  * is terminated by the user.
    6908             :  */
    6909             : 
    6910         513 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    6911             :                                          double *pdfMax, double *pdfMean,
    6912             :                                          double *pdfStdDev,
    6913             :                                          GDALProgressFunc pfnProgress,
    6914             :                                          void *pProgressData)
    6915             : 
    6916             : {
    6917         513 :     if (pfnProgress == nullptr)
    6918         183 :         pfnProgress = GDALDummyProgress;
    6919             : 
    6920             :     /* -------------------------------------------------------------------- */
    6921             :     /*      If we have overview bands, use them for statistics.             */
    6922             :     /* -------------------------------------------------------------------- */
    6923         513 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    6924             :     {
    6925             :         GDALRasterBand *poBand =
    6926           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    6927             : 
    6928           3 :         if (poBand != this)
    6929             :         {
    6930           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    6931             :                                                     pdfMean, pdfStdDev,
    6932           3 :                                                     pfnProgress, pProgressData);
    6933           3 :             if (eErr == CE_None)
    6934             :             {
    6935           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    6936             :                 {
    6937           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6938           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    6939             :                 }
    6940             : 
    6941             :                 /* transfer metadata from overview band to this */
    6942             :                 const char *pszPercentValid =
    6943           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    6944             : 
    6945           3 :                 if (pszPercentValid != nullptr)
    6946             :                 {
    6947           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    6948           3 :                                     pszPercentValid);
    6949             :                 }
    6950             :             }
    6951           3 :             return eErr;
    6952             :         }
    6953             :     }
    6954             : 
    6955         510 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    6956             :     {
    6957           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6958           0 :         return CE_Failure;
    6959             :     }
    6960             : 
    6961             :     /* -------------------------------------------------------------------- */
    6962             :     /*      Read actual data and compute statistics.                        */
    6963             :     /* -------------------------------------------------------------------- */
    6964             :     // Using Welford algorithm:
    6965             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    6966             :     // to compute standard deviation in a more numerically robust way than
    6967             :     // the difference of the sum of square values with the square of the sum.
    6968             :     // dfMean and dfM2 are updated at each sample.
    6969             :     // dfM2 is the sum of square of differences to the current mean.
    6970         510 :     double dfMin = std::numeric_limits<double>::infinity();
    6971         510 :     double dfMax = -std::numeric_limits<double>::infinity();
    6972         510 :     double dfMean = 0.0;
    6973         510 :     double dfM2 = 0.0;
    6974             : 
    6975             :     GDALRasterIOExtraArg sExtraArg;
    6976         510 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    6977             : 
    6978         510 :     GDALNoDataValues sNoDataValues(this, eDataType);
    6979         510 :     GDALRasterBand *poMaskBand = nullptr;
    6980         510 :     if (!sNoDataValues.bGotNoDataValue)
    6981             :     {
    6982         477 :         const int l_nMaskFlags = GetMaskFlags();
    6983         523 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    6984          46 :             GetColorInterpretation() != GCI_AlphaBand)
    6985             :         {
    6986          46 :             poMaskBand = GetMaskBand();
    6987             :         }
    6988             :     }
    6989             : 
    6990         510 :     bool bSignedByte = false;
    6991         510 :     if (eDataType == GDT_UInt8)
    6992             :     {
    6993         213 :         EnablePixelTypeSignedByteWarning(false);
    6994             :         const char *pszPixelType =
    6995         213 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    6996         213 :         EnablePixelTypeSignedByteWarning(true);
    6997         213 :         bSignedByte =
    6998         213 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    6999             :     }
    7000             : 
    7001         510 :     GUIntBig nSampleCount = 0;
    7002         510 :     GUIntBig nValidCount = 0;
    7003             : 
    7004         510 :     if (bApproxOK && HasArbitraryOverviews())
    7005             :     {
    7006             :         /* --------------------------------------------------------------------
    7007             :          */
    7008             :         /*      Figure out how much the image should be reduced to get an */
    7009             :         /*      approximate value. */
    7010             :         /* --------------------------------------------------------------------
    7011             :          */
    7012           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7013           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7014             : 
    7015           0 :         int nXReduced = nRasterXSize;
    7016           0 :         int nYReduced = nRasterYSize;
    7017           0 :         if (dfReduction > 1.0)
    7018             :         {
    7019           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7020           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7021             : 
    7022             :             // Catch the case of huge resizing ratios here
    7023           0 :             if (nXReduced == 0)
    7024           0 :                 nXReduced = 1;
    7025           0 :             if (nYReduced == 0)
    7026           0 :                 nYReduced = 1;
    7027             :         }
    7028             : 
    7029           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    7030           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7031             : 
    7032             :         const CPLErr eErr =
    7033           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7034           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7035           0 :         if (eErr != CE_None)
    7036             :         {
    7037           0 :             CPLFree(pData);
    7038           0 :             return eErr;
    7039             :         }
    7040             : 
    7041           0 :         GByte *pabyMaskData = nullptr;
    7042           0 :         if (poMaskBand)
    7043             :         {
    7044             :             pabyMaskData =
    7045           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7046           0 :             if (!pabyMaskData)
    7047             :             {
    7048           0 :                 CPLFree(pData);
    7049           0 :                 return CE_Failure;
    7050             :             }
    7051             : 
    7052           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7053             :                                      pabyMaskData, nXReduced, nYReduced,
    7054           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    7055             :             {
    7056           0 :                 CPLFree(pData);
    7057           0 :                 CPLFree(pabyMaskData);
    7058           0 :                 return CE_Failure;
    7059             :             }
    7060             :         }
    7061             : 
    7062             :         /* this isn't the fastest way to do this, but is easier for now */
    7063           0 :         for (int iY = 0; iY < nYReduced; iY++)
    7064             :         {
    7065           0 :             for (int iX = 0; iX < nXReduced; iX++)
    7066             :             {
    7067           0 :                 const int iOffset = iX + iY * nXReduced;
    7068           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7069           0 :                     continue;
    7070             : 
    7071           0 :                 bool bValid = true;
    7072           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7073           0 :                                                iOffset, sNoDataValues, bValid);
    7074           0 :                 if (!bValid)
    7075           0 :                     continue;
    7076             : 
    7077           0 :                 dfMin = std::min(dfMin, dfValue);
    7078           0 :                 dfMax = std::max(dfMax, dfValue);
    7079             : 
    7080           0 :                 nValidCount++;
    7081           0 :                 if (dfMin == dfMax)
    7082             :                 {
    7083           0 :                     if (nValidCount == 1)
    7084           0 :                         dfMean = dfMin;
    7085             :                 }
    7086             :                 else
    7087             :                 {
    7088           0 :                     const double dfDelta = dfValue - dfMean;
    7089           0 :                     dfMean += dfDelta / nValidCount;
    7090           0 :                     dfM2 += dfDelta * (dfValue - dfMean);
    7091             :                 }
    7092             :             }
    7093             :         }
    7094             : 
    7095           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    7096             : 
    7097           0 :         CPLFree(pData);
    7098           0 :         CPLFree(pabyMaskData);
    7099             :     }
    7100             : 
    7101             :     else  // No arbitrary overviews.
    7102             :     {
    7103         510 :         if (!InitBlockInfo())
    7104         243 :             return CE_Failure;
    7105             : 
    7106             :         /* --------------------------------------------------------------------
    7107             :          */
    7108             :         /*      Figure out the ratio of blocks we will read to get an */
    7109             :         /*      approximate value. */
    7110             :         /* --------------------------------------------------------------------
    7111             :          */
    7112         510 :         int nSampleRate = 1;
    7113         510 :         if (bApproxOK)
    7114             :         {
    7115          43 :             nSampleRate = static_cast<int>(std::max(
    7116          86 :                 1.0,
    7117          43 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7118             :             // We want to avoid probing only the first column of blocks for
    7119             :             // a square shaped raster, because it is not unlikely that it may
    7120             :             // be padding only (#6378)
    7121          43 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7122           1 :                 nSampleRate += 1;
    7123             :         }
    7124         510 :         if (nSampleRate == 1)
    7125         476 :             bApproxOK = false;
    7126             : 
    7127             :         // Particular case for GDT_UInt8 and GUInt16 that only use integral types
    7128             :         // for each block, and possibly for the whole raster.
    7129         510 :         if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    7130         268 :                             eDataType == GDT_UInt16))
    7131             :         {
    7132             :             // We can do integer computation on the whole raster in the Byte case
    7133             :             // only if the number of pixels explored is lower than
    7134             :             // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
    7135             :             // Should be 99.99999% of cases.
    7136             :             // For GUInt16, this limits to raster of 4 giga pixels
    7137             : 
    7138             :             const bool bIntegerStats =
    7139         439 :                 ((eDataType == GDT_UInt8 &&
    7140         196 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7141         196 :                           nSampleRate <
    7142         196 :                       GUINTBIG_MAX / (255U * 255U) /
    7143         196 :                           (static_cast<GUInt64>(nBlockXSize) *
    7144         196 :                            static_cast<GUInt64>(nBlockYSize))) ||
    7145          47 :                  (eDataType == GDT_UInt16 &&
    7146          47 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7147          47 :                           nSampleRate <
    7148          47 :                       GUINTBIG_MAX / (65535U * 65535U) /
    7149          47 :                           (static_cast<GUInt64>(nBlockXSize) *
    7150         533 :                            static_cast<GUInt64>(nBlockYSize)))) &&
    7151             :                 // Can be set to NO for easier debugging of the !bIntegerStats
    7152             :                 // case which requires huge rasters to trigger
    7153         243 :                 CPLTestBool(
    7154         243 :                     CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
    7155             : 
    7156         243 :             const GUInt32 nMaxValueType =
    7157         243 :                 (eDataType == GDT_UInt8) ? 255 : 65535;
    7158         243 :             GUInt32 nMin = nMaxValueType;
    7159         243 :             GUInt32 nMax = 0;
    7160         243 :             GUIntBig nSum = 0;
    7161         243 :             GUIntBig nSumSquare = 0;
    7162             :             // If no valid nodata, map to invalid value (256 for Byte)
    7163         243 :             const GUInt32 nNoDataValue =
    7164         270 :                 (sNoDataValues.bGotNoDataValue &&
    7165          27 :                  sNoDataValues.dfNoDataValue >= 0 &&
    7166          27 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    7167          27 :                  fabs(sNoDataValues.dfNoDataValue -
    7168          27 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    7169             :                                            1e-10)) < 1e-10)
    7170         270 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    7171             :                     : nMaxValueType + 1;
    7172             : 
    7173         243 :             for (GIntBig iSampleBlock = 0;
    7174       13082 :                  iSampleBlock <
    7175       13082 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7176       12839 :                  iSampleBlock += nSampleRate)
    7177             :             {
    7178       12839 :                 const int iYBlock =
    7179       12839 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7180       12839 :                 const int iXBlock =
    7181       12839 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7182             : 
    7183             :                 GDALRasterBlock *const poBlock =
    7184       12839 :                     GetLockedBlockRef(iXBlock, iYBlock);
    7185       12839 :                 if (poBlock == nullptr)
    7186           0 :                     return CE_Failure;
    7187             : 
    7188       12839 :                 void *const pData = poBlock->GetDataRef();
    7189             : 
    7190       12838 :                 int nXCheck = 0, nYCheck = 0;
    7191       12838 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7192             : 
    7193       12839 :                 GUIntBig nBlockSum = 0;
    7194       12839 :                 GUIntBig nBlockSumSquare = 0;
    7195       12839 :                 GUIntBig nBlockSampleCount = 0;
    7196       12839 :                 GUIntBig nBlockValidCount = 0;
    7197       12839 :                 GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
    7198       12839 :                 GUIntBig &nBlockSumSquareRef =
    7199             :                     bIntegerStats ? nSumSquare : nBlockSumSquare;
    7200       12839 :                 GUIntBig &nBlockSampleCountRef =
    7201             :                     bIntegerStats ? nSampleCount : nBlockSampleCount;
    7202       12839 :                 GUIntBig &nBlockValidCountRef =
    7203             :                     bIntegerStats ? nValidCount : nBlockValidCount;
    7204             : 
    7205       12839 :                 if (eDataType == GDT_UInt8)
    7206             :                 {
    7207             :                     ComputeStatisticsInternal<
    7208             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    7209       12157 :                         f(nXCheck, nBlockXSize, nYCheck,
    7210             :                           static_cast<const GByte *>(pData),
    7211             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7212             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7213             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7214             :                 }
    7215             :                 else
    7216             :                 {
    7217             :                     ComputeStatisticsInternal<
    7218             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    7219         682 :                         f(nXCheck, nBlockXSize, nYCheck,
    7220             :                           static_cast<const GUInt16 *>(pData),
    7221             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7222             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7223             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7224             :                 }
    7225             : 
    7226       12839 :                 poBlock->DropLock();
    7227             : 
    7228       12839 :                 if (!bIntegerStats)
    7229             :                 {
    7230         169 :                     nSampleCount += nBlockSampleCount;
    7231         169 :                     if (nBlockValidCount)
    7232             :                     {
    7233             :                         // Update the global mean and M2 (the difference of the
    7234             :                         // square to the mean) from the values of the block
    7235             :                         // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7236         169 :                         const double dfBlockValidCount =
    7237         169 :                             static_cast<double>(nBlockValidCount);
    7238         169 :                         const double dfBlockMean =
    7239         169 :                             static_cast<double>(nBlockSum) / dfBlockValidCount;
    7240             :                         const double dfBlockM2 =
    7241         169 :                             static_cast<double>(
    7242         169 :                                 GDALUInt128::Mul(nBlockSumSquare,
    7243         169 :                                                  nBlockValidCount) -
    7244         338 :                                 GDALUInt128::Mul(nBlockSum, nBlockSum)) /
    7245         169 :                             dfBlockValidCount;
    7246         169 :                         const double dfDelta = dfBlockMean - dfMean;
    7247         169 :                         const auto nNewValidCount =
    7248         169 :                             nValidCount + nBlockValidCount;
    7249         169 :                         const double dfNewValidCount =
    7250             :                             static_cast<double>(nNewValidCount);
    7251         169 :                         dfMean +=
    7252         169 :                             dfDelta * (dfBlockValidCount / dfNewValidCount);
    7253         169 :                         dfM2 +=
    7254         169 :                             dfBlockM2 + dfDelta * dfDelta *
    7255         169 :                                             static_cast<double>(nValidCount) *
    7256         169 :                                             dfBlockValidCount / dfNewValidCount;
    7257         169 :                         nValidCount = nNewValidCount;
    7258             :                     }
    7259             :                 }
    7260             : 
    7261       12839 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    7262       12839 :                                      (static_cast<double>(nBlocksPerRow) *
    7263       12839 :                                       nBlocksPerColumn),
    7264             :                                  "Compute Statistics", pProgressData))
    7265             :                 {
    7266           0 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    7267             :                                 "User terminated");
    7268           0 :                     return CE_Failure;
    7269             :                 }
    7270             :             }
    7271             : 
    7272         243 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    7273             :             {
    7274           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7275           0 :                 return CE_Failure;
    7276             :             }
    7277             : 
    7278         243 :             double dfStdDev = 0;
    7279         243 :             if (bIntegerStats)
    7280             :             {
    7281         219 :                 if (nValidCount)
    7282         210 :                     dfMean = static_cast<double>(nSum) / nValidCount;
    7283             : 
    7284             :                 // To avoid potential precision issues when doing the difference,
    7285             :                 // we need to do that computation on 128 bit rather than casting
    7286             :                 // to double
    7287             :                 const GDALUInt128 nTmpForStdDev(
    7288         219 :                     GDALUInt128::Mul(nSumSquare, nValidCount) -
    7289         438 :                     GDALUInt128::Mul(nSum, nSum));
    7290         219 :                 dfStdDev =
    7291         219 :                     nValidCount > 0
    7292         219 :                         ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    7293             :                         : 0.0;
    7294             :             }
    7295          24 :             else if (nValidCount > 0)
    7296             :             {
    7297          24 :                 dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
    7298             :             }
    7299             : 
    7300             :             /// Save computed information
    7301         243 :             if (nValidCount > 0)
    7302             :             {
    7303         234 :                 if (bApproxOK)
    7304             :                 {
    7305          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7306             :                 }
    7307         210 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    7308             :                 {
    7309           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    7310             :                 }
    7311         234 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    7312             :             }
    7313             : 
    7314         243 :             SetValidPercent(nSampleCount, nValidCount);
    7315             : 
    7316             :             /* --------------------------------------------------------------------
    7317             :              */
    7318             :             /*      Record results. */
    7319             :             /* --------------------------------------------------------------------
    7320             :              */
    7321         243 :             if (pdfMin != nullptr)
    7322         240 :                 *pdfMin = nValidCount ? nMin : 0;
    7323         243 :             if (pdfMax != nullptr)
    7324         240 :                 *pdfMax = nValidCount ? nMax : 0;
    7325             : 
    7326         243 :             if (pdfMean != nullptr)
    7327         236 :                 *pdfMean = dfMean;
    7328             : 
    7329         243 :             if (pdfStdDev != nullptr)
    7330         236 :                 *pdfStdDev = dfStdDev;
    7331             : 
    7332         243 :             if (nValidCount > 0)
    7333         234 :                 return CE_None;
    7334             : 
    7335           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    7336             :                         "Failed to compute statistics, no valid pixels found "
    7337             :                         "in sampling.");
    7338           9 :             return CE_Failure;
    7339             :         }
    7340             : 
    7341         267 :         GByte *pabyMaskData = nullptr;
    7342         267 :         if (poMaskBand)
    7343             :         {
    7344             :             pabyMaskData = static_cast<GByte *>(
    7345          46 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7346          46 :             if (!pabyMaskData)
    7347             :             {
    7348           0 :                 return CE_Failure;
    7349             :             }
    7350             :         }
    7351             : 
    7352         267 :         float fMin = std::numeric_limits<float>::infinity();
    7353         267 :         float fMax = -std::numeric_limits<float>::infinity();
    7354             :         const bool bFloat32Optim =
    7355          44 :             eDataType == GDT_Float32 && !pabyMaskData &&
    7356         329 :             nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
    7357          18 :             CPLTestBool(
    7358         267 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
    7359             : 
    7360             : #if (defined(__x86_64__) || defined(_M_X64))
    7361             :         const bool bFloat64Optim =
    7362          13 :             eDataType == GDT_Float64 && !pabyMaskData &&
    7363         293 :             nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
    7364          13 :             CPLTestBool(
    7365         267 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
    7366             : #endif
    7367             : 
    7368         267 :         for (GIntBig iSampleBlock = 0;
    7369        5918 :              iSampleBlock <
    7370        5918 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7371        5651 :              iSampleBlock += nSampleRate)
    7372             :         {
    7373        5651 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    7374        5651 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    7375             : 
    7376        5651 :             int nXCheck = 0, nYCheck = 0;
    7377        5651 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7378             : 
    7379        6224 :             if (poMaskBand &&
    7380         573 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7381         573 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    7382             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    7383         573 :                                      0, nBlockXSize, nullptr) != CE_None)
    7384             :             {
    7385           0 :                 CPLFree(pabyMaskData);
    7386           0 :                 return CE_Failure;
    7387             :             }
    7388             : 
    7389             :             GDALRasterBlock *const poBlock =
    7390        5651 :                 GetLockedBlockRef(iXBlock, iYBlock);
    7391        5651 :             if (poBlock == nullptr)
    7392             :             {
    7393           0 :                 CPLFree(pabyMaskData);
    7394           0 :                 return CE_Failure;
    7395             :             }
    7396             : 
    7397        5651 :             const void *const pData = poBlock->GetDataRef();
    7398             : 
    7399        5651 :             if (bFloat32Optim)
    7400             :             {
    7401        2330 :                 const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
    7402           0 :                                         !std::isnan(sNoDataValues.fNoDataValue);
    7403        2330 :                 float fBlockMean = 0.0f;
    7404        2330 :                 float fBlockM2 = 0.0f;
    7405        2330 :                 int nBlockValidCount = 0;
    7406        7219 :                 for (int iY = 0; iY < nYCheck; iY++)
    7407             :                 {
    7408        4889 :                     const int iOffset = iY * nBlockXSize;
    7409        4889 :                     if (nBlockValidCount && fMin != fMax)
    7410             :                     {
    7411        2432 :                         int iX = 0;
    7412             : #if (defined(__x86_64__) || defined(_M_X64))
    7413        2432 :                         if (bHasNoData)
    7414             :                         {
    7415             :                             iX = ComputeStatisticsFloat32_SSE2<
    7416             :                                 /* bCheckMinEqMax = */ false,
    7417           0 :                                 /* bHasNoData = */ true>(
    7418           0 :                                 static_cast<const float *>(pData) + iOffset,
    7419             :                                 sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
    7420             :                                 fMax, fBlockMean, fBlockM2, nBlockValidCount);
    7421             :                         }
    7422             :                         else
    7423             :                         {
    7424             :                             iX = ComputeStatisticsFloat32_SSE2<
    7425             :                                 /* bCheckMinEqMax = */ false,
    7426        2432 :                                 /* bHasNoData = */ false>(
    7427        2432 :                                 static_cast<const float *>(pData) + iOffset,
    7428             :                                 sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
    7429             :                                 fMax, fBlockMean, fBlockM2, nBlockValidCount);
    7430             :                         }
    7431             : #endif
    7432        2961 :                         for (; iX < nXCheck; iX++)
    7433             :                         {
    7434         529 :                             const float fValue =
    7435         529 :                                 static_cast<const float *>(pData)[iOffset + iX];
    7436         529 :                             if (std::isnan(fValue) ||
    7437           0 :                                 (bHasNoData &&
    7438           0 :                                  fValue == sNoDataValues.fNoDataValue))
    7439          11 :                                 continue;
    7440         518 :                             fMin = std::min(fMin, fValue);
    7441         518 :                             fMax = std::max(fMax, fValue);
    7442         518 :                             ++nBlockValidCount;
    7443         518 :                             const float fDelta = fValue - fBlockMean;
    7444         518 :                             fBlockMean +=
    7445         518 :                                 fDelta / static_cast<float>(nBlockValidCount);
    7446         518 :                             fBlockM2 += fDelta * (fValue - fBlockMean);
    7447        2432 :                         }
    7448             :                     }
    7449             :                     else
    7450             :                     {
    7451        2457 :                         int iX = 0;
    7452        2457 :                         if (nBlockValidCount == 0)
    7453             :                         {
    7454        2330 :                             for (; iX < nXCheck; iX++)
    7455             :                             {
    7456        2330 :                                 const float fValue = static_cast<const float *>(
    7457        2330 :                                     pData)[iOffset + iX];
    7458        2330 :                                 if (std::isnan(fValue) ||
    7459           0 :                                     (bHasNoData &&
    7460           0 :                                      fValue == sNoDataValues.fNoDataValue))
    7461           0 :                                     continue;
    7462        2330 :                                 fMin = std::min(fMin, fValue);
    7463        2330 :                                 fMax = std::max(fMax, fValue);
    7464        2330 :                                 nBlockValidCount = 1;
    7465        2330 :                                 fBlockMean = fValue;
    7466        2330 :                                 iX++;
    7467        2330 :                                 break;
    7468             :                             }
    7469             :                         }
    7470             : #if (defined(__x86_64__) || defined(_M_X64))
    7471        2457 :                         if (bHasNoData)
    7472             :                         {
    7473             :                             iX = ComputeStatisticsFloat32_SSE2<
    7474             :                                 /* bCheckMinEqMax = */ true,
    7475           0 :                                 /* bHasNoData = */ true>(
    7476           0 :                                 static_cast<const float *>(pData) + iOffset,
    7477             :                                 sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
    7478             :                                 fMax, fBlockMean, fBlockM2, nBlockValidCount);
    7479             :                         }
    7480             :                         else
    7481             :                         {
    7482             :                             iX = ComputeStatisticsFloat32_SSE2<
    7483             :                                 /* bCheckMinEqMax = */ true,
    7484        2457 :                                 /* bHasNoData = */ false>(
    7485        2457 :                                 static_cast<const float *>(pData) + iOffset,
    7486             :                                 sNoDataValues.fNoDataValue, iX, nXCheck, fMin,
    7487             :                                 fMax, fBlockMean, fBlockM2, nBlockValidCount);
    7488             :                         }
    7489             : #endif
    7490       17534 :                         for (; iX < nXCheck; iX++)
    7491             :                         {
    7492       15077 :                             const float fValue =
    7493       15077 :                                 static_cast<const float *>(pData)[iOffset + iX];
    7494       15077 :                             if (std::isnan(fValue) ||
    7495           0 :                                 (bHasNoData &&
    7496           0 :                                  fValue == sNoDataValues.fNoDataValue))
    7497           1 :                                 continue;
    7498       15076 :                             fMin = std::min(fMin, fValue);
    7499       15076 :                             fMax = std::max(fMax, fValue);
    7500       15076 :                             ++nBlockValidCount;
    7501       15076 :                             if (fMin != fMax)
    7502             :                             {
    7503        7123 :                                 const float fDelta = fValue - fBlockMean;
    7504        7123 :                                 fBlockMean += fDelta / static_cast<float>(
    7505             :                                                            nBlockValidCount);
    7506        7123 :                                 fBlockM2 += fDelta * (fValue - fBlockMean);
    7507             :                             }
    7508             :                         }
    7509             :                     }
    7510             :                 }
    7511             : 
    7512        2330 :                 if (nBlockValidCount)
    7513             :                 {
    7514             :                     // Update the global mean and M2 (the difference of the
    7515             :                     // square to the mean) from the values of the block
    7516             :                     // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7517        2330 :                     const auto nNewValidCount = nValidCount + nBlockValidCount;
    7518        2330 :                     const double dfBlockMean = static_cast<double>(fBlockMean);
    7519        2330 :                     if (dfBlockMean != dfMean)
    7520             :                     {
    7521        1066 :                         const double dfBlockM2 = static_cast<double>(fBlockM2);
    7522        1066 :                         if (nValidCount == 0)
    7523             :                         {
    7524          13 :                             dfMean = dfBlockMean;
    7525          13 :                             dfM2 = dfBlockM2;
    7526             :                         }
    7527             :                         else
    7528             :                         {
    7529        1053 :                             const double dfBlockValidCount =
    7530        1053 :                                 static_cast<double>(nBlockValidCount);
    7531        1053 :                             const double dfDelta = dfBlockMean - dfMean;
    7532        1053 :                             const double dfNewValidCount =
    7533             :                                 static_cast<double>(nNewValidCount);
    7534        1053 :                             dfMean +=
    7535        1053 :                                 dfDelta * (dfBlockValidCount / dfNewValidCount);
    7536        1053 :                             dfM2 += dfBlockM2 +
    7537        1053 :                                     dfDelta * dfDelta *
    7538        1053 :                                         static_cast<double>(nValidCount) *
    7539        1053 :                                         dfBlockValidCount / dfNewValidCount;
    7540             :                         }
    7541             :                     }
    7542        2330 :                     nValidCount = nNewValidCount;
    7543             :                 }
    7544             :             }
    7545             : 
    7546             : #if (defined(__x86_64__) || defined(_M_X64))
    7547        3321 :             else if (bFloat64Optim)
    7548             :             {
    7549             :                 const bool bHasNoData =
    7550         545 :                     sNoDataValues.bGotNoDataValue &&
    7551         263 :                     !std::isnan(sNoDataValues.dfNoDataValue);
    7552         282 :                 double dfBlockMean = 0;
    7553         282 :                 double dfBlockM2 = 0;
    7554         282 :                 double dfBlockValidCount = 0;
    7555        1633 :                 for (int iY = 0; iY < nYCheck; iY++)
    7556             :                 {
    7557        1351 :                     const int iOffset = iY * nBlockXSize;
    7558        1351 :                     if (dfBlockValidCount != 0 && dfMin != dfMax)
    7559             :                     {
    7560         813 :                         int iX = 0;
    7561         813 :                         if (bHasNoData)
    7562             :                         {
    7563             :                             iX = ComputeStatisticsFloat64_SSE2<
    7564             :                                 /* bCheckMinEqMax = */ false,
    7565         381 :                                 /* bHasNoData = */ true>(
    7566         381 :                                 static_cast<const double *>(pData) + iOffset,
    7567             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7568             :                                 dfMax, dfBlockMean, dfBlockM2,
    7569             :                                 dfBlockValidCount);
    7570             :                         }
    7571             :                         else
    7572             :                         {
    7573             :                             iX = ComputeStatisticsFloat64_SSE2<
    7574             :                                 /* bCheckMinEqMax = */ false,
    7575         432 :                                 /* bHasNoData = */ false>(
    7576         432 :                                 static_cast<const double *>(pData) + iOffset,
    7577             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7578             :                                 dfMax, dfBlockMean, dfBlockM2,
    7579             :                                 dfBlockValidCount);
    7580             :                         }
    7581        1931 :                         for (; iX < nXCheck; iX++)
    7582             :                         {
    7583        1118 :                             const double dfValue = static_cast<const double *>(
    7584        1118 :                                 pData)[iOffset + iX];
    7585        1625 :                             if (std::isnan(dfValue) ||
    7586         507 :                                 (bHasNoData &&
    7587         507 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7588          53 :                                 continue;
    7589        1065 :                             dfMin = std::min(dfMin, dfValue);
    7590        1065 :                             dfMax = std::max(dfMax, dfValue);
    7591        1065 :                             dfBlockValidCount += 1.0;
    7592        1065 :                             const double dfDelta = dfValue - dfBlockMean;
    7593        1065 :                             dfBlockMean += dfDelta / dfBlockValidCount;
    7594        1065 :                             dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7595         813 :                         }
    7596             :                     }
    7597             :                     else
    7598             :                     {
    7599         538 :                         int iX = 0;
    7600         538 :                         if (dfBlockValidCount == 0)
    7601             :                         {
    7602        7661 :                             for (; iX < nXCheck; iX++)
    7603             :                             {
    7604        7627 :                                 const double dfValue =
    7605             :                                     static_cast<const double *>(
    7606        7627 :                                         pData)[iOffset + iX];
    7607       15235 :                                 if (std::isnan(dfValue) ||
    7608        7608 :                                     (bHasNoData &&
    7609        7608 :                                      dfValue == sNoDataValues.dfNoDataValue))
    7610        7377 :                                     continue;
    7611         250 :                                 dfMin = std::min(dfMin, dfValue);
    7612         250 :                                 dfMax = std::max(dfMax, dfValue);
    7613         250 :                                 dfBlockValidCount = 1;
    7614         250 :                                 dfBlockMean = dfValue;
    7615         250 :                                 iX++;
    7616         250 :                                 break;
    7617             :                             }
    7618             :                         }
    7619         538 :                         if (bHasNoData)
    7620             :                         {
    7621             :                             iX = ComputeStatisticsFloat64_SSE2<
    7622             :                                 /* bCheckMinEqMax = */ true,
    7623         392 :                                 /* bHasNoData = */ true>(
    7624         392 :                                 static_cast<const double *>(pData) + iOffset,
    7625             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7626             :                                 dfMax, dfBlockMean, dfBlockM2,
    7627             :                                 dfBlockValidCount);
    7628             :                         }
    7629             :                         else
    7630             :                         {
    7631             :                             iX = ComputeStatisticsFloat64_SSE2<
    7632             :                                 /* bCheckMinEqMax = */ true,
    7633         146 :                                 /* bHasNoData = */ false>(
    7634         146 :                                 static_cast<const double *>(pData) + iOffset,
    7635             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7636             :                                 dfMax, dfBlockMean, dfBlockM2,
    7637             :                                 dfBlockValidCount);
    7638             :                         }
    7639        1081 :                         for (; iX < nXCheck; iX++)
    7640             :                         {
    7641         543 :                             const double dfValue = static_cast<const double *>(
    7642         543 :                                 pData)[iOffset + iX];
    7643        1065 :                             if (std::isnan(dfValue) ||
    7644         522 :                                 (bHasNoData &&
    7645         522 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7646         140 :                                 continue;
    7647         403 :                             dfMin = std::min(dfMin, dfValue);
    7648         403 :                             dfMax = std::max(dfMax, dfValue);
    7649         403 :                             dfBlockValidCount += 1.0;
    7650         403 :                             if (dfMin != dfMax)
    7651             :                             {
    7652         128 :                                 const double dfDelta = dfValue - dfBlockMean;
    7653         128 :                                 dfBlockMean += dfDelta / dfBlockValidCount;
    7654         128 :                                 dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7655             :                             }
    7656             :                         }
    7657             :                     }
    7658             :                 }
    7659             : 
    7660         282 :                 if (dfBlockValidCount > 0)
    7661             :                 {
    7662             :                     // Update the global mean and M2 (the difference of the
    7663             :                     // square to the mean) from the values of the block
    7664             :                     // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7665         250 :                     const auto nNewValidCount =
    7666         250 :                         nValidCount + static_cast<int>(dfBlockValidCount);
    7667         250 :                     if (dfBlockMean != dfMean)
    7668             :                     {
    7669         237 :                         if (nValidCount == 0)
    7670             :                         {
    7671          11 :                             dfMean = dfBlockMean;
    7672          11 :                             dfM2 = dfBlockM2;
    7673             :                         }
    7674             :                         else
    7675             :                         {
    7676         226 :                             const double dfDelta = dfBlockMean - dfMean;
    7677         226 :                             const double dfNewValidCount =
    7678             :                                 static_cast<double>(nNewValidCount);
    7679         226 :                             dfMean +=
    7680         226 :                                 dfDelta * (dfBlockValidCount / dfNewValidCount);
    7681         226 :                             dfM2 += dfBlockM2 +
    7682         226 :                                     dfDelta * dfDelta *
    7683         226 :                                         static_cast<double>(nValidCount) *
    7684         226 :                                         dfBlockValidCount / dfNewValidCount;
    7685             :                         }
    7686             :                     }
    7687         250 :                     nValidCount = nNewValidCount;
    7688             :                 }
    7689             :             }
    7690             : #endif  // (defined(__x86_64__) || defined(_M_X64))
    7691             : 
    7692             :             else
    7693             :             {
    7694             :                 // This isn't the fastest way to do this, but is easier for now.
    7695        8754 :                 for (int iY = 0; iY < nYCheck; iY++)
    7696             :                 {
    7697        5715 :                     if (nValidCount && dfMin != dfMax)
    7698             :                     {
    7699      212546 :                         for (int iX = 0; iX < nXCheck; iX++)
    7700             :                         {
    7701      209962 :                             const GPtrDiff_t iOffset =
    7702      209962 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7703      209962 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7704        9635 :                                 continue;
    7705             : 
    7706      200339 :                             bool bValid = true;
    7707             :                             double dfValue =
    7708      200339 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    7709      200339 :                                               iOffset, sNoDataValues, bValid);
    7710             : 
    7711      200339 :                             if (!bValid)
    7712          12 :                                 continue;
    7713             : 
    7714      200327 :                             dfMin = std::min(dfMin, dfValue);
    7715      200327 :                             dfMax = std::max(dfMax, dfValue);
    7716             : 
    7717      200327 :                             nValidCount++;
    7718      200327 :                             const double dfDelta = dfValue - dfMean;
    7719      200327 :                             dfMean += dfDelta / nValidCount;
    7720      200327 :                             dfM2 += dfDelta * (dfValue - dfMean);
    7721        2584 :                         }
    7722             :                     }
    7723             :                     else
    7724             :                     {
    7725        3131 :                         int iX = 0;
    7726        3131 :                         if (nValidCount == 0)
    7727             :                         {
    7728       94577 :                             for (; iX < nXCheck; iX++)
    7729             :                             {
    7730       94520 :                                 const GPtrDiff_t iOffset =
    7731       94520 :                                     iX +
    7732       94520 :                                     static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7733       94520 :                                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7734       94282 :                                     continue;
    7735             : 
    7736         239 :                                 bool bValid = true;
    7737         239 :                                 double dfValue = GetPixelValue(
    7738             :                                     eDataType, bSignedByte, pData, iOffset,
    7739             :                                     sNoDataValues, bValid);
    7740             : 
    7741         239 :                                 if (!bValid)
    7742           1 :                                     continue;
    7743             : 
    7744         238 :                                 dfMin = dfValue;
    7745         238 :                                 dfMax = dfValue;
    7746         238 :                                 dfMean = dfValue;
    7747         238 :                                 nValidCount = 1;
    7748         238 :                                 iX++;
    7749         238 :                                 break;
    7750             :                             }
    7751             :                         }
    7752      227675 :                         for (; iX < nXCheck; iX++)
    7753             :                         {
    7754      224544 :                             const GPtrDiff_t iOffset =
    7755      224544 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7756      224544 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7757         358 :                                 continue;
    7758             : 
    7759      224187 :                             bool bValid = true;
    7760             :                             double dfValue =
    7761      224187 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    7762      224187 :                                               iOffset, sNoDataValues, bValid);
    7763             : 
    7764      224187 :                             if (!bValid)
    7765           1 :                                 continue;
    7766             : 
    7767      224186 :                             dfMin = std::min(dfMin, dfValue);
    7768      224186 :                             dfMax = std::max(dfMax, dfValue);
    7769             : 
    7770      224186 :                             nValidCount++;
    7771      224186 :                             if (dfMin != dfMax)
    7772             :                             {
    7773        2170 :                                 const double dfDelta = dfValue - dfMean;
    7774        2170 :                                 dfMean += dfDelta / nValidCount;
    7775        2170 :                                 dfM2 += dfDelta * (dfValue - dfMean);
    7776             :                             }
    7777             :                         }
    7778             :                     }
    7779             :                 }
    7780             :             }
    7781             : 
    7782        5651 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    7783             : 
    7784        5651 :             poBlock->DropLock();
    7785             : 
    7786        5651 :             if (!pfnProgress(
    7787        5651 :                     static_cast<double>(iSampleBlock) /
    7788        5651 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    7789             :                     "Compute Statistics", pProgressData))
    7790             :             {
    7791           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7792           0 :                 CPLFree(pabyMaskData);
    7793           0 :                 return CE_Failure;
    7794             :             }
    7795             :         }
    7796             : 
    7797         267 :         if (bFloat32Optim)
    7798             :         {
    7799          17 :             dfMin = static_cast<double>(fMin);
    7800          17 :             dfMax = static_cast<double>(fMax);
    7801             :         }
    7802         267 :         CPLFree(pabyMaskData);
    7803             :     }
    7804             : 
    7805         267 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    7806             :     {
    7807           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7808           0 :         return CE_Failure;
    7809             :     }
    7810             : 
    7811             :     /* -------------------------------------------------------------------- */
    7812             :     /*      Save computed information.                                      */
    7813             :     /* -------------------------------------------------------------------- */
    7814         267 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    7815             : 
    7816         267 :     if (nValidCount > 0)
    7817             :     {
    7818         266 :         if (bApproxOK)
    7819             :         {
    7820           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7821             :         }
    7822         258 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    7823             :         {
    7824           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    7825             :         }
    7826         266 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    7827             :     }
    7828             :     else
    7829             :     {
    7830           1 :         dfMin = 0.0;
    7831           1 :         dfMax = 0.0;
    7832             :     }
    7833             : 
    7834         267 :     SetValidPercent(nSampleCount, nValidCount);
    7835             : 
    7836             :     /* -------------------------------------------------------------------- */
    7837             :     /*      Record results.                                                 */
    7838             :     /* -------------------------------------------------------------------- */
    7839         267 :     if (pdfMin != nullptr)
    7840         264 :         *pdfMin = dfMin;
    7841         267 :     if (pdfMax != nullptr)
    7842         264 :         *pdfMax = dfMax;
    7843             : 
    7844         267 :     if (pdfMean != nullptr)
    7845         261 :         *pdfMean = dfMean;
    7846             : 
    7847         267 :     if (pdfStdDev != nullptr)
    7848         261 :         *pdfStdDev = dfStdDev;
    7849             : 
    7850         267 :     if (nValidCount > 0)
    7851         266 :         return CE_None;
    7852             : 
    7853           1 :     ReportError(
    7854             :         CE_Failure, CPLE_AppDefined,
    7855             :         "Failed to compute statistics, no valid pixels found in sampling.");
    7856           1 :     return CE_Failure;
    7857             : }
    7858             : 
    7859             : /************************************************************************/
    7860             : /*                    GDALComputeRasterStatistics()                     */
    7861             : /************************************************************************/
    7862             : 
    7863             : /**
    7864             :  * \brief Compute image statistics.
    7865             :  *
    7866             :  * @see GDALRasterBand::ComputeStatistics()
    7867             :  */
    7868             : 
    7869         169 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    7870             :                                                int bApproxOK, double *pdfMin,
    7871             :                                                double *pdfMax, double *pdfMean,
    7872             :                                                double *pdfStdDev,
    7873             :                                                GDALProgressFunc pfnProgress,
    7874             :                                                void *pProgressData)
    7875             : 
    7876             : {
    7877         169 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    7878             : 
    7879         169 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7880             : 
    7881         169 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    7882         169 :                                      pdfStdDev, pfnProgress, pProgressData);
    7883             : }
    7884             : 
    7885             : /************************************************************************/
    7886             : /*                           SetStatistics()                            */
    7887             : /************************************************************************/
    7888             : 
    7889             : /**
    7890             :  * \brief Set statistics on band.
    7891             :  *
    7892             :  * This method can be used to store min/max/mean/standard deviation
    7893             :  * statistics on a raster band.
    7894             :  *
    7895             :  * The default implementation stores them as metadata, and will only work
    7896             :  * on formats that can save arbitrary metadata.  This method cannot detect
    7897             :  * whether metadata will be properly saved and so may return CE_None even
    7898             :  * if the statistics will never be saved.
    7899             :  *
    7900             :  * This method is the same as the C function GDALSetRasterStatistics().
    7901             :  *
    7902             :  * @param dfMin minimum pixel value.
    7903             :  *
    7904             :  * @param dfMax maximum pixel value.
    7905             :  *
    7906             :  * @param dfMean mean (average) of all pixel values.
    7907             :  *
    7908             :  * @param dfStdDev Standard deviation of all pixel values.
    7909             :  *
    7910             :  * @return CE_None on success or CE_Failure on failure.
    7911             :  */
    7912             : 
    7913         533 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    7914             :                                      double dfStdDev)
    7915             : 
    7916             : {
    7917         533 :     char szValue[128] = {0};
    7918             : 
    7919         533 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    7920         533 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    7921             : 
    7922         533 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    7923         533 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    7924             : 
    7925         533 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    7926         533 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    7927             : 
    7928         533 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    7929         533 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    7930             : 
    7931         533 :     return CE_None;
    7932             : }
    7933             : 
    7934             : /************************************************************************/
    7935             : /*                      GDALSetRasterStatistics()                       */
    7936             : /************************************************************************/
    7937             : 
    7938             : /**
    7939             :  * \brief Set statistics on band.
    7940             :  *
    7941             :  * @see GDALRasterBand::SetStatistics()
    7942             :  */
    7943             : 
    7944           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    7945             :                                            double dfMax, double dfMean,
    7946             :                                            double dfStdDev)
    7947             : 
    7948             : {
    7949           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    7950             : 
    7951           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7952           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    7953             : }
    7954             : 
    7955             : /************************************************************************/
    7956             : /*                        ComputeRasterMinMax()                         */
    7957             : /************************************************************************/
    7958             : 
    7959             : template <class T, bool HAS_NODATA>
    7960           2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    7961             :                           T *pMax)
    7962             : {
    7963           2 :     T min0 = *pMin;
    7964           2 :     T max0 = *pMax;
    7965           2 :     T min1 = *pMin;
    7966           2 :     T max1 = *pMax;
    7967             :     size_t i;
    7968           2 :     for (i = 0; i + 1 < nElts; i += 2)
    7969             :     {
    7970           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7971             :         {
    7972           0 :             min0 = std::min(min0, buffer[i]);
    7973           0 :             max0 = std::max(max0, buffer[i]);
    7974             :         }
    7975           0 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    7976             :         {
    7977           0 :             min1 = std::min(min1, buffer[i + 1]);
    7978           0 :             max1 = std::max(max1, buffer[i + 1]);
    7979             :         }
    7980             :     }
    7981           2 :     T min = std::min(min0, min1);
    7982           2 :     T max = std::max(max0, max1);
    7983           2 :     if (i < nElts)
    7984             :     {
    7985           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7986             :         {
    7987           2 :             min = std::min(min, buffer[i]);
    7988           2 :             max = std::max(max, buffer[i]);
    7989             :         }
    7990             :     }
    7991           2 :     *pMin = min;
    7992           2 :     *pMax = max;
    7993           2 : }
    7994             : 
    7995             : template <GDALDataType eDataType, bool bSignedByte>
    7996             : static void
    7997        6703 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    7998             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    7999             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    8000             : {
    8001        6703 :     double dfLocalMin = dfMin;
    8002        6703 :     double dfLocalMax = dfMax;
    8003             : 
    8004       22051 :     for (int iY = 0; iY < nYCheck; iY++)
    8005             :     {
    8006    14858421 :         for (int iX = 0; iX < nXCheck; iX++)
    8007             :         {
    8008    14843085 :             const GPtrDiff_t iOffset =
    8009    14843085 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    8010    14843085 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8011      109836 :                 continue;
    8012    14760102 :             bool bValid = true;
    8013    14760102 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    8014             :                                            iOffset, sNoDataValues, bValid);
    8015    14760102 :             if (!bValid)
    8016       26871 :                 continue;
    8017             : 
    8018    14733202 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    8019    14733202 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    8020             :         }
    8021             :     }
    8022             : 
    8023        6703 :     dfMin = dfLocalMin;
    8024        6703 :     dfMax = dfLocalMax;
    8025        6703 : }
    8026             : 
    8027        6703 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    8028             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    8029             :                                  int nBlockXSize,
    8030             :                                  const GDALNoDataValues &sNoDataValues,
    8031             :                                  const GByte *pabyMaskData, double &dfMin,
    8032             :                                  double &dfMax)
    8033             : {
    8034        6703 :     switch (eDataType)
    8035             :     {
    8036           0 :         case GDT_Unknown:
    8037           0 :             CPLAssert(false);
    8038             :             break;
    8039         660 :         case GDT_UInt8:
    8040         660 :             if (bSignedByte)
    8041             :             {
    8042           3 :                 ComputeMinMaxGeneric<GDT_UInt8, true>(
    8043             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8044             :                     pabyMaskData, dfMin, dfMax);
    8045             :             }
    8046             :             else
    8047             :             {
    8048         657 :                 ComputeMinMaxGeneric<GDT_UInt8, false>(
    8049             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8050             :                     pabyMaskData, dfMin, dfMax);
    8051             :             }
    8052         660 :             break;
    8053           4 :         case GDT_Int8:
    8054           4 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    8055             :                                                   nBlockXSize, sNoDataValues,
    8056             :                                                   pabyMaskData, dfMin, dfMax);
    8057           4 :             break;
    8058         969 :         case GDT_UInt16:
    8059         969 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    8060             :                                                     nBlockXSize, sNoDataValues,
    8061             :                                                     pabyMaskData, dfMin, dfMax);
    8062         969 :             break;
    8063           2 :         case GDT_Int16:
    8064           2 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    8065             :                                                    nBlockXSize, sNoDataValues,
    8066             :                                                    pabyMaskData, dfMin, dfMax);
    8067           2 :             break;
    8068           3 :         case GDT_UInt32:
    8069           3 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    8070             :                                                     nBlockXSize, sNoDataValues,
    8071             :                                                     pabyMaskData, dfMin, dfMax);
    8072           3 :             break;
    8073           3 :         case GDT_Int32:
    8074           3 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    8075             :                                                    nBlockXSize, sNoDataValues,
    8076             :                                                    pabyMaskData, dfMin, dfMax);
    8077           3 :             break;
    8078           4 :         case GDT_UInt64:
    8079           4 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    8080             :                                                     nBlockXSize, sNoDataValues,
    8081             :                                                     pabyMaskData, dfMin, dfMax);
    8082           4 :             break;
    8083           4 :         case GDT_Int64:
    8084           4 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    8085             :                                                    nBlockXSize, sNoDataValues,
    8086             :                                                    pabyMaskData, dfMin, dfMax);
    8087           4 :             break;
    8088           2 :         case GDT_Float16:
    8089           2 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    8090             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8091             :                 pabyMaskData, dfMin, dfMax);
    8092           2 :             break;
    8093        4941 :         case GDT_Float32:
    8094        4941 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    8095             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8096             :                 pabyMaskData, dfMin, dfMax);
    8097        4941 :             break;
    8098           1 :         case GDT_Float64:
    8099           1 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    8100             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8101             :                 pabyMaskData, dfMin, dfMax);
    8102           1 :             break;
    8103           9 :         case GDT_CInt16:
    8104           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    8105             :                                                     nBlockXSize, sNoDataValues,
    8106             :                                                     pabyMaskData, dfMin, dfMax);
    8107           9 :             break;
    8108           9 :         case GDT_CInt32:
    8109           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    8110             :                                                     nBlockXSize, sNoDataValues,
    8111             :                                                     pabyMaskData, dfMin, dfMax);
    8112           9 :             break;
    8113           0 :         case GDT_CFloat16:
    8114           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    8115             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8116             :                 pabyMaskData, dfMin, dfMax);
    8117           0 :             break;
    8118          75 :         case GDT_CFloat32:
    8119          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    8120             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8121             :                 pabyMaskData, dfMin, dfMax);
    8122          75 :             break;
    8123          17 :         case GDT_CFloat64:
    8124          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    8125             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8126             :                 pabyMaskData, dfMin, dfMax);
    8127          17 :             break;
    8128           0 :         case GDT_TypeCount:
    8129           0 :             CPLAssert(false);
    8130             :             break;
    8131             :     }
    8132        6703 : }
    8133             : 
    8134         189 : static bool ComputeMinMaxGenericIterBlocks(
    8135             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    8136             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    8137             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    8138             :     double &dfMin, double &dfMax)
    8139             : 
    8140             : {
    8141         189 :     GByte *pabyMaskData = nullptr;
    8142             :     int nBlockXSize, nBlockYSize;
    8143         189 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    8144             : 
    8145         189 :     if (poMaskBand)
    8146             :     {
    8147             :         pabyMaskData =
    8148         125 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8149         125 :         if (!pabyMaskData)
    8150             :         {
    8151           0 :             return false;
    8152             :         }
    8153             :     }
    8154             : 
    8155        6892 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    8156        6703 :          iSampleBlock += nSampleRate)
    8157             :     {
    8158        6703 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    8159        6703 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    8160             : 
    8161        6703 :         int nXCheck = 0, nYCheck = 0;
    8162        6703 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8163             : 
    8164       13283 :         if (poMaskBand &&
    8165        6580 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    8166             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    8167             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    8168             :                                  nBlockXSize, nullptr) != CE_None)
    8169             :         {
    8170           0 :             CPLFree(pabyMaskData);
    8171           0 :             return false;
    8172             :         }
    8173             : 
    8174        6703 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    8175        6703 :         if (poBlock == nullptr)
    8176             :         {
    8177           0 :             CPLFree(pabyMaskData);
    8178           0 :             return false;
    8179             :         }
    8180             : 
    8181        6703 :         void *const pData = poBlock->GetDataRef();
    8182             : 
    8183        6703 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    8184             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    8185             :                              dfMax);
    8186             : 
    8187        6703 :         poBlock->DropLock();
    8188             :     }
    8189             : 
    8190         189 :     CPLFree(pabyMaskData);
    8191         189 :     return true;
    8192             : }
    8193             : 
    8194             : /**
    8195             :  * \brief Compute the min/max values for a band.
    8196             :  *
    8197             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    8198             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    8199             :  * get an approximate min/max.  If the band has a nodata value it will
    8200             :  * be excluded from the minimum and maximum.
    8201             :  *
    8202             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    8203             :  * an exact range.
    8204             :  *
    8205             :  * This method is the same as the C function GDALComputeRasterMinMax().
    8206             :  *
    8207             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    8208             :  * FALSE.
    8209             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    8210             :  * maximum (adfMinMax[1]) are returned.
    8211             :  *
    8212             :  * @return CE_None on success or CE_Failure on failure.
    8213             :  */
    8214             : 
    8215        1814 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    8216             : {
    8217             :     /* -------------------------------------------------------------------- */
    8218             :     /*      Does the driver already know the min/max?                       */
    8219             :     /* -------------------------------------------------------------------- */
    8220        1814 :     if (bApproxOK)
    8221             :     {
    8222          23 :         int bSuccessMin = FALSE;
    8223          23 :         int bSuccessMax = FALSE;
    8224             : 
    8225          23 :         double dfMin = GetMinimum(&bSuccessMin);
    8226          23 :         double dfMax = GetMaximum(&bSuccessMax);
    8227             : 
    8228          23 :         if (bSuccessMin && bSuccessMax)
    8229             :         {
    8230           1 :             adfMinMax[0] = dfMin;
    8231           1 :             adfMinMax[1] = dfMax;
    8232           1 :             return CE_None;
    8233             :         }
    8234             :     }
    8235             : 
    8236             :     /* -------------------------------------------------------------------- */
    8237             :     /*      If we have overview bands, use them for min/max.                */
    8238             :     /* -------------------------------------------------------------------- */
    8239             :     // cppcheck-suppress knownConditionTrueFalse
    8240        1813 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    8241             :     {
    8242             :         GDALRasterBand *poBand =
    8243           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    8244             : 
    8245           0 :         if (poBand != this)
    8246           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    8247             :     }
    8248             : 
    8249             :     /* -------------------------------------------------------------------- */
    8250             :     /*      Read actual data and compute minimum and maximum.               */
    8251             :     /* -------------------------------------------------------------------- */
    8252        1813 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8253        1813 :     GDALRasterBand *poMaskBand = nullptr;
    8254        1813 :     if (!sNoDataValues.bGotNoDataValue)
    8255             :     {
    8256        1551 :         const int l_nMaskFlags = GetMaskFlags();
    8257        1676 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8258         125 :             GetColorInterpretation() != GCI_AlphaBand)
    8259             :         {
    8260         125 :             poMaskBand = GetMaskBand();
    8261             :         }
    8262             :     }
    8263             : 
    8264        1813 :     if (!bApproxOK &&
    8265        1791 :         (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
    8266        1653 :          eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
    8267        1450 :          eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
    8268        1404 :          eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
    8269        1791 :          eDataType == GDT_Float64) &&
    8270             :         !poMaskBand)
    8271             :     {
    8272        1464 :         CPLErr eErr = ComputeRasterMinMaxLocation(
    8273         732 :             &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
    8274         732 :         if (eErr == CE_Warning)
    8275             :         {
    8276           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    8277             :                         "Failed to compute min/max, no valid pixels found in "
    8278             :                         "sampling.");
    8279           9 :             eErr = CE_Failure;
    8280             :         }
    8281         732 :         return eErr;
    8282             :     }
    8283             : 
    8284        1081 :     bool bSignedByte = false;
    8285        1081 :     if (eDataType == GDT_UInt8)
    8286             :     {
    8287         781 :         EnablePixelTypeSignedByteWarning(false);
    8288             :         const char *pszPixelType =
    8289         781 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8290         781 :         EnablePixelTypeSignedByteWarning(true);
    8291         781 :         bSignedByte =
    8292         781 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8293             :     }
    8294             : 
    8295             :     GDALRasterIOExtraArg sExtraArg;
    8296        1081 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    8297             : 
    8298        2162 :     GUInt32 nMin = (eDataType == GDT_UInt8)
    8299        1081 :                        ? 255
    8300             :                        : 65535;  // used for GByte & GUInt16 cases
    8301        1081 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    8302        1081 :     GInt16 nMinInt16 =
    8303             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    8304        1081 :     GInt16 nMaxInt16 =
    8305             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    8306        1081 :     double dfMin =
    8307             :         std::numeric_limits<double>::infinity();  // used for generic code path
    8308        1081 :     double dfMax =
    8309             :         -std::numeric_limits<double>::infinity();  // used for generic code path
    8310        1081 :     const bool bUseOptimizedPath =
    8311        1287 :         !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    8312         206 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    8313             : 
    8314             :     const auto ComputeMinMaxForBlock =
    8315       19520 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    8316             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    8317      113020 :                      int nYCheck)
    8318             :     {
    8319       19520 :         if (eDataType == GDT_UInt8 && !bSignedByte)
    8320             :         {
    8321             :             const bool bHasNoData =
    8322       11562 :                 sNoDataValues.bGotNoDataValue &&
    8323       29667 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    8324       11562 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    8325       11562 :                     sNoDataValues.dfNoDataValue;
    8326       18105 :             const GUInt32 nNoDataValue =
    8327       18105 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    8328             :                            : 0;
    8329             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8330             :             ComputeStatisticsInternal<GByte,
    8331             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8332       18105 :                 f(nXCheck, nBufferWidth, nYCheck,
    8333             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    8334       18105 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8335             :         }
    8336        1415 :         else if (eDataType == GDT_UInt16)
    8337             :         {
    8338             :             const bool bHasNoData =
    8339          84 :                 sNoDataValues.bGotNoDataValue &&
    8340        1497 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    8341          84 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    8342          84 :                     sNoDataValues.dfNoDataValue;
    8343        1413 :             const GUInt32 nNoDataValue =
    8344        1413 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    8345             :                            : 0;
    8346             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8347             :             ComputeStatisticsInternal<GUInt16,
    8348             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8349        1413 :                 f(nXCheck, nBufferWidth, nYCheck,
    8350             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    8351             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8352             :         }
    8353           2 :         else if (eDataType == GDT_Int16)
    8354             :         {
    8355             :             const bool bHasNoData =
    8356           0 :                 sNoDataValues.bGotNoDataValue &&
    8357           2 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    8358           0 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    8359           0 :                     sNoDataValues.dfNoDataValue;
    8360           2 :             if (bHasNoData)
    8361             :             {
    8362           0 :                 const int16_t nNoDataValue =
    8363           0 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    8364           0 :                 for (int iY = 0; iY < nYCheck; iY++)
    8365             :                 {
    8366           0 :                     ComputeMinMax<int16_t, true>(
    8367           0 :                         static_cast<const int16_t *>(pData) +
    8368           0 :                             static_cast<size_t>(iY) * nBufferWidth,
    8369             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    8370             :                 }
    8371             :             }
    8372             :             else
    8373             :             {
    8374           4 :                 for (int iY = 0; iY < nYCheck; iY++)
    8375             :                 {
    8376           2 :                     ComputeMinMax<int16_t, false>(
    8377           2 :                         static_cast<const int16_t *>(pData) +
    8378           2 :                             static_cast<size_t>(iY) * nBufferWidth,
    8379             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    8380             :                 }
    8381             :             }
    8382             :         }
    8383       19520 :     };
    8384             : 
    8385        1081 :     if (bApproxOK && HasArbitraryOverviews())
    8386             :     {
    8387             :         /* --------------------------------------------------------------------
    8388             :          */
    8389             :         /*      Figure out how much the image should be reduced to get an */
    8390             :         /*      approximate value. */
    8391             :         /* --------------------------------------------------------------------
    8392             :          */
    8393           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    8394           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    8395             : 
    8396           0 :         int nXReduced = nRasterXSize;
    8397           0 :         int nYReduced = nRasterYSize;
    8398           0 :         if (dfReduction > 1.0)
    8399             :         {
    8400           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    8401           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    8402             : 
    8403             :             // Catch the case of huge resizing ratios here
    8404           0 :             if (nXReduced == 0)
    8405           0 :                 nXReduced = 1;
    8406           0 :             if (nYReduced == 0)
    8407           0 :                 nYReduced = 1;
    8408             :         }
    8409             : 
    8410           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    8411           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    8412             : 
    8413             :         const CPLErr eErr =
    8414           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    8415           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    8416           0 :         if (eErr != CE_None)
    8417             :         {
    8418           0 :             CPLFree(pData);
    8419           0 :             return eErr;
    8420             :         }
    8421             : 
    8422           0 :         GByte *pabyMaskData = nullptr;
    8423           0 :         if (poMaskBand)
    8424             :         {
    8425             :             pabyMaskData =
    8426           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    8427           0 :             if (!pabyMaskData)
    8428             :             {
    8429           0 :                 CPLFree(pData);
    8430           0 :                 return CE_Failure;
    8431             :             }
    8432             : 
    8433           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    8434             :                                      pabyMaskData, nXReduced, nYReduced,
    8435           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    8436             :             {
    8437           0 :                 CPLFree(pData);
    8438           0 :                 CPLFree(pabyMaskData);
    8439           0 :                 return CE_Failure;
    8440             :             }
    8441             :         }
    8442             : 
    8443           0 :         if (bUseOptimizedPath)
    8444             :         {
    8445           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    8446             :         }
    8447             :         else
    8448             :         {
    8449           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    8450             :                                  nYReduced, nXReduced, sNoDataValues,
    8451             :                                  pabyMaskData, dfMin, dfMax);
    8452             :         }
    8453             : 
    8454           0 :         CPLFree(pData);
    8455           0 :         CPLFree(pabyMaskData);
    8456             :     }
    8457             : 
    8458             :     else  // No arbitrary overviews
    8459             :     {
    8460        1081 :         if (!InitBlockInfo())
    8461           0 :             return CE_Failure;
    8462             : 
    8463             :         /* --------------------------------------------------------------------
    8464             :          */
    8465             :         /*      Figure out the ratio of blocks we will read to get an */
    8466             :         /*      approximate value. */
    8467             :         /* --------------------------------------------------------------------
    8468             :          */
    8469        1081 :         int nSampleRate = 1;
    8470             : 
    8471        1081 :         if (bApproxOK)
    8472             :         {
    8473          22 :             nSampleRate = static_cast<int>(std::max(
    8474          44 :                 1.0,
    8475          22 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    8476             :             // We want to avoid probing only the first column of blocks for
    8477             :             // a square shaped raster, because it is not unlikely that it may
    8478             :             // be padding only (#6378).
    8479          22 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    8480           0 :                 nSampleRate += 1;
    8481             :         }
    8482             : 
    8483        1081 :         if (bUseOptimizedPath)
    8484             :         {
    8485         892 :             for (GIntBig iSampleBlock = 0;
    8486       20338 :                  iSampleBlock <
    8487       20338 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8488       19446 :                  iSampleBlock += nSampleRate)
    8489             :             {
    8490       19522 :                 const int iYBlock =
    8491       19522 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    8492       19522 :                 const int iXBlock =
    8493       19522 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    8494             : 
    8495       19522 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    8496       19522 :                 if (poBlock == nullptr)
    8497           2 :                     return CE_Failure;
    8498             : 
    8499       19520 :                 void *const pData = poBlock->GetDataRef();
    8500             : 
    8501       19520 :                 int nXCheck = 0, nYCheck = 0;
    8502       19520 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8503             : 
    8504       19520 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    8505             : 
    8506       19520 :                 poBlock->DropLock();
    8507             : 
    8508       19520 :                 if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
    8509        4110 :                     nMax == 255)
    8510          74 :                     break;
    8511             :             }
    8512             :         }
    8513             :         else
    8514             :         {
    8515         189 :             const GIntBig nTotalBlocks =
    8516         189 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8517         189 :             if (!ComputeMinMaxGenericIterBlocks(
    8518             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    8519             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    8520             :             {
    8521           0 :                 return CE_Failure;
    8522             :             }
    8523             :         }
    8524             :     }
    8525             : 
    8526        1079 :     if (bUseOptimizedPath)
    8527             :     {
    8528         890 :         if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
    8529             :         {
    8530         889 :             dfMin = nMin;
    8531         889 :             dfMax = nMax;
    8532             :         }
    8533           1 :         else if (eDataType == GDT_Int16)
    8534             :         {
    8535           1 :             dfMin = nMinInt16;
    8536           1 :             dfMax = nMaxInt16;
    8537             :         }
    8538             :     }
    8539             : 
    8540        1079 :     if (dfMin > dfMax)
    8541             :     {
    8542          23 :         adfMinMax[0] = 0;
    8543          23 :         adfMinMax[1] = 0;
    8544          23 :         ReportError(
    8545             :             CE_Failure, CPLE_AppDefined,
    8546             :             "Failed to compute min/max, no valid pixels found in sampling.");
    8547          23 :         return CE_Failure;
    8548             :     }
    8549             : 
    8550        1056 :     adfMinMax[0] = dfMin;
    8551        1056 :     adfMinMax[1] = dfMax;
    8552             : 
    8553        1056 :     return CE_None;
    8554             : }
    8555             : 
    8556             : /************************************************************************/
    8557             : /*                      GDALComputeRasterMinMax()                       */
    8558             : /************************************************************************/
    8559             : 
    8560             : /**
    8561             :  * \brief Compute the min/max values for a band.
    8562             :  *
    8563             :  * @see GDALRasterBand::ComputeRasterMinMax()
    8564             :  *
    8565             :  * @note Prior to GDAL 3.6, this function returned void
    8566             :  */
    8567             : 
    8568        1663 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    8569             :                                            double adfMinMax[2])
    8570             : 
    8571             : {
    8572        1663 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    8573             : 
    8574        1663 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8575        1663 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    8576             : }
    8577             : 
    8578             : /************************************************************************/
    8579             : /*                    ComputeRasterMinMaxLocation()                     */
    8580             : /************************************************************************/
    8581             : 
    8582             : /**
    8583             :  * \brief Compute the min/max values for a band, and their location.
    8584             :  *
    8585             :  * Pixels whose value matches the nodata value or are masked by the mask
    8586             :  * band are ignored.
    8587             :  *
    8588             :  * If the minimum or maximum value is hit in several locations, it is not
    8589             :  * specified which one will be returned.
    8590             :  *
    8591             :  * @param[out] pdfMin Pointer to the minimum value.
    8592             :  * @param[out] pdfMax Pointer to the maximum value.
    8593             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    8594             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    8595             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    8596             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    8597             :  *
    8598             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    8599             :  *         CE_Failure in case of error.
    8600             :  *
    8601             :  * @since GDAL 3.11
    8602             :  */
    8603             : 
    8604         748 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    8605             :                                                    double *pdfMax, int *pnMinX,
    8606             :                                                    int *pnMinY, int *pnMaxX,
    8607             :                                                    int *pnMaxY)
    8608             : {
    8609         748 :     int nMinX = -1;
    8610         748 :     int nMinY = -1;
    8611         748 :     int nMaxX = -1;
    8612         748 :     int nMaxY = -1;
    8613         748 :     double dfMin = std::numeric_limits<double>::infinity();
    8614         748 :     double dfMax = -std::numeric_limits<double>::infinity();
    8615         748 :     if (pdfMin)
    8616         745 :         *pdfMin = dfMin;
    8617         748 :     if (pdfMax)
    8618         745 :         *pdfMax = dfMax;
    8619         748 :     if (pnMinX)
    8620          14 :         *pnMinX = nMinX;
    8621         748 :     if (pnMinY)
    8622          14 :         *pnMinY = nMinY;
    8623         748 :     if (pnMaxX)
    8624          14 :         *pnMaxX = nMaxX;
    8625         748 :     if (pnMaxY)
    8626          14 :         *pnMaxY = nMaxY;
    8627             : 
    8628         748 :     if (GDALDataTypeIsComplex(eDataType))
    8629             :     {
    8630           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    8631             :                  "Complex data type not supported");
    8632           0 :         return CE_Failure;
    8633             :     }
    8634             : 
    8635         748 :     if (!InitBlockInfo())
    8636           0 :         return CE_Failure;
    8637             : 
    8638         748 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8639         748 :     GDALRasterBand *poMaskBand = nullptr;
    8640         748 :     if (!sNoDataValues.bGotNoDataValue)
    8641             :     {
    8642         575 :         const int l_nMaskFlags = GetMaskFlags();
    8643         576 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8644           1 :             GetColorInterpretation() != GCI_AlphaBand)
    8645             :         {
    8646           1 :             poMaskBand = GetMaskBand();
    8647             :         }
    8648             :     }
    8649             : 
    8650         748 :     bool bSignedByte = false;
    8651         748 :     if (eDataType == GDT_UInt8)
    8652             :     {
    8653           7 :         EnablePixelTypeSignedByteWarning(false);
    8654             :         const char *pszPixelType =
    8655           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8656           7 :         EnablePixelTypeSignedByteWarning(true);
    8657           7 :         bSignedByte =
    8658           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8659             :     }
    8660             : 
    8661         748 :     GByte *pabyMaskData = nullptr;
    8662         748 :     if (poMaskBand)
    8663             :     {
    8664             :         pabyMaskData =
    8665           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8666           1 :         if (!pabyMaskData)
    8667             :         {
    8668           0 :             return CE_Failure;
    8669             :         }
    8670             :     }
    8671             : 
    8672         748 :     const GIntBig nTotalBlocks =
    8673         748 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8674         748 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    8675         748 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    8676        7842 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    8677             :     {
    8678        7097 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    8679        7097 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    8680             : 
    8681        7097 :         int nXCheck = 0, nYCheck = 0;
    8682        7097 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8683             : 
    8684        7099 :         if (poMaskBand &&
    8685           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    8686           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    8687             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    8688           2 :                                  nBlockXSize, nullptr) != CE_None)
    8689             :         {
    8690           0 :             CPLFree(pabyMaskData);
    8691           0 :             return CE_Failure;
    8692             :         }
    8693             : 
    8694        7097 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    8695        7097 :         if (poBlock == nullptr)
    8696             :         {
    8697           0 :             CPLFree(pabyMaskData);
    8698           0 :             return CE_Failure;
    8699             :         }
    8700             : 
    8701        7097 :         void *const pData = poBlock->GetDataRef();
    8702             : 
    8703        7097 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    8704             :         {
    8705        5059 :             for (int iY = 0; iY < nYCheck; ++iY)
    8706             :             {
    8707      238290 :                 for (int iX = 0; iX < nXCheck; ++iX)
    8708             :                 {
    8709      233478 :                     const GPtrDiff_t iOffset =
    8710      233478 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    8711      233478 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8712           2 :                         continue;
    8713      233476 :                     bool bValid = true;
    8714             :                     double dfValue =
    8715      233476 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    8716             :                                       sNoDataValues, bValid);
    8717      233476 :                     if (!bValid)
    8718           0 :                         continue;
    8719      233476 :                     if (dfValue < dfMin)
    8720             :                     {
    8721         606 :                         dfMin = dfValue;
    8722         606 :                         nMinX = iXBlock * nBlockXSize + iX;
    8723         606 :                         nMinY = iYBlock * nBlockYSize + iY;
    8724             :                     }
    8725      233476 :                     if (dfValue > dfMax)
    8726             :                     {
    8727        1515 :                         dfMax = dfValue;
    8728        1515 :                         nMaxX = iXBlock * nBlockXSize + iX;
    8729        1515 :                         nMaxY = iYBlock * nBlockYSize + iY;
    8730             :                     }
    8731             :                 }
    8732         247 :             }
    8733             :         }
    8734             :         else
    8735             :         {
    8736        6850 :             size_t pos_min = 0;
    8737        6850 :             size_t pos_max = 0;
    8738        6850 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    8739        6850 :             if (bNeedsMin && bNeedsMax)
    8740             :             {
    8741       13692 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    8742        6846 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8743        6846 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8744       13692 :                     sNoDataValues.dfNoDataValue);
    8745             :             }
    8746           4 :             else if (bNeedsMin)
    8747             :             {
    8748           1 :                 pos_min = gdal::min_element(
    8749           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8750           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8751             :                     sNoDataValues.dfNoDataValue);
    8752             :             }
    8753           3 :             else if (bNeedsMax)
    8754             :             {
    8755           2 :                 pos_max = gdal::max_element(
    8756           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    8757           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    8758             :                     sNoDataValues.dfNoDataValue);
    8759             :             }
    8760             : 
    8761        6850 :             if (bNeedsMin)
    8762             :             {
    8763        6847 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    8764        6847 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    8765        6847 :                 bool bValid = true;
    8766             :                 const double dfMinValueBlock =
    8767        6847 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    8768             :                                   sNoDataValues, bValid);
    8769        6847 :                 if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
    8770             :                 {
    8771        1039 :                     dfMin = dfMinValueBlock;
    8772        1039 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    8773        1039 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    8774             :                 }
    8775             :             }
    8776             : 
    8777        6850 :             if (bNeedsMax)
    8778             :             {
    8779        6848 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    8780        6848 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    8781        6848 :                 bool bValid = true;
    8782             :                 const double dfMaxValueBlock =
    8783        6848 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    8784             :                                   sNoDataValues, bValid);
    8785        6848 :                 if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
    8786             :                 {
    8787         954 :                     dfMax = dfMaxValueBlock;
    8788         954 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    8789         954 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    8790             :                 }
    8791             :             }
    8792             :         }
    8793             : 
    8794        7097 :         poBlock->DropLock();
    8795             : 
    8796        7097 :         if (eDataType == GDT_UInt8)
    8797             :         {
    8798          10 :             if (bNeedsMin && dfMin == 0)
    8799             :             {
    8800           1 :                 bNeedsMin = false;
    8801             :             }
    8802          10 :             if (bNeedsMax && dfMax == 255)
    8803             :             {
    8804           4 :                 bNeedsMax = false;
    8805             :             }
    8806          10 :             if (!bNeedsMin && !bNeedsMax)
    8807             :             {
    8808           3 :                 break;
    8809             :             }
    8810             :         }
    8811             :     }
    8812             : 
    8813         748 :     CPLFree(pabyMaskData);
    8814             : 
    8815         748 :     if (pdfMin)
    8816         745 :         *pdfMin = dfMin;
    8817         748 :     if (pdfMax)
    8818         745 :         *pdfMax = dfMax;
    8819         748 :     if (pnMinX)
    8820          14 :         *pnMinX = nMinX;
    8821         748 :     if (pnMinY)
    8822          14 :         *pnMinY = nMinY;
    8823         748 :     if (pnMaxX)
    8824          14 :         *pnMaxX = nMaxX;
    8825         748 :     if (pnMaxY)
    8826          14 :         *pnMaxY = nMaxY;
    8827         748 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    8828         748 :                                                                   : CE_None;
    8829             : }
    8830             : 
    8831             : /************************************************************************/
    8832             : /*                    GDALComputeRasterMinMaxLocation()                 */
    8833             : /************************************************************************/
    8834             : 
    8835             : /**
    8836             :  * \brief Compute the min/max values for a band, and their location.
    8837             :  *
    8838             :  * @see GDALRasterBand::ComputeRasterMinMax()
    8839             :  * @since GDAL 3.11
    8840             :  */
    8841             : 
    8842          14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    8843             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    8844             :                                        int *pnMaxX, int *pnMaxY)
    8845             : 
    8846             : {
    8847          14 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    8848             : 
    8849          14 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8850          14 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    8851          14 :                                                pnMaxX, pnMaxY);
    8852             : }
    8853             : 
    8854             : /************************************************************************/
    8855             : /*                        SetDefaultHistogram()                         */
    8856             : /************************************************************************/
    8857             : 
    8858             : /* FIXME : add proper documentation */
    8859             : /**
    8860             :  * \brief Set default histogram.
    8861             :  *
    8862             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    8863             :  * GDALSetDefaultHistogramEx()
    8864             :  */
    8865           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    8866             :                                            double /* dfMax */,
    8867             :                                            int /* nBuckets */,
    8868             :                                            GUIntBig * /* panHistogram */)
    8869             : 
    8870             : {
    8871           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    8872           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    8873             :                     "SetDefaultHistogram() not implemented for this format.");
    8874             : 
    8875           0 :     return CE_Failure;
    8876             : }
    8877             : 
    8878             : /************************************************************************/
    8879             : /*                      GDALSetDefaultHistogram()                       */
    8880             : /************************************************************************/
    8881             : 
    8882             : /**
    8883             :  * \brief Set default histogram.
    8884             :  *
    8885             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    8886             :  * 2 billion.
    8887             :  *
    8888             :  * @see GDALRasterBand::SetDefaultHistogram()
    8889             :  * @see GDALSetRasterHistogramEx()
    8890             :  */
    8891             : 
    8892           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    8893             :                                            double dfMax, int nBuckets,
    8894             :                                            int *panHistogram)
    8895             : 
    8896             : {
    8897           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    8898             : 
    8899           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8900             : 
    8901             :     GUIntBig *panHistogramTemp =
    8902           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    8903           0 :     if (panHistogramTemp == nullptr)
    8904             :     {
    8905           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    8906             :                             "Out of memory in GDALSetDefaultHistogram().");
    8907           0 :         return CE_Failure;
    8908             :     }
    8909             : 
    8910           0 :     for (int i = 0; i < nBuckets; ++i)
    8911             :     {
    8912           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    8913             :     }
    8914             : 
    8915             :     const CPLErr eErr =
    8916           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    8917             : 
    8918           0 :     CPLFree(panHistogramTemp);
    8919             : 
    8920           0 :     return eErr;
    8921             : }
    8922             : 
    8923             : /************************************************************************/
    8924             : /*                     GDALSetDefaultHistogramEx()                      */
    8925             : /************************************************************************/
    8926             : 
    8927             : /**
    8928             :  * \brief Set default histogram.
    8929             :  *
    8930             :  * @see GDALRasterBand::SetDefaultHistogram()
    8931             :  *
    8932             :  */
    8933             : 
    8934           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    8935             :                                              double dfMin, double dfMax,
    8936             :                                              int nBuckets,
    8937             :                                              GUIntBig *panHistogram)
    8938             : 
    8939             : {
    8940           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    8941             : 
    8942           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8943           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    8944             : }
    8945             : 
    8946             : /************************************************************************/
    8947             : /*                           GetDefaultRAT()                            */
    8948             : /************************************************************************/
    8949             : 
    8950             : /**
    8951             :  * \brief Fetch default Raster Attribute Table.
    8952             :  *
    8953             :  * A RAT will be returned if there is a default one associated with the
    8954             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    8955             :  * band and should not be deleted by the application.
    8956             :  *
    8957             :  * This method is the same as the C function GDALGetDefaultRAT().
    8958             :  *
    8959             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    8960             :  */
    8961             : 
    8962         180 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    8963             : 
    8964             : {
    8965         180 :     return nullptr;
    8966             : }
    8967             : 
    8968             : /************************************************************************/
    8969             : /*                         GDALGetDefaultRAT()                          */
    8970             : /************************************************************************/
    8971             : 
    8972             : /**
    8973             :  * \brief Fetch default Raster Attribute Table.
    8974             :  *
    8975             :  * @see GDALRasterBand::GetDefaultRAT()
    8976             :  */
    8977             : 
    8978        1158 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    8979             : 
    8980             : {
    8981        1158 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    8982             : 
    8983        1158 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8984        1158 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    8985             : }
    8986             : 
    8987             : /************************************************************************/
    8988             : /*                           SetDefaultRAT()                            */
    8989             : /************************************************************************/
    8990             : 
    8991             : /**
    8992             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    8993             :  * \brief Set default Raster Attribute Table.
    8994             :  *
    8995             :  * Associates a default RAT with the band.  If not implemented for the
    8996             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    8997             :  * of the RAT is made, the original remains owned by the caller.
    8998             :  *
    8999             :  * This method is the same as the C function GDALSetDefaultRAT().
    9000             :  *
    9001             :  * @param poRAT the RAT to assign to the band.
    9002             :  *
    9003             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    9004             :  * failing.
    9005             :  */
    9006             : 
    9007             : /**/
    9008             : /**/
    9009             : 
    9010             : CPLErr
    9011           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    9012             : {
    9013           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    9014             :     {
    9015           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    9016           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    9017             :                     "SetDefaultRAT() not implemented for this format.");
    9018           0 :         CPLPopErrorHandler();
    9019             :     }
    9020           0 :     return CE_Failure;
    9021             : }
    9022             : 
    9023             : /************************************************************************/
    9024             : /*                         GDALSetDefaultRAT()                          */
    9025             : /************************************************************************/
    9026             : 
    9027             : /**
    9028             :  * \brief Set default Raster Attribute Table.
    9029             :  *
    9030             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    9031             :  */
    9032             : 
    9033          25 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    9034             :                                      GDALRasterAttributeTableH hRAT)
    9035             : 
    9036             : {
    9037          25 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    9038             : 
    9039          25 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9040             : 
    9041          25 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    9042             : }
    9043             : 
    9044             : /************************************************************************/
    9045             : /*                            GetMaskBand()                             */
    9046             : /************************************************************************/
    9047             : 
    9048             : /**
    9049             :  * \brief Return the mask band associated with the band.
    9050             :  *
    9051             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9052             :  * that returns one of four default implementations :
    9053             :  * <ul>
    9054             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9055             :  * </li>
    9056             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9057             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9058             :  * GMF_NODATA | GMF_PER_DATASET.
    9059             :  * </li>
    9060             :  * <li>If the band has a nodata value set, an instance of the new
    9061             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9062             :  * GMF_NODATA.
    9063             :  * </li>
    9064             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    9065             :  * to apply to this band (specific rules yet to be determined) and that is of
    9066             :  * type GDT_UInt8 then that alpha band will be returned, and the flags
    9067             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9068             :  * </li>
    9069             :  * <li>If neither of the above apply, an instance of the new
    9070             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9071             :  * pixels. The null flags will return GMF_ALL_VALID.
    9072             :  * </li>
    9073             :  * </ul>
    9074             :  *
    9075             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    9076             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    9077             :  *
    9078             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9079             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9080             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9081             :  * main dataset.
    9082             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9083             :  * level, where xx matches the band number of a band of the main dataset. The
    9084             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9085             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9086             :  * a band, then the other rules explained above will be used to generate a
    9087             :  * on-the-fly mask band.
    9088             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9089             :  *
    9090             :  * This method is the same as the C function GDALGetMaskBand().
    9091             :  *
    9092             :  * @return a valid mask band.
    9093             :  *
    9094             :  *
    9095             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9096             :  *
    9097             :  */
    9098      698790 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    9099             : 
    9100             : {
    9101      397087 :     const auto HasNoData = [this]()
    9102             :     {
    9103      132040 :         int bHaveNoDataRaw = FALSE;
    9104      132040 :         bool bHaveNoData = false;
    9105      132040 :         if (eDataType == GDT_Int64)
    9106             :         {
    9107         204 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
    9108         204 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9109             :         }
    9110      131836 :         else if (eDataType == GDT_UInt64)
    9111             :         {
    9112         152 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    9113         152 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9114             :         }
    9115             :         else
    9116             :         {
    9117      131684 :             const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
    9118      131694 :             if (bHaveNoDataRaw &&
    9119      131694 :                 GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    9120             :             {
    9121        1126 :                 bHaveNoData = true;
    9122             :             }
    9123             :         }
    9124      132051 :         return bHaveNoData;
    9125      698790 :     };
    9126             : 
    9127      698790 :     if (poMask != nullptr)
    9128             :     {
    9129      577690 :         if (poMask.IsOwned())
    9130             :         {
    9131      294146 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    9132             :             {
    9133       33613 :                 if (HasNoData())
    9134             :                 {
    9135           9 :                     InvalidateMaskBand();
    9136             :                 }
    9137             :             }
    9138      267780 :             else if (auto poNoDataMaskBand =
    9139      270884 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    9140             :             {
    9141         396 :                 int bHaveNoDataRaw = FALSE;
    9142         396 :                 bool bIsSame = false;
    9143         396 :                 if (eDataType == GDT_Int64)
    9144          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    9145          27 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    9146          10 :                               bHaveNoDataRaw;
    9147         379 :                 else if (eDataType == GDT_UInt64)
    9148          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    9149          27 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    9150          10 :                               bHaveNoDataRaw;
    9151             :                 else
    9152             :                 {
    9153             :                     const double dfNoDataValue =
    9154         362 :                         GetNoDataValue(&bHaveNoDataRaw);
    9155         362 :                     if (bHaveNoDataRaw)
    9156             :                     {
    9157         359 :                         bIsSame =
    9158         359 :                             std::isnan(dfNoDataValue)
    9159         359 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    9160         324 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    9161             :                                       dfNoDataValue;
    9162             :                     }
    9163             :                 }
    9164         396 :                 if (!bIsSame)
    9165          23 :                     InvalidateMaskBand();
    9166             :             }
    9167             :         }
    9168             : 
    9169      636910 :         if (poMask)
    9170      657409 :             return poMask.get();
    9171             :     }
    9172             : 
    9173             :     /* -------------------------------------------------------------------- */
    9174             :     /*      Check for a mask in a .msk file.                                */
    9175             :     /* -------------------------------------------------------------------- */
    9176       98537 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    9177             :     {
    9178          47 :         poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
    9179          47 :         if (poMask != nullptr)
    9180             :         {
    9181          45 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    9182          45 :             return poMask.get();
    9183             :         }
    9184             :     }
    9185             : 
    9186             :     /* -------------------------------------------------------------------- */
    9187             :     /*      Check for NODATA_VALUES metadata.                               */
    9188             :     /* -------------------------------------------------------------------- */
    9189       98489 :     if (poDS != nullptr)
    9190             :     {
    9191             :         const char *pszGDALNoDataValues =
    9192       98473 :             poDS->GetMetadataItem("NODATA_VALUES");
    9193       98475 :         if (pszGDALNoDataValues != nullptr)
    9194             :         {
    9195          68 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    9196             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    9197             : 
    9198             :             // Make sure we have as many values as bands.
    9199         136 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    9200          68 :                 poDS->GetRasterCount() != 0)
    9201             :             {
    9202             :                 // Make sure that all bands have the same data type
    9203             :                 // This is clearly not a fundamental condition, just a
    9204             :                 // condition to make implementation easier.
    9205          68 :                 GDALDataType eDT = GDT_Unknown;
    9206          68 :                 int i = 0;  // Used after for.
    9207         270 :                 for (; i < poDS->GetRasterCount(); ++i)
    9208             :                 {
    9209         202 :                     if (i == 0)
    9210          68 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    9211         134 :                     else if (eDT !=
    9212         134 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    9213             :                     {
    9214           0 :                         break;
    9215             :                     }
    9216             :                 }
    9217          68 :                 if (i == poDS->GetRasterCount())
    9218             :                 {
    9219          68 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    9220             :                     try
    9221             :                     {
    9222          68 :                         poMask.reset(
    9223         136 :                             std::make_unique<GDALNoDataValuesMaskBand>(poDS));
    9224             :                     }
    9225           0 :                     catch (const std::bad_alloc &)
    9226             :                     {
    9227           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9228           0 :                         poMask.reset();
    9229             :                     }
    9230          68 :                     CSLDestroy(papszGDALNoDataValues);
    9231          68 :                     return poMask.get();
    9232             :                 }
    9233             :                 else
    9234             :                 {
    9235           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    9236             :                                 "All bands should have the same type in "
    9237             :                                 "order the NODATA_VALUES metadata item "
    9238             :                                 "to be used as a mask.");
    9239             :                 }
    9240             :             }
    9241             :             else
    9242             :             {
    9243           0 :                 ReportError(
    9244             :                     CE_Warning, CPLE_AppDefined,
    9245             :                     "NODATA_VALUES metadata item doesn't have the same number "
    9246             :                     "of values as the number of bands.  "
    9247             :                     "Ignoring it for mask.");
    9248             :             }
    9249             : 
    9250           0 :             CSLDestroy(papszGDALNoDataValues);
    9251             :         }
    9252             :     }
    9253             : 
    9254             :     /* -------------------------------------------------------------------- */
    9255             :     /*      Check for nodata case.                                          */
    9256             :     /* -------------------------------------------------------------------- */
    9257       98423 :     if (HasNoData())
    9258             :     {
    9259        1152 :         nMaskFlags = GMF_NODATA;
    9260             :         try
    9261             :         {
    9262        1152 :             poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
    9263             :         }
    9264           0 :         catch (const std::bad_alloc &)
    9265             :         {
    9266           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9267           0 :             poMask.reset();
    9268             :         }
    9269        1152 :         return poMask.get();
    9270             :     }
    9271             : 
    9272             :     /* -------------------------------------------------------------------- */
    9273             :     /*      Check for alpha case.                                           */
    9274             :     /* -------------------------------------------------------------------- */
    9275       97255 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    9276      195124 :         this == poDS->GetRasterBand(1) &&
    9277         599 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    9278             :     {
    9279         231 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
    9280             :         {
    9281         187 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9282         187 :             poMask.resetNotOwned(poDS->GetRasterBand(2));
    9283         187 :             return poMask.get();
    9284             :         }
    9285          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    9286             :         {
    9287          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9288             :             try
    9289             :             {
    9290          23 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9291          46 :                     poDS->GetRasterBand(2)));
    9292             :             }
    9293           0 :             catch (const std::bad_alloc &)
    9294             :             {
    9295           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9296           0 :                 poMask.reset();
    9297             :             }
    9298          23 :             return poMask.get();
    9299             :         }
    9300             :     }
    9301             : 
    9302       97045 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    9303        3132 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    9304      194840 :          this == poDS->GetRasterBand(3)) &&
    9305        2450 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    9306             :     {
    9307        1571 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
    9308             :         {
    9309        1515 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9310        1515 :             poMask.resetNotOwned(poDS->GetRasterBand(4));
    9311        1514 :             return poMask.get();
    9312             :         }
    9313          57 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    9314             :         {
    9315          42 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9316             :             try
    9317             :             {
    9318          42 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9319          84 :                     poDS->GetRasterBand(4)));
    9320             :             }
    9321           0 :             catch (const std::bad_alloc &)
    9322             :             {
    9323           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9324           0 :                 poMask.reset();
    9325             :             }
    9326          42 :             return poMask.get();
    9327             :         }
    9328             :     }
    9329             : 
    9330             :     /* -------------------------------------------------------------------- */
    9331             :     /*      Fallback to all valid case.                                     */
    9332             :     /* -------------------------------------------------------------------- */
    9333       95501 :     nMaskFlags = GMF_ALL_VALID;
    9334             :     try
    9335             :     {
    9336       95501 :         poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
    9337             :     }
    9338           0 :     catch (const std::bad_alloc &)
    9339             :     {
    9340           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9341           0 :         poMask.reset();
    9342             :     }
    9343             : 
    9344       95501 :     return poMask.get();
    9345             : }
    9346             : 
    9347             : /************************************************************************/
    9348             : /*                          GDALGetMaskBand()                           */
    9349             : /************************************************************************/
    9350             : 
    9351             : /**
    9352             :  * \brief Return the mask band associated with the band.
    9353             :  *
    9354             :  * @see GDALRasterBand::GetMaskBand()
    9355             :  */
    9356             : 
    9357       11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    9358             : 
    9359             : {
    9360       11042 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    9361             : 
    9362       11042 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9363       11042 :     return poBand->GetMaskBand();
    9364             : }
    9365             : 
    9366             : /************************************************************************/
    9367             : /*                            GetMaskFlags()                            */
    9368             : /************************************************************************/
    9369             : 
    9370             : /**
    9371             :  * \brief Return the status flags of the mask band associated with the band.
    9372             :  *
    9373             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    9374             :  * the following available definitions that may be extended in the future:
    9375             :  * <ul>
    9376             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    9377             :  * 255. When used this will normally be the only flag set.
    9378             :  * </li>
    9379             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    9380             :  * dataset.
    9381             :  * </li>
    9382             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    9383             :  * and may have values other than 0 and 255.
    9384             :  * </li>
    9385             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    9386             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    9387             :  * </li>
    9388             :  * </ul>
    9389             :  *
    9390             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9391             :  * that returns one of four default implementations:
    9392             :  * <ul>
    9393             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9394             :  * </li>
    9395             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9396             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9397             :  * GMF_NODATA | GMF_PER_DATASET.
    9398             :  * </li>
    9399             :  * <li>If the band has a nodata value set, an instance of the new
    9400             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9401             :  * GMF_NODATA.
    9402             :  * </li>
    9403             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    9404             :  * seems to apply to this band (specific rules yet to be determined) and that is
    9405             :  * of type GDT_UInt8 then that alpha band will be returned, and the flags
    9406             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9407             :  * </li>
    9408             :  * <li>If neither of the above apply, an instance of the new
    9409             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9410             :  * pixels. The null flags will return GMF_ALL_VALID.
    9411             :  * </li>
    9412             :  * </ul>
    9413             :  *
    9414             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9415             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9416             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9417             :  * main dataset.
    9418             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9419             :  * level, where xx matches the band number of a band of the main dataset. The
    9420             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9421             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9422             :  * a band, then the other rules explained above will be used to generate a
    9423             :  * on-the-fly mask band.
    9424             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9425             :  *
    9426             :  * This method is the same as the C function GDALGetMaskFlags().
    9427             :  *
    9428             :  *
    9429             :  * @return a valid mask band.
    9430             :  *
    9431             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9432             :  *
    9433             :  */
    9434      157755 : int GDALRasterBand::GetMaskFlags()
    9435             : 
    9436             : {
    9437             :     // If we don't have a band yet, force this now so that the masks value
    9438             :     // will be initialized.
    9439             : 
    9440      157755 :     if (poMask == nullptr)
    9441       96813 :         GetMaskBand();
    9442             : 
    9443      157749 :     return nMaskFlags;
    9444             : }
    9445             : 
    9446             : /************************************************************************/
    9447             : /*                          GDALGetMaskFlags()                          */
    9448             : /************************************************************************/
    9449             : 
    9450             : /**
    9451             :  * \brief Return the status flags of the mask band associated with the band.
    9452             :  *
    9453             :  * @see GDALRasterBand::GetMaskFlags()
    9454             :  */
    9455             : 
    9456        8838 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    9457             : 
    9458             : {
    9459        8838 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    9460             : 
    9461        8838 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9462        8838 :     return poBand->GetMaskFlags();
    9463             : }
    9464             : 
    9465             : /************************************************************************/
    9466             : /*                         InvalidateMaskBand()                         */
    9467             : /************************************************************************/
    9468             : 
    9469             : //! @cond Doxygen_Suppress
    9470     1850220 : void GDALRasterBand::InvalidateMaskBand()
    9471             : {
    9472     1850220 :     poMask.reset();
    9473     1850210 :     nMaskFlags = 0;
    9474     1850210 : }
    9475             : 
    9476             : //! @endcond
    9477             : 
    9478             : /************************************************************************/
    9479             : /*                           CreateMaskBand()                           */
    9480             : /************************************************************************/
    9481             : 
    9482             : /**
    9483             :  * \brief Adds a mask band to the current band
    9484             :  *
    9485             :  * The default implementation of the CreateMaskBand() method is implemented
    9486             :  * based on similar rules to the .ovr handling implemented using the
    9487             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    9488             :  * be created with the same basename as the original file, and it will have
    9489             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    9490             :  * The mask images will be deflate compressed tiled images with the same
    9491             :  * block size as the original image if possible.
    9492             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9493             :  * level, where xx matches the band number of a band of the main dataset. The
    9494             :  * value of those items will be the one of the nFlagsIn parameter.
    9495             :  *
    9496             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    9497             :  * it might be invalidated by CreateMaskBand(). So you have to call
    9498             :  * GetMaskBand() again.
    9499             :  *
    9500             :  * This method is the same as the C function GDALCreateMaskBand().
    9501             :  *
    9502             :  *
    9503             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    9504             :  *
    9505             :  * @return CE_None on success or CE_Failure on an error.
    9506             :  *
    9507             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9508             :  * @see GDALDataset::CreateMaskBand()
    9509             :  *
    9510             :  */
    9511             : 
    9512          10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    9513             : 
    9514             : {
    9515          10 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    9516             :     {
    9517          10 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    9518          10 :         if (eErr != CE_None)
    9519           1 :             return eErr;
    9520             : 
    9521           9 :         InvalidateMaskBand();
    9522             : 
    9523           9 :         return CE_None;
    9524             :     }
    9525             : 
    9526           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    9527             :                 "CreateMaskBand() not supported for this band.");
    9528             : 
    9529           0 :     return CE_Failure;
    9530             : }
    9531             : 
    9532             : /************************************************************************/
    9533             : /*                         GDALCreateMaskBand()                         */
    9534             : /************************************************************************/
    9535             : 
    9536             : /**
    9537             :  * \brief Adds a mask band to the current band
    9538             :  *
    9539             :  * @see GDALRasterBand::CreateMaskBand()
    9540             :  */
    9541             : 
    9542          34 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    9543             : 
    9544             : {
    9545          34 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    9546             : 
    9547          34 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9548          34 :     return poBand->CreateMaskBand(nFlags);
    9549             : }
    9550             : 
    9551             : /************************************************************************/
    9552             : /*                            IsMaskBand()                              */
    9553             : /************************************************************************/
    9554             : 
    9555             : /**
    9556             :  * \brief Returns whether a band is a mask band.
    9557             :  *
    9558             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9559             :  * mask band, an alpha band, or an implicit mask band.
    9560             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9561             :  *
    9562             :  * This method is the same as the C function GDALIsMaskBand().
    9563             :  *
    9564             :  * @return true if the band is a mask band.
    9565             :  *
    9566             :  * @see GDALDataset::CreateMaskBand()
    9567             :  *
    9568             :  * @since GDAL 3.5.0
    9569             :  *
    9570             :  */
    9571             : 
    9572         444 : bool GDALRasterBand::IsMaskBand() const
    9573             : {
    9574             :     // The GeoTIFF driver, among others, override this method to
    9575             :     // also handle external .msk bands.
    9576         444 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    9577         444 :            GCI_AlphaBand;
    9578             : }
    9579             : 
    9580             : /************************************************************************/
    9581             : /*                            GDALIsMaskBand()                          */
    9582             : /************************************************************************/
    9583             : 
    9584             : /**
    9585             :  * \brief Returns whether a band is a mask band.
    9586             :  *
    9587             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9588             :  * mask band, an alpha band, or an implicit mask band.
    9589             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9590             :  *
    9591             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    9592             :  *
    9593             :  * @return true if the band is a mask band.
    9594             :  *
    9595             :  * @see GDALRasterBand::IsMaskBand()
    9596             :  *
    9597             :  * @since GDAL 3.5.0
    9598             :  *
    9599             :  */
    9600             : 
    9601          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    9602             : 
    9603             : {
    9604          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    9605             : 
    9606          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9607          37 :     return poBand->IsMaskBand();
    9608             : }
    9609             : 
    9610             : /************************************************************************/
    9611             : /*                         GetMaskValueRange()                          */
    9612             : /************************************************************************/
    9613             : 
    9614             : /**
    9615             :  * \brief Returns the range of values that a mask band can take.
    9616             :  *
    9617             :  * @return the range of values that a mask band can take.
    9618             :  *
    9619             :  * @since GDAL 3.5.0
    9620             :  *
    9621             :  */
    9622             : 
    9623           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    9624             : {
    9625           0 :     return GMVR_UNKNOWN;
    9626             : }
    9627             : 
    9628             : /************************************************************************/
    9629             : /*                    GetIndexColorTranslationTo()                      */
    9630             : /************************************************************************/
    9631             : 
    9632             : /**
    9633             :  * \brief Compute translation table for color tables.
    9634             :  *
    9635             :  * When the raster band has a palette index, it may be useful to compute
    9636             :  * the "translation" of this palette to the palette of another band.
    9637             :  * The translation tries to do exact matching first, and then approximate
    9638             :  * matching if no exact matching is possible.
    9639             :  * This method returns a table such that table[i] = j where i is an index
    9640             :  * of the 'this' rasterband and j the corresponding index for the reference
    9641             :  * rasterband.
    9642             :  *
    9643             :  * This method is thought as internal to GDAL and is used for drivers
    9644             :  * like RPFTOC.
    9645             :  *
    9646             :  * The implementation only supports 1-byte palette rasterbands.
    9647             :  *
    9648             :  * @param poReferenceBand the raster band
    9649             :  * @param pTranslationTable an already allocated translation table (at least 256
    9650             :  * bytes), or NULL to let the method allocate it
    9651             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    9652             :  *                              is approximate. May be NULL.
    9653             :  *
    9654             :  * @return a translation table if the two bands are palette index and that they
    9655             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    9656             :  * NULL was passed for pTranslationTable.
    9657             :  */
    9658             : 
    9659             : unsigned char *
    9660           4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    9661             :                                            unsigned char *pTranslationTable,
    9662             :                                            int *pApproximateMatching)
    9663             : {
    9664           4 :     if (poReferenceBand == nullptr)
    9665           0 :         return nullptr;
    9666             : 
    9667             :     // cppcheck-suppress knownConditionTrueFalse
    9668           4 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    9669             :         // cppcheck-suppress knownConditionTrueFalse
    9670           4 :         GetColorInterpretation() == GCI_PaletteIndex &&
    9671          12 :         poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
    9672           4 :         GetRasterDataType() == GDT_UInt8)
    9673             :     {
    9674           4 :         const GDALColorTable *srcColorTable = GetColorTable();
    9675           4 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    9676           4 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    9677             :         {
    9678           4 :             const int nEntries = srcColorTable->GetColorEntryCount();
    9679           4 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    9680             : 
    9681           4 :             int bHasNoDataValueSrc = FALSE;
    9682           4 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    9683           4 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    9684           4 :                   dfNoDataValueSrc <= 255 &&
    9685           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    9686           0 :                 bHasNoDataValueSrc = FALSE;
    9687           4 :             const int noDataValueSrc =
    9688           4 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
    9689             : 
    9690           4 :             int bHasNoDataValueRef = FALSE;
    9691             :             const double dfNoDataValueRef =
    9692           4 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
    9693           4 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
    9694           3 :                   dfNoDataValueRef <= 255 &&
    9695           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
    9696           1 :                 bHasNoDataValueRef = FALSE;
    9697           4 :             const int noDataValueRef =
    9698           4 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
    9699             : 
    9700           4 :             bool samePalette = false;
    9701             : 
    9702           4 :             if (pApproximateMatching)
    9703           3 :                 *pApproximateMatching = FALSE;
    9704             : 
    9705           4 :             if (nEntries == nRefEntries &&
    9706           3 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
    9707           3 :                 (bHasNoDataValueSrc == FALSE ||
    9708             :                  noDataValueSrc == noDataValueRef))
    9709             :             {
    9710           3 :                 samePalette = true;
    9711         654 :                 for (int i = 0; i < nEntries; ++i)
    9712             :                 {
    9713         651 :                     if (noDataValueSrc == i)
    9714           3 :                         continue;
    9715             :                     const GDALColorEntry *entry =
    9716         648 :                         srcColorTable->GetColorEntry(i);
    9717             :                     const GDALColorEntry *entryRef =
    9718         648 :                         destColorTable->GetColorEntry(i);
    9719         648 :                     if (entry->c1 != entryRef->c1 ||
    9720         648 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
    9721             :                     {
    9722           0 :                         samePalette = false;
    9723             :                     }
    9724             :                 }
    9725             :             }
    9726             : 
    9727           4 :             if (!samePalette)
    9728             :             {
    9729           1 :                 if (pTranslationTable == nullptr)
    9730             :                 {
    9731             :                     pTranslationTable = static_cast<unsigned char *>(
    9732           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
    9733           1 :                     if (pTranslationTable == nullptr)
    9734           1 :                         return nullptr;
    9735             :                 }
    9736             : 
    9737             :                 // Trying to remap the product palette on the subdataset
    9738             :                 // palette.
    9739           5 :                 for (int i = 0; i < nEntries; ++i)
    9740             :                 {
    9741           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
    9742             :                         noDataValueSrc == i)
    9743           0 :                         continue;
    9744             :                     const GDALColorEntry *entry =
    9745           4 :                         srcColorTable->GetColorEntry(i);
    9746           4 :                     bool bMatchFound = false;
    9747          13 :                     for (int j = 0; j < nRefEntries; ++j)
    9748             :                     {
    9749          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
    9750           0 :                             continue;
    9751             :                         const GDALColorEntry *entryRef =
    9752          10 :                             destColorTable->GetColorEntry(j);
    9753          10 :                         if (entry->c1 == entryRef->c1 &&
    9754           2 :                             entry->c2 == entryRef->c2 &&
    9755           2 :                             entry->c3 == entryRef->c3)
    9756             :                         {
    9757           1 :                             pTranslationTable[i] =
    9758             :                                 static_cast<unsigned char>(j);
    9759           1 :                             bMatchFound = true;
    9760           1 :                             break;
    9761             :                         }
    9762             :                     }
    9763           4 :                     if (!bMatchFound)
    9764             :                     {
    9765             :                         // No exact match. Looking for closest color now.
    9766           3 :                         int best_j = 0;
    9767           3 :                         int best_distance = 0;
    9768           3 :                         if (pApproximateMatching)
    9769           0 :                             *pApproximateMatching = TRUE;
    9770          12 :                         for (int j = 0; j < nRefEntries; ++j)
    9771             :                         {
    9772             :                             const GDALColorEntry *entryRef =
    9773           9 :                                 destColorTable->GetColorEntry(j);
    9774           9 :                             int distance = (entry->c1 - entryRef->c1) *
    9775           9 :                                                (entry->c1 - entryRef->c1) +
    9776           9 :                                            (entry->c2 - entryRef->c2) *
    9777           9 :                                                (entry->c2 - entryRef->c2) +
    9778           9 :                                            (entry->c3 - entryRef->c3) *
    9779           9 :                                                (entry->c3 - entryRef->c3);
    9780           9 :                             if (j == 0 || distance < best_distance)
    9781             :                             {
    9782           7 :                                 best_j = j;
    9783           7 :                                 best_distance = distance;
    9784             :                             }
    9785             :                         }
    9786           3 :                         pTranslationTable[i] =
    9787             :                             static_cast<unsigned char>(best_j);
    9788             :                     }
    9789             :                 }
    9790           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
    9791           0 :                     pTranslationTable[noDataValueSrc] =
    9792             :                         static_cast<unsigned char>(noDataValueRef);
    9793             : 
    9794           1 :                 return pTranslationTable;
    9795             :             }
    9796             :         }
    9797             :     }
    9798           3 :     return nullptr;
    9799             : }
    9800             : 
    9801             : /************************************************************************/
    9802             : /*                         SetFlushBlockErr()                           */
    9803             : /************************************************************************/
    9804             : 
    9805             : /**
    9806             :  * \brief Store that an error occurred while writing a dirty block.
    9807             :  *
    9808             :  * This function stores the fact that an error occurred while writing a dirty
    9809             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
    9810             :  * flushed when the block cache get full, it is not convenient/possible to
    9811             :  * report that a dirty block could not be written correctly. This function
    9812             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
    9813             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
    9814             :  * places where the user can easily match the error with the relevant dataset.
    9815             :  */
    9816             : 
    9817           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
    9818             : {
    9819           0 :     eFlushBlockErr = eErr;
    9820           0 : }
    9821             : 
    9822             : /************************************************************************/
    9823             : /*                         IncDirtyBlocks()                             */
    9824             : /************************************************************************/
    9825             : 
    9826             : /**
    9827             :  * \brief Increment/decrement the number of dirty blocks
    9828             :  */
    9829             : 
    9830      796703 : void GDALRasterBand::IncDirtyBlocks(int nInc)
    9831             : {
    9832      796703 :     if (poBandBlockCache)
    9833      796703 :         poBandBlockCache->IncDirtyBlocks(nInc);
    9834      796703 : }
    9835             : 
    9836             : /************************************************************************/
    9837             : /*                            ReportError()                             */
    9838             : /************************************************************************/
    9839             : 
    9840             : #ifndef DOXYGEN_XML
    9841             : /**
    9842             :  * \brief Emits an error related to a raster band.
    9843             :  *
    9844             :  * This function is a wrapper for regular CPLError(). The only difference
    9845             :  * with CPLError() is that it prepends the error message with the dataset
    9846             :  * name and the band number.
    9847             :  *
    9848             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    9849             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    9850             :  * @param fmt a printf() style format string.  Any additional arguments
    9851             :  * will be treated as arguments to fill in this format in a manner
    9852             :  * similar to printf().
    9853             :  *
    9854             :  */
    9855             : 
    9856        2498 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    9857             :                                  const char *fmt, ...) const
    9858             : {
    9859             :     va_list args;
    9860             : 
    9861        2498 :     va_start(args, fmt);
    9862             : 
    9863        2498 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
    9864        2498 :     pszDSName = CPLGetFilename(pszDSName);
    9865        2498 :     if (pszDSName[0] != '\0')
    9866             :     {
    9867        2404 :         CPLError(eErrClass, err_no, "%s",
    9868        4808 :                  CPLString()
    9869        2404 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
    9870        4808 :                      .append(CPLString().vPrintf(fmt, args))
    9871             :                      .c_str());
    9872             :     }
    9873             :     else
    9874             :     {
    9875          94 :         CPLErrorV(eErrClass, err_no, fmt, args);
    9876             :     }
    9877             : 
    9878        2498 :     va_end(args);
    9879        2498 : }
    9880             : #endif
    9881             : 
    9882             : /************************************************************************/
    9883             : /*                           GetVirtualMemAuto()                        */
    9884             : /************************************************************************/
    9885             : 
    9886             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9887             :  *
    9888             :  * Only supported on Linux and Unix systems with mmap() for now.
    9889             :  *
    9890             :  * This method allows creating a virtual memory object for a GDALRasterBand,
    9891             :  * that exposes the whole image data as a virtual array.
    9892             :  *
    9893             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
    9894             :  * specialized implementation, such as for raw files, may also directly use
    9895             :  * mechanisms of the operating system to create a view of the underlying file
    9896             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
    9897             :  *
    9898             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
    9899             :  * offer a specialized implementation with direct file mapping, provided that
    9900             :  * some requirements are met :
    9901             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
    9902             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
    9903             :  *     must match the native ordering of the CPU.
    9904             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
    9905             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
    9906             :  * the file in sequential order, and be equally spaced (which is generally the
    9907             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
    9908             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
    9909             :  *
    9910             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
    9911             :  * CPLVirtualMemFree() must be called before the raster band object is
    9912             :  * destroyed.
    9913             :  *
    9914             :  * If p is such a pointer and base_type the type matching
    9915             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
    9916             :  * accessed with
    9917             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
    9918             :  *
    9919             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
    9920             :  *
    9921             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
    9922             :  * read/write the band.
    9923             :  *
    9924             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
    9925             :  * one pixel value in the buffer to the start of the next pixel value within a
    9926             :  * scanline.
    9927             :  *
    9928             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
    9929             :  * one scanline in the buffer to the start of the next.
    9930             :  *
    9931             :  * @param papszOptions NULL terminated list of options.
    9932             :  *                     If a specialized implementation exists, defining
    9933             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
    9934             :  * used. On the contrary, defining
    9935             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
    9936             :  * being used (thus only allowing efficient implementations to be used). When
    9937             :  * requiring or falling back to the default implementation, the following
    9938             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
    9939             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
    9940             :  * to FALSE)
    9941             :  *
    9942             :  * @return a virtual memory object that must be unreferenced by
    9943             :  * CPLVirtualMemFree(), or NULL in case of failure.
    9944             :  *
    9945             :  */
    9946             : 
    9947           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
    9948             :                                                  int *pnPixelSpace,
    9949             :                                                  GIntBig *pnLineSpace,
    9950             :                                                  char **papszOptions)
    9951             : {
    9952           9 :     const char *pszImpl = CSLFetchNameValueDef(
    9953             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
    9954           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
    9955           8 :         EQUAL(pszImpl, "FALSE"))
    9956             :     {
    9957           1 :         return nullptr;
    9958             :     }
    9959             : 
    9960           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
    9961           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
    9962           8 :     if (pnPixelSpace)
    9963           8 :         *pnPixelSpace = nPixelSpace;
    9964           8 :     if (pnLineSpace)
    9965           8 :         *pnLineSpace = nLineSpace;
    9966             :     const size_t nCacheSize =
    9967           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
    9968             :     const size_t nPageSizeHint =
    9969           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
    9970           8 :     const bool bSingleThreadUsage = CPLTestBool(
    9971             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
    9972           8 :     return GDALRasterBandGetVirtualMem(
    9973             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
    9974             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
    9975             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
    9976           8 :         papszOptions);
    9977             : }
    9978             : 
    9979             : /************************************************************************/
    9980             : /*                         GDALGetVirtualMemAuto()                      */
    9981             : /************************************************************************/
    9982             : 
    9983             : /**
    9984             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9985             :  *
    9986             :  * @see GDALRasterBand::GetVirtualMemAuto()
    9987             :  */
    9988             : 
    9989          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
    9990             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
    9991             :                                      CSLConstList papszOptions)
    9992             : {
    9993          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
    9994             : 
    9995          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9996             : 
    9997          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
    9998          31 :                                      const_cast<char **>(papszOptions));
    9999             : }
   10000             : 
   10001             : /************************************************************************/
   10002             : /*                        GDALGetDataCoverageStatus()                   */
   10003             : /************************************************************************/
   10004             : 
   10005             : /**
   10006             :  * \brief Get the coverage status of a sub-window of the raster.
   10007             :  *
   10008             :  * Returns whether a sub-window of the raster contains only data, only empty
   10009             :  * blocks or a mix of both. This function can be used to determine quickly
   10010             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10011             :  * be sparse.
   10012             :  *
   10013             :  * Empty blocks are blocks that are generally not physically present in the
   10014             :  * file, and when read through GDAL, contain only pixels whose value is the
   10015             :  * nodata value when it is set, or whose value is 0 when the nodata value is
   10016             :  * not set.
   10017             :  *
   10018             :  * The query is done in an efficient way without reading the actual pixel
   10019             :  * values. If not possible, or not implemented at all by the driver,
   10020             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10021             :  * be returned.
   10022             :  *
   10023             :  * The values that can be returned by the function are the following,
   10024             :  * potentially combined with the binary or operator :
   10025             :  * <ul>
   10026             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10027             :  * GetDataCoverageStatus(). This flag should be returned together with
   10028             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10029             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10030             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10031             :  * the queried window. This is typically identified by the concept of missing
   10032             :  * block in formats that supports it.
   10033             :  * </li>
   10034             :  * </ul>
   10035             :  *
   10036             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10037             :  * should be interpreted more as hint of potential presence of data. For example
   10038             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10039             :  * nodata value), instead of using the missing block mechanism,
   10040             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10041             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10042             :  *
   10043             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10044             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10045             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10046             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10047             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10048             :  * the function will exit, so that you can potentially refine the requested area
   10049             :  * to find which particular region(s) have missing blocks.
   10050             :  *
   10051             :  * @see GDALRasterBand::GetDataCoverageStatus()
   10052             :  *
   10053             :  * @param hBand raster band
   10054             :  *
   10055             :  * @param nXOff The pixel offset to the top left corner of the region
   10056             :  * of the band to be queried. This would be zero to start from the left side.
   10057             :  *
   10058             :  * @param nYOff The line offset to the top left corner of the region
   10059             :  * of the band to be queried. This would be zero to start from the top.
   10060             :  *
   10061             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10062             :  *
   10063             :  * @param nYSize The height of the region of the band to be queried in lines.
   10064             :  *
   10065             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10066             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10067             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10068             :  * as the computation of the coverage matches the mask, the computation will be
   10069             :  * stopped. *pdfDataPct will not be valid in that case.
   10070             :  *
   10071             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10072             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10073             :  * sub-window that have valid values. The implementation might not always be
   10074             :  * able to compute it, in which case it will be set to a negative value.
   10075             :  *
   10076             :  * @return a binary-or'ed combination of possible values
   10077             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10078             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10079             :  */
   10080             : 
   10081          29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
   10082             :                                           int nYOff, int nXSize, int nYSize,
   10083             :                                           int nMaskFlagStop, double *pdfDataPct)
   10084             : {
   10085          29 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
   10086             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
   10087             : 
   10088          29 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10089             : 
   10090          29 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
   10091          29 :                                          nMaskFlagStop, pdfDataPct);
   10092             : }
   10093             : 
   10094             : /************************************************************************/
   10095             : /*                          GetDataCoverageStatus()                     */
   10096             : /************************************************************************/
   10097             : 
   10098             : /**
   10099             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
   10100             :  *                                           int nYOff,
   10101             :  *                                           int nXSize,
   10102             :  *                                           int nYSize,
   10103             :  *                                           int nMaskFlagStop,
   10104             :  *                                           double* pdfDataPct)
   10105             :  * \brief Get the coverage status of a sub-window of the raster.
   10106             :  *
   10107             :  * Returns whether a sub-window of the raster contains only data, only empty
   10108             :  * blocks or a mix of both. This function can be used to determine quickly
   10109             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10110             :  * be sparse.
   10111             :  *
   10112             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10113             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10114             :  *
   10115             :  * The query is done in an efficient way without reading the actual pixel
   10116             :  * values. If not possible, or not implemented at all by the driver,
   10117             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10118             :  * be returned.
   10119             :  *
   10120             :  * The values that can be returned by the function are the following,
   10121             :  * potentially combined with the binary or operator :
   10122             :  * <ul>
   10123             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10124             :  * GetDataCoverageStatus(). This flag should be returned together with
   10125             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10126             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10127             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10128             :  * the queried window. This is typically identified by the concept of missing
   10129             :  * block in formats that supports it.
   10130             :  * </li>
   10131             :  * </ul>
   10132             :  *
   10133             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10134             :  * should be interpreted more as hint of potential presence of data. For example
   10135             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10136             :  * nodata value), instead of using the missing block mechanism,
   10137             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10138             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10139             :  *
   10140             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10141             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10142             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10143             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10144             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10145             :  * the function will exit, so that you can potentially refine the requested area
   10146             :  * to find which particular region(s) have missing blocks.
   10147             :  *
   10148             :  * @see GDALGetDataCoverageStatus()
   10149             :  *
   10150             :  * @param nXOff The pixel offset to the top left corner of the region
   10151             :  * of the band to be queried. This would be zero to start from the left side.
   10152             :  *
   10153             :  * @param nYOff The line offset to the top left corner of the region
   10154             :  * of the band to be queried. This would be zero to start from the top.
   10155             :  *
   10156             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10157             :  *
   10158             :  * @param nYSize The height of the region of the band to be queried in lines.
   10159             :  *
   10160             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10161             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10162             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10163             :  * as the computation of the coverage matches the mask, the computation will be
   10164             :  * stopped. *pdfDataPct will not be valid in that case.
   10165             :  *
   10166             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10167             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10168             :  * sub-window that have valid values. The implementation might not always be
   10169             :  * able to compute it, in which case it will be set to a negative value.
   10170             :  *
   10171             :  * @return a binary-or'ed combination of possible values
   10172             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10173             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10174             :  */
   10175             : 
   10176             : /**
   10177             :  * \brief Get the coverage status of a sub-window of the raster.
   10178             :  *
   10179             :  * Returns whether a sub-window of the raster contains only data, only empty
   10180             :  * blocks or a mix of both. This function can be used to determine quickly
   10181             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10182             :  * be sparse.
   10183             :  *
   10184             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10185             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10186             :  *
   10187             :  * The query is done in an efficient way without reading the actual pixel
   10188             :  * values. If not possible, or not implemented at all by the driver,
   10189             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10190             :  * be returned.
   10191             :  *
   10192             :  * The values that can be returned by the function are the following,
   10193             :  * potentially combined with the binary or operator :
   10194             :  * <ul>
   10195             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10196             :  * GetDataCoverageStatus(). This flag should be returned together with
   10197             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10198             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10199             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10200             :  * the queried window. This is typically identified by the concept of missing
   10201             :  * block in formats that supports it.
   10202             :  * </li>
   10203             :  * </ul>
   10204             :  *
   10205             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10206             :  * should be interpreted more as hint of potential presence of data. For example
   10207             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10208             :  * nodata value), instead of using the missing block mechanism,
   10209             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10210             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10211             :  *
   10212             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10213             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10214             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10215             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10216             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10217             :  * the function will exit, so that you can potentially refine the requested area
   10218             :  * to find which particular region(s) have missing blocks.
   10219             :  *
   10220             :  * @see GDALGetDataCoverageStatus()
   10221             :  *
   10222             :  * @param nXOff The pixel offset to the top left corner of the region
   10223             :  * of the band to be queried. This would be zero to start from the left side.
   10224             :  *
   10225             :  * @param nYOff The line offset to the top left corner of the region
   10226             :  * of the band to be queried. This would be zero to start from the top.
   10227             :  *
   10228             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10229             :  *
   10230             :  * @param nYSize The height of the region of the band to be queried in lines.
   10231             :  *
   10232             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10233             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10234             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10235             :  * as the computation of the coverage matches the mask, the computation will be
   10236             :  * stopped. *pdfDataPct will not be valid in that case.
   10237             :  *
   10238             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10239             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10240             :  * sub-window that have valid values. The implementation might not always be
   10241             :  * able to compute it, in which case it will be set to a negative value.
   10242             :  *
   10243             :  * @return a binary-or'ed combination of possible values
   10244             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10245             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10246             :  */
   10247             : 
   10248        4705 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
   10249             :                                           int nYSize, int nMaskFlagStop,
   10250             :                                           double *pdfDataPct)
   10251             : {
   10252        4705 :     if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
   10253        4705 :         nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
   10254        4705 :         nYOff + nYSize > nRasterYSize)
   10255             :     {
   10256           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
   10257           0 :         if (pdfDataPct)
   10258           0 :             *pdfDataPct = 0.0;
   10259             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10260           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
   10261             :     }
   10262        4705 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
   10263        4705 :                                   pdfDataPct);
   10264             : }
   10265             : 
   10266             : /************************************************************************/
   10267             : /*                         IGetDataCoverageStatus()                     */
   10268             : /************************************************************************/
   10269             : 
   10270         685 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
   10271             :                                            int /*nXSize*/, int /*nYSize*/,
   10272             :                                            int /*nMaskFlagStop*/,
   10273             :                                            double *pdfDataPct)
   10274             : {
   10275         685 :     if (pdfDataPct != nullptr)
   10276           0 :         *pdfDataPct = 100.0;
   10277             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10278         685 :            GDAL_DATA_COVERAGE_STATUS_DATA;
   10279             : }
   10280             : 
   10281             : //! @cond Doxygen_Suppress
   10282             : /************************************************************************/
   10283             : /*                          EnterReadWrite()                            */
   10284             : /************************************************************************/
   10285             : 
   10286     7760910 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
   10287             : {
   10288     7760910 :     if (poDS != nullptr)
   10289     7037670 :         return poDS->EnterReadWrite(eRWFlag);
   10290      723239 :     return FALSE;
   10291             : }
   10292             : 
   10293             : /************************************************************************/
   10294             : /*                         LeaveReadWrite()                             */
   10295             : /************************************************************************/
   10296             : 
   10297     1129220 : void GDALRasterBand::LeaveReadWrite()
   10298             : {
   10299     1129220 :     if (poDS != nullptr)
   10300     1129220 :         poDS->LeaveReadWrite();
   10301     1129220 : }
   10302             : 
   10303             : /************************************************************************/
   10304             : /*                           InitRWLock()                               */
   10305             : /************************************************************************/
   10306             : 
   10307     3978320 : void GDALRasterBand::InitRWLock()
   10308             : {
   10309     3978320 :     if (poDS != nullptr)
   10310     3977910 :         poDS->InitRWLock();
   10311     3978320 : }
   10312             : 
   10313             : //! @endcond
   10314             : 
   10315             : // clang-format off
   10316             : 
   10317             : /**
   10318             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
   10319             :  * \brief Set metadata.
   10320             :  *
   10321             :  * CAUTION: depending on the format, older values of the updated information
   10322             :  * might still be found in the file in a "ghost" state, even if no longer
   10323             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10324             :  * format (this is not a exhaustive list)
   10325             :  *
   10326             :  * The C function GDALSetMetadata() does the same thing as this method.
   10327             :  *
   10328             :  * @param papszMetadata the metadata in name=value string list format to
   10329             :  * apply.
   10330             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
   10331             :  * domain.
   10332             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
   10333             :  * metadata has been accepted, but is likely not maintained persistently
   10334             :  * by the underlying object between sessions.
   10335             :  */
   10336             : 
   10337             : /**
   10338             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
   10339             :  * \brief Set single metadata item.
   10340             :  *
   10341             :  * CAUTION: depending on the format, older values of the updated information
   10342             :  * might still be found in the file in a "ghost" state, even if no longer
   10343             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10344             :  * format (this is not a exhaustive list)
   10345             :  *
   10346             :  * The C function GDALSetMetadataItem() does the same thing as this method.
   10347             :  *
   10348             :  * @param pszName the key for the metadata item to fetch.
   10349             :  * @param pszValue the value to assign to the key.
   10350             :  * @param pszDomain the domain to set within, use NULL for the default domain.
   10351             :  *
   10352             :  * @return CE_None on success, or an error code on failure.
   10353             :  */
   10354             : 
   10355             : // clang-format on
   10356             : 
   10357             : //! @cond Doxygen_Suppress
   10358             : /************************************************************************/
   10359             : /*                    EnablePixelTypeSignedByteWarning()                */
   10360             : /************************************************************************/
   10361             : 
   10362      157203 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
   10363             : {
   10364      157203 :     m_bEnablePixelTypeSignedByteWarning = b;
   10365      157203 : }
   10366             : 
   10367        4904 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
   10368             : {
   10369        4904 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
   10370        4904 : }
   10371             : 
   10372             : //! @endcond
   10373             : 
   10374             : /************************************************************************/
   10375             : /*                           GetMetadataItem()                          */
   10376             : /************************************************************************/
   10377             : 
   10378      621360 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
   10379             :                                             const char *pszDomain)
   10380             : {
   10381             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
   10382      621360 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
   10383      462695 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
   10384      322053 :         EQUAL(pszName, "PIXELTYPE"))
   10385             :     {
   10386           2 :         CPLError(CE_Warning, CPLE_AppDefined,
   10387             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
   10388             :                  "used to signal signed 8-bit raster. Change your code to "
   10389             :                  "test for the new GDT_Int8 data type instead.");
   10390             :     }
   10391      621360 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
   10392             : }
   10393             : 
   10394             : /************************************************************************/
   10395             : /*                            WindowIterator                            */
   10396             : /************************************************************************/
   10397             : 
   10398             : //! @cond Doxygen_Suppress
   10399             : 
   10400         576 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
   10401             :                                                int nRasterYSize,
   10402             :                                                int nBlockXSize, int nBlockYSize,
   10403         576 :                                                int nRow, int nCol)
   10404             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
   10405             :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
   10406         576 :       m_col(nCol)
   10407             : {
   10408         576 : }
   10409             : 
   10410         784 : bool GDALRasterBand::WindowIterator::operator==(
   10411             :     const WindowIterator &other) const
   10412             : {
   10413         259 :     return m_row == other.m_row && m_col == other.m_col &&
   10414         259 :            m_nRasterXSize == other.m_nRasterXSize &&
   10415         259 :            m_nRasterYSize == other.m_nRasterYSize &&
   10416        1302 :            m_nBlockXSize == other.m_nBlockXSize &&
   10417        1043 :            m_nBlockYSize == other.m_nBlockYSize;
   10418             : }
   10419             : 
   10420         758 : bool GDALRasterBand::WindowIterator::operator!=(
   10421             :     const WindowIterator &other) const
   10422             : {
   10423         758 :     return !(*this == other);
   10424             : }
   10425             : 
   10426             : GDALRasterBand::WindowIterator::value_type
   10427         524 : GDALRasterBand::WindowIterator::operator*() const
   10428             : {
   10429             :     GDALRasterWindow ret;
   10430         524 :     ret.nXOff = m_col * m_nBlockXSize;
   10431         524 :     ret.nYOff = m_row * m_nBlockYSize;
   10432         524 :     ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
   10433         524 :     ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
   10434             : 
   10435         524 :     return ret;
   10436             : }
   10437             : 
   10438         522 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
   10439             : {
   10440         522 :     m_col++;
   10441         522 :     if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
   10442             :     {
   10443         438 :         m_col = 0;
   10444         438 :         m_row++;
   10445             :     }
   10446         522 :     return *this;
   10447             : }
   10448             : 
   10449         305 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
   10450         305 :     const GDALRasterBand &band, size_t maxSize)
   10451         305 :     : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
   10452         305 :       m_nBlockXSize(-1), m_nBlockYSize(-1)
   10453             : {
   10454             : #ifdef CSA_BUILD
   10455             :     assert(this);
   10456             : #endif
   10457             :     int nXSize, nYSize;
   10458             : 
   10459         305 :     CPLErrorStateBackuper state(CPLQuietErrorHandler);
   10460         305 :     band.GetBlockSize(&nXSize, &nYSize);
   10461         305 :     if (nXSize < 1 || nYSize < 0)
   10462             :     {
   10463             :         // If invalid block size is reported, assume scanlines
   10464           4 :         nXSize = m_nRasterXSize;
   10465           4 :         nYSize = 1;
   10466             :     }
   10467             : 
   10468         305 :     if (maxSize == 0)
   10469             :     {
   10470         234 :         m_nBlockXSize = nXSize;
   10471         234 :         m_nBlockYSize = nYSize;
   10472         234 :         return;
   10473             :     }
   10474             : 
   10475          71 :     const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
   10476          71 :     const double dfBlocksPerChunk =
   10477          71 :         static_cast<double>(maxSize) /
   10478          71 :         (static_cast<double>(nXSize) * static_cast<double>(nYSize));
   10479             : 
   10480          71 :     if (dfBlocksPerChunk < dfBlocksPerRow)
   10481             :     {
   10482          14 :         m_nBlockXSize = static_cast<int>(std::min<double>(
   10483          14 :             m_nRasterXSize,
   10484          14 :             nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
   10485          14 :         m_nBlockYSize = nYSize;
   10486             :     }
   10487             :     else
   10488             :     {
   10489          57 :         m_nBlockXSize = m_nRasterXSize;
   10490          57 :         m_nBlockYSize = static_cast<int>(std::min<double>(
   10491          57 :             m_nRasterYSize,
   10492          57 :             nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
   10493             :     }
   10494             :     if constexpr (sizeof(size_t) < sizeof(uint64_t))
   10495             :     {
   10496             :         if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
   10497             :         {
   10498             :             nXSize = m_nRasterXSize;
   10499             :             nYSize = 1;
   10500             :         }
   10501             :     }
   10502             : }
   10503             : 
   10504             : GDALRasterBand::WindowIterator
   10505         274 : GDALRasterBand::WindowIteratorWrapper::begin() const
   10506             : {
   10507         274 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10508         274 :                           m_nBlockYSize, 0, 0);
   10509             : }
   10510             : 
   10511             : GDALRasterBand::WindowIterator
   10512         274 : GDALRasterBand::WindowIteratorWrapper::end() const
   10513             : {
   10514         274 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10515         274 :                           m_nBlockYSize,
   10516         274 :                           DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
   10517             : }
   10518             : 
   10519          63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
   10520             : {
   10521          63 :     return static_cast<uint64_t>(
   10522          63 :                cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
   10523          63 :            static_cast<uint64_t>(
   10524          63 :                cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
   10525             : }
   10526             : 
   10527             : //! @endcond
   10528             : 
   10529             : /** Return an object whose begin() and end() methods can be used to iterate
   10530             :  *  over GDALRasterWindow objects that are aligned with blocks in this raster
   10531             :  *  band. The iteration order is from left to right, then from top to bottom.
   10532             :  *
   10533             : \code{.cpp}
   10534             :     std::vector<double> pixelValues;
   10535             :     for (const auto& window : poBand->IterateWindows()) {
   10536             :         CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
   10537             :                                          window.nXSize, window.nYSize);
   10538             :         // check eErr
   10539             :     }
   10540             : \endcode
   10541             :  *
   10542             :  *
   10543             :  *  @param maxSize The maximum number of pixels in each window. If set to
   10544             :  *         zero (the default), or a number smaller than the block size,
   10545             :  *         the window size will be the same as the block size.
   10546             :  *  @since GDAL 3.12
   10547             :  */
   10548             : GDALRasterBand::WindowIteratorWrapper
   10549         305 : GDALRasterBand::IterateWindows(size_t maxSize) const
   10550             : {
   10551         305 :     return WindowIteratorWrapper(*this, maxSize);
   10552             : }
   10553             : 
   10554             : /************************************************************************/
   10555             : /*                     GDALMDArrayFromRasterBand                        */
   10556             : /************************************************************************/
   10557             : 
   10558             : class GDALMDArrayFromRasterBand final : public GDALMDArray
   10559             : {
   10560             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
   10561             : 
   10562             :     GDALDataset *m_poDS;
   10563             :     GDALRasterBand *m_poBand;
   10564             :     GDALExtendedDataType m_dt;
   10565             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
   10566             :     std::string m_osUnit;
   10567             :     std::vector<GByte> m_pabyNoData{};
   10568             :     std::shared_ptr<GDALMDArray> m_varX{};
   10569             :     std::shared_ptr<GDALMDArray> m_varY{};
   10570             :     std::string m_osFilename{};
   10571             : 
   10572             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
   10573             :                    const size_t *count, const GInt64 *arrayStep,
   10574             :                    const GPtrDiff_t *bufferStride,
   10575             :                    const GDALExtendedDataType &bufferDataType,
   10576             :                    void *pBuffer) const;
   10577             : 
   10578             :   protected:
   10579          34 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
   10580          68 :         : GDALAbstractMDArray(std::string(),
   10581          68 :                               std::string(poDS->GetDescription()) +
   10582             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
   10583          68 :           GDALMDArray(std::string(),
   10584          68 :                       std::string(poDS->GetDescription()) +
   10585             :                           CPLSPrintf(" band %d", poBand->GetBand())),
   10586             :           m_poDS(poDS), m_poBand(poBand),
   10587             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
   10588         170 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
   10589             :     {
   10590          34 :         m_poDS->Reference();
   10591             : 
   10592          34 :         int bHasNoData = false;
   10593          34 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
   10594             :         {
   10595           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
   10596           0 :             if (bHasNoData)
   10597             :             {
   10598           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   10599           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
   10600             :                                 m_dt.GetNumericDataType(), 0, 1);
   10601             :             }
   10602             :         }
   10603          34 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
   10604             :         {
   10605           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
   10606           0 :             if (bHasNoData)
   10607             :             {
   10608           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   10609           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
   10610             :                                 m_dt.GetNumericDataType(), 0, 1);
   10611             :             }
   10612             :         }
   10613             :         else
   10614             :         {
   10615          34 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
   10616          34 :             if (bHasNoData)
   10617             :             {
   10618           1 :                 m_pabyNoData.resize(m_dt.GetSize());
   10619           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
   10620             :                                 m_dt.GetNumericDataType(), 0, 1);
   10621             :             }
   10622             :         }
   10623             : 
   10624          34 :         const int nXSize = poBand->GetXSize();
   10625          34 :         const int nYSize = poBand->GetYSize();
   10626             : 
   10627          34 :         auto poSRS = m_poDS->GetSpatialRef();
   10628          68 :         std::string osTypeY;
   10629          68 :         std::string osTypeX;
   10630          68 :         std::string osDirectionY;
   10631          68 :         std::string osDirectionX;
   10632          34 :         if (poSRS && poSRS->GetAxesCount() == 2)
   10633             :         {
   10634          24 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
   10635          24 :             OGRAxisOrientation eOrientation1 = OAO_Other;
   10636          24 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
   10637          24 :             OGRAxisOrientation eOrientation2 = OAO_Other;
   10638          24 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
   10639          24 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
   10640             :             {
   10641           8 :                 if (mapping == std::vector<int>{1, 2})
   10642             :                 {
   10643           8 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   10644           8 :                     osDirectionY = "NORTH";
   10645           8 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   10646           8 :                     osDirectionX = "EAST";
   10647             :                 }
   10648             :             }
   10649          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
   10650             :             {
   10651          16 :                 if (mapping == std::vector<int>{2, 1})
   10652             :                 {
   10653          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   10654          16 :                     osDirectionY = "NORTH";
   10655          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   10656          16 :                     osDirectionX = "EAST";
   10657             :                 }
   10658             :             }
   10659             :         }
   10660             : 
   10661         170 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
   10662             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
   10663          68 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
   10664         102 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
   10665             : 
   10666          34 :         GDALGeoTransform gt;
   10667          34 :         if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
   10668             :         {
   10669          50 :             m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
   10670          50 :                                                         gt[0], gt[1], 0.5);
   10671          25 :             m_dims[1]->SetIndexingVariable(m_varX);
   10672             : 
   10673          50 :             m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
   10674          50 :                                                         gt[3], gt[5], 0.5);
   10675          25 :             m_dims[0]->SetIndexingVariable(m_varY);
   10676             :         }
   10677          34 :     }
   10678             : 
   10679             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
   10680             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   10681             :                const GDALExtendedDataType &bufferDataType,
   10682             :                void *pDstBuffer) const override;
   10683             : 
   10684           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
   10685             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   10686             :                 const GDALExtendedDataType &bufferDataType,
   10687             :                 const void *pSrcBuffer) override
   10688             :     {
   10689           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
   10690             :                          bufferStride, bufferDataType,
   10691           1 :                          const_cast<void *>(pSrcBuffer));
   10692             :     }
   10693             : 
   10694             :   public:
   10695          68 :     ~GDALMDArrayFromRasterBand() override
   10696          34 :     {
   10697          34 :         m_poDS->ReleaseRef();
   10698          68 :     }
   10699             : 
   10700          34 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
   10701             :                                                GDALRasterBand *poBand)
   10702             :     {
   10703             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
   10704          68 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
   10705          34 :         array->SetSelf(array);
   10706          68 :         return array;
   10707             :     }
   10708             : 
   10709           5 :     bool IsWritable() const override
   10710             :     {
   10711           5 :         return m_poDS->GetAccess() == GA_Update;
   10712             :     }
   10713             : 
   10714         122 :     const std::string &GetFilename() const override
   10715             :     {
   10716         122 :         return m_osFilename;
   10717             :     }
   10718             : 
   10719             :     const std::vector<std::shared_ptr<GDALDimension>> &
   10720         343 :     GetDimensions() const override
   10721             :     {
   10722         343 :         return m_dims;
   10723             :     }
   10724             : 
   10725         158 :     const GDALExtendedDataType &GetDataType() const override
   10726             :     {
   10727         158 :         return m_dt;
   10728             :     }
   10729             : 
   10730           5 :     const std::string &GetUnit() const override
   10731             :     {
   10732           5 :         return m_osUnit;
   10733             :     }
   10734             : 
   10735          32 :     const void *GetRawNoDataValue() const override
   10736             :     {
   10737          32 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
   10738             :     }
   10739             : 
   10740           4 :     double GetOffset(bool *pbHasOffset,
   10741             :                      GDALDataType *peStorageType) const override
   10742             :     {
   10743           4 :         int bHasOffset = false;
   10744           4 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
   10745           4 :         if (pbHasOffset)
   10746           4 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
   10747           4 :         if (peStorageType)
   10748           1 :             *peStorageType = GDT_Unknown;
   10749           4 :         return dfRes;
   10750             :     }
   10751             : 
   10752           4 :     double GetScale(bool *pbHasScale,
   10753             :                     GDALDataType *peStorageType) const override
   10754             :     {
   10755           4 :         int bHasScale = false;
   10756           4 :         double dfRes = m_poBand->GetScale(&bHasScale);
   10757           4 :         if (pbHasScale)
   10758           4 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
   10759           4 :         if (peStorageType)
   10760           1 :             *peStorageType = GDT_Unknown;
   10761           4 :         return dfRes;
   10762             :     }
   10763             : 
   10764          88 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
   10765             :     {
   10766          88 :         auto poSrcSRS = m_poDS->GetSpatialRef();
   10767          88 :         if (!poSrcSRS)
   10768           2 :             return nullptr;
   10769         172 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
   10770             : 
   10771         172 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
   10772          86 :         constexpr int iYDim = 0;
   10773          86 :         constexpr int iXDim = 1;
   10774         258 :         for (auto &m : axisMapping)
   10775             :         {
   10776         172 :             if (m == 1)
   10777          86 :                 m = iXDim + 1;
   10778          86 :             else if (m == 2)
   10779          86 :                 m = iYDim + 1;
   10780             :             else
   10781           0 :                 m = 0;
   10782             :         }
   10783          86 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
   10784          86 :         return poSRS;
   10785             :     }
   10786             : 
   10787          32 :     std::vector<GUInt64> GetBlockSize() const override
   10788             :     {
   10789          32 :         int nBlockXSize = 0;
   10790          32 :         int nBlockYSize = 0;
   10791          32 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
   10792          32 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
   10793          32 :                                     static_cast<GUInt64>(nBlockXSize)};
   10794             :     }
   10795             : 
   10796             :     std::vector<std::shared_ptr<GDALAttribute>>
   10797          23 :     GetAttributes(CSLConstList) const override
   10798             :     {
   10799          23 :         std::vector<std::shared_ptr<GDALAttribute>> res;
   10800          23 :         auto papszMD = m_poBand->GetMetadata();
   10801          25 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
   10802             :         {
   10803           2 :             char *pszKey = nullptr;
   10804           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
   10805           2 :             if (pszKey && pszValue)
   10806             :             {
   10807             :                 res.emplace_back(
   10808           2 :                     std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
   10809             :             }
   10810           2 :             CPLFree(pszKey);
   10811             :         }
   10812          23 :         return res;
   10813             :     }
   10814             : };
   10815             : 
   10816          39 : bool GDALMDArrayFromRasterBand::IRead(
   10817             :     const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
   10818             :     const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
   10819             :     void *pDstBuffer) const
   10820             : {
   10821          39 :     return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
   10822          39 :                      bufferDataType, pDstBuffer);
   10823             : }
   10824             : 
   10825             : /************************************************************************/
   10826             : /*                            ReadWrite()                               */
   10827             : /************************************************************************/
   10828             : 
   10829          40 : bool GDALMDArrayFromRasterBand::ReadWrite(
   10830             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
   10831             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   10832             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
   10833             : {
   10834          40 :     constexpr size_t iDimX = 1;
   10835          40 :     constexpr size_t iDimY = 0;
   10836          40 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
   10837             :                                   arrayStartIdx, count, arrayStep, bufferStride,
   10838          40 :                                   bufferDataType, pBuffer);
   10839             : }
   10840             : 
   10841             : /************************************************************************/
   10842             : /*                       GDALMDRasterIOFromBand()                       */
   10843             : /************************************************************************/
   10844             : 
   10845          73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
   10846             :                             size_t iDimX, size_t iDimY,
   10847             :                             const GUInt64 *arrayStartIdx, const size_t *count,
   10848             :                             const GInt64 *arrayStep,
   10849             :                             const GPtrDiff_t *bufferStride,
   10850             :                             const GDALExtendedDataType &bufferDataType,
   10851             :                             void *pBuffer)
   10852             : {
   10853          73 :     const auto eDT(bufferDataType.GetNumericDataType());
   10854          73 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
   10855          73 :     const int nX =
   10856          73 :         arrayStep[iDimX] > 0
   10857          73 :             ? static_cast<int>(arrayStartIdx[iDimX])
   10858           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
   10859           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
   10860          73 :     const int nY =
   10861          73 :         arrayStep[iDimY] > 0
   10862          73 :             ? static_cast<int>(arrayStartIdx[iDimY])
   10863           6 :             : static_cast<int>(arrayStartIdx[iDimY] -
   10864           6 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
   10865          73 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
   10866          73 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
   10867          73 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
   10868          73 :     int nStrideXSign = 1;
   10869          73 :     if (arrayStep[iDimX] < 0)
   10870             :     {
   10871           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
   10872           2 :         nStrideXSign = -1;
   10873             :     }
   10874          73 :     int nStrideYSign = 1;
   10875          73 :     if (arrayStep[iDimY] < 0)
   10876             :     {
   10877           6 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
   10878           6 :         nStrideYSign = -1;
   10879             :     }
   10880             : 
   10881         146 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
   10882          73 :                             static_cast<int>(count[iDimX]),
   10883          73 :                             static_cast<int>(count[iDimY]), eDT,
   10884             :                             static_cast<GSpacing>(
   10885          73 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
   10886             :                             static_cast<GSpacing>(
   10887          73 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
   10888          73 :                             nullptr) == CE_None;
   10889             : }
   10890             : 
   10891             : /************************************************************************/
   10892             : /*                            AsMDArray()                               */
   10893             : /************************************************************************/
   10894             : 
   10895             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
   10896             :  *
   10897             :  * The band must be linked to a GDALDataset. If this dataset is not already
   10898             :  * marked as shared, it will be, so that the returned array holds a reference
   10899             :  * to it.
   10900             :  *
   10901             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   10902             :  * returned array will have an associated indexing variable.
   10903             :  *
   10904             :  * This is the same as the C function GDALRasterBandAsMDArray().
   10905             :  *
   10906             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
   10907             :  *
   10908             :  * @return a new array, or nullptr.
   10909             :  *
   10910             :  * @since GDAL 3.1
   10911             :  */
   10912          34 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
   10913             : {
   10914          34 :     if (!poDS)
   10915             :     {
   10916           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
   10917           0 :         return nullptr;
   10918             :     }
   10919          34 :     if (!poDS->GetShared())
   10920             :     {
   10921          33 :         poDS->MarkAsShared();
   10922             :     }
   10923             :     return GDALMDArrayFromRasterBand::Create(
   10924          34 :         poDS, const_cast<GDALRasterBand *>(this));
   10925             : }
   10926             : 
   10927             : /************************************************************************/
   10928             : /*                             InterpolateAtPoint()                     */
   10929             : /************************************************************************/
   10930             : 
   10931             : /**
   10932             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10933             :  * taking pixel/line coordinates as input.
   10934             :  *
   10935             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
   10936             :  * @param dfLine line coordinate as a double, where interpolation should be done.
   10937             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   10938             :  * @param pdfRealValue pointer to real part of interpolated value
   10939             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   10940             :  *
   10941             :  * @return CE_None on success, or an error code on failure.
   10942             :  * @since GDAL 3.10
   10943             :  */
   10944             : 
   10945         167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
   10946             :                                           GDALRIOResampleAlg eInterpolation,
   10947             :                                           double *pdfRealValue,
   10948             :                                           double *pdfImagValue) const
   10949             : {
   10950         167 :     if (eInterpolation != GRIORA_NearestNeighbour &&
   10951          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
   10952             :         eInterpolation != GRIORA_CubicSpline)
   10953             :     {
   10954           2 :         CPLError(CE_Failure, CPLE_AppDefined,
   10955             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
   10956             :                  "methods "
   10957             :                  "allowed");
   10958             : 
   10959           2 :         return CE_Failure;
   10960             :     }
   10961             : 
   10962         165 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
   10963         165 :     if (!m_poPointsCache)
   10964          85 :         m_poPointsCache = new GDALDoublePointsCache();
   10965             : 
   10966             :     const bool res =
   10967         165 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
   10968             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
   10969             : 
   10970         165 :     return res ? CE_None : CE_Failure;
   10971             : }
   10972             : 
   10973             : /************************************************************************/
   10974             : /*                        GDALRasterInterpolateAtPoint()                */
   10975             : /************************************************************************/
   10976             : 
   10977             : /**
   10978             :  * \brief Interpolates the value between pixels using
   10979             :  * a resampling algorithm
   10980             :  *
   10981             :  * @see GDALRasterBand::InterpolateAtPoint()
   10982             :  * @since GDAL 3.10
   10983             :  */
   10984             : 
   10985         144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
   10986             :                                     double dfLine,
   10987             :                                     GDALRIOResampleAlg eInterpolation,
   10988             :                                     double *pdfRealValue, double *pdfImagValue)
   10989             : {
   10990         144 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
   10991             : 
   10992         144 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10993         144 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
   10994         144 :                                       pdfRealValue, pdfImagValue);
   10995             : }
   10996             : 
   10997             : /************************************************************************/
   10998             : /*                    InterpolateAtGeolocation()                        */
   10999             : /************************************************************************/
   11000             : 
   11001             : /**
   11002             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11003             :  * taking georeferenced coordinates as input.
   11004             :  *
   11005             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   11006             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   11007             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   11008             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   11009             :  * array (generally WGS 84) if there is a geolocation array.
   11010             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   11011             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   11012             :  * be a easting, and dfGeolocY a northing.
   11013             :  *
   11014             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   11015             :  * expressed in that CRS, and that tuple must be conformant with the
   11016             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   11017             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   11018             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   11019             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   11020             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   11021             :  *
   11022             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
   11023             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
   11024             :  * it for details on how that transformation is done.
   11025             :  *
   11026             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   11027             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11028             :  * where interpolation should be done.
   11029             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   11030             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11031             :  * where interpolation should be done.
   11032             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   11033             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   11034             :  * @param pdfRealValue pointer to real part of interpolated value
   11035             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   11036             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
   11037             :  *
   11038             :  * @return CE_None on success, or an error code on failure.
   11039             :  * @since GDAL 3.11
   11040             :  */
   11041             : 
   11042          15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
   11043             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
   11044             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
   11045             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
   11046             : {
   11047             :     double dfPixel;
   11048             :     double dfLine;
   11049          15 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
   11050             :                                      &dfLine,
   11051          15 :                                      papszTransformerOptions) != CE_None)
   11052             :     {
   11053           1 :         return CE_Failure;
   11054             :     }
   11055          14 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
   11056          14 :                               pdfImagValue);
   11057             : }
   11058             : 
   11059             : /************************************************************************/
   11060             : /*                  GDALRasterInterpolateAtGeolocation()                */
   11061             : /************************************************************************/
   11062             : 
   11063             : /**
   11064             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11065             :  * taking georeferenced coordinates as input.
   11066             :  *
   11067             :  * @see GDALRasterBand::InterpolateAtGeolocation()
   11068             :  * @since GDAL 3.11
   11069             :  */
   11070             : 
   11071          15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
   11072             :                                           double dfGeolocX, double dfGeolocY,
   11073             :                                           OGRSpatialReferenceH hSRS,
   11074             :                                           GDALRIOResampleAlg eInterpolation,
   11075             :                                           double *pdfRealValue,
   11076             :                                           double *pdfImagValue,
   11077             :                                           CSLConstList papszTransformerOptions)
   11078             : {
   11079          15 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
   11080             : 
   11081          15 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   11082          15 :     return poBand->InterpolateAtGeolocation(
   11083          15 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
   11084          15 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
   11085             : }
   11086             : 
   11087             : /************************************************************************/
   11088             : /*                    GDALRasterBand::SplitRasterIO()                   */
   11089             : /************************************************************************/
   11090             : 
   11091             : //! @cond Doxygen_Suppress
   11092             : 
   11093             : /** Implements IRasterIO() by dividing the request in 2.
   11094             :  *
   11095             :  * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
   11096             :  *
   11097             :  * Return CE_Warning if the split could not be done, CE_None in case of
   11098             :  * success and CE_Failure in case of error.
   11099             :  *
   11100             :  * @since 3.12
   11101             :  */
   11102         999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
   11103             :                                      [[maybe_unused]] int nXSize,
   11104             :                                      [[maybe_unused]] int nYSize, void *pData,
   11105             :                                      int nBufXSize, int nBufYSize,
   11106             :                                      GDALDataType eBufType,
   11107             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
   11108             :                                      GDALRasterIOExtraArg *psExtraArg)
   11109             : {
   11110         999 :     CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
   11111             : 
   11112         999 :     GByte *pabyData = static_cast<GByte *>(pData);
   11113         999 :     if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
   11114             :     {
   11115             :         GDALRasterIOExtraArg sArg;
   11116         499 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11117         499 :         const int nHalfHeight = nBufYSize / 2;
   11118             : 
   11119         499 :         sArg.pfnProgress = GDALScaledProgress;
   11120         499 :         sArg.pProgressData = GDALCreateScaledProgress(
   11121             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11122         499 :         if (sArg.pProgressData == nullptr)
   11123         499 :             sArg.pfnProgress = nullptr;
   11124         998 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
   11125             :                                 pabyData, nBufXSize, nHalfHeight, eBufType,
   11126         499 :                                 nPixelSpace, nLineSpace, &sArg);
   11127         499 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11128             : 
   11129         499 :         if (eErr == CE_None)
   11130             :         {
   11131         499 :             sArg.pfnProgress = GDALScaledProgress;
   11132         499 :             sArg.pProgressData = GDALCreateScaledProgress(
   11133             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11134         499 :             if (sArg.pProgressData == nullptr)
   11135         499 :                 sArg.pfnProgress = nullptr;
   11136         998 :             eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
   11137             :                              nBufYSize - nHalfHeight,
   11138         499 :                              pabyData + nHalfHeight * nLineSpace, nBufXSize,
   11139             :                              nBufYSize - nHalfHeight, eBufType, nPixelSpace,
   11140         499 :                              nLineSpace, &sArg);
   11141         499 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11142             :         }
   11143         499 :         return eErr;
   11144             :     }
   11145         500 :     else if (nBufXSize >= 2)
   11146             :     {
   11147             :         GDALRasterIOExtraArg sArg;
   11148         500 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11149         500 :         const int nHalfWidth = nBufXSize / 2;
   11150             : 
   11151         500 :         sArg.pfnProgress = GDALScaledProgress;
   11152         500 :         sArg.pProgressData = GDALCreateScaledProgress(
   11153             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11154         500 :         if (sArg.pProgressData == nullptr)
   11155         500 :             sArg.pfnProgress = nullptr;
   11156        1000 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
   11157             :                                 pabyData, nHalfWidth, nBufYSize, eBufType,
   11158         500 :                                 nPixelSpace, nLineSpace, &sArg);
   11159         500 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11160             : 
   11161         500 :         if (eErr == CE_None)
   11162             :         {
   11163         500 :             sArg.pfnProgress = GDALScaledProgress;
   11164         500 :             sArg.pProgressData = GDALCreateScaledProgress(
   11165             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11166         500 :             if (sArg.pProgressData == nullptr)
   11167         500 :                 sArg.pfnProgress = nullptr;
   11168        1000 :             eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
   11169             :                              nBufXSize - nHalfWidth, nBufYSize,
   11170         500 :                              pabyData + nHalfWidth * nPixelSpace,
   11171             :                              nBufXSize - nHalfWidth, nBufYSize, eBufType,
   11172         500 :                              nPixelSpace, nLineSpace, &sArg);
   11173         500 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11174             :         }
   11175         500 :         return eErr;
   11176             :     }
   11177             : 
   11178           0 :     return CE_Warning;
   11179             : }
   11180             : 
   11181             : //! @endcond
   11182             : 
   11183             : /************************************************************************/
   11184             : /*                         ThrowIfNotSameDimensions()                   */
   11185             : /************************************************************************/
   11186             : 
   11187             : //! @cond Doxygen_Suppress
   11188             : /* static */
   11189         169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
   11190             :                                               const GDALRasterBand &second)
   11191             : {
   11192         320 :     if (first.GetXSize() != second.GetXSize() ||
   11193         151 :         first.GetYSize() != second.GetYSize())
   11194             :     {
   11195          36 :         throw std::runtime_error("Bands do not have the same dimensions");
   11196             :     }
   11197         133 : }
   11198             : 
   11199             : //! @endcond
   11200             : 
   11201             : /************************************************************************/
   11202             : /*                          GDALRasterBandUnaryOp()                     */
   11203             : /************************************************************************/
   11204             : 
   11205             : /** Apply a unary operation on this band.
   11206             :  *
   11207             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11208             :  * dataset.
   11209             :  *
   11210             :  * @since 3.12
   11211             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11212             :  */
   11213             : GDALComputedRasterBandH
   11214           6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
   11215             :                       GDALRasterAlgebraUnaryOperation eOp)
   11216             : {
   11217           6 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11218           6 :     GDALComputedRasterBand::Operation cppOp{};
   11219           6 :     switch (eOp)
   11220             :     {
   11221           2 :         case GRAUO_LOGICAL_NOT:
   11222             :             return new GDALComputedRasterBand(
   11223             :                 GDALComputedRasterBand::Operation::OP_NE,
   11224           2 :                 *(GDALRasterBand::FromHandle(hBand)), true);
   11225           1 :         case GRAUO_ABS:
   11226           1 :             cppOp = GDALComputedRasterBand::Operation::OP_ABS;
   11227           1 :             break;
   11228           1 :         case GRAUO_SQRT:
   11229           1 :             cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
   11230           1 :             break;
   11231           1 :         case GRAUO_LOG:
   11232             : #ifndef HAVE_MUPARSER
   11233             :             CPLError(
   11234             :                 CE_Failure, CPLE_NotSupported,
   11235             :                 "log(band) not available on a GDAL build without muparser");
   11236             :             return nullptr;
   11237             : #else
   11238           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG;
   11239           1 :             break;
   11240             : #endif
   11241           1 :         case GRAUO_LOG10:
   11242           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
   11243           1 :             break;
   11244             :     }
   11245             :     return new GDALComputedRasterBand(cppOp,
   11246           4 :                                       *(GDALRasterBand::FromHandle(hBand)));
   11247             : }
   11248             : 
   11249             : /************************************************************************/
   11250             : /*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
   11251             : /************************************************************************/
   11252             : 
   11253             : static GDALComputedRasterBand::Operation
   11254         120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
   11255             :     GDALRasterAlgebraBinaryOperation eOp)
   11256             : {
   11257         120 :     switch (eOp)
   11258             :     {
   11259          26 :         case GRABO_ADD:
   11260          26 :             return GDALComputedRasterBand::Operation::OP_ADD;
   11261           2 :         case GRABO_SUB:
   11262           2 :             return GDALComputedRasterBand::Operation::OP_SUBTRACT;
   11263          24 :         case GRABO_MUL:
   11264          24 :             return GDALComputedRasterBand::Operation::OP_MULTIPLY;
   11265           3 :         case GRABO_DIV:
   11266           3 :             return GDALComputedRasterBand::Operation::OP_DIVIDE;
   11267           6 :         case GRABO_GT:
   11268           6 :             return GDALComputedRasterBand::Operation::OP_GT;
   11269           8 :         case GRABO_GE:
   11270           8 :             return GDALComputedRasterBand::Operation::OP_GE;
   11271           6 :         case GRABO_LT:
   11272           6 :             return GDALComputedRasterBand::Operation::OP_LT;
   11273           6 :         case GRABO_LE:
   11274           6 :             return GDALComputedRasterBand::Operation::OP_LE;
   11275           6 :         case GRABO_EQ:
   11276           6 :             return GDALComputedRasterBand::Operation::OP_EQ;
   11277           6 :         case GRABO_NE:
   11278           6 :             break;
   11279          12 :         case GRABO_LOGICAL_AND:
   11280          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
   11281          12 :         case GRABO_LOGICAL_OR:
   11282          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
   11283           3 :         case GRABO_POW:
   11284           3 :             return GDALComputedRasterBand::Operation::OP_POW;
   11285             :     }
   11286           6 :     return GDALComputedRasterBand::Operation::OP_NE;
   11287             : }
   11288             : 
   11289             : /************************************************************************/
   11290             : /*                     GDALRasterBandBinaryOpBand()                     */
   11291             : /************************************************************************/
   11292             : 
   11293             : /** Apply a binary operation on this band with another one.
   11294             :  *
   11295             :  * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
   11296             :  * "hBand1 - hBand2".
   11297             :  *
   11298             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11299             :  * datasets.
   11300             :  *
   11301             :  * @since 3.12
   11302             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11303             :  */
   11304             : GDALComputedRasterBandH
   11305          57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
   11306             :                            GDALRasterAlgebraBinaryOperation eOp,
   11307             :                            GDALRasterBandH hOtherBand)
   11308             : {
   11309          57 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11310          57 :     VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
   11311             : #ifndef HAVE_MUPARSER
   11312             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11313             :     {
   11314             :         CPLError(
   11315             :             CE_Failure, CPLE_NotSupported,
   11316             :             "Band comparison operators not available on a GDAL build without "
   11317             :             "muparser");
   11318             :         return nullptr;
   11319             :     }
   11320             :     else if (eOp == GRABO_POW)
   11321             :     {
   11322             :         CPLError(
   11323             :             CE_Failure, CPLE_NotSupported,
   11324             :             "pow(band, band) not available on a GDAL build without muparser");
   11325             :         return nullptr;
   11326             :     }
   11327             : #endif
   11328          57 :     auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
   11329          57 :     auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
   11330             :     try
   11331             :     {
   11332          57 :         GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
   11333             :     }
   11334          13 :     catch (const std::exception &e)
   11335             :     {
   11336          13 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   11337          13 :         return nullptr;
   11338             :     }
   11339             :     return new GDALComputedRasterBand(
   11340          44 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
   11341          44 :         secondBand);
   11342             : }
   11343             : 
   11344             : /************************************************************************/
   11345             : /*                     GDALRasterBandBinaryOpDouble()                   */
   11346             : /************************************************************************/
   11347             : 
   11348             : /** Apply a binary operation on this band with a constant
   11349             :  *
   11350             :  * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
   11351             :  * "hBand - constant".
   11352             :  *
   11353             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11354             :  * dataset.
   11355             :  *
   11356             :  * @since 3.12
   11357             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11358             :  */
   11359             : GDALComputedRasterBandH
   11360          59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
   11361             :                              GDALRasterAlgebraBinaryOperation eOp,
   11362             :                              double constant)
   11363             : {
   11364          59 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11365             : #ifndef HAVE_MUPARSER
   11366             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11367             :     {
   11368             :         CPLError(
   11369             :             CE_Failure, CPLE_NotSupported,
   11370             :             "Band comparison operators not available on a GDAL build without "
   11371             :             "muparser");
   11372             :         return nullptr;
   11373             :     }
   11374             : #endif
   11375             :     return new GDALComputedRasterBand(
   11376          59 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11377          59 :         *(GDALRasterBand::FromHandle(hBand)), constant);
   11378             : }
   11379             : 
   11380             : /************************************************************************/
   11381             : /*                   GDALRasterBandBinaryOpDoubleToBand()               */
   11382             : /************************************************************************/
   11383             : 
   11384             : /** Apply a binary operation on the constant with this band
   11385             :  *
   11386             :  * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
   11387             :  * "constant - hBand".
   11388             :  *
   11389             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11390             :  * dataset.
   11391             :  *
   11392             :  * @since 3.12
   11393             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11394             :  */
   11395             : GDALComputedRasterBandH
   11396          18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
   11397             :                                    GDALRasterAlgebraBinaryOperation eOp,
   11398             :                                    GDALRasterBandH hBand)
   11399             : {
   11400          18 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11401             : #ifndef HAVE_MUPARSER
   11402             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11403             :     {
   11404             :         CPLError(
   11405             :             CE_Failure, CPLE_NotSupported,
   11406             :             "Band comparison operators not available on a GDAL build without "
   11407             :             "muparser");
   11408             :         return nullptr;
   11409             :     }
   11410             : #endif
   11411          18 :     switch (eOp)
   11412             :     {
   11413          15 :         case GRABO_ADD:
   11414             :         case GRABO_MUL:
   11415             :         {
   11416             :             return new GDALComputedRasterBand(
   11417          15 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11418          15 :                 *(GDALRasterBand::FromHandle(hBand)), constant);
   11419             :         }
   11420             : 
   11421           2 :         case GRABO_DIV:
   11422             :         case GRABO_GT:
   11423             :         case GRABO_GE:
   11424             :         case GRABO_LT:
   11425             :         case GRABO_LE:
   11426             :         case GRABO_EQ:
   11427             :         case GRABO_NE:
   11428             :         case GRABO_LOGICAL_AND:
   11429             :         case GRABO_LOGICAL_OR:
   11430             :         case GRABO_POW:
   11431             :         {
   11432             :             return new GDALComputedRasterBand(
   11433           2 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
   11434           2 :                 *(GDALRasterBand::FromHandle(hBand)));
   11435             :         }
   11436             : 
   11437           1 :         case GRABO_SUB:
   11438             :         {
   11439           1 :             break;
   11440             :         }
   11441             :     }
   11442             : 
   11443             :     return new GDALComputedRasterBand(
   11444             :         GDALComputedRasterBand::Operation::OP_ADD,
   11445           2 :         GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
   11446           1 :                                *(GDALRasterBand::FromHandle(hBand)), -1.0),
   11447           1 :         constant);
   11448             : }
   11449             : 
   11450             : /************************************************************************/
   11451             : /*                           operator+()                                */
   11452             : /************************************************************************/
   11453             : 
   11454             : /** Add this band with another one.
   11455             :  *
   11456             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11457             :  * datasets.
   11458             :  *
   11459             :  * @since 3.12
   11460             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11461             :  */
   11462             : GDALComputedRasterBand
   11463           8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
   11464             : {
   11465           8 :     ThrowIfNotSameDimensions(*this, other);
   11466             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11467           7 :                                   *this, other);
   11468             : }
   11469             : 
   11470             : /************************************************************************/
   11471             : /*                           operator+()                                */
   11472             : /************************************************************************/
   11473             : 
   11474             : /** Add this band with a constant.
   11475             :  *
   11476             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11477             :  * dataset.
   11478             :  *
   11479             :  * @since 3.12
   11480             :  */
   11481          13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
   11482             : {
   11483             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11484          13 :                                   *this, constant);
   11485             : }
   11486             : 
   11487             : /************************************************************************/
   11488             : /*                           operator+()                                */
   11489             : /************************************************************************/
   11490             : 
   11491             : /** Add a band with a constant.
   11492             :  *
   11493             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11494             :  * dataset.
   11495             :  *
   11496             :  * @since 3.12
   11497             :  */
   11498           1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
   11499             : {
   11500           1 :     return other + constant;
   11501             : }
   11502             : 
   11503             : /************************************************************************/
   11504             : /*                           operator-()                                */
   11505             : /************************************************************************/
   11506             : 
   11507             : /** Return a band whose value is the opposite value of the band for each
   11508             :  * pixel.
   11509             :  *
   11510             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11511             :  * dataset.
   11512             :  *
   11513             :  * @since 3.12
   11514             :  */
   11515           2 : GDALComputedRasterBand GDALRasterBand::operator-() const
   11516             : {
   11517           2 :     return 0 - *this;
   11518             : }
   11519             : 
   11520             : /************************************************************************/
   11521             : /*                           operator-()                                */
   11522             : /************************************************************************/
   11523             : 
   11524             : /** Subtract this band with another one.
   11525             :  *
   11526             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11527             :  * datasets.
   11528             :  *
   11529             :  * @since 3.12
   11530             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11531             :  */
   11532             : GDALComputedRasterBand
   11533           2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
   11534             : {
   11535           2 :     ThrowIfNotSameDimensions(*this, other);
   11536             :     return GDALComputedRasterBand(
   11537           2 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
   11538             : }
   11539             : 
   11540             : /************************************************************************/
   11541             : /*                           operator-()                                */
   11542             : /************************************************************************/
   11543             : 
   11544             : /** Subtract this band with a constant.
   11545             :  *
   11546             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11547             :  * dataset.
   11548             :  *
   11549             :  * @since 3.12
   11550             :  */
   11551           1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
   11552             : {
   11553             :     return GDALComputedRasterBand(
   11554           1 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
   11555             : }
   11556             : 
   11557             : /************************************************************************/
   11558             : /*                           operator-()                                */
   11559             : /************************************************************************/
   11560             : 
   11561             : /** Subtract a constant with a band.
   11562             :  *
   11563             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11564             :  * dataset.
   11565             :  *
   11566             :  * @since 3.12
   11567             :  */
   11568           3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
   11569             : {
   11570           6 :     return other * (-1.0) + constant;
   11571             : }
   11572             : 
   11573             : /************************************************************************/
   11574             : /*                           operator*()                                */
   11575             : /************************************************************************/
   11576             : 
   11577             : /** Multiply this band with another one.
   11578             :  *
   11579             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11580             :  * datasets.
   11581             :  *
   11582             :  * @since 3.12
   11583             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11584             :  */
   11585             : GDALComputedRasterBand
   11586           2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
   11587             : {
   11588           2 :     ThrowIfNotSameDimensions(*this, other);
   11589             :     return GDALComputedRasterBand(
   11590           2 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
   11591             : }
   11592             : 
   11593             : /************************************************************************/
   11594             : /*                           operator*()                                */
   11595             : /************************************************************************/
   11596             : 
   11597             : /** Multiply this band by a constant.
   11598             :  *
   11599             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11600             :  * dataset.
   11601             :  *
   11602             :  * @since 3.12
   11603             :  */
   11604          14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
   11605             : {
   11606             :     return GDALComputedRasterBand(
   11607          14 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
   11608             : }
   11609             : 
   11610             : /************************************************************************/
   11611             : /*                           operator*()                                */
   11612             : /************************************************************************/
   11613             : 
   11614             : /** Multiply a band with a constant.
   11615             :  *
   11616             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11617             :  * dataset.
   11618             :  *
   11619             :  * @since 3.12
   11620             :  */
   11621           2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
   11622             : {
   11623           2 :     return other * constant;
   11624             : }
   11625             : 
   11626             : /************************************************************************/
   11627             : /*                           operator/()                                */
   11628             : /************************************************************************/
   11629             : 
   11630             : /** Divide this band with another one.
   11631             :  *
   11632             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11633             :  * datasets.
   11634             :  *
   11635             :  * @since 3.12
   11636             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11637             :  */
   11638             : GDALComputedRasterBand
   11639           2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
   11640             : {
   11641           2 :     ThrowIfNotSameDimensions(*this, other);
   11642             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   11643           2 :                                   *this, other);
   11644             : }
   11645             : 
   11646             : /************************************************************************/
   11647             : /*                           operator/()                                */
   11648             : /************************************************************************/
   11649             : 
   11650             : /** Divide this band by a constant.
   11651             :  *
   11652             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11653             :  * dataset.
   11654             :  *
   11655             :  * @since 3.12
   11656             :  */
   11657           0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
   11658             : {
   11659             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   11660           0 :                                   *this, constant);
   11661             : }
   11662             : 
   11663             : /************************************************************************/
   11664             : /*                           operator/()                                */
   11665             : /************************************************************************/
   11666             : 
   11667             : /** Divide a constant by a band.
   11668             :  *
   11669             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11670             :  * dataset.
   11671             :  *
   11672             :  * @since 3.12
   11673             :  */
   11674           1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
   11675             : {
   11676             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   11677           1 :                                   constant, other);
   11678             : }
   11679             : 
   11680             : /************************************************************************/
   11681             : /*                          ThrowIfNotMuparser()                        */
   11682             : /************************************************************************/
   11683             : 
   11684             : #ifndef HAVE_MUPARSER
   11685             : static GDALComputedRasterBand ThrowIfNotMuparser()
   11686             : {
   11687             :     throw std::runtime_error("Operator not available on a "
   11688             :                              "GDAL build without muparser");
   11689             : }
   11690             : #endif
   11691             : 
   11692             : /************************************************************************/
   11693             : /*                           operator>()                                */
   11694             : /************************************************************************/
   11695             : 
   11696             : /** Return a band whose value is 1 if the pixel value of the left operand
   11697             :  * is greater than the pixel value of the right operand.
   11698             :  *
   11699             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11700             :  * dataset.
   11701             :  *
   11702             :  * @since 3.12
   11703             :  */
   11704             : GDALComputedRasterBand
   11705           3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
   11706             : {
   11707             : #ifndef HAVE_MUPARSER
   11708             :     (void)other;
   11709             :     return ThrowIfNotMuparser();
   11710             : #else
   11711           3 :     ThrowIfNotSameDimensions(*this, other);
   11712             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   11713           2 :                                   *this, other);
   11714             : #endif
   11715             : }
   11716             : 
   11717             : /************************************************************************/
   11718             : /*                           operator>()                                */
   11719             : /************************************************************************/
   11720             : 
   11721             : /** Return a band whose value is 1 if the pixel value of the left operand
   11722             :  * is greater than the constant.
   11723             :  *
   11724             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11725             :  * dataset.
   11726             :  *
   11727             :  * @since 3.12
   11728             :  */
   11729           3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
   11730             : {
   11731             : #ifndef HAVE_MUPARSER
   11732             :     (void)constant;
   11733             :     return ThrowIfNotMuparser();
   11734             : #else
   11735             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   11736           3 :                                   *this, constant);
   11737             : #endif
   11738             : }
   11739             : 
   11740             : /************************************************************************/
   11741             : /*                           operator>()                                */
   11742             : /************************************************************************/
   11743             : 
   11744             : /** Return a band whose value is 1 if the constant is greater than the pixel
   11745             :  * value of the right operand.
   11746             :  *
   11747             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11748             :  * dataset.
   11749             :  *
   11750             :  * @since 3.12
   11751             :  */
   11752           2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
   11753             : {
   11754             : #ifndef HAVE_MUPARSER
   11755             :     (void)constant;
   11756             :     (void)other;
   11757             :     return ThrowIfNotMuparser();
   11758             : #else
   11759             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   11760           2 :                                   constant, other);
   11761             : #endif
   11762             : }
   11763             : 
   11764             : /************************************************************************/
   11765             : /*                           operator>=()                               */
   11766             : /************************************************************************/
   11767             : 
   11768             : /** Return a band whose value is 1 if the pixel value of the left operand
   11769             :  * is greater or equal to the pixel value of the right operand.
   11770             :  *
   11771             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11772             :  * dataset.
   11773             :  *
   11774             :  * @since 3.12
   11775             :  */
   11776             : GDALComputedRasterBand
   11777           4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
   11778             : {
   11779             : #ifndef HAVE_MUPARSER
   11780             :     (void)other;
   11781             :     return ThrowIfNotMuparser();
   11782             : #else
   11783           4 :     ThrowIfNotSameDimensions(*this, other);
   11784             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   11785           3 :                                   *this, other);
   11786             : #endif
   11787             : }
   11788             : 
   11789             : /************************************************************************/
   11790             : /*                           operator>=()                               */
   11791             : /************************************************************************/
   11792             : 
   11793             : /** Return a band whose value is 1 if the pixel value of the left operand
   11794             :  * is greater or equal to the constant.
   11795             :  *
   11796             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11797             :  * dataset.
   11798             :  *
   11799             :  * @since 3.12
   11800             :  */
   11801           3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
   11802             : {
   11803             : #ifndef HAVE_MUPARSER
   11804             :     (void)constant;
   11805             :     return ThrowIfNotMuparser();
   11806             : #else
   11807             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   11808           3 :                                   *this, constant);
   11809             : #endif
   11810             : }
   11811             : 
   11812             : /************************************************************************/
   11813             : /*                           operator>=()                               */
   11814             : /************************************************************************/
   11815             : 
   11816             : /** Return a band whose value is 1 if the constant is greater or equal to
   11817             :  * the pixel value of the right operand.
   11818             :  *
   11819             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11820             :  * dataset.
   11821             :  *
   11822             :  * @since 3.12
   11823             :  */
   11824           2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
   11825             : {
   11826             : #ifndef HAVE_MUPARSER
   11827             :     (void)constant;
   11828             :     (void)other;
   11829             :     return ThrowIfNotMuparser();
   11830             : #else
   11831             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   11832           2 :                                   constant, other);
   11833             : #endif
   11834             : }
   11835             : 
   11836             : /************************************************************************/
   11837             : /*                           operator<()                                */
   11838             : /************************************************************************/
   11839             : 
   11840             : /** Return a band whose value is 1 if the pixel value of the left operand
   11841             :  * is lesser than the pixel value of the right operand.
   11842             :  *
   11843             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11844             :  * dataset.
   11845             :  *
   11846             :  * @since 3.12
   11847             :  */
   11848             : GDALComputedRasterBand
   11849           3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
   11850             : {
   11851             : #ifndef HAVE_MUPARSER
   11852             :     (void)other;
   11853             :     return ThrowIfNotMuparser();
   11854             : #else
   11855           3 :     ThrowIfNotSameDimensions(*this, other);
   11856             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11857           2 :                                   *this, other);
   11858             : #endif
   11859             : }
   11860             : 
   11861             : /************************************************************************/
   11862             : /*                           operator<()                                */
   11863             : /************************************************************************/
   11864             : 
   11865             : /** Return a band whose value is 1 if the pixel value of the left operand
   11866             :  * is lesser than the constant.
   11867             :  *
   11868             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11869             :  * dataset.
   11870             :  *
   11871             :  * @since 3.12
   11872             :  */
   11873           3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
   11874             : {
   11875             : #ifndef HAVE_MUPARSER
   11876             :     (void)constant;
   11877             :     return ThrowIfNotMuparser();
   11878             : #else
   11879             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11880           3 :                                   *this, constant);
   11881             : #endif
   11882             : }
   11883             : 
   11884             : /************************************************************************/
   11885             : /*                           operator<()                                */
   11886             : /************************************************************************/
   11887             : 
   11888             : /** Return a band whose value is 1 if the constant is lesser than the pixel
   11889             :  * value of the right operand.
   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 operator<(double constant, const GDALRasterBand &other)
   11897             : {
   11898             : #ifndef HAVE_MUPARSER
   11899             :     (void)constant;
   11900             :     (void)other;
   11901             :     return ThrowIfNotMuparser();
   11902             : #else
   11903             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11904           2 :                                   constant, other);
   11905             : #endif
   11906             : }
   11907             : 
   11908             : /************************************************************************/
   11909             : /*                           operator<=()                               */
   11910             : /************************************************************************/
   11911             : 
   11912             : /** Return a band whose value is 1 if the pixel value of the left operand
   11913             :  * is lesser or equal to the pixel value of the right operand.
   11914             :  *
   11915             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11916             :  * dataset.
   11917             :  *
   11918             :  * @since 3.12
   11919             :  */
   11920             : GDALComputedRasterBand
   11921           4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
   11922             : {
   11923             : #ifndef HAVE_MUPARSER
   11924             :     (void)other;
   11925             :     return ThrowIfNotMuparser();
   11926             : #else
   11927           4 :     ThrowIfNotSameDimensions(*this, other);
   11928             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11929           3 :                                   *this, other);
   11930             : #endif
   11931             : }
   11932             : 
   11933             : /************************************************************************/
   11934             : /*                           operator<=()                               */
   11935             : /************************************************************************/
   11936             : 
   11937             : /** Return a band whose value is 1 if the pixel value of the left operand
   11938             :  * is lesser or equal to the constant.
   11939             :  *
   11940             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11941             :  * dataset.
   11942             :  *
   11943             :  * @since 3.12
   11944             :  */
   11945           3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
   11946             : {
   11947             : #ifndef HAVE_MUPARSER
   11948             :     (void)constant;
   11949             :     return ThrowIfNotMuparser();
   11950             : #else
   11951             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11952           3 :                                   *this, constant);
   11953             : #endif
   11954             : }
   11955             : 
   11956             : /************************************************************************/
   11957             : /*                           operator<=()                               */
   11958             : /************************************************************************/
   11959             : 
   11960             : /** Return a band whose value is 1 if the constant is lesser or equal to
   11961             :  * the pixel value of the right operand.
   11962             :  *
   11963             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11964             :  * dataset.
   11965             :  *
   11966             :  * @since 3.12
   11967             :  */
   11968           2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
   11969             : {
   11970             : #ifndef HAVE_MUPARSER
   11971             :     (void)constant;
   11972             :     (void)other;
   11973             :     return ThrowIfNotMuparser();
   11974             : #else
   11975             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11976           2 :                                   constant, other);
   11977             : #endif
   11978             : }
   11979             : 
   11980             : /************************************************************************/
   11981             : /*                           operator==()                               */
   11982             : /************************************************************************/
   11983             : 
   11984             : /** Return a band whose value is 1 if the pixel value of the left operand
   11985             :  * is equal to the pixel value of the right operand.
   11986             :  *
   11987             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11988             :  * dataset.
   11989             :  *
   11990             :  * @since 3.12
   11991             :  */
   11992             : GDALComputedRasterBand
   11993           3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
   11994             : {
   11995             : #ifndef HAVE_MUPARSER
   11996             :     (void)other;
   11997             :     return ThrowIfNotMuparser();
   11998             : #else
   11999           3 :     ThrowIfNotSameDimensions(*this, other);
   12000             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12001           2 :                                   *this, other);
   12002             : #endif
   12003             : }
   12004             : 
   12005             : /************************************************************************/
   12006             : /*                           operator==()                               */
   12007             : /************************************************************************/
   12008             : 
   12009             : /** Return a band whose value is 1 if the pixel value of the left operand
   12010             :  * is equal to the constant.
   12011             :  *
   12012             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12013             :  * dataset.
   12014             :  *
   12015             :  * @since 3.12
   12016             :  */
   12017           8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
   12018             : {
   12019             : #ifndef HAVE_MUPARSER
   12020             :     (void)constant;
   12021             :     return ThrowIfNotMuparser();
   12022             : #else
   12023             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12024           8 :                                   *this, constant);
   12025             : #endif
   12026             : }
   12027             : 
   12028             : /************************************************************************/
   12029             : /*                           operator==()                               */
   12030             : /************************************************************************/
   12031             : 
   12032             : /** Return a band whose value is 1 if the constant is equal to
   12033             :  * the pixel value of the right operand.
   12034             :  *
   12035             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12036             :  * dataset.
   12037             :  *
   12038             :  * @since 3.12
   12039             :  */
   12040           2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
   12041             : {
   12042             : #ifndef HAVE_MUPARSER
   12043             :     (void)constant;
   12044             :     (void)other;
   12045             :     return ThrowIfNotMuparser();
   12046             : #else
   12047             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12048           2 :                                   constant, other);
   12049             : #endif
   12050             : }
   12051             : 
   12052             : /************************************************************************/
   12053             : /*                           operator!=()                               */
   12054             : /************************************************************************/
   12055             : 
   12056             : /** Return a band whose value is 1 if the pixel value of the left operand
   12057             :  * is different from the pixel value of the right operand.
   12058             :  *
   12059             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12060             :  * dataset.
   12061             :  *
   12062             :  * @since 3.12
   12063             :  */
   12064             : GDALComputedRasterBand
   12065           3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
   12066             : {
   12067             : #ifndef HAVE_MUPARSER
   12068             :     (void)other;
   12069             :     return ThrowIfNotMuparser();
   12070             : #else
   12071           3 :     ThrowIfNotSameDimensions(*this, other);
   12072             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12073           2 :                                   *this, other);
   12074             : #endif
   12075             : }
   12076             : 
   12077             : /************************************************************************/
   12078             : /*                           operator!=()                               */
   12079             : /************************************************************************/
   12080             : 
   12081             : /** Return a band whose value is 1 if the pixel value of the left operand
   12082             :  * is different from the constant.
   12083             :  *
   12084             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12085             :  * dataset.
   12086             :  *
   12087             :  * @since 3.12
   12088             :  */
   12089           6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
   12090             : {
   12091             : #ifndef HAVE_MUPARSER
   12092             :     (void)constant;
   12093             :     return ThrowIfNotMuparser();
   12094             : #else
   12095             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12096           6 :                                   *this, constant);
   12097             : #endif
   12098             : }
   12099             : 
   12100             : /************************************************************************/
   12101             : /*                           operator!=()                               */
   12102             : /************************************************************************/
   12103             : 
   12104             : /** Return a band whose value is 1 if the constant is different from
   12105             :  * the pixel value of the right operand.
   12106             :  *
   12107             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12108             :  * dataset.
   12109             :  *
   12110             :  * @since 3.12
   12111             :  */
   12112           2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
   12113             : {
   12114             : #ifndef HAVE_MUPARSER
   12115             :     (void)constant;
   12116             :     (void)other;
   12117             :     return ThrowIfNotMuparser();
   12118             : #else
   12119             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12120           2 :                                   constant, other);
   12121             : #endif
   12122             : }
   12123             : 
   12124             : #if defined(__GNUC__)
   12125             : #pragma GCC diagnostic push
   12126             : #pragma GCC diagnostic ignored "-Weffc++"
   12127             : #endif
   12128             : 
   12129             : /************************************************************************/
   12130             : /*                           operator&&()                               */
   12131             : /************************************************************************/
   12132             : 
   12133             : /** Return a band whose value is 1 if the pixel value of the left and right
   12134             :  * operands is true.
   12135             :  *
   12136             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12137             :  * dataset.
   12138             :  *
   12139             :  * @since 3.12
   12140             :  */
   12141             : GDALComputedRasterBand
   12142           3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
   12143             : {
   12144             : #ifndef HAVE_MUPARSER
   12145             :     (void)other;
   12146             :     return ThrowIfNotMuparser();
   12147             : #else
   12148           3 :     ThrowIfNotSameDimensions(*this, other);
   12149             :     return GDALComputedRasterBand(
   12150           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
   12151             : #endif
   12152             : }
   12153             : 
   12154             : /************************************************************************/
   12155             : /*                           operator&&()                               */
   12156             : /************************************************************************/
   12157             : 
   12158             : /** Return a band whose value is 1 if the pixel value of the left operand
   12159             :  * is true, as well as the constant
   12160             :  *
   12161             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12162             :  * dataset.
   12163             :  *
   12164             :  * @since 3.12
   12165             :  */
   12166           2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
   12167             : {
   12168             : #ifndef HAVE_MUPARSER
   12169             :     (void)constant;
   12170             :     return ThrowIfNotMuparser();
   12171             : #else
   12172             :     return GDALComputedRasterBand(
   12173           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
   12174             : #endif
   12175             : }
   12176             : 
   12177             : /************************************************************************/
   12178             : /*                           operator&&()                               */
   12179             : /************************************************************************/
   12180             : 
   12181             : /** Return a band whose value is 1 if the constant is true, as well as
   12182             :  * the pixel value of the right operand.
   12183             :  *
   12184             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12185             :  * dataset.
   12186             :  *
   12187             :  * @since 3.12
   12188             :  */
   12189           2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
   12190             : {
   12191             : #ifndef HAVE_MUPARSER
   12192             :     (void)constant;
   12193             :     (void)other;
   12194             :     return ThrowIfNotMuparser();
   12195             : #else
   12196             :     return GDALComputedRasterBand(
   12197           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
   12198             : #endif
   12199             : }
   12200             : 
   12201             : /************************************************************************/
   12202             : /*                           operator||()                               */
   12203             : /************************************************************************/
   12204             : 
   12205             : /** Return a band whose value is 1 if the pixel value of the left or right
   12206             :  * operands is true.
   12207             :  *
   12208             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12209             :  * dataset.
   12210             :  *
   12211             :  * @since 3.12
   12212             :  */
   12213             : GDALComputedRasterBand
   12214           4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
   12215             : {
   12216             : #ifndef HAVE_MUPARSER
   12217             :     (void)other;
   12218             :     return ThrowIfNotMuparser();
   12219             : #else
   12220           4 :     ThrowIfNotSameDimensions(*this, other);
   12221             :     return GDALComputedRasterBand(
   12222           3 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
   12223             : #endif
   12224             : }
   12225             : 
   12226             : /************************************************************************/
   12227             : /*                           operator||()                               */
   12228             : /************************************************************************/
   12229             : 
   12230             : /** Return a band whose value is 1 if the pixel value of the left operand
   12231             :  * is true, or if the constant is true
   12232             :  *
   12233             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12234             :  * dataset.
   12235             :  *
   12236             :  * @since 3.12
   12237             :  */
   12238           4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
   12239             : {
   12240             : #ifndef HAVE_MUPARSER
   12241             :     (void)constant;
   12242             :     return ThrowIfNotMuparser();
   12243             : #else
   12244             :     return GDALComputedRasterBand(
   12245           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
   12246             : #endif
   12247             : }
   12248             : 
   12249             : /************************************************************************/
   12250             : /*                           operator||()                               */
   12251             : /************************************************************************/
   12252             : 
   12253             : /** Return a band whose value is 1 if the constant is true, or
   12254             :  * the pixel value of the right operand is true
   12255             :  *
   12256             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12257             :  * dataset.
   12258             :  *
   12259             :  * @since 3.12
   12260             :  */
   12261           4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
   12262             : {
   12263             : #ifndef HAVE_MUPARSER
   12264             :     (void)constant;
   12265             :     (void)other;
   12266             :     return ThrowIfNotMuparser();
   12267             : #else
   12268             :     return GDALComputedRasterBand(
   12269           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
   12270             : #endif
   12271             : }
   12272             : 
   12273             : #if defined(__GNUC__)
   12274             : #pragma GCC diagnostic pop
   12275             : #endif
   12276             : 
   12277             : /************************************************************************/
   12278             : /*                            operator!()                               */
   12279             : /************************************************************************/
   12280             : 
   12281             : /** Return a band whose value is the logical negation of the pixel value
   12282             :  *
   12283             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12284             :  * dataset.
   12285             :  *
   12286             :  * @since 3.12
   12287             :  */
   12288           2 : GDALComputedRasterBand GDALRasterBand::operator!() const
   12289             : {
   12290             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12291           2 :                                   *this, true);
   12292             : }
   12293             : 
   12294             : namespace gdal
   12295             : {
   12296             : 
   12297             : /************************************************************************/
   12298             : /*                           IfThenElse()                               */
   12299             : /************************************************************************/
   12300             : 
   12301             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12302             :  * is not zero, or the one from elseBand otherwise.
   12303             :  *
   12304             :  * Variants of this method exits where thenBand and/or elseBand can be double
   12305             :  * values.
   12306             :  *
   12307             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12308             :  * datasets.
   12309             :  *
   12310             :  * This method is the same as the C function GDALRasterBandIfThenElse()
   12311             :  *
   12312             :  * @since 3.12
   12313             :  */
   12314           5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12315             :                                   const GDALRasterBand &thenBand,
   12316             :                                   const GDALRasterBand &elseBand)
   12317             : {
   12318             : #ifndef HAVE_MUPARSER
   12319             :     (void)condBand;
   12320             :     (void)thenBand;
   12321             :     (void)elseBand;
   12322             :     return ThrowIfNotMuparser();
   12323             : #else
   12324           5 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12325           4 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12326             :     return GDALComputedRasterBand(
   12327             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12328           6 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12329             : #endif
   12330             : }
   12331             : 
   12332             : //! @cond Doxygen_Suppress
   12333             : 
   12334             : /************************************************************************/
   12335             : /*                           IfThenElse()                               */
   12336             : /************************************************************************/
   12337             : 
   12338             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12339             :  * is not zero, or the one from elseBand otherwise.
   12340             :  *
   12341             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12342             :  * datasets.
   12343             :  *
   12344             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12345             :  * with thenBand = (condBand * 0) + thenValue
   12346             :  *
   12347             :  * @since 3.12
   12348             :  */
   12349           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12350             :                                   double thenValue,
   12351             :                                   const GDALRasterBand &elseBand)
   12352             : {
   12353             : #ifndef HAVE_MUPARSER
   12354             :     (void)condBand;
   12355             :     (void)thenValue;
   12356             :     (void)elseBand;
   12357             :     return ThrowIfNotMuparser();
   12358             : #else
   12359           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12360             :     auto thenBand =
   12361           1 :         (condBand * 0)
   12362           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12363           1 :         thenValue;
   12364             :     return GDALComputedRasterBand(
   12365             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12366           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12367             : #endif
   12368             : }
   12369             : 
   12370             : /************************************************************************/
   12371             : /*                           IfThenElse()                               */
   12372             : /************************************************************************/
   12373             : 
   12374             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12375             :  * is not zero, or the one from elseValue otherwise.
   12376             :  *
   12377             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12378             :  * datasets.
   12379             :  *
   12380             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12381             :  * with elseBand = (condBand * 0) + elseValue
   12382             : 
   12383             :  * @since 3.12
   12384             :  */
   12385           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12386             :                                   const GDALRasterBand &thenBand,
   12387             :                                   double elseValue)
   12388             : {
   12389             : #ifndef HAVE_MUPARSER
   12390             :     (void)condBand;
   12391             :     (void)thenBand;
   12392             :     (void)elseValue;
   12393             :     return ThrowIfNotMuparser();
   12394             : #else
   12395           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12396             :     auto elseBand =
   12397           1 :         (condBand * 0)
   12398           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12399           1 :         elseValue;
   12400             :     return GDALComputedRasterBand(
   12401             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12402           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12403             : #endif
   12404             : }
   12405             : 
   12406             : /************************************************************************/
   12407             : /*                           IfThenElse()                               */
   12408             : /************************************************************************/
   12409             : 
   12410             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12411             :  * is not zero, or the one from elseValue otherwise.
   12412             :  *
   12413             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12414             :  * datasets.
   12415             :  *
   12416             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12417             :  * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
   12418             :  *
   12419             :  * @since 3.12
   12420             :  */
   12421           3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12422             :                                   double thenValue, double elseValue)
   12423             : {
   12424             : #ifndef HAVE_MUPARSER
   12425             :     (void)condBand;
   12426             :     (void)thenValue;
   12427             :     (void)elseValue;
   12428             :     return ThrowIfNotMuparser();
   12429             : #else
   12430             :     auto thenBand =
   12431           3 :         (condBand * 0)
   12432           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12433           6 :         thenValue;
   12434             :     auto elseBand =
   12435           3 :         (condBand * 0)
   12436           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12437           3 :         elseValue;
   12438             :     return GDALComputedRasterBand(
   12439             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12440           9 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12441             : #endif
   12442             : }
   12443             : 
   12444             : //! @endcond
   12445             : 
   12446             : }  // namespace gdal
   12447             : 
   12448             : /************************************************************************/
   12449             : /*                     GDALRasterBandIfThenElse()                       */
   12450             : /************************************************************************/
   12451             : 
   12452             : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
   12453             :  * is not zero, or the one from hElseBand otherwise.
   12454             :  *
   12455             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12456             :  * datasets.
   12457             :  *
   12458             :  * This function is the same as the C++ method gdal::IfThenElse()
   12459             :  *
   12460             :  * @since 3.12
   12461             :  */
   12462          12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
   12463             :                                                  GDALRasterBandH hThenBand,
   12464             :                                                  GDALRasterBandH hElseBand)
   12465             : {
   12466          12 :     VALIDATE_POINTER1(hCondBand, __func__, nullptr);
   12467          12 :     VALIDATE_POINTER1(hThenBand, __func__, nullptr);
   12468          12 :     VALIDATE_POINTER1(hElseBand, __func__, nullptr);
   12469             : #ifndef HAVE_MUPARSER
   12470             :     CPLError(CE_Failure, CPLE_NotSupported,
   12471             :              "Band comparison operators not available on a GDAL build without "
   12472             :              "muparser");
   12473             :     return nullptr;
   12474             : #else
   12475             : 
   12476          12 :     auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
   12477          12 :     auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
   12478          12 :     auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
   12479             :     try
   12480             :     {
   12481          12 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12482          11 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12483             :     }
   12484           2 :     catch (const std::exception &e)
   12485             :     {
   12486           2 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   12487           2 :         return nullptr;
   12488             :     }
   12489             :     return new GDALComputedRasterBand(
   12490             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12491          10 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12492             : #endif
   12493             : }
   12494             : 
   12495             : /************************************************************************/
   12496             : /*                       GDALRasterBand::AsType()                       */
   12497             : /************************************************************************/
   12498             : 
   12499             : /** Cast this band to another type.
   12500             :  *
   12501             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12502             :  * dataset.
   12503             :  *
   12504             :  * This method is the same as the C function GDALRasterBandAsDataType()
   12505             :  *
   12506             :  * @since 3.12
   12507             :  */
   12508          10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
   12509             : {
   12510          10 :     if (dt == GDT_Unknown)
   12511             :     {
   12512           1 :         throw std::runtime_error("AsType(GDT_Unknown) is not supported");
   12513             :     }
   12514             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
   12515           9 :                                   *this, dt);
   12516             : }
   12517             : 
   12518             : /************************************************************************/
   12519             : /*                       GDALRasterBandAsDataType()                     */
   12520             : /************************************************************************/
   12521             : 
   12522             : /** Cast this band to another type.
   12523             :  *
   12524             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12525             :  * dataset.
   12526             :  *
   12527             :  * This function is the same as the C++ method GDALRasterBand::AsType()
   12528             :  *
   12529             :  * @since 3.12
   12530             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12531             :  */
   12532          16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
   12533             :                                                  GDALDataType eDT)
   12534             : {
   12535          16 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   12536          16 :     if (eDT == GDT_Unknown)
   12537             :     {
   12538           1 :         CPLError(CE_Failure, CPLE_NotSupported,
   12539             :                  "GDALRasterBandAsDataType(GDT_Unknown) not supported");
   12540           1 :         return nullptr;
   12541             :     }
   12542             :     return new GDALComputedRasterBand(
   12543             :         GDALComputedRasterBand::Operation::OP_CAST,
   12544          15 :         *(GDALRasterBand::FromHandle(hBand)), eDT);
   12545             : }
   12546             : 
   12547             : /************************************************************************/
   12548             : /*                         GetBandVector()                              */
   12549             : /************************************************************************/
   12550             : 
   12551             : static std::vector<const GDALRasterBand *>
   12552          10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
   12553             : {
   12554          10 :     std::vector<const GDALRasterBand *> bands;
   12555          27 :     for (size_t i = 0; i < nBandCount; ++i)
   12556             :     {
   12557          20 :         if (i > 0)
   12558             :         {
   12559          10 :             GDALRasterBand::ThrowIfNotSameDimensions(
   12560          10 :                 *(GDALRasterBand::FromHandle(pahBands[0])),
   12561          10 :                 *(GDALRasterBand::FromHandle(pahBands[i])));
   12562             :         }
   12563          17 :         bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
   12564             :     }
   12565           7 :     return bands;
   12566             : }
   12567             : 
   12568             : /************************************************************************/
   12569             : /*                       GDALOperationOnNBands()                        */
   12570             : /************************************************************************/
   12571             : 
   12572             : static GDALComputedRasterBandH
   12573          11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
   12574             :                       GDALRasterBandH *pahBands)
   12575             : {
   12576          11 :     VALIDATE_POINTER1(pahBands, __func__, nullptr);
   12577          11 :     if (nBandCount == 0)
   12578             :     {
   12579           1 :         CPLError(CE_Failure, CPLE_AppDefined,
   12580             :                  "At least one band should be passed");
   12581           1 :         return nullptr;
   12582             :     }
   12583             : 
   12584          20 :     std::vector<const GDALRasterBand *> bands;
   12585             :     try
   12586             :     {
   12587          10 :         bands = GetBandVector(nBandCount, pahBands);
   12588             :     }
   12589           3 :     catch (const std::exception &e)
   12590             :     {
   12591           3 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   12592           3 :         return nullptr;
   12593             :     }
   12594           7 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
   12595             : }
   12596             : 
   12597             : /************************************************************************/
   12598             : /*                       GDALMaximumOfNBands()                          */
   12599             : /************************************************************************/
   12600             : 
   12601             : /** Return a band whose each pixel value is the maximum of the corresponding
   12602             :  * pixel values in the input bands.
   12603             :  *
   12604             :  * The resulting band is lazy evaluated. A reference is taken on input
   12605             :  * datasets.
   12606             :  *
   12607             :  * This function is the same as the C ++ method gdal::max()
   12608             :  *
   12609             :  * @since 3.12
   12610             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12611             :  */
   12612           4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
   12613             :                                             GDALRasterBandH *pahBands)
   12614             : {
   12615           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
   12616           4 :                                  nBandCount, pahBands);
   12617             : }
   12618             : 
   12619             : /************************************************************************/
   12620             : /*                               gdal::max()                            */
   12621             : /************************************************************************/
   12622             : 
   12623             : namespace gdal
   12624             : {
   12625             : /** Return a band whose each pixel value is the maximum of the corresponding
   12626             :  * pixel values in the inputs (bands or constants)
   12627             :  *
   12628             :  * The resulting band is lazy evaluated. A reference is taken on input
   12629             :  * datasets.
   12630             :  *
   12631             :  * Two or more bands can be passed.
   12632             :  *
   12633             :  * This method is the same as the C function GDALMaximumOfNBands()
   12634             :  *
   12635             :  * @since 3.12
   12636             :  * @throw std::runtime_error if bands do not have the same dimensions.
   12637             :  */
   12638           1 : GDALComputedRasterBand max(const GDALRasterBand &first,
   12639             :                            const GDALRasterBand &second)
   12640             : {
   12641           1 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   12642             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
   12643           1 :                                   first, second);
   12644             : }
   12645             : }  // namespace gdal
   12646             : 
   12647             : /************************************************************************/
   12648             : /*                     GDALRasterBandMaxConstant()                      */
   12649             : /************************************************************************/
   12650             : 
   12651             : /** Return a band whose each pixel value is the maximum of the corresponding
   12652             :  * pixel values in the input band and the constant.
   12653             :  *
   12654             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12655             :  * dataset.
   12656             :  *
   12657             :  * This function is the same as the C ++ method gdal::max()
   12658             :  *
   12659             :  * @since 3.12
   12660             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12661             :  */
   12662           2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
   12663             :                                                   double dfConstant)
   12664             : {
   12665           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   12666             :         GDALComputedRasterBand::Operation::OP_MAX,
   12667           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   12668           6 :         dfConstant));
   12669             : }
   12670             : 
   12671             : /************************************************************************/
   12672             : /*                       GDALMinimumOfNBands()                          */
   12673             : /************************************************************************/
   12674             : 
   12675             : /** Return a band whose each pixel value is the minimum of the corresponding
   12676             :  * pixel values in the input bands.
   12677             :  *
   12678             :  * The resulting band is lazy evaluated. A reference is taken on input
   12679             :  * datasets.
   12680             :  *
   12681             :  * This function is the same as the C ++ method gdal::min()
   12682             :  *
   12683             :  * @since 3.12
   12684             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12685             :  */
   12686           4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
   12687             :                                             GDALRasterBandH *pahBands)
   12688             : {
   12689           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
   12690           4 :                                  nBandCount, pahBands);
   12691             : }
   12692             : 
   12693             : /************************************************************************/
   12694             : /*                               gdal::min()                            */
   12695             : /************************************************************************/
   12696             : 
   12697             : namespace gdal
   12698             : {
   12699             : /** Return a band whose each pixel value is the minimum of the corresponding
   12700             :  * pixel values in the inputs (bands or constants)
   12701             :  *
   12702             :  * The resulting band is lazy evaluated. A reference is taken on input
   12703             :  * datasets.
   12704             :  *
   12705             :  * Two or more bands can be passed.
   12706             :  *
   12707             :  * This method is the same as the C function GDALMinimumOfNBands()
   12708             :  *
   12709             :  * @since 3.12
   12710             :  * @throw std::runtime_error if bands do not have the same dimensions.
   12711             :  */
   12712           0 : GDALComputedRasterBand min(const GDALRasterBand &first,
   12713             :                            const GDALRasterBand &second)
   12714             : {
   12715           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   12716             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
   12717           0 :                                   first, second);
   12718             : }
   12719             : }  // namespace gdal
   12720             : 
   12721             : /************************************************************************/
   12722             : /*                     GDALRasterBandMinConstant()                      */
   12723             : /************************************************************************/
   12724             : 
   12725             : /** Return a band whose each pixel value is the minimum of the corresponding
   12726             :  * pixel values in the input band and the constant.
   12727             :  *
   12728             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12729             :  * dataset.
   12730             :  *
   12731             :  * This function is the same as the C ++ method gdal::min()
   12732             :  *
   12733             :  * @since 3.12
   12734             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12735             :  */
   12736           2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
   12737             :                                                   double dfConstant)
   12738             : {
   12739           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   12740             :         GDALComputedRasterBand::Operation::OP_MIN,
   12741           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   12742           6 :         dfConstant));
   12743             : }
   12744             : 
   12745             : /************************************************************************/
   12746             : /*                         GDALMeanOfNBands()                           */
   12747             : /************************************************************************/
   12748             : 
   12749             : /** Return a band whose each pixel value is the arithmetic mean of the
   12750             :  * corresponding pixel values in the input bands.
   12751             :  *
   12752             :  * The resulting band is lazy evaluated. A reference is taken on input
   12753             :  * datasets.
   12754             :  *
   12755             :  * This function is the same as the C ++ method gdal::mean()
   12756             :  *
   12757             :  * @since 3.12
   12758             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   12759             :  */
   12760           3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
   12761             :                                          GDALRasterBandH *pahBands)
   12762             : {
   12763           3 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
   12764           3 :                                  nBandCount, pahBands);
   12765             : }
   12766             : 
   12767             : /************************************************************************/
   12768             : /*                              gdal::mean()                            */
   12769             : /************************************************************************/
   12770             : 
   12771             : namespace gdal
   12772             : {
   12773             : 
   12774             : /** Return a band whose each pixel value is the arithmetic mean of the
   12775             :  * corresponding pixel values in the input bands.
   12776             :  *
   12777             :  * The resulting band is lazy evaluated. A reference is taken on input
   12778             :  * datasets.
   12779             :  *
   12780             :  * Two or more bands can be passed.
   12781             :  *
   12782             :  * This method is the same as the C function GDALMeanOfNBands()
   12783             :  *
   12784             :  * @since 3.12
   12785             :  * @throw std::runtime_error if bands do not have the same dimensions.
   12786             :  */
   12787           0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
   12788             :                             const GDALRasterBand &second)
   12789             : {
   12790           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   12791             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
   12792           0 :                                   first, second);
   12793             : }
   12794             : }  // namespace gdal
   12795             : 
   12796             : /************************************************************************/
   12797             : /*                              gdal::abs()                             */
   12798             : /************************************************************************/
   12799             : 
   12800             : namespace gdal
   12801             : {
   12802             : 
   12803             : /** Return a band whose each pixel value is the absolute value (or module
   12804             :  * for complex data type) of the corresponding pixel value in the input band.
   12805             :  *
   12806             :  * The resulting band is lazy evaluated. A reference is taken on input
   12807             :  * datasets.
   12808             :  *
   12809             :  * @since 3.12
   12810             :  */
   12811           1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
   12812             : {
   12813             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   12814           1 :                                   band);
   12815             : }
   12816             : }  // namespace gdal
   12817             : 
   12818             : /************************************************************************/
   12819             : /*                             gdal::fabs()                             */
   12820             : /************************************************************************/
   12821             : 
   12822             : namespace gdal
   12823             : {
   12824             : 
   12825             : /** Return a band whose each pixel value is the absolute value (or module
   12826             :  * for complex data type) of the corresponding pixel value in the input band.
   12827             :  *
   12828             :  * The resulting band is lazy evaluated. A reference is taken on input
   12829             :  * datasets.
   12830             :  *
   12831             :  * @since 3.12
   12832             :  */
   12833           1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
   12834             : {
   12835             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   12836           1 :                                   band);
   12837             : }
   12838             : }  // namespace gdal
   12839             : 
   12840             : /************************************************************************/
   12841             : /*                             gdal::sqrt()                             */
   12842             : /************************************************************************/
   12843             : 
   12844             : namespace gdal
   12845             : {
   12846             : 
   12847             : /** Return a band whose each pixel value is the square root of the
   12848             :  * corresponding pixel value in the input band.
   12849             :  *
   12850             :  * The resulting band is lazy evaluated. A reference is taken on input
   12851             :  * datasets.
   12852             :  *
   12853             :  * @since 3.12
   12854             :  */
   12855           1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
   12856             : {
   12857             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
   12858           1 :                                   band);
   12859             : }
   12860             : }  // namespace gdal
   12861             : 
   12862             : /************************************************************************/
   12863             : /*                             gdal::log()                              */
   12864             : /************************************************************************/
   12865             : 
   12866             : namespace gdal
   12867             : {
   12868             : 
   12869             : /** Return a band whose each pixel value is the natural logarithm of the
   12870             :  * corresponding pixel value in the input band.
   12871             :  *
   12872             :  * The resulting band is lazy evaluated. A reference is taken on input
   12873             :  * datasets.
   12874             :  *
   12875             :  * @since 3.12
   12876             :  */
   12877           1 : GDALComputedRasterBand log(const GDALRasterBand &band)
   12878             : {
   12879             : #ifndef HAVE_MUPARSER
   12880             :     (void)band;
   12881             :     return ThrowIfNotMuparser();
   12882             : #else
   12883             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
   12884           1 :                                   band);
   12885             : #endif
   12886             : }
   12887             : }  // namespace gdal
   12888             : 
   12889             : /************************************************************************/
   12890             : /*                             gdal::log10()                            */
   12891             : /************************************************************************/
   12892             : 
   12893             : namespace gdal
   12894             : {
   12895             : 
   12896             : /** Return a band whose each pixel value is the logarithm base 10 of the
   12897             :  * corresponding pixel value in the input band.
   12898             :  *
   12899             :  * The resulting band is lazy evaluated. A reference is taken on input
   12900             :  * datasets.
   12901             :  *
   12902             :  * @since 3.12
   12903             :  */
   12904           1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
   12905             : {
   12906             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
   12907           1 :                                   band);
   12908             : }
   12909             : }  // namespace gdal
   12910             : 
   12911             : /************************************************************************/
   12912             : /*                             gdal::pow()                              */
   12913             : /************************************************************************/
   12914             : 
   12915             : namespace gdal
   12916             : {
   12917             : 
   12918             : #ifndef DOXYGEN_SKIP
   12919             : /** Return a band whose each pixel value is the constant raised to the power of
   12920             :  * the corresponding pixel value in the input band.
   12921             :  *
   12922             :  * The resulting band is lazy evaluated. A reference is taken on input
   12923             :  * datasets.
   12924             :  *
   12925             :  * @since 3.12
   12926             :  */
   12927           1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
   12928             : {
   12929             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12930           1 :                                   constant, band);
   12931             : }
   12932             : #endif
   12933             : 
   12934             : }  // namespace gdal
   12935             : 
   12936             : /************************************************************************/
   12937             : /*                             gdal::pow()                              */
   12938             : /************************************************************************/
   12939             : 
   12940             : namespace gdal
   12941             : {
   12942             : 
   12943             : /** Return a band whose each pixel value is the the corresponding pixel value
   12944             :  * in the input band raised to the power of the constant.
   12945             :  *
   12946             :  * The resulting band is lazy evaluated. A reference is taken on input
   12947             :  * datasets.
   12948             :  *
   12949             :  * @since 3.12
   12950             :  */
   12951           1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
   12952             : {
   12953             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12954           1 :                                   band, constant);
   12955             : }
   12956             : }  // namespace gdal
   12957             : 
   12958             : /************************************************************************/
   12959             : /*                             gdal::pow()                              */
   12960             : /************************************************************************/
   12961             : 
   12962             : namespace gdal
   12963             : {
   12964             : 
   12965             : #ifndef DOXYGEN_SKIP
   12966             : /** Return a band whose each pixel value is the the corresponding pixel value
   12967             :  * in the input band1 raised to the power of the corresponding pixel value
   12968             :  * in the input band2
   12969             :  *
   12970             :  * The resulting band is lazy evaluated. A reference is taken on input
   12971             :  * datasets.
   12972             :  *
   12973             :  * @since 3.12
   12974             :  * @throw std::runtime_error if bands do not have the same dimensions.
   12975             :  */
   12976           2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
   12977             :                            const GDALRasterBand &band2)
   12978             : {
   12979             : #ifndef HAVE_MUPARSER
   12980             :     (void)band1;
   12981             :     (void)band2;
   12982             :     return ThrowIfNotMuparser();
   12983             : #else
   12984           2 :     GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
   12985             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12986           1 :                                   band1, band2);
   12987             : #endif
   12988             : }
   12989             : #endif
   12990             : }  // namespace gdal

Generated by: LCOV version 1.14