LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3424 4136 82.8 %
Date: 2026-04-02 20:31:41 Functions: 320 353 90.7 %

          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 <algorithm>
      19             : #include <cassert>
      20             : #include <climits>
      21             : #include <cmath>
      22             : #include <cstdarg>
      23             : #include <cstddef>
      24             : #include <cstdio>
      25             : #include <cstdlib>
      26             : #include <cstring>
      27             : #include <limits>
      28             : #include <memory>
      29             : #include <new>
      30             : #include <numeric>  // std::lcm
      31             : #include <type_traits>
      32             : 
      33             : #include "cpl_conv.h"
      34             : #include "cpl_error.h"
      35             : #include "cpl_float.h"
      36             : #include "cpl_multiproc.h"
      37             : #include "cpl_progress.h"
      38             : #include "cpl_string.h"
      39             : #include "cpl_virtualmem.h"
      40             : #include "cpl_vsi.h"
      41             : #include "cpl_worker_thread_pool.h"
      42             : #include "gdal.h"
      43             : #include "gdal_abstractbandblockcache.h"
      44             : #include "gdalantirecursion.h"
      45             : #include "gdal_rat.h"
      46             : #include "gdal_rasterband.h"
      47             : #include "gdal_priv_templates.hpp"
      48             : #include "gdal_interpolateatpoint.h"
      49             : #include "gdal_minmax_element.hpp"
      50             : #include "gdalmultidim_priv.h"
      51             : #include "gdal_thread_pool.h"
      52             : 
      53             : #ifdef USE_NEON_OPTIMIZATIONS
      54             : #include "include_sse2neon.h"
      55             : #endif
      56             : 
      57             : #if defined(__AVX2__) || defined(__FMA__)
      58             : #include <immintrin.h>
      59             : #endif
      60             : 
      61             : /************************************************************************/
      62             : /*                           GDALRasterBand()                           */
      63             : /************************************************************************/
      64             : 
      65             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      66             : 
      67     1578780 : GDALRasterBand::GDALRasterBand()
      68             :     : GDALRasterBand(
      69     1578780 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      70             : {
      71     1578780 : }
      72             : 
      73             : /** Constructor. Applications should never create GDALRasterBands directly.
      74             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      75             :  */
      76     1870890 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      77     1870890 :     : bForceCachedIO(bForceCachedIOIn)
      78             : 
      79             : {
      80     1870890 : }
      81             : 
      82             : /************************************************************************/
      83             : /*                          ~GDALRasterBand()                           */
      84             : /************************************************************************/
      85             : 
      86             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      87             :     instead destroy the GDALDataset. */
      88             : 
      89     1870890 : GDALRasterBand::~GDALRasterBand()
      90             : 
      91             : {
      92     1870890 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      93             :     {
      94         593 :         if (poBandBlockCache)
      95         530 :             poBandBlockCache->DisableDirtyBlockWriting();
      96             :     }
      97     1870890 :     GDALRasterBand::FlushCache(true);
      98             : 
      99     1870890 :     delete poBandBlockCache;
     100             : 
     101     1870890 :     if (static_cast<GIntBig>(nBlockReads) >
     102     1870890 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
     103         244 :         nBand == 1 && poDS != nullptr)
     104             :     {
     105         350 :         CPLDebug(
     106             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
     107         175 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
     108         175 :             poDS->GetDescription());
     109             :     }
     110             : 
     111     1870890 :     InvalidateMaskBand();
     112     1870890 :     nBand = -nBand;
     113             : 
     114     1870890 :     delete m_poPointsCache;
     115     1870890 : }
     116             : 
     117             : /************************************************************************/
     118             : /*                              RasterIO()                              */
     119             : /************************************************************************/
     120             : 
     121             : /**
     122             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     123             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     124             :  *                                void * pData, int nBufXSize, int nBufYSize,
     125             :  *                                GDALDataType eBufType,
     126             :  *                                GSpacing nPixelSpace,
     127             :  *                                GSpacing nLineSpace,
     128             :  *                                GDALRasterIOExtraArg* psExtraArg )
     129             :  * \brief Read/write a region of image data for this band.
     130             :  *
     131             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     132             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     133             :  * automatically takes care of data type translation if the data type
     134             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     135             :  * The method also takes care of image decimation / replication if the
     136             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     137             :  * region being accessed (nXSize x nYSize).
     138             :  *
     139             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     140             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     141             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     142             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     143             :  * Or use nLineSpace and a possibly shifted pData value.
     144             :  *
     145             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     146             :  * writing from unusually organized buffers. This is primarily used
     147             :  * for buffers containing more than one bands raster data in interleaved
     148             :  * format.
     149             :  *
     150             :  * Some formats may efficiently implement decimation into a buffer by
     151             :  * reading from lower resolution overview images. The logic of the default
     152             :  * implementation in the base class GDALRasterBand is the following one. It
     153             :  * computes a target_downscaling_factor from the window of interest and buffer
     154             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     155             :  * It then walks through overviews and will select the first one whose
     156             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     157             :  *
     158             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     159             :  * The relationship between target_downscaling_factor and the select overview
     160             :  * level is the following one:
     161             :  *
     162             :  * target_downscaling_factor  | selected_overview
     163             :  * -------------------------  | -----------------
     164             :  * ]0,       2 / 1.2]         | full resolution band
     165             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     166             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     167             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     168             :  *
     169             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     170             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     171             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     172             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     173             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     174             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     175             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     176             :  *
     177             :  * For highest performance full resolution data access, read and write
     178             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     179             :  * ReadBlock() and WriteBlock() methods.
     180             :  *
     181             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     182             :  * functions.
     183             :  *
     184             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     185             :  * write a region of data.
     186             :  *
     187             :  * @param nXOff The pixel offset to the top left corner of the region
     188             :  * of the band to be accessed. This would be zero to start from the left side.
     189             :  *
     190             :  * @param nYOff The line offset to the top left corner of the region
     191             :  * of the band to be accessed. This would be zero to start from the top.
     192             :  *
     193             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     194             :  *
     195             :  * @param nYSize The height of the region of the band to be accessed in lines.
     196             :  *
     197             :  * @param pData The buffer into which the data should be read, or from which
     198             :  * it should be written. This buffer must contain at least nBufXSize *
     199             :  * nBufYSize words of type eBufType. It is organized in left to right,
     200             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     201             :  * and nLineSpace parameters.
     202             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     203             :  * temporarily modified during the execution of this method (and eventually
     204             :  * restored back to its original content), so it is not safe to use a buffer
     205             :  * stored in a read-only section of the calling program.
     206             :  *
     207             :  * @param nBufXSize the width of the buffer image into which the desired region
     208             :  * is to be read, or from which it is to be written.
     209             :  *
     210             :  * @param nBufYSize the height of the buffer image into which the desired region
     211             :  * is to be read, or from which it is to be written.
     212             :  *
     213             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     214             :  * pixel values will automatically be translated to/from the GDALRasterBand
     215             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     216             :  * to perform data type translation.
     217             :  *
     218             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     219             :  * pData to the start of the next pixel value within a scanline. If defaulted
     220             :  * (0) the size of the datatype eBufType is used.
     221             :  *
     222             :  * @param nLineSpace The byte offset from the start of one scanline in
     223             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     224             :  * eBufType * nBufXSize is used.
     225             :  *
     226             :  * @param psExtraArg Pointer to a GDALRasterIOExtraArg
     227             :  * structure with additional arguments to specify resampling and progress
     228             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     229             :  * configuration option can also be defined to override the default resampling
     230             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     231             :  *
     232             :  * @return CE_Failure if the access fails, otherwise CE_None.
     233             :  */
     234             : 
     235             : /**
     236             :  * \brief Read/write a region of image data for this band.
     237             :  *
     238             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     239             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     240             :  * automatically takes care of data type translation if the data type
     241             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     242             :  * The method also takes care of image decimation / replication if the
     243             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     244             :  * region being accessed (nXSize x nYSize).
     245             :  *
     246             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     247             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     248             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     249             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     250             :  * Or use nLineSpace and a possibly shifted pData value.
     251             :  *
     252             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     253             :  * writing from unusually organized buffers. This is primarily used
     254             :  * for buffers containing more than one bands raster data in interleaved
     255             :  * format.
     256             :  *
     257             :  * Some formats may efficiently implement decimation into a buffer by
     258             :  * reading from lower resolution overview images. The logic of the default
     259             :  * implementation in the base class GDALRasterBand is the following one. It
     260             :  * computes a target_downscaling_factor from the window of interest and buffer
     261             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     262             :  * It then walks through overviews and will select the first one whose
     263             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     264             :  *
     265             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     266             :  * The relationship between target_downscaling_factor and the select overview
     267             :  * level is the following one:
     268             :  *
     269             :  * target_downscaling_factor  | selected_overview
     270             :  * -------------------------  | -----------------
     271             :  * ]0,       2 / 1.2]         | full resolution band
     272             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     273             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     274             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     275             :  *
     276             :  * For highest performance full resolution data access, read and write
     277             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     278             :  * ReadBlock() and WriteBlock() methods.
     279             :  *
     280             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     281             :  * functions.
     282             :  *
     283             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     284             :  * more convenient to use for most common use cases.
     285             :  *
     286             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     287             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     288             :  * instance of this dataset) concurrently from several threads.
     289             :  *
     290             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     291             :  * write a region of data.
     292             :  *
     293             :  * @param nXOff The pixel offset to the top left corner of the region
     294             :  * of the band to be accessed. This would be zero to start from the left side.
     295             :  *
     296             :  * @param nYOff The line offset to the top left corner of the region
     297             :  * of the band to be accessed. This would be zero to start from the top.
     298             :  *
     299             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     300             :  *
     301             :  * @param nYSize The height of the region of the band to be accessed in lines.
     302             :  *
     303             :  * @param[in,out] pData The buffer into which the data should be read, or from
     304             :  * which it should be written. This buffer must contain at least nBufXSize *
     305             :  * nBufYSize words of type eBufType. It is organized in left to right,
     306             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     307             :  * and nLineSpace parameters.
     308             :  *
     309             :  * @param nBufXSize the width of the buffer image into which the desired region
     310             :  * is to be read, or from which it is to be written.
     311             :  *
     312             :  * @param nBufYSize the height of the buffer image into which the desired region
     313             :  * is to be read, or from which it is to be written.
     314             :  *
     315             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     316             :  * pixel values will automatically be translated to/from the GDALRasterBand
     317             :  * data type as needed.
     318             :  *
     319             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     320             :  * pData to the start of the next pixel value within a scanline. If defaulted
     321             :  * (0) the size of the datatype eBufType is used.
     322             :  *
     323             :  * @param nLineSpace The byte offset from the start of one scanline in
     324             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     325             :  * eBufType * nBufXSize is used.
     326             :  *
     327             :  * @param[in] psExtraArg Pointer to a GDALRasterIOExtraArg
     328             :  * structure with additional arguments to specify resampling and progress
     329             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     330             :  * configuration option can also be defined to override the default resampling
     331             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     332             :  *
     333             :  * @return CE_Failure if the access fails, otherwise CE_None.
     334             :  *
     335             :  * @see GDALRasterBand::ReadRaster()
     336             :  */
     337             : 
     338     4644420 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     339             :                                 int nXSize, int nYSize, void *pData,
     340             :                                 int nBufXSize, int nBufYSize,
     341             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     342             :                                 GSpacing nLineSpace,
     343             :                                 GDALRasterIOExtraArg *psExtraArg)
     344             : 
     345             : {
     346             :     GDALRasterIOExtraArg sExtraArg;
     347     4644420 :     if (psExtraArg == nullptr)
     348             :     {
     349     4038060 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     350     4038060 :         psExtraArg = &sExtraArg;
     351             :     }
     352      606355 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
     353             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     354             :     {
     355           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     356             :                     "Unhandled version of GDALRasterIOExtraArg");
     357           0 :         return CE_Failure;
     358             :     }
     359             : 
     360     4644420 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     361             :                                        nBufYSize);
     362             : 
     363     4644420 :     if (CPL_UNLIKELY(nullptr == pData))
     364             :     {
     365           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     366             :                     "The buffer into which the data should be read is null");
     367           0 :         return CE_Failure;
     368             :     }
     369             : 
     370             :     /* -------------------------------------------------------------------- */
     371             :     /*      Some size values are "noop".  Lets just return to avoid         */
     372             :     /*      stressing lower level functions.                                */
     373             :     /* -------------------------------------------------------------------- */
     374     4644420 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     375             :                      nBufYSize < 1))
     376             :     {
     377           2 :         CPLDebug("GDAL",
     378             :                  "RasterIO() skipped for odd window or buffer size.\n"
     379             :                  "  Window = (%d,%d)x%dx%d\n"
     380             :                  "  Buffer = %dx%d\n",
     381             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     382             : 
     383           2 :         return CE_None;
     384             :     }
     385             : 
     386     4644420 :     if (eRWFlag == GF_Write)
     387             :     {
     388      407880 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     389             :         {
     390           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     391             :                         "An error occurred while writing a dirty block "
     392             :                         "from GDALRasterBand::RasterIO");
     393           0 :             CPLErr eErr = eFlushBlockErr;
     394           0 :             eFlushBlockErr = CE_None;
     395           0 :             return eErr;
     396             :         }
     397      407880 :         if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
     398             :         {
     399           7 :             return CE_Failure;
     400             :         }
     401             :     }
     402             : 
     403             :     /* -------------------------------------------------------------------- */
     404             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     405             :     /*      value assuming a packed buffer.                                 */
     406             :     /* -------------------------------------------------------------------- */
     407     4644410 :     if (nPixelSpace == 0)
     408             :     {
     409     4236020 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     410             :     }
     411             : 
     412     4644410 :     if (nLineSpace == 0)
     413             :     {
     414     4223640 :         nLineSpace = nPixelSpace * nBufXSize;
     415             :     }
     416             : 
     417             :     /* -------------------------------------------------------------------- */
     418             :     /*      Do some validation of parameters.                               */
     419             :     /* -------------------------------------------------------------------- */
     420     4644410 :     if (CPL_UNLIKELY(nXOff < 0 || nXSize > nRasterXSize - nXOff || nYOff < 0 ||
     421             :                      nYSize > nRasterYSize - nYOff))
     422             :     {
     423          15 :         ReportError(CE_Failure, CPLE_IllegalArg,
     424             :                     "Access window out of range in RasterIO().  Requested\n"
     425             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     426             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     427          15 :         return CE_Failure;
     428             :     }
     429             : 
     430     4644400 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     431             :     {
     432           0 :         ReportError(
     433             :             CE_Failure, CPLE_IllegalArg,
     434             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     435             :             eRWFlag);
     436           0 :         return CE_Failure;
     437             :     }
     438     4644400 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     439             :     {
     440           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     441             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     442           2 :         return CE_Failure;
     443             :     }
     444             : 
     445     4644390 :     return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     446             :                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
     447     4644390 :                             nLineSpace, psExtraArg);
     448             : }
     449             : 
     450             : /************************************************************************/
     451             : /*                          RasterIOInternal()                          */
     452             : /************************************************************************/
     453             : 
     454     4644500 : CPLErr GDALRasterBand::RasterIOInternal(
     455             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     456             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     457             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     458             : {
     459             :     /* -------------------------------------------------------------------- */
     460             :     /*      Call the format specific function.                              */
     461             :     /* -------------------------------------------------------------------- */
     462             : 
     463     4644500 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     464             : 
     465             :     CPLErr eErr;
     466     4644500 :     if (bForceCachedIO)
     467          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     468             :                                          pData, nBufXSize, nBufYSize, eBufType,
     469             :                                          nPixelSpace, nLineSpace, psExtraArg);
     470             :     else
     471             :         eErr =
     472     4644470 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     473     4644470 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     474             : 
     475     4644500 :     if (bCallLeaveReadWrite)
     476      612647 :         LeaveReadWrite();
     477             : 
     478     4644500 :     return eErr;
     479             : }
     480             : 
     481             : /************************************************************************/
     482             : /*                            GDALRasterIO()                            */
     483             : /************************************************************************/
     484             : 
     485             : /**
     486             :  * \brief Read/write a region of image data for this band.
     487             :  *
     488             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     489             :  * resolution, progress callback, etc. are needed)
     490             :  *
     491             :  * @see GDALRasterBand::RasterIO()
     492             :  */
     493             : 
     494     3589480 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     495             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     496             :                                 void *pData, int nBufXSize, int nBufYSize,
     497             :                                 GDALDataType eBufType, int nPixelSpace,
     498             :                                 int nLineSpace)
     499             : 
     500             : {
     501     3589480 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     502             : 
     503     3589480 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     504             : 
     505     3589480 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     506             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     507     3589480 :                              nLineSpace, nullptr));
     508             : }
     509             : 
     510             : /************************************************************************/
     511             : /*                           GDALRasterIOEx()                           */
     512             : /************************************************************************/
     513             : 
     514             : /**
     515             :  * \brief Read/write a region of image data for this band.
     516             :  *
     517             :  * @see GDALRasterBand::RasterIO()
     518             :  */
     519             : 
     520       42501 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     521             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     522             :                                   void *pData, int nBufXSize, int nBufYSize,
     523             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     524             :                                   GSpacing nLineSpace,
     525             :                                   GDALRasterIOExtraArg *psExtraArg)
     526             : 
     527             : {
     528       42501 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     529             : 
     530       42501 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     531             : 
     532       42501 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     533             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     534       42501 :                              nLineSpace, psExtraArg));
     535             : }
     536             : 
     537             : /************************************************************************/
     538             : /*                         GetGDTFromCppType()                          */
     539             : /************************************************************************/
     540             : 
     541             : namespace
     542             : {
     543             : template <class T> struct GetGDTFromCppType;
     544             : 
     545             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     546             :     template <> struct GetGDTFromCppType<T>                                    \
     547             :     {                                                                          \
     548             :         static constexpr GDALDataType GDT = eDT;                               \
     549             :     }
     550             : 
     551             : DEFINE_GetGDTFromCppType(uint8_t, GDT_UInt8);
     552             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     553             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     554             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     555             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     556             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     557             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     558             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     559             : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
     560             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     561             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     562             : // Not allowed by C++ standard
     563             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     564             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     565             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     566             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     567             : }  // namespace
     568             : 
     569             : /************************************************************************/
     570             : /*                             ReadRaster()                             */
     571             : /************************************************************************/
     572             : 
     573             : // clang-format off
     574             : /** Read a region of image data for this band.
     575             :  *
     576             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     577             :  * for common use cases, like reading a whole band.
     578             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     579             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     580             :  * float, double, std::complex<float|double>.
     581             :  *
     582             :  * 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>&,
     583             :  * and can allocate memory automatically.
     584             :  *
     585             :  * To read a whole band (assuming it fits into memory), as an array of double:
     586             :  *
     587             : \code{.cpp}
     588             :  double* myArray = static_cast<double*>(
     589             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     590             :  // TODO: check here that myArray != nullptr
     591             :  const size_t nArrayEltCount =
     592             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     593             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     594             :  {
     595             :      // do something
     596             :  }
     597             :  VSIFree(myArray)
     598             : \endcode
     599             :  *
     600             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     601             :  *
     602             : \code{.cpp}
     603             :  double* myArray = static_cast<double*>(
     604             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     605             :  // TODO: check here that myArray != nullptr
     606             :  const size_t nArrayEltCount = 128 * 128;
     607             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     608             :  {
     609             :      // do something
     610             :  }
     611             :  VSIFree(myArray)
     612             : \endcode
     613             :  *
     614             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     615             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     616             :  * instance of this dataset) concurrently from several threads.
     617             :  *
     618             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     619             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     620             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     621             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     622             :  * Or use nLineSpace and a possibly shifted pData value.
     623             :  *
     624             :  * @param[out] pData The buffer into which the data should be written.
     625             :  * This buffer must contain at least nBufXSize *
     626             :  * nBufYSize words of type T. It is organized in left to right,
     627             :  * top to bottom pixel order, and fully packed.
     628             :  * The type of the buffer does not need to be the one of GetDataType(). The
     629             :  * method will perform data type translation (with potential rounding, clamping)
     630             :  * if needed.
     631             :  *
     632             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     633             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     634             :  * return in error if it is not. If set to zero, then pData is trusted to be
     635             :  * large enough.
     636             :  *
     637             :  * @param dfXOff The pixel offset to the top left corner of the region
     638             :  * of the band to be accessed. This would be zero to start from the left side.
     639             :  * Defaults to 0.
     640             :  *
     641             :  * @param dfYOff The line offset to the top left corner of the region
     642             :  * of the band to be accessed. This would be zero to start from the top.
     643             :  * Defaults to 0.
     644             :  *
     645             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     646             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     647             :  * dfXSize is set to the band width.
     648             :  *
     649             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     650             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     651             :  * dfYSize is set to the band height.
     652             :  *
     653             :  * @param nBufXSize the width of the buffer image into which the desired region
     654             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     655             :  * then nBufXSize is initialized with dfXSize.
     656             :  *
     657             :  * @param nBufYSize the height of the buffer image into which the desired region
     658             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     659             :  * then nBufYSize is initialized with dfYSize.
     660             :  *
     661             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     662             :  *
     663             :  * @param pfnProgress Progress function. May be nullptr.
     664             :  *
     665             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     666             :  *
     667             :  * @return CE_Failure if the access fails, otherwise CE_None.
     668             :  *
     669             :  * @see GDALRasterBand::RasterIO()
     670             :  * @since GDAL 3.10
     671             :  */
     672             : // clang-format on
     673             : 
     674             : template <class T>
     675          20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     676             :                                   double dfXOff, double dfYOff, double dfXSize,
     677             :                                   double dfYSize, size_t nBufXSize,
     678             :                                   size_t nBufYSize,
     679             :                                   GDALRIOResampleAlg eResampleAlg,
     680             :                                   GDALProgressFunc pfnProgress,
     681             :                                   void *pProgressData) const
     682             : {
     683          20 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     684             :     {
     685           2 :         return CE_Failure;
     686             :     }
     687             : 
     688          18 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     689             :     {
     690          16 :         dfXSize = nRasterXSize;
     691          16 :         dfYSize = nRasterYSize;
     692             :     }
     693           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     694           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     695           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     696           2 :              dfYOff + dfYSize > INT_MAX)
     697             :     {
     698           0 :         return CE_Failure;
     699             :     }
     700             : 
     701             :     GDALRasterIOExtraArg sExtraArg;
     702          18 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     703          18 :     CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
     704          18 :     CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
     705          18 :     CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
     706          18 :     CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
     707          18 :     sExtraArg.eResampleAlg = eResampleAlg;
     708          18 :     sExtraArg.pfnProgress = pfnProgress;
     709          18 :     sExtraArg.pProgressData = pProgressData;
     710          18 :     sExtraArg.bFloatingPointWindowValidity = true;
     711          18 :     sExtraArg.dfXOff = dfXOff;
     712          18 :     sExtraArg.dfYOff = dfYOff;
     713          18 :     sExtraArg.dfXSize = dfXSize;
     714          18 :     sExtraArg.dfYSize = dfYSize;
     715             : 
     716          18 :     const int nXOff = static_cast<int>(dfXOff);
     717          18 :     const int nYOff = static_cast<int>(dfYOff);
     718          18 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     719          18 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     720          18 :     if (nBufXSize == 0 && nBufYSize == 0)
     721             :     {
     722          17 :         if (static_cast<int>(dfXSize) == dfXSize &&
     723          17 :             static_cast<int>(dfYSize) == dfYSize)
     724             :         {
     725          17 :             nBufXSize = static_cast<int>(dfXSize);
     726          17 :             nBufYSize = static_cast<int>(dfYSize);
     727             :         }
     728             :         else
     729             :         {
     730           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     731             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     732             :                      "dfYSize is not an integer value");
     733           0 :             return CE_Failure;
     734             :         }
     735             :     }
     736          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     737             :     {
     738           0 :         CPLDebug("GDAL",
     739             :                  "RasterIO() skipped for odd window or buffer size.\n"
     740             :                  "  Window = (%d,%d)x%dx%d\n"
     741             :                  "  Buffer = %dx%d\n",
     742             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     743             :                  static_cast<int>(nBufYSize));
     744             : 
     745           0 :         return CE_None;
     746             :     }
     747             : 
     748          18 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     749             :     {
     750           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     751             :                  "Provided array is not large enough");
     752           1 :         return CE_Failure;
     753             :     }
     754             : 
     755          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     756          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     757          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     758             : 
     759          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     760             : 
     761             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     762             :                                    static_cast<int>(nBufXSize),
     763             :                                    static_cast<int>(nBufYSize), eBufType,
     764          17 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     765             : }
     766             : 
     767             : //! @cond Doxygen_Suppress
     768             : 
     769             : #define INSTANTIATE_READ_RASTER(T)                                             \
     770             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     771             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     772             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     773             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     774             :         void *pProgressData) const;
     775             : 
     776             : INSTANTIATE_READ_RASTER(uint8_t)
     777             : INSTANTIATE_READ_RASTER(int8_t)
     778             : INSTANTIATE_READ_RASTER(uint16_t)
     779             : INSTANTIATE_READ_RASTER(int16_t)
     780             : INSTANTIATE_READ_RASTER(uint32_t)
     781             : INSTANTIATE_READ_RASTER(int32_t)
     782             : INSTANTIATE_READ_RASTER(uint64_t)
     783             : INSTANTIATE_READ_RASTER(int64_t)
     784             : INSTANTIATE_READ_RASTER(GFloat16)
     785             : INSTANTIATE_READ_RASTER(float)
     786             : INSTANTIATE_READ_RASTER(double)
     787             : // Not allowed by C++ standard
     788             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     789             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     790             : INSTANTIATE_READ_RASTER(std::complex<float>)
     791             : INSTANTIATE_READ_RASTER(std::complex<double>)
     792             : 
     793             : //! @endcond
     794             : 
     795             : /************************************************************************/
     796             : /*                             ReadRaster()                             */
     797             : /************************************************************************/
     798             : 
     799             : /** Read a region of image data for this band.
     800             :  *
     801             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     802             :  * for common use cases, like reading a whole band.
     803             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     804             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     805             :  * float, double, std::complex<float|double>.
     806             :  *
     807             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     808             :  *
     809             : \code
     810             :  std::vector<double> myArray;
     811             :  if (poBand->ReadRaster(myArray) == CE_None)
     812             :  {
     813             :      // do something
     814             :  }
     815             : \endcode
     816             :  *
     817             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     818             :  *
     819             : \code{.cpp}
     820             :  std::vector<double> myArray;
     821             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     822             :  {
     823             :      // do something
     824             :  }
     825             : \endcode
     826             :  *
     827             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     828             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     829             :  * instance of this dataset) concurrently from several threads.
     830             :  *
     831             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     832             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     833             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     834             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     835             :  * Or use nLineSpace and a possibly shifted pData value.
     836             :  *
     837             :  * @param[out] vData The vector into which the data should be written.
     838             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     839             :  * nBufYSize values. The values in the vector are organized in left to right,
     840             :  * top to bottom pixel order, and fully packed.
     841             :  * The type of the vector does not need to be the one of GetDataType(). The
     842             :  * method will perform data type translation (with potential rounding, clamping)
     843             :  * if needed.
     844             :  *
     845             :  * @param dfXOff The pixel offset to the top left corner of the region
     846             :  * of the band to be accessed. This would be zero to start from the left side.
     847             :  * Defaults to 0.
     848             :  *
     849             :  * @param dfYOff The line offset to the top left corner of the region
     850             :  * of the band to be accessed. This would be zero to start from the top.
     851             :  * Defaults to 0.
     852             :  *
     853             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     854             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     855             :  * dfXSize is set to the band width.
     856             :  *
     857             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     858             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     859             :  * dfYSize is set to the band height.
     860             :  *
     861             :  * @param nBufXSize the width of the buffer image into which the desired region
     862             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     863             :  * then nBufXSize is initialized with dfXSize.
     864             :  *
     865             :  * @param nBufYSize the height of the buffer image into which the desired region
     866             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     867             :  * then nBufYSize is initialized with dfYSize.
     868             :  *
     869             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     870             :  *
     871             :  * @param pfnProgress Progress function. May be nullptr.
     872             :  *
     873             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     874             :  *
     875             :  * @return CE_Failure if the access fails, otherwise CE_None.
     876             :  *
     877             :  * @see GDALRasterBand::RasterIO()
     878             :  * @since GDAL 3.10
     879             :  */
     880             : template <class T>
     881          90 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     882             :                                   double dfYOff, double dfXSize, double dfYSize,
     883             :                                   size_t nBufXSize, size_t nBufYSize,
     884             :                                   GDALRIOResampleAlg eResampleAlg,
     885             :                                   GDALProgressFunc pfnProgress,
     886             :                                   void *pProgressData) const
     887             : {
     888          90 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     889             :     {
     890           2 :         return CE_Failure;
     891             :     }
     892             : 
     893          88 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     894             :     {
     895          81 :         dfXSize = nRasterXSize;
     896          81 :         dfYSize = nRasterYSize;
     897             :     }
     898           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     899           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     900           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     901           7 :              dfYOff + dfYSize > INT_MAX)
     902             :     {
     903           0 :         return CE_Failure;
     904             :     }
     905             : 
     906             :     GDALRasterIOExtraArg sExtraArg;
     907          88 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     908          88 :     CPL_IGNORE_RET_VAL(sExtraArg.eResampleAlg);
     909          88 :     CPL_IGNORE_RET_VAL(sExtraArg.pfnProgress);
     910          88 :     CPL_IGNORE_RET_VAL(sExtraArg.pProgressData);
     911          88 :     CPL_IGNORE_RET_VAL(sExtraArg.bFloatingPointWindowValidity);
     912          88 :     sExtraArg.eResampleAlg = eResampleAlg;
     913          88 :     sExtraArg.pfnProgress = pfnProgress;
     914          88 :     sExtraArg.pProgressData = pProgressData;
     915          88 :     sExtraArg.bFloatingPointWindowValidity = true;
     916          88 :     sExtraArg.dfXOff = dfXOff;
     917          88 :     sExtraArg.dfYOff = dfYOff;
     918          88 :     sExtraArg.dfXSize = dfXSize;
     919          88 :     sExtraArg.dfYSize = dfYSize;
     920             : 
     921          88 :     const int nXOff = static_cast<int>(dfXOff);
     922          88 :     const int nYOff = static_cast<int>(dfYOff);
     923          88 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     924          88 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     925          88 :     if (nBufXSize == 0 && nBufYSize == 0)
     926             :     {
     927          84 :         if (static_cast<int>(dfXSize) == dfXSize &&
     928          83 :             static_cast<int>(dfYSize) == dfYSize)
     929             :         {
     930          83 :             nBufXSize = static_cast<int>(dfXSize);
     931          83 :             nBufYSize = static_cast<int>(dfYSize);
     932             :         }
     933             :         else
     934             :         {
     935           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     936             :                      "nBufXSize and nBufYSize must be provided if "
     937             :                      "dfXSize or dfYSize is not an integer value");
     938           1 :             return CE_Failure;
     939             :         }
     940             :     }
     941          87 :     if (nBufXSize == 0 || nBufYSize == 0)
     942             :     {
     943           0 :         CPLDebug("GDAL",
     944             :                  "RasterIO() skipped for odd window or buffer size.\n"
     945             :                  "  Window = (%d,%d)x%dx%d\n"
     946             :                  "  Buffer = %dx%d\n",
     947             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     948             :                  static_cast<int>(nBufYSize));
     949             : 
     950           0 :         return CE_None;
     951             :     }
     952             : 
     953             :     if constexpr (SIZEOF_VOIDP < 8)
     954             :     {
     955             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     956             :         {
     957             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     958             :             return CE_Failure;
     959             :         }
     960             :     }
     961             : 
     962          87 :     if (vData.size() < nBufXSize * nBufYSize)
     963             :     {
     964             :         try
     965             :         {
     966          85 :             vData.resize(nBufXSize * nBufYSize);
     967             :         }
     968           1 :         catch (const std::exception &)
     969             :         {
     970           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     971           1 :             return CE_Failure;
     972             :         }
     973             :     }
     974             : 
     975          86 :     constexpr GSpacing nPixelSpace = sizeof(T);
     976          86 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     977          86 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     978             : 
     979          86 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     980             : 
     981             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
     982             :                                    vData.data(), static_cast<int>(nBufXSize),
     983             :                                    static_cast<int>(nBufYSize), eBufType,
     984          86 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     985             : }
     986             : 
     987             : //! @cond Doxygen_Suppress
     988             : 
     989             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     990             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     991             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     992             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     993             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     994             :         void *pProgressData) const;
     995             : 
     996             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     997             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     998             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     999             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
    1000             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
    1001             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
    1002             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
    1003             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
    1004             : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
    1005             : INSTANTIATE_READ_RASTER_VECTOR(float)
    1006             : INSTANTIATE_READ_RASTER_VECTOR(double)
    1007             : // Not allowed by C++ standard
    1008             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
    1009             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
    1010             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
    1011             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
    1012             : 
    1013             : //! @endcond
    1014             : 
    1015             : /************************************************************************/
    1016             : /*                             ReadBlock()                              */
    1017             : /************************************************************************/
    1018             : 
    1019             : /**
    1020             :  * \brief Read a block of image data efficiently.
    1021             :  *
    1022             :  * This method accesses a "natural" block from the raster band without
    1023             :  * resampling, or data type conversion.  For a more generalized, but
    1024             :  * potentially less efficient access use RasterIO().
    1025             :  *
    1026             :  * This method is the same as the C GDALReadBlock() function.
    1027             :  *
    1028             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1029             :  * block oriented data without an extra copy into an application buffer.
    1030             :  *
    1031             :  * The following code would efficiently compute a histogram of eight bit
    1032             :  * raster data.  Note that the final block may be partial ... data beyond
    1033             :  * the edge of the underlying raster band in these edge blocks is of an
    1034             :  * undetermined value.
    1035             :  *
    1036             : \code{.cpp}
    1037             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1038             : 
    1039             :  {
    1040             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1041             : 
    1042             :      CPLAssert( poBand->GetRasterDataType() == GDT_UInt8 );
    1043             : 
    1044             :      int nXBlockSize, nYBlockSize;
    1045             : 
    1046             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1047             :      int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
    1048             :      int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
    1049             : 
    1050             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1051             : 
    1052             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1053             :      {
    1054             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1055             :          {
    1056             :              int        nXValid, nYValid;
    1057             : 
    1058             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1059             : 
    1060             :              // Compute the portion of the block that is valid
    1061             :              // for partial edge blocks.
    1062             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1063             : 
    1064             :              // Collect the histogram counts.
    1065             :              for( int iY = 0; iY < nYValid; iY++ )
    1066             :              {
    1067             :                  for( int iX = 0; iX < nXValid; iX++ )
    1068             :                  {
    1069             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1070             :                  }
    1071             :              }
    1072             :          }
    1073             :      }
    1074             :  }
    1075             : \endcode
    1076             :  *
    1077             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1078             :  * the left most block, 1 the next block and so forth.
    1079             :  *
    1080             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1081             :  * the top most block, 1 the next block and so forth.
    1082             :  *
    1083             :  * @param pImage the buffer into which the data will be read.  The buffer
    1084             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1085             :  * of type GetRasterDataType().
    1086             :  *
    1087             :  * @return CE_None on success or CE_Failure on an error.
    1088             :  */
    1089             : 
    1090        1076 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1091             : 
    1092             : {
    1093             :     /* -------------------------------------------------------------------- */
    1094             :     /*      Validate arguments.                                             */
    1095             :     /* -------------------------------------------------------------------- */
    1096        1076 :     CPLAssert(pImage != nullptr);
    1097             : 
    1098        1076 :     if (!InitBlockInfo())
    1099           0 :         return CE_Failure;
    1100             : 
    1101        1076 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1102             :     {
    1103           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1104             :                     "Illegal nXBlockOff value (%d) in "
    1105             :                     "GDALRasterBand::ReadBlock()\n",
    1106             :                     nXBlockOff);
    1107             : 
    1108           0 :         return (CE_Failure);
    1109             :     }
    1110             : 
    1111        1076 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1112             :     {
    1113           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1114             :                     "Illegal nYBlockOff value (%d) in "
    1115             :                     "GDALRasterBand::ReadBlock()\n",
    1116             :                     nYBlockOff);
    1117             : 
    1118           0 :         return (CE_Failure);
    1119             :     }
    1120             : 
    1121             :     /* -------------------------------------------------------------------- */
    1122             :     /*      Invoke underlying implementation method.                        */
    1123             :     /* -------------------------------------------------------------------- */
    1124             : 
    1125        1076 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1126        1076 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1127        1076 :     if (bCallLeaveReadWrite)
    1128           4 :         LeaveReadWrite();
    1129        1076 :     return eErr;
    1130             : }
    1131             : 
    1132             : /************************************************************************/
    1133             : /*                           GDALReadBlock()                            */
    1134             : /************************************************************************/
    1135             : 
    1136             : /**
    1137             :  * \brief Read a block of image data efficiently.
    1138             :  *
    1139             :  * @see GDALRasterBand::ReadBlock()
    1140             :  */
    1141             : 
    1142          79 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1143             :                                  void *pData)
    1144             : 
    1145             : {
    1146          79 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1147             : 
    1148          79 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1149          79 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1150             : }
    1151             : 
    1152             : /************************************************************************/
    1153             : /*                             IReadBlock()                             */
    1154             : /************************************************************************/
    1155             : 
    1156             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1157             :  * ) \brief Read a block of data.
    1158             :  *
    1159             :  * Default internal implementation ... to be overridden by
    1160             :  * subclasses that support reading.
    1161             :  * @param nBlockXOff Block X Offset
    1162             :  * @param nBlockYOff Block Y Offset
    1163             :  * @param pData Pixel buffer into which to place read data.
    1164             :  * @return CE_None on success or CE_Failure on an error.
    1165             :  */
    1166             : 
    1167             : /************************************************************************/
    1168             : /*                            IWriteBlock()                             */
    1169             : /************************************************************************/
    1170             : 
    1171             : /**
    1172             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1173             :  * Write a block of data.
    1174             :  *
    1175             :  * Default internal implementation ... to be overridden by
    1176             :  * subclasses that support writing.
    1177             :  * @param nBlockXOff Block X Offset
    1178             :  * @param nBlockYOff Block Y Offset
    1179             :  * @param pData Pixel buffer to write
    1180             :  * @return CE_None on success or CE_Failure on an error.
    1181             :  */
    1182             : 
    1183             : /**/
    1184             : /**/
    1185             : 
    1186           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1187             :                                    void * /*pData*/)
    1188             : 
    1189             : {
    1190           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1191           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1192             :                     "WriteBlock() not supported for this dataset.");
    1193             : 
    1194           0 :     return (CE_Failure);
    1195             : }
    1196             : 
    1197             : /************************************************************************/
    1198             : /*                             WriteBlock()                             */
    1199             : /************************************************************************/
    1200             : 
    1201             : /**
    1202             :  * \brief Write a block of image data efficiently.
    1203             :  *
    1204             :  * This method accesses a "natural" block from the raster band without
    1205             :  * resampling, or data type conversion.  For a more generalized, but
    1206             :  * potentially less efficient access use RasterIO().
    1207             :  *
    1208             :  * This method is the same as the C GDALWriteBlock() function.
    1209             :  *
    1210             :  * See ReadBlock() for an example of block oriented data access.
    1211             :  *
    1212             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1213             :  * the left most block, 1 the next block and so forth.
    1214             :  *
    1215             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1216             :  * the left most block, 1 the next block and so forth.
    1217             :  *
    1218             :  * @param pImage the buffer from which the data will be written.  The buffer
    1219             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1220             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1221             :  * temporarily modified during the execution of this method (and eventually
    1222             :  * restored back to its original content), so it is not safe to use a buffer
    1223             :  * stored in a read-only section of the calling program.
    1224             :  *
    1225             :  * @return CE_None on success or CE_Failure on an error.
    1226             :  */
    1227             : 
    1228        4883 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1229             : 
    1230             : {
    1231             :     /* -------------------------------------------------------------------- */
    1232             :     /*      Validate arguments.                                             */
    1233             :     /* -------------------------------------------------------------------- */
    1234        4883 :     CPLAssert(pImage != nullptr);
    1235             : 
    1236        4883 :     if (!InitBlockInfo())
    1237           0 :         return CE_Failure;
    1238             : 
    1239        4883 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1240             :     {
    1241           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1242             :                     "Illegal nXBlockOff value (%d) in "
    1243             :                     "GDALRasterBand::WriteBlock()\n",
    1244             :                     nXBlockOff);
    1245             : 
    1246           0 :         return (CE_Failure);
    1247             :     }
    1248             : 
    1249        4883 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1250             :     {
    1251           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1252             :                     "Illegal nYBlockOff value (%d) in "
    1253             :                     "GDALRasterBand::WriteBlock()\n",
    1254             :                     nYBlockOff);
    1255             : 
    1256           0 :         return (CE_Failure);
    1257             :     }
    1258             : 
    1259        4883 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
    1260             :     {
    1261           0 :         return CE_Failure;
    1262             :     }
    1263             : 
    1264        4883 :     if (eFlushBlockErr != CE_None)
    1265             :     {
    1266           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1267             :                     "An error occurred while writing a dirty block "
    1268             :                     "from GDALRasterBand::WriteBlock");
    1269           0 :         CPLErr eErr = eFlushBlockErr;
    1270           0 :         eFlushBlockErr = CE_None;
    1271           0 :         return eErr;
    1272             :     }
    1273             : 
    1274             :     /* -------------------------------------------------------------------- */
    1275             :     /*      Invoke underlying implementation method.                        */
    1276             :     /* -------------------------------------------------------------------- */
    1277             : 
    1278        4883 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1279        4883 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1280        4883 :     if (bCallLeaveReadWrite)
    1281        4883 :         LeaveReadWrite();
    1282             : 
    1283        4883 :     return eErr;
    1284             : }
    1285             : 
    1286             : /************************************************************************/
    1287             : /*                           GDALWriteBlock()                           */
    1288             : /************************************************************************/
    1289             : 
    1290             : /**
    1291             :  * \brief Write a block of image data efficiently.
    1292             :  *
    1293             :  * @see GDALRasterBand::WriteBlock()
    1294             :  */
    1295             : 
    1296           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1297             :                                   void *pData)
    1298             : 
    1299             : {
    1300           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1301             : 
    1302           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1303           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1304             : }
    1305             : 
    1306             : /************************************************************************/
    1307             : /*                EmitErrorMessageIfWriteNotSupported()                 */
    1308             : /************************************************************************/
    1309             : 
    1310             : /**
    1311             :  * Emit an error message if a write operation to this band is not supported.
    1312             :  *
    1313             :  * The base implementation will emit an error message if the access mode is
    1314             :  * read-only. Derived classes may implement it to provide a custom message.
    1315             :  *
    1316             :  * @param pszCaller Calling function.
    1317             :  * @return true if an error message has been emitted.
    1318             :  */
    1319      681775 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
    1320             :     const char *pszCaller) const
    1321             : {
    1322      681775 :     if (eAccess == GA_ReadOnly)
    1323             :     {
    1324           4 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1325             :                     "%s: attempt to write to dataset opened in read-only mode.",
    1326             :                     pszCaller);
    1327             : 
    1328           4 :         return true;
    1329             :     }
    1330      681771 :     return false;
    1331             : }
    1332             : 
    1333             : /************************************************************************/
    1334             : /*                         GetActualBlockSize()                         */
    1335             : /************************************************************************/
    1336             : /**
    1337             :  * \brief Fetch the actual block size for a given block offset.
    1338             :  *
    1339             :  * Handles partial blocks at the edges of the raster and returns the true
    1340             :  * number of pixels
    1341             :  *
    1342             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1343             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1344             :  * block and so forth.
    1345             :  *
    1346             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1347             :  * the top most block, 1 the next block and so forth.
    1348             :  *
    1349             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1350             :  * the x direction will be stored
    1351             :  *
    1352             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1353             :  * the y direction will be stored
    1354             :  *
    1355             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1356             :  *
    1357             :  */
    1358       33951 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1359             :                                           int *pnXValid, int *pnYValid) const
    1360             : {
    1361       67901 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1362       67898 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1363       67894 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1364       33947 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1365             :     {
    1366           6 :         return CE_Failure;
    1367             :     }
    1368             : 
    1369       33945 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1370       33945 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1371             : 
    1372       33945 :     *pnXValid = nBlockXSize;
    1373       33945 :     *pnYValid = nBlockYSize;
    1374             : 
    1375       33945 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1376             :     {
    1377       32608 :         *pnXValid = nRasterXSize - nXPixelOff;
    1378             :     }
    1379             : 
    1380       33945 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1381             :     {
    1382        3294 :         *pnYValid = nRasterYSize - nYPixelOff;
    1383             :     }
    1384             : 
    1385       33945 :     return CE_None;
    1386             : }
    1387             : 
    1388             : /************************************************************************/
    1389             : /*                       GDALGetActualBlockSize()                       */
    1390             : /************************************************************************/
    1391             : 
    1392             : /**
    1393             :  * \brief Retrieve the actual block size for a given block offset.
    1394             :  *
    1395             :  * @see GDALRasterBand::GetActualBlockSize()
    1396             :  */
    1397             : 
    1398           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1399             :                                           int nYBlockOff, int *pnXValid,
    1400             :                                           int *pnYValid)
    1401             : 
    1402             : {
    1403           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1404             : 
    1405           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1406             :     return (
    1407           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1408             : }
    1409             : 
    1410             : /************************************************************************/
    1411             : /*                   GetSuggestedBlockAccessPattern()                   */
    1412             : /************************************************************************/
    1413             : 
    1414             : /**
    1415             :  * \brief Return the suggested/most efficient access pattern to blocks
    1416             :  *        (for read operations).
    1417             :  *
    1418             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1419             :  * efficient random access (GSBAP_RANDOM) to any block.
    1420             :  * Some drivers for example decompress sequentially a compressed stream from
    1421             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1422             :  * case best performance will be achieved while reading blocks in that order.
    1423             :  * (accessing blocks in random access in such rasters typically causes the
    1424             :  * decoding to be re-initialized from the start if accessing blocks in
    1425             :  * a non-sequential order)
    1426             :  *
    1427             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1428             :  * returned by drivers that expose a somewhat artificial block size, because
    1429             :  * they can extract any part of a raster, but in a rather inefficient way.
    1430             :  *
    1431             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1432             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1433             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1434             :  * most efficient strategy is to read as many pixels as possible in the less
    1435             :  * RasterIO() operations.
    1436             :  *
    1437             :  * The return of this method is for example used to determine the swath size
    1438             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1439             :  *
    1440             :  * @since GDAL 3.6
    1441             :  */
    1442             : 
    1443             : GDALSuggestedBlockAccessPattern
    1444        2491 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1445             : {
    1446        2491 :     return GSBAP_UNKNOWN;
    1447             : }
    1448             : 
    1449             : /************************************************************************/
    1450             : /*                         GetRasterDataType()                          */
    1451             : /************************************************************************/
    1452             : 
    1453             : /**
    1454             :  * \brief Fetch the pixel data type for this band.
    1455             :  *
    1456             :  * This method is the same as the C function GDALGetRasterDataType().
    1457             :  *
    1458             :  * @return the data type of pixels for this band.
    1459             :  */
    1460             : 
    1461     9054580 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1462             : 
    1463             : {
    1464     9054580 :     return eDataType;
    1465             : }
    1466             : 
    1467             : /************************************************************************/
    1468             : /*                       GDALGetRasterDataType()                        */
    1469             : /************************************************************************/
    1470             : 
    1471             : /**
    1472             :  * \brief Fetch the pixel data type for this band.
    1473             :  *
    1474             :  * @see GDALRasterBand::GetRasterDataType()
    1475             :  */
    1476             : 
    1477      911252 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1478             : 
    1479             : {
    1480      911252 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1481             : 
    1482      911252 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1483      911252 :     return poBand->GetRasterDataType();
    1484             : }
    1485             : 
    1486             : /************************************************************************/
    1487             : /*                            GetBlockSize()                            */
    1488             : /************************************************************************/
    1489             : 
    1490             : /**
    1491             :  * \brief Fetch the "natural" block size of this band.
    1492             :  *
    1493             :  * GDAL contains a concept of the natural block size of rasters so that
    1494             :  * applications can organized data access efficiently for some file formats.
    1495             :  * The natural block size is the block size that is most efficient for
    1496             :  * accessing the format.  For many formats this is simple a whole scanline
    1497             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1498             :  *
    1499             :  * However, for tiled images this will typically be the tile size.
    1500             :  *
    1501             :  * Note that the X and Y block sizes don't have to divide the image size
    1502             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1503             :  * See ReadBlock() for an example of code dealing with these issues.
    1504             :  *
    1505             :  * This method is the same as the C function GDALGetBlockSize().
    1506             :  *
    1507             :  * @param pnXSize integer to put the X block size into or NULL.
    1508             :  *
    1509             :  * @param pnYSize integer to put the Y block size into or NULL.
    1510             :  */
    1511             : 
    1512     5584880 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1513             : 
    1514             : {
    1515     5584880 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1516             :     {
    1517           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1518           0 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1519           0 :                     nBlockYSize);
    1520           0 :         if (pnXSize != nullptr)
    1521           0 :             *pnXSize = 0;
    1522           0 :         if (pnYSize != nullptr)
    1523           0 :             *pnYSize = 0;
    1524             :     }
    1525             :     else
    1526             :     {
    1527     5584880 :         if (pnXSize != nullptr)
    1528     5584880 :             *pnXSize = nBlockXSize;
    1529     5584880 :         if (pnYSize != nullptr)
    1530     5584880 :             *pnYSize = nBlockYSize;
    1531             :     }
    1532     5584880 : }
    1533             : 
    1534             : /************************************************************************/
    1535             : /*                          GDALGetBlockSize()                          */
    1536             : /************************************************************************/
    1537             : 
    1538             : /**
    1539             :  * \brief Fetch the "natural" block size of this band.
    1540             :  *
    1541             :  * @see GDALRasterBand::GetBlockSize()
    1542             :  */
    1543             : 
    1544       41361 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1545             :                                   int *pnYSize)
    1546             : 
    1547             : {
    1548       41361 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1549             : 
    1550       41361 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1551       41361 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1552             : }
    1553             : 
    1554             : /************************************************************************/
    1555             : /*                           InitBlockInfo()                            */
    1556             : /************************************************************************/
    1557             : 
    1558             : //! @cond Doxygen_Suppress
    1559     3677100 : int GDALRasterBand::InitBlockInfo()
    1560             : 
    1561             : {
    1562     3677100 :     if (poBandBlockCache != nullptr)
    1563     3436100 :         return poBandBlockCache->IsInitOK();
    1564             : 
    1565             :     /* Do some validation of raster and block dimensions in case the driver */
    1566             :     /* would have neglected to do it itself */
    1567      241004 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1568             :     {
    1569           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1570             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1571             :                     nBlockYSize);
    1572           0 :         return FALSE;
    1573             :     }
    1574             : 
    1575      241004 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1576             :     {
    1577           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    1578             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1579             :                     nRasterYSize);
    1580           0 :         return FALSE;
    1581             :     }
    1582             : 
    1583      241004 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1584      241004 :     if (nDataTypeSize == 0)
    1585             :     {
    1586           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1587           0 :         return FALSE;
    1588             :     }
    1589             : 
    1590             : #if SIZEOF_VOIDP == 4
    1591             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1592             :     {
    1593             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1594             :          * multiplication in other cases */
    1595             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1596             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1597             :         {
    1598             :             ReportError(CE_Failure, CPLE_NotSupported,
    1599             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1600             :                         nBlockYSize);
    1601             :             return FALSE;
    1602             :         }
    1603             :     }
    1604             : #endif
    1605             : 
    1606      241004 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1607      241004 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1608             : 
    1609             :     const char *pszBlockStrategy =
    1610      241004 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1611      241004 :     bool bUseArray = true;
    1612      241004 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1613             :     {
    1614      240964 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1615             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1616             :         {
    1617      240945 :             GUIntBig nBlockCount =
    1618      240945 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1619      240945 :             if (poDS != nullptr)
    1620      240741 :                 nBlockCount *= poDS->GetRasterCount();
    1621      240945 :             bUseArray = (nBlockCount < 1024 * 1024);
    1622             :         }
    1623          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1624             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1625             :         {
    1626           0 :             bUseArray = false;
    1627      240964 :         }
    1628             :     }
    1629          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1630          40 :         bUseArray = false;
    1631           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1632           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1633             :                  pszBlockStrategy);
    1634             : 
    1635      241004 :     if (bUseArray)
    1636      240933 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1637             :     else
    1638             :     {
    1639          71 :         if (nBand == 1)
    1640          26 :             CPLDebug("GDAL", "Use hashset band block cache");
    1641          71 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1642             :     }
    1643      241004 :     if (poBandBlockCache == nullptr)
    1644           0 :         return FALSE;
    1645      241004 :     return poBandBlockCache->Init();
    1646             : }
    1647             : 
    1648             : //! @endcond
    1649             : 
    1650             : /************************************************************************/
    1651             : /*                             FlushCache()                             */
    1652             : /************************************************************************/
    1653             : 
    1654             : /**
    1655             :  * \brief Flush raster data cache.
    1656             :  *
    1657             :  * This call will recover memory used to cache data blocks for this raster
    1658             :  * band, and ensure that new requests are referred to the underlying driver.
    1659             :  *
    1660             :  * This method is the same as the C function GDALFlushRasterCache().
    1661             :  *
    1662             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1663             :  * @return CE_None on success.
    1664             :  */
    1665             : 
    1666     5833400 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1667             : 
    1668             : {
    1669     5963560 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1670      130163 :         poBandBlockCache)
    1671        4330 :         poBandBlockCache->DisableDirtyBlockWriting();
    1672             : 
    1673     5833400 :     CPLErr eGlobalErr = eFlushBlockErr;
    1674             : 
    1675     5833400 :     if (eFlushBlockErr != CE_None)
    1676             :     {
    1677           0 :         ReportError(
    1678             :             eFlushBlockErr, CPLE_AppDefined,
    1679             :             "An error occurred while writing a dirty block from FlushCache");
    1680           0 :         eFlushBlockErr = CE_None;
    1681             :     }
    1682             : 
    1683     5833400 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1684     5061690 :         return eGlobalErr;
    1685             : 
    1686      771710 :     return poBandBlockCache->FlushCache();
    1687             : }
    1688             : 
    1689             : /************************************************************************/
    1690             : /*                        GDALFlushRasterCache()                        */
    1691             : /************************************************************************/
    1692             : 
    1693             : /**
    1694             :  * \brief Flush raster data cache.
    1695             :  *
    1696             :  * @see GDALRasterBand::FlushCache()
    1697             :  */
    1698             : 
    1699         625 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1700             : 
    1701             : {
    1702         625 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1703             : 
    1704         625 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1705             : }
    1706             : 
    1707             : /************************************************************************/
    1708             : /*                             DropCache()                              */
    1709             : /************************************************************************/
    1710             : 
    1711             : /**
    1712             : * \brief Drop raster data cache : data in cache will be lost.
    1713             : *
    1714             : * This call will recover memory used to cache data blocks for this raster
    1715             : * band, and ensure that new requests are referred to the underlying driver.
    1716             : *
    1717             : * This method is the same as the C function GDALDropRasterCache().
    1718             : *
    1719             : * @return CE_None on success.
    1720             : * @since 3.9
    1721             : */
    1722             : 
    1723           1 : CPLErr GDALRasterBand::DropCache()
    1724             : 
    1725             : {
    1726           1 :     CPLErr result = CE_None;
    1727             : 
    1728           1 :     if (poBandBlockCache)
    1729           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1730             : 
    1731           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1732             : 
    1733           1 :     if (eFlushBlockErr != CE_None)
    1734             :     {
    1735           0 :         ReportError(
    1736             :             eFlushBlockErr, CPLE_AppDefined,
    1737             :             "An error occurred while writing a dirty block from DropCache");
    1738           0 :         eFlushBlockErr = CE_None;
    1739             :     }
    1740             : 
    1741           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1742           0 :         result = eGlobalErr;
    1743             :     else
    1744           1 :         result = poBandBlockCache->FlushCache();
    1745             : 
    1746           1 :     if (poBandBlockCache)
    1747           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1748             : 
    1749           1 :     return result;
    1750             : }
    1751             : 
    1752             : /************************************************************************/
    1753             : /*                        GDALDropRasterCache()                         */
    1754             : /************************************************************************/
    1755             : 
    1756             : /**
    1757             : * \brief Drop raster data cache.
    1758             : *
    1759             : * @see GDALRasterBand::DropCache()
    1760             : * @since 3.9
    1761             : */
    1762             : 
    1763           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1764             : 
    1765             : {
    1766           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1767             : 
    1768           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1769             : }
    1770             : 
    1771             : /************************************************************************/
    1772             : /*                        UnreferenceBlock()                            */
    1773             : /*                                                                      */
    1774             : /*      Unreference the block from our array of blocks                  */
    1775             : /*      This method should only be called by                            */
    1776             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1777             : /*      the block cache mutex)                                          */
    1778             : /************************************************************************/
    1779             : 
    1780       29635 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1781             : {
    1782             : #ifdef notdef
    1783             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1784             :     {
    1785             :         if (poBandBlockCache == nullptr)
    1786             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1787             :         else
    1788             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1789             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1790             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1791             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1792             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1793             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1794             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1795             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1796             :         poBlock->DumpBlock();
    1797             :         if (GetDataset() != nullptr)
    1798             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1799             :         GDALRasterBlock::Verify();
    1800             :         abort();
    1801             :     }
    1802             : #endif
    1803       29635 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1804       29635 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1805             : }
    1806             : 
    1807             : /************************************************************************/
    1808             : /*                        AddBlockToFreeList()                          */
    1809             : /*                                                                      */
    1810             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1811             : /*      finished with a block about to be free'd, they pass it to that  */
    1812             : /*      method.                                                         */
    1813             : /************************************************************************/
    1814             : 
    1815             : //! @cond Doxygen_Suppress
    1816       29635 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1817             : {
    1818       29635 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1819       29635 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1820             : }
    1821             : 
    1822             : //! @endcond
    1823             : 
    1824             : /************************************************************************/
    1825             : /*                           HasDirtyBlocks()                           */
    1826             : /************************************************************************/
    1827             : 
    1828             : //! @cond Doxygen_Suppress
    1829          17 : bool GDALRasterBand::HasDirtyBlocks() const
    1830             : {
    1831          17 :     return poBandBlockCache && poBandBlockCache->HasDirtyBlocks();
    1832             : }
    1833             : 
    1834             : //! @endcond
    1835             : 
    1836             : /************************************************************************/
    1837             : /*                             FlushBlock()                             */
    1838             : /************************************************************************/
    1839             : 
    1840             : /** Flush a block out of the block cache.
    1841             :  * @param nXBlockOff block x offset
    1842             :  * @param nYBlockOff blocky offset
    1843             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1844             :  * @return CE_None in case of success, an error code otherwise.
    1845             :  */
    1846        2315 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1847             :                                   int bWriteDirtyBlock)
    1848             : 
    1849             : {
    1850        2315 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1851           0 :         return (CE_Failure);
    1852             : 
    1853             :     /* -------------------------------------------------------------------- */
    1854             :     /*      Validate the request                                            */
    1855             :     /* -------------------------------------------------------------------- */
    1856        2315 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1857             :     {
    1858           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1859             :                     "Illegal nBlockXOff value (%d) in "
    1860             :                     "GDALRasterBand::FlushBlock()\n",
    1861             :                     nXBlockOff);
    1862             : 
    1863           0 :         return (CE_Failure);
    1864             :     }
    1865             : 
    1866        2315 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1867             :     {
    1868           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1869             :                     "Illegal nBlockYOff value (%d) in "
    1870             :                     "GDALRasterBand::FlushBlock()\n",
    1871             :                     nYBlockOff);
    1872             : 
    1873           0 :         return (CE_Failure);
    1874             :     }
    1875             : 
    1876        2315 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1877        2315 :                                         bWriteDirtyBlock);
    1878             : }
    1879             : 
    1880             : /************************************************************************/
    1881             : /*                        TryGetLockedBlockRef()                        */
    1882             : /************************************************************************/
    1883             : 
    1884             : /**
    1885             :  * \brief Try fetching block ref.
    1886             :  *
    1887             :  * This method will returned the requested block (locked) if it is already
    1888             :  * in the block cache for the layer.  If not, nullptr is returned.
    1889             :  *
    1890             :  * If a non-NULL value is returned, then a lock for the block will have been
    1891             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1892             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1893             :  * severe problems may result.
    1894             :  *
    1895             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1896             :  * the left most block, 1 the next block and so forth.
    1897             :  *
    1898             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1899             :  * the top most block, 1 the next block and so forth.
    1900             :  *
    1901             :  * @return NULL if block not available, or locked block pointer.
    1902             :  */
    1903             : 
    1904    10766300 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1905             :                                                       int nYBlockOff)
    1906             : 
    1907             : {
    1908    10766300 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1909      174048 :         return nullptr;
    1910             : 
    1911             :     /* -------------------------------------------------------------------- */
    1912             :     /*      Validate the request                                            */
    1913             :     /* -------------------------------------------------------------------- */
    1914    10592200 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1915             :     {
    1916           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1917             :                     "Illegal nBlockXOff value (%d) in "
    1918             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1919             :                     nXBlockOff);
    1920             : 
    1921           0 :         return (nullptr);
    1922             :     }
    1923             : 
    1924    10592200 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1925             :     {
    1926           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1927             :                     "Illegal nBlockYOff value (%d) in "
    1928             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1929             :                     nYBlockOff);
    1930             : 
    1931           0 :         return (nullptr);
    1932             :     }
    1933             : 
    1934    10592200 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1935             : }
    1936             : 
    1937             : /************************************************************************/
    1938             : /*                         GetLockedBlockRef()                          */
    1939             : /************************************************************************/
    1940             : 
    1941             : /**
    1942             :  * \brief Fetch a pointer to an internally cached raster block.
    1943             :  *
    1944             :  * This method will returned the requested block (locked) if it is already
    1945             :  * in the block cache for the layer.  If not, the block will be read from
    1946             :  * the driver, and placed in the layer block cached, then returned.  If an
    1947             :  * error occurs reading the block from the driver, a NULL value will be
    1948             :  * returned.
    1949             :  *
    1950             :  * If a non-NULL value is returned, then a lock for the block will have been
    1951             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1952             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1953             :  * severe problems may result.
    1954             :  *
    1955             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1956             :  * enable caching.
    1957             :  *
    1958             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1959             :  * the left most block, 1 the next block and so forth.
    1960             :  *
    1961             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1962             :  * the top most block, 1 the next block and so forth.
    1963             :  *
    1964             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1965             :  * but not actually read from the source.  This is useful when it will just
    1966             :  * be completely set and written back.
    1967             :  *
    1968             :  * @return pointer to the block object, or NULL on failure.
    1969             :  */
    1970             : 
    1971    10455800 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1972             :                                                    int nYBlockOff,
    1973             :                                                    int bJustInitialize)
    1974             : 
    1975             : {
    1976             :     /* -------------------------------------------------------------------- */
    1977             :     /*      Try and fetch from cache.                                       */
    1978             :     /* -------------------------------------------------------------------- */
    1979    10455800 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1980             : 
    1981             :     /* -------------------------------------------------------------------- */
    1982             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1983             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1984             :     /*      cache.                                                          */
    1985             :     /* -------------------------------------------------------------------- */
    1986    10455800 :     if (poBlock == nullptr)
    1987             :     {
    1988     3398740 :         if (!InitBlockInfo())
    1989           0 :             return (nullptr);
    1990             : 
    1991             :         /* --------------------------------------------------------------------
    1992             :          */
    1993             :         /*      Validate the request */
    1994             :         /* --------------------------------------------------------------------
    1995             :          */
    1996     3398740 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1997             :         {
    1998           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1999             :                         "Illegal nBlockXOff value (%d) in "
    2000             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    2001             :                         nXBlockOff);
    2002             : 
    2003           0 :             return (nullptr);
    2004             :         }
    2005             : 
    2006     3398740 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    2007             :         {
    2008           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    2009             :                         "Illegal nBlockYOff value (%d) in "
    2010             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    2011             :                         nYBlockOff);
    2012             : 
    2013           0 :             return (nullptr);
    2014             :         }
    2015             : 
    2016     3398740 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    2017     3398740 :         if (poBlock == nullptr)
    2018           0 :             return nullptr;
    2019             : 
    2020     3398740 :         poBlock->AddLock();
    2021             : 
    2022             :         /* We need to temporarily drop the read-write lock in the following */
    2023             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    2024             :          */
    2025             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    2026             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    2027             :          */
    2028             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    2029             :          */
    2030             :         /* called and attempt at taking the lock on T2 (already taken).
    2031             :          * Similarly */
    2032             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    2033             :         /* But this may open the door to other problems... */
    2034     3398740 :         if (poDS)
    2035     3398000 :             poDS->TemporarilyDropReadWriteLock();
    2036             :         /* allocate data space */
    2037     3398740 :         CPLErr eErr = poBlock->Internalize();
    2038     3398740 :         if (poDS)
    2039     3398000 :             poDS->ReacquireReadWriteLock();
    2040     3398740 :         if (eErr != CE_None)
    2041             :         {
    2042           0 :             poBlock->DropLock();
    2043           0 :             delete poBlock;
    2044           0 :             return nullptr;
    2045             :         }
    2046             : 
    2047     3398740 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2048             :         {
    2049           0 :             poBlock->DropLock();
    2050           0 :             delete poBlock;
    2051           0 :             return nullptr;
    2052             :         }
    2053             : 
    2054     3398740 :         if (!bJustInitialize)
    2055             :         {
    2056     2900860 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2057     2900860 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2058     2900860 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2059     2900860 :             if (bCallLeaveReadWrite)
    2060      133890 :                 LeaveReadWrite();
    2061     2900860 :             if (eErr != CE_None)
    2062             :             {
    2063        1165 :                 poBlock->DropLock();
    2064        1165 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2065        1165 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2066             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2067             :                             nXBlockOff, nYBlockOff,
    2068        1165 :                             (nErrorCounter != CPLGetErrorCounter())
    2069        1163 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2070             :                                 : "");
    2071        1165 :                 return nullptr;
    2072             :             }
    2073             : 
    2074     2899700 :             nBlockReads++;
    2075     2899700 :             if (static_cast<GIntBig>(nBlockReads) ==
    2076     2899700 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2077         244 :                         1 &&
    2078         244 :                 nBand == 1 && poDS != nullptr)
    2079             :             {
    2080         175 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2081         175 :                          poDS->GetDescription());
    2082             :             }
    2083             :         }
    2084             :     }
    2085             : 
    2086    10454600 :     return poBlock;
    2087             : }
    2088             : 
    2089             : /************************************************************************/
    2090             : /*                                Fill()                                */
    2091             : /************************************************************************/
    2092             : 
    2093             : /**
    2094             :  * \brief Fill this band with a constant value.
    2095             :  *
    2096             :  * GDAL makes no guarantees
    2097             :  * about what values pixels in newly created files are set to, so this
    2098             :  * method can be used to clear a band to a specified "default" value.
    2099             :  * The fill value is passed in as a double but this will be converted
    2100             :  * to the underlying type before writing to the file. An optional
    2101             :  * second argument allows the imaginary component of a complex
    2102             :  * constant value to be specified.
    2103             :  *
    2104             :  * This method is the same as the C function GDALFillRaster().
    2105             :  *
    2106             :  * @param dfRealValue Real component of fill value
    2107             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2108             :  *
    2109             :  * @return CE_Failure if the write fails, otherwise CE_None
    2110             :  */
    2111      269827 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2112             : {
    2113             : 
    2114             :     // General approach is to construct a source block of the file's
    2115             :     // native type containing the appropriate value and then copy this
    2116             :     // to each block in the image via the RasterBlock cache. Using
    2117             :     // the cache means we avoid file I/O if it is not necessary, at the
    2118             :     // expense of some extra memcpy's (since we write to the
    2119             :     // RasterBlock cache, which is then at some point written to the
    2120             :     // underlying file, rather than simply directly to the underlying
    2121             :     // file.)
    2122             : 
    2123             :     // Check we can write to the file.
    2124      269827 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
    2125             :     {
    2126           6 :         return CE_Failure;
    2127             :     }
    2128             : 
    2129             :     // Make sure block parameters are set.
    2130      269821 :     if (!InitBlockInfo())
    2131           0 :         return CE_Failure;
    2132             : 
    2133             :     // Allocate the source block.
    2134      269821 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2135      269821 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2136      269821 :     auto blockByteSize = blockSize * elementSize;
    2137             :     unsigned char *srcBlock =
    2138      269821 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2139      269821 :     if (srcBlock == nullptr)
    2140             :     {
    2141           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2142             :                     "GDALRasterBand::Fill(): Out of memory "
    2143             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2144             :                     static_cast<GUIntBig>(blockByteSize));
    2145           0 :         return CE_Failure;
    2146             :     }
    2147             : 
    2148             :     // Initialize the source block.
    2149      269821 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2150      269821 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2151             :                     elementSize, blockSize);
    2152             : 
    2153      269821 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2154             : 
    2155             :     // Write block to block cache
    2156      881425 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2157             :     {
    2158     1517580 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2159             :         {
    2160      905978 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2161      905978 :             if (destBlock == nullptr)
    2162             :             {
    2163           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2164             :                             "GDALRasterBand::Fill(): Error "
    2165             :                             "while retrieving cache block.");
    2166           0 :                 VSIFree(srcBlock);
    2167           0 :                 return CE_Failure;
    2168             :             }
    2169      905978 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2170      905978 :             destBlock->MarkDirty();
    2171      905978 :             destBlock->DropLock();
    2172             :         }
    2173             :     }
    2174             : 
    2175      269821 :     if (bCallLeaveReadWrite)
    2176      267757 :         LeaveReadWrite();
    2177             : 
    2178             :     // Free up the source block
    2179      269821 :     VSIFree(srcBlock);
    2180             : 
    2181      269821 :     return CE_None;
    2182             : }
    2183             : 
    2184             : /************************************************************************/
    2185             : /*                           GDALFillRaster()                           */
    2186             : /************************************************************************/
    2187             : 
    2188             : /**
    2189             :  * \brief Fill this band with a constant value.
    2190             :  *
    2191             :  * @see GDALRasterBand::Fill()
    2192             :  */
    2193      269597 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2194             :                                   double dfImaginaryValue)
    2195             : {
    2196      269597 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2197             : 
    2198      269597 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2199      269597 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2200             : }
    2201             : 
    2202             : /************************************************************************/
    2203             : /*                             GetAccess()                              */
    2204             : /************************************************************************/
    2205             : 
    2206             : /**
    2207             :  * \brief Find out if we have update permission for this band.
    2208             :  *
    2209             :  * This method is the same as the C function GDALGetRasterAccess().
    2210             :  *
    2211             :  * @return Either GA_Update or GA_ReadOnly.
    2212             :  */
    2213             : 
    2214        3224 : GDALAccess GDALRasterBand::GetAccess()
    2215             : 
    2216             : {
    2217        3224 :     return eAccess;
    2218             : }
    2219             : 
    2220             : /************************************************************************/
    2221             : /*                        GDALGetRasterAccess()                         */
    2222             : /************************************************************************/
    2223             : 
    2224             : /**
    2225             :  * \brief Find out if we have update permission for this band.
    2226             :  *
    2227             :  * @see GDALRasterBand::GetAccess()
    2228             :  */
    2229             : 
    2230        2564 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2231             : 
    2232             : {
    2233        2564 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2234             : 
    2235        2564 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2236        2564 :     return poBand->GetAccess();
    2237             : }
    2238             : 
    2239             : /************************************************************************/
    2240             : /*                          GetCategoryNames()                          */
    2241             : /************************************************************************/
    2242             : 
    2243             : /**
    2244             :  * \brief Fetch the list of category names for this raster.
    2245             :  *
    2246             :  * The return list is a "StringList" in the sense of the CPL functions.
    2247             :  * That is a NULL terminated array of strings.  Raster values without
    2248             :  * associated names will have an empty string in the returned list.  The
    2249             :  * first entry in the list is for raster values of zero, and so on.
    2250             :  *
    2251             :  * The returned stringlist should not be altered or freed by the application.
    2252             :  * It may change on the next GDAL call, so please copy it if it is needed
    2253             :  * for any period of time.
    2254             :  *
    2255             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2256             :  *
    2257             :  * @return list of names, or NULL if none.
    2258             :  */
    2259             : 
    2260         332 : char **GDALRasterBand::GetCategoryNames()
    2261             : 
    2262             : {
    2263         332 :     return nullptr;
    2264             : }
    2265             : 
    2266             : /************************************************************************/
    2267             : /*                     GDALGetRasterCategoryNames()                     */
    2268             : /************************************************************************/
    2269             : 
    2270             : /**
    2271             :  * \brief Fetch the list of category names for this raster.
    2272             :  *
    2273             :  * @see GDALRasterBand::GetCategoryNames()
    2274             :  */
    2275             : 
    2276         210 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2277             : 
    2278             : {
    2279         210 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2280             : 
    2281         210 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2282         210 :     return poBand->GetCategoryNames();
    2283             : }
    2284             : 
    2285             : /************************************************************************/
    2286             : /*                          SetCategoryNames()                          */
    2287             : /************************************************************************/
    2288             : 
    2289             : /**
    2290             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2291             :  * \brief Set the category names for this band.
    2292             :  *
    2293             :  * See the GetCategoryNames() method for more on the interpretation of
    2294             :  * category names.
    2295             :  *
    2296             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2297             :  *
    2298             :  * @param papszNames the NULL terminated StringList of category names.  May
    2299             :  * be NULL to just clear the existing list.
    2300             :  *
    2301             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2302             :  * by the driver CE_Failure is returned, but no error message is reported.
    2303             :  */
    2304             : 
    2305             : /**/
    2306             : /**/
    2307             : 
    2308           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2309             : {
    2310           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2311           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2312             :                     "SetCategoryNames() not supported for this dataset.");
    2313             : 
    2314           0 :     return CE_Failure;
    2315             : }
    2316             : 
    2317             : /************************************************************************/
    2318             : /*                        GDALSetCategoryNames()                        */
    2319             : /************************************************************************/
    2320             : 
    2321             : /**
    2322             :  * \brief Set the category names for this band.
    2323             :  *
    2324             :  * @see GDALRasterBand::SetCategoryNames()
    2325             :  */
    2326             : 
    2327           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2328             :                                               CSLConstList papszNames)
    2329             : 
    2330             : {
    2331           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2332             : 
    2333           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2334           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2335             : }
    2336             : 
    2337             : /************************************************************************/
    2338             : /*                           GetNoDataValue()                           */
    2339             : /************************************************************************/
    2340             : 
    2341             : /**
    2342             :  * \brief Fetch the no data value for this band.
    2343             :  *
    2344             :  * If there is no out of data value, an out of range value will generally
    2345             :  * be returned.  The no data value for a band is generally a special marker
    2346             :  * value used to mark pixels that are not valid data.  Such pixels should
    2347             :  * generally not be displayed, nor contribute to analysis operations.
    2348             :  *
    2349             :  * The no data value returned is 'raw', meaning that it has no offset and
    2350             :  * scale applied.
    2351             :  *
    2352             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2353             :  * lossy if the nodata value cannot exactly been represented by a double.
    2354             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2355             :  *
    2356             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2357             :  *
    2358             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2359             :  * is actually associated with this layer.  May be NULL (default).
    2360             :  *
    2361             :  * @return the nodata value for this band.
    2362             :  */
    2363             : 
    2364       31877 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2365             : 
    2366             : {
    2367       31877 :     if (pbSuccess != nullptr)
    2368       31877 :         *pbSuccess = FALSE;
    2369             : 
    2370       31877 :     return -1e10;
    2371             : }
    2372             : 
    2373             : /************************************************************************/
    2374             : /*                      GDALGetRasterNoDataValue()                      */
    2375             : /************************************************************************/
    2376             : 
    2377             : /**
    2378             :  * \brief Fetch the no data value for this band.
    2379             :  *
    2380             :  * @see GDALRasterBand::GetNoDataValue()
    2381             :  */
    2382             : 
    2383      415181 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2384             :                                             int *pbSuccess)
    2385             : 
    2386             : {
    2387      415181 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2388             : 
    2389      415181 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2390      415181 :     return poBand->GetNoDataValue(pbSuccess);
    2391             : }
    2392             : 
    2393             : /************************************************************************/
    2394             : /*                       GetNoDataValueAsInt64()                        */
    2395             : /************************************************************************/
    2396             : 
    2397             : /**
    2398             :  * \brief Fetch the no data value for this band.
    2399             :  *
    2400             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2401             :  *
    2402             :  * If there is no out of data value, an out of range value will generally
    2403             :  * be returned.  The no data value for a band is generally a special marker
    2404             :  * value used to mark pixels that are not valid data.  Such pixels should
    2405             :  * generally not be displayed, nor contribute to analysis operations.
    2406             :  *
    2407             :  * The no data value returned is 'raw', meaning that it has no offset and
    2408             :  * scale applied.
    2409             :  *
    2410             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2411             :  *
    2412             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2413             :  * is actually associated with this layer.  May be NULL (default).
    2414             :  *
    2415             :  * @return the nodata value for this band.
    2416             :  *
    2417             :  * @since GDAL 3.5
    2418             :  */
    2419             : 
    2420          11 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2421             : 
    2422             : {
    2423          11 :     if (pbSuccess != nullptr)
    2424          11 :         *pbSuccess = FALSE;
    2425             : 
    2426          11 :     return std::numeric_limits<int64_t>::min();
    2427             : }
    2428             : 
    2429             : /************************************************************************/
    2430             : /*                  GDALGetRasterNoDataValueAsInt64()                   */
    2431             : /************************************************************************/
    2432             : 
    2433             : /**
    2434             :  * \brief Fetch the no data value for this band.
    2435             :  *
    2436             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2437             :  *
    2438             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2439             :  *
    2440             :  * @since GDAL 3.5
    2441             :  */
    2442             : 
    2443          31 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2444             :                                                     int *pbSuccess)
    2445             : 
    2446             : {
    2447          31 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2448             :                       std::numeric_limits<int64_t>::min());
    2449             : 
    2450          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2451          31 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2452             : }
    2453             : 
    2454             : /************************************************************************/
    2455             : /*                       GetNoDataValueAsUInt64()                       */
    2456             : /************************************************************************/
    2457             : 
    2458             : /**
    2459             :  * \brief Fetch the no data value for this band.
    2460             :  *
    2461             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2462             :  *
    2463             :  * If there is no out of data value, an out of range value will generally
    2464             :  * be returned.  The no data value for a band is generally a special marker
    2465             :  * value used to mark pixels that are not valid data.  Such pixels should
    2466             :  * generally not be displayed, nor contribute to analysis operations.
    2467             :  *
    2468             :  * The no data value returned is 'raw', meaning that it has no offset and
    2469             :  * scale applied.
    2470             :  *
    2471             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2472             :  *
    2473             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2474             :  * is actually associated with this layer.  May be NULL (default).
    2475             :  *
    2476             :  * @return the nodata value for this band.
    2477             :  *
    2478             :  * @since GDAL 3.5
    2479             :  */
    2480             : 
    2481          10 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2482             : 
    2483             : {
    2484          10 :     if (pbSuccess != nullptr)
    2485          10 :         *pbSuccess = FALSE;
    2486             : 
    2487          10 :     return std::numeric_limits<uint64_t>::max();
    2488             : }
    2489             : 
    2490             : /************************************************************************/
    2491             : /*                  GDALGetRasterNoDataValueAsUInt64()                  */
    2492             : /************************************************************************/
    2493             : 
    2494             : /**
    2495             :  * \brief Fetch the no data value for this band.
    2496             :  *
    2497             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2498             :  *
    2499             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2500             :  *
    2501             :  * @since GDAL 3.5
    2502             :  */
    2503             : 
    2504          22 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2505             :                                                       int *pbSuccess)
    2506             : 
    2507             : {
    2508          22 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2509             :                       std::numeric_limits<uint64_t>::max());
    2510             : 
    2511          22 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2512          22 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2513             : }
    2514             : 
    2515             : /************************************************************************/
    2516             : /*                       SetNoDataValueAsString()                       */
    2517             : /************************************************************************/
    2518             : 
    2519             : /**
    2520             :  * \brief Set the no data value for this band.
    2521             :  *
    2522             :  * Depending on drivers, changing the no data value may or may not have an
    2523             :  * effect on the pixel values of a raster that has just been created. It is
    2524             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2525             :  * the raster to the nodata value.
    2526             :  * In any case, changing an existing no data value, when one already exists and
    2527             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2528             :  * value matched the previous nodata value.
    2529             :  *
    2530             :  * To clear the nodata value, use DeleteNoDataValue().
    2531             :  *
    2532             :  * @param pszNoData the value to set.
    2533             :  * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
    2534             :  *             If the value cannot be exactly represented on the output data
    2535             :  *             type, *pbCannotBeExactlyRepresented will be set to true.
    2536             :  *
    2537             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2538             :  * by the driver, CE_Failure is returned but no error message will have
    2539             :  * been emitted.
    2540             :  *
    2541             :  * @since 3.11
    2542             :  */
    2543             : 
    2544             : CPLErr
    2545         126 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
    2546             :                                        bool *pbCannotBeExactlyRepresented)
    2547             : {
    2548         126 :     if (pbCannotBeExactlyRepresented)
    2549         126 :         *pbCannotBeExactlyRepresented = false;
    2550         126 :     if (eDataType == GDT_Int64)
    2551             :     {
    2552           8 :         if (strchr(pszNoData, '.') ||
    2553           3 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2554             :         {
    2555           2 :             char *endptr = nullptr;
    2556           2 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2557           4 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2558           2 :                 GDALIsValueExactAs<int64_t>(dfVal))
    2559             :             {
    2560           0 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
    2561             :             }
    2562             :         }
    2563             :         else
    2564             :         {
    2565             :             try
    2566             :             {
    2567           7 :                 const auto val = std::stoll(pszNoData);
    2568           1 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(val));
    2569             :             }
    2570           2 :             catch (const std::exception &)
    2571             :             {
    2572             :             }
    2573             :         }
    2574             :     }
    2575         121 :     else if (eDataType == GDT_UInt64)
    2576             :     {
    2577           2 :         if (strchr(pszNoData, '.') ||
    2578           1 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2579             :         {
    2580           0 :             char *endptr = nullptr;
    2581           0 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2582           0 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2583           0 :                 GDALIsValueExactAs<uint64_t>(dfVal))
    2584             :             {
    2585           0 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
    2586             :             }
    2587             :         }
    2588             :         else
    2589             :         {
    2590             :             try
    2591             :             {
    2592           1 :                 const auto val = std::stoull(pszNoData);
    2593           1 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
    2594             :             }
    2595           0 :             catch (const std::exception &)
    2596             :             {
    2597             :             }
    2598             :         }
    2599             :     }
    2600         120 :     else if (eDataType == GDT_Float32)
    2601             :     {
    2602          10 :         char *endptr = nullptr;
    2603          10 :         const float fVal = CPLStrtof(pszNoData, &endptr);
    2604          10 :         if (endptr == pszNoData + strlen(pszNoData))
    2605             :         {
    2606          10 :             return SetNoDataValue(double(fVal));
    2607             :         }
    2608             :     }
    2609             :     else
    2610             :     {
    2611         110 :         char *endptr = nullptr;
    2612         110 :         const double dfVal = CPLStrtod(pszNoData, &endptr);
    2613         220 :         if (endptr == pszNoData + strlen(pszNoData) &&
    2614         110 :             GDALIsValueExactAs(dfVal, eDataType))
    2615             :         {
    2616         109 :             return SetNoDataValue(dfVal);
    2617             :         }
    2618             :     }
    2619           5 :     if (pbCannotBeExactlyRepresented)
    2620           5 :         *pbCannotBeExactlyRepresented = true;
    2621           5 :     return CE_Failure;
    2622             : }
    2623             : 
    2624             : /************************************************************************/
    2625             : /*                           SetNoDataValue()                           */
    2626             : /************************************************************************/
    2627             : 
    2628             : /**
    2629             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2630             :  * \brief Set the no data value for this band.
    2631             :  *
    2632             :  * Depending on drivers, changing the no data value may or may not have an
    2633             :  * effect on the pixel values of a raster that has just been created. It is
    2634             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2635             :  * the raster to the nodata value.
    2636             :  * In any case, changing an existing no data value, when one already exists and
    2637             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2638             :  * value matched the previous nodata value.
    2639             :  *
    2640             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2641             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2642             :  * SetNoDataValueAsUInt64() instead.
    2643             :  *
    2644             :  * To clear the nodata value, use DeleteNoDataValue().
    2645             :  *
    2646             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2647             :  *
    2648             :  * @param dfNoData the value to set.
    2649             :  *
    2650             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2651             :  * by the driver, CE_Failure is returned but no error message will have
    2652             :  * been emitted.
    2653             :  */
    2654             : 
    2655             : /**/
    2656             : /**/
    2657             : 
    2658           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2659             : 
    2660             : {
    2661           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2662           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2663             :                     "SetNoDataValue() not supported for this dataset.");
    2664             : 
    2665           0 :     return CE_Failure;
    2666             : }
    2667             : 
    2668             : /************************************************************************/
    2669             : /*                      GDALSetRasterNoDataValue()                      */
    2670             : /************************************************************************/
    2671             : 
    2672             : /**
    2673             :  * \brief Set the no data value for this band.
    2674             :  *
    2675             :  * Depending on drivers, changing the no data value may or may not have an
    2676             :  * effect on the pixel values of a raster that has just been created. It is
    2677             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2678             :  * the raster to the nodata value.
    2679             :  * In any case, changing an existing no data value, when one already exists and
    2680             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2681             :  * value matched the previous nodata value.
    2682             :  *
    2683             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2684             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2685             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2686             :  *
    2687             :  * @see GDALRasterBand::SetNoDataValue()
    2688             :  */
    2689             : 
    2690        1277 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2691             :                                             double dfValue)
    2692             : 
    2693             : {
    2694        1277 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2695             : 
    2696        1277 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2697        1277 :     return poBand->SetNoDataValue(dfValue);
    2698             : }
    2699             : 
    2700             : /************************************************************************/
    2701             : /*                       SetNoDataValueAsInt64()                        */
    2702             : /************************************************************************/
    2703             : 
    2704             : /**
    2705             :  * \brief Set the no data value for this band.
    2706             :  *
    2707             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2708             :  *
    2709             :  * Depending on drivers, changing the no data value may or may not have an
    2710             :  * effect on the pixel values of a raster that has just been created. It is
    2711             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2712             :  * the raster to the nodata value.
    2713             :  * In ay case, changing an existing no data value, when one already exists and
    2714             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2715             :  * value matched the previous nodata value.
    2716             :  *
    2717             :  * To clear the nodata value, use DeleteNoDataValue().
    2718             :  *
    2719             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2720             :  *
    2721             :  * @param nNoDataValue the value to set.
    2722             :  *
    2723             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2724             :  * by the driver, CE_Failure is returned but no error message will have
    2725             :  * been emitted.
    2726             :  *
    2727             :  * @since GDAL 3.5
    2728             :  */
    2729             : 
    2730           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2731             : 
    2732             : {
    2733           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2734           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2735             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2736             : 
    2737           0 :     return CE_Failure;
    2738             : }
    2739             : 
    2740             : /************************************************************************/
    2741             : /*                  GDALSetRasterNoDataValueAsInt64()                   */
    2742             : /************************************************************************/
    2743             : 
    2744             : /**
    2745             :  * \brief Set the no data value for this band.
    2746             :  *
    2747             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2748             :  *
    2749             :  * Depending on drivers, changing the no data value may or may not have an
    2750             :  * effect on the pixel values of a raster that has just been created. It is
    2751             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2752             :  * the raster to the nodata value.
    2753             :  * In ay case, changing an existing no data value, when one already exists and
    2754             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2755             :  * value matched the previous nodata value.
    2756             :  *
    2757             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2758             :  *
    2759             :  * @since GDAL 3.5
    2760             :  */
    2761             : 
    2762          24 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2763             :                                                    int64_t nValue)
    2764             : 
    2765             : {
    2766          24 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2767             : 
    2768          24 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2769          24 :     return poBand->SetNoDataValueAsInt64(nValue);
    2770             : }
    2771             : 
    2772             : /************************************************************************/
    2773             : /*                       SetNoDataValueAsUInt64()                       */
    2774             : /************************************************************************/
    2775             : 
    2776             : /**
    2777             :  * \brief Set the no data value for this band.
    2778             :  *
    2779             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2780             :  *
    2781             :  * Depending on drivers, changing the no data value may or may not have an
    2782             :  * effect on the pixel values of a raster that has just been created. It is
    2783             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2784             :  * the raster to the nodata value.
    2785             :  * In ay case, changing an existing no data value, when one already exists and
    2786             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2787             :  * value matched the previous nodata value.
    2788             :  *
    2789             :  * To clear the nodata value, use DeleteNoDataValue().
    2790             :  *
    2791             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2792             :  *
    2793             :  * @param nNoDataValue the value to set.
    2794             :  *
    2795             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2796             :  * by the driver, CE_Failure is returned but no error message will have
    2797             :  * been emitted.
    2798             :  *
    2799             :  * @since GDAL 3.5
    2800             :  */
    2801             : 
    2802           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2803             : 
    2804             : {
    2805           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2806           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2807             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2808             : 
    2809           0 :     return CE_Failure;
    2810             : }
    2811             : 
    2812             : /************************************************************************/
    2813             : /*                  GDALSetRasterNoDataValueAsUInt64()                  */
    2814             : /************************************************************************/
    2815             : 
    2816             : /**
    2817             :  * \brief Set the no data value for this band.
    2818             :  *
    2819             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2820             :  *
    2821             :  * Depending on drivers, changing the no data value may or may not have an
    2822             :  * effect on the pixel values of a raster that has just been created. It is
    2823             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2824             :  * the raster to the nodata value.
    2825             :  * In ay case, changing an existing no data value, when one already exists and
    2826             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2827             :  * value matched the previous nodata value.
    2828             :  *
    2829             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2830             :  *
    2831             :  * @since GDAL 3.5
    2832             :  */
    2833             : 
    2834          23 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2835             :                                                     uint64_t nValue)
    2836             : 
    2837             : {
    2838          23 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2839             : 
    2840          23 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2841          23 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2842             : }
    2843             : 
    2844             : /************************************************************************/
    2845             : /*                         DeleteNoDataValue()                          */
    2846             : /************************************************************************/
    2847             : 
    2848             : /**
    2849             :  * \brief Remove the no data value for this band.
    2850             :  *
    2851             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2852             :  *
    2853             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2854             :  * by the driver, CE_Failure is returned but no error message will have
    2855             :  * been emitted.
    2856             :  *
    2857             :  */
    2858             : 
    2859           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2860             : 
    2861             : {
    2862           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2863           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2864             :                     "DeleteNoDataValue() not supported for this dataset.");
    2865             : 
    2866           0 :     return CE_Failure;
    2867             : }
    2868             : 
    2869             : /************************************************************************/
    2870             : /*                    GDALDeleteRasterNoDataValue()                     */
    2871             : /************************************************************************/
    2872             : 
    2873             : /**
    2874             :  * \brief Remove the no data value for this band.
    2875             :  *
    2876             :  * @see GDALRasterBand::DeleteNoDataValue()
    2877             :  *
    2878             :  */
    2879             : 
    2880          56 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2881             : 
    2882             : {
    2883          56 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2884             : 
    2885          56 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2886          56 :     return poBand->DeleteNoDataValue();
    2887             : }
    2888             : 
    2889             : /************************************************************************/
    2890             : /*                             GetMaximum()                             */
    2891             : /************************************************************************/
    2892             : 
    2893             : /**
    2894             :  * \brief Fetch the maximum value for this band.
    2895             :  *
    2896             :  * For file formats that don't know this intrinsically, the maximum supported
    2897             :  * value for the data type will generally be returned.
    2898             :  *
    2899             :  * This method is the same as the C function GDALGetRasterMaximum().
    2900             :  *
    2901             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2902             :  * returned value is a tight maximum or not.  May be NULL (default).
    2903             :  *
    2904             :  * @return the maximum raster value (excluding no data pixels)
    2905             :  */
    2906             : 
    2907         548 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2908             : 
    2909             : {
    2910         548 :     const char *pszValue = nullptr;
    2911             : 
    2912         548 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2913             :     {
    2914          47 :         if (pbSuccess != nullptr)
    2915          42 :             *pbSuccess = TRUE;
    2916             : 
    2917          47 :         return CPLAtofM(pszValue);
    2918             :     }
    2919             : 
    2920         501 :     if (pbSuccess != nullptr)
    2921         497 :         *pbSuccess = FALSE;
    2922             : 
    2923         501 :     switch (eDataType)
    2924             :     {
    2925         345 :         case GDT_UInt8:
    2926             :         {
    2927         345 :             EnablePixelTypeSignedByteWarning(false);
    2928             :             const char *pszPixelType =
    2929         345 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2930         345 :             EnablePixelTypeSignedByteWarning(true);
    2931         345 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2932           0 :                 return 127;
    2933             : 
    2934         345 :             return 255;
    2935             :         }
    2936             : 
    2937           1 :         case GDT_Int8:
    2938           1 :             return 127;
    2939             : 
    2940          21 :         case GDT_UInt16:
    2941          21 :             return 65535;
    2942             : 
    2943          24 :         case GDT_Int16:
    2944             :         case GDT_CInt16:
    2945          24 :             return 32767;
    2946             : 
    2947          39 :         case GDT_Int32:
    2948             :         case GDT_CInt32:
    2949          39 :             return 2147483647.0;
    2950             : 
    2951          14 :         case GDT_UInt32:
    2952          14 :             return 4294967295.0;
    2953             : 
    2954           1 :         case GDT_Int64:
    2955           1 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2956             : 
    2957           1 :         case GDT_UInt64:
    2958           1 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2959             : 
    2960           0 :         case GDT_Float16:
    2961             :         case GDT_CFloat16:
    2962           0 :             return 65504.0;
    2963             : 
    2964          33 :         case GDT_Float32:
    2965             :         case GDT_CFloat32:
    2966          33 :             return 4294967295.0;  // Not actually accurate.
    2967             : 
    2968          22 :         case GDT_Float64:
    2969             :         case GDT_CFloat64:
    2970          22 :             return 4294967295.0;  // Not actually accurate.
    2971             : 
    2972           0 :         case GDT_Unknown:
    2973             :         case GDT_TypeCount:
    2974           0 :             break;
    2975             :     }
    2976           0 :     return 4294967295.0;  // Not actually accurate.
    2977             : }
    2978             : 
    2979             : /************************************************************************/
    2980             : /*                        GDALGetRasterMaximum()                        */
    2981             : /************************************************************************/
    2982             : 
    2983             : /**
    2984             :  * \brief Fetch the maximum value for this band.
    2985             :  *
    2986             :  * @see GDALRasterBand::GetMaximum()
    2987             :  */
    2988             : 
    2989         350 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2990             : 
    2991             : {
    2992         350 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2993             : 
    2994         350 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2995         350 :     return poBand->GetMaximum(pbSuccess);
    2996             : }
    2997             : 
    2998             : /************************************************************************/
    2999             : /*                             GetMinimum()                             */
    3000             : /************************************************************************/
    3001             : 
    3002             : /**
    3003             :  * \brief Fetch the minimum value for this band.
    3004             :  *
    3005             :  * For file formats that don't know this intrinsically, the minimum supported
    3006             :  * value for the data type will generally be returned.
    3007             :  *
    3008             :  * This method is the same as the C function GDALGetRasterMinimum().
    3009             :  *
    3010             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3011             :  * returned value is a tight minimum or not.  May be NULL (default).
    3012             :  *
    3013             :  * @return the minimum raster value (excluding no data pixels)
    3014             :  */
    3015             : 
    3016         556 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    3017             : 
    3018             : {
    3019         556 :     const char *pszValue = nullptr;
    3020             : 
    3021         556 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    3022             :     {
    3023          52 :         if (pbSuccess != nullptr)
    3024          47 :             *pbSuccess = TRUE;
    3025             : 
    3026          52 :         return CPLAtofM(pszValue);
    3027             :     }
    3028             : 
    3029         504 :     if (pbSuccess != nullptr)
    3030         500 :         *pbSuccess = FALSE;
    3031             : 
    3032         504 :     switch (eDataType)
    3033             :     {
    3034         348 :         case GDT_UInt8:
    3035             :         {
    3036         348 :             EnablePixelTypeSignedByteWarning(false);
    3037             :             const char *pszPixelType =
    3038         348 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    3039         348 :             EnablePixelTypeSignedByteWarning(true);
    3040         348 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    3041           0 :                 return -128;
    3042             : 
    3043         348 :             return 0;
    3044             :         }
    3045             : 
    3046           1 :         case GDT_Int8:
    3047           1 :             return -128;
    3048             : 
    3049          21 :         case GDT_UInt16:
    3050          21 :             return 0;
    3051             : 
    3052          24 :         case GDT_Int16:
    3053             :         case GDT_CInt16:
    3054          24 :             return -32768;
    3055             : 
    3056          39 :         case GDT_Int32:
    3057             :         case GDT_CInt32:
    3058          39 :             return -2147483648.0;
    3059             : 
    3060          14 :         case GDT_UInt32:
    3061          14 :             return 0;
    3062             : 
    3063           1 :         case GDT_Int64:
    3064           1 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    3065             : 
    3066           1 :         case GDT_UInt64:
    3067           1 :             return 0;
    3068             : 
    3069           0 :         case GDT_Float16:
    3070             :         case GDT_CFloat16:
    3071           0 :             return -65504.0;
    3072             : 
    3073          33 :         case GDT_Float32:
    3074             :         case GDT_CFloat32:
    3075          33 :             return -4294967295.0;  // Not actually accurate.
    3076             : 
    3077          22 :         case GDT_Float64:
    3078             :         case GDT_CFloat64:
    3079          22 :             return -4294967295.0;  // Not actually accurate.
    3080             : 
    3081           0 :         case GDT_Unknown:
    3082             :         case GDT_TypeCount:
    3083           0 :             break;
    3084             :     }
    3085           0 :     return -4294967295.0;  // Not actually accurate.
    3086             : }
    3087             : 
    3088             : /************************************************************************/
    3089             : /*                        GDALGetRasterMinimum()                        */
    3090             : /************************************************************************/
    3091             : 
    3092             : /**
    3093             :  * \brief Fetch the minimum value for this band.
    3094             :  *
    3095             :  * @see GDALRasterBand::GetMinimum()
    3096             :  */
    3097             : 
    3098         360 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    3099             : 
    3100             : {
    3101         360 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    3102             : 
    3103         360 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3104         360 :     return poBand->GetMinimum(pbSuccess);
    3105             : }
    3106             : 
    3107             : /************************************************************************/
    3108             : /*                       GetColorInterpretation()                       */
    3109             : /************************************************************************/
    3110             : 
    3111             : /**
    3112             :  * \brief How should this band be interpreted as color?
    3113             :  *
    3114             :  * GCI_Undefined is returned when the format doesn't know anything
    3115             :  * about the color interpretation.
    3116             :  *
    3117             :  * This method is the same as the C function
    3118             :  * GDALGetRasterColorInterpretation().
    3119             :  *
    3120             :  * @return color interpretation value for band.
    3121             :  */
    3122             : 
    3123         163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    3124             : 
    3125             : {
    3126         163 :     return GCI_Undefined;
    3127             : }
    3128             : 
    3129             : /************************************************************************/
    3130             : /*                  GDALGetRasterColorInterpretation()                  */
    3131             : /************************************************************************/
    3132             : 
    3133             : /**
    3134             :  * \brief How should this band be interpreted as color?
    3135             :  *
    3136             :  * @see GDALRasterBand::GetColorInterpretation()
    3137             :  */
    3138             : 
    3139             : GDALColorInterp CPL_STDCALL
    3140        6441 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    3141             : 
    3142             : {
    3143        6441 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    3144             : 
    3145        6441 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3146        6441 :     return poBand->GetColorInterpretation();
    3147             : }
    3148             : 
    3149             : /************************************************************************/
    3150             : /*                       SetColorInterpretation()                       */
    3151             : /************************************************************************/
    3152             : 
    3153             : /**
    3154             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3155             :  * \brief Set color interpretation of a band.
    3156             :  *
    3157             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3158             :  *
    3159             :  * @param eColorInterp the new color interpretation to apply to this band.
    3160             :  *
    3161             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3162             :  */
    3163             : 
    3164             : /**/
    3165             : /**/
    3166             : 
    3167           1 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3168             : 
    3169             : {
    3170           1 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3171           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    3172             :                     "SetColorInterpretation() not supported for this dataset.");
    3173           1 :     return CE_Failure;
    3174             : }
    3175             : 
    3176             : /************************************************************************/
    3177             : /*                  GDALSetRasterColorInterpretation()                  */
    3178             : /************************************************************************/
    3179             : 
    3180             : /**
    3181             :  * \brief Set color interpretation of a band.
    3182             :  *
    3183             :  * @see GDALRasterBand::SetColorInterpretation()
    3184             :  */
    3185             : 
    3186        1891 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3187             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3188             : 
    3189             : {
    3190        1891 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3191             : 
    3192        1891 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3193        1891 :     return poBand->SetColorInterpretation(eColorInterp);
    3194             : }
    3195             : 
    3196             : /************************************************************************/
    3197             : /*                           GetColorTable()                            */
    3198             : /************************************************************************/
    3199             : 
    3200             : /**
    3201             :  * \brief Fetch the color table associated with band.
    3202             :  *
    3203             :  * If there is no associated color table, the return result is NULL.  The
    3204             :  * returned color table remains owned by the GDALRasterBand, and can't
    3205             :  * be depended on for long, nor should it ever be modified by the caller.
    3206             :  *
    3207             :  * This method is the same as the C function GDALGetRasterColorTable().
    3208             :  *
    3209             :  * @return internal color table, or NULL.
    3210             :  */
    3211             : 
    3212         203 : GDALColorTable *GDALRasterBand::GetColorTable()
    3213             : 
    3214             : {
    3215         203 :     return nullptr;
    3216             : }
    3217             : 
    3218             : /************************************************************************/
    3219             : /*                      GDALGetRasterColorTable()                       */
    3220             : /************************************************************************/
    3221             : 
    3222             : /**
    3223             :  * \brief Fetch the color table associated with band.
    3224             :  *
    3225             :  * @see GDALRasterBand::GetColorTable()
    3226             :  */
    3227             : 
    3228        2202 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3229             : 
    3230             : {
    3231        2202 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3232             : 
    3233        2202 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3234        2202 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3235             : }
    3236             : 
    3237             : /************************************************************************/
    3238             : /*                           SetColorTable()                            */
    3239             : /************************************************************************/
    3240             : 
    3241             : /**
    3242             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3243             :  * \brief Set the raster color table.
    3244             :  *
    3245             :  * The driver will make a copy of all desired data in the colortable.  It
    3246             :  * remains owned by the caller after the call.
    3247             :  *
    3248             :  * This method is the same as the C function GDALSetRasterColorTable().
    3249             :  *
    3250             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3251             :  * table (where supported).
    3252             :  *
    3253             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3254             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3255             :  * error is issued.
    3256             :  */
    3257             : 
    3258             : /**/
    3259             : /**/
    3260             : 
    3261           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3262             : 
    3263             : {
    3264           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3265           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3266             :                     "SetColorTable() not supported for this dataset.");
    3267           0 :     return CE_Failure;
    3268             : }
    3269             : 
    3270             : /************************************************************************/
    3271             : /*                      GDALSetRasterColorTable()                       */
    3272             : /************************************************************************/
    3273             : 
    3274             : /**
    3275             :  * \brief Set the raster color table.
    3276             :  *
    3277             :  * @see GDALRasterBand::SetColorTable()
    3278             :  */
    3279             : 
    3280         105 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3281             :                                            GDALColorTableH hCT)
    3282             : 
    3283             : {
    3284         105 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3285             : 
    3286         105 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3287         105 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3288             : }
    3289             : 
    3290             : /************************************************************************/
    3291             : /*                       HasArbitraryOverviews()                        */
    3292             : /************************************************************************/
    3293             : 
    3294             : /**
    3295             :  * \brief Check for arbitrary overviews.
    3296             :  *
    3297             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3298             :  * overviews efficiently, such as is the case with OGDI over a network.
    3299             :  * Datastores with arbitrary overviews don't generally have any fixed
    3300             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3301             :  * to get overview data efficiently.
    3302             :  *
    3303             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3304             :  *
    3305             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3306             :  * FALSE.
    3307             :  */
    3308             : 
    3309         279 : int GDALRasterBand::HasArbitraryOverviews()
    3310             : 
    3311             : {
    3312         279 :     return FALSE;
    3313             : }
    3314             : 
    3315             : /************************************************************************/
    3316             : /*                     GDALHasArbitraryOverviews()                      */
    3317             : /************************************************************************/
    3318             : 
    3319             : /**
    3320             :  * \brief Check for arbitrary overviews.
    3321             :  *
    3322             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3323             :  */
    3324             : 
    3325         200 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3326             : 
    3327             : {
    3328         200 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3329             : 
    3330         200 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3331         200 :     return poBand->HasArbitraryOverviews();
    3332             : }
    3333             : 
    3334             : /************************************************************************/
    3335             : /*                          GetOverviewCount()                          */
    3336             : /************************************************************************/
    3337             : 
    3338             : /**
    3339             :  * \brief Return the number of overview layers available.
    3340             :  *
    3341             :  * This method is the same as the C function GDALGetOverviewCount().
    3342             :  *
    3343             :  * @return overview count, zero if none.
    3344             :  */
    3345             : 
    3346     1077360 : int GDALRasterBand::GetOverviewCount()
    3347             : 
    3348             : {
    3349     1734440 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3350      657087 :         poDS->AreOverviewsEnabled())
    3351      657087 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3352             : 
    3353      420268 :     return 0;
    3354             : }
    3355             : 
    3356             : /************************************************************************/
    3357             : /*                        GDALGetOverviewCount()                        */
    3358             : /************************************************************************/
    3359             : 
    3360             : /**
    3361             :  * \brief Return the number of overview layers available.
    3362             :  *
    3363             :  * @see GDALRasterBand::GetOverviewCount()
    3364             :  */
    3365             : 
    3366        3329 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3367             : 
    3368             : {
    3369        3329 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3370             : 
    3371        3329 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3372        3329 :     return poBand->GetOverviewCount();
    3373             : }
    3374             : 
    3375             : /************************************************************************/
    3376             : /*                            GetOverview()                             */
    3377             : /************************************************************************/
    3378             : 
    3379             : /**
    3380             :  * \brief Fetch overview raster band object.
    3381             :  *
    3382             :  * This method is the same as the C function GDALGetOverview().
    3383             :  *
    3384             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3385             :  *
    3386             :  * @return overview GDALRasterBand.
    3387             :  */
    3388             : 
    3389         944 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3390             : 
    3391             : {
    3392        1735 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3393         791 :         poDS->AreOverviewsEnabled())
    3394         791 :         return poDS->oOvManager.GetOverview(nBand, i);
    3395             : 
    3396         153 :     return nullptr;
    3397             : }
    3398             : 
    3399             : /************************************************************************/
    3400             : /*                          GDALGetOverview()                           */
    3401             : /************************************************************************/
    3402             : 
    3403             : /**
    3404             :  * \brief Fetch overview raster band object.
    3405             :  *
    3406             :  * @see GDALRasterBand::GetOverview()
    3407             :  */
    3408             : 
    3409        5672 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3410             : 
    3411             : {
    3412        5672 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3413             : 
    3414        5672 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3415        5672 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3416             : }
    3417             : 
    3418             : /************************************************************************/
    3419             : /*                      GetRasterSampleOverview()                       */
    3420             : /************************************************************************/
    3421             : 
    3422             : /**
    3423             :  * \brief Fetch best sampling overview.
    3424             :  *
    3425             :  * Returns the most reduced overview of the given band that still satisfies
    3426             :  * the desired number of samples.  This function can be used with zero
    3427             :  * as the number of desired samples to fetch the most reduced overview.
    3428             :  * The same band as was passed in will be returned if it has not overviews,
    3429             :  * or if none of the overviews have enough samples.
    3430             :  *
    3431             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3432             :  * and GDALGetRasterSampleOverviewEx().
    3433             :  *
    3434             :  * @param nDesiredSamples the returned band will have at least this many
    3435             :  * pixels.
    3436             :  *
    3437             :  * @return optimal overview or the band itself.
    3438             :  */
    3439             : 
    3440             : GDALRasterBand *
    3441        2009 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3442             : 
    3443             : {
    3444        2009 :     GDALRasterBand *poBestBand = this;
    3445             : 
    3446        2009 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3447             : 
    3448        4029 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3449             :     {
    3450        2020 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3451             : 
    3452        2020 :         if (poOBand == nullptr)
    3453           0 :             continue;
    3454             : 
    3455             :         const double dfOSamples =
    3456        2020 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3457             : 
    3458        2020 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3459             :         {
    3460        2017 :             dfBestSamples = dfOSamples;
    3461        2017 :             poBestBand = poOBand;
    3462             :         }
    3463             :     }
    3464             : 
    3465        2009 :     return poBestBand;
    3466             : }
    3467             : 
    3468             : /************************************************************************/
    3469             : /*                    GDALGetRasterSampleOverview()                     */
    3470             : /************************************************************************/
    3471             : 
    3472             : /**
    3473             :  * \brief Fetch best sampling overview.
    3474             :  *
    3475             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3476             :  * billion samples.
    3477             :  *
    3478             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3479             :  * @see GDALGetRasterSampleOverviewEx()
    3480             :  */
    3481             : 
    3482           0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3483             :                                                         int nDesiredSamples)
    3484             : 
    3485             : {
    3486           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3487             : 
    3488           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3489           0 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3490           0 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3491             : }
    3492             : 
    3493             : /************************************************************************/
    3494             : /*                   GDALGetRasterSampleOverviewEx()                    */
    3495             : /************************************************************************/
    3496             : 
    3497             : /**
    3498             :  * \brief Fetch best sampling overview.
    3499             :  *
    3500             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3501             :  */
    3502             : 
    3503             : GDALRasterBandH CPL_STDCALL
    3504        2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3505             : 
    3506             : {
    3507        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3508             : 
    3509        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3510        2000 :     return GDALRasterBand::ToHandle(
    3511        4000 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3512             : }
    3513             : 
    3514             : /************************************************************************/
    3515             : /*                           BuildOverviews()                           */
    3516             : /************************************************************************/
    3517             : 
    3518             : /**
    3519             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3520             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3521             :  *
    3522             :  * If the operation is unsupported for the indicated dataset, then
    3523             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3524             :  * CPLE_NotSupported.
    3525             :  *
    3526             :  * WARNING: Most formats don't support per-band overview computation, but
    3527             :  * require that overviews are computed for all bands of a dataset, using
    3528             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3529             :  * is the HFA driver which supports this method.
    3530             :  *
    3531             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3532             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3533             :  * applied.
    3534             :  * @param nOverviews number of overviews to build.
    3535             :  * @param panOverviewList the list of overview decimation factors to build.
    3536             :  * @param pfnProgress a function to call to report progress, or NULL.
    3537             :  * @param pProgressData application data to pass to the progress function.
    3538             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3539             :  *                     key=value pairs, or NULL
    3540             :  *
    3541             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3542             :  */
    3543             : 
    3544             : /**/
    3545             : /**/
    3546             : 
    3547           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3548             :                                       int /*nOverviews*/,
    3549             :                                       const int * /*panOverviewList*/,
    3550             :                                       GDALProgressFunc /*pfnProgress*/,
    3551             :                                       void * /*pProgressData*/,
    3552             :                                       CSLConstList /* papszOptions */)
    3553             : 
    3554             : {
    3555           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3556             :                 "BuildOverviews() not supported for this dataset.");
    3557             : 
    3558           0 :     return (CE_Failure);
    3559             : }
    3560             : 
    3561             : /************************************************************************/
    3562             : /*                             GetOffset()                              */
    3563             : /************************************************************************/
    3564             : 
    3565             : /**
    3566             :  * \brief Fetch the raster value offset.
    3567             :  *
    3568             :  * This value (in combination with the GetScale() value) can be used to
    3569             :  * transform raw pixel values into the units returned by GetUnitType().
    3570             :  * For example this might be used to store elevations in GUInt16 bands
    3571             :  * with a precision of 0.1, and starting from -100.
    3572             :  *
    3573             :  * Units value = (raw value * scale) + offset
    3574             :  *
    3575             :  * Note that applying scale and offset is of the responsibility of the user,
    3576             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3577             :  *
    3578             :  * For file formats that don't know this intrinsically a value of zero
    3579             :  * is returned.
    3580             :  *
    3581             :  * This method is the same as the C function GDALGetRasterOffset().
    3582             :  *
    3583             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3584             :  * returned value is meaningful or not.  May be NULL (default).
    3585             :  *
    3586             :  * @return the raster offset.
    3587             :  */
    3588             : 
    3589         510 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3590             : 
    3591             : {
    3592         510 :     if (pbSuccess != nullptr)
    3593         333 :         *pbSuccess = FALSE;
    3594             : 
    3595         510 :     return 0.0;
    3596             : }
    3597             : 
    3598             : /************************************************************************/
    3599             : /*                        GDALGetRasterOffset()                         */
    3600             : /************************************************************************/
    3601             : 
    3602             : /**
    3603             :  * \brief Fetch the raster value offset.
    3604             :  *
    3605             :  * @see GDALRasterBand::GetOffset()
    3606             :  */
    3607             : 
    3608         423 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3609             : 
    3610             : {
    3611         423 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3612             : 
    3613         423 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3614         423 :     return poBand->GetOffset(pbSuccess);
    3615             : }
    3616             : 
    3617             : /************************************************************************/
    3618             : /*                             SetOffset()                              */
    3619             : /************************************************************************/
    3620             : 
    3621             : /**
    3622             :  * \fn GDALRasterBand::SetOffset(double)
    3623             :  * \brief Set scaling offset.
    3624             :  *
    3625             :  * Very few formats implement this method.   When not implemented it will
    3626             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3627             :  *
    3628             :  * This method is the same as the C function GDALSetRasterOffset().
    3629             :  *
    3630             :  * @param dfNewOffset the new offset.
    3631             :  *
    3632             :  * @return CE_None or success or CE_Failure on failure.
    3633             :  */
    3634             : 
    3635             : /**/
    3636             : /**/
    3637             : 
    3638           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3639             : {
    3640           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3641           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3642             :                     "SetOffset() not supported on this raster band.");
    3643             : 
    3644           0 :     return CE_Failure;
    3645             : }
    3646             : 
    3647             : /************************************************************************/
    3648             : /*                        GDALSetRasterOffset()                         */
    3649             : /************************************************************************/
    3650             : 
    3651             : /**
    3652             :  * \brief Set scaling offset.
    3653             :  *
    3654             :  * @see GDALRasterBand::SetOffset()
    3655             :  */
    3656             : 
    3657          86 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3658             :                                        double dfNewOffset)
    3659             : 
    3660             : {
    3661          86 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3662             : 
    3663          86 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3664          86 :     return poBand->SetOffset(dfNewOffset);
    3665             : }
    3666             : 
    3667             : /************************************************************************/
    3668             : /*                              GetScale()                              */
    3669             : /************************************************************************/
    3670             : 
    3671             : /**
    3672             :  * \brief Fetch the raster value scale.
    3673             :  *
    3674             :  * This value (in combination with the GetOffset() value) can be used to
    3675             :  * transform raw pixel values into the units returned by GetUnitType().
    3676             :  * For example this might be used to store elevations in GUInt16 bands
    3677             :  * with a precision of 0.1, and starting from -100.
    3678             :  *
    3679             :  * Units value = (raw value * scale) + offset
    3680             :  *
    3681             :  * Note that applying scale and offset is of the responsibility of the user,
    3682             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3683             :  *
    3684             :  * For file formats that don't know this intrinsically a value of one
    3685             :  * is returned.
    3686             :  *
    3687             :  * This method is the same as the C function GDALGetRasterScale().
    3688             :  *
    3689             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3690             :  * returned value is meaningful or not.  May be NULL (default).
    3691             :  *
    3692             :  * @return the raster scale.
    3693             :  */
    3694             : 
    3695         510 : double GDALRasterBand::GetScale(int *pbSuccess)
    3696             : 
    3697             : {
    3698         510 :     if (pbSuccess != nullptr)
    3699         333 :         *pbSuccess = FALSE;
    3700             : 
    3701         510 :     return 1.0;
    3702             : }
    3703             : 
    3704             : /************************************************************************/
    3705             : /*                         GDALGetRasterScale()                         */
    3706             : /************************************************************************/
    3707             : 
    3708             : /**
    3709             :  * \brief Fetch the raster value scale.
    3710             :  *
    3711             :  * @see GDALRasterBand::GetScale()
    3712             :  */
    3713             : 
    3714         421 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3715             : 
    3716             : {
    3717         421 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3718             : 
    3719         421 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3720         421 :     return poBand->GetScale(pbSuccess);
    3721             : }
    3722             : 
    3723             : /************************************************************************/
    3724             : /*                              SetScale()                              */
    3725             : /************************************************************************/
    3726             : 
    3727             : /**
    3728             :  * \fn GDALRasterBand::SetScale(double)
    3729             :  * \brief Set scaling ratio.
    3730             :  *
    3731             :  * Very few formats implement this method.   When not implemented it will
    3732             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3733             :  *
    3734             :  * This method is the same as the C function GDALSetRasterScale().
    3735             :  *
    3736             :  * @param dfNewScale the new scale.
    3737             :  *
    3738             :  * @return CE_None or success or CE_Failure on failure.
    3739             :  */
    3740             : 
    3741             : /**/
    3742             : /**/
    3743             : 
    3744           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3745             : 
    3746             : {
    3747           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3748           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3749             :                     "SetScale() not supported on this raster band.");
    3750             : 
    3751           0 :     return CE_Failure;
    3752             : }
    3753             : 
    3754             : /************************************************************************/
    3755             : /*                         GDALSetRasterScale()                         */
    3756             : /************************************************************************/
    3757             : 
    3758             : /**
    3759             :  * \brief Set scaling ratio.
    3760             :  *
    3761             :  * @see GDALRasterBand::SetScale()
    3762             :  */
    3763             : 
    3764          87 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3765             : 
    3766             : {
    3767          87 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3768             : 
    3769          87 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3770          87 :     return poBand->SetScale(dfNewOffset);
    3771             : }
    3772             : 
    3773             : /************************************************************************/
    3774             : /*                            GetUnitType()                             */
    3775             : /************************************************************************/
    3776             : 
    3777             : /**
    3778             :  * \brief Return raster unit type.
    3779             :  *
    3780             :  * Return a name for the units of this raster's values.  For instance, it
    3781             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3782             :  * units are available, a value of "" will be returned.  The returned string
    3783             :  * should not be modified, nor freed by the calling application.
    3784             :  *
    3785             :  * This method is the same as the C function GDALGetRasterUnitType().
    3786             :  *
    3787             :  * @return unit name string.
    3788             :  */
    3789             : 
    3790         181 : const char *GDALRasterBand::GetUnitType()
    3791             : 
    3792             : {
    3793         181 :     return "";
    3794             : }
    3795             : 
    3796             : /************************************************************************/
    3797             : /*                       GDALGetRasterUnitType()                        */
    3798             : /************************************************************************/
    3799             : 
    3800             : /**
    3801             :  * \brief Return raster unit type.
    3802             :  *
    3803             :  * @see GDALRasterBand::GetUnitType()
    3804             :  */
    3805             : 
    3806        1748 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3807             : 
    3808             : {
    3809        1748 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3810             : 
    3811        1748 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3812        1748 :     return poBand->GetUnitType();
    3813             : }
    3814             : 
    3815             : /************************************************************************/
    3816             : /*                            SetUnitType()                             */
    3817             : /************************************************************************/
    3818             : 
    3819             : /**
    3820             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3821             :  * \brief Set unit type.
    3822             :  *
    3823             :  * Set the unit type for a raster band.  Values should be one of
    3824             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3825             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3826             :  *
    3827             :  * This method is the same as the C function GDALSetRasterUnitType().
    3828             :  *
    3829             :  * @param pszNewValue the new unit type value.
    3830             :  *
    3831             :  * @return CE_None on success or CE_Failure if not successful, or
    3832             :  * unsupported.
    3833             :  */
    3834             : 
    3835             : /**/
    3836             : /**/
    3837             : 
    3838           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3839             : 
    3840             : {
    3841           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3842           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3843             :                     "SetUnitType() not supported on this raster band.");
    3844           0 :     return CE_Failure;
    3845             : }
    3846             : 
    3847             : /************************************************************************/
    3848             : /*                       GDALSetRasterUnitType()                        */
    3849             : /************************************************************************/
    3850             : 
    3851             : /**
    3852             :  * \brief Set unit type.
    3853             :  *
    3854             :  * @see GDALRasterBand::SetUnitType()
    3855             :  *
    3856             :  */
    3857             : 
    3858         124 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3859             :                                          const char *pszNewValue)
    3860             : 
    3861             : {
    3862         124 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3863             : 
    3864         124 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3865         124 :     return poBand->SetUnitType(pszNewValue);
    3866             : }
    3867             : 
    3868             : /************************************************************************/
    3869             : /*                              GetXSize()                              */
    3870             : /************************************************************************/
    3871             : 
    3872             : /**
    3873             :  * \brief Fetch XSize of raster.
    3874             :  *
    3875             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3876             :  *
    3877             :  * @return the width in pixels of this band.
    3878             :  */
    3879             : 
    3880     8577500 : int GDALRasterBand::GetXSize() const
    3881             : 
    3882             : {
    3883     8577500 :     return nRasterXSize;
    3884             : }
    3885             : 
    3886             : /************************************************************************/
    3887             : /*                       GDALGetRasterBandXSize()                       */
    3888             : /************************************************************************/
    3889             : 
    3890             : /**
    3891             :  * \brief Fetch XSize of raster.
    3892             :  *
    3893             :  * @see GDALRasterBand::GetXSize()
    3894             :  */
    3895             : 
    3896       58338 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3897             : 
    3898             : {
    3899       58338 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3900             : 
    3901       58338 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3902       58338 :     return poBand->GetXSize();
    3903             : }
    3904             : 
    3905             : /************************************************************************/
    3906             : /*                              GetYSize()                              */
    3907             : /************************************************************************/
    3908             : 
    3909             : /**
    3910             :  * \brief Fetch YSize of raster.
    3911             :  *
    3912             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3913             :  *
    3914             :  * @return the height in pixels of this band.
    3915             :  */
    3916             : 
    3917     4767290 : int GDALRasterBand::GetYSize() const
    3918             : 
    3919             : {
    3920     4767290 :     return nRasterYSize;
    3921             : }
    3922             : 
    3923             : /************************************************************************/
    3924             : /*                       GDALGetRasterBandYSize()                       */
    3925             : /************************************************************************/
    3926             : 
    3927             : /**
    3928             :  * \brief Fetch YSize of raster.
    3929             :  *
    3930             :  * @see GDALRasterBand::GetYSize()
    3931             :  */
    3932             : 
    3933       57201 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3934             : 
    3935             : {
    3936       57201 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3937             : 
    3938       57201 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3939       57201 :     return poBand->GetYSize();
    3940             : }
    3941             : 
    3942             : /************************************************************************/
    3943             : /*                              GetBand()                               */
    3944             : /************************************************************************/
    3945             : 
    3946             : /**
    3947             :  * \brief Fetch the band number.
    3948             :  *
    3949             :  * This method returns the band that this GDALRasterBand objects represents
    3950             :  * within its dataset.  This method may return a value of 0 to indicate
    3951             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3952             :  * such as GDALRasterBands serving as overviews.
    3953             :  *
    3954             :  * This method is the same as the C function GDALGetBandNumber().
    3955             :  *
    3956             :  * @return band number (1+) or 0 if the band number isn't known.
    3957             :  */
    3958             : 
    3959      151661 : int GDALRasterBand::GetBand() const
    3960             : 
    3961             : {
    3962      151661 :     return nBand;
    3963             : }
    3964             : 
    3965             : /************************************************************************/
    3966             : /*                         GDALGetBandNumber()                          */
    3967             : /************************************************************************/
    3968             : 
    3969             : /**
    3970             :  * \brief Fetch the band number.
    3971             :  *
    3972             :  * @see GDALRasterBand::GetBand()
    3973             :  */
    3974             : 
    3975         159 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3976             : 
    3977             : {
    3978         159 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3979             : 
    3980         159 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3981         159 :     return poBand->GetBand();
    3982             : }
    3983             : 
    3984             : /************************************************************************/
    3985             : /*                             GetDataset()                             */
    3986             : /************************************************************************/
    3987             : 
    3988             : /**
    3989             :  * \brief Fetch the owning dataset handle.
    3990             :  *
    3991             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3992             :  * such as overviews or other "freestanding" bands.
    3993             :  *
    3994             :  * This method is the same as the C function GDALGetBandDataset().
    3995             :  *
    3996             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3997             :  * NULL if this cannot be determined.
    3998             :  */
    3999             : 
    4000     4991710 : GDALDataset *GDALRasterBand::GetDataset() const
    4001             : 
    4002             : {
    4003     4991710 :     return poDS;
    4004             : }
    4005             : 
    4006             : /************************************************************************/
    4007             : /*                         GDALGetBandDataset()                         */
    4008             : /************************************************************************/
    4009             : 
    4010             : /**
    4011             :  * \brief Fetch the owning dataset handle.
    4012             :  *
    4013             :  * @see GDALRasterBand::GetDataset()
    4014             :  */
    4015             : 
    4016         360 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    4017             : 
    4018             : {
    4019         360 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    4020             : 
    4021         360 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4022         360 :     return GDALDataset::ToHandle(poBand->GetDataset());
    4023             : }
    4024             : 
    4025             : /************************************************************************/
    4026             : /*                     ComputeFloat16NoDataValue()                      */
    4027             : /************************************************************************/
    4028             : 
    4029        3284 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    4030             :                                              double dfNoDataValue,
    4031             :                                              int &bGotNoDataValue,
    4032             :                                              GFloat16 &hfNoDataValue,
    4033             :                                              bool &bGotFloat16NoDataValue)
    4034             : {
    4035        3284 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    4036             :     {
    4037           7 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4038           7 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    4039             :         {
    4040           7 :             hfNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    4041           7 :             bGotFloat16NoDataValue = true;
    4042           7 :             bGotNoDataValue = false;
    4043             :         }
    4044             :     }
    4045        3284 : }
    4046             : 
    4047             : /************************************************************************/
    4048             : /*                      ComputeFloatNoDataValue()                       */
    4049             : /************************************************************************/
    4050             : 
    4051        3284 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    4052             :                                            double dfNoDataValue,
    4053             :                                            int &bGotNoDataValue,
    4054             :                                            float &fNoDataValue,
    4055             :                                            bool &bGotFloatNoDataValue)
    4056             : {
    4057        3284 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    4058             :     {
    4059         117 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4060         117 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    4061             :         {
    4062         117 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    4063         117 :             bGotFloatNoDataValue = true;
    4064         117 :             bGotNoDataValue = false;
    4065             :         }
    4066             :     }
    4067        3280 :     else if (eDataType == GDT_Int16 && bGotNoDataValue &&
    4068         113 :              GDALIsValueExactAs<int16_t>(dfNoDataValue))
    4069             :     {
    4070         113 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4071         113 :         bGotFloatNoDataValue = true;
    4072             :     }
    4073        3087 :     else if (eDataType == GDT_UInt16 && bGotNoDataValue &&
    4074          33 :              GDALIsValueExactAs<uint16_t>(dfNoDataValue))
    4075             :     {
    4076          33 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4077          33 :         bGotFloatNoDataValue = true;
    4078             :     }
    4079        3028 :     else if (eDataType == GDT_Float16 && bGotNoDataValue &&
    4080           7 :              GDALIsValueExactAs<GFloat16>(dfNoDataValue))
    4081             :     {
    4082           7 :         fNoDataValue = static_cast<float>(dfNoDataValue);
    4083           7 :         bGotFloatNoDataValue = true;
    4084             :     }
    4085        3284 : }
    4086             : 
    4087             : /************************************************************************/
    4088             : /*                       struct GDALNoDataValues                        */
    4089             : /************************************************************************/
    4090             : 
    4091             : /**
    4092             :  * \brief No-data-values for all types
    4093             :  *
    4094             :  * The functions below pass various no-data-values around. To avoid
    4095             :  * long argument lists, this struct collects the no-data-values for
    4096             :  * all types into a single, convenient place.
    4097             :  **/
    4098             : 
    4099             : struct GDALNoDataValues
    4100             : {
    4101             :     int bGotNoDataValue;
    4102             :     double dfNoDataValue;
    4103             : 
    4104             :     bool bGotInt64NoDataValue;
    4105             :     int64_t nInt64NoDataValue;
    4106             : 
    4107             :     bool bGotUInt64NoDataValue;
    4108             :     uint64_t nUInt64NoDataValue;
    4109             : 
    4110             :     bool bGotFloatNoDataValue;
    4111             :     float fNoDataValue;
    4112             : 
    4113             :     bool bGotFloat16NoDataValue;
    4114             :     GFloat16 hfNoDataValue;
    4115             : 
    4116        3384 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    4117        3384 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    4118             :           bGotInt64NoDataValue(false), nInt64NoDataValue(0),
    4119             :           bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
    4120             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    4121        3384 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    4122             :     {
    4123        3384 :         if (eDataType == GDT_Int64)
    4124             :         {
    4125          62 :             int nGot = false;
    4126          62 :             nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
    4127          62 :             bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
    4128          62 :             if (bGotInt64NoDataValue)
    4129             :             {
    4130          10 :                 dfNoDataValue = static_cast<double>(nInt64NoDataValue);
    4131          10 :                 bGotNoDataValue =
    4132          10 :                     nInt64NoDataValue <=
    4133          20 :                         std::numeric_limits<int64_t>::max() - 1024 &&
    4134          10 :                     static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
    4135             :             }
    4136             :             else
    4137          52 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4138             :         }
    4139        3322 :         else if (eDataType == GDT_UInt64)
    4140             :         {
    4141          38 :             int nGot = false;
    4142          38 :             nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
    4143          38 :             bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
    4144          38 :             if (bGotUInt64NoDataValue)
    4145             :             {
    4146          10 :                 dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
    4147          10 :                 bGotNoDataValue =
    4148          10 :                     nUInt64NoDataValue <=
    4149          20 :                         std::numeric_limits<uint64_t>::max() - 2048 &&
    4150          10 :                     static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
    4151             :             }
    4152             :             else
    4153          28 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4154             :         }
    4155             :         else
    4156             :         {
    4157        3284 :             dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4158        3284 :             bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4159             : 
    4160        3284 :             ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4161        3284 :                                     fNoDataValue, bGotFloatNoDataValue);
    4162             : 
    4163        3284 :             ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4164        3284 :                                       hfNoDataValue, bGotFloat16NoDataValue);
    4165             :         }
    4166        3384 :     }
    4167             : };
    4168             : 
    4169             : /************************************************************************/
    4170             : /*                           ARE_REAL_EQUAL()                           */
    4171             : /************************************************************************/
    4172             : 
    4173          28 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
    4174             : {
    4175             :     using std::abs;
    4176          56 :     return dfVal1 == dfVal2 || /* Should cover infinity */
    4177          28 :            abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
    4178          28 :                                       abs(dfVal1 + dfVal2) * ulp;
    4179             : }
    4180             : 
    4181             : /************************************************************************/
    4182             : /*                            GetHistogram()                            */
    4183             : /************************************************************************/
    4184             : 
    4185             : /**
    4186             :  * \brief Compute raster histogram.
    4187             :  *
    4188             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    4189             :  *
    4190             :  * For example to compute a simple 256 entry histogram of eight bit data,
    4191             :  * the following would be suitable.  The unusual bounds are to ensure that
    4192             :  * bucket boundaries don't fall right on integer values causing possible errors
    4193             :  * due to rounding after scaling.
    4194             : \code{.cpp}
    4195             :     GUIntBig anHistogram[256];
    4196             : 
    4197             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    4198             :                           GDALDummyProgress, nullptr );
    4199             : \endcode
    4200             :  *
    4201             :  * Note that setting bApproxOK will generally result in a subsampling of the
    4202             :  * file, and will utilize overviews if available.  It should generally
    4203             :  * produce a representative histogram for the data that is suitable for use
    4204             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    4205             :  * much faster than an exactly computed histogram.
    4206             :  *
    4207             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    4208             :  * GDALGetRasterHistogramEx().
    4209             :  *
    4210             :  * @param dfMin the lower bound of the histogram.
    4211             :  * @param dfMax the upper bound of the histogram.
    4212             :  * @param nBuckets the number of buckets in panHistogram.
    4213             :  * @param panHistogram array into which the histogram totals are placed.
    4214             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    4215             :  * mapped into panHistogram[0], and values above will be mapped into
    4216             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4217             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4218             :  * @param pfnProgress function to report progress to completion.
    4219             :  * @param pProgressData application data to pass to pfnProgress.
    4220             :  *
    4221             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4222             :  */
    4223             : 
    4224          45 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4225             :                                     GUIntBig *panHistogram,
    4226             :                                     int bIncludeOutOfRange, int bApproxOK,
    4227             :                                     GDALProgressFunc pfnProgress,
    4228             :                                     void *pProgressData)
    4229             : 
    4230             : {
    4231          45 :     CPLAssert(nullptr != panHistogram);
    4232             : 
    4233          45 :     if (pfnProgress == nullptr)
    4234          29 :         pfnProgress = GDALDummyProgress;
    4235             : 
    4236             :     /* -------------------------------------------------------------------- */
    4237             :     /*      If we have overviews, use them for the histogram.               */
    4238             :     /* -------------------------------------------------------------------- */
    4239          45 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4240             :     {
    4241             :         // FIXME: should we use the most reduced overview here or use some
    4242             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4243             :         // does?
    4244           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4245             : 
    4246           0 :         if (poBestOverview != this)
    4247             :         {
    4248           0 :             return poBestOverview->GetHistogram(
    4249             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4250           0 :                 bApproxOK, pfnProgress, pProgressData);
    4251             :         }
    4252             :     }
    4253             : 
    4254             :     /* -------------------------------------------------------------------- */
    4255             :     /*      Read actual data and build histogram.                           */
    4256             :     /* -------------------------------------------------------------------- */
    4257          45 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4258             :     {
    4259           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4260           0 :         return CE_Failure;
    4261             :     }
    4262             : 
    4263             :     // Written this way to deal with NaN
    4264          45 :     if (!(dfMax > dfMin))
    4265             :     {
    4266           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4267             :                     "dfMax should be strictly greater than dfMin");
    4268           5 :         return CE_Failure;
    4269             :     }
    4270             : 
    4271             :     GDALRasterIOExtraArg sExtraArg;
    4272          40 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4273             : 
    4274          40 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4275          40 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4276             :     {
    4277           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4278             :                     "dfMin and dfMax should be finite values such that "
    4279             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4280           5 :         return CE_Failure;
    4281             :     }
    4282          35 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4283             : 
    4284          35 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4285          35 :     GDALRasterBand *poMaskBand = nullptr;
    4286          35 :     if (!sNoDataValues.bGotNoDataValue)
    4287             :     {
    4288          34 :         const int l_nMaskFlags = GetMaskFlags();
    4289          36 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    4290           2 :             GetColorInterpretation() != GCI_AlphaBand)
    4291             :         {
    4292           2 :             poMaskBand = GetMaskBand();
    4293             :         }
    4294             :     }
    4295             : 
    4296          35 :     bool bSignedByte = false;
    4297          35 :     if (eDataType == GDT_UInt8)
    4298             :     {
    4299          26 :         EnablePixelTypeSignedByteWarning(false);
    4300             :         const char *pszPixelType =
    4301          26 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4302          26 :         EnablePixelTypeSignedByteWarning(true);
    4303          26 :         bSignedByte =
    4304          26 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4305             :     }
    4306             : 
    4307          35 :     if (bApproxOK && HasArbitraryOverviews())
    4308             :     {
    4309             :         /* --------------------------------------------------------------------
    4310             :          */
    4311             :         /*      Figure out how much the image should be reduced to get an */
    4312             :         /*      approximate value. */
    4313             :         /* --------------------------------------------------------------------
    4314             :          */
    4315             :         const double dfReduction =
    4316           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4317             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4318             : 
    4319           0 :         int nXReduced = nRasterXSize;
    4320           0 :         int nYReduced = nRasterYSize;
    4321           0 :         if (dfReduction > 1.0)
    4322             :         {
    4323           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4324           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4325             : 
    4326             :             // Catch the case of huge resizing ratios here
    4327           0 :             if (nXReduced == 0)
    4328           0 :                 nXReduced = 1;
    4329           0 :             if (nYReduced == 0)
    4330           0 :                 nYReduced = 1;
    4331             :         }
    4332             : 
    4333           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4334             :                                           nXReduced, nYReduced);
    4335           0 :         if (!pData)
    4336           0 :             return CE_Failure;
    4337             : 
    4338             :         const CPLErr eErr =
    4339           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4340           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4341           0 :         if (eErr != CE_None)
    4342             :         {
    4343           0 :             CPLFree(pData);
    4344           0 :             return eErr;
    4345             :         }
    4346             : 
    4347           0 :         GByte *pabyMaskData = nullptr;
    4348           0 :         if (poMaskBand)
    4349             :         {
    4350             :             pabyMaskData =
    4351           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4352           0 :             if (!pabyMaskData)
    4353             :             {
    4354           0 :                 CPLFree(pData);
    4355           0 :                 return CE_Failure;
    4356             :             }
    4357             : 
    4358           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4359             :                                      pabyMaskData, nXReduced, nYReduced,
    4360           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    4361             :             {
    4362           0 :                 CPLFree(pData);
    4363           0 :                 CPLFree(pabyMaskData);
    4364           0 :                 return CE_Failure;
    4365             :             }
    4366             :         }
    4367             : 
    4368             :         // This isn't the fastest way to do this, but is easier for now.
    4369           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4370             :         {
    4371           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4372             :             {
    4373           0 :                 const int iOffset = iX + iY * nXReduced;
    4374           0 :                 double dfValue = 0.0;
    4375             : 
    4376           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4377           0 :                     continue;
    4378             : 
    4379           0 :                 switch (eDataType)
    4380             :                 {
    4381           0 :                     case GDT_UInt8:
    4382             :                     {
    4383           0 :                         if (bSignedByte)
    4384           0 :                             dfValue =
    4385           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4386             :                         else
    4387           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4388           0 :                         break;
    4389             :                     }
    4390           0 :                     case GDT_Int8:
    4391           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4392           0 :                         break;
    4393           0 :                     case GDT_UInt16:
    4394           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4395           0 :                         break;
    4396           0 :                     case GDT_Int16:
    4397           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4398           0 :                         break;
    4399           0 :                     case GDT_UInt32:
    4400           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4401           0 :                         break;
    4402           0 :                     case GDT_Int32:
    4403           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4404           0 :                         break;
    4405           0 :                     case GDT_UInt64:
    4406           0 :                         dfValue = static_cast<double>(
    4407           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4408           0 :                         break;
    4409           0 :                     case GDT_Int64:
    4410           0 :                         dfValue = static_cast<double>(
    4411           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4412           0 :                         break;
    4413           0 :                     case GDT_Float16:
    4414             :                     {
    4415             :                         using namespace std;
    4416           0 :                         const GFloat16 hfValue =
    4417           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4418           0 :                         if (isnan(hfValue) ||
    4419           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4420           0 :                              ARE_REAL_EQUAL(hfValue,
    4421             :                                             sNoDataValues.hfNoDataValue)))
    4422           0 :                             continue;
    4423           0 :                         dfValue = hfValue;
    4424           0 :                         break;
    4425             :                     }
    4426           0 :                     case GDT_Float32:
    4427             :                     {
    4428           0 :                         const float fValue =
    4429           0 :                             static_cast<float *>(pData)[iOffset];
    4430           0 :                         if (std::isnan(fValue) ||
    4431           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4432           0 :                              ARE_REAL_EQUAL(fValue,
    4433             :                                             sNoDataValues.fNoDataValue)))
    4434           0 :                             continue;
    4435           0 :                         dfValue = double(fValue);
    4436           0 :                         break;
    4437             :                     }
    4438           0 :                     case GDT_Float64:
    4439           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4440           0 :                         if (std::isnan(dfValue))
    4441           0 :                             continue;
    4442           0 :                         break;
    4443           0 :                     case GDT_CInt16:
    4444             :                     {
    4445           0 :                         const double dfReal =
    4446           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4447           0 :                         const double dfImag =
    4448           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4449           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4450           0 :                             continue;
    4451           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4452             :                     }
    4453           0 :                     break;
    4454           0 :                     case GDT_CInt32:
    4455             :                     {
    4456           0 :                         const double dfReal =
    4457           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4458           0 :                         const double dfImag =
    4459           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4460           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4461           0 :                             continue;
    4462           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4463             :                     }
    4464           0 :                     break;
    4465           0 :                     case GDT_CFloat16:
    4466             :                     {
    4467             :                         const double dfReal =
    4468           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4469             :                         const double dfImag =
    4470           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4471           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4472           0 :                             continue;
    4473           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4474           0 :                         break;
    4475             :                     }
    4476           0 :                     case GDT_CFloat32:
    4477             :                     {
    4478           0 :                         const double dfReal =
    4479           0 :                             double(static_cast<float *>(pData)[iOffset * 2]);
    4480           0 :                         const double dfImag = double(
    4481           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1]);
    4482           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4483           0 :                             continue;
    4484           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4485           0 :                         break;
    4486             :                     }
    4487           0 :                     case GDT_CFloat64:
    4488             :                     {
    4489           0 :                         const double dfReal =
    4490           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4491           0 :                         const double dfImag =
    4492           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4493           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4494           0 :                             continue;
    4495           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4496           0 :                         break;
    4497             :                     }
    4498           0 :                     case GDT_Unknown:
    4499             :                     case GDT_TypeCount:
    4500           0 :                         CPLAssert(false);
    4501             :                 }
    4502             : 
    4503           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4504           0 :                     sNoDataValues.bGotNoDataValue &&
    4505           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4506           0 :                     continue;
    4507             : 
    4508             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4509             :                 // finite, the result of the multiplication cannot be NaN
    4510           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4511             : 
    4512           0 :                 if (dfIndex < 0)
    4513             :                 {
    4514           0 :                     if (bIncludeOutOfRange)
    4515           0 :                         panHistogram[0]++;
    4516             :                 }
    4517           0 :                 else if (dfIndex >= nBuckets)
    4518             :                 {
    4519           0 :                     if (bIncludeOutOfRange)
    4520           0 :                         ++panHistogram[nBuckets - 1];
    4521             :                 }
    4522             :                 else
    4523             :                 {
    4524           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4525             :                 }
    4526             :             }
    4527             :         }
    4528             : 
    4529           0 :         CPLFree(pData);
    4530           0 :         CPLFree(pabyMaskData);
    4531             :     }
    4532             :     else  // No arbitrary overviews.
    4533             :     {
    4534          35 :         if (!InitBlockInfo())
    4535           0 :             return CE_Failure;
    4536             : 
    4537             :         /* --------------------------------------------------------------------
    4538             :          */
    4539             :         /*      Figure out the ratio of blocks we will read to get an */
    4540             :         /*      approximate value. */
    4541             :         /* --------------------------------------------------------------------
    4542             :          */
    4543             : 
    4544          35 :         int nSampleRate = 1;
    4545          35 :         if (bApproxOK)
    4546             :         {
    4547           8 :             nSampleRate = static_cast<int>(std::max(
    4548          16 :                 1.0,
    4549           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4550             :             // We want to avoid probing only the first column of blocks for
    4551             :             // a square shaped raster, because it is not unlikely that it may
    4552             :             // be padding only (#6378).
    4553           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4554           1 :                 nSampleRate += 1;
    4555             :         }
    4556             : 
    4557          35 :         GByte *pabyMaskData = nullptr;
    4558          35 :         if (poMaskBand)
    4559             :         {
    4560             :             pabyMaskData = static_cast<GByte *>(
    4561           2 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4562           2 :             if (!pabyMaskData)
    4563             :             {
    4564           0 :                 return CE_Failure;
    4565             :             }
    4566             :         }
    4567             : 
    4568             :         /* --------------------------------------------------------------------
    4569             :          */
    4570             :         /*      Read the blocks, and add to histogram. */
    4571             :         /* --------------------------------------------------------------------
    4572             :          */
    4573          35 :         for (GIntBig iSampleBlock = 0;
    4574         160 :              iSampleBlock <
    4575         160 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4576         125 :              iSampleBlock += nSampleRate)
    4577             :         {
    4578         125 :             if (!pfnProgress(
    4579         125 :                     static_cast<double>(iSampleBlock) /
    4580         125 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4581             :                     "Compute Histogram", pProgressData))
    4582             :             {
    4583           0 :                 CPLFree(pabyMaskData);
    4584           0 :                 return CE_Failure;
    4585             :             }
    4586             : 
    4587         125 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4588         125 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4589             : 
    4590         125 :             int nXCheck = 0, nYCheck = 0;
    4591         125 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4592             : 
    4593         127 :             if (poMaskBand &&
    4594           2 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4595           2 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4596             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    4597           2 :                                      0, nBlockXSize, nullptr) != CE_None)
    4598             :             {
    4599           0 :                 CPLFree(pabyMaskData);
    4600           0 :                 return CE_Failure;
    4601             :             }
    4602             : 
    4603         125 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4604         125 :             if (poBlock == nullptr)
    4605             :             {
    4606           0 :                 CPLFree(pabyMaskData);
    4607           0 :                 return CE_Failure;
    4608             :             }
    4609             : 
    4610         125 :             void *pData = poBlock->GetDataRef();
    4611             : 
    4612             :             // this is a special case for a common situation.
    4613         125 :             if (eDataType == GDT_UInt8 && !bSignedByte && dfScale == 1.0 &&
    4614          89 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4615          86 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4616             :             {
    4617          86 :                 const GPtrDiff_t nPixels =
    4618          86 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4619          86 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4620             : 
    4621       79640 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4622             :                 {
    4623       79554 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4624           0 :                         continue;
    4625       79554 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4626         512 :                           (pabyData[i] ==
    4627         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4628             :                     {
    4629       79298 :                         panHistogram[pabyData[i]]++;
    4630             :                     }
    4631             :                 }
    4632             : 
    4633          86 :                 poBlock->DropLock();
    4634          86 :                 continue;  // To next sample block.
    4635             :             }
    4636             : 
    4637             :             // This isn't the fastest way to do this, but is easier for now.
    4638         257 :             for (int iY = 0; iY < nYCheck; iY++)
    4639             :             {
    4640       36389 :                 for (int iX = 0; iX < nXCheck; iX++)
    4641             :                 {
    4642       36171 :                     const GPtrDiff_t iOffset =
    4643       36171 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4644             : 
    4645       36171 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4646           2 :                         continue;
    4647             : 
    4648       36169 :                     double dfValue = 0.0;
    4649             : 
    4650       36169 :                     switch (eDataType)
    4651             :                     {
    4652       19716 :                         case GDT_UInt8:
    4653             :                         {
    4654       19716 :                             if (bSignedByte)
    4655           0 :                                 dfValue =
    4656           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4657             :                             else
    4658       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4659       19716 :                             break;
    4660             :                         }
    4661           1 :                         case GDT_Int8:
    4662           1 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4663           1 :                             break;
    4664       16384 :                         case GDT_UInt16:
    4665       16384 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4666       16384 :                             break;
    4667           3 :                         case GDT_Int16:
    4668           3 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4669           3 :                             break;
    4670           0 :                         case GDT_UInt32:
    4671           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4672           0 :                             break;
    4673          60 :                         case GDT_Int32:
    4674          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4675          60 :                             break;
    4676           0 :                         case GDT_UInt64:
    4677           0 :                             dfValue = static_cast<double>(
    4678           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4679           0 :                             break;
    4680           0 :                         case GDT_Int64:
    4681           0 :                             dfValue = static_cast<double>(
    4682           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4683           0 :                             break;
    4684           0 :                         case GDT_Float16:
    4685             :                         {
    4686             :                             using namespace std;
    4687           0 :                             const GFloat16 hfValue =
    4688           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4689           0 :                             if (isnan(hfValue) ||
    4690           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4691           0 :                                  ARE_REAL_EQUAL(hfValue,
    4692             :                                                 sNoDataValues.hfNoDataValue)))
    4693           0 :                                 continue;
    4694           0 :                             dfValue = hfValue;
    4695           0 :                             break;
    4696             :                         }
    4697           3 :                         case GDT_Float32:
    4698             :                         {
    4699           3 :                             const float fValue =
    4700           3 :                                 static_cast<float *>(pData)[iOffset];
    4701           6 :                             if (std::isnan(fValue) ||
    4702           6 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4703           3 :                                  ARE_REAL_EQUAL(fValue,
    4704             :                                                 sNoDataValues.fNoDataValue)))
    4705           0 :                                 continue;
    4706           3 :                             dfValue = double(fValue);
    4707           3 :                             break;
    4708             :                         }
    4709           2 :                         case GDT_Float64:
    4710           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4711           2 :                             if (std::isnan(dfValue))
    4712           0 :                                 continue;
    4713           2 :                             break;
    4714           0 :                         case GDT_CInt16:
    4715             :                         {
    4716           0 :                             double dfReal =
    4717           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4718           0 :                             double dfImag =
    4719           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4720           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4721           0 :                             break;
    4722             :                         }
    4723           0 :                         case GDT_CInt32:
    4724             :                         {
    4725           0 :                             double dfReal =
    4726           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4727           0 :                             double dfImag =
    4728           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4729           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4730           0 :                             break;
    4731             :                         }
    4732           0 :                         case GDT_CFloat16:
    4733             :                         {
    4734             :                             double dfReal =
    4735           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4736             :                             double dfImag =
    4737           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4738           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4739           0 :                                 continue;
    4740           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4741           0 :                             break;
    4742             :                         }
    4743           0 :                         case GDT_CFloat32:
    4744             :                         {
    4745           0 :                             double dfReal = double(
    4746           0 :                                 static_cast<float *>(pData)[iOffset * 2]);
    4747           0 :                             double dfImag = double(
    4748           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1]);
    4749           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4750           0 :                                 continue;
    4751           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4752           0 :                             break;
    4753             :                         }
    4754           0 :                         case GDT_CFloat64:
    4755             :                         {
    4756           0 :                             double dfReal =
    4757           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4758           0 :                             double dfImag =
    4759           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4760           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4761           0 :                                 continue;
    4762           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4763           0 :                             break;
    4764             :                         }
    4765           0 :                         case GDT_Unknown:
    4766             :                         case GDT_TypeCount:
    4767           0 :                             CPLAssert(false);
    4768             :                             CPLFree(pabyMaskData);
    4769             :                             return CE_Failure;
    4770             :                     }
    4771             : 
    4772       36169 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4773       72338 :                         sNoDataValues.bGotNoDataValue &&
    4774           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4775           0 :                         continue;
    4776             : 
    4777             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4778             :                     // and finite, the result of the multiplication cannot be
    4779             :                     // NaN
    4780       36169 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4781             : 
    4782       36169 :                     if (dfIndex < 0)
    4783             :                     {
    4784           1 :                         if (bIncludeOutOfRange)
    4785           1 :                             panHistogram[0]++;
    4786             :                     }
    4787       36168 :                     else if (dfIndex >= nBuckets)
    4788             :                     {
    4789           7 :                         if (bIncludeOutOfRange)
    4790           4 :                             ++panHistogram[nBuckets - 1];
    4791             :                     }
    4792             :                     else
    4793             :                     {
    4794       36161 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4795             :                     }
    4796             :                 }
    4797             :             }
    4798             : 
    4799          39 :             poBlock->DropLock();
    4800             :         }
    4801             : 
    4802          35 :         CPLFree(pabyMaskData);
    4803             :     }
    4804             : 
    4805          35 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4806             : 
    4807          35 :     return CE_None;
    4808             : }
    4809             : 
    4810             : /************************************************************************/
    4811             : /*                       GDALGetRasterHistogram()                       */
    4812             : /************************************************************************/
    4813             : 
    4814             : /**
    4815             :  * \brief Compute raster histogram.
    4816             :  *
    4817             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4818             :  * exceeding 2 billion.
    4819             :  *
    4820             :  * @see GDALRasterBand::GetHistogram()
    4821             :  * @see GDALGetRasterHistogramEx()
    4822             :  */
    4823             : 
    4824           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4825             :                                           double dfMax, int nBuckets,
    4826             :                                           int *panHistogram,
    4827             :                                           int bIncludeOutOfRange, int bApproxOK,
    4828             :                                           GDALProgressFunc pfnProgress,
    4829             :                                           void *pProgressData)
    4830             : 
    4831             : {
    4832           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4833           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4834             : 
    4835           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4836             : 
    4837             :     GUIntBig *panHistogramTemp =
    4838           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4839           0 :     if (panHistogramTemp == nullptr)
    4840             :     {
    4841           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4842             :                             "Out of memory in GDALGetRasterHistogram().");
    4843           0 :         return CE_Failure;
    4844             :     }
    4845             : 
    4846           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4847             :                                        bIncludeOutOfRange, bApproxOK,
    4848           0 :                                        pfnProgress, pProgressData);
    4849             : 
    4850           0 :     if (eErr == CE_None)
    4851             :     {
    4852           0 :         for (int i = 0; i < nBuckets; i++)
    4853             :         {
    4854           0 :             if (panHistogramTemp[i] > INT_MAX)
    4855             :             {
    4856           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4857             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4858             :                          " exceeds maximum 32 bit value",
    4859           0 :                          i, panHistogramTemp[i]);
    4860           0 :                 panHistogram[i] = INT_MAX;
    4861             :             }
    4862             :             else
    4863             :             {
    4864           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4865             :             }
    4866             :         }
    4867             :     }
    4868             : 
    4869           0 :     CPLFree(panHistogramTemp);
    4870             : 
    4871           0 :     return eErr;
    4872             : }
    4873             : 
    4874             : /************************************************************************/
    4875             : /*                      GDALGetRasterHistogramEx()                      */
    4876             : /************************************************************************/
    4877             : 
    4878             : /**
    4879             :  * \brief Compute raster histogram.
    4880             :  *
    4881             :  * @see GDALRasterBand::GetHistogram()
    4882             :  *
    4883             :  */
    4884             : 
    4885          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4886             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4887             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4888             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4889             : 
    4890             : {
    4891          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4892          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4893             : 
    4894          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4895             : 
    4896          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4897             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4898          26 :                                 pProgressData);
    4899             : }
    4900             : 
    4901             : /************************************************************************/
    4902             : /*                        GetDefaultHistogram()                         */
    4903             : /************************************************************************/
    4904             : 
    4905             : /**
    4906             :  * \brief Fetch default raster histogram.
    4907             :  *
    4908             :  * The default method in GDALRasterBand will compute a default histogram. This
    4909             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4910             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4911             :  * stored histogram.
    4912             :  *
    4913             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4914             :  * GDALGetDefaultHistogramEx().
    4915             :  *
    4916             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4917             :  * the histogram.
    4918             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4919             :  * the histogram.
    4920             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4921             :  * in *ppanHistogram.
    4922             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4923             :  * placed. To be freed with VSIFree
    4924             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4925             :  * histogram is available, the method will return CE_Warning
    4926             :  * @param pfnProgress function to report progress to completion.
    4927             :  * @param pProgressData application data to pass to pfnProgress.
    4928             :  *
    4929             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4930             :  * CE_Warning if no default histogram is available.
    4931             :  */
    4932             : 
    4933          27 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4934             :                                            int *pnBuckets,
    4935             :                                            GUIntBig **ppanHistogram, int bForce,
    4936             :                                            GDALProgressFunc pfnProgress,
    4937             :                                            void *pProgressData)
    4938             : 
    4939             : {
    4940          27 :     CPLAssert(nullptr != pnBuckets);
    4941          27 :     CPLAssert(nullptr != ppanHistogram);
    4942          27 :     CPLAssert(nullptr != pdfMin);
    4943          27 :     CPLAssert(nullptr != pdfMax);
    4944             : 
    4945          27 :     *pnBuckets = 0;
    4946          27 :     *ppanHistogram = nullptr;
    4947             : 
    4948          27 :     if (!bForce)
    4949           5 :         return CE_Warning;
    4950             : 
    4951          22 :     int nBuckets = 256;
    4952             : 
    4953          22 :     bool bSignedByte = false;
    4954          22 :     if (eDataType == GDT_UInt8)
    4955             :     {
    4956          20 :         EnablePixelTypeSignedByteWarning(false);
    4957             :         const char *pszPixelType =
    4958          20 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4959          20 :         EnablePixelTypeSignedByteWarning(true);
    4960          20 :         bSignedByte =
    4961          20 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4962             :     }
    4963             : 
    4964          22 :     if (GetRasterDataType() == GDT_UInt8 && !bSignedByte)
    4965             :     {
    4966          20 :         *pdfMin = -0.5;
    4967          20 :         *pdfMax = 255.5;
    4968             :     }
    4969           2 :     else if (GetRasterDataType() == GDT_Int8)
    4970             :     {
    4971           1 :         *pdfMin = -128 - 0.5;
    4972           1 :         *pdfMax = 127 + 0.5;
    4973             :     }
    4974             :     else
    4975             :     {
    4976             : 
    4977             :         const CPLErr eErr =
    4978           1 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4979           1 :         if (eErr != CE_None)
    4980           0 :             return eErr;
    4981           1 :         if (*pdfMin == *pdfMax)
    4982             :         {
    4983           1 :             nBuckets = 1;
    4984           1 :             *pdfMin -= 0.5;
    4985           1 :             *pdfMax += 0.5;
    4986             :         }
    4987             :         else
    4988             :         {
    4989           0 :             const double dfHalfBucket =
    4990           0 :                 (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4991           0 :             *pdfMin -= dfHalfBucket;
    4992           0 :             *pdfMax += dfHalfBucket;
    4993             :         }
    4994             :     }
    4995             : 
    4996          22 :     *ppanHistogram =
    4997          22 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4998          22 :     if (*ppanHistogram == nullptr)
    4999             :     {
    5000           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    5001             :                     "Out of memory in GetDefaultHistogram().");
    5002           0 :         return CE_Failure;
    5003             :     }
    5004             : 
    5005          22 :     *pnBuckets = nBuckets;
    5006          44 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    5007          22 :                                TRUE, FALSE, pfnProgress, pProgressData);
    5008          22 :     if (eErr != CE_None)
    5009             :     {
    5010           0 :         *pnBuckets = 0;
    5011             :     }
    5012          22 :     return eErr;
    5013             : }
    5014             : 
    5015             : /************************************************************************/
    5016             : /*                      GDALGetDefaultHistogram()                       */
    5017             : /************************************************************************/
    5018             : 
    5019             : /**
    5020             :  * \brief Fetch default raster histogram.
    5021             :  *
    5022             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    5023             :  * exceeding 2 billion.
    5024             :  *
    5025             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    5026             :  * @see GDALGetRasterHistogramEx()
    5027             :  */
    5028             : 
    5029           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    5030             :                                            double *pdfMin, double *pdfMax,
    5031             :                                            int *pnBuckets, int **ppanHistogram,
    5032             :                                            int bForce,
    5033             :                                            GDALProgressFunc pfnProgress,
    5034             :                                            void *pProgressData)
    5035             : 
    5036             : {
    5037           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5038           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5039           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5040           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5041           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5042             : 
    5043           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    5044           0 :     GUIntBig *panHistogramTemp = nullptr;
    5045           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    5046             :                                               &panHistogramTemp, bForce,
    5047           0 :                                               pfnProgress, pProgressData);
    5048           0 :     if (eErr == CE_None)
    5049             :     {
    5050           0 :         const int nBuckets = *pnBuckets;
    5051           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    5052           0 :         if (*ppanHistogram == nullptr)
    5053             :         {
    5054           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    5055             :                                 "Out of memory in GDALGetDefaultHistogram().");
    5056           0 :             VSIFree(panHistogramTemp);
    5057           0 :             return CE_Failure;
    5058             :         }
    5059             : 
    5060           0 :         for (int i = 0; i < nBuckets; ++i)
    5061             :         {
    5062           0 :             if (panHistogramTemp[i] > INT_MAX)
    5063             :             {
    5064           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    5065             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    5066             :                          " exceeds maximum 32 bit value",
    5067           0 :                          i, panHistogramTemp[i]);
    5068           0 :                 (*ppanHistogram)[i] = INT_MAX;
    5069             :             }
    5070             :             else
    5071             :             {
    5072           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    5073             :             }
    5074             :         }
    5075             : 
    5076           0 :         CPLFree(panHistogramTemp);
    5077             :     }
    5078             :     else
    5079             :     {
    5080           0 :         *ppanHistogram = nullptr;
    5081             :     }
    5082             : 
    5083           0 :     return eErr;
    5084             : }
    5085             : 
    5086             : /************************************************************************/
    5087             : /*                     GDALGetDefaultHistogramEx()                      */
    5088             : /************************************************************************/
    5089             : 
    5090             : /**
    5091             :  * \brief Fetch default raster histogram.
    5092             :  *
    5093             :  * @see GDALRasterBand::GetDefaultHistogram()
    5094             :  *
    5095             :  */
    5096             : 
    5097             : CPLErr CPL_STDCALL
    5098          30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    5099             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    5100             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    5101             : 
    5102             : {
    5103          30 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5104          30 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5105          30 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5106          30 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5107          30 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5108             : 
    5109          30 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5110          30 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    5111          30 :                                        bForce, pfnProgress, pProgressData);
    5112             : }
    5113             : 
    5114             : /************************************************************************/
    5115             : /*                             AdviseRead()                             */
    5116             : /************************************************************************/
    5117             : 
    5118             : /**
    5119             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    5120             :  * \brief Advise driver of upcoming read requests.
    5121             :  *
    5122             :  * Some GDAL drivers operate more efficiently if they know in advance what
    5123             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    5124             :  * an application to notify the driver of the region of interest,
    5125             :  * and at what resolution the region will be read.
    5126             :  *
    5127             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    5128             :  * accelerate access via some drivers.
    5129             :  *
    5130             :  * Depending on call paths, drivers might receive several calls to
    5131             :  * AdviseRead() with the same parameters.
    5132             :  *
    5133             :  * @param nXOff The pixel offset to the top left corner of the region
    5134             :  * of the band to be accessed.  This would be zero to start from the left side.
    5135             :  *
    5136             :  * @param nYOff The line offset to the top left corner of the region
    5137             :  * of the band to be accessed.  This would be zero to start from the top.
    5138             :  *
    5139             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    5140             :  *
    5141             :  * @param nYSize The height of the region of the band to be accessed in lines.
    5142             :  *
    5143             :  * @param nBufXSize the width of the buffer image into which the desired region
    5144             :  * is to be read, or from which it is to be written.
    5145             :  *
    5146             :  * @param nBufYSize the height of the buffer image into which the desired
    5147             :  * region is to be read, or from which it is to be written.
    5148             :  *
    5149             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    5150             :  * pixel values will automatically be translated to/from the GDALRasterBand
    5151             :  * data type as needed.
    5152             :  *
    5153             :  * @param papszOptions a list of name=value strings with special control
    5154             :  * options.  Normally this is NULL.
    5155             :  *
    5156             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    5157             :  * is ignored.
    5158             :  */
    5159             : 
    5160             : /**/
    5161             : /**/
    5162             : 
    5163      114595 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    5164             :                                   int /*nYSize*/, int /*nBufXSize*/,
    5165             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    5166             :                                   CSLConstList /*papszOptions*/)
    5167             : {
    5168      114595 :     return CE_None;
    5169             : }
    5170             : 
    5171             : /************************************************************************/
    5172             : /*                        GDALRasterAdviseRead()                        */
    5173             : /************************************************************************/
    5174             : 
    5175             : /**
    5176             :  * \brief Advise driver of upcoming read requests.
    5177             :  *
    5178             :  * @see GDALRasterBand::AdviseRead()
    5179             :  */
    5180             : 
    5181           4 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    5182             :                                         int nYOff, int nXSize, int nYSize,
    5183             :                                         int nBufXSize, int nBufYSize,
    5184             :                                         GDALDataType eDT,
    5185             :                                         CSLConstList papszOptions)
    5186             : 
    5187             : {
    5188           4 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    5189             : 
    5190           4 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5191           4 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    5192             :                               nBufYSize, eDT,
    5193           4 :                               const_cast<char **>(papszOptions));
    5194             : }
    5195             : 
    5196             : /************************************************************************/
    5197             : /*                           GetStatistics()                            */
    5198             : /************************************************************************/
    5199             : 
    5200             : /**
    5201             :  * \brief Fetch image statistics.
    5202             :  *
    5203             :  * Returns the minimum, maximum, mean and standard deviation of all
    5204             :  * pixel values in this band.  If approximate statistics are sufficient,
    5205             :  * the bApproxOK flag can be set to true in which case overviews, or a
    5206             :  * subset of image tiles may be used in computing the statistics.
    5207             :  *
    5208             :  * If bForce is FALSE results will only be returned if it can be done
    5209             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    5210             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    5211             :  * returned efficiently, the method will return CE_Warning but no warning will
    5212             :  * be issued. This is a non-standard use of the CE_Warning return value
    5213             :  * to indicate "nothing done".
    5214             :  *
    5215             :  * If bForce is TRUE, and results are quickly available without scanning the
    5216             :  * image, they will be used. If bForce is TRUE and results are not quickly
    5217             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    5218             :  * which will scan the image.
    5219             :  *
    5220             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    5221             :  * of this method.
    5222             :  *
    5223             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    5224             :  * will generally cache statistics in the .pam file allowing fast fetch
    5225             :  * after the first request.
    5226             :  *
    5227             :  * This method is the same as the C function GDALGetRasterStatistics().
    5228             :  *
    5229             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5230             :  * or a subset of all tiles.
    5231             :  *
    5232             :  * @param bForce If FALSE statistics will only be returned if it can
    5233             :  * be done without rescanning the image. If TRUE, statistics computation will
    5234             :  * be forced if pre-existing values are not quickly available.
    5235             :  *
    5236             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5237             :  *
    5238             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5239             :  *
    5240             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5241             :  *
    5242             :  * @param pdfStdDev Location into which to load image standard deviation
    5243             :  * (may be NULL).
    5244             :  *
    5245             :  * @return CE_None on success, CE_Warning if no values returned,
    5246             :  * CE_Failure if an error occurs.
    5247             :  */
    5248             : 
    5249         676 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5250             :                                      double *pdfMax, double *pdfMean,
    5251             :                                      double *pdfStdDev)
    5252             : 
    5253             : {
    5254             :     /* -------------------------------------------------------------------- */
    5255             :     /*      Do we already have metadata items for the requested values?     */
    5256             :     /* -------------------------------------------------------------------- */
    5257        1352 :     if ((pdfMin == nullptr ||
    5258         676 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5259         206 :         (pdfMax == nullptr ||
    5260         206 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5261        1558 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5262         206 :         (pdfStdDev == nullptr ||
    5263         206 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5264             :     {
    5265         206 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5266             :         {
    5267         199 :             if (pdfMin != nullptr)
    5268         199 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5269         199 :             if (pdfMax != nullptr)
    5270         199 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5271         199 :             if (pdfMean != nullptr)
    5272         199 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5273         199 :             if (pdfStdDev != nullptr)
    5274         199 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5275             : 
    5276         199 :             return CE_None;
    5277             :         }
    5278             :     }
    5279             : 
    5280             :     /* -------------------------------------------------------------------- */
    5281             :     /*      Does the driver already know the min/max?                       */
    5282             :     /* -------------------------------------------------------------------- */
    5283         477 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5284             :     {
    5285           1 :         int bSuccessMin = FALSE;
    5286           1 :         int bSuccessMax = FALSE;
    5287             : 
    5288           1 :         const double dfMin = GetMinimum(&bSuccessMin);
    5289           1 :         const double dfMax = GetMaximum(&bSuccessMax);
    5290             : 
    5291           1 :         if (bSuccessMin && bSuccessMax)
    5292             :         {
    5293           0 :             if (pdfMin != nullptr)
    5294           0 :                 *pdfMin = dfMin;
    5295           0 :             if (pdfMax != nullptr)
    5296           0 :                 *pdfMax = dfMax;
    5297           0 :             return CE_None;
    5298             :         }
    5299             :     }
    5300             : 
    5301             :     /* -------------------------------------------------------------------- */
    5302             :     /*      Either return without results, or force computation.            */
    5303             :     /* -------------------------------------------------------------------- */
    5304         477 :     if (!bForce)
    5305         194 :         return CE_Warning;
    5306             :     else
    5307         283 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5308         283 :                                  GDALDummyProgress, nullptr);
    5309             : }
    5310             : 
    5311             : /************************************************************************/
    5312             : /*                      GDALGetRasterStatistics()                       */
    5313             : /************************************************************************/
    5314             : 
    5315             : /**
    5316             :  * \brief Fetch image statistics.
    5317             :  *
    5318             :  * @see GDALRasterBand::GetStatistics()
    5319             :  */
    5320             : 
    5321         324 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5322             :                                            int bForce, double *pdfMin,
    5323             :                                            double *pdfMax, double *pdfMean,
    5324             :                                            double *pdfStdDev)
    5325             : 
    5326             : {
    5327         324 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5328             : 
    5329         324 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5330         324 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5331         324 :                                  pdfStdDev);
    5332             : }
    5333             : 
    5334             : /************************************************************************/
    5335             : /*                             GDALUInt128                              */
    5336             : /************************************************************************/
    5337             : 
    5338             : #ifdef HAVE_UINT128_T
    5339             : class GDALUInt128
    5340             : {
    5341             :     __uint128_t val;
    5342             : 
    5343        1200 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5344             :     {
    5345        1200 :     }
    5346             : 
    5347             :   public:
    5348         800 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5349             :     {
    5350             :         // Evaluates to just a single mul on x86_64
    5351         800 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5352             :     }
    5353             : 
    5354         400 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5355             :     {
    5356         400 :         return GDALUInt128(val - other.val);
    5357             :     }
    5358             : 
    5359         391 :     operator double() const
    5360             :     {
    5361         391 :         return static_cast<double>(val);
    5362             :     }
    5363             : };
    5364             : #else
    5365             : 
    5366             : #if defined(_MSC_VER) && defined(_M_X64)
    5367             : #include <intrin.h>
    5368             : #endif
    5369             : 
    5370             : class GDALUInt128
    5371             : {
    5372             :     GUIntBig low, high;
    5373             : 
    5374             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5375             :     {
    5376             :     }
    5377             : 
    5378             :   public:
    5379             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5380             :     {
    5381             : #if defined(_MSC_VER) && defined(_M_X64)
    5382             :         GUIntBig highRes;
    5383             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5384             :         return GDALUInt128(lowRes, highRes);
    5385             : #else
    5386             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5387             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5388             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5389             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5390             :         GUIntBig highRes = 0;
    5391             :         const GUIntBig firstLowSecondHigh =
    5392             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5393             :         const GUIntBig firstHighSecondLow =
    5394             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5395             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5396             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5397             :             highRes += static_cast<GUIntBig>(1) << 32;
    5398             :         const GUIntBig firstLowSecondLow =
    5399             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5400             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5401             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5402             :             highRes++;
    5403             :         highRes +=
    5404             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5405             :         return GDALUInt128(lowRes, highRes);
    5406             : #endif
    5407             :     }
    5408             : 
    5409             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5410             :     {
    5411             :         GUIntBig highRes = high - other.high;
    5412             :         GUIntBig lowRes = low - other.low;
    5413             :         if (lowRes > low)  // check for underflow
    5414             :             --highRes;
    5415             :         return GDALUInt128(lowRes, highRes);
    5416             :     }
    5417             : 
    5418             :     operator double() const
    5419             :     {
    5420             :         const double twoPow64 = 18446744073709551616.0;
    5421             :         return high * twoPow64 + low;
    5422             :     }
    5423             : };
    5424             : #endif
    5425             : 
    5426             : /************************************************************************/
    5427             : /*                     ComputeStatisticsInternal()                      */
    5428             : /************************************************************************/
    5429             : 
    5430             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5431             : // not needed.
    5432             : #define static_cast_for_coverity_scan static_cast
    5433             : 
    5434             : // The rationale for below optimizations is detailed in statistics.txt
    5435             : 
    5436             : // Use with T = GByte or GUInt16 only !
    5437             : template <class T, bool COMPUTE_OTHER_STATS>
    5438             : struct ComputeStatisticsInternalGeneric
    5439             : {
    5440         301 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5441             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5442             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5443             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5444             :     {
    5445             :         static_assert(std::is_same<T, GByte>::value ||
    5446             :                           std::is_same<T, GUInt16>::value,
    5447             :                       "bad type for T");
    5448         301 :         if (bHasNoData)
    5449             :         {
    5450             :             // General case
    5451         700 :             for (int iY = 0; iY < nYCheck; iY++)
    5452             :             {
    5453      161945 :                 for (int iX = 0; iX < nXCheck; iX++)
    5454             :                 {
    5455      161413 :                     const GPtrDiff_t iOffset =
    5456      161413 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5457      161413 :                     const GUInt32 nValue = pData[iOffset];
    5458      161413 :                     if (nValue == nNoDataValue)
    5459         339 :                         continue;
    5460      161074 :                     if (nValue < nMin)
    5461          64 :                         nMin = nValue;
    5462      161074 :                     if (nValue > nMax)
    5463         179 :                         nMax = nValue;
    5464             :                     if constexpr (COMPUTE_OTHER_STATS)
    5465             :                     {
    5466      159334 :                         nValidCount++;
    5467      159334 :                         nSum += nValue;
    5468      159334 :                         nSumSquare +=
    5469      159334 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5470      159334 :                             nValue;
    5471             :                     }
    5472             :                 }
    5473             :             }
    5474             :             if constexpr (COMPUTE_OTHER_STATS)
    5475             :             {
    5476          44 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5477             :             }
    5478             :         }
    5479         153 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5480          20 :                  nMax == std::numeric_limits<T>::max())
    5481             :         {
    5482             :             if constexpr (COMPUTE_OTHER_STATS)
    5483             :             {
    5484             :                 // Optimization when there is no nodata and we know we have already
    5485             :                 // reached the min and max
    5486         416 :                 for (int iY = 0; iY < nYCheck; iY++)
    5487             :                 {
    5488             :                     int iX;
    5489        2004 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5490             :                     {
    5491        1600 :                         const GPtrDiff_t iOffset =
    5492        1600 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5493        1600 :                         const GUIntBig nValue = pData[iOffset];
    5494        1600 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5495        1600 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5496        1600 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5497        1600 :                         nSum += nValue;
    5498        1600 :                         nSumSquare += nValue * nValue;
    5499        1600 :                         nSum += nValue2;
    5500        1600 :                         nSumSquare += nValue2 * nValue2;
    5501        1600 :                         nSum += nValue3;
    5502        1600 :                         nSumSquare += nValue3 * nValue3;
    5503        1600 :                         nSum += nValue4;
    5504        1600 :                         nSumSquare += nValue4 * nValue4;
    5505             :                     }
    5506         414 :                     for (; iX < nXCheck; ++iX)
    5507             :                     {
    5508          10 :                         const GPtrDiff_t iOffset =
    5509          10 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5510          10 :                         const GUIntBig nValue = pData[iOffset];
    5511          10 :                         nSum += nValue;
    5512          10 :                         nSumSquare += nValue * nValue;
    5513             :                     }
    5514             :                 }
    5515          12 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5516          12 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5517             :             }
    5518             :         }
    5519             :         else
    5520             :         {
    5521        6531 :             for (int iY = 0; iY < nYCheck; iY++)
    5522             :             {
    5523             :                 int iX;
    5524     1329024 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5525             :                 {
    5526     1322620 :                     const GPtrDiff_t iOffset =
    5527     1322620 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5528     1322620 :                     const GUInt32 nValue = pData[iOffset];
    5529     1322620 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5530     1322620 :                     if (nValue < nValue2)
    5531             :                     {
    5532        2329 :                         if (nValue < nMin)
    5533          53 :                             nMin = nValue;
    5534        2329 :                         if (nValue2 > nMax)
    5535         123 :                             nMax = nValue2;
    5536             :                     }
    5537             :                     else
    5538             :                     {
    5539     1320289 :                         if (nValue2 < nMin)
    5540          67 :                             nMin = nValue2;
    5541     1320289 :                         if (nValue > nMax)
    5542         219 :                             nMax = nValue;
    5543             :                     }
    5544             :                     if constexpr (COMPUTE_OTHER_STATS)
    5545             :                     {
    5546     1315560 :                         nSum += nValue;
    5547     1315560 :                         nSumSquare +=
    5548     1315560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5549     1315560 :                             nValue;
    5550     1315560 :                         nSum += nValue2;
    5551     1315560 :                         nSumSquare +=
    5552     1315560 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5553     1315560 :                             nValue2;
    5554             :                     }
    5555             :                 }
    5556        6410 :                 if (iX < nXCheck)
    5557             :                 {
    5558          31 :                     const GPtrDiff_t iOffset =
    5559          31 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5560          31 :                     const GUInt32 nValue = pData[iOffset];
    5561          31 :                     if (nValue < nMin)
    5562          19 :                         nMin = nValue;
    5563          31 :                     if (nValue > nMax)
    5564          22 :                         nMax = nValue;
    5565             :                     if (COMPUTE_OTHER_STATS)
    5566             :                     {
    5567          19 :                         nSum += nValue;
    5568          19 :                         nSumSquare +=
    5569          19 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5570          19 :                             nValue;
    5571             :                     }
    5572             :                 }
    5573             :             }
    5574             :             if constexpr (COMPUTE_OTHER_STATS)
    5575             :             {
    5576          62 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5577          62 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5578             :             }
    5579             :         }
    5580         301 :     }
    5581             : };
    5582             : 
    5583             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5584             : // using 64bit accumulators in internal loops. This also slightly helps in
    5585             : // 64bit mode.
    5586             : template <bool COMPUTE_OTHER_STATS>
    5587             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5588             : {
    5589       13828 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5590             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5591             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5592             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5593             :     {
    5594       13828 :         int nOuterLoops = nXCheck / 65536;
    5595       13828 :         if (nXCheck % 65536)
    5596       13828 :             nOuterLoops++;
    5597             : 
    5598       13828 :         if (bHasNoData)
    5599             :         {
    5600             :             // General case
    5601       23881 :             for (int iY = 0; iY < nYCheck; iY++)
    5602             :             {
    5603       13245 :                 int iX = 0;
    5604       26490 :                 for (int k = 0; k < nOuterLoops; k++)
    5605             :                 {
    5606       13245 :                     int iMax = iX + 65536;
    5607       13245 :                     if (iMax > nXCheck)
    5608       13245 :                         iMax = nXCheck;
    5609       13245 :                     GUInt32 nSum32bit = 0;
    5610       13245 :                     GUInt32 nSumSquare32bit = 0;
    5611       13245 :                     GUInt32 nValidCount32bit = 0;
    5612       13245 :                     GUInt32 nSampleCount32bit = 0;
    5613    20723132 :                     for (; iX < iMax; iX++)
    5614             :                     {
    5615    20709887 :                         const GPtrDiff_t iOffset =
    5616    20709887 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5617    20709887 :                         const GUInt32 nValue = pData[iOffset];
    5618             : 
    5619    20709887 :                         nSampleCount32bit++;
    5620    20709887 :                         if (nValue == nNoDataValue)
    5621    20353620 :                             continue;
    5622      356216 :                         if (nValue < nMin)
    5623         401 :                             nMin = nValue;
    5624      356216 :                         if (nValue > nMax)
    5625         942 :                             nMax = nValue;
    5626             :                         if constexpr (COMPUTE_OTHER_STATS)
    5627             :                         {
    5628       32367 :                             nValidCount32bit++;
    5629       32367 :                             nSum32bit += nValue;
    5630       32367 :                             nSumSquare32bit += nValue * nValue;
    5631             :                         }
    5632             :                     }
    5633             :                     if constexpr (COMPUTE_OTHER_STATS)
    5634             :                     {
    5635         945 :                         nSampleCount += nSampleCount32bit;
    5636         945 :                         nValidCount += nValidCount32bit;
    5637         945 :                         nSum += nSum32bit;
    5638         945 :                         nSumSquare += nSumSquare32bit;
    5639             :                     }
    5640             :                 }
    5641             :             }
    5642             :         }
    5643        3192 :         else if (nMin == 0 && nMax == 255)
    5644             :         {
    5645             :             if constexpr (COMPUTE_OTHER_STATS)
    5646             :             {
    5647             :                 // Optimization when there is no nodata and we know we have already
    5648             :                 // reached the min and max
    5649        2850 :                 for (int iY = 0; iY < nYCheck; iY++)
    5650             :                 {
    5651        2818 :                     int iX = 0;
    5652        5636 :                     for (int k = 0; k < nOuterLoops; k++)
    5653             :                     {
    5654        2818 :                         int iMax = iX + 65536;
    5655        2818 :                         if (iMax > nXCheck)
    5656        2818 :                             iMax = nXCheck;
    5657        2818 :                         GUInt32 nSum32bit = 0;
    5658        2818 :                         GUInt32 nSumSquare32bit = 0;
    5659      177298 :                         for (; iX + 3 < iMax; iX += 4)
    5660             :                         {
    5661      174480 :                             const GPtrDiff_t iOffset =
    5662      174480 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5663      174480 :                             const GUInt32 nValue = pData[iOffset];
    5664      174480 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5665      174480 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5666      174480 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5667      174480 :                             nSum32bit += nValue;
    5668      174480 :                             nSumSquare32bit += nValue * nValue;
    5669      174480 :                             nSum32bit += nValue2;
    5670      174480 :                             nSumSquare32bit += nValue2 * nValue2;
    5671      174480 :                             nSum32bit += nValue3;
    5672      174480 :                             nSumSquare32bit += nValue3 * nValue3;
    5673      174480 :                             nSum32bit += nValue4;
    5674      174480 :                             nSumSquare32bit += nValue4 * nValue4;
    5675             :                         }
    5676        2818 :                         nSum += nSum32bit;
    5677        2818 :                         nSumSquare += nSumSquare32bit;
    5678             :                     }
    5679        2824 :                     for (; iX < nXCheck; ++iX)
    5680             :                     {
    5681           6 :                         const GPtrDiff_t iOffset =
    5682           6 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5683           6 :                         const GUIntBig nValue = pData[iOffset];
    5684           6 :                         nSum += nValue;
    5685           6 :                         nSumSquare += nValue * nValue;
    5686             :                     }
    5687             :                 }
    5688          32 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5689          32 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5690          32 :             }
    5691             :         }
    5692             :         else
    5693             :         {
    5694        9026 :             for (int iY = 0; iY < nYCheck; iY++)
    5695             :             {
    5696        5866 :                 int iX = 0;
    5697       11732 :                 for (int k = 0; k < nOuterLoops; k++)
    5698             :                 {
    5699        5866 :                     int iMax = iX + 65536;
    5700        5866 :                     if (iMax > nXCheck)
    5701        5866 :                         iMax = nXCheck;
    5702        5866 :                     GUInt32 nSum32bit = 0;
    5703        5866 :                     GUInt32 nSumSquare32bit = 0;
    5704      343848 :                     for (; iX + 1 < iMax; iX += 2)
    5705             :                     {
    5706      337982 :                         const GPtrDiff_t iOffset =
    5707      337982 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5708      337982 :                         const GUInt32 nValue = pData[iOffset];
    5709      337982 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5710      337982 :                         if (nValue < nValue2)
    5711             :                         {
    5712        8155 :                             if (nValue < nMin)
    5713         237 :                                 nMin = nValue;
    5714        8155 :                             if (nValue2 > nMax)
    5715         230 :                                 nMax = nValue2;
    5716             :                         }
    5717             :                         else
    5718             :                         {
    5719      329827 :                             if (nValue2 < nMin)
    5720         364 :                                 nMin = nValue2;
    5721      329827 :                             if (nValue > nMax)
    5722         841 :                                 nMax = nValue;
    5723             :                         }
    5724             :                         if constexpr (COMPUTE_OTHER_STATS)
    5725             :                         {
    5726      315626 :                             nSum32bit += nValue;
    5727      315626 :                             nSumSquare32bit += nValue * nValue;
    5728      315626 :                             nSum32bit += nValue2;
    5729      315626 :                             nSumSquare32bit += nValue2 * nValue2;
    5730             :                         }
    5731             :                     }
    5732             :                     if constexpr (COMPUTE_OTHER_STATS)
    5733             :                     {
    5734        2650 :                         nSum += nSum32bit;
    5735        2650 :                         nSumSquare += nSumSquare32bit;
    5736             :                     }
    5737             :                 }
    5738        5866 :                 if (iX < nXCheck)
    5739             :                 {
    5740        1541 :                     const GPtrDiff_t iOffset =
    5741        1541 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5742        1541 :                     const GUInt32 nValue = pData[iOffset];
    5743        1541 :                     if (nValue < nMin)
    5744         117 :                         nMin = nValue;
    5745        1541 :                     if (nValue > nMax)
    5746         103 :                         nMax = nValue;
    5747             :                     if constexpr (COMPUTE_OTHER_STATS)
    5748             :                     {
    5749         321 :                         nSum += nValue;
    5750         321 :                         nSumSquare +=
    5751         321 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5752         321 :                             nValue;
    5753             :                     }
    5754             :                 }
    5755             :             }
    5756             :             if constexpr (COMPUTE_OTHER_STATS)
    5757             :             {
    5758         938 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5759         938 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5760             :             }
    5761             :         }
    5762       13828 :     }
    5763             : };
    5764             : 
    5765             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5766             : {
    5767             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5768             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5769             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5770             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5771             :     {
    5772             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5773             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5774             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5775             :     }
    5776             : };
    5777             : 
    5778             : constexpr int ALIGNMENT_AVX2_OPTIM = 32;
    5779             : 
    5780             : #if (defined(__x86_64__) || defined(_M_X64) ||                                 \
    5781             :      defined(USE_NEON_OPTIMIZATIONS)) &&                                       \
    5782             :     (defined(__GNUC__) || defined(_MSC_VER))
    5783             : 
    5784             : #include "gdal_avx2_emulation.hpp"
    5785             : 
    5786             : #define ZERO256 GDALmm256_setzero_si256()
    5787             : 
    5788             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5789             : static void
    5790       21355 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5791             :                               // assumed to be aligned on 256 bits
    5792             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5793             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5794             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5795             : {
    5796             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5797             :     GByte aby32ByteUnaligned[ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM +
    5798             :                              ALIGNMENT_AVX2_OPTIM +
    5799             :                              (COMPUTE_OTHER_STATS
    5800             :                                   ? ALIGNMENT_AVX2_OPTIM + ALIGNMENT_AVX2_OPTIM
    5801             :                                   : 0)];
    5802       21355 :     GByte *paby32ByteAligned =
    5803             :         aby32ByteUnaligned +
    5804       21355 :         (ALIGNMENT_AVX2_OPTIM -
    5805       21355 :          (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) %
    5806             :           ALIGNMENT_AVX2_OPTIM));
    5807       21355 :     GByte *pabyMin = paby32ByteAligned;
    5808       21355 :     GByte *pabyMax = paby32ByteAligned + ALIGNMENT_AVX2_OPTIM;
    5809       21355 :     GUInt32 *panSum = COMPUTE_OTHER_STATS
    5810             :                           ? reinterpret_cast<GUInt32 *>(
    5811             :                                 paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 2)
    5812             :                           : nullptr;
    5813       21355 :     GUInt32 *panSumSquare =
    5814             :         COMPUTE_OTHER_STATS ? reinterpret_cast<GUInt32 *>(
    5815             :                                   paby32ByteAligned + ALIGNMENT_AVX2_OPTIM * 3)
    5816             :                             : nullptr;
    5817             : 
    5818       21355 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % ALIGNMENT_AVX2_OPTIM) == 0);
    5819             : 
    5820       21355 :     GPtrDiff_t i = 0;
    5821             :     // Make sure that sumSquare can fit on uint32
    5822             :     // * 8 since we can hold 8 sums per vector register
    5823       21355 :     const int nMaxIterationsPerInnerLoop =
    5824             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5825       21355 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5826       21355 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5827       21355 :         nOuterLoops++;
    5828             : 
    5829             :     GDALm256i ymm_min =
    5830       21355 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5831       21355 :     GDALm256i ymm_max = ymm_min;
    5832       21355 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5833             : 
    5834       42710 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5835             :     {
    5836       21355 :         const auto iMax =
    5837       21355 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5838             : 
    5839             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5840       21355 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5841             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5842       21355 :             ZERO256;  // holds 8 uint32 sums
    5843      752431 :         for (; i + 31 < iMax; i += 32)
    5844             :         {
    5845      731076 :             const GDALm256i ymm = GDALmm256_load_si256(
    5846      731076 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5847             :             if (COMPUTE_MIN)
    5848             :             {
    5849      271015 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5850             :             }
    5851             :             if (COMPUTE_MAX)
    5852             :             {
    5853      636401 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5854             :             }
    5855             : 
    5856             :             if constexpr (COMPUTE_OTHER_STATS)
    5857             :             {
    5858             :                 // Extract even-8bit values
    5859             :                 const GDALm256i ymm_even =
    5860      531792 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5861             :                 // Compute square of those 16 values as 32 bit result
    5862             :                 // and add adjacent pairs
    5863             :                 const GDALm256i ymm_even_square =
    5864      531792 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5865             :                 // Add to the sumsquare accumulator
    5866             :                 ymm_sumsquare =
    5867      531792 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5868             : 
    5869             :                 // Extract odd-8bit values
    5870      531792 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5871             :                 const GDALm256i ymm_odd_square =
    5872      531792 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5873             :                 ymm_sumsquare =
    5874      531792 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5875             : 
    5876             :                 // Now compute the sums
    5877      531792 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5878             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5879             :             }
    5880             :         }
    5881             : 
    5882             :         if constexpr (COMPUTE_OTHER_STATS)
    5883             :         {
    5884       10685 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5885             :                                   ymm_sum);
    5886       10685 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5887             :                                   ymm_sumsquare);
    5888             : 
    5889       10685 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5890       10685 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5891       10685 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5892       10685 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5893             :                           panSumSquare[7];
    5894             :         }
    5895             :     }
    5896             : 
    5897             :     if constexpr (COMPUTE_MIN)
    5898             :     {
    5899        8464 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5900             :     }
    5901             :     if constexpr (COMPUTE_MAX)
    5902             :     {
    5903       17407 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5904             :     }
    5905             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5906             :     {
    5907      591459 :         for (int j = 0; j < 32; j++)
    5908             :         {
    5909             :             if constexpr (COMPUTE_MIN)
    5910             :             {
    5911      270848 :                 if (pabyMin[j] < nMin)
    5912        1247 :                     nMin = pabyMin[j];
    5913             :             }
    5914             :             if constexpr (COMPUTE_MAX)
    5915             :             {
    5916      557024 :                 if (pabyMax[j] > nMax)
    5917        1794 :                     nMax = pabyMax[j];
    5918             :             }
    5919             :         }
    5920             :     }
    5921             : 
    5922      234373 :     for (; i < nBlockPixels; i++)
    5923             :     {
    5924      213018 :         const GUInt32 nValue = pData[i];
    5925             :         if constexpr (COMPUTE_MIN)
    5926             :         {
    5927       88342 :             if (nValue < nMin)
    5928           2 :                 nMin = nValue;
    5929             :         }
    5930             :         if constexpr (COMPUTE_MAX)
    5931             :         {
    5932      210243 :             if (nValue > nMax)
    5933        1150 :                 nMax = nValue;
    5934             :         }
    5935             :         if constexpr (COMPUTE_OTHER_STATS)
    5936             :         {
    5937       77203 :             nSum += nValue;
    5938       77203 :             nSumSquare +=
    5939       77203 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5940             :         }
    5941             :     }
    5942             : 
    5943             :     if constexpr (COMPUTE_OTHER_STATS)
    5944             :     {
    5945       10685 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5946       10685 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5947             :     }
    5948       21355 : }
    5949             : 
    5950             : // SSE2/AVX2 optimization for GByte case
    5951             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5952             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5953             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5954             : template <bool COMPUTE_OTHER_STATS>
    5955             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5956             : {
    5957       30352 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5958             :                   // assumed to be aligned on 256 bits
    5959             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5960             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5961             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5962             :                   GUIntBig &nValidCount)
    5963             :     {
    5964       30352 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5965       30352 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5966       11610 :             nMin <= nMax)
    5967             :         {
    5968             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5969             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5970        1492 :             GByte *paby32ByteAligned =
    5971             :                 aby32ByteUnaligned +
    5972        1492 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5973        1492 :             GByte *pabyMin = paby32ByteAligned;
    5974        1492 :             GByte *pabyMax = paby32ByteAligned + 32;
    5975        1492 :             GUInt32 *panSum =
    5976             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5977        1492 :             GUInt32 *panSumSquare =
    5978             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5979             : 
    5980        1492 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5981             : 
    5982        1492 :             GPtrDiff_t i = 0;
    5983             :             // Make sure that sumSquare can fit on uint32
    5984             :             // * 8 since we can hold 8 sums per vector register
    5985        1492 :             const int nMaxIterationsPerInnerLoop =
    5986             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5987        1492 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5988        1492 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5989        1492 :                 nOuterLoops++;
    5990             : 
    5991             :             const GDALm256i ymm_nodata =
    5992        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5993             :             // any non noData value in [min,max] would do.
    5994             :             const GDALm256i ymm_neutral =
    5995        1492 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5996        1492 :             GDALm256i ymm_min = ymm_neutral;
    5997        1492 :             GDALm256i ymm_max = ymm_neutral;
    5998             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5999        1492 :                 GDALmm256_set1_epi16(0xFF);
    6000             : 
    6001        1492 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    6002        1492 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    6003        1492 :             const bool bComputeMinMax =
    6004        1492 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    6005             : 
    6006        2984 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    6007             :             {
    6008        1492 :                 const auto iMax =
    6009        1492 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6010             : 
    6011             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    6012        1492 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    6013             :                 // holds 8 uint32 sums
    6014        1492 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    6015             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    6016        1492 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    6017        1492 :                 const auto iInit = i;
    6018       18982 :                 for (; i + 31 < iMax; i += 32)
    6019             :                 {
    6020       17490 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6021       17490 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6022             : 
    6023             :                     // Check which values are nodata
    6024             :                     const GDALm256i ymm_eq_nodata =
    6025       17490 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    6026             :                     if constexpr (COMPUTE_OTHER_STATS)
    6027             :                     {
    6028             :                         // Count how many values are nodata (due to cmpeq
    6029             :                         // putting 255 when condition is met, this will actually
    6030             :                         // be 255 times the number of nodata value, spread in 4
    6031             :                         // 64 bits words). We can use add_epi32 as the counter
    6032             :                         // will not overflow uint32
    6033        9148 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    6034             :                             ymm_count_nodata_mul_255,
    6035             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    6036             :                     }
    6037             :                     // Replace all nodata values by zero for the purpose of sum
    6038             :                     // and sumquare.
    6039             :                     const GDALm256i ymm_nodata_by_zero =
    6040       17490 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    6041       17490 :                     if (bComputeMinMax)
    6042             :                     {
    6043             :                         // Replace all nodata values by a neutral value for the
    6044             :                         // purpose of min and max.
    6045             :                         const GDALm256i ymm_nodata_by_neutral =
    6046        8720 :                             GDALmm256_or_si256(
    6047             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    6048             :                                 ymm_nodata_by_zero);
    6049             : 
    6050             :                         ymm_min =
    6051        8720 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    6052             :                         ymm_max =
    6053        8720 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    6054             :                     }
    6055             : 
    6056             :                     if constexpr (COMPUTE_OTHER_STATS)
    6057             :                     {
    6058             :                         // Extract even-8bit values
    6059        9148 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    6060             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    6061             :                         // Compute square of those 16 values as 32 bit result
    6062             :                         // and add adjacent pairs
    6063             :                         const GDALm256i ymm_even_square =
    6064        9148 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    6065             :                         // Add to the sumsquare accumulator
    6066             :                         ymm_sumsquare =
    6067        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    6068             : 
    6069             :                         // Extract odd-8bit values
    6070             :                         const GDALm256i ymm_odd =
    6071        9148 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    6072             :                         const GDALm256i ymm_odd_square =
    6073        9148 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    6074             :                         ymm_sumsquare =
    6075        9148 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    6076             : 
    6077             :                         // Now compute the sums
    6078        9148 :                         ymm_sum = GDALmm256_add_epi32(
    6079             :                             ymm_sum,
    6080             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    6081             :                     }
    6082             :                 }
    6083             : 
    6084             :                 if constexpr (COMPUTE_OTHER_STATS)
    6085             :                 {
    6086         186 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    6087         186 :                     GDALmm256_store_si256(
    6088             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    6089             :                         ymm_count_nodata_mul_255);
    6090             : 
    6091         186 :                     nSampleCount += (i - iInit);
    6092             : 
    6093         186 :                     nValidCount +=
    6094         186 :                         (i - iInit) -
    6095         186 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    6096         186 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    6097             :                             255;
    6098             : 
    6099         186 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    6100             :                                           ymm_sum);
    6101         186 :                     GDALmm256_store_si256(
    6102             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    6103             :                         ymm_sumsquare);
    6104         186 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    6105         186 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    6106         186 :                                   panSumSquare[1] + panSumSquare[2] +
    6107         186 :                                   panSumSquare[3] + panSumSquare[4] +
    6108         186 :                                   panSumSquare[5] + panSumSquare[6] +
    6109             :                                   panSumSquare[7];
    6110             :                 }
    6111             :             }
    6112             : 
    6113        1492 :             if (bComputeMinMax)
    6114             :             {
    6115        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    6116             :                                       ymm_min);
    6117        1430 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    6118             :                                       ymm_max);
    6119       47190 :                 for (int j = 0; j < 32; j++)
    6120             :                 {
    6121       45760 :                     if (pabyMin[j] < nMin)
    6122          40 :                         nMin = pabyMin[j];
    6123       45760 :                     if (pabyMax[j] > nMax)
    6124         161 :                         nMax = pabyMax[j];
    6125             :                 }
    6126             :             }
    6127             : 
    6128             :             if constexpr (COMPUTE_OTHER_STATS)
    6129             :             {
    6130         186 :                 nSampleCount += nBlockPixels - i;
    6131             :             }
    6132       34048 :             for (; i < nBlockPixels; i++)
    6133             :             {
    6134       32556 :                 const GUInt32 nValue = pData[i];
    6135       32556 :                 if (nValue == nNoDataValue)
    6136       24923 :                     continue;
    6137        7633 :                 if (nValue < nMin)
    6138           2 :                     nMin = nValue;
    6139        7633 :                 if (nValue > nMax)
    6140          14 :                     nMax = nValue;
    6141             :                 if constexpr (COMPUTE_OTHER_STATS)
    6142             :                 {
    6143        3700 :                     nValidCount++;
    6144        3700 :                     nSum += nValue;
    6145        3700 :                     nSumSquare +=
    6146        3700 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6147        3700 :                         nValue;
    6148             :                 }
    6149        1492 :             }
    6150             :         }
    6151       28860 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    6152             :         {
    6153       14999 :             if (nMin > 0)
    6154             :             {
    6155        2108 :                 if (nMax < 255)
    6156             :                 {
    6157             :                     ComputeStatisticsByteNoNodata<true, true,
    6158        1592 :                                                   COMPUTE_OTHER_STATS>(
    6159             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6160             :                         nSampleCount, nValidCount);
    6161             :                 }
    6162             :                 else
    6163             :                 {
    6164             :                     ComputeStatisticsByteNoNodata<true, false,
    6165         516 :                                                   COMPUTE_OTHER_STATS>(
    6166             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6167             :                         nSampleCount, nValidCount);
    6168             :                 }
    6169             :             }
    6170             :             else
    6171             :             {
    6172       12891 :                 if (nMax < 255)
    6173             :                 {
    6174             :                     ComputeStatisticsByteNoNodata<false, true,
    6175        9459 :                                                   COMPUTE_OTHER_STATS>(
    6176             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6177             :                         nSampleCount, nValidCount);
    6178             :                 }
    6179             :                 else
    6180             :                 {
    6181             :                     ComputeStatisticsByteNoNodata<false, false,
    6182        3432 :                                                   COMPUTE_OTHER_STATS>(
    6183             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6184             :                         nSampleCount, nValidCount);
    6185             :                 }
    6186             :             }
    6187             :         }
    6188       12561 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    6189          33 :                  (nBlockXSize % 32) == 0)
    6190             :         {
    6191        6389 :             for (int iY = 0; iY < nYCheck; iY++)
    6192             :             {
    6193        6356 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    6194        6356 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    6195             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6196          33 :             }
    6197             :         }
    6198             :         else
    6199             :         {
    6200       13828 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    6201             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6202             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6203             :         }
    6204       30352 :     }
    6205             : };
    6206             : 
    6207             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    6208         578 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    6209             :                              GUIntBig i)
    6210             : {
    6211         578 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    6212         578 : }
    6213             : 
    6214             : // AVX2/SSE2 optimization for GUInt16 case
    6215             : template <bool COMPUTE_OTHER_STATS>
    6216             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    6217             : {
    6218        2153 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    6219             :                   // assumed to be aligned on 128 bits
    6220             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    6221             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    6222             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    6223             :                   GUIntBig &nValidCount)
    6224             :     {
    6225        2153 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    6226        2153 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    6227             :         {
    6228        1852 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    6229             : 
    6230        1852 :             GPtrDiff_t i = 0;
    6231             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    6232             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    6233             :             // Furthermore the shift is also needed to use madd_epi16
    6234        1852 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    6235        1852 :             GDALm256i ymm_min = GDALmm256_load_si256(
    6236        1852 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6237        1852 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6238        1852 :             GDALm256i ymm_max = ymm_min;
    6239             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6240        1852 :                 ZERO256;  // holds 4 uint64 sums
    6241             : 
    6242             :             // Make sure that sum can fit on uint32
    6243             :             // * 8 since we can hold 8 sums per vector register
    6244        1852 :             const int nMaxIterationsPerInnerLoop =
    6245             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6246        1852 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6247        1852 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6248        1852 :                 nOuterLoops++;
    6249             : 
    6250        1852 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6251             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6252        1852 :                 GDALmm256_set1_epi32(0xFFFF);
    6253             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6254        1852 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6255             : 
    6256        1852 :             GUIntBig nSumThis = 0;
    6257        3728 :             for (int k = 0; k < nOuterLoops; k++)
    6258             :             {
    6259        1876 :                 const auto iMax =
    6260        1876 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6261             : 
    6262             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6263        1876 :                     ZERO256;  // holds 8 uint32 sums
    6264     1112456 :                 for (; i + 15 < iMax; i += 16)
    6265             :                 {
    6266     1110580 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6267     1110580 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6268             :                     const GDALm256i ymm_shifted =
    6269     1110580 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6270     1110580 :                     if (bComputeMinMax)
    6271             :                     {
    6272     1092542 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6273     1092542 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6274             :                     }
    6275             : 
    6276             :                     if constexpr (COMPUTE_OTHER_STATS)
    6277             :                     {
    6278             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6279             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6280             :                         // is positive, this is OK as we interpret is a uint32.
    6281             :                         const GDALm256i ymm_square =
    6282      243562 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6283      243562 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6284             :                             ymm_sumsquare,
    6285             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6286      243562 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6287             :                             ymm_sumsquare,
    6288             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6289             : 
    6290             :                         // Now compute the sums
    6291      243562 :                         ymm_sum = GDALmm256_add_epi32(
    6292             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6293      243562 :                         ymm_sum = GDALmm256_add_epi32(
    6294             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6295             :                     }
    6296             :                 }
    6297             : 
    6298             :                 if constexpr (COMPUTE_OTHER_STATS)
    6299             :                 {
    6300             :                     GUInt32 anSum[8];
    6301         578 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6302             :                                            ymm_sum);
    6303         578 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6304         578 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6305         578 :                                 anSum[6] + anSum[7];
    6306             :                 }
    6307             :             }
    6308             : 
    6309        1852 :             if (bComputeMinMax)
    6310             :             {
    6311             :                 GUInt16 anMin[16];
    6312             :                 GUInt16 anMax[16];
    6313             : 
    6314             :                 // Unshift the result
    6315        1770 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6316        1770 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6317        1770 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6318             :                                        ymm_min);
    6319        1770 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6320             :                                        ymm_max);
    6321       30090 :                 for (int j = 0; j < 16; j++)
    6322             :                 {
    6323       28320 :                     if (anMin[j] < nMin)
    6324         394 :                         nMin = anMin[j];
    6325       28320 :                     if (anMax[j] > nMax)
    6326         571 :                         nMax = anMax[j];
    6327             :                 }
    6328             :             }
    6329             : 
    6330             :             if constexpr (COMPUTE_OTHER_STATS)
    6331             :             {
    6332             :                 GUIntBig anSumSquare[4];
    6333         578 :                 GDALmm256_storeu_si256(
    6334             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6335         578 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6336             :                               anSumSquare[3];
    6337             : 
    6338             :                 // Unshift the sum of squares
    6339         578 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6340             :                                  static_cast<GUIntBig>(i));
    6341             : 
    6342         578 :                 nSum += nSumThis;
    6343             : 
    6344        1022 :                 for (; i < nBlockPixels; i++)
    6345             :                 {
    6346         444 :                     const GUInt32 nValue = pData[i];
    6347         444 :                     if (nValue < nMin)
    6348           2 :                         nMin = nValue;
    6349         444 :                     if (nValue > nMax)
    6350           2 :                         nMax = nValue;
    6351         444 :                     nSum += nValue;
    6352         444 :                     nSumSquare +=
    6353         444 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6354         444 :                         nValue;
    6355             :                 }
    6356             : 
    6357         578 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6358         578 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6359        1852 :             }
    6360             :         }
    6361             :         else
    6362             :         {
    6363         301 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6364             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6365             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6366             :         }
    6367        2153 :     }
    6368             : };
    6369             : 
    6370             : #endif
    6371             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6372             : // defined(_MSC_VER))
    6373             : 
    6374             : /************************************************************************/
    6375             : /*                           GetPixelValue()                            */
    6376             : /************************************************************************/
    6377             : 
    6378    15872500 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6379             :                                    const void *pData, GPtrDiff_t iOffset,
    6380             :                                    const GDALNoDataValues &sNoDataValues,
    6381             :                                    bool &bValid)
    6382             : {
    6383    15872500 :     bValid = true;
    6384    15872500 :     double dfValue = 0;
    6385    15872500 :     switch (eDataType)
    6386             :     {
    6387     1400770 :         case GDT_UInt8:
    6388             :         {
    6389     1400770 :             if (bSignedByte)
    6390         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6391             :             else
    6392     1400580 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6393     1400770 :             break;
    6394             :         }
    6395         641 :         case GDT_Int8:
    6396         641 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6397         641 :             break;
    6398      200608 :         case GDT_UInt16:
    6399      200608 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6400      200608 :             break;
    6401       54336 :         case GDT_Int16:
    6402       54336 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6403       54336 :             break;
    6404       10478 :         case GDT_UInt32:
    6405       10478 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6406       10478 :             break;
    6407      140220 :         case GDT_Int32:
    6408      140220 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6409      140220 :             break;
    6410          60 :         case GDT_UInt64:
    6411          60 :             dfValue = static_cast<double>(
    6412          60 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6413          60 :             break;
    6414        3268 :         case GDT_Int64:
    6415        3268 :             dfValue = static_cast<double>(
    6416        3268 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6417        3268 :             break;
    6418          40 :         case GDT_Float16:
    6419             :         {
    6420             :             using namespace std;
    6421          40 :             const GFloat16 hfValue =
    6422          40 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6423          74 :             if (isnan(hfValue) ||
    6424          34 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6425          28 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6426             :             {
    6427           6 :                 bValid = false;
    6428           6 :                 return 0.0;
    6429             :             }
    6430          34 :             dfValue = hfValue;
    6431          34 :             return dfValue;
    6432             :         }
    6433    13644000 :         case GDT_Float32:
    6434             :         {
    6435    13644000 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6436    27261100 :             if (std::isnan(fValue) ||
    6437    26886000 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6438    13268900 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6439             :             {
    6440       26883 :                 bValid = false;
    6441       26883 :                 return 0.0;
    6442             :             }
    6443    13617100 :             dfValue = double(fValue);
    6444    13617100 :             return dfValue;
    6445             :         }
    6446      400956 :         case GDT_Float64:
    6447      400956 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6448      400956 :             if (std::isnan(dfValue))
    6449             :             {
    6450           6 :                 bValid = false;
    6451           6 :                 return 0.0;
    6452             :             }
    6453      400950 :             break;
    6454        2692 :         case GDT_CInt16:
    6455        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6456        2692 :             break;
    6457        2692 :         case GDT_CInt32:
    6458        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6459        2692 :             break;
    6460           0 :         case GDT_CFloat16:
    6461           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6462           0 :             if (std::isnan(dfValue))
    6463             :             {
    6464           0 :                 bValid = false;
    6465           0 :                 return 0.0;
    6466             :             }
    6467           0 :             break;
    6468        5812 :         case GDT_CFloat32:
    6469        5812 :             dfValue = double(static_cast<const float *>(pData)[iOffset * 2]);
    6470        5812 :             if (std::isnan(dfValue))
    6471             :             {
    6472           0 :                 bValid = false;
    6473           0 :                 return 0.0;
    6474             :             }
    6475        5812 :             break;
    6476        5892 :         case GDT_CFloat64:
    6477        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6478        5892 :             if (std::isnan(dfValue))
    6479             :             {
    6480           0 :                 bValid = false;
    6481           0 :                 return 0.0;
    6482             :             }
    6483        5892 :             break;
    6484           0 :         case GDT_Unknown:
    6485             :         case GDT_TypeCount:
    6486           0 :             CPLAssert(false);
    6487             :             break;
    6488             :     }
    6489             : 
    6490     2483820 :     if (sNoDataValues.bGotNoDataValue &&
    6491      255405 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6492             :     {
    6493        4222 :         bValid = false;
    6494        4222 :         return 0.0;
    6495             :     }
    6496     2224190 :     return dfValue;
    6497             : }
    6498             : 
    6499             : /************************************************************************/
    6500             : /*                          SetValidPercent()                           */
    6501             : /************************************************************************/
    6502             : 
    6503             : //! @cond Doxygen_Suppress
    6504             : /**
    6505             :  * \brief Set percentage of valid (not nodata) pixels.
    6506             :  *
    6507             :  * Stores the percentage of valid pixels in the metadata item
    6508             :  * STATISTICS_VALID_PERCENT
    6509             :  *
    6510             :  * @param nSampleCount Number of sampled pixels.
    6511             :  *
    6512             :  * @param nValidCount Number of valid pixels.
    6513             :  */
    6514             : 
    6515         599 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6516             :                                      GUIntBig nValidCount)
    6517             : {
    6518         599 :     if (nValidCount == 0)
    6519             :     {
    6520          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6521             :     }
    6522         587 :     else if (nValidCount == nSampleCount)
    6523             :     {
    6524         494 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6525             :     }
    6526             :     else /* nValidCount < nSampleCount */
    6527             :     {
    6528          93 :         char szValue[128] = {0};
    6529             : 
    6530             :         /* percentage is only an indicator: limit precision */
    6531          93 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6532          93 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6533             : 
    6534          93 :         if (EQUAL(szValue, "100"))
    6535             :         {
    6536             :             /* don't set 100 percent valid
    6537             :              * because some of the sampled pixels were nodata */
    6538           4 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6539             :         }
    6540             :         else
    6541             :         {
    6542          89 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6543             :         }
    6544             :     }
    6545         599 : }
    6546             : 
    6547             : //! @endcond
    6548             : 
    6549             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6550             : 
    6551             : #ifdef __AVX2__
    6552             : 
    6553             : #define set1_ps _mm256_set1_ps
    6554             : #define loadu_ps _mm256_loadu_ps
    6555             : #define or_ps _mm256_or_ps
    6556             : #define min_ps _mm256_min_ps
    6557             : #define max_ps _mm256_max_ps
    6558             : #define cmpeq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_EQ_OQ)
    6559             : #define cmpneq_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_NEQ_OQ)
    6560             : #define cmpunord_ps(x, y) _mm256_cmp_ps((x), (y), _CMP_UNORD_Q)
    6561             : #define movemask_ps _mm256_movemask_ps
    6562             : #define storeu_ps _mm256_storeu_ps
    6563             : #define cvtps_lo_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 0))
    6564             : #define cvtps_hi_pd(x) _mm256_cvtps_pd(_mm256_extractf128_ps((x), 1))
    6565             : 
    6566             : #define unpacklo_ps _mm256_unpacklo_ps
    6567             : #define castps_pd _mm256_castps_pd
    6568             : 
    6569             : inline __m256 dup_hi_ps(__m256 x)
    6570             : {
    6571             :     const __m256i idx = _mm256_set_epi32(7, 7, 6, 6, 5, 5, 4, 4);
    6572             :     return _mm256_permutevar8x32_ps(x, idx);
    6573             : }
    6574             : 
    6575             : #define setzero_pd _mm256_setzero_pd
    6576             : #define set1_pd _mm256_set1_pd
    6577             : #define loadu_pd _mm256_loadu_pd
    6578             : #define or_pd _mm256_or_pd
    6579             : #define min_pd _mm256_min_pd
    6580             : #define max_pd _mm256_max_pd
    6581             : #define cmpeq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_EQ_OQ)
    6582             : #define cmpneq_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_NEQ_OQ)
    6583             : #define cmpunord_pd(x, y) _mm256_cmp_pd((x), (y), _CMP_UNORD_Q)
    6584             : #define movemask_pd _mm256_movemask_pd
    6585             : #define add_pd _mm256_add_pd
    6586             : #define sub_pd _mm256_sub_pd
    6587             : #define mul_pd _mm256_mul_pd
    6588             : #define div_pd _mm256_div_pd
    6589             : #define storeu_pd _mm256_storeu_pd
    6590             : #define cvtsd_f64(x) _mm_cvtsd_f64(_mm256_castpd256_pd128((x)))
    6591             : #define blendv_pd _mm256_blendv_pd
    6592             : #ifdef __FMA__
    6593             : #define fmadd_pd _mm256_fmadd_pd
    6594             : #else
    6595             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6596             : #endif
    6597             : 
    6598             : #else
    6599             : 
    6600             : #define set1_ps _mm_set1_ps
    6601             : #define loadu_ps _mm_loadu_ps
    6602             : #define or_ps _mm_or_ps
    6603             : #define min_ps _mm_min_ps
    6604             : #define max_ps _mm_max_ps
    6605             : #define cmpeq_ps _mm_cmpeq_ps
    6606             : #define cmpneq_ps _mm_cmpneq_ps
    6607             : #define cmpunord_ps _mm_cmpunord_ps
    6608             : #define movemask_ps _mm_movemask_ps
    6609             : #define storeu_ps _mm_storeu_ps
    6610             : #define cvtps_lo_pd(x) _mm_cvtps_pd((x))
    6611             : #define cvtps_hi_pd(x) _mm_cvtps_pd(_mm_movehl_ps((x), (x)))
    6612             : #define unpacklo_ps _mm_unpacklo_ps
    6613             : #define castps_pd _mm_castps_pd
    6614             : #define dup_hi_ps(x) _mm_unpackhi_ps((x), (x))
    6615             : 
    6616             : #define setzero_pd _mm_setzero_pd
    6617             : #define set1_pd _mm_set1_pd
    6618             : #define loadu_pd _mm_loadu_pd
    6619             : #define or_pd _mm_or_pd
    6620             : #define min_pd _mm_min_pd
    6621             : #define max_pd _mm_max_pd
    6622             : #define cmpeq_pd _mm_cmpeq_pd
    6623             : #define cmpneq_pd _mm_cmpneq_pd
    6624             : #define cmpunord_pd _mm_cmpunord_pd
    6625             : #define movemask_pd _mm_movemask_pd
    6626             : #define add_pd _mm_add_pd
    6627             : #define sub_pd _mm_sub_pd
    6628             : #define mul_pd _mm_mul_pd
    6629             : #define div_pd _mm_div_pd
    6630             : #define storeu_pd _mm_storeu_pd
    6631             : #define cvtsd_f64 _mm_cvtsd_f64
    6632             : #ifdef __FMA__
    6633             : #define fmadd_pd _mm_fmadd_pd
    6634             : #else
    6635             : #define fmadd_pd(a, b, c) add_pd(mul_pd((a), (b)), (c))
    6636             : #endif
    6637             : 
    6638     4299340 : inline __m128d blendv_pd(__m128d a, __m128d b, __m128d mask)
    6639             : {
    6640             : #if defined(__SSE4_1__) || defined(__AVX__) || defined(USE_NEON_OPTIMIZATIONS)
    6641             :     return _mm_blendv_pd(a, b, mask);
    6642             : #else
    6643    12898000 :     return _mm_or_pd(_mm_andnot_pd(mask, a), _mm_and_pd(mask, b));
    6644             : #endif
    6645             : }
    6646             : #endif
    6647             : 
    6648             : #define dup_lo_ps(x) unpacklo_ps((x), (x))
    6649             : 
    6650             : /************************************************************************/
    6651             : /*                   ComputeStatisticsFloat32_SSE2()                    */
    6652             : /************************************************************************/
    6653             : 
    6654             : template <bool HAS_NAN, bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6655             : #if defined(__GNUC__)
    6656             : __attribute__((noinline))
    6657             : #endif
    6658        8326 : static int ComputeStatisticsFloat32_SSE2(const float *const pafData,
    6659             :                                          [[maybe_unused]] float fNoDataValue,
    6660             :                                          int iX, int nCount, float &fMin,
    6661             :                                          float &fMax, double &dfBlockMean,
    6662             :                                          double &dfBlockM2,
    6663             :                                          double &dfBlockValidCount)
    6664             : {
    6665        8326 :     auto vValidCount = setzero_pd();
    6666        8326 :     const auto vOne = set1_pd(1);
    6667        8326 :     [[maybe_unused]] const auto vNoData = set1_ps(fNoDataValue);
    6668             : 
    6669        8326 :     auto vMin = set1_ps(fMin);
    6670       16652 :     auto vMax = set1_ps(fMax);
    6671             : 
    6672        8326 :     auto vMean_lo = setzero_pd();
    6673        8326 :     auto vM2_lo = setzero_pd();
    6674             : 
    6675        8326 :     auto vMean_hi = setzero_pd();
    6676        8326 :     auto vM2_hi = setzero_pd();
    6677             : 
    6678        8326 :     constexpr int VALS_PER_LOOP =
    6679             :         static_cast<int>(sizeof(vOne) / sizeof(float));
    6680     1258075 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6681             :     {
    6682     2499510 :         const auto vValues = loadu_ps(pafData + iX);
    6683             : 
    6684             :         if constexpr (HAS_NAN)
    6685             :         {
    6686     1236117 :             auto isNaNOrNoData = cmpunord_ps(vValues, vValues);
    6687             :             if constexpr (HAS_NODATA)
    6688             :             {
    6689             :                 isNaNOrNoData =
    6690           0 :                     or_ps(isNaNOrNoData, cmpeq_ps(vValues, vNoData));
    6691             :             }
    6692     1236117 :             if (movemask_ps(isNaNOrNoData))
    6693             :             {
    6694           1 :                 break;
    6695             :             }
    6696             :         }
    6697             :         else if constexpr (HAS_NODATA)
    6698             :         {
    6699           0 :             if (movemask_ps(cmpeq_ps(vValues, vNoData)))
    6700             :             {
    6701           0 :                 break;
    6702             :             }
    6703             :         }
    6704             : 
    6705     1249754 :         vMin = min_ps(vMin, vValues);
    6706     1249754 :         vMax = max_ps(vMax, vValues);
    6707             : 
    6708     1249754 :         const auto vValues_lo = cvtps_lo_pd(vValues);
    6709     2499508 :         const auto vValues_hi = cvtps_hi_pd(vValues);
    6710     1249754 :         [[maybe_unused]] const auto vMinNotSameAsMax = cmpneq_ps(vMin, vMax);
    6711             : 
    6712     1249754 :         vValidCount = add_pd(vValidCount, vOne);
    6713     1249754 :         const auto vInvValidCount = div_pd(vOne, vValidCount);
    6714             : 
    6715     1249754 :         const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
    6716     2298362 :         const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
    6717             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6718             :         {
    6719             :             const auto vMinNotSameAsMax_lo =
    6720     1048608 :                 castps_pd(dup_lo_ps(vMinNotSameAsMax));
    6721     1048608 :             vMean_lo = blendv_pd(vValues_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6722             :             const auto vNewM2_lo =
    6723     2097216 :                 fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6724     1048608 :             vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6725             :         }
    6726             :         else
    6727             :         {
    6728      201146 :             vMean_lo = vNewMean_lo;
    6729      603438 :             vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6730             :         }
    6731             : 
    6732     1249754 :         const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
    6733     2298362 :         const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
    6734             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6735             :         {
    6736             :             const auto vMinNotSameAsMax_hi =
    6737     1048608 :                 castps_pd(dup_hi_ps(vMinNotSameAsMax));
    6738     1048608 :             vMean_hi = blendv_pd(vValues_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6739             :             const auto vNewM2_hi =
    6740     2097216 :                 fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6741     1048608 :             vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6742             :         }
    6743             :         else
    6744             :         {
    6745      201146 :             vMean_hi = vNewMean_hi;
    6746      603438 :             vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6747             :         }
    6748             :     }
    6749        8326 :     const double dfValidVectorCount = cvtsd_f64(vValidCount);
    6750        8326 :     if (dfValidVectorCount > 0)
    6751             :     {
    6752             :         float afMin[VALS_PER_LOOP], afMax[VALS_PER_LOOP];
    6753             :         storeu_ps(afMin, vMin);
    6754             :         storeu_ps(afMax, vMax);
    6755       39955 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6756             :         {
    6757       31964 :             fMin = std::min(fMin, afMin[i]);
    6758       31964 :             fMax = std::max(fMax, afMax[i]);
    6759             :         }
    6760             : 
    6761             :         double adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
    6762             :         storeu_pd(adfMean, vMean_lo);
    6763             :         storeu_pd(adfM2, vM2_lo);
    6764        7991 :         storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
    6765        7991 :         storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
    6766       39955 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6767             :         {
    6768       31964 :             const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
    6769       31964 :             dfBlockM2 += adfM2[i];
    6770       31964 :             if (adfMean[i] != dfBlockMean)
    6771             :             {
    6772       13172 :                 const double dfDelta = adfMean[i] - dfBlockMean;
    6773       13172 :                 dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
    6774       13172 :                 dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
    6775       13172 :                              dfValidVectorCount / dfNewValidCount;
    6776             :             }
    6777       31964 :             dfBlockValidCount = dfNewValidCount;
    6778             :         }
    6779             :     }
    6780             : 
    6781        8326 :     return iX;
    6782             : }
    6783             : 
    6784             : /************************************************************************/
    6785             : /*                   ComputeStatisticsFloat64_SSE2()                    */
    6786             : /************************************************************************/
    6787             : 
    6788             : template <bool CHECK_MIN_NOT_SAME_AS_MAX, bool HAS_NODATA>
    6789             : #if defined(__GNUC__)
    6790             : __attribute__((noinline))
    6791             : #endif
    6792        2367 : static int ComputeStatisticsFloat64_SSE2(const double *padfData,
    6793             :                                          [[maybe_unused]] double dfNoDataValue,
    6794             :                                          int iX, int nCount, double &dfMin,
    6795             :                                          double &dfMax, double &dfBlockMean,
    6796             :                                          double &dfBlockM2,
    6797             :                                          double &dfBlockValidCount)
    6798             : {
    6799        2367 :     auto vValidCount = setzero_pd();
    6800        2367 :     const auto vOne = set1_pd(1);
    6801        2367 :     [[maybe_unused]] const auto vNoData = set1_pd(dfNoDataValue);
    6802             : 
    6803        2367 :     auto vMin_lo = set1_pd(dfMin);
    6804        4734 :     auto vMax_lo = set1_pd(dfMax);
    6805        2367 :     auto vMean_lo = setzero_pd();
    6806        2367 :     auto vM2_lo = setzero_pd();
    6807             : 
    6808        2367 :     auto vMin_hi = vMin_lo;
    6809        2367 :     auto vMax_hi = vMax_lo;
    6810        2367 :     auto vMean_hi = setzero_pd();
    6811        2367 :     auto vM2_hi = setzero_pd();
    6812             : 
    6813        2367 :     constexpr int VALS_PER_LOOP =
    6814             :         2 * static_cast<int>(sizeof(vOne) / sizeof(double));
    6815      107199 :     for (; iX <= nCount - VALS_PER_LOOP; iX += VALS_PER_LOOP)
    6816             :     {
    6817      104875 :         const auto vValues_lo = loadu_pd(padfData + iX);
    6818      209750 :         const auto vValues_hi = loadu_pd(padfData + iX + VALS_PER_LOOP / 2);
    6819             :         // Check if there's at least one NaN in both vectors
    6820      104875 :         auto isNaNOrNoData = cmpunord_pd(vValues_lo, vValues_hi);
    6821             :         if constexpr (HAS_NODATA)
    6822             :         {
    6823             :             isNaNOrNoData =
    6824      103248 :                 or_pd(isNaNOrNoData, or_pd(cmpeq_pd(vValues_lo, vNoData),
    6825             :                                            cmpeq_pd(vValues_hi, vNoData)));
    6826             :         }
    6827      104875 :         if (movemask_pd(isNaNOrNoData))
    6828             :         {
    6829          43 :             break;
    6830             :         }
    6831             : 
    6832      104832 :         vValidCount = add_pd(vValidCount, vOne);
    6833      104832 :         const auto vInvValidCount = div_pd(vOne, vValidCount);
    6834             : 
    6835      104832 :         vMin_lo = min_pd(vMin_lo, vValues_lo);
    6836      104832 :         vMax_lo = max_pd(vMax_lo, vValues_lo);
    6837      104832 :         const auto vDelta_lo = sub_pd(vValues_lo, vMean_lo);
    6838      131060 :         const auto vNewMean_lo = fmadd_pd(vDelta_lo, vInvValidCount, vMean_lo);
    6839             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6840             :         {
    6841       26228 :             const auto vMinNotSameAsMax_lo = cmpneq_pd(vMin_lo, vMax_lo);
    6842       26228 :             vMean_lo = blendv_pd(vMin_lo, vNewMean_lo, vMinNotSameAsMax_lo);
    6843             :             const auto vNewM2_lo =
    6844       52456 :                 fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6845       26228 :             vM2_lo = blendv_pd(vM2_lo, vNewM2_lo, vMinNotSameAsMax_lo);
    6846             :         }
    6847             :         else
    6848             :         {
    6849       78604 :             vMean_lo = vNewMean_lo;
    6850      235812 :             vM2_lo = fmadd_pd(vDelta_lo, sub_pd(vValues_lo, vMean_lo), vM2_lo);
    6851             :         }
    6852             : 
    6853      104832 :         vMin_hi = min_pd(vMin_hi, vValues_hi);
    6854      104832 :         vMax_hi = max_pd(vMax_hi, vValues_hi);
    6855      104832 :         const auto vDelta_hi = sub_pd(vValues_hi, vMean_hi);
    6856      131060 :         const auto vNewMean_hi = fmadd_pd(vDelta_hi, vInvValidCount, vMean_hi);
    6857             :         if constexpr (CHECK_MIN_NOT_SAME_AS_MAX)
    6858             :         {
    6859       26228 :             const auto vMinNotSameAsMax_hi = cmpneq_pd(vMin_hi, vMax_hi);
    6860       26228 :             vMean_hi = blendv_pd(vMin_hi, vNewMean_hi, vMinNotSameAsMax_hi);
    6861             :             const auto vNewM2_hi =
    6862       52456 :                 fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6863       26228 :             vM2_hi = blendv_pd(vM2_hi, vNewM2_hi, vMinNotSameAsMax_hi);
    6864             :         }
    6865             :         else
    6866             :         {
    6867       78604 :             vMean_hi = vNewMean_hi;
    6868      235812 :             vM2_hi = fmadd_pd(vDelta_hi, sub_pd(vValues_hi, vMean_hi), vM2_hi);
    6869             :         }
    6870             :     }
    6871        2367 :     const double dfValidVectorCount = cvtsd_f64(vValidCount);
    6872        2367 :     if (dfValidVectorCount > 0)
    6873             :     {
    6874             :         double adfMin[VALS_PER_LOOP], adfMax[VALS_PER_LOOP],
    6875             :             adfMean[VALS_PER_LOOP], adfM2[VALS_PER_LOOP];
    6876             :         storeu_pd(adfMin, vMin_lo);
    6877             :         storeu_pd(adfMax, vMax_lo);
    6878             :         storeu_pd(adfMean, vMean_lo);
    6879             :         storeu_pd(adfM2, vM2_lo);
    6880        1801 :         storeu_pd(adfMin + VALS_PER_LOOP / 2, vMin_hi);
    6881        1801 :         storeu_pd(adfMax + VALS_PER_LOOP / 2, vMax_hi);
    6882        1801 :         storeu_pd(adfMean + VALS_PER_LOOP / 2, vMean_hi);
    6883        1801 :         storeu_pd(adfM2 + VALS_PER_LOOP / 2, vM2_hi);
    6884             : 
    6885        9005 :         for (int i = 0; i < VALS_PER_LOOP; ++i)
    6886             :         {
    6887        7204 :             dfMin = std::min(dfMin, adfMin[i]);
    6888        7204 :             dfMax = std::max(dfMax, adfMax[i]);
    6889        7204 :             const auto dfNewValidCount = dfBlockValidCount + dfValidVectorCount;
    6890        7204 :             dfBlockM2 += adfM2[i];
    6891        7204 :             if (adfMean[i] != dfBlockMean)
    6892             :             {
    6893        5871 :                 const double dfDelta = adfMean[i] - dfBlockMean;
    6894        5871 :                 dfBlockMean += dfDelta * dfValidVectorCount / dfNewValidCount;
    6895        5871 :                 dfBlockM2 += dfDelta * dfDelta * dfBlockValidCount *
    6896        5871 :                              dfValidVectorCount / dfNewValidCount;
    6897             :             }
    6898        7204 :             dfBlockValidCount = dfNewValidCount;
    6899             :         }
    6900             :     }
    6901             : 
    6902        2367 :     return iX;
    6903             : }
    6904             : 
    6905             : #endif
    6906             : 
    6907             : /************************************************************************/
    6908             : /*                   ComputeBlockStatisticsFloat32()                    */
    6909             : /************************************************************************/
    6910             : 
    6911             : template <bool HAS_NAN, bool HAS_NODATA>
    6912        4729 : static void ComputeBlockStatisticsFloat32(
    6913             :     const float *const pafSrcData, const int nBlockXSize, const int nXCheck,
    6914             :     const int nYCheck, const GDALNoDataValues &sNoDataValues, float &fMinInOut,
    6915             :     float &fMaxInOut, double &dfBlockMeanInOut, double &dfBlockM2InOut,
    6916             :     double &dfBlockValidCountInOut)
    6917             : {
    6918        4729 :     float fMin = fMinInOut;
    6919        4729 :     float fMax = fMaxInOut;
    6920        4729 :     double dfBlockMean = dfBlockMeanInOut;
    6921        4729 :     double dfBlockM2 = dfBlockM2InOut;
    6922        4729 :     double dfBlockValidCount = dfBlockValidCountInOut;
    6923             : 
    6924       13055 :     for (int iY = 0; iY < nYCheck; iY++)
    6925             :     {
    6926        8326 :         const int iOffset = iY * nBlockXSize;
    6927        8326 :         if (dfBlockValidCount > 0 && fMin != fMax)
    6928             :         {
    6929        3470 :             int iX = 0;
    6930             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6931             :             iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
    6932             :                                                /* bCheckMinEqMax = */ false,
    6933        3470 :                                                HAS_NODATA>(
    6934        3470 :                 pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
    6935             :                 fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    6936             : #endif
    6937        4011 :             for (; iX < nXCheck; iX++)
    6938             :             {
    6939         541 :                 const float fValue = pafSrcData[iOffset + iX];
    6940             :                 if constexpr (HAS_NAN)
    6941             :                 {
    6942         535 :                     if (std::isnan(fValue))
    6943          13 :                         continue;
    6944             :                 }
    6945             :                 if constexpr (HAS_NODATA)
    6946             :                 {
    6947           6 :                     if (fValue == sNoDataValues.fNoDataValue)
    6948           1 :                         continue;
    6949             :                 }
    6950         527 :                 fMin = std::min(fMin, fValue);
    6951         527 :                 fMax = std::max(fMax, fValue);
    6952         527 :                 dfBlockValidCount += 1.0;
    6953         527 :                 const double dfValue = static_cast<double>(fValue);
    6954         527 :                 const double dfDelta = dfValue - dfBlockMean;
    6955         527 :                 dfBlockMean += dfDelta / dfBlockValidCount;
    6956         527 :                 dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    6957        3470 :             }
    6958             :         }
    6959             :         else
    6960             :         {
    6961        4856 :             int iX = 0;
    6962        4856 :             if (dfBlockValidCount == 0)
    6963             :             {
    6964        4730 :                 while (iX < nXCheck)
    6965             :                 {
    6966        4730 :                     const float fValue = pafSrcData[iOffset + iX];
    6967        4730 :                     ++iX;
    6968             :                     if constexpr (HAS_NAN)
    6969             :                     {
    6970        2338 :                         if (std::isnan(fValue))
    6971           0 :                             continue;
    6972             :                     }
    6973             :                     if constexpr (HAS_NODATA)
    6974             :                     {
    6975           7 :                         if (fValue == sNoDataValues.fNoDataValue)
    6976           1 :                             continue;
    6977             :                     }
    6978        4729 :                     fMin = std::min(fMin, fValue);
    6979        4729 :                     fMax = std::max(fMax, fValue);
    6980        4729 :                     dfBlockValidCount = 1;
    6981        4729 :                     dfBlockMean = static_cast<double>(fValue);
    6982        4729 :                     break;
    6983             :                 }
    6984             :             }
    6985             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    6986             :             iX = ComputeStatisticsFloat32_SSE2<HAS_NAN,
    6987             :                                                /* bCheckMinEqMax = */ true,
    6988        4856 :                                                HAS_NODATA>(
    6989        4856 :                 pafSrcData + iOffset, sNoDataValues.fNoDataValue, iX, nXCheck,
    6990             :                 fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    6991             : #endif
    6992       14986 :             for (; iX < nXCheck; iX++)
    6993             :             {
    6994       10130 :                 const float fValue = pafSrcData[iOffset + iX];
    6995             :                 if constexpr (HAS_NAN)
    6996             :                 {
    6997        6873 :                     if (std::isnan(fValue))
    6998           5 :                         continue;
    6999             :                 }
    7000             :                 if constexpr (HAS_NODATA)
    7001             :                 {
    7002           9 :                     if (fValue == sNoDataValues.fNoDataValue)
    7003           2 :                         continue;
    7004             :                 }
    7005       10123 :                 fMin = std::min(fMin, fValue);
    7006       10123 :                 fMax = std::max(fMax, fValue);
    7007       10123 :                 dfBlockValidCount += 1.0;
    7008       10123 :                 if (fMin != fMax)
    7009             :                 {
    7010        3258 :                     const double dfValue = static_cast<double>(fValue);
    7011        3258 :                     const double dfDelta = dfValue - dfBlockMean;
    7012        3258 :                     dfBlockMean += dfDelta / dfBlockValidCount;
    7013        3258 :                     dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7014             :                 }
    7015             :             }
    7016             :         }
    7017             :     }
    7018             : 
    7019        4729 :     fMinInOut = fMin;
    7020        4729 :     fMaxInOut = fMax;
    7021        4729 :     dfBlockMeanInOut = dfBlockMean;
    7022        4729 :     dfBlockM2InOut = dfBlockM2;
    7023        4729 :     dfBlockValidCountInOut = dfBlockValidCount;
    7024        4729 : }
    7025             : 
    7026             : /************************************************************************/
    7027             : /*                        StatisticsTaskFloat32                         */
    7028             : /************************************************************************/
    7029             : 
    7030             : namespace
    7031             : {
    7032             : struct StatisticsTaskFloat32
    7033             : {
    7034             :     double dfBlockMean = 0;
    7035             :     double dfBlockM2 = 0;
    7036             :     double dfBlockValidCount = 0;
    7037             :     GDALDataType eDataType = GDT_Unknown;
    7038             :     bool bHasNoData = false;
    7039             :     GDALNoDataValues *psNoDataValues = nullptr;
    7040             :     const float *pafSrcData = nullptr;
    7041             :     float fMin = std::numeric_limits<float>::infinity();
    7042             :     float fMax = -std::numeric_limits<float>::infinity();
    7043             :     int nChunkXSize = 0;
    7044             :     int nXCheck = 0;
    7045             :     int nYCheck = 0;
    7046             : 
    7047        4729 :     void Perform()
    7048             :     {
    7049        4729 :         if (GDALDataTypeIsInteger(eDataType))
    7050             :         {
    7051        2391 :             if (bHasNoData)
    7052             :             {
    7053             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
    7054           6 :                                               /* HAS_NODATA = */ true>(
    7055           6 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7056           6 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7057             :             }
    7058             :             else
    7059             :             {
    7060             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ false,
    7061        2385 :                                               /* HAS_NODATA = */ false>(
    7062        2385 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7063        2385 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7064             :             }
    7065             :         }
    7066             :         else
    7067             :         {
    7068        2338 :             if (bHasNoData)
    7069             :             {
    7070             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
    7071           0 :                                               /* HAS_NODATA = */ true>(
    7072           0 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7073           0 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7074             :             }
    7075             :             else
    7076             :             {
    7077             :                 ComputeBlockStatisticsFloat32</* HAS_NAN = */ true,
    7078        2338 :                                               /* HAS_NODATA = */ false>(
    7079        2338 :                     pafSrcData, nChunkXSize, nXCheck, nYCheck, *psNoDataValues,
    7080        2338 :                     fMin, fMax, dfBlockMean, dfBlockM2, dfBlockValidCount);
    7081             :             }
    7082             :         }
    7083        4729 :     }
    7084             : };
    7085             : }  // namespace
    7086             : 
    7087             : /************************************************************************/
    7088             : /*                         ComputeStatistics()                          */
    7089             : /************************************************************************/
    7090             : 
    7091             : /**
    7092             :  * \brief Compute image statistics.
    7093             :  *
    7094             :  * Returns the minimum, maximum, mean and standard deviation of all
    7095             :  * pixel values in this band.  If approximate statistics are sufficient,
    7096             :  * the bApproxOK flag can be set to true in which case overviews, or a
    7097             :  * subset of image tiles may be used in computing the statistics.
    7098             :  *
    7099             :  * Once computed, the statistics will generally be "set" back on the
    7100             :  * raster band using SetStatistics().
    7101             :  *
    7102             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    7103             :  *
    7104             :  * This method is the same as the C function GDALComputeRasterStatistics().
    7105             :  *
    7106             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    7107             :  * or a subset of all tiles.
    7108             :  *
    7109             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    7110             :  *
    7111             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    7112             :  *
    7113             :  * @param pdfMean Location into which to load image mean (may be NULL).
    7114             :  *
    7115             :  * @param pdfStdDev Location into which to load image standard deviation
    7116             :  * (may be NULL).
    7117             :  *
    7118             :  * @param pfnProgress a function to call to report progress, or NULL.
    7119             :  *
    7120             :  * @param pProgressData application data to pass to the progress function.
    7121             :  *
    7122             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    7123             :  * is terminated by the user.
    7124             :  */
    7125             : 
    7126         581 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    7127             :                                          double *pdfMax, double *pdfMean,
    7128             :                                          double *pdfStdDev,
    7129             :                                          GDALProgressFunc pfnProgress,
    7130             :                                          void *pProgressData)
    7131             : 
    7132             : {
    7133         581 :     if (pfnProgress == nullptr)
    7134         252 :         pfnProgress = GDALDummyProgress;
    7135             : 
    7136             :     /* -------------------------------------------------------------------- */
    7137             :     /*      If we have overview bands, use them for statistics.             */
    7138             :     /* -------------------------------------------------------------------- */
    7139         581 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7140             :     {
    7141             :         GDALRasterBand *poBand =
    7142           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7143             : 
    7144           3 :         if (poBand != this)
    7145             :         {
    7146           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    7147             :                                                     pdfMean, pdfStdDev,
    7148           3 :                                                     pfnProgress, pProgressData);
    7149           3 :             if (eErr == CE_None)
    7150             :             {
    7151           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    7152             :                 {
    7153           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7154           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    7155             :                 }
    7156             : 
    7157             :                 /* transfer metadata from overview band to this */
    7158             :                 const char *pszPercentValid =
    7159           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    7160             : 
    7161           3 :                 if (pszPercentValid != nullptr)
    7162             :                 {
    7163           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    7164           3 :                                     pszPercentValid);
    7165             :                 }
    7166             :             }
    7167           3 :             return eErr;
    7168             :         }
    7169             :     }
    7170             : 
    7171         578 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    7172             :     {
    7173           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7174           0 :         return CE_Failure;
    7175             :     }
    7176             : 
    7177             :     /* -------------------------------------------------------------------- */
    7178             :     /*      Read actual data and compute statistics.                        */
    7179             :     /* -------------------------------------------------------------------- */
    7180             :     // Using Welford algorithm:
    7181             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    7182             :     // to compute standard deviation in a more numerically robust way than
    7183             :     // the difference of the sum of square values with the square of the sum.
    7184             :     // dfMean and dfM2 are updated at each sample.
    7185             :     // dfM2 is the sum of square of differences to the current mean.
    7186         578 :     double dfMin = std::numeric_limits<double>::infinity();
    7187         578 :     double dfMax = -std::numeric_limits<double>::infinity();
    7188         578 :     double dfMean = 0.0;
    7189         578 :     double dfM2 = 0.0;
    7190             : 
    7191             :     GDALRasterIOExtraArg sExtraArg;
    7192         578 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7193             : 
    7194         578 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7195         578 :     GDALRasterBand *poMaskBand = nullptr;
    7196         578 :     if (!sNoDataValues.bGotNoDataValue)
    7197             :     {
    7198         507 :         const int l_nMaskFlags = GetMaskFlags();
    7199         565 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    7200          58 :             GetColorInterpretation() != GCI_AlphaBand)
    7201             :         {
    7202          58 :             poMaskBand = GetMaskBand();
    7203             :         }
    7204             :     }
    7205             : 
    7206         578 :     bool bSignedByte = false;
    7207         578 :     if (eDataType == GDT_UInt8)
    7208             :     {
    7209         221 :         EnablePixelTypeSignedByteWarning(false);
    7210             :         const char *pszPixelType =
    7211         221 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7212         221 :         EnablePixelTypeSignedByteWarning(true);
    7213         221 :         bSignedByte =
    7214         221 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7215             :     }
    7216             : 
    7217         578 :     GUIntBig nSampleCount = 0;
    7218         578 :     GUIntBig nValidCount = 0;
    7219             : 
    7220         578 :     if (bApproxOK && HasArbitraryOverviews())
    7221             :     {
    7222             :         /* --------------------------------------------------------------------
    7223             :          */
    7224             :         /*      Figure out how much the image should be reduced to get an */
    7225             :         /*      approximate value. */
    7226             :         /* --------------------------------------------------------------------
    7227             :          */
    7228           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7229           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7230             : 
    7231           0 :         int nXReduced = nRasterXSize;
    7232           0 :         int nYReduced = nRasterYSize;
    7233           0 :         if (dfReduction > 1.0)
    7234             :         {
    7235           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7236           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7237             : 
    7238             :             // Catch the case of huge resizing ratios here
    7239           0 :             if (nXReduced == 0)
    7240           0 :                 nXReduced = 1;
    7241           0 :             if (nYReduced == 0)
    7242           0 :                 nYReduced = 1;
    7243             :         }
    7244             : 
    7245           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    7246           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7247             : 
    7248             :         const CPLErr eErr =
    7249           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7250           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7251           0 :         if (eErr != CE_None)
    7252             :         {
    7253           0 :             CPLFree(pData);
    7254           0 :             return eErr;
    7255             :         }
    7256             : 
    7257           0 :         GByte *pabyMaskData = nullptr;
    7258           0 :         if (poMaskBand)
    7259             :         {
    7260             :             pabyMaskData =
    7261           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7262           0 :             if (!pabyMaskData)
    7263             :             {
    7264           0 :                 CPLFree(pData);
    7265           0 :                 return CE_Failure;
    7266             :             }
    7267             : 
    7268           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7269             :                                      pabyMaskData, nXReduced, nYReduced,
    7270           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    7271             :             {
    7272           0 :                 CPLFree(pData);
    7273           0 :                 CPLFree(pabyMaskData);
    7274           0 :                 return CE_Failure;
    7275             :             }
    7276             :         }
    7277             : 
    7278             :         /* this isn't the fastest way to do this, but is easier for now */
    7279           0 :         for (int iY = 0; iY < nYReduced; iY++)
    7280             :         {
    7281           0 :             for (int iX = 0; iX < nXReduced; iX++)
    7282             :             {
    7283           0 :                 const int iOffset = iX + iY * nXReduced;
    7284           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7285           0 :                     continue;
    7286             : 
    7287           0 :                 bool bValid = true;
    7288           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7289           0 :                                                iOffset, sNoDataValues, bValid);
    7290           0 :                 if (!bValid)
    7291           0 :                     continue;
    7292             : 
    7293           0 :                 dfMin = std::min(dfMin, dfValue);
    7294           0 :                 dfMax = std::max(dfMax, dfValue);
    7295             : 
    7296           0 :                 nValidCount++;
    7297           0 :                 if (dfMin == dfMax)
    7298             :                 {
    7299           0 :                     if (nValidCount == 1)
    7300           0 :                         dfMean = dfMin;
    7301             :                 }
    7302             :                 else
    7303             :                 {
    7304           0 :                     const double dfDelta = dfValue - dfMean;
    7305           0 :                     dfMean += dfDelta / nValidCount;
    7306           0 :                     dfM2 += dfDelta * (dfValue - dfMean);
    7307             :                 }
    7308             :             }
    7309             :         }
    7310             : 
    7311           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    7312             : 
    7313           0 :         CPLFree(pData);
    7314           0 :         CPLFree(pabyMaskData);
    7315             :     }
    7316             : 
    7317             :     else  // No arbitrary overviews.
    7318             :     {
    7319         578 :         if (!InitBlockInfo())
    7320         259 :             return CE_Failure;
    7321             : 
    7322             :         /* --------------------------------------------------------------------
    7323             :          */
    7324             :         /*      Figure out the ratio of blocks we will read to get an */
    7325             :         /*      approximate value. */
    7326             :         /* --------------------------------------------------------------------
    7327             :          */
    7328         578 :         int nSampleRate = 1;
    7329         578 :         if (bApproxOK)
    7330             :         {
    7331          43 :             nSampleRate = static_cast<int>(std::max(
    7332          86 :                 1.0,
    7333          43 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7334             :             // We want to avoid probing only the first column of blocks for
    7335             :             // a square shaped raster, because it is not unlikely that it may
    7336             :             // be padding only (#6378)
    7337          43 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7338           1 :                 nSampleRate += 1;
    7339             :         }
    7340         578 :         if (nSampleRate == 1)
    7341         544 :             bApproxOK = false;
    7342             : 
    7343             :         // Particular case for GDT_UInt8 and GUInt16 that only use integral types
    7344             :         // for each block, and possibly for the whole raster.
    7345         578 :         if (!poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    7346         316 :                             eDataType == GDT_UInt16))
    7347             :         {
    7348             :             // We can do integer computation on the whole raster in the Byte case
    7349             :             // only if the number of pixels explored is lower than
    7350             :             // GUINTBIG_MAX / (255*255), so that nSumSquare can fit on a uint64.
    7351             :             // Should be 99.99999% of cases.
    7352             :             // For GUInt16, this limits to raster of 4 giga pixels
    7353             : 
    7354             :             const bool bIntegerStats =
    7355         463 :                 ((eDataType == GDT_UInt8 &&
    7356         204 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7357         204 :                           nSampleRate <
    7358         204 :                       GUINTBIG_MAX / (255U * 255U) /
    7359         204 :                           (static_cast<GUInt64>(nBlockXSize) *
    7360         204 :                            static_cast<GUInt64>(nBlockYSize))) ||
    7361          55 :                  (eDataType == GDT_UInt16 &&
    7362          55 :                   static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    7363          55 :                           nSampleRate <
    7364          55 :                       GUINTBIG_MAX / (65535U * 65535U) /
    7365          55 :                           (static_cast<GUInt64>(nBlockXSize) *
    7366         573 :                            static_cast<GUInt64>(nBlockYSize)))) &&
    7367             :                 // Can be set to NO for easier debugging of the !bIntegerStats
    7368             :                 // case which requires huge rasters to trigger
    7369         259 :                 CPLTestBool(
    7370         259 :                     CPLGetConfigOption("GDAL_STATS_USE_INTEGER_STATS", "YES"));
    7371             : 
    7372         259 :             const GUInt32 nMaxValueType =
    7373         259 :                 (eDataType == GDT_UInt8) ? 255 : 65535;
    7374         259 :             GUInt32 nMin = nMaxValueType;
    7375         259 :             GUInt32 nMax = 0;
    7376         259 :             GUIntBig nSum = 0;
    7377         259 :             GUIntBig nSumSquare = 0;
    7378             :             // If no valid nodata, map to invalid value (256 for Byte)
    7379         259 :             const GUInt32 nNoDataValue =
    7380         294 :                 (sNoDataValues.bGotNoDataValue &&
    7381          35 :                  sNoDataValues.dfNoDataValue >= 0 &&
    7382          35 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    7383          35 :                  fabs(sNoDataValues.dfNoDataValue -
    7384          35 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    7385             :                                            1e-10)) < 1e-10)
    7386         294 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    7387             :                     : nMaxValueType + 1;
    7388             : 
    7389         259 :             int nChunkXSize = nBlockXSize;
    7390         259 :             int nChunkYSize = nBlockYSize;
    7391         259 :             int nChunksPerRow = nBlocksPerRow;
    7392         259 :             int nChunksPerCol = nBlocksPerColumn;
    7393             : 
    7394         259 :             int nThreads = 1;
    7395         259 :             if (nChunkYSize > 1)
    7396             :             {
    7397         115 :                 nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
    7398             :                                              /* bDefaultToAllCPUs = */ false);
    7399             :             }
    7400             : 
    7401         259 :             int nNewChunkXSize = nChunkXSize;
    7402         259 :             const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
    7403         267 :             if (!bApproxOK && nThreads > 1 &&
    7404           8 :                 MayMultiBlockReadingBeMultiThreaded())
    7405             :             {
    7406           4 :                 const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
    7407           4 :                 const size_t nChunkPixels =
    7408           4 :                     static_cast<size_t>(nChunkXSize) * nChunkYSize;
    7409           8 :                 if (nRAMAmount > 0 &&
    7410             :                     nChunkPixels <=
    7411           4 :                         std::numeric_limits<size_t>::max() / nDTSize)
    7412             :                 {
    7413           4 :                     const size_t nBlockSize = nDTSize * nChunkPixels;
    7414           4 :                     const int64_t nBlockCount = nRAMAmount / nBlockSize;
    7415           4 :                     if (nBlockCount >= 2)
    7416             :                     {
    7417           4 :                         nNewChunkXSize = static_cast<int>(std::min<int64_t>(
    7418          12 :                             nChunkXSize * std::min<int64_t>(
    7419             :                                               nBlockCount,
    7420           8 :                                               (std::numeric_limits<int>::max() -
    7421           8 :                                                ALIGNMENT_AVX2_OPTIM) /
    7422           4 :                                                   nChunkPixels),
    7423           8 :                             nRasterXSize));
    7424             : 
    7425           4 :                         CPLAssert(nChunkXSize <
    7426             :                                   std::numeric_limits<int>::max() /
    7427             :                                       nChunkYSize);
    7428             :                     }
    7429             :                 }
    7430             :             }
    7431             : 
    7432         259 :             std::unique_ptr<GByte, VSIFreeReleaser> pabyTempUnaligned;
    7433         259 :             GByte *pabyTemp = nullptr;
    7434         259 :             if (nNewChunkXSize != nBlockXSize)
    7435             :             {
    7436           4 :                 pabyTempUnaligned.reset(static_cast<GByte *>(
    7437           4 :                     VSIMalloc(nDTSize * nNewChunkXSize * nChunkYSize +
    7438             :                               ALIGNMENT_AVX2_OPTIM)));
    7439           4 :                 if (pabyTempUnaligned)
    7440             :                 {
    7441           4 :                     pabyTemp = reinterpret_cast<GByte *>(
    7442           4 :                         reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) +
    7443             :                         (ALIGNMENT_AVX2_OPTIM -
    7444           4 :                          (reinterpret_cast<uintptr_t>(pabyTempUnaligned.get()) %
    7445             :                           ALIGNMENT_AVX2_OPTIM)));
    7446           4 :                     nChunkXSize = nNewChunkXSize;
    7447             :                     nChunksPerRow =
    7448           4 :                         cpl::div_round_up(nRasterXSize, nChunkXSize);
    7449             :                 }
    7450             :             }
    7451             : 
    7452         259 :             for (GIntBig iSampleBlock = 0;
    7453       13126 :                  iSampleBlock <
    7454       13126 :                  static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
    7455       12867 :                  iSampleBlock += nSampleRate)
    7456             :             {
    7457       12871 :                 const int iYBlock =
    7458       12871 :                     static_cast<int>(iSampleBlock / nChunksPerRow);
    7459       12871 :                 const int iXBlock =
    7460       12871 :                     static_cast<int>(iSampleBlock % nChunksPerRow);
    7461             : 
    7462             :                 const int nXCheck =
    7463       12871 :                     std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
    7464             :                 const int nYCheck =
    7465       12871 :                     std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
    7466             : 
    7467       12871 :                 GDALRasterBlock *poBlock = nullptr;
    7468       12871 :                 if (pabyTemp)
    7469             :                 {
    7470          12 :                     if (RasterIO(GF_Read, iXBlock * nChunkXSize,
    7471             :                                  iYBlock * nChunkYSize, nXCheck, nYCheck,
    7472             :                                  pabyTemp, nXCheck, nYCheck, eDataType, 0,
    7473           6 :                                  static_cast<GSpacing>(nChunkXSize) * nDTSize,
    7474           6 :                                  nullptr) != CE_None)
    7475             :                     {
    7476           4 :                         return CE_Failure;
    7477             :                     }
    7478             :                 }
    7479             :                 else
    7480             :                 {
    7481       12865 :                     poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7482       12865 :                     if (poBlock == nullptr)
    7483             :                     {
    7484           2 :                         return CE_Failure;
    7485             :                     }
    7486             :                 }
    7487             : 
    7488             :                 const void *const pData =
    7489       12867 :                     poBlock ? poBlock->GetDataRef() : pabyTemp;
    7490             : 
    7491       12867 :                 GUIntBig nBlockSum = 0;
    7492       12867 :                 GUIntBig nBlockSumSquare = 0;
    7493       12867 :                 GUIntBig nBlockSampleCount = 0;
    7494       12867 :                 GUIntBig nBlockValidCount = 0;
    7495       12867 :                 GUIntBig &nBlockSumRef = bIntegerStats ? nSum : nBlockSum;
    7496       12867 :                 GUIntBig &nBlockSumSquareRef =
    7497             :                     bIntegerStats ? nSumSquare : nBlockSumSquare;
    7498       12867 :                 GUIntBig &nBlockSampleCountRef =
    7499             :                     bIntegerStats ? nSampleCount : nBlockSampleCount;
    7500       12867 :                 GUIntBig &nBlockValidCountRef =
    7501             :                     bIntegerStats ? nValidCount : nBlockValidCount;
    7502             : 
    7503       12867 :                 if (eDataType == GDT_UInt8)
    7504             :                 {
    7505             :                     ComputeStatisticsInternal<
    7506             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    7507       12171 :                         f(nXCheck, nChunkXSize, nYCheck,
    7508             :                           static_cast<const GByte *>(pData),
    7509             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7510             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7511             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7512             :                 }
    7513             :                 else
    7514             :                 {
    7515             :                     ComputeStatisticsInternal<
    7516             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    7517         696 :                         f(nXCheck, nChunkXSize, nYCheck,
    7518             :                           static_cast<const GUInt16 *>(pData),
    7519             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    7520             :                           nMax, nBlockSumRef, nBlockSumSquareRef,
    7521             :                           nBlockSampleCountRef, nBlockValidCountRef);
    7522             :                 }
    7523             : 
    7524       12867 :                 if (poBlock)
    7525       12863 :                     poBlock->DropLock();
    7526             : 
    7527       12867 :                 if (!bIntegerStats)
    7528             :                 {
    7529         169 :                     nSampleCount += nBlockSampleCount;
    7530         169 :                     if (nBlockValidCount)
    7531             :                     {
    7532             :                         // Update the global mean and M2 (the difference of the
    7533             :                         // square to the mean) from the values of the block
    7534             :                         // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7535         169 :                         const double dfBlockValidCount =
    7536         169 :                             static_cast<double>(nBlockValidCount);
    7537         169 :                         const double dfBlockMean =
    7538         169 :                             static_cast<double>(nBlockSum) / dfBlockValidCount;
    7539             :                         const double dfBlockM2 =
    7540         169 :                             static_cast<double>(
    7541         169 :                                 GDALUInt128::Mul(nBlockSumSquare,
    7542         169 :                                                  nBlockValidCount) -
    7543         338 :                                 GDALUInt128::Mul(nBlockSum, nBlockSum)) /
    7544         169 :                             dfBlockValidCount;
    7545         169 :                         const double dfDelta = dfBlockMean - dfMean;
    7546         169 :                         const auto nNewValidCount =
    7547         169 :                             nValidCount + nBlockValidCount;
    7548         169 :                         const double dfNewValidCount =
    7549             :                             static_cast<double>(nNewValidCount);
    7550         169 :                         dfMean +=
    7551         169 :                             dfDelta * (dfBlockValidCount / dfNewValidCount);
    7552         169 :                         dfM2 +=
    7553         169 :                             dfBlockM2 + dfDelta * dfDelta *
    7554         169 :                                             static_cast<double>(nValidCount) *
    7555         169 :                                             dfBlockValidCount / dfNewValidCount;
    7556         169 :                         nValidCount = nNewValidCount;
    7557             :                     }
    7558             :                 }
    7559             : 
    7560       12867 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    7561       12867 :                                      (static_cast<double>(nChunksPerRow) *
    7562             :                                       nChunksPerCol),
    7563             :                                  "Compute Statistics", pProgressData))
    7564             :                 {
    7565           0 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    7566             :                                 "User terminated");
    7567           0 :                     return CE_Failure;
    7568             :                 }
    7569             :             }
    7570             : 
    7571         255 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    7572             :             {
    7573           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7574           0 :                 return CE_Failure;
    7575             :             }
    7576             : 
    7577         255 :             double dfStdDev = 0;
    7578         255 :             if (bIntegerStats)
    7579             :             {
    7580         231 :                 if (nValidCount)
    7581         222 :                     dfMean = static_cast<double>(nSum) / nValidCount;
    7582             : 
    7583             :                 // To avoid potential precision issues when doing the difference,
    7584             :                 // we need to do that computation on 128 bit rather than casting
    7585             :                 // to double
    7586             :                 const GDALUInt128 nTmpForStdDev(
    7587         231 :                     GDALUInt128::Mul(nSumSquare, nValidCount) -
    7588         462 :                     GDALUInt128::Mul(nSum, nSum));
    7589         231 :                 dfStdDev =
    7590         231 :                     nValidCount > 0
    7591         231 :                         ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    7592             :                         : 0.0;
    7593             :             }
    7594          24 :             else if (nValidCount > 0)
    7595             :             {
    7596          24 :                 dfStdDev = sqrt(dfM2 / static_cast<double>(nValidCount));
    7597             :             }
    7598             : 
    7599             :             /// Save computed information
    7600         255 :             if (nValidCount > 0)
    7601             :             {
    7602         246 :                 if (bApproxOK)
    7603             :                 {
    7604          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7605             :                 }
    7606         222 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    7607             :                 {
    7608           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    7609             :                 }
    7610         246 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    7611             :             }
    7612             : 
    7613         255 :             SetValidPercent(nSampleCount, nValidCount);
    7614             : 
    7615             :             /* --------------------------------------------------------------------
    7616             :              */
    7617             :             /*      Record results. */
    7618             :             /* --------------------------------------------------------------------
    7619             :              */
    7620         255 :             if (pdfMin != nullptr)
    7621         252 :                 *pdfMin = nValidCount ? nMin : 0;
    7622         255 :             if (pdfMax != nullptr)
    7623         252 :                 *pdfMax = nValidCount ? nMax : 0;
    7624             : 
    7625         255 :             if (pdfMean != nullptr)
    7626         248 :                 *pdfMean = dfMean;
    7627             : 
    7628         255 :             if (pdfStdDev != nullptr)
    7629         248 :                 *pdfStdDev = dfStdDev;
    7630             : 
    7631         255 :             if (nValidCount > 0)
    7632         246 :                 return CE_None;
    7633             : 
    7634           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    7635             :                         "Failed to compute statistics, no valid pixels found "
    7636             :                         "in sampling.");
    7637           9 :             return CE_Failure;
    7638             :         }
    7639             : 
    7640         319 :         GByte *pabyMaskData = nullptr;
    7641         319 :         if (poMaskBand)
    7642             :         {
    7643             :             pabyMaskData = static_cast<GByte *>(
    7644          58 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7645          58 :             if (!pabyMaskData)
    7646             :             {
    7647           0 :                 return CE_Failure;
    7648             :             }
    7649             :         }
    7650             : 
    7651         319 :         float fMin = std::numeric_limits<float>::infinity();
    7652         319 :         float fMax = -std::numeric_limits<float>::infinity();
    7653             :         bool bFloat32Optim =
    7654         133 :             (eDataType == GDT_Int16 || eDataType == GDT_UInt16 ||
    7655         319 :              eDataType == GDT_Float16 || eDataType == GDT_Float32) &&
    7656         209 :             !pabyMaskData &&
    7657         847 :             nBlockXSize < std::numeric_limits<int>::max() / nBlockYSize &&
    7658         209 :             CPLTestBool(
    7659         319 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT32_OPTIM", "YES"));
    7660           0 :         std::unique_ptr<float, VSIFreeReleaser> pafTemp;
    7661             : 
    7662         319 :         int nChunkXSize = nBlockXSize;
    7663         319 :         int nChunkYSize = nBlockYSize;
    7664         319 :         int nChunksPerRow = nBlocksPerRow;
    7665         319 :         int nChunksPerCol = nBlocksPerColumn;
    7666             : 
    7667             : #define nBlockXSize use_nChunkXSize_instead
    7668             : #define nBlockYSize use_nChunkYSize_instead
    7669             : #define nBlocksPerRow use_nChunksPerRow_instead
    7670             : #define nBlocksPerColumn use_nChunksPerCol_instead
    7671             : 
    7672         319 :         int nThreads = 1;
    7673         319 :         CPLWorkerThreadPool *psThreadPool = nullptr;
    7674         319 :         if (bFloat32Optim)
    7675             :         {
    7676         207 :             if (nChunkYSize > 1)
    7677             :             {
    7678          15 :                 nThreads = GDALGetNumThreads(CPLGetNumCPUs(),
    7679             :                                              /* bDefaultToAllCPUs = */ false);
    7680             :             }
    7681             : 
    7682         207 :             int nNewChunkXSize = nChunkXSize;
    7683         211 :             if (!bApproxOK && nThreads > 1 &&
    7684           4 :                 MayMultiBlockReadingBeMultiThreaded())
    7685             :             {
    7686           0 :                 const int64_t nRAMAmount = CPLGetUsablePhysicalRAM() / 10;
    7687           0 :                 const size_t nChunkPixels =
    7688           0 :                     static_cast<size_t>(nChunkXSize) * nChunkYSize;
    7689           0 :                 if (nRAMAmount > 0 &&
    7690             :                     nChunkPixels <=
    7691           0 :                         std::numeric_limits<size_t>::max() / sizeof(float))
    7692             :                 {
    7693           0 :                     const size_t nBlockSizeAsFloat32 =
    7694             :                         sizeof(float) * nChunkPixels;
    7695           0 :                     const int64_t nBlockCount =
    7696           0 :                         nRAMAmount / nBlockSizeAsFloat32;
    7697           0 :                     if (nBlockCount >= 2)
    7698             :                     {
    7699           0 :                         nNewChunkXSize = static_cast<int>(std::min<int64_t>(
    7700           0 :                             nChunkXSize * std::min<int64_t>(
    7701             :                                               nBlockCount,
    7702           0 :                                               std::numeric_limits<int>::max() /
    7703           0 :                                                   nChunkPixels),
    7704           0 :                             nRasterXSize));
    7705             : 
    7706           0 :                         CPLAssert(nChunkXSize <
    7707             :                                   std::numeric_limits<int>::max() /
    7708             :                                       nChunkYSize);
    7709             :                     }
    7710             :                 }
    7711             :             }
    7712         207 :             if (eDataType != GDT_Float32 || nNewChunkXSize != nChunkXSize)
    7713             :             {
    7714         187 :                 pafTemp.reset(static_cast<float *>(
    7715         187 :                     VSIMalloc(sizeof(float) * nNewChunkXSize * nChunkYSize)));
    7716         187 :                 bFloat32Optim = pafTemp != nullptr;
    7717         187 :                 if (bFloat32Optim)
    7718             :                 {
    7719         187 :                     nChunkXSize = nNewChunkXSize;
    7720             :                     nChunksPerRow =
    7721         187 :                         cpl::div_round_up(nRasterXSize, nChunkXSize);
    7722             :                 }
    7723             :             }
    7724         207 :             CPLDebug("GDAL", "Using %d x %d chunks for statistics computation",
    7725             :                      nChunkXSize, nChunkYSize);
    7726             :         }
    7727             : 
    7728             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    7729             :         const bool bFloat64Optim =
    7730          23 :             eDataType == GDT_Float64 && !pabyMaskData &&
    7731         365 :             nChunkXSize < std::numeric_limits<int>::max() / nChunkYSize &&
    7732          23 :             CPLTestBool(
    7733         319 :                 CPLGetConfigOption("GDAL_STATS_USE_FLOAT64_OPTIM", "YES"));
    7734             : #endif
    7735             : 
    7736         319 :         std::vector<StatisticsTaskFloat32> tasksFloat32;
    7737             : 
    7738         319 :         for (GIntBig iSampleBlock = 0;
    7739        6034 :              iSampleBlock < static_cast<GIntBig>(nChunksPerRow) * nChunksPerCol;
    7740        5715 :              iSampleBlock += nSampleRate)
    7741             :         {
    7742        5715 :             const int iYBlock = static_cast<int>(iSampleBlock / nChunksPerRow);
    7743        5715 :             const int iXBlock = static_cast<int>(iSampleBlock % nChunksPerRow);
    7744             : 
    7745             :             const int nXCheck =
    7746        5715 :                 std::min(nRasterXSize - nChunkXSize * iXBlock, nChunkXSize);
    7747             :             const int nYCheck =
    7748        5715 :                 std::min(nRasterYSize - nChunkYSize * iYBlock, nChunkYSize);
    7749             : 
    7750        6300 :             if (poMaskBand &&
    7751         585 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nChunkXSize,
    7752             :                                      iYBlock * nChunkYSize, nXCheck, nYCheck,
    7753             :                                      pabyMaskData, nXCheck, nYCheck, GDT_UInt8,
    7754             :                                      0, nChunkXSize, nullptr) != CE_None)
    7755             :             {
    7756           0 :                 CPLFree(pabyMaskData);
    7757           0 :                 return CE_Failure;
    7758             :             }
    7759             : 
    7760        5715 :             GDALRasterBlock *poBlock = nullptr;
    7761        5715 :             if (pafTemp)
    7762             :             {
    7763        2393 :                 if (RasterIO(GF_Read, iXBlock * nChunkXSize,
    7764             :                              iYBlock * nChunkYSize, nXCheck, nYCheck,
    7765        2393 :                              pafTemp.get(), nXCheck, nYCheck, GDT_Float32, 0,
    7766        2393 :                              static_cast<GSpacing>(nChunkXSize * sizeof(float)),
    7767        2393 :                              nullptr) != CE_None)
    7768             :                 {
    7769           0 :                     CPLFree(pabyMaskData);
    7770           0 :                     return CE_Failure;
    7771             :                 }
    7772             :             }
    7773             :             else
    7774             :             {
    7775        3322 :                 poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7776        3322 :                 if (poBlock == nullptr)
    7777             :                 {
    7778           0 :                     CPLFree(pabyMaskData);
    7779           0 :                     return CE_Failure;
    7780             :                 }
    7781             :             }
    7782             : 
    7783             :             const void *const pData =
    7784        5715 :                 poBlock ? poBlock->GetDataRef() : pafTemp.get();
    7785             : 
    7786        5715 :             if (bFloat32Optim)
    7787             :             {
    7788        4729 :                 const float *const pafSrcData =
    7789             :                     static_cast<const float *>(pData);
    7790             : 
    7791        4735 :                 const bool bHasNoData = sNoDataValues.bGotFloatNoDataValue &&
    7792           6 :                                         !std::isnan(sNoDataValues.fNoDataValue);
    7793        4729 :                 const int nTasks = std::min(nYCheck, nThreads);
    7794        4729 :                 const int nRowsPerTask = cpl::div_round_up(nYCheck, nTasks);
    7795        4729 :                 tasksFloat32.clear();
    7796        9462 :                 for (int i = 0; i < nTasks; ++i)
    7797             :                 {
    7798        4733 :                     StatisticsTaskFloat32 task;
    7799        4733 :                     task.eDataType = eDataType;
    7800        4733 :                     task.bHasNoData = bHasNoData;
    7801        4733 :                     task.psNoDataValues = &sNoDataValues;
    7802        4733 :                     task.nChunkXSize = nChunkXSize;
    7803        4733 :                     task.fMin = fMin;
    7804        4733 :                     task.fMax = fMax;
    7805        4733 :                     task.pafSrcData = pafSrcData + static_cast<size_t>(i) *
    7806        4733 :                                                        nRowsPerTask *
    7807        4733 :                                                        nChunkXSize;
    7808        4733 :                     task.nXCheck = nXCheck;
    7809        4733 :                     task.nYCheck =
    7810        4733 :                         std::min(nRowsPerTask, nYCheck - i * nRowsPerTask);
    7811        4733 :                     tasksFloat32.emplace_back(std::move(task));
    7812             :                 }
    7813        4729 :                 if (psThreadPool)
    7814             :                 {
    7815           0 :                     auto poJobQueue = psThreadPool->CreateJobQueue();
    7816           0 :                     for (auto &task : tasksFloat32)
    7817             :                     {
    7818           0 :                         poJobQueue->SubmitJob([&task]() { task.Perform(); });
    7819             :                     }
    7820           0 :                     poJobQueue->WaitCompletion();
    7821             :                 }
    7822             :                 else
    7823             :                 {
    7824        4729 :                     tasksFloat32[0].Perform();
    7825             :                 }
    7826             : 
    7827        9462 :                 for (const auto &task : tasksFloat32)
    7828             :                 {
    7829        4733 :                     if (task.dfBlockValidCount > 0)
    7830             :                     {
    7831        4729 :                         fMin = std::min(fMin, task.fMin);
    7832        4729 :                         fMax = std::max(fMax, task.fMax);
    7833             : 
    7834             :                         // Update the global mean and M2 (the difference of the
    7835             :                         // square to the mean) from the values of the block
    7836             :                         // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7837        4729 :                         const auto nNewValidCount =
    7838        4729 :                             nValidCount +
    7839        4729 :                             static_cast<int>(task.dfBlockValidCount);
    7840        4729 :                         dfM2 += task.dfBlockM2;
    7841        4729 :                         if (task.dfBlockMean != dfMean)
    7842             :                         {
    7843        1167 :                             if (nValidCount == 0)
    7844             :                             {
    7845          50 :                                 dfMean = task.dfBlockMean;
    7846             :                             }
    7847             :                             else
    7848             :                             {
    7849        1117 :                                 const double dfDelta =
    7850        1117 :                                     task.dfBlockMean - dfMean;
    7851        1117 :                                 const double dfNewValidCount =
    7852             :                                     static_cast<double>(nNewValidCount);
    7853        1117 :                                 dfMean += dfDelta * (task.dfBlockValidCount /
    7854             :                                                      dfNewValidCount);
    7855        1117 :                                 dfM2 += dfDelta * dfDelta *
    7856        1117 :                                         static_cast<double>(nValidCount) *
    7857        1117 :                                         task.dfBlockValidCount /
    7858             :                                         dfNewValidCount;
    7859             :                             }
    7860             :                         }
    7861        4729 :                         nValidCount = nNewValidCount;
    7862             :                     }
    7863             :                 }
    7864             :             }
    7865             : 
    7866             : #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    7867         986 :             else if (bFloat64Optim)
    7868             :             {
    7869             :                 const bool bHasNoData =
    7870         563 :                     sNoDataValues.bGotNoDataValue &&
    7871         269 :                     !std::isnan(sNoDataValues.dfNoDataValue);
    7872         294 :                 double dfBlockMean = 0;
    7873         294 :                 double dfBlockM2 = 0;
    7874         294 :                 double dfBlockValidCount = 0;
    7875        2661 :                 for (int iY = 0; iY < nYCheck; iY++)
    7876             :                 {
    7877        2367 :                     const int iOffset = iY * nChunkXSize;
    7878        2367 :                     if (dfBlockValidCount != 0 && dfMin != dfMax)
    7879             :                     {
    7880        1817 :                         int iX = 0;
    7881        1817 :                         if (bHasNoData)
    7882             :                         {
    7883             :                             iX = ComputeStatisticsFloat64_SSE2<
    7884             :                                 /* bCheckMinEqMax = */ false,
    7885         387 :                                 /* bHasNoData = */ true>(
    7886         387 :                                 static_cast<const double *>(pData) + iOffset,
    7887             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7888             :                                 dfMax, dfBlockMean, dfBlockM2,
    7889             :                                 dfBlockValidCount);
    7890             :                         }
    7891             :                         else
    7892             :                         {
    7893             :                             iX = ComputeStatisticsFloat64_SSE2<
    7894             :                                 /* bCheckMinEqMax = */ false,
    7895        1430 :                                 /* bHasNoData = */ false>(
    7896        1430 :                                 static_cast<const double *>(pData) + iOffset,
    7897             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7898             :                                 dfMax, dfBlockMean, dfBlockM2,
    7899             :                                 dfBlockValidCount);
    7900             :                         }
    7901        2959 :                         for (; iX < nXCheck; iX++)
    7902             :                         {
    7903        1142 :                             const double dfValue = static_cast<const double *>(
    7904        1142 :                                 pData)[iOffset + iX];
    7905        1665 :                             if (std::isnan(dfValue) ||
    7906         523 :                                 (bHasNoData &&
    7907         523 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7908          59 :                                 continue;
    7909        1083 :                             dfMin = std::min(dfMin, dfValue);
    7910        1083 :                             dfMax = std::max(dfMax, dfValue);
    7911        1083 :                             dfBlockValidCount += 1.0;
    7912        1083 :                             const double dfDelta = dfValue - dfBlockMean;
    7913        1083 :                             dfBlockMean += dfDelta / dfBlockValidCount;
    7914        1083 :                             dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7915        1817 :                         }
    7916             :                     }
    7917             :                     else
    7918             :                     {
    7919         550 :                         int iX = 0;
    7920         550 :                         if (dfBlockValidCount == 0)
    7921             :                         {
    7922        7673 :                             for (; iX < nXCheck; iX++)
    7923             :                             {
    7924        7639 :                                 const double dfValue =
    7925             :                                     static_cast<const double *>(
    7926        7639 :                                         pData)[iOffset + iX];
    7927       15253 :                                 if (std::isnan(dfValue) ||
    7928        7614 :                                     (bHasNoData &&
    7929        7614 :                                      dfValue == sNoDataValues.dfNoDataValue))
    7930        7377 :                                     continue;
    7931         262 :                                 dfMin = std::min(dfMin, dfValue);
    7932         262 :                                 dfMax = std::max(dfMax, dfValue);
    7933         262 :                                 dfBlockValidCount = 1;
    7934         262 :                                 dfBlockMean = dfValue;
    7935         262 :                                 iX++;
    7936         262 :                                 break;
    7937             :                             }
    7938             :                         }
    7939         550 :                         if (bHasNoData)
    7940             :                         {
    7941             :                             iX = ComputeStatisticsFloat64_SSE2<
    7942             :                                 /* bCheckMinEqMax = */ true,
    7943         398 :                                 /* bHasNoData = */ true>(
    7944         398 :                                 static_cast<const double *>(pData) + iOffset,
    7945             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7946             :                                 dfMax, dfBlockMean, dfBlockM2,
    7947             :                                 dfBlockValidCount);
    7948             :                         }
    7949             :                         else
    7950             :                         {
    7951             :                             iX = ComputeStatisticsFloat64_SSE2<
    7952             :                                 /* bCheckMinEqMax = */ true,
    7953         152 :                                 /* bHasNoData = */ false>(
    7954         152 :                                 static_cast<const double *>(pData) + iOffset,
    7955             :                                 sNoDataValues.dfNoDataValue, iX, nXCheck, dfMin,
    7956             :                                 dfMax, dfBlockMean, dfBlockM2,
    7957             :                                 dfBlockValidCount);
    7958             :                         }
    7959        1121 :                         for (; iX < nXCheck; iX++)
    7960             :                         {
    7961         571 :                             const double dfValue = static_cast<const double *>(
    7962         571 :                                 pData)[iOffset + iX];
    7963        1103 :                             if (std::isnan(dfValue) ||
    7964         532 :                                 (bHasNoData &&
    7965         532 :                                  dfValue == sNoDataValues.dfNoDataValue))
    7966         146 :                                 continue;
    7967         425 :                             dfMin = std::min(dfMin, dfValue);
    7968         425 :                             dfMax = std::max(dfMax, dfValue);
    7969         425 :                             dfBlockValidCount += 1.0;
    7970         425 :                             if (dfMin != dfMax)
    7971             :                             {
    7972         150 :                                 const double dfDelta = dfValue - dfBlockMean;
    7973         150 :                                 dfBlockMean += dfDelta / dfBlockValidCount;
    7974         150 :                                 dfBlockM2 += dfDelta * (dfValue - dfBlockMean);
    7975             :                             }
    7976             :                         }
    7977             :                     }
    7978             :                 }
    7979             : 
    7980         294 :                 if (dfBlockValidCount > 0)
    7981             :                 {
    7982             :                     // Update the global mean and M2 (the difference of the
    7983             :                     // square to the mean) from the values of the block
    7984             :                     // using https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm
    7985         262 :                     const auto nNewValidCount =
    7986         262 :                         nValidCount + static_cast<int>(dfBlockValidCount);
    7987         262 :                     dfM2 += dfBlockM2;
    7988         262 :                     if (dfBlockMean != dfMean)
    7989             :                     {
    7990         249 :                         if (nValidCount == 0)
    7991             :                         {
    7992          20 :                             dfMean = dfBlockMean;
    7993             :                         }
    7994             :                         else
    7995             :                         {
    7996         229 :                             const double dfDelta = dfBlockMean - dfMean;
    7997         229 :                             const double dfNewValidCount =
    7998             :                                 static_cast<double>(nNewValidCount);
    7999         229 :                             dfMean +=
    8000         229 :                                 dfDelta * (dfBlockValidCount / dfNewValidCount);
    8001         229 :                             dfM2 += dfDelta * dfDelta *
    8002         229 :                                     static_cast<double>(nValidCount) *
    8003         229 :                                     dfBlockValidCount / dfNewValidCount;
    8004             :                         }
    8005             :                     }
    8006         262 :                     nValidCount = nNewValidCount;
    8007             :                 }
    8008             :             }
    8009             : #endif  // #if defined(__x86_64__) || defined(_M_X64) || defined(USE_NEON_OPTIMIZATIONS)
    8010             : 
    8011             :             else
    8012             :             {
    8013             :                 // This isn't the fastest way to do this, but is easier for now.
    8014        6046 :                 for (int iY = 0; iY < nYCheck; iY++)
    8015             :                 {
    8016        5354 :                     if (nValidCount && dfMin != dfMax)
    8017             :                     {
    8018      712990 :                         for (int iX = 0; iX < nXCheck; iX++)
    8019             :                         {
    8020      708474 :                             const GPtrDiff_t iOffset =
    8021      708474 :                                 iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    8022      708474 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8023        9653 :                                 continue;
    8024             : 
    8025      698847 :                             bool bValid = true;
    8026             :                             double dfValue =
    8027      698847 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    8028      698847 :                                               iOffset, sNoDataValues, bValid);
    8029             : 
    8030      698847 :                             if (!bValid)
    8031          26 :                                 continue;
    8032             : 
    8033      698821 :                             dfMin = std::min(dfMin, dfValue);
    8034      698821 :                             dfMax = std::max(dfMax, dfValue);
    8035             : 
    8036      698821 :                             nValidCount++;
    8037      698821 :                             const double dfDelta = dfValue - dfMean;
    8038      698821 :                             dfMean += dfDelta / nValidCount;
    8039      698821 :                             dfM2 += dfDelta * (dfValue - dfMean);
    8040        4516 :                         }
    8041             :                     }
    8042             :                     else
    8043             :                     {
    8044         838 :                         int iX = 0;
    8045         838 :                         if (nValidCount == 0)
    8046             :                         {
    8047       94429 :                             for (; iX < nXCheck; iX++)
    8048             :                             {
    8049       94372 :                                 const GPtrDiff_t iOffset =
    8050       94372 :                                     iX +
    8051       94372 :                                     static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    8052       94372 :                                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8053       94281 :                                     continue;
    8054             : 
    8055          91 :                                 bool bValid = true;
    8056          91 :                                 double dfValue = GetPixelValue(
    8057             :                                     eDataType, bSignedByte, pData, iOffset,
    8058             :                                     sNoDataValues, bValid);
    8059             : 
    8060          91 :                                 if (!bValid)
    8061           0 :                                     continue;
    8062             : 
    8063          91 :                                 dfMin = dfValue;
    8064          91 :                                 dfMax = dfValue;
    8065          91 :                                 dfMean = dfValue;
    8066          91 :                                 nValidCount = 1;
    8067          91 :                                 iX++;
    8068          91 :                                 break;
    8069             :                             }
    8070             :                         }
    8071      167021 :                         for (; iX < nXCheck; iX++)
    8072             :                         {
    8073      166183 :                             const GPtrDiff_t iOffset =
    8074      166183 :                                 iX + static_cast<GPtrDiff_t>(iY) * nChunkXSize;
    8075      166183 :                             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8076         376 :                                 continue;
    8077             : 
    8078      165822 :                             bool bValid = true;
    8079             :                             double dfValue =
    8080      165822 :                                 GetPixelValue(eDataType, bSignedByte, pData,
    8081      165822 :                                               iOffset, sNoDataValues, bValid);
    8082             : 
    8083      165822 :                             if (!bValid)
    8084          15 :                                 continue;
    8085             : 
    8086      165807 :                             dfMin = std::min(dfMin, dfValue);
    8087      165807 :                             dfMax = std::max(dfMax, dfValue);
    8088             : 
    8089      165807 :                             nValidCount++;
    8090      165807 :                             if (dfMin != dfMax)
    8091             :                             {
    8092        2636 :                                 const double dfDelta = dfValue - dfMean;
    8093        2636 :                                 dfMean += dfDelta / nValidCount;
    8094        2636 :                                 dfM2 += dfDelta * (dfValue - dfMean);
    8095             :                             }
    8096             :                         }
    8097             :                     }
    8098             :                 }
    8099             :             }
    8100             : 
    8101        5715 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    8102             : 
    8103        5715 :             if (poBlock)
    8104        3322 :                 poBlock->DropLock();
    8105             : 
    8106        5715 :             if (!pfnProgress(
    8107        5715 :                     static_cast<double>(iSampleBlock) /
    8108        5715 :                         (static_cast<double>(nChunksPerRow) * nChunksPerCol),
    8109             :                     "Compute Statistics", pProgressData))
    8110             :             {
    8111           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    8112           0 :                 CPLFree(pabyMaskData);
    8113           0 :                 return CE_Failure;
    8114             :             }
    8115             :         }
    8116             : 
    8117             : #undef nBlockXSize
    8118             : #undef nBlockYSize
    8119             : #undef nBlocksPerRow
    8120             : #undef nBlocksPerColumn
    8121             : 
    8122         319 :         if (bFloat32Optim)
    8123             :         {
    8124         207 :             dfMin = static_cast<double>(fMin);
    8125         207 :             dfMax = static_cast<double>(fMax);
    8126             :         }
    8127         319 :         CPLFree(pabyMaskData);
    8128             :     }
    8129             : 
    8130         319 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    8131             :     {
    8132           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    8133           0 :         return CE_Failure;
    8134             :     }
    8135             : 
    8136             :     /* -------------------------------------------------------------------- */
    8137             :     /*      Save computed information.                                      */
    8138             :     /* -------------------------------------------------------------------- */
    8139         319 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    8140             : 
    8141         319 :     if (nValidCount > 0)
    8142             :     {
    8143         318 :         if (bApproxOK)
    8144             :         {
    8145           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    8146             :         }
    8147         310 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    8148             :         {
    8149           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    8150             :         }
    8151         318 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    8152             :     }
    8153             :     else
    8154             :     {
    8155           1 :         dfMin = 0.0;
    8156           1 :         dfMax = 0.0;
    8157             :     }
    8158             : 
    8159         319 :     SetValidPercent(nSampleCount, nValidCount);
    8160             : 
    8161             :     /* -------------------------------------------------------------------- */
    8162             :     /*      Record results.                                                 */
    8163             :     /* -------------------------------------------------------------------- */
    8164         319 :     if (pdfMin != nullptr)
    8165         316 :         *pdfMin = dfMin;
    8166         319 :     if (pdfMax != nullptr)
    8167         316 :         *pdfMax = dfMax;
    8168             : 
    8169         319 :     if (pdfMean != nullptr)
    8170         313 :         *pdfMean = dfMean;
    8171             : 
    8172         319 :     if (pdfStdDev != nullptr)
    8173         313 :         *pdfStdDev = dfStdDev;
    8174             : 
    8175         319 :     if (nValidCount > 0)
    8176         318 :         return CE_None;
    8177             : 
    8178           1 :     ReportError(
    8179             :         CE_Failure, CPLE_AppDefined,
    8180             :         "Failed to compute statistics, no valid pixels found in sampling.");
    8181           1 :     return CE_Failure;
    8182             : }
    8183             : 
    8184             : /************************************************************************/
    8185             : /*                    GDALComputeRasterStatistics()                     */
    8186             : /************************************************************************/
    8187             : 
    8188             : /**
    8189             :  * \brief Compute image statistics.
    8190             :  *
    8191             :  * @see GDALRasterBand::ComputeStatistics()
    8192             :  */
    8193             : 
    8194         238 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    8195             :                                                int bApproxOK, double *pdfMin,
    8196             :                                                double *pdfMax, double *pdfMean,
    8197             :                                                double *pdfStdDev,
    8198             :                                                GDALProgressFunc pfnProgress,
    8199             :                                                void *pProgressData)
    8200             : 
    8201             : {
    8202         238 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    8203             : 
    8204         238 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8205             : 
    8206         238 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    8207         238 :                                      pdfStdDev, pfnProgress, pProgressData);
    8208             : }
    8209             : 
    8210             : /************************************************************************/
    8211             : /*                           SetStatistics()                            */
    8212             : /************************************************************************/
    8213             : 
    8214             : /**
    8215             :  * \brief Set statistics on band.
    8216             :  *
    8217             :  * This method can be used to store min/max/mean/standard deviation
    8218             :  * statistics on a raster band.
    8219             :  *
    8220             :  * The default implementation stores them as metadata, and will only work
    8221             :  * on formats that can save arbitrary metadata.  This method cannot detect
    8222             :  * whether metadata will be properly saved and so may return CE_None even
    8223             :  * if the statistics will never be saved.
    8224             :  *
    8225             :  * This method is the same as the C function GDALSetRasterStatistics().
    8226             :  *
    8227             :  * @param dfMin minimum pixel value.
    8228             :  *
    8229             :  * @param dfMax maximum pixel value.
    8230             :  *
    8231             :  * @param dfMean mean (average) of all pixel values.
    8232             :  *
    8233             :  * @param dfStdDev Standard deviation of all pixel values.
    8234             :  *
    8235             :  * @return CE_None on success or CE_Failure on failure.
    8236             :  */
    8237             : 
    8238         597 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    8239             :                                      double dfStdDev)
    8240             : 
    8241             : {
    8242         597 :     char szValue[128] = {0};
    8243             : 
    8244         597 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    8245         597 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    8246             : 
    8247         597 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    8248         597 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    8249             : 
    8250         597 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    8251         597 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    8252             : 
    8253         597 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    8254         597 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    8255             : 
    8256         597 :     return CE_None;
    8257             : }
    8258             : 
    8259             : /************************************************************************/
    8260             : /*                      GDALSetRasterStatistics()                       */
    8261             : /************************************************************************/
    8262             : 
    8263             : /**
    8264             :  * \brief Set statistics on band.
    8265             :  *
    8266             :  * @see GDALRasterBand::SetStatistics()
    8267             :  */
    8268             : 
    8269           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    8270             :                                            double dfMax, double dfMean,
    8271             :                                            double dfStdDev)
    8272             : 
    8273             : {
    8274           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    8275             : 
    8276           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8277           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    8278             : }
    8279             : 
    8280             : /************************************************************************/
    8281             : /*                        ComputeRasterMinMax()                         */
    8282             : /************************************************************************/
    8283             : 
    8284             : template <class T, bool HAS_NODATA>
    8285           2 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    8286             :                           T *pMax)
    8287             : {
    8288           2 :     T min0 = *pMin;
    8289           2 :     T max0 = *pMax;
    8290           2 :     T min1 = *pMin;
    8291           2 :     T max1 = *pMax;
    8292             :     size_t i;
    8293           2 :     for (i = 0; i + 1 < nElts; i += 2)
    8294             :     {
    8295           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    8296             :         {
    8297           0 :             min0 = std::min(min0, buffer[i]);
    8298           0 :             max0 = std::max(max0, buffer[i]);
    8299             :         }
    8300           0 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    8301             :         {
    8302           0 :             min1 = std::min(min1, buffer[i + 1]);
    8303           0 :             max1 = std::max(max1, buffer[i + 1]);
    8304             :         }
    8305             :     }
    8306           2 :     T min = std::min(min0, min1);
    8307           2 :     T max = std::max(max0, max1);
    8308           2 :     if (i < nElts)
    8309             :     {
    8310           0 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    8311             :         {
    8312           2 :             min = std::min(min, buffer[i]);
    8313           2 :             max = std::max(max, buffer[i]);
    8314             :         }
    8315             :     }
    8316           2 :     *pMin = min;
    8317           2 :     *pMax = max;
    8318           2 : }
    8319             : 
    8320             : template <GDALDataType eDataType, bool bSignedByte>
    8321             : static void
    8322        6743 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    8323             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    8324             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    8325             : {
    8326        6743 :     double dfLocalMin = dfMin;
    8327        6743 :     double dfLocalMax = dfMax;
    8328             : 
    8329       22131 :     for (int iY = 0; iY < nYCheck; iY++)
    8330             :     {
    8331    14858621 :         for (int iX = 0; iX < nXCheck; iX++)
    8332             :         {
    8333    14843185 :             const GPtrDiff_t iOffset =
    8334    14843185 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    8335    14843185 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    8336      109852 :                 continue;
    8337    14760202 :             bool bValid = true;
    8338    14760202 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    8339             :                                            iOffset, sNoDataValues, bValid);
    8340    14760202 :             if (!bValid)
    8341       26871 :                 continue;
    8342             : 
    8343    14733402 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    8344    14733402 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    8345             :         }
    8346             :     }
    8347             : 
    8348        6743 :     dfMin = dfLocalMin;
    8349        6743 :     dfMax = dfLocalMax;
    8350        6743 : }
    8351             : 
    8352        6743 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    8353             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    8354             :                                  int nBlockXSize,
    8355             :                                  const GDALNoDataValues &sNoDataValues,
    8356             :                                  const GByte *pabyMaskData, double &dfMin,
    8357             :                                  double &dfMax)
    8358             : {
    8359        6743 :     switch (eDataType)
    8360             :     {
    8361           0 :         case GDT_Unknown:
    8362           0 :             CPLAssert(false);
    8363             :             break;
    8364         660 :         case GDT_UInt8:
    8365         660 :             if (bSignedByte)
    8366             :             {
    8367           3 :                 ComputeMinMaxGeneric<GDT_UInt8, true>(
    8368             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8369             :                     pabyMaskData, dfMin, dfMax);
    8370             :             }
    8371             :             else
    8372             :             {
    8373         657 :                 ComputeMinMaxGeneric<GDT_UInt8, false>(
    8374             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8375             :                     pabyMaskData, dfMin, dfMax);
    8376             :             }
    8377         660 :             break;
    8378           4 :         case GDT_Int8:
    8379           4 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    8380             :                                                   nBlockXSize, sNoDataValues,
    8381             :                                                   pabyMaskData, dfMin, dfMax);
    8382           4 :             break;
    8383         969 :         case GDT_UInt16:
    8384         969 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    8385             :                                                     nBlockXSize, sNoDataValues,
    8386             :                                                     pabyMaskData, dfMin, dfMax);
    8387         969 :             break;
    8388           2 :         case GDT_Int16:
    8389           2 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    8390             :                                                    nBlockXSize, sNoDataValues,
    8391             :                                                    pabyMaskData, dfMin, dfMax);
    8392           2 :             break;
    8393           3 :         case GDT_UInt32:
    8394           3 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    8395             :                                                     nBlockXSize, sNoDataValues,
    8396             :                                                     pabyMaskData, dfMin, dfMax);
    8397           3 :             break;
    8398           3 :         case GDT_Int32:
    8399           3 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    8400             :                                                    nBlockXSize, sNoDataValues,
    8401             :                                                    pabyMaskData, dfMin, dfMax);
    8402           3 :             break;
    8403           4 :         case GDT_UInt64:
    8404           4 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    8405             :                                                     nBlockXSize, sNoDataValues,
    8406             :                                                     pabyMaskData, dfMin, dfMax);
    8407           4 :             break;
    8408           4 :         case GDT_Int64:
    8409           4 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    8410             :                                                    nBlockXSize, sNoDataValues,
    8411             :                                                    pabyMaskData, dfMin, dfMax);
    8412           4 :             break;
    8413           2 :         case GDT_Float16:
    8414           2 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    8415             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8416             :                 pabyMaskData, dfMin, dfMax);
    8417           2 :             break;
    8418        4981 :         case GDT_Float32:
    8419        4981 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    8420             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8421             :                 pabyMaskData, dfMin, dfMax);
    8422        4981 :             break;
    8423           1 :         case GDT_Float64:
    8424           1 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    8425             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8426             :                 pabyMaskData, dfMin, dfMax);
    8427           1 :             break;
    8428           9 :         case GDT_CInt16:
    8429           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    8430             :                                                     nBlockXSize, sNoDataValues,
    8431             :                                                     pabyMaskData, dfMin, dfMax);
    8432           9 :             break;
    8433           9 :         case GDT_CInt32:
    8434           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    8435             :                                                     nBlockXSize, sNoDataValues,
    8436             :                                                     pabyMaskData, dfMin, dfMax);
    8437           9 :             break;
    8438           0 :         case GDT_CFloat16:
    8439           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    8440             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8441             :                 pabyMaskData, dfMin, dfMax);
    8442           0 :             break;
    8443          75 :         case GDT_CFloat32:
    8444          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    8445             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8446             :                 pabyMaskData, dfMin, dfMax);
    8447          75 :             break;
    8448          17 :         case GDT_CFloat64:
    8449          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    8450             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    8451             :                 pabyMaskData, dfMin, dfMax);
    8452          17 :             break;
    8453           0 :         case GDT_TypeCount:
    8454           0 :             CPLAssert(false);
    8455             :             break;
    8456             :     }
    8457        6743 : }
    8458             : 
    8459         209 : static bool ComputeMinMaxGenericIterBlocks(
    8460             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    8461             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    8462             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    8463             :     double &dfMin, double &dfMax)
    8464             : 
    8465             : {
    8466         209 :     GByte *pabyMaskData = nullptr;
    8467             :     int nBlockXSize, nBlockYSize;
    8468         209 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    8469             : 
    8470         209 :     if (poMaskBand)
    8471             :     {
    8472             :         pabyMaskData =
    8473         145 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8474         145 :         if (!pabyMaskData)
    8475             :         {
    8476           0 :             return false;
    8477             :         }
    8478             :     }
    8479             : 
    8480        6952 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    8481        6743 :          iSampleBlock += nSampleRate)
    8482             :     {
    8483        6743 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    8484        6743 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    8485             : 
    8486        6743 :         int nXCheck = 0, nYCheck = 0;
    8487        6743 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8488             : 
    8489       13363 :         if (poMaskBand &&
    8490        6620 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    8491             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    8492             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    8493             :                                  nBlockXSize, nullptr) != CE_None)
    8494             :         {
    8495           0 :             CPLFree(pabyMaskData);
    8496           0 :             return false;
    8497             :         }
    8498             : 
    8499        6743 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    8500        6743 :         if (poBlock == nullptr)
    8501             :         {
    8502           0 :             CPLFree(pabyMaskData);
    8503           0 :             return false;
    8504             :         }
    8505             : 
    8506        6743 :         void *const pData = poBlock->GetDataRef();
    8507             : 
    8508        6743 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    8509             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    8510             :                              dfMax);
    8511             : 
    8512        6743 :         poBlock->DropLock();
    8513             :     }
    8514             : 
    8515         209 :     CPLFree(pabyMaskData);
    8516         209 :     return true;
    8517             : }
    8518             : 
    8519             : /**
    8520             :  * \brief Compute the min/max values for a band.
    8521             :  *
    8522             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    8523             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    8524             :  * get an approximate min/max.  If the band has a nodata value it will
    8525             :  * be excluded from the minimum and maximum.
    8526             :  *
    8527             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    8528             :  * an exact range.
    8529             :  *
    8530             :  * This method is the same as the C function GDALComputeRasterMinMax().
    8531             :  *
    8532             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    8533             :  * FALSE.
    8534             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    8535             :  * maximum (adfMinMax[1]) are returned.
    8536             :  *
    8537             :  * @return CE_None on success or CE_Failure on failure.
    8538             :  */
    8539             : 
    8540        1953 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    8541             : {
    8542             :     /* -------------------------------------------------------------------- */
    8543             :     /*      Does the driver already know the min/max?                       */
    8544             :     /* -------------------------------------------------------------------- */
    8545        1953 :     if (bApproxOK)
    8546             :     {
    8547          23 :         int bSuccessMin = FALSE;
    8548          23 :         int bSuccessMax = FALSE;
    8549             : 
    8550          23 :         double dfMin = GetMinimum(&bSuccessMin);
    8551          23 :         double dfMax = GetMaximum(&bSuccessMax);
    8552             : 
    8553          23 :         if (bSuccessMin && bSuccessMax)
    8554             :         {
    8555           1 :             adfMinMax[0] = dfMin;
    8556           1 :             adfMinMax[1] = dfMax;
    8557           1 :             return CE_None;
    8558             :         }
    8559             :     }
    8560             : 
    8561             :     /* -------------------------------------------------------------------- */
    8562             :     /*      If we have overview bands, use them for min/max.                */
    8563             :     /* -------------------------------------------------------------------- */
    8564             :     // cppcheck-suppress knownConditionTrueFalse
    8565        1952 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    8566             :     {
    8567             :         GDALRasterBand *poBand =
    8568           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    8569             : 
    8570           0 :         if (poBand != this)
    8571           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    8572             :     }
    8573             : 
    8574             :     /* -------------------------------------------------------------------- */
    8575             :     /*      Read actual data and compute minimum and maximum.               */
    8576             :     /* -------------------------------------------------------------------- */
    8577        1952 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8578        1952 :     GDALRasterBand *poMaskBand = nullptr;
    8579        1952 :     if (!sNoDataValues.bGotNoDataValue)
    8580             :     {
    8581        1589 :         const int l_nMaskFlags = GetMaskFlags();
    8582        1734 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8583         145 :             GetColorInterpretation() != GCI_AlphaBand)
    8584             :         {
    8585         145 :             poMaskBand = GetMaskBand();
    8586             :         }
    8587             :     }
    8588             : 
    8589        1952 :     if (!bApproxOK &&
    8590        1930 :         (eDataType == GDT_Int8 || eDataType == GDT_Int16 ||
    8591        1770 :          eDataType == GDT_UInt32 || eDataType == GDT_Int32 ||
    8592        1545 :          eDataType == GDT_UInt64 || eDataType == GDT_Int64 ||
    8593        1499 :          eDataType == GDT_Float16 || eDataType == GDT_Float32 ||
    8594        1930 :          eDataType == GDT_Float64) &&
    8595             :         !poMaskBand)
    8596             :     {
    8597        1606 :         CPLErr eErr = ComputeRasterMinMaxLocation(
    8598         803 :             &adfMinMax[0], &adfMinMax[1], nullptr, nullptr, nullptr, nullptr);
    8599         803 :         if (eErr == CE_Warning)
    8600             :         {
    8601           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    8602             :                         "Failed to compute min/max, no valid pixels found in "
    8603             :                         "sampling.");
    8604           9 :             eErr = CE_Failure;
    8605             :         }
    8606         803 :         return eErr;
    8607             :     }
    8608             : 
    8609        1149 :     bool bSignedByte = false;
    8610        1149 :     if (eDataType == GDT_UInt8)
    8611             :     {
    8612         807 :         EnablePixelTypeSignedByteWarning(false);
    8613             :         const char *pszPixelType =
    8614         807 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8615         807 :         EnablePixelTypeSignedByteWarning(true);
    8616         807 :         bSignedByte =
    8617         807 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8618             :     }
    8619             : 
    8620             :     GDALRasterIOExtraArg sExtraArg;
    8621        1149 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    8622             : 
    8623        2298 :     GUInt32 nMin = (eDataType == GDT_UInt8)
    8624        1149 :                        ? 255
    8625             :                        : 65535;  // used for GByte & GUInt16 cases
    8626        1149 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    8627        1149 :     GInt16 nMinInt16 =
    8628             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    8629        1149 :     GInt16 nMaxInt16 =
    8630             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    8631        1149 :     double dfMin =
    8632             :         std::numeric_limits<double>::infinity();  // used for generic code path
    8633        1149 :     double dfMax =
    8634             :         -std::numeric_limits<double>::infinity();  // used for generic code path
    8635        1149 :     const bool bUseOptimizedPath =
    8636        1377 :         !poMaskBand && ((eDataType == GDT_UInt8 && !bSignedByte) ||
    8637         228 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    8638             : 
    8639             :     const auto ComputeMinMaxForBlock =
    8640       19640 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    8641             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    8642      113770 :                      int nYCheck)
    8643             :     {
    8644       19640 :         if (eDataType == GDT_UInt8 && !bSignedByte)
    8645             :         {
    8646             :             const bool bHasNoData =
    8647       11612 :                 sNoDataValues.bGotNoDataValue &&
    8648       29793 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    8649       11612 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    8650       11612 :                     sNoDataValues.dfNoDataValue;
    8651       18181 :             const GUInt32 nNoDataValue =
    8652       18181 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    8653             :                            : 0;
    8654             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8655             :             ComputeStatisticsInternal<GByte,
    8656             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8657       18181 :                 f(nXCheck, nBufferWidth, nYCheck,
    8658             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    8659       18181 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8660             :         }
    8661        1459 :         else if (eDataType == GDT_UInt16)
    8662             :         {
    8663             :             const bool bHasNoData =
    8664         124 :                 sNoDataValues.bGotNoDataValue &&
    8665        1581 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    8666         124 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    8667         124 :                     sNoDataValues.dfNoDataValue;
    8668        1457 :             const GUInt32 nNoDataValue =
    8669        1457 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    8670             :                            : 0;
    8671             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    8672             :             ComputeStatisticsInternal<GUInt16,
    8673             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    8674        1457 :                 f(nXCheck, nBufferWidth, nYCheck,
    8675             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    8676             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    8677             :         }
    8678           2 :         else if (eDataType == GDT_Int16)
    8679             :         {
    8680             :             const bool bHasNoData =
    8681           0 :                 sNoDataValues.bGotNoDataValue &&
    8682           2 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    8683           0 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    8684           0 :                     sNoDataValues.dfNoDataValue;
    8685           2 :             if (bHasNoData)
    8686             :             {
    8687           0 :                 const int16_t nNoDataValue =
    8688           0 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    8689           0 :                 for (int iY = 0; iY < nYCheck; iY++)
    8690             :                 {
    8691           0 :                     ComputeMinMax<int16_t, true>(
    8692           0 :                         static_cast<const int16_t *>(pData) +
    8693           0 :                             static_cast<size_t>(iY) * nBufferWidth,
    8694             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    8695             :                 }
    8696             :             }
    8697             :             else
    8698             :             {
    8699           4 :                 for (int iY = 0; iY < nYCheck; iY++)
    8700             :                 {
    8701           2 :                     ComputeMinMax<int16_t, false>(
    8702           2 :                         static_cast<const int16_t *>(pData) +
    8703           2 :                             static_cast<size_t>(iY) * nBufferWidth,
    8704             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    8705             :                 }
    8706             :             }
    8707             :         }
    8708       19640 :     };
    8709             : 
    8710        1149 :     if (bApproxOK && HasArbitraryOverviews())
    8711             :     {
    8712             :         /* --------------------------------------------------------------------
    8713             :          */
    8714             :         /*      Figure out how much the image should be reduced to get an */
    8715             :         /*      approximate value. */
    8716             :         /* --------------------------------------------------------------------
    8717             :          */
    8718           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    8719           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    8720             : 
    8721           0 :         int nXReduced = nRasterXSize;
    8722           0 :         int nYReduced = nRasterYSize;
    8723           0 :         if (dfReduction > 1.0)
    8724             :         {
    8725           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    8726           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    8727             : 
    8728             :             // Catch the case of huge resizing ratios here
    8729           0 :             if (nXReduced == 0)
    8730           0 :                 nXReduced = 1;
    8731           0 :             if (nYReduced == 0)
    8732           0 :                 nYReduced = 1;
    8733             :         }
    8734             : 
    8735           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    8736           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    8737             : 
    8738             :         const CPLErr eErr =
    8739           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    8740           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    8741           0 :         if (eErr != CE_None)
    8742             :         {
    8743           0 :             CPLFree(pData);
    8744           0 :             return eErr;
    8745             :         }
    8746             : 
    8747           0 :         GByte *pabyMaskData = nullptr;
    8748           0 :         if (poMaskBand)
    8749             :         {
    8750             :             pabyMaskData =
    8751           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    8752           0 :             if (!pabyMaskData)
    8753             :             {
    8754           0 :                 CPLFree(pData);
    8755           0 :                 return CE_Failure;
    8756             :             }
    8757             : 
    8758           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    8759             :                                      pabyMaskData, nXReduced, nYReduced,
    8760           0 :                                      GDT_UInt8, 0, 0, nullptr) != CE_None)
    8761             :             {
    8762           0 :                 CPLFree(pData);
    8763           0 :                 CPLFree(pabyMaskData);
    8764           0 :                 return CE_Failure;
    8765             :             }
    8766             :         }
    8767             : 
    8768           0 :         if (bUseOptimizedPath)
    8769             :         {
    8770           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    8771             :         }
    8772             :         else
    8773             :         {
    8774           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    8775             :                                  nYReduced, nXReduced, sNoDataValues,
    8776             :                                  pabyMaskData, dfMin, dfMax);
    8777             :         }
    8778             : 
    8779           0 :         CPLFree(pData);
    8780           0 :         CPLFree(pabyMaskData);
    8781             :     }
    8782             : 
    8783             :     else  // No arbitrary overviews
    8784             :     {
    8785        1149 :         if (!InitBlockInfo())
    8786           0 :             return CE_Failure;
    8787             : 
    8788             :         /* --------------------------------------------------------------------
    8789             :          */
    8790             :         /*      Figure out the ratio of blocks we will read to get an */
    8791             :         /*      approximate value. */
    8792             :         /* --------------------------------------------------------------------
    8793             :          */
    8794        1149 :         int nSampleRate = 1;
    8795             : 
    8796        1149 :         if (bApproxOK)
    8797             :         {
    8798          22 :             nSampleRate = static_cast<int>(std::max(
    8799          44 :                 1.0,
    8800          22 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    8801             :             // We want to avoid probing only the first column of blocks for
    8802             :             // a square shaped raster, because it is not unlikely that it may
    8803             :             // be padding only (#6378).
    8804          22 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    8805           0 :                 nSampleRate += 1;
    8806             :         }
    8807             : 
    8808        1149 :         if (bUseOptimizedPath)
    8809             :         {
    8810         940 :             for (GIntBig iSampleBlock = 0;
    8811       20506 :                  iSampleBlock <
    8812       20506 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8813       19566 :                  iSampleBlock += nSampleRate)
    8814             :             {
    8815       19642 :                 const int iYBlock =
    8816       19642 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    8817       19642 :                 const int iXBlock =
    8818       19642 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    8819             : 
    8820       19642 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    8821       19642 :                 if (poBlock == nullptr)
    8822           2 :                     return CE_Failure;
    8823             : 
    8824       19640 :                 void *const pData = poBlock->GetDataRef();
    8825             : 
    8826       19640 :                 int nXCheck = 0, nYCheck = 0;
    8827       19640 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    8828             : 
    8829       19640 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    8830             : 
    8831       19640 :                 poBlock->DropLock();
    8832             : 
    8833       19640 :                 if (eDataType == GDT_UInt8 && !bSignedByte && nMin == 0 &&
    8834        4114 :                     nMax == 255)
    8835          74 :                     break;
    8836             :             }
    8837             :         }
    8838             :         else
    8839             :         {
    8840         209 :             const GIntBig nTotalBlocks =
    8841         209 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8842         209 :             if (!ComputeMinMaxGenericIterBlocks(
    8843             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    8844             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    8845             :             {
    8846           0 :                 return CE_Failure;
    8847             :             }
    8848             :         }
    8849             :     }
    8850             : 
    8851        1147 :     if (bUseOptimizedPath)
    8852             :     {
    8853         938 :         if ((eDataType == GDT_UInt8 && !bSignedByte) || eDataType == GDT_UInt16)
    8854             :         {
    8855         937 :             dfMin = nMin;
    8856         937 :             dfMax = nMax;
    8857             :         }
    8858           1 :         else if (eDataType == GDT_Int16)
    8859             :         {
    8860           1 :             dfMin = nMinInt16;
    8861           1 :             dfMax = nMaxInt16;
    8862             :         }
    8863             :     }
    8864             : 
    8865        1147 :     if (dfMin > dfMax)
    8866             :     {
    8867          24 :         adfMinMax[0] = 0;
    8868          24 :         adfMinMax[1] = 0;
    8869          24 :         ReportError(
    8870             :             CE_Failure, CPLE_AppDefined,
    8871             :             "Failed to compute min/max, no valid pixels found in sampling.");
    8872          24 :         return CE_Failure;
    8873             :     }
    8874             : 
    8875        1123 :     adfMinMax[0] = dfMin;
    8876        1123 :     adfMinMax[1] = dfMax;
    8877             : 
    8878        1123 :     return CE_None;
    8879             : }
    8880             : 
    8881             : /************************************************************************/
    8882             : /*                      GDALComputeRasterMinMax()                       */
    8883             : /************************************************************************/
    8884             : 
    8885             : /**
    8886             :  * \brief Compute the min/max values for a band.
    8887             :  *
    8888             :  * @see GDALRasterBand::ComputeRasterMinMax()
    8889             :  *
    8890             :  * @note Prior to GDAL 3.6, this function returned void
    8891             :  */
    8892             : 
    8893        1802 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    8894             :                                            double adfMinMax[2])
    8895             : 
    8896             : {
    8897        1802 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    8898             : 
    8899        1802 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8900        1802 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    8901             : }
    8902             : 
    8903             : /************************************************************************/
    8904             : /*                    ComputeRasterMinMaxLocation()                     */
    8905             : /************************************************************************/
    8906             : 
    8907             : /**
    8908             :  * \brief Compute the min/max values for a band, and their location.
    8909             :  *
    8910             :  * Pixels whose value matches the nodata value or are masked by the mask
    8911             :  * band are ignored.
    8912             :  *
    8913             :  * If the minimum or maximum value is hit in several locations, it is not
    8914             :  * specified which one will be returned.
    8915             :  *
    8916             :  * @param[out] pdfMin Pointer to the minimum value.
    8917             :  * @param[out] pdfMax Pointer to the maximum value.
    8918             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    8919             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    8920             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    8921             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    8922             :  *
    8923             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    8924             :  *         CE_Failure in case of error.
    8925             :  *
    8926             :  * @since GDAL 3.11
    8927             :  */
    8928             : 
    8929         819 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    8930             :                                                    double *pdfMax, int *pnMinX,
    8931             :                                                    int *pnMinY, int *pnMaxX,
    8932             :                                                    int *pnMaxY)
    8933             : {
    8934         819 :     int nMinX = -1;
    8935         819 :     int nMinY = -1;
    8936         819 :     int nMaxX = -1;
    8937         819 :     int nMaxY = -1;
    8938         819 :     double dfMin = std::numeric_limits<double>::infinity();
    8939         819 :     double dfMax = -std::numeric_limits<double>::infinity();
    8940         819 :     if (pdfMin)
    8941         816 :         *pdfMin = dfMin;
    8942         819 :     if (pdfMax)
    8943         816 :         *pdfMax = dfMax;
    8944         819 :     if (pnMinX)
    8945          14 :         *pnMinX = nMinX;
    8946         819 :     if (pnMinY)
    8947          14 :         *pnMinY = nMinY;
    8948         819 :     if (pnMaxX)
    8949          14 :         *pnMaxX = nMaxX;
    8950         819 :     if (pnMaxY)
    8951          14 :         *pnMaxY = nMaxY;
    8952             : 
    8953         819 :     if (GDALDataTypeIsComplex(eDataType))
    8954             :     {
    8955           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    8956             :                  "Complex data type not supported");
    8957           0 :         return CE_Failure;
    8958             :     }
    8959             : 
    8960         819 :     if (!InitBlockInfo())
    8961           0 :         return CE_Failure;
    8962             : 
    8963         819 :     GDALNoDataValues sNoDataValues(this, eDataType);
    8964         819 :     GDALRasterBand *poMaskBand = nullptr;
    8965         819 :     if (!sNoDataValues.bGotNoDataValue)
    8966             :     {
    8967         586 :         const int l_nMaskFlags = GetMaskFlags();
    8968         587 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    8969           1 :             GetColorInterpretation() != GCI_AlphaBand)
    8970             :         {
    8971           1 :             poMaskBand = GetMaskBand();
    8972             :         }
    8973             :     }
    8974             : 
    8975         819 :     bool bSignedByte = false;
    8976         819 :     if (eDataType == GDT_UInt8)
    8977             :     {
    8978           7 :         EnablePixelTypeSignedByteWarning(false);
    8979             :         const char *pszPixelType =
    8980           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    8981           7 :         EnablePixelTypeSignedByteWarning(true);
    8982           7 :         bSignedByte =
    8983           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    8984             :     }
    8985             : 
    8986         819 :     GByte *pabyMaskData = nullptr;
    8987         819 :     if (poMaskBand)
    8988             :     {
    8989             :         pabyMaskData =
    8990           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    8991           1 :         if (!pabyMaskData)
    8992             :         {
    8993           0 :             return CE_Failure;
    8994             :         }
    8995             :     }
    8996             : 
    8997         819 :     const GIntBig nTotalBlocks =
    8998         819 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    8999         819 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    9000         819 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    9001        8061 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    9002             :     {
    9003        7245 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    9004        7245 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    9005             : 
    9006        7245 :         int nXCheck = 0, nYCheck = 0;
    9007        7245 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    9008             : 
    9009        7247 :         if (poMaskBand &&
    9010           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    9011           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    9012             :                                  pabyMaskData, nXCheck, nYCheck, GDT_UInt8, 0,
    9013           2 :                                  nBlockXSize, nullptr) != CE_None)
    9014             :         {
    9015           0 :             CPLFree(pabyMaskData);
    9016           0 :             return CE_Failure;
    9017             :         }
    9018             : 
    9019        7245 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    9020        7245 :         if (poBlock == nullptr)
    9021             :         {
    9022           0 :             CPLFree(pabyMaskData);
    9023           0 :             return CE_Failure;
    9024             :         }
    9025             : 
    9026        7245 :         void *const pData = poBlock->GetDataRef();
    9027             : 
    9028        7245 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    9029             :         {
    9030        5059 :             for (int iY = 0; iY < nYCheck; ++iY)
    9031             :             {
    9032      238290 :                 for (int iX = 0; iX < nXCheck; ++iX)
    9033             :                 {
    9034      233478 :                     const GPtrDiff_t iOffset =
    9035      233478 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    9036      233478 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    9037           2 :                         continue;
    9038      233476 :                     bool bValid = true;
    9039             :                     double dfValue =
    9040      233476 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    9041             :                                       sNoDataValues, bValid);
    9042      233476 :                     if (!bValid)
    9043           0 :                         continue;
    9044      233476 :                     if (dfValue < dfMin)
    9045             :                     {
    9046         606 :                         dfMin = dfValue;
    9047         606 :                         nMinX = iXBlock * nBlockXSize + iX;
    9048         606 :                         nMinY = iYBlock * nBlockYSize + iY;
    9049             :                     }
    9050      233476 :                     if (dfValue > dfMax)
    9051             :                     {
    9052        1515 :                         dfMax = dfValue;
    9053        1515 :                         nMaxX = iXBlock * nBlockXSize + iX;
    9054        1515 :                         nMaxY = iYBlock * nBlockYSize + iY;
    9055             :                     }
    9056             :                 }
    9057         247 :             }
    9058             :         }
    9059             :         else
    9060             :         {
    9061        6998 :             size_t pos_min = 0;
    9062        6998 :             size_t pos_max = 0;
    9063        6998 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    9064        6998 :             if (bNeedsMin && bNeedsMax)
    9065             :             {
    9066       13988 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    9067        6994 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    9068        6994 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    9069       13988 :                     sNoDataValues.dfNoDataValue);
    9070             :             }
    9071           4 :             else if (bNeedsMin)
    9072             :             {
    9073           1 :                 pos_min = gdal::min_element(
    9074           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    9075           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    9076             :                     sNoDataValues.dfNoDataValue);
    9077             :             }
    9078           3 :             else if (bNeedsMax)
    9079             :             {
    9080           2 :                 pos_max = gdal::max_element(
    9081           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    9082           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    9083             :                     sNoDataValues.dfNoDataValue);
    9084             :             }
    9085             : 
    9086        6998 :             if (bNeedsMin)
    9087             :             {
    9088        6995 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    9089        6995 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    9090        6995 :                 bool bValid = true;
    9091             :                 const double dfMinValueBlock =
    9092        6995 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    9093             :                                   sNoDataValues, bValid);
    9094        6995 :                 if (bValid && (dfMinValueBlock < dfMin || nMinX < 0))
    9095             :                 {
    9096        1110 :                     dfMin = dfMinValueBlock;
    9097        1110 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    9098        1110 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    9099             :                 }
    9100             :             }
    9101             : 
    9102        6998 :             if (bNeedsMax)
    9103             :             {
    9104        6996 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    9105        6996 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    9106        6996 :                 bool bValid = true;
    9107             :                 const double dfMaxValueBlock =
    9108        6996 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    9109             :                                   sNoDataValues, bValid);
    9110        6996 :                 if (bValid && (dfMaxValueBlock > dfMax || nMaxX < 0))
    9111             :                 {
    9112        1098 :                     dfMax = dfMaxValueBlock;
    9113        1098 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    9114        1098 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    9115             :                 }
    9116             :             }
    9117             :         }
    9118             : 
    9119        7245 :         poBlock->DropLock();
    9120             : 
    9121        7245 :         if (eDataType == GDT_UInt8)
    9122             :         {
    9123          10 :             if (bNeedsMin && dfMin == 0)
    9124             :             {
    9125           1 :                 bNeedsMin = false;
    9126             :             }
    9127          10 :             if (bNeedsMax && dfMax == 255)
    9128             :             {
    9129           4 :                 bNeedsMax = false;
    9130             :             }
    9131          10 :             if (!bNeedsMin && !bNeedsMax)
    9132             :             {
    9133           3 :                 break;
    9134             :             }
    9135             :         }
    9136             :     }
    9137             : 
    9138         819 :     CPLFree(pabyMaskData);
    9139             : 
    9140         819 :     if (pdfMin)
    9141         816 :         *pdfMin = dfMin;
    9142         819 :     if (pdfMax)
    9143         816 :         *pdfMax = dfMax;
    9144         819 :     if (pnMinX)
    9145          14 :         *pnMinX = nMinX;
    9146         819 :     if (pnMinY)
    9147          14 :         *pnMinY = nMinY;
    9148         819 :     if (pnMaxX)
    9149          14 :         *pnMaxX = nMaxX;
    9150         819 :     if (pnMaxY)
    9151          14 :         *pnMaxY = nMaxY;
    9152         819 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    9153         819 :                                                                   : CE_None;
    9154             : }
    9155             : 
    9156             : /************************************************************************/
    9157             : /*                  GDALComputeRasterMinMaxLocation()                   */
    9158             : /************************************************************************/
    9159             : 
    9160             : /**
    9161             :  * \brief Compute the min/max values for a band, and their location.
    9162             :  *
    9163             :  * @see GDALRasterBand::ComputeRasterMinMax()
    9164             :  * @since GDAL 3.11
    9165             :  */
    9166             : 
    9167          14 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    9168             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    9169             :                                        int *pnMaxX, int *pnMaxY)
    9170             : 
    9171             : {
    9172          14 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    9173             : 
    9174          14 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9175          14 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    9176          14 :                                                pnMaxX, pnMaxY);
    9177             : }
    9178             : 
    9179             : /************************************************************************/
    9180             : /*                        SetDefaultHistogram()                         */
    9181             : /************************************************************************/
    9182             : 
    9183             : /* FIXME : add proper documentation */
    9184             : /**
    9185             :  * \brief Set default histogram.
    9186             :  *
    9187             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    9188             :  * GDALSetDefaultHistogramEx()
    9189             :  */
    9190           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    9191             :                                            double /* dfMax */,
    9192             :                                            int /* nBuckets */,
    9193             :                                            GUIntBig * /* panHistogram */)
    9194             : 
    9195             : {
    9196           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    9197           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    9198             :                     "SetDefaultHistogram() not implemented for this format.");
    9199             : 
    9200           0 :     return CE_Failure;
    9201             : }
    9202             : 
    9203             : /************************************************************************/
    9204             : /*                      GDALSetDefaultHistogram()                       */
    9205             : /************************************************************************/
    9206             : 
    9207             : /**
    9208             :  * \brief Set default histogram.
    9209             :  *
    9210             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    9211             :  * 2 billion.
    9212             :  *
    9213             :  * @see GDALRasterBand::SetDefaultHistogram()
    9214             :  * @see GDALSetRasterHistogramEx()
    9215             :  */
    9216             : 
    9217           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    9218             :                                            double dfMax, int nBuckets,
    9219             :                                            int *panHistogram)
    9220             : 
    9221             : {
    9222           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    9223             : 
    9224           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9225             : 
    9226             :     GUIntBig *panHistogramTemp =
    9227           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    9228           0 :     if (panHistogramTemp == nullptr)
    9229             :     {
    9230           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    9231             :                             "Out of memory in GDALSetDefaultHistogram().");
    9232           0 :         return CE_Failure;
    9233             :     }
    9234             : 
    9235           0 :     for (int i = 0; i < nBuckets; ++i)
    9236             :     {
    9237           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    9238             :     }
    9239             : 
    9240             :     const CPLErr eErr =
    9241           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    9242             : 
    9243           0 :     CPLFree(panHistogramTemp);
    9244             : 
    9245           0 :     return eErr;
    9246             : }
    9247             : 
    9248             : /************************************************************************/
    9249             : /*                     GDALSetDefaultHistogramEx()                      */
    9250             : /************************************************************************/
    9251             : 
    9252             : /**
    9253             :  * \brief Set default histogram.
    9254             :  *
    9255             :  * @see GDALRasterBand::SetDefaultHistogram()
    9256             :  *
    9257             :  */
    9258             : 
    9259           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    9260             :                                              double dfMin, double dfMax,
    9261             :                                              int nBuckets,
    9262             :                                              GUIntBig *panHistogram)
    9263             : 
    9264             : {
    9265           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    9266             : 
    9267           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9268           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    9269             : }
    9270             : 
    9271             : /************************************************************************/
    9272             : /*                           GetDefaultRAT()                            */
    9273             : /************************************************************************/
    9274             : 
    9275             : /**
    9276             :  * \brief Fetch default Raster Attribute Table.
    9277             :  *
    9278             :  * A RAT will be returned if there is a default one associated with the
    9279             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    9280             :  * band and should not be deleted by the application.
    9281             :  *
    9282             :  * This method is the same as the C function GDALGetDefaultRAT().
    9283             :  *
    9284             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    9285             :  */
    9286             : 
    9287         251 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    9288             : 
    9289             : {
    9290         251 :     return nullptr;
    9291             : }
    9292             : 
    9293             : /************************************************************************/
    9294             : /*                         GDALGetDefaultRAT()                          */
    9295             : /************************************************************************/
    9296             : 
    9297             : /**
    9298             :  * \brief Fetch default Raster Attribute Table.
    9299             :  *
    9300             :  * @see GDALRasterBand::GetDefaultRAT()
    9301             :  */
    9302             : 
    9303        1343 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    9304             : 
    9305             : {
    9306        1343 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    9307             : 
    9308        1343 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9309        1343 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    9310             : }
    9311             : 
    9312             : /************************************************************************/
    9313             : /*                           SetDefaultRAT()                            */
    9314             : /************************************************************************/
    9315             : 
    9316             : /**
    9317             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    9318             :  * \brief Set default Raster Attribute Table.
    9319             :  *
    9320             :  * Associates a default RAT with the band.  If not implemented for the
    9321             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    9322             :  * of the RAT is made, the original remains owned by the caller.
    9323             :  *
    9324             :  * This method is the same as the C function GDALSetDefaultRAT().
    9325             :  *
    9326             :  * @param poRAT the RAT to assign to the band.
    9327             :  *
    9328             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    9329             :  * failing.
    9330             :  */
    9331             : 
    9332             : /**/
    9333             : /**/
    9334             : 
    9335             : CPLErr
    9336           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    9337             : {
    9338           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    9339             :     {
    9340           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    9341           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    9342             :                     "SetDefaultRAT() not implemented for this format.");
    9343           0 :         CPLPopErrorHandler();
    9344             :     }
    9345           0 :     return CE_Failure;
    9346             : }
    9347             : 
    9348             : /************************************************************************/
    9349             : /*                         GDALSetDefaultRAT()                          */
    9350             : /************************************************************************/
    9351             : 
    9352             : /**
    9353             :  * \brief Set default Raster Attribute Table.
    9354             :  *
    9355             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    9356             :  */
    9357             : 
    9358          65 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    9359             :                                      GDALRasterAttributeTableH hRAT)
    9360             : 
    9361             : {
    9362          65 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    9363             : 
    9364          65 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9365             : 
    9366          65 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    9367             : }
    9368             : 
    9369             : /************************************************************************/
    9370             : /*                             HasNoData()                              */
    9371             : /************************************************************************/
    9372             : 
    9373      137164 : bool GDALRasterBand::HasNoData() const
    9374             : {
    9375      137164 :     int bHaveNoDataRaw = FALSE;
    9376      137164 :     bool bHaveNoData = false;
    9377      137164 :     GDALRasterBand *poThis = const_cast<GDALRasterBand *>(this);
    9378      137164 :     if (eDataType == GDT_Int64)
    9379             :     {
    9380         212 :         CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsInt64(&bHaveNoDataRaw));
    9381         212 :         bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9382             :     }
    9383      136952 :     else if (eDataType == GDT_UInt64)
    9384             :     {
    9385         160 :         CPL_IGNORE_RET_VAL(poThis->GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    9386         160 :         bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    9387             :     }
    9388             :     else
    9389             :     {
    9390      136792 :         const double dfNoDataValue = poThis->GetNoDataValue(&bHaveNoDataRaw);
    9391      136792 :         if (bHaveNoDataRaw &&
    9392      136792 :             GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    9393             :         {
    9394        1256 :             bHaveNoData = true;
    9395             :         }
    9396             :     }
    9397      137164 :     return bHaveNoData;
    9398             : }
    9399             : 
    9400             : /************************************************************************/
    9401             : /*                            GetMaskBand()                             */
    9402             : /************************************************************************/
    9403             : 
    9404             : /**
    9405             :  * \brief Return the mask band associated with the band.
    9406             :  *
    9407             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9408             :  * that returns one of four default implementations :
    9409             :  * <ul>
    9410             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9411             :  * </li>
    9412             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9413             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9414             :  * GMF_NODATA | GMF_PER_DATASET.
    9415             :  * </li>
    9416             :  * <li>If the band has a nodata value set, an instance of the new
    9417             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9418             :  * GMF_NODATA.
    9419             :  * </li>
    9420             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    9421             :  * to apply to this band (specific rules yet to be determined) and that is of
    9422             :  * type GDT_UInt8 then that alpha band will be returned, and the flags
    9423             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9424             :  * </li>
    9425             :  * <li>If neither of the above apply, an instance of the new
    9426             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9427             :  * pixels. The null flags will return GMF_ALL_VALID.
    9428             :  * </li>
    9429             :  * </ul>
    9430             :  *
    9431             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    9432             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    9433             :  *
    9434             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9435             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9436             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9437             :  * main dataset.
    9438             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9439             :  * level, where xx matches the band number of a band of the main dataset. The
    9440             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9441             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9442             :  * a band, then the other rules explained above will be used to generate a
    9443             :  * on-the-fly mask band.
    9444             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9445             :  *
    9446             :  * This method is the same as the C function GDALGetMaskBand().
    9447             :  *
    9448             :  * @return a valid mask band.
    9449             :  *
    9450             :  *
    9451             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9452             :  *
    9453             :  */
    9454      825158 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    9455             : 
    9456             : {
    9457      825158 :     if (poMask != nullptr)
    9458             :     {
    9459      725214 :         if (poMask.IsOwned())
    9460             :         {
    9461      337865 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    9462             :             {
    9463       37169 :                 if (HasNoData())
    9464             :                 {
    9465           9 :                     InvalidateMaskBand();
    9466             :                 }
    9467             :             }
    9468      300696 :             else if (auto poNoDataMaskBand =
    9469      300696 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    9470             :             {
    9471         435 :                 int bHaveNoDataRaw = FALSE;
    9472         435 :                 bool bIsSame = false;
    9473         435 :                 if (eDataType == GDT_Int64)
    9474          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    9475          27 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    9476          10 :                               bHaveNoDataRaw;
    9477         418 :                 else if (eDataType == GDT_UInt64)
    9478          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    9479          27 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    9480          10 :                               bHaveNoDataRaw;
    9481             :                 else
    9482             :                 {
    9483             :                     const double dfNoDataValue =
    9484         401 :                         GetNoDataValue(&bHaveNoDataRaw);
    9485         401 :                     if (bHaveNoDataRaw)
    9486             :                     {
    9487         398 :                         bIsSame =
    9488         398 :                             std::isnan(dfNoDataValue)
    9489         398 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    9490         363 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    9491             :                                       dfNoDataValue;
    9492             :                     }
    9493             :                 }
    9494         435 :                 if (!bIsSame)
    9495          23 :                     InvalidateMaskBand();
    9496             :             }
    9497             :         }
    9498             : 
    9499      725214 :         if (poMask)
    9500      725182 :             return poMask.get();
    9501             :     }
    9502             : 
    9503             :     /* -------------------------------------------------------------------- */
    9504             :     /*      Check for a mask in a .msk file.                                */
    9505             :     /* -------------------------------------------------------------------- */
    9506       99976 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    9507             :     {
    9508          47 :         poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
    9509          47 :         if (poMask != nullptr)
    9510             :         {
    9511          45 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    9512          45 :             return poMask.get();
    9513             :         }
    9514             :     }
    9515             : 
    9516             :     /* -------------------------------------------------------------------- */
    9517             :     /*      Check for NODATA_VALUES metadata.                               */
    9518             :     /* -------------------------------------------------------------------- */
    9519       99931 :     if (poDS != nullptr)
    9520             :     {
    9521             :         const char *pszGDALNoDataValues =
    9522       99911 :             poDS->GetMetadataItem("NODATA_VALUES");
    9523       99911 :         if (pszGDALNoDataValues != nullptr)
    9524             :         {
    9525          62 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    9526             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    9527             : 
    9528             :             // Make sure we have as many values as bands.
    9529         122 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    9530          60 :                 poDS->GetRasterCount() != 0)
    9531             :             {
    9532             :                 // Make sure that all bands have the same data type
    9533             :                 // This is clearly not a fundamental condition, just a
    9534             :                 // condition to make implementation easier.
    9535          60 :                 GDALDataType eDT = GDT_Unknown;
    9536          60 :                 int i = 0;  // Used after for.
    9537         236 :                 for (; i < poDS->GetRasterCount(); ++i)
    9538             :                 {
    9539         176 :                     if (i == 0)
    9540          60 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    9541         116 :                     else if (eDT !=
    9542         116 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    9543             :                     {
    9544           0 :                         break;
    9545             :                     }
    9546             :                 }
    9547          60 :                 if (i == poDS->GetRasterCount())
    9548             :                 {
    9549          60 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    9550             :                     try
    9551             :                     {
    9552          60 :                         poMask.reset(
    9553         120 :                             std::make_unique<GDALNoDataValuesMaskBand>(poDS));
    9554             :                     }
    9555           0 :                     catch (const std::bad_alloc &)
    9556             :                     {
    9557           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9558           0 :                         poMask.reset();
    9559             :                     }
    9560          60 :                     CSLDestroy(papszGDALNoDataValues);
    9561          60 :                     return poMask.get();
    9562             :                 }
    9563             :                 else
    9564             :                 {
    9565           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    9566             :                                 "All bands should have the same type in "
    9567             :                                 "order the NODATA_VALUES metadata item "
    9568             :                                 "to be used as a mask.");
    9569             :                 }
    9570             :             }
    9571             :             else
    9572             :             {
    9573           2 :                 ReportError(
    9574             :                     CE_Warning, CPLE_AppDefined,
    9575             :                     "NODATA_VALUES metadata item doesn't have the same number "
    9576             :                     "of values as the number of bands.  "
    9577             :                     "Ignoring it for mask.");
    9578             :             }
    9579             : 
    9580           2 :             CSLDestroy(papszGDALNoDataValues);
    9581             :         }
    9582             :     }
    9583             : 
    9584             :     /* -------------------------------------------------------------------- */
    9585             :     /*      Check for nodata case.                                          */
    9586             :     /* -------------------------------------------------------------------- */
    9587       99871 :     if (HasNoData())
    9588             :     {
    9589        1244 :         nMaskFlags = GMF_NODATA;
    9590             :         try
    9591             :         {
    9592        1244 :             poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
    9593             :         }
    9594           0 :         catch (const std::bad_alloc &)
    9595             :         {
    9596           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9597           0 :             poMask.reset();
    9598             :         }
    9599        1244 :         return poMask.get();
    9600             :     }
    9601             : 
    9602             :     /* -------------------------------------------------------------------- */
    9603             :     /*      Check for alpha case.                                           */
    9604             :     /* -------------------------------------------------------------------- */
    9605       98608 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    9606      197864 :         this == poDS->GetRasterBand(1) &&
    9607         629 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    9608             :     {
    9609         228 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt8)
    9610             :         {
    9611         184 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9612         184 :             poMask.resetNotOwned(poDS->GetRasterBand(2));
    9613         184 :             return poMask.get();
    9614             :         }
    9615          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    9616             :         {
    9617          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9618             :             try
    9619             :             {
    9620          23 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9621          46 :                     poDS->GetRasterBand(2)));
    9622             :             }
    9623           0 :             catch (const std::bad_alloc &)
    9624             :             {
    9625           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9626           0 :                 poMask.reset();
    9627             :             }
    9628          23 :             return poMask.get();
    9629             :         }
    9630             :     }
    9631             : 
    9632       98401 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    9633        3002 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    9634      197526 :          this == poDS->GetRasterBand(3)) &&
    9635        2334 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    9636             :     {
    9637        1455 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt8)
    9638             :         {
    9639        1399 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9640        1399 :             poMask.resetNotOwned(poDS->GetRasterBand(4));
    9641        1399 :             return poMask.get();
    9642             :         }
    9643          56 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    9644             :         {
    9645          42 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    9646             :             try
    9647             :             {
    9648          42 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    9649          84 :                     poDS->GetRasterBand(4)));
    9650             :             }
    9651           0 :             catch (const std::bad_alloc &)
    9652             :             {
    9653           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9654           0 :                 poMask.reset();
    9655             :             }
    9656          42 :             return poMask.get();
    9657             :         }
    9658             :     }
    9659             : 
    9660             :     /* -------------------------------------------------------------------- */
    9661             :     /*      Fallback to all valid case.                                     */
    9662             :     /* -------------------------------------------------------------------- */
    9663       96979 :     nMaskFlags = GMF_ALL_VALID;
    9664             :     try
    9665             :     {
    9666       96979 :         poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
    9667             :     }
    9668           0 :     catch (const std::bad_alloc &)
    9669             :     {
    9670           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    9671           0 :         poMask.reset();
    9672             :     }
    9673             : 
    9674       96979 :     return poMask.get();
    9675             : }
    9676             : 
    9677             : /************************************************************************/
    9678             : /*                          GDALGetMaskBand()                           */
    9679             : /************************************************************************/
    9680             : 
    9681             : /**
    9682             :  * \brief Return the mask band associated with the band.
    9683             :  *
    9684             :  * @see GDALRasterBand::GetMaskBand()
    9685             :  */
    9686             : 
    9687       10997 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    9688             : 
    9689             : {
    9690       10997 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    9691             : 
    9692       10997 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9693       10997 :     return poBand->GetMaskBand();
    9694             : }
    9695             : 
    9696             : /************************************************************************/
    9697             : /*                            GetMaskFlags()                            */
    9698             : /************************************************************************/
    9699             : 
    9700             : /**
    9701             :  * \brief Return the status flags of the mask band associated with the band.
    9702             :  *
    9703             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    9704             :  * the following available definitions that may be extended in the future:
    9705             :  * <ul>
    9706             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    9707             :  * 255. When used this will normally be the only flag set.
    9708             :  * </li>
    9709             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    9710             :  * dataset.
    9711             :  * </li>
    9712             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    9713             :  * and may have values other than 0 and 255.
    9714             :  * </li>
    9715             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    9716             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    9717             :  * </li>
    9718             :  * </ul>
    9719             :  *
    9720             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    9721             :  * that returns one of four default implementations:
    9722             :  * <ul>
    9723             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    9724             :  * </li>
    9725             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    9726             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    9727             :  * GMF_NODATA | GMF_PER_DATASET.
    9728             :  * </li>
    9729             :  * <li>If the band has a nodata value set, an instance of the new
    9730             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    9731             :  * GMF_NODATA.
    9732             :  * </li>
    9733             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    9734             :  * seems to apply to this band (specific rules yet to be determined) and that is
    9735             :  * of type GDT_UInt8 then that alpha band will be returned, and the flags
    9736             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    9737             :  * </li>
    9738             :  * <li>If neither of the above apply, an instance of the new
    9739             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    9740             :  * pixels. The null flags will return GMF_ALL_VALID.
    9741             :  * </li>
    9742             :  * </ul>
    9743             :  *
    9744             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    9745             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    9746             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    9747             :  * main dataset.
    9748             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9749             :  * level, where xx matches the band number of a band of the main dataset. The
    9750             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    9751             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    9752             :  * a band, then the other rules explained above will be used to generate a
    9753             :  * on-the-fly mask band.
    9754             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    9755             :  *
    9756             :  * This method is the same as the C function GDALGetMaskFlags().
    9757             :  *
    9758             :  *
    9759             :  * @return a valid mask band.
    9760             :  *
    9761             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9762             :  *
    9763             :  */
    9764      172031 : int GDALRasterBand::GetMaskFlags()
    9765             : 
    9766             : {
    9767             :     // If we don't have a band yet, force this now so that the masks value
    9768             :     // will be initialized.
    9769             : 
    9770      172031 :     if (poMask == nullptr)
    9771       98372 :         GetMaskBand();
    9772             : 
    9773      172031 :     return nMaskFlags;
    9774             : }
    9775             : 
    9776             : /************************************************************************/
    9777             : /*                          GDALGetMaskFlags()                          */
    9778             : /************************************************************************/
    9779             : 
    9780             : /**
    9781             :  * \brief Return the status flags of the mask band associated with the band.
    9782             :  *
    9783             :  * @see GDALRasterBand::GetMaskFlags()
    9784             :  */
    9785             : 
    9786        9955 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    9787             : 
    9788             : {
    9789        9955 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    9790             : 
    9791        9955 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9792        9955 :     return poBand->GetMaskFlags();
    9793             : }
    9794             : 
    9795             : /************************************************************************/
    9796             : /*                         InvalidateMaskBand()                         */
    9797             : /************************************************************************/
    9798             : 
    9799             : //! @cond Doxygen_Suppress
    9800     1871040 : void GDALRasterBand::InvalidateMaskBand()
    9801             : {
    9802     1871040 :     poMask.reset();
    9803     1871040 :     nMaskFlags = 0;
    9804     1871040 : }
    9805             : 
    9806             : //! @endcond
    9807             : 
    9808             : /************************************************************************/
    9809             : /*                           CreateMaskBand()                           */
    9810             : /************************************************************************/
    9811             : 
    9812             : /**
    9813             :  * \brief Adds a mask band to the current band
    9814             :  *
    9815             :  * The default implementation of the CreateMaskBand() method is implemented
    9816             :  * based on similar rules to the .ovr handling implemented using the
    9817             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    9818             :  * be created with the same basename as the original file, and it will have
    9819             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    9820             :  * The mask images will be deflate compressed tiled images with the same
    9821             :  * block size as the original image if possible.
    9822             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    9823             :  * level, where xx matches the band number of a band of the main dataset. The
    9824             :  * value of those items will be the one of the nFlagsIn parameter.
    9825             :  *
    9826             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    9827             :  * it might be invalidated by CreateMaskBand(). So you have to call
    9828             :  * GetMaskBand() again.
    9829             :  *
    9830             :  * This method is the same as the C function GDALCreateMaskBand().
    9831             :  *
    9832             :  *
    9833             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    9834             :  *
    9835             :  * @return CE_None on success or CE_Failure on an error.
    9836             :  *
    9837             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    9838             :  * @see GDALDataset::CreateMaskBand()
    9839             :  *
    9840             :  */
    9841             : 
    9842          10 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    9843             : 
    9844             : {
    9845          10 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    9846             :     {
    9847          10 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    9848          10 :         if (eErr != CE_None)
    9849           1 :             return eErr;
    9850             : 
    9851           9 :         InvalidateMaskBand();
    9852             : 
    9853           9 :         return CE_None;
    9854             :     }
    9855             : 
    9856           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    9857             :                 "CreateMaskBand() not supported for this band.");
    9858             : 
    9859           0 :     return CE_Failure;
    9860             : }
    9861             : 
    9862             : /************************************************************************/
    9863             : /*                         GDALCreateMaskBand()                         */
    9864             : /************************************************************************/
    9865             : 
    9866             : /**
    9867             :  * \brief Adds a mask band to the current band
    9868             :  *
    9869             :  * @see GDALRasterBand::CreateMaskBand()
    9870             :  */
    9871             : 
    9872          36 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    9873             : 
    9874             : {
    9875          36 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    9876             : 
    9877          36 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9878          36 :     return poBand->CreateMaskBand(nFlags);
    9879             : }
    9880             : 
    9881             : /************************************************************************/
    9882             : /*                             IsMaskBand()                             */
    9883             : /************************************************************************/
    9884             : 
    9885             : /**
    9886             :  * \brief Returns whether a band is a mask band.
    9887             :  *
    9888             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9889             :  * mask band, an alpha band, or an implicit mask band.
    9890             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9891             :  *
    9892             :  * This method is the same as the C function GDALIsMaskBand().
    9893             :  *
    9894             :  * @return true if the band is a mask band.
    9895             :  *
    9896             :  * @see GDALDataset::CreateMaskBand()
    9897             :  *
    9898             :  * @since GDAL 3.5.0
    9899             :  *
    9900             :  */
    9901             : 
    9902         303 : bool GDALRasterBand::IsMaskBand() const
    9903             : {
    9904             :     // The GeoTIFF driver, among others, override this method to
    9905             :     // also handle external .msk bands.
    9906         303 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    9907         303 :            GCI_AlphaBand;
    9908             : }
    9909             : 
    9910             : /************************************************************************/
    9911             : /*                           GDALIsMaskBand()                           */
    9912             : /************************************************************************/
    9913             : 
    9914             : /**
    9915             :  * \brief Returns whether a band is a mask band.
    9916             :  *
    9917             :  * Mask band must be understood in the broad term: it can be a per-dataset
    9918             :  * mask band, an alpha band, or an implicit mask band.
    9919             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    9920             :  *
    9921             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    9922             :  *
    9923             :  * @return true if the band is a mask band.
    9924             :  *
    9925             :  * @see GDALRasterBand::IsMaskBand()
    9926             :  *
    9927             :  * @since GDAL 3.5.0
    9928             :  *
    9929             :  */
    9930             : 
    9931          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    9932             : 
    9933             : {
    9934          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    9935             : 
    9936          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9937          37 :     return poBand->IsMaskBand();
    9938             : }
    9939             : 
    9940             : /************************************************************************/
    9941             : /*                         GetMaskValueRange()                          */
    9942             : /************************************************************************/
    9943             : 
    9944             : /**
    9945             :  * \brief Returns the range of values that a mask band can take.
    9946             :  *
    9947             :  * @return the range of values that a mask band can take.
    9948             :  *
    9949             :  * @since GDAL 3.5.0
    9950             :  *
    9951             :  */
    9952             : 
    9953           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    9954             : {
    9955           0 :     return GMVR_UNKNOWN;
    9956             : }
    9957             : 
    9958             : /************************************************************************/
    9959             : /*                     HasConflictingMaskSources()                      */
    9960             : /************************************************************************/
    9961             : 
    9962             : /**
    9963             :  * \brief Returns whether a raster band has conflicting mask sources.
    9964             :  *
    9965             :  * That is, if more than one of the following conditions is met:
    9966             :  * - it has a binary mask band (that is not an alpha band)
    9967             :  * - it has an external mask flags (.msk file)
    9968             :  * - it has a nodata value
    9969             :  * - it belongs to a dataset with the NODATA_VALUES metadata item set
    9970             :  * - it belongs to a dataset that has a band with a GCI_AlphaBand color interpretation
    9971             :  *
    9972             :  * @param[out] posDetailMessage Pointer to a string that will contain the
    9973             :  *                              details of the conflict.
    9974             :  * @param bMentionPrioritarySource Whether the mask source used should be
    9975             :  *                                 mentioned in *posDetailMessage.
    9976             :  * @since GDAL 3.13.0
    9977             :  */
    9978             : 
    9979         124 : bool GDALRasterBand::HasConflictingMaskSources(
    9980             :     std::string *posDetailMessage, bool bMentionPrioritarySource) const
    9981             : {
    9982         124 :     const bool bHasExternalMask = poDS && poDS->oOvManager.HaveMaskFile();
    9983             :     const bool bHasBinaryMaskBand =
    9984         124 :         ((const_cast<GDALRasterBand *>(this)->GetMaskFlags() &
    9985         146 :           (GMF_ALL_VALID | GMF_NODATA | GMF_ALPHA)) == 0) &&
    9986          22 :         (!bHasExternalMask || poDS->oOvManager.GetMaskBand(nBand) != this);
    9987         124 :     const bool bHasNoData = HasNoData();
    9988             :     const bool bHasNODATA_VALUES =
    9989         124 :         poDS && poDS->GetMetadataItem("NODATA_VALUES");
    9990             :     const bool bHasAlphaBand =
    9991         244 :         poDS &&
    9992         120 :         poDS->GetRasterBand(poDS->GetRasterCount())->GetColorInterpretation() ==
    9993         124 :             GCI_AlphaBand;
    9994             :     const bool abMaskSources[] = {bHasBinaryMaskBand, bHasExternalMask,
    9995         124 :                                   bHasNoData, bHasNODATA_VALUES, bHasAlphaBand};
    9996             :     const size_t nCount =
    9997         124 :         std::count(std::begin(abMaskSources), std::end(abMaskSources), true);
    9998         124 :     if (nCount >= 2)
    9999             :     {
   10000          23 :         if (posDetailMessage)
   10001             :         {
   10002          17 :             *posDetailMessage = "Raster band ";
   10003          17 :             *posDetailMessage += std::to_string(nBand);
   10004          17 :             if (poDS && poDS->GetDescription()[0])
   10005             :             {
   10006          11 :                 *posDetailMessage += " of dataset ";
   10007          11 :                 *posDetailMessage += poDS->GetDescription();
   10008             :             }
   10009          17 :             *posDetailMessage += " has several conflicting mask sources:\n";
   10010          17 :             if (bHasExternalMask)
   10011           1 :                 *posDetailMessage += "- internal binary mask band\n";
   10012          17 :             if (bHasExternalMask)
   10013           1 :                 *posDetailMessage += "- external mask band (.msk)\n";
   10014          17 :             if (bHasNoData)
   10015          13 :                 *posDetailMessage += "- nodata value\n";
   10016          17 :             if (bHasNODATA_VALUES)
   10017           9 :                 *posDetailMessage += "- NODATA_VALUES dataset metadata item\n";
   10018          17 :             if (bHasAlphaBand)
   10019             :                 *posDetailMessage +=
   10020           7 :                     "- related to a raster band that is an alpha band\n";
   10021          17 :             if (bMentionPrioritarySource)
   10022             :                 *posDetailMessage +=
   10023           6 :                     "Only the first listed one will be taken into account.";
   10024             :         }
   10025          23 :         return true;
   10026             :     }
   10027         101 :     return false;
   10028             : }
   10029             : 
   10030             : /************************************************************************/
   10031             : /*                     GetIndexColorTranslationTo()                     */
   10032             : /************************************************************************/
   10033             : 
   10034             : /**
   10035             :  * \brief Compute translation table for color tables.
   10036             :  *
   10037             :  * When the raster band has a palette index, it may be useful to compute
   10038             :  * the "translation" of this palette to the palette of another band.
   10039             :  * The translation tries to do exact matching first, and then approximate
   10040             :  * matching if no exact matching is possible.
   10041             :  * This method returns a table such that table[i] = j where i is an index
   10042             :  * of the 'this' rasterband and j the corresponding index for the reference
   10043             :  * rasterband.
   10044             :  *
   10045             :  * This method is thought as internal to GDAL and is used for drivers
   10046             :  * like RPFTOC.
   10047             :  *
   10048             :  * The implementation only supports 1-byte palette rasterbands.
   10049             :  *
   10050             :  * @param poReferenceBand the raster band
   10051             :  * @param pTranslationTable an already allocated translation table (at least 256
   10052             :  * bytes), or NULL to let the method allocate it
   10053             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
   10054             :  *                              is approximate. May be NULL.
   10055             :  *
   10056             :  * @return a translation table if the two bands are palette index and that they
   10057             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
   10058             :  * NULL was passed for pTranslationTable.
   10059             :  */
   10060             : 
   10061             : unsigned char *
   10062           5 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
   10063             :                                            unsigned char *pTranslationTable,
   10064             :                                            int *pApproximateMatching)
   10065             : {
   10066           5 :     if (poReferenceBand == nullptr)
   10067           0 :         return nullptr;
   10068             : 
   10069             :     // cppcheck-suppress knownConditionTrueFalse
   10070           5 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
   10071             :         // cppcheck-suppress knownConditionTrueFalse
   10072           5 :         GetColorInterpretation() == GCI_PaletteIndex &&
   10073          15 :         poReferenceBand->GetRasterDataType() == GDT_UInt8 &&
   10074           5 :         GetRasterDataType() == GDT_UInt8)
   10075             :     {
   10076           5 :         const GDALColorTable *srcColorTable = GetColorTable();
   10077           5 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
   10078           5 :         if (srcColorTable != nullptr && destColorTable != nullptr)
   10079             :         {
   10080           5 :             const int nEntries = srcColorTable->GetColorEntryCount();
   10081           5 :             const int nRefEntries = destColorTable->GetColorEntryCount();
   10082             : 
   10083           5 :             int bHasNoDataValueSrc = FALSE;
   10084           5 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
   10085           5 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
   10086           5 :                   dfNoDataValueSrc <= 255 &&
   10087           5 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
   10088           0 :                 bHasNoDataValueSrc = FALSE;
   10089           5 :             const int noDataValueSrc =
   10090           5 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
   10091             : 
   10092           5 :             int bHasNoDataValueRef = FALSE;
   10093             :             const double dfNoDataValueRef =
   10094           5 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
   10095           5 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
   10096           4 :                   dfNoDataValueRef <= 255 &&
   10097           4 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
   10098           1 :                 bHasNoDataValueRef = FALSE;
   10099           5 :             const int noDataValueRef =
   10100           5 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
   10101             : 
   10102           5 :             bool samePalette = false;
   10103             : 
   10104           5 :             if (pApproximateMatching)
   10105           4 :                 *pApproximateMatching = FALSE;
   10106             : 
   10107           5 :             if (nEntries == nRefEntries &&
   10108           4 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
   10109           4 :                 (bHasNoDataValueSrc == FALSE ||
   10110             :                  noDataValueSrc == noDataValueRef))
   10111             :             {
   10112           4 :                 samePalette = true;
   10113         872 :                 for (int i = 0; i < nEntries; ++i)
   10114             :                 {
   10115         868 :                     if (noDataValueSrc == i)
   10116           4 :                         continue;
   10117             :                     const GDALColorEntry *entry =
   10118         864 :                         srcColorTable->GetColorEntry(i);
   10119             :                     const GDALColorEntry *entryRef =
   10120         864 :                         destColorTable->GetColorEntry(i);
   10121         864 :                     if (entry->c1 != entryRef->c1 ||
   10122         864 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
   10123             :                     {
   10124           0 :                         samePalette = false;
   10125             :                     }
   10126             :                 }
   10127             :             }
   10128             : 
   10129           5 :             if (!samePalette)
   10130             :             {
   10131           1 :                 if (pTranslationTable == nullptr)
   10132             :                 {
   10133             :                     pTranslationTable = static_cast<unsigned char *>(
   10134           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
   10135           1 :                     if (pTranslationTable == nullptr)
   10136           1 :                         return nullptr;
   10137             :                 }
   10138             : 
   10139             :                 // Trying to remap the product palette on the subdataset
   10140             :                 // palette.
   10141           5 :                 for (int i = 0; i < nEntries; ++i)
   10142             :                 {
   10143           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
   10144             :                         noDataValueSrc == i)
   10145           0 :                         continue;
   10146             :                     const GDALColorEntry *entry =
   10147           4 :                         srcColorTable->GetColorEntry(i);
   10148           4 :                     bool bMatchFound = false;
   10149          13 :                     for (int j = 0; j < nRefEntries; ++j)
   10150             :                     {
   10151          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
   10152           0 :                             continue;
   10153             :                         const GDALColorEntry *entryRef =
   10154          10 :                             destColorTable->GetColorEntry(j);
   10155          10 :                         if (entry->c1 == entryRef->c1 &&
   10156           2 :                             entry->c2 == entryRef->c2 &&
   10157           2 :                             entry->c3 == entryRef->c3)
   10158             :                         {
   10159           1 :                             pTranslationTable[i] =
   10160             :                                 static_cast<unsigned char>(j);
   10161           1 :                             bMatchFound = true;
   10162           1 :                             break;
   10163             :                         }
   10164             :                     }
   10165           4 :                     if (!bMatchFound)
   10166             :                     {
   10167             :                         // No exact match. Looking for closest color now.
   10168           3 :                         int best_j = 0;
   10169           3 :                         int best_distance = 0;
   10170           3 :                         if (pApproximateMatching)
   10171           0 :                             *pApproximateMatching = TRUE;
   10172          12 :                         for (int j = 0; j < nRefEntries; ++j)
   10173             :                         {
   10174             :                             const GDALColorEntry *entryRef =
   10175           9 :                                 destColorTable->GetColorEntry(j);
   10176           9 :                             int distance = (entry->c1 - entryRef->c1) *
   10177           9 :                                                (entry->c1 - entryRef->c1) +
   10178           9 :                                            (entry->c2 - entryRef->c2) *
   10179           9 :                                                (entry->c2 - entryRef->c2) +
   10180           9 :                                            (entry->c3 - entryRef->c3) *
   10181           9 :                                                (entry->c3 - entryRef->c3);
   10182           9 :                             if (j == 0 || distance < best_distance)
   10183             :                             {
   10184           7 :                                 best_j = j;
   10185           7 :                                 best_distance = distance;
   10186             :                             }
   10187             :                         }
   10188           3 :                         pTranslationTable[i] =
   10189             :                             static_cast<unsigned char>(best_j);
   10190             :                     }
   10191             :                 }
   10192           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
   10193           0 :                     pTranslationTable[noDataValueSrc] =
   10194             :                         static_cast<unsigned char>(noDataValueRef);
   10195             : 
   10196           1 :                 return pTranslationTable;
   10197             :             }
   10198             :         }
   10199             :     }
   10200           4 :     return nullptr;
   10201             : }
   10202             : 
   10203             : /************************************************************************/
   10204             : /*                          SetFlushBlockErr()                          */
   10205             : /************************************************************************/
   10206             : 
   10207             : /**
   10208             :  * \brief Store that an error occurred while writing a dirty block.
   10209             :  *
   10210             :  * This function stores the fact that an error occurred while writing a dirty
   10211             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
   10212             :  * flushed when the block cache get full, it is not convenient/possible to
   10213             :  * report that a dirty block could not be written correctly. This function
   10214             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
   10215             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
   10216             :  * places where the user can easily match the error with the relevant dataset.
   10217             :  */
   10218             : 
   10219           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
   10220             : {
   10221           0 :     eFlushBlockErr = eErr;
   10222           0 : }
   10223             : 
   10224             : /************************************************************************/
   10225             : /*                           IncDirtyBlocks()                           */
   10226             : /************************************************************************/
   10227             : 
   10228             : /**
   10229             :  * \brief Increment/decrement the number of dirty blocks
   10230             :  */
   10231             : 
   10232      815921 : void GDALRasterBand::IncDirtyBlocks(int nInc)
   10233             : {
   10234      815921 :     if (poBandBlockCache)
   10235      815921 :         poBandBlockCache->IncDirtyBlocks(nInc);
   10236      815921 : }
   10237             : 
   10238             : /************************************************************************/
   10239             : /*                            ReportError()                             */
   10240             : /************************************************************************/
   10241             : 
   10242             : #ifndef DOXYGEN_XML
   10243             : /**
   10244             :  * \brief Emits an error related to a raster band.
   10245             :  *
   10246             :  * This function is a wrapper for regular CPLError(). The only difference
   10247             :  * with CPLError() is that it prepends the error message with the dataset
   10248             :  * name and the band number.
   10249             :  *
   10250             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
   10251             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
   10252             :  * @param fmt a printf() style format string.  Any additional arguments
   10253             :  * will be treated as arguments to fill in this format in a manner
   10254             :  * similar to printf().
   10255             :  *
   10256             :  */
   10257             : 
   10258        2501 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
   10259             :                                  const char *fmt, ...) const
   10260             : {
   10261             :     va_list args;
   10262             : 
   10263        2501 :     va_start(args, fmt);
   10264             : 
   10265        2501 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
   10266        2501 :     pszDSName = CPLGetFilename(pszDSName);
   10267        2501 :     if (pszDSName[0] != '\0')
   10268             :     {
   10269        2408 :         CPLError(eErrClass, err_no, "%s",
   10270        4816 :                  CPLString()
   10271        2408 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
   10272        4816 :                      .append(CPLString().vPrintf(fmt, args))
   10273             :                      .c_str());
   10274             :     }
   10275             :     else
   10276             :     {
   10277          93 :         CPLErrorV(eErrClass, err_no, fmt, args);
   10278             :     }
   10279             : 
   10280        2501 :     va_end(args);
   10281        2501 : }
   10282             : #endif
   10283             : 
   10284             : /************************************************************************/
   10285             : /*                         GetVirtualMemAuto()                          */
   10286             : /************************************************************************/
   10287             : 
   10288             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
   10289             :  *
   10290             :  * Only supported on Linux and Unix systems with mmap() for now.
   10291             :  *
   10292             :  * This method allows creating a virtual memory object for a GDALRasterBand,
   10293             :  * that exposes the whole image data as a virtual array.
   10294             :  *
   10295             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
   10296             :  * specialized implementation, such as for raw files, may also directly use
   10297             :  * mechanisms of the operating system to create a view of the underlying file
   10298             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
   10299             :  *
   10300             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
   10301             :  * offer a specialized implementation with direct file mapping, provided that
   10302             :  * some requirements are met :
   10303             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
   10304             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
   10305             :  *     must match the native ordering of the CPU.
   10306             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
   10307             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
   10308             :  * the file in sequential order, and be equally spaced (which is generally the
   10309             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
   10310             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
   10311             :  *
   10312             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
   10313             :  * CPLVirtualMemFree() must be called before the raster band object is
   10314             :  * destroyed.
   10315             :  *
   10316             :  * If p is such a pointer and base_type the type matching
   10317             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
   10318             :  * accessed with
   10319             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
   10320             :  *
   10321             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
   10322             :  *
   10323             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
   10324             :  * read/write the band.
   10325             :  *
   10326             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
   10327             :  * one pixel value in the buffer to the start of the next pixel value within a
   10328             :  * scanline.
   10329             :  *
   10330             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
   10331             :  * one scanline in the buffer to the start of the next.
   10332             :  *
   10333             :  * @param papszOptions NULL terminated list of options.
   10334             :  *                     If a specialized implementation exists, defining
   10335             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
   10336             :  * used. On the contrary, defining
   10337             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
   10338             :  * being used (thus only allowing efficient implementations to be used). When
   10339             :  * requiring or falling back to the default implementation, the following
   10340             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
   10341             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
   10342             :  * to FALSE)
   10343             :  *
   10344             :  * @return a virtual memory object that must be unreferenced by
   10345             :  * CPLVirtualMemFree(), or NULL in case of failure.
   10346             :  *
   10347             :  */
   10348             : 
   10349           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
   10350             :                                                  int *pnPixelSpace,
   10351             :                                                  GIntBig *pnLineSpace,
   10352             :                                                  CSLConstList papszOptions)
   10353             : {
   10354           9 :     const char *pszImpl = CSLFetchNameValueDef(
   10355             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
   10356           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
   10357           8 :         EQUAL(pszImpl, "FALSE"))
   10358             :     {
   10359           1 :         return nullptr;
   10360             :     }
   10361             : 
   10362           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
   10363           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
   10364           8 :     if (pnPixelSpace)
   10365           8 :         *pnPixelSpace = nPixelSpace;
   10366           8 :     if (pnLineSpace)
   10367           8 :         *pnLineSpace = nLineSpace;
   10368             :     const size_t nCacheSize =
   10369           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
   10370             :     const size_t nPageSizeHint =
   10371           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
   10372           8 :     const bool bSingleThreadUsage = CPLTestBool(
   10373             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
   10374           8 :     return GDALRasterBandGetVirtualMem(
   10375             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
   10376             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
   10377             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
   10378           8 :         papszOptions);
   10379             : }
   10380             : 
   10381             : /************************************************************************/
   10382             : /*                       GDALGetVirtualMemAuto()                        */
   10383             : /************************************************************************/
   10384             : 
   10385             : /**
   10386             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
   10387             :  *
   10388             :  * @see GDALRasterBand::GetVirtualMemAuto()
   10389             :  */
   10390             : 
   10391          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
   10392             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
   10393             :                                      CSLConstList papszOptions)
   10394             : {
   10395          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
   10396             : 
   10397          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10398             : 
   10399          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
   10400          31 :                                      const_cast<char **>(papszOptions));
   10401             : }
   10402             : 
   10403             : /************************************************************************/
   10404             : /*                     GDALGetDataCoverageStatus()                      */
   10405             : /************************************************************************/
   10406             : 
   10407             : /**
   10408             :  * \brief Get the coverage status of a sub-window of the raster.
   10409             :  *
   10410             :  * Returns whether a sub-window of the raster contains only data, only empty
   10411             :  * blocks or a mix of both. This function can be used to determine quickly
   10412             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10413             :  * be sparse.
   10414             :  *
   10415             :  * Empty blocks are blocks that are generally not physically present in the
   10416             :  * file, and when read through GDAL, contain only pixels whose value is the
   10417             :  * nodata value when it is set, or whose value is 0 when the nodata value is
   10418             :  * not set.
   10419             :  *
   10420             :  * The query is done in an efficient way without reading the actual pixel
   10421             :  * values. If not possible, or not implemented at all by the driver,
   10422             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10423             :  * be returned.
   10424             :  *
   10425             :  * The values that can be returned by the function are the following,
   10426             :  * potentially combined with the binary or operator :
   10427             :  * <ul>
   10428             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10429             :  * GetDataCoverageStatus(). This flag should be returned together with
   10430             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10431             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10432             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10433             :  * the queried window. This is typically identified by the concept of missing
   10434             :  * block in formats that supports it.
   10435             :  * </li>
   10436             :  * </ul>
   10437             :  *
   10438             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10439             :  * should be interpreted more as hint of potential presence of data. For example
   10440             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10441             :  * nodata value), instead of using the missing block mechanism,
   10442             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10443             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10444             :  *
   10445             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10446             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10447             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10448             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10449             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10450             :  * the function will exit, so that you can potentially refine the requested area
   10451             :  * to find which particular region(s) have missing blocks.
   10452             :  *
   10453             :  * @see GDALRasterBand::GetDataCoverageStatus()
   10454             :  *
   10455             :  * @param hBand raster band
   10456             :  *
   10457             :  * @param nXOff The pixel offset to the top left corner of the region
   10458             :  * of the band to be queried. This would be zero to start from the left side.
   10459             :  *
   10460             :  * @param nYOff The line offset to the top left corner of the region
   10461             :  * of the band to be queried. This would be zero to start from the top.
   10462             :  *
   10463             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10464             :  *
   10465             :  * @param nYSize The height of the region of the band to be queried in lines.
   10466             :  *
   10467             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10468             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10469             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10470             :  * as the computation of the coverage matches the mask, the computation will be
   10471             :  * stopped. *pdfDataPct will not be valid in that case.
   10472             :  *
   10473             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10474             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10475             :  * sub-window that have valid values. The implementation might not always be
   10476             :  * able to compute it, in which case it will be set to a negative value.
   10477             :  *
   10478             :  * @return a binary-or'ed combination of possible values
   10479             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10480             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10481             :  */
   10482             : 
   10483          29 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
   10484             :                                           int nYOff, int nXSize, int nYSize,
   10485             :                                           int nMaskFlagStop, double *pdfDataPct)
   10486             : {
   10487          29 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
   10488             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
   10489             : 
   10490          29 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10491             : 
   10492          29 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
   10493          29 :                                          nMaskFlagStop, pdfDataPct);
   10494             : }
   10495             : 
   10496             : /************************************************************************/
   10497             : /*                       GetDataCoverageStatus()                        */
   10498             : /************************************************************************/
   10499             : 
   10500             : /**
   10501             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
   10502             :  *                                           int nYOff,
   10503             :  *                                           int nXSize,
   10504             :  *                                           int nYSize,
   10505             :  *                                           int nMaskFlagStop,
   10506             :  *                                           double* pdfDataPct)
   10507             :  * \brief Get the coverage status of a sub-window of the raster.
   10508             :  *
   10509             :  * Returns whether a sub-window of the raster contains only data, only empty
   10510             :  * blocks or a mix of both. This function can be used to determine quickly
   10511             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10512             :  * be sparse.
   10513             :  *
   10514             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10515             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10516             :  *
   10517             :  * The query is done in an efficient way without reading the actual pixel
   10518             :  * values. If not possible, or not implemented at all by the driver,
   10519             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10520             :  * be returned.
   10521             :  *
   10522             :  * The values that can be returned by the function are the following,
   10523             :  * potentially combined with the binary or operator :
   10524             :  * <ul>
   10525             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10526             :  * GetDataCoverageStatus(). This flag should be returned together with
   10527             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10528             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10529             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10530             :  * the queried window. This is typically identified by the concept of missing
   10531             :  * block in formats that supports it.
   10532             :  * </li>
   10533             :  * </ul>
   10534             :  *
   10535             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10536             :  * should be interpreted more as hint of potential presence of data. For example
   10537             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10538             :  * nodata value), instead of using the missing block mechanism,
   10539             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10540             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10541             :  *
   10542             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10543             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10544             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10545             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10546             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10547             :  * the function will exit, so that you can potentially refine the requested area
   10548             :  * to find which particular region(s) have missing blocks.
   10549             :  *
   10550             :  * @see GDALGetDataCoverageStatus()
   10551             :  *
   10552             :  * @param nXOff The pixel offset to the top left corner of the region
   10553             :  * of the band to be queried. This would be zero to start from the left side.
   10554             :  *
   10555             :  * @param nYOff The line offset to the top left corner of the region
   10556             :  * of the band to be queried. This would be zero to start from the top.
   10557             :  *
   10558             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10559             :  *
   10560             :  * @param nYSize The height of the region of the band to be queried in lines.
   10561             :  *
   10562             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10563             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10564             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10565             :  * as the computation of the coverage matches the mask, the computation will be
   10566             :  * stopped. *pdfDataPct will not be valid in that case.
   10567             :  *
   10568             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10569             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10570             :  * sub-window that have valid values. The implementation might not always be
   10571             :  * able to compute it, in which case it will be set to a negative value.
   10572             :  *
   10573             :  * @return a binary-or'ed combination of possible values
   10574             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10575             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10576             :  */
   10577             : 
   10578             : /**
   10579             :  * \brief Get the coverage status of a sub-window of the raster.
   10580             :  *
   10581             :  * Returns whether a sub-window of the raster contains only data, only empty
   10582             :  * blocks or a mix of both. This function can be used to determine quickly
   10583             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
   10584             :  * be sparse.
   10585             :  *
   10586             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
   10587             :  * value when it is set, or whose value is 0 when the nodata value is not set.
   10588             :  *
   10589             :  * The query is done in an efficient way without reading the actual pixel
   10590             :  * values. If not possible, or not implemented at all by the driver,
   10591             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
   10592             :  * be returned.
   10593             :  *
   10594             :  * The values that can be returned by the function are the following,
   10595             :  * potentially combined with the binary or operator :
   10596             :  * <ul>
   10597             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
   10598             :  * GetDataCoverageStatus(). This flag should be returned together with
   10599             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
   10600             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
   10601             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
   10602             :  * the queried window. This is typically identified by the concept of missing
   10603             :  * block in formats that supports it.
   10604             :  * </li>
   10605             :  * </ul>
   10606             :  *
   10607             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
   10608             :  * should be interpreted more as hint of potential presence of data. For example
   10609             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
   10610             :  * nodata value), instead of using the missing block mechanism,
   10611             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
   10612             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
   10613             :  *
   10614             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
   10615             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
   10616             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
   10617             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
   10618             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
   10619             :  * the function will exit, so that you can potentially refine the requested area
   10620             :  * to find which particular region(s) have missing blocks.
   10621             :  *
   10622             :  * @see GDALGetDataCoverageStatus()
   10623             :  *
   10624             :  * @param nXOff The pixel offset to the top left corner of the region
   10625             :  * of the band to be queried. This would be zero to start from the left side.
   10626             :  *
   10627             :  * @param nYOff The line offset to the top left corner of the region
   10628             :  * of the band to be queried. This would be zero to start from the top.
   10629             :  *
   10630             :  * @param nXSize The width of the region of the band to be queried in pixels.
   10631             :  *
   10632             :  * @param nYSize The height of the region of the band to be queried in lines.
   10633             :  *
   10634             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
   10635             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10636             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
   10637             :  * as the computation of the coverage matches the mask, the computation will be
   10638             :  * stopped. *pdfDataPct will not be valid in that case.
   10639             :  *
   10640             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
   10641             :  * to the (approximate) percentage in [0,100] of pixels in the queried
   10642             :  * sub-window that have valid values. The implementation might not always be
   10643             :  * able to compute it, in which case it will be set to a negative value.
   10644             :  *
   10645             :  * @return a binary-or'ed combination of possible values
   10646             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
   10647             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
   10648             :  */
   10649             : 
   10650        4753 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
   10651             :                                           int nYSize, int nMaskFlagStop,
   10652             :                                           double *pdfDataPct)
   10653             : {
   10654        4753 :     if (nXOff < 0 || nYOff < 0 || nXSize > nRasterXSize - nXOff ||
   10655        4753 :         nYSize > nRasterYSize - nYOff)
   10656             :     {
   10657           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
   10658           0 :         if (pdfDataPct)
   10659           0 :             *pdfDataPct = 0.0;
   10660             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10661           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
   10662             :     }
   10663        4753 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
   10664        4753 :                                   pdfDataPct);
   10665             : }
   10666             : 
   10667             : /************************************************************************/
   10668             : /*                       IGetDataCoverageStatus()                       */
   10669             : /************************************************************************/
   10670             : 
   10671         692 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
   10672             :                                            int /*nXSize*/, int /*nYSize*/,
   10673             :                                            int /*nMaskFlagStop*/,
   10674             :                                            double *pdfDataPct)
   10675             : {
   10676         692 :     if (pdfDataPct != nullptr)
   10677           0 :         *pdfDataPct = 100.0;
   10678             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
   10679         692 :            GDAL_DATA_COVERAGE_STATUS_DATA;
   10680             : }
   10681             : 
   10682             : //! @cond Doxygen_Suppress
   10683             : /************************************************************************/
   10684             : /*                           EnterReadWrite()                           */
   10685             : /************************************************************************/
   10686             : 
   10687     8059500 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
   10688             : {
   10689     8059500 :     if (poDS != nullptr)
   10690     7290940 :         return poDS->EnterReadWrite(eRWFlag);
   10691      768558 :     return FALSE;
   10692             : }
   10693             : 
   10694             : /************************************************************************/
   10695             : /*                           LeaveReadWrite()                           */
   10696             : /************************************************************************/
   10697             : 
   10698     1145470 : void GDALRasterBand::LeaveReadWrite()
   10699             : {
   10700     1145470 :     if (poDS != nullptr)
   10701     1145470 :         poDS->LeaveReadWrite();
   10702     1145470 : }
   10703             : 
   10704             : /************************************************************************/
   10705             : /*                             InitRWLock()                             */
   10706             : /************************************************************************/
   10707             : 
   10708     3989040 : void GDALRasterBand::InitRWLock()
   10709             : {
   10710     3989040 :     if (poDS != nullptr)
   10711     3988630 :         poDS->InitRWLock();
   10712     3989040 : }
   10713             : 
   10714             : //! @endcond
   10715             : 
   10716             : // clang-format off
   10717             : 
   10718             : /**
   10719             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
   10720             :  * \brief Set metadata.
   10721             :  *
   10722             :  * CAUTION: depending on the format, older values of the updated information
   10723             :  * might still be found in the file in a "ghost" state, even if no longer
   10724             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10725             :  * format (this is not a exhaustive list)
   10726             :  *
   10727             :  * The C function GDALSetMetadata() does the same thing as this method.
   10728             :  *
   10729             :  * @param papszMetadata the metadata in name=value string list format to
   10730             :  * apply.
   10731             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
   10732             :  * domain.
   10733             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
   10734             :  * metadata has been accepted, but is likely not maintained persistently
   10735             :  * by the underlying object between sessions.
   10736             :  */
   10737             : 
   10738             : /**
   10739             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
   10740             :  * \brief Set single metadata item.
   10741             :  *
   10742             :  * CAUTION: depending on the format, older values of the updated information
   10743             :  * might still be found in the file in a "ghost" state, even if no longer
   10744             :  * accessible through the GDAL API. This is for example the case of the GTiff
   10745             :  * format (this is not a exhaustive list)
   10746             :  *
   10747             :  * The C function GDALSetMetadataItem() does the same thing as this method.
   10748             :  *
   10749             :  * @param pszName the key for the metadata item to fetch.
   10750             :  * @param pszValue the value to assign to the key.
   10751             :  * @param pszDomain the domain to set within, use NULL for the default domain.
   10752             :  *
   10753             :  * @return CE_None on success, or an error code on failure.
   10754             :  */
   10755             : 
   10756             : // clang-format on
   10757             : 
   10758             : //! @cond Doxygen_Suppress
   10759             : /************************************************************************/
   10760             : /*                  EnablePixelTypeSignedByteWarning()                  */
   10761             : /************************************************************************/
   10762             : 
   10763      157817 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
   10764             : {
   10765      157817 :     m_bEnablePixelTypeSignedByteWarning = b;
   10766      157817 : }
   10767             : 
   10768        4882 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
   10769             : {
   10770        4882 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
   10771        4882 : }
   10772             : 
   10773             : //! @endcond
   10774             : 
   10775             : /************************************************************************/
   10776             : /*                          GetMetadataItem()                           */
   10777             : /************************************************************************/
   10778             : 
   10779      633712 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
   10780             :                                             const char *pszDomain)
   10781             : {
   10782             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
   10783      633712 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_UInt8 &&
   10784      474300 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
   10785      333559 :         EQUAL(pszName, "PIXELTYPE"))
   10786             :     {
   10787           2 :         CPLError(CE_Warning, CPLE_AppDefined,
   10788             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
   10789             :                  "used to signal signed 8-bit raster. Change your code to "
   10790             :                  "test for the new GDT_Int8 data type instead.");
   10791             :     }
   10792      633712 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
   10793             : }
   10794             : 
   10795             : /************************************************************************/
   10796             : /*                      GDALRasterBandAsMDArray()                       */
   10797             : /************************************************************************/
   10798             : 
   10799             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
   10800             :  *
   10801             :  * The band must be linked to a GDALDataset. If this dataset is not already
   10802             :  * marked as shared, it will be, so that the returned array holds a reference
   10803             :  * to it.
   10804             :  *
   10805             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   10806             :  * returned array will have an associated indexing variable.
   10807             :  *
   10808             :  * The returned pointer must be released with GDALMDArrayRelease().
   10809             :  *
   10810             :  * This is the same as the C++ method GDALRasterBand::AsMDArray().
   10811             :  *
   10812             :  * @return a new array, or NULL.
   10813             :  *
   10814             :  * @since GDAL 3.1
   10815             :  */
   10816          25 : GDALMDArrayH GDALRasterBandAsMDArray(GDALRasterBandH hBand)
   10817             : {
   10818          25 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   10819          50 :     auto poArray(GDALRasterBand::FromHandle(hBand)->AsMDArray());
   10820          25 :     if (!poArray)
   10821           0 :         return nullptr;
   10822          25 :     return new GDALMDArrayHS(poArray);
   10823             : }
   10824             : 
   10825             : /************************************************************************/
   10826             : /*                            WindowIterator                            */
   10827             : /************************************************************************/
   10828             : 
   10829             : //! @cond Doxygen_Suppress
   10830             : 
   10831         696 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
   10832             :                                                int nRasterYSize,
   10833             :                                                int nBlockXSize, int nBlockYSize,
   10834         696 :                                                int nRow, int nCol)
   10835             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
   10836             :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
   10837         696 :       m_col(nCol)
   10838             : {
   10839         696 : }
   10840             : 
   10841         751 : bool GDALRasterBand::WindowIterator::operator==(
   10842             :     const WindowIterator &other) const
   10843             : {
   10844         310 :     return m_row == other.m_row && m_col == other.m_col &&
   10845         310 :            m_nRasterXSize == other.m_nRasterXSize &&
   10846         310 :            m_nRasterYSize == other.m_nRasterYSize &&
   10847        1371 :            m_nBlockXSize == other.m_nBlockXSize &&
   10848        1061 :            m_nBlockYSize == other.m_nBlockYSize;
   10849             : }
   10850             : 
   10851         727 : bool GDALRasterBand::WindowIterator::operator!=(
   10852             :     const WindowIterator &other) const
   10853             : {
   10854         727 :     return !(*this == other);
   10855             : }
   10856             : 
   10857             : GDALRasterBand::WindowIterator::value_type
   10858         440 : GDALRasterBand::WindowIterator::operator*() const
   10859             : {
   10860             :     GDALRasterWindow ret;
   10861         440 :     ret.nXOff = m_col * m_nBlockXSize;
   10862         440 :     ret.nYOff = m_row * m_nBlockYSize;
   10863         440 :     ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
   10864         440 :     ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
   10865             : 
   10866         440 :     return ret;
   10867             : }
   10868             : 
   10869         431 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
   10870             : {
   10871         431 :     m_col++;
   10872         431 :     if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
   10873             :     {
   10874         335 :         m_col = 0;
   10875         335 :         m_row++;
   10876             :     }
   10877         431 :     return *this;
   10878             : }
   10879             : 
   10880         163 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
   10881         163 :     const GDALRasterBand &band, size_t maxSize)
   10882         163 :     : WindowIteratorWrapper(band.GetXSize(), band.GetYSize(), band.nBlockXSize,
   10883         163 :                             band.nBlockYSize, maxSize)
   10884             : {
   10885         163 : }
   10886             : 
   10887         201 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
   10888         201 :     const GDALRasterBand &band1, const GDALRasterBand &band2, size_t maxSize)
   10889         201 :     : WindowIteratorWrapper(std::min(band1.GetXSize(), band2.GetXSize()),
   10890         201 :                             std::min(band1.GetYSize(), band2.GetYSize()),
   10891         201 :                             std::lcm(band1.nBlockXSize, band2.nBlockXSize),
   10892         201 :                             std::lcm(band1.nBlockYSize, band2.nBlockYSize),
   10893         603 :                             maxSize)
   10894             : {
   10895         402 :     if (band1.GetXSize() != band2.GetXSize() ||
   10896         201 :         band1.GetYSize() != band2.GetYSize())
   10897             :     {
   10898           0 :         CPLError(CE_Warning, CPLE_AppDefined,
   10899             :                  "WindowIteratorWrapper called on bands of different "
   10900             :                  "dimensions. Selecting smallest one");
   10901             :     }
   10902         201 : }
   10903             : 
   10904         364 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(int nRasterXSize,
   10905             :                                                              int nRasterYSize,
   10906             :                                                              int nBlockXSize,
   10907             :                                                              int nBlockYSize,
   10908         364 :                                                              size_t maxSize)
   10909             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
   10910         364 :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize)
   10911             : {
   10912             : #ifdef CSA_BUILD
   10913             :     assert(this);
   10914             : #endif
   10915         364 :     int nXSize = std::min(m_nRasterXSize, m_nBlockXSize);
   10916         364 :     int nYSize = std::min(m_nRasterYSize, m_nBlockYSize);
   10917             : 
   10918         364 :     if (nXSize < 1 || nYSize < 1)
   10919             :     {
   10920             :         // If invalid block size is reported, assume scanlines
   10921           8 :         nXSize = m_nRasterXSize;
   10922           8 :         nYSize = 1;
   10923             :     }
   10924             : 
   10925         364 :     if (maxSize == 0)
   10926             :     {
   10927          69 :         m_nBlockXSize = nXSize;
   10928          69 :         m_nBlockYSize = nYSize;
   10929          69 :         return;
   10930             :     }
   10931             : 
   10932         295 :     const double dfBlocksPerRow = static_cast<double>(m_nRasterXSize) / nXSize;
   10933         295 :     const double dfBlocksPerChunk =
   10934         295 :         static_cast<double>(maxSize) /
   10935         295 :         (static_cast<double>(nXSize) * static_cast<double>(nYSize));
   10936             : 
   10937         295 :     if (dfBlocksPerChunk < dfBlocksPerRow)
   10938             :     {
   10939          14 :         m_nBlockXSize = static_cast<int>(std::min<double>(
   10940          14 :             m_nRasterXSize,
   10941          14 :             nXSize * std::max(std::floor(dfBlocksPerChunk), 1.0)));
   10942          14 :         m_nBlockYSize = nYSize;
   10943             :     }
   10944             :     else
   10945             :     {
   10946         281 :         m_nBlockXSize = m_nRasterXSize;
   10947         281 :         m_nBlockYSize = static_cast<int>(std::min<double>(
   10948         281 :             m_nRasterYSize,
   10949         281 :             nYSize * std::floor(dfBlocksPerChunk / dfBlocksPerRow)));
   10950             :     }
   10951             :     if constexpr (sizeof(size_t) < sizeof(uint64_t))
   10952             :     {
   10953             :         if (m_nBlockXSize > std::numeric_limits<int>::max() / m_nBlockYSize)
   10954             :         {
   10955             :             m_nBlockXSize = m_nRasterXSize;
   10956             :             m_nBlockYSize = 1;
   10957             :         }
   10958             :     }
   10959             : }
   10960             : 
   10961             : GDALRasterBand::WindowIterator
   10962         333 : GDALRasterBand::WindowIteratorWrapper::begin() const
   10963             : {
   10964         333 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10965         333 :                           m_nBlockYSize, 0, 0);
   10966             : }
   10967             : 
   10968             : GDALRasterBand::WindowIterator
   10969         333 : GDALRasterBand::WindowIteratorWrapper::end() const
   10970             : {
   10971         333 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
   10972         333 :                           m_nBlockYSize,
   10973         333 :                           DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
   10974             : }
   10975             : 
   10976          63 : uint64_t GDALRasterBand::WindowIteratorWrapper::count() const
   10977             : {
   10978          63 :     return static_cast<uint64_t>(
   10979          63 :                cpl::div_round_up(m_nRasterXSize, m_nBlockXSize)) *
   10980          63 :            static_cast<uint64_t>(
   10981          63 :                cpl::div_round_up(m_nRasterYSize, m_nBlockYSize));
   10982             : }
   10983             : 
   10984             : //! @endcond
   10985             : 
   10986             : /** Return an object whose begin() and end() methods can be used to iterate
   10987             :  *  over GDALRasterWindow objects that are aligned with blocks in this raster
   10988             :  *  band. The iteration order is from left to right, then from top to bottom.
   10989             :  *
   10990             : \code{.cpp}
   10991             :     std::vector<double> pixelValues;
   10992             :     for (const auto& window : poBand->IterateWindows()) {
   10993             :         CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
   10994             :                                          window.nXSize, window.nYSize);
   10995             :         // check eErr
   10996             :     }
   10997             : \endcode
   10998             :  *
   10999             :  *
   11000             :  *  @param maxSize The maximum number of pixels in each window. If set to
   11001             :  *         zero (the default), or a number smaller than the block size,
   11002             :  *         the window size will be the same as the block size.
   11003             :  *  @since GDAL 3.12
   11004             :  */
   11005             : GDALRasterBand::WindowIteratorWrapper
   11006         163 : GDALRasterBand::IterateWindows(size_t maxSize) const
   11007             : {
   11008         163 :     return WindowIteratorWrapper(*this, maxSize);
   11009             : }
   11010             : 
   11011             : /************************************************************************/
   11012             : /*                MayMultiBlockReadingBeMultiThreaded()                 */
   11013             : /************************************************************************/
   11014             : 
   11015             : /** Return whether a RasterIO(GF_Read) request spanning over multiple
   11016             :  * blocks may be accelerated internally using multi-threading.
   11017             :  *
   11018             :  * This can be used to determine the best chunk size to read a raster band.
   11019             :  *
   11020             :  * Note that such optimizations may require that the window is perfectly aligned
   11021             :  * on block boundaries and does not involve resampling or data type translation
   11022             :  * occurs, etc.
   11023             :  *
   11024             :  * @since GDAL 3.13
   11025             :  */
   11026           0 : bool GDALRasterBand::MayMultiBlockReadingBeMultiThreaded() const
   11027             : {
   11028           0 :     return false;
   11029             : }
   11030             : 
   11031             : /************************************************************************/
   11032             : /*                      GDALMDArrayFromRasterBand                       */
   11033             : /************************************************************************/
   11034             : 
   11035             : class GDALMDArrayFromRasterBand final : public GDALMDArray
   11036             : {
   11037             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
   11038             : 
   11039             :     GDALDataset *m_poDS;
   11040             :     GDALRasterBand *m_poBand;
   11041             :     GDALExtendedDataType m_dt;
   11042             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
   11043             :     std::string m_osUnit;
   11044             :     std::vector<GByte> m_pabyNoData{};
   11045             :     std::shared_ptr<GDALMDArray> m_varX{};
   11046             :     std::shared_ptr<GDALMDArray> m_varY{};
   11047             :     std::string m_osFilename{};
   11048             :     mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
   11049             : 
   11050             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
   11051             :                    const size_t *count, const GInt64 *arrayStep,
   11052             :                    const GPtrDiff_t *bufferStride,
   11053             :                    const GDALExtendedDataType &bufferDataType,
   11054             :                    void *pBuffer) const;
   11055             : 
   11056             :   protected:
   11057          36 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
   11058          72 :         : GDALAbstractMDArray(std::string(),
   11059          72 :                               std::string(poDS->GetDescription()) +
   11060             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
   11061          72 :           GDALMDArray(std::string(),
   11062          72 :                       std::string(poDS->GetDescription()) +
   11063             :                           CPLSPrintf(" band %d", poBand->GetBand())),
   11064             :           m_poDS(poDS), m_poBand(poBand),
   11065             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
   11066         180 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
   11067             :     {
   11068          36 :         m_poDS->Reference();
   11069             : 
   11070          36 :         int bHasNoData = false;
   11071          36 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
   11072             :         {
   11073           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
   11074           0 :             if (bHasNoData)
   11075             :             {
   11076           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   11077           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
   11078             :                                 m_dt.GetNumericDataType(), 0, 1);
   11079             :             }
   11080             :         }
   11081          36 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
   11082             :         {
   11083           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
   11084           0 :             if (bHasNoData)
   11085             :             {
   11086           0 :                 m_pabyNoData.resize(m_dt.GetSize());
   11087           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
   11088             :                                 m_dt.GetNumericDataType(), 0, 1);
   11089             :             }
   11090             :         }
   11091             :         else
   11092             :         {
   11093          36 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
   11094          36 :             if (bHasNoData)
   11095             :             {
   11096           1 :                 m_pabyNoData.resize(m_dt.GetSize());
   11097           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
   11098             :                                 m_dt.GetNumericDataType(), 0, 1);
   11099             :             }
   11100             :         }
   11101             : 
   11102          36 :         const int nXSize = poBand->GetXSize();
   11103          36 :         const int nYSize = poBand->GetYSize();
   11104             : 
   11105          36 :         auto poSRS = m_poDS->GetSpatialRef();
   11106          72 :         std::string osTypeY;
   11107          72 :         std::string osTypeX;
   11108          72 :         std::string osDirectionY;
   11109          72 :         std::string osDirectionX;
   11110          36 :         if (poSRS && poSRS->GetAxesCount() == 2)
   11111             :         {
   11112          24 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
   11113          24 :             OGRAxisOrientation eOrientation1 = OAO_Other;
   11114          24 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
   11115          24 :             OGRAxisOrientation eOrientation2 = OAO_Other;
   11116          24 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
   11117          24 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
   11118             :             {
   11119           8 :                 if (mapping == std::vector<int>{1, 2})
   11120             :                 {
   11121           8 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11122           8 :                     osDirectionY = "NORTH";
   11123           8 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11124           8 :                     osDirectionX = "EAST";
   11125             :                 }
   11126             :             }
   11127          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
   11128             :             {
   11129          16 :                 if (mapping == std::vector<int>{2, 1})
   11130             :                 {
   11131          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
   11132          16 :                     osDirectionY = "NORTH";
   11133          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
   11134          16 :                     osDirectionX = "EAST";
   11135             :                 }
   11136             :             }
   11137             :         }
   11138             : 
   11139         180 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
   11140             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
   11141          72 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
   11142         108 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
   11143             : 
   11144          36 :         GDALGeoTransform gt;
   11145          36 :         if (m_poDS->GetGeoTransform(gt) == CE_None && gt.IsAxisAligned())
   11146             :         {
   11147          50 :             m_varX = GDALMDArrayRegularlySpaced::Create(
   11148          50 :                 "/", "X", m_dims[1], gt.xorig, gt.xscale, 0.5);
   11149          25 :             m_dims[1]->SetIndexingVariable(m_varX);
   11150             : 
   11151          50 :             m_varY = GDALMDArrayRegularlySpaced::Create(
   11152          50 :                 "/", "Y", m_dims[0], gt.yorig, gt.yscale, 0.5);
   11153          25 :             m_dims[0]->SetIndexingVariable(m_varY);
   11154             :         }
   11155          36 :     }
   11156             : 
   11157             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
   11158             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11159             :                const GDALExtendedDataType &bufferDataType,
   11160             :                void *pDstBuffer) const override;
   11161             : 
   11162           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
   11163             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11164             :                 const GDALExtendedDataType &bufferDataType,
   11165             :                 const void *pSrcBuffer) override
   11166             :     {
   11167           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
   11168             :                          bufferStride, bufferDataType,
   11169           1 :                          const_cast<void *>(pSrcBuffer));
   11170             :     }
   11171             : 
   11172             :   public:
   11173          72 :     ~GDALMDArrayFromRasterBand() override
   11174          36 :     {
   11175          36 :         m_poDS->ReleaseRef();
   11176          72 :     }
   11177             : 
   11178          36 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
   11179             :                                                GDALRasterBand *poBand)
   11180             :     {
   11181             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
   11182          72 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
   11183          36 :         array->SetSelf(array);
   11184          72 :         return array;
   11185             :     }
   11186             : 
   11187           5 :     bool IsWritable() const override
   11188             :     {
   11189           5 :         return m_poDS->GetAccess() == GA_Update;
   11190             :     }
   11191             : 
   11192         112 :     const std::string &GetFilename() const override
   11193             :     {
   11194         112 :         return m_osFilename;
   11195             :     }
   11196             : 
   11197             :     const std::vector<std::shared_ptr<GDALDimension>> &
   11198         350 :     GetDimensions() const override
   11199             :     {
   11200         350 :         return m_dims;
   11201             :     }
   11202             : 
   11203         158 :     const GDALExtendedDataType &GetDataType() const override
   11204             :     {
   11205         158 :         return m_dt;
   11206             :     }
   11207             : 
   11208           5 :     const std::string &GetUnit() const override
   11209             :     {
   11210           5 :         return m_osUnit;
   11211             :     }
   11212             : 
   11213          32 :     const void *GetRawNoDataValue() const override
   11214             :     {
   11215          32 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
   11216             :     }
   11217             : 
   11218           4 :     double GetOffset(bool *pbHasOffset,
   11219             :                      GDALDataType *peStorageType) const override
   11220             :     {
   11221           4 :         int bHasOffset = false;
   11222           4 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
   11223           4 :         if (pbHasOffset)
   11224           4 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
   11225           4 :         if (peStorageType)
   11226           1 :             *peStorageType = GDT_Unknown;
   11227           4 :         return dfRes;
   11228             :     }
   11229             : 
   11230           4 :     double GetScale(bool *pbHasScale,
   11231             :                     GDALDataType *peStorageType) const override
   11232             :     {
   11233           4 :         int bHasScale = false;
   11234           4 :         double dfRes = m_poBand->GetScale(&bHasScale);
   11235           4 :         if (pbHasScale)
   11236           4 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
   11237           4 :         if (peStorageType)
   11238           1 :             *peStorageType = GDT_Unknown;
   11239           4 :         return dfRes;
   11240             :     }
   11241             : 
   11242          88 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
   11243             :     {
   11244          88 :         auto poSrcSRS = m_poDS->GetSpatialRef();
   11245          88 :         if (!poSrcSRS)
   11246           2 :             return nullptr;
   11247         172 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
   11248             : 
   11249         172 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
   11250          86 :         constexpr int iYDim = 0;
   11251          86 :         constexpr int iXDim = 1;
   11252         258 :         for (auto &m : axisMapping)
   11253             :         {
   11254         172 :             if (m == 1)
   11255          86 :                 m = iXDim + 1;
   11256          86 :             else if (m == 2)
   11257          86 :                 m = iYDim + 1;
   11258             :             else
   11259           0 :                 m = 0;
   11260             :         }
   11261          86 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
   11262          86 :         return poSRS;
   11263             :     }
   11264             : 
   11265          32 :     std::vector<GUInt64> GetBlockSize() const override
   11266             :     {
   11267          32 :         int nBlockXSize = 0;
   11268          32 :         int nBlockYSize = 0;
   11269          32 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
   11270          32 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
   11271          32 :                                     static_cast<GUInt64>(nBlockXSize)};
   11272             :     }
   11273             : 
   11274             :     std::vector<std::shared_ptr<GDALAttribute>>
   11275          23 :     GetAttributes(CSLConstList) const override
   11276             :     {
   11277          23 :         std::vector<std::shared_ptr<GDALAttribute>> res;
   11278          23 :         auto papszMD = m_poBand->GetMetadata();
   11279          25 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
   11280             :         {
   11281           2 :             char *pszKey = nullptr;
   11282           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
   11283           2 :             if (pszKey && pszValue)
   11284             :             {
   11285             :                 res.emplace_back(
   11286           2 :                     std::make_shared<GDALMDIAsAttribute>(pszKey, pszValue));
   11287             :             }
   11288           2 :             CPLFree(pszKey);
   11289             :         }
   11290          23 :         return res;
   11291             :     }
   11292             : 
   11293           6 :     int GetOverviewCount() const override
   11294             :     {
   11295           6 :         return m_poBand->GetOverviewCount();
   11296             :     }
   11297             : 
   11298           4 :     std::shared_ptr<GDALMDArray> GetOverview(int idx) const override
   11299             :     {
   11300           4 :         const int nOverviews = GetOverviewCount();
   11301           4 :         if (idx < 0 || idx >= nOverviews)
   11302           2 :             return nullptr;
   11303           2 :         m_apoOverviews.resize(nOverviews);
   11304           2 :         if (!m_apoOverviews[idx])
   11305             :         {
   11306           1 :             if (auto poOvrBand = m_poBand->GetOverview(idx))
   11307             :             {
   11308           1 :                 if (auto poOvrDS = poOvrBand->GetDataset())
   11309             :                 {
   11310           1 :                     m_apoOverviews[idx] = Create(poOvrDS, poOvrBand);
   11311             :                 }
   11312             :             }
   11313             :         }
   11314           2 :         return m_apoOverviews[idx];
   11315             :     }
   11316             : };
   11317             : 
   11318          39 : bool GDALMDArrayFromRasterBand::IRead(
   11319             :     const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
   11320             :     const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
   11321             :     void *pDstBuffer) const
   11322             : {
   11323          39 :     return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
   11324          39 :                      bufferDataType, pDstBuffer);
   11325             : }
   11326             : 
   11327             : /************************************************************************/
   11328             : /*                             ReadWrite()                              */
   11329             : /************************************************************************/
   11330             : 
   11331          40 : bool GDALMDArrayFromRasterBand::ReadWrite(
   11332             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
   11333             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
   11334             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
   11335             : {
   11336          40 :     constexpr size_t iDimX = 1;
   11337          40 :     constexpr size_t iDimY = 0;
   11338          40 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
   11339             :                                   arrayStartIdx, count, arrayStep, bufferStride,
   11340          40 :                                   bufferDataType, pBuffer);
   11341             : }
   11342             : 
   11343             : /************************************************************************/
   11344             : /*                       GDALMDRasterIOFromBand()                       */
   11345             : /************************************************************************/
   11346             : 
   11347          73 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
   11348             :                             size_t iDimX, size_t iDimY,
   11349             :                             const GUInt64 *arrayStartIdx, const size_t *count,
   11350             :                             const GInt64 *arrayStep,
   11351             :                             const GPtrDiff_t *bufferStride,
   11352             :                             const GDALExtendedDataType &bufferDataType,
   11353             :                             void *pBuffer)
   11354             : {
   11355          73 :     const auto eDT(bufferDataType.GetNumericDataType());
   11356          73 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
   11357          73 :     const int nX =
   11358          73 :         arrayStep[iDimX] > 0
   11359          73 :             ? static_cast<int>(arrayStartIdx[iDimX])
   11360           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
   11361           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
   11362          73 :     const int nY =
   11363          73 :         arrayStep[iDimY] > 0
   11364          73 :             ? static_cast<int>(arrayStartIdx[iDimY])
   11365           6 :             : static_cast<int>(arrayStartIdx[iDimY] -
   11366           6 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
   11367             :     const int nSizeX =
   11368          73 :         static_cast<int>(count[iDimX] * std::abs(arrayStep[iDimX]));
   11369             :     const int nSizeY =
   11370          73 :         static_cast<int>(count[iDimY] * std::abs(arrayStep[iDimY]));
   11371          73 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
   11372          73 :     int nStrideXSign = 1;
   11373          73 :     if (arrayStep[iDimX] < 0)
   11374             :     {
   11375           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
   11376           2 :         nStrideXSign = -1;
   11377             :     }
   11378          73 :     int nStrideYSign = 1;
   11379          73 :     if (arrayStep[iDimY] < 0)
   11380             :     {
   11381           6 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
   11382           6 :         nStrideYSign = -1;
   11383             :     }
   11384             : 
   11385         146 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
   11386          73 :                             static_cast<int>(count[iDimX]),
   11387          73 :                             static_cast<int>(count[iDimY]), eDT,
   11388             :                             static_cast<GSpacing>(
   11389          73 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
   11390             :                             static_cast<GSpacing>(
   11391          73 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
   11392          73 :                             nullptr) == CE_None;
   11393             : }
   11394             : 
   11395             : /************************************************************************/
   11396             : /*                             AsMDArray()                              */
   11397             : /************************************************************************/
   11398             : 
   11399             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
   11400             :  *
   11401             :  * The band must be linked to a GDALDataset. If this dataset is not already
   11402             :  * marked as shared, it will be, so that the returned array holds a reference
   11403             :  * to it.
   11404             :  *
   11405             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   11406             :  * returned array will have an associated indexing variable.
   11407             :  *
   11408             :  * This is the same as the C function GDALRasterBandAsMDArray().
   11409             :  *
   11410             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
   11411             :  *
   11412             :  * @return a new array, or nullptr.
   11413             :  *
   11414             :  * @since GDAL 3.1
   11415             :  */
   11416          35 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
   11417             : {
   11418          35 :     if (!poDS)
   11419             :     {
   11420           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
   11421           0 :         return nullptr;
   11422             :     }
   11423          35 :     if (!poDS->GetShared())
   11424             :     {
   11425          33 :         poDS->MarkAsShared();
   11426             :     }
   11427             :     return GDALMDArrayFromRasterBand::Create(
   11428          35 :         poDS, const_cast<GDALRasterBand *>(this));
   11429             : }
   11430             : 
   11431             : /************************************************************************/
   11432             : /*                         InterpolateAtPoint()                         */
   11433             : /************************************************************************/
   11434             : 
   11435             : /**
   11436             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11437             :  * taking pixel/line coordinates as input.
   11438             :  *
   11439             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
   11440             :  * @param dfLine line coordinate as a double, where interpolation should be done.
   11441             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   11442             :  * @param pdfRealValue pointer to real part of interpolated value
   11443             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   11444             :  *
   11445             :  * @return CE_None on success, or an error code on failure.
   11446             :  * @since GDAL 3.10
   11447             :  */
   11448             : 
   11449         185 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
   11450             :                                           GDALRIOResampleAlg eInterpolation,
   11451             :                                           double *pdfRealValue,
   11452             :                                           double *pdfImagValue) const
   11453             : {
   11454         185 :     if (eInterpolation != GRIORA_NearestNeighbour &&
   11455          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
   11456             :         eInterpolation != GRIORA_CubicSpline)
   11457             :     {
   11458           2 :         CPLError(CE_Failure, CPLE_AppDefined,
   11459             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
   11460             :                  "methods "
   11461             :                  "allowed");
   11462             : 
   11463           2 :         return CE_Failure;
   11464             :     }
   11465             : 
   11466         183 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
   11467         183 :     if (!m_poPointsCache)
   11468         103 :         m_poPointsCache = new GDALDoublePointsCache();
   11469             : 
   11470             :     const bool res =
   11471         183 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
   11472             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
   11473             : 
   11474         183 :     return res ? CE_None : CE_Failure;
   11475             : }
   11476             : 
   11477             : /************************************************************************/
   11478             : /*                    GDALRasterInterpolateAtPoint()                    */
   11479             : /************************************************************************/
   11480             : 
   11481             : /**
   11482             :  * \brief Interpolates the value between pixels using
   11483             :  * a resampling algorithm
   11484             :  *
   11485             :  * @see GDALRasterBand::InterpolateAtPoint()
   11486             :  * @since GDAL 3.10
   11487             :  */
   11488             : 
   11489         162 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
   11490             :                                     double dfLine,
   11491             :                                     GDALRIOResampleAlg eInterpolation,
   11492             :                                     double *pdfRealValue, double *pdfImagValue)
   11493             : {
   11494         162 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
   11495             : 
   11496         162 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   11497         162 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
   11498         162 :                                       pdfRealValue, pdfImagValue);
   11499             : }
   11500             : 
   11501             : /************************************************************************/
   11502             : /*                      InterpolateAtGeolocation()                      */
   11503             : /************************************************************************/
   11504             : 
   11505             : /**
   11506             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11507             :  * taking georeferenced coordinates as input.
   11508             :  *
   11509             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   11510             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   11511             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   11512             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   11513             :  * array (generally WGS 84) if there is a geolocation array.
   11514             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   11515             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   11516             :  * be a easting, and dfGeolocY a northing.
   11517             :  *
   11518             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   11519             :  * expressed in that CRS, and that tuple must be conformant with the
   11520             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   11521             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   11522             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   11523             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   11524             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   11525             :  *
   11526             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
   11527             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
   11528             :  * it for details on how that transformation is done.
   11529             :  *
   11530             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   11531             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11532             :  * where interpolation should be done.
   11533             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   11534             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   11535             :  * where interpolation should be done.
   11536             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   11537             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   11538             :  * @param pdfRealValue pointer to real part of interpolated value
   11539             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   11540             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
   11541             :  *
   11542             :  * @return CE_None on success, or an error code on failure.
   11543             :  * @since GDAL 3.11
   11544             :  */
   11545             : 
   11546          15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
   11547             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
   11548             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
   11549             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
   11550             : {
   11551             :     double dfPixel;
   11552             :     double dfLine;
   11553          15 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
   11554             :                                      &dfLine,
   11555          15 :                                      papszTransformerOptions) != CE_None)
   11556             :     {
   11557           1 :         return CE_Failure;
   11558             :     }
   11559          14 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
   11560          14 :                               pdfImagValue);
   11561             : }
   11562             : 
   11563             : /************************************************************************/
   11564             : /*                 GDALRasterInterpolateAtGeolocation()                 */
   11565             : /************************************************************************/
   11566             : 
   11567             : /**
   11568             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   11569             :  * taking georeferenced coordinates as input.
   11570             :  *
   11571             :  * @see GDALRasterBand::InterpolateAtGeolocation()
   11572             :  * @since GDAL 3.11
   11573             :  */
   11574             : 
   11575          15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
   11576             :                                           double dfGeolocX, double dfGeolocY,
   11577             :                                           OGRSpatialReferenceH hSRS,
   11578             :                                           GDALRIOResampleAlg eInterpolation,
   11579             :                                           double *pdfRealValue,
   11580             :                                           double *pdfImagValue,
   11581             :                                           CSLConstList papszTransformerOptions)
   11582             : {
   11583          15 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
   11584             : 
   11585          15 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   11586          15 :     return poBand->InterpolateAtGeolocation(
   11587          15 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
   11588          15 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
   11589             : }
   11590             : 
   11591             : /************************************************************************/
   11592             : /*                   GDALRasterBand::SplitRasterIO()                    */
   11593             : /************************************************************************/
   11594             : 
   11595             : //! @cond Doxygen_Suppress
   11596             : 
   11597             : /** Implements IRasterIO() by dividing the request in 2.
   11598             :  *
   11599             :  * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
   11600             :  *
   11601             :  * Return CE_Warning if the split could not be done, CE_None in case of
   11602             :  * success and CE_Failure in case of error.
   11603             :  *
   11604             :  * @since 3.12
   11605             :  */
   11606         999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
   11607             :                                      [[maybe_unused]] int nXSize,
   11608             :                                      [[maybe_unused]] int nYSize, void *pData,
   11609             :                                      int nBufXSize, int nBufYSize,
   11610             :                                      GDALDataType eBufType,
   11611             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
   11612             :                                      GDALRasterIOExtraArg *psExtraArg)
   11613             : {
   11614         999 :     CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
   11615             : 
   11616         999 :     GByte *pabyData = static_cast<GByte *>(pData);
   11617         999 :     if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
   11618             :     {
   11619             :         GDALRasterIOExtraArg sArg;
   11620         499 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11621         499 :         const int nHalfHeight = nBufYSize / 2;
   11622             : 
   11623         499 :         sArg.pfnProgress = GDALScaledProgress;
   11624         499 :         sArg.pProgressData = GDALCreateScaledProgress(
   11625             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11626         499 :         if (sArg.pProgressData == nullptr)
   11627         499 :             sArg.pfnProgress = nullptr;
   11628         998 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
   11629             :                                 pabyData, nBufXSize, nHalfHeight, eBufType,
   11630         499 :                                 nPixelSpace, nLineSpace, &sArg);
   11631         499 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11632             : 
   11633         499 :         if (eErr == CE_None)
   11634             :         {
   11635         499 :             sArg.pfnProgress = GDALScaledProgress;
   11636         499 :             sArg.pProgressData = GDALCreateScaledProgress(
   11637             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11638         499 :             if (sArg.pProgressData == nullptr)
   11639         499 :                 sArg.pfnProgress = nullptr;
   11640         998 :             eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
   11641             :                              nBufYSize - nHalfHeight,
   11642         499 :                              pabyData + nHalfHeight * nLineSpace, nBufXSize,
   11643             :                              nBufYSize - nHalfHeight, eBufType, nPixelSpace,
   11644         499 :                              nLineSpace, &sArg);
   11645         499 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11646             :         }
   11647         499 :         return eErr;
   11648             :     }
   11649         500 :     else if (nBufXSize >= 2)
   11650             :     {
   11651             :         GDALRasterIOExtraArg sArg;
   11652         500 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   11653         500 :         const int nHalfWidth = nBufXSize / 2;
   11654             : 
   11655         500 :         sArg.pfnProgress = GDALScaledProgress;
   11656         500 :         sArg.pProgressData = GDALCreateScaledProgress(
   11657             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11658         500 :         if (sArg.pProgressData == nullptr)
   11659         500 :             sArg.pfnProgress = nullptr;
   11660        1000 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
   11661             :                                 pabyData, nHalfWidth, nBufYSize, eBufType,
   11662         500 :                                 nPixelSpace, nLineSpace, &sArg);
   11663         500 :         GDALDestroyScaledProgress(sArg.pProgressData);
   11664             : 
   11665         500 :         if (eErr == CE_None)
   11666             :         {
   11667         500 :             sArg.pfnProgress = GDALScaledProgress;
   11668         500 :             sArg.pProgressData = GDALCreateScaledProgress(
   11669             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   11670         500 :             if (sArg.pProgressData == nullptr)
   11671         500 :                 sArg.pfnProgress = nullptr;
   11672        1000 :             eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
   11673             :                              nBufXSize - nHalfWidth, nBufYSize,
   11674         500 :                              pabyData + nHalfWidth * nPixelSpace,
   11675             :                              nBufXSize - nHalfWidth, nBufYSize, eBufType,
   11676         500 :                              nPixelSpace, nLineSpace, &sArg);
   11677         500 :             GDALDestroyScaledProgress(sArg.pProgressData);
   11678             :         }
   11679         500 :         return eErr;
   11680             :     }
   11681             : 
   11682           0 :     return CE_Warning;
   11683             : }
   11684             : 
   11685             : //! @endcond
   11686             : 
   11687             : /************************************************************************/
   11688             : /*                      ThrowIfNotSameDimensions()                      */
   11689             : /************************************************************************/
   11690             : 
   11691             : //! @cond Doxygen_Suppress
   11692             : /* static */
   11693         169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
   11694             :                                               const GDALRasterBand &second)
   11695             : {
   11696         320 :     if (first.GetXSize() != second.GetXSize() ||
   11697         151 :         first.GetYSize() != second.GetYSize())
   11698             :     {
   11699          36 :         throw std::runtime_error("Bands do not have the same dimensions");
   11700             :     }
   11701         133 : }
   11702             : 
   11703             : //! @endcond
   11704             : 
   11705             : /************************************************************************/
   11706             : /*                       GDALRasterBandUnaryOp()                        */
   11707             : /************************************************************************/
   11708             : 
   11709             : /** Apply a unary operation on this band.
   11710             :  *
   11711             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11712             :  * dataset.
   11713             :  *
   11714             :  * @since 3.12
   11715             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11716             :  */
   11717             : GDALComputedRasterBandH
   11718           6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
   11719             :                       GDALRasterAlgebraUnaryOperation eOp)
   11720             : {
   11721           6 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11722           6 :     GDALComputedRasterBand::Operation cppOp{};
   11723           6 :     switch (eOp)
   11724             :     {
   11725           2 :         case GRAUO_LOGICAL_NOT:
   11726             :             return new GDALComputedRasterBand(
   11727             :                 GDALComputedRasterBand::Operation::OP_NE,
   11728           2 :                 *(GDALRasterBand::FromHandle(hBand)), true);
   11729           1 :         case GRAUO_ABS:
   11730           1 :             cppOp = GDALComputedRasterBand::Operation::OP_ABS;
   11731           1 :             break;
   11732           1 :         case GRAUO_SQRT:
   11733           1 :             cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
   11734           1 :             break;
   11735           1 :         case GRAUO_LOG:
   11736             : #ifndef HAVE_MUPARSER
   11737             :             CPLError(
   11738             :                 CE_Failure, CPLE_NotSupported,
   11739             :                 "log(band) not available on a GDAL build without muparser");
   11740             :             return nullptr;
   11741             : #else
   11742           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG;
   11743           1 :             break;
   11744             : #endif
   11745           1 :         case GRAUO_LOG10:
   11746           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
   11747           1 :             break;
   11748             :     }
   11749             :     return new GDALComputedRasterBand(cppOp,
   11750           4 :                                       *(GDALRasterBand::FromHandle(hBand)));
   11751             : }
   11752             : 
   11753             : /************************************************************************/
   11754             : /*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
   11755             : /************************************************************************/
   11756             : 
   11757             : static GDALComputedRasterBand::Operation
   11758         120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
   11759             :     GDALRasterAlgebraBinaryOperation eOp)
   11760             : {
   11761         120 :     switch (eOp)
   11762             :     {
   11763          26 :         case GRABO_ADD:
   11764          26 :             return GDALComputedRasterBand::Operation::OP_ADD;
   11765           2 :         case GRABO_SUB:
   11766           2 :             return GDALComputedRasterBand::Operation::OP_SUBTRACT;
   11767          24 :         case GRABO_MUL:
   11768          24 :             return GDALComputedRasterBand::Operation::OP_MULTIPLY;
   11769           3 :         case GRABO_DIV:
   11770           3 :             return GDALComputedRasterBand::Operation::OP_DIVIDE;
   11771           6 :         case GRABO_GT:
   11772           6 :             return GDALComputedRasterBand::Operation::OP_GT;
   11773           8 :         case GRABO_GE:
   11774           8 :             return GDALComputedRasterBand::Operation::OP_GE;
   11775           6 :         case GRABO_LT:
   11776           6 :             return GDALComputedRasterBand::Operation::OP_LT;
   11777           6 :         case GRABO_LE:
   11778           6 :             return GDALComputedRasterBand::Operation::OP_LE;
   11779           6 :         case GRABO_EQ:
   11780           6 :             return GDALComputedRasterBand::Operation::OP_EQ;
   11781           6 :         case GRABO_NE:
   11782           6 :             break;
   11783          12 :         case GRABO_LOGICAL_AND:
   11784          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
   11785          12 :         case GRABO_LOGICAL_OR:
   11786          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
   11787           3 :         case GRABO_POW:
   11788           3 :             return GDALComputedRasterBand::Operation::OP_POW;
   11789             :     }
   11790           6 :     return GDALComputedRasterBand::Operation::OP_NE;
   11791             : }
   11792             : 
   11793             : /************************************************************************/
   11794             : /*                     GDALRasterBandBinaryOpBand()                     */
   11795             : /************************************************************************/
   11796             : 
   11797             : /** Apply a binary operation on this band with another one.
   11798             :  *
   11799             :  * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
   11800             :  * "hBand1 - hBand2".
   11801             :  *
   11802             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11803             :  * datasets.
   11804             :  *
   11805             :  * @since 3.12
   11806             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11807             :  */
   11808             : GDALComputedRasterBandH
   11809          57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
   11810             :                            GDALRasterAlgebraBinaryOperation eOp,
   11811             :                            GDALRasterBandH hOtherBand)
   11812             : {
   11813          57 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11814          57 :     VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
   11815             : #ifndef HAVE_MUPARSER
   11816             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11817             :     {
   11818             :         CPLError(
   11819             :             CE_Failure, CPLE_NotSupported,
   11820             :             "Band comparison operators not available on a GDAL build without "
   11821             :             "muparser");
   11822             :         return nullptr;
   11823             :     }
   11824             :     else if (eOp == GRABO_POW)
   11825             :     {
   11826             :         CPLError(
   11827             :             CE_Failure, CPLE_NotSupported,
   11828             :             "pow(band, band) not available on a GDAL build without muparser");
   11829             :         return nullptr;
   11830             :     }
   11831             : #endif
   11832          57 :     auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
   11833          57 :     auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
   11834             :     try
   11835             :     {
   11836          57 :         GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
   11837             :     }
   11838          13 :     catch (const std::exception &e)
   11839             :     {
   11840          13 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   11841          13 :         return nullptr;
   11842             :     }
   11843             :     return new GDALComputedRasterBand(
   11844          44 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
   11845          44 :         secondBand);
   11846             : }
   11847             : 
   11848             : /************************************************************************/
   11849             : /*                    GDALRasterBandBinaryOpDouble()                    */
   11850             : /************************************************************************/
   11851             : 
   11852             : /** Apply a binary operation on this band with a constant
   11853             :  *
   11854             :  * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
   11855             :  * "hBand - constant".
   11856             :  *
   11857             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11858             :  * dataset.
   11859             :  *
   11860             :  * @since 3.12
   11861             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11862             :  */
   11863             : GDALComputedRasterBandH
   11864          59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
   11865             :                              GDALRasterAlgebraBinaryOperation eOp,
   11866             :                              double constant)
   11867             : {
   11868          59 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11869             : #ifndef HAVE_MUPARSER
   11870             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11871             :     {
   11872             :         CPLError(
   11873             :             CE_Failure, CPLE_NotSupported,
   11874             :             "Band comparison operators not available on a GDAL build without "
   11875             :             "muparser");
   11876             :         return nullptr;
   11877             :     }
   11878             : #endif
   11879             :     return new GDALComputedRasterBand(
   11880          59 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11881          59 :         *(GDALRasterBand::FromHandle(hBand)), constant);
   11882             : }
   11883             : 
   11884             : /************************************************************************/
   11885             : /*                 GDALRasterBandBinaryOpDoubleToBand()                 */
   11886             : /************************************************************************/
   11887             : 
   11888             : /** Apply a binary operation on the constant with this band
   11889             :  *
   11890             :  * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
   11891             :  * "constant - hBand".
   11892             :  *
   11893             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11894             :  * dataset.
   11895             :  *
   11896             :  * @since 3.12
   11897             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11898             :  */
   11899             : GDALComputedRasterBandH
   11900          18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
   11901             :                                    GDALRasterAlgebraBinaryOperation eOp,
   11902             :                                    GDALRasterBandH hBand)
   11903             : {
   11904          18 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11905             : #ifndef HAVE_MUPARSER
   11906             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   11907             :     {
   11908             :         CPLError(
   11909             :             CE_Failure, CPLE_NotSupported,
   11910             :             "Band comparison operators not available on a GDAL build without "
   11911             :             "muparser");
   11912             :         return nullptr;
   11913             :     }
   11914             : #endif
   11915          18 :     switch (eOp)
   11916             :     {
   11917          15 :         case GRABO_ADD:
   11918             :         case GRABO_MUL:
   11919             :         {
   11920             :             return new GDALComputedRasterBand(
   11921          15 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   11922          15 :                 *(GDALRasterBand::FromHandle(hBand)), constant);
   11923             :         }
   11924             : 
   11925           2 :         case GRABO_DIV:
   11926             :         case GRABO_GT:
   11927             :         case GRABO_GE:
   11928             :         case GRABO_LT:
   11929             :         case GRABO_LE:
   11930             :         case GRABO_EQ:
   11931             :         case GRABO_NE:
   11932             :         case GRABO_LOGICAL_AND:
   11933             :         case GRABO_LOGICAL_OR:
   11934             :         case GRABO_POW:
   11935             :         {
   11936             :             return new GDALComputedRasterBand(
   11937           2 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
   11938           2 :                 *(GDALRasterBand::FromHandle(hBand)));
   11939             :         }
   11940             : 
   11941           1 :         case GRABO_SUB:
   11942             :         {
   11943           1 :             break;
   11944             :         }
   11945             :     }
   11946             : 
   11947             :     return new GDALComputedRasterBand(
   11948             :         GDALComputedRasterBand::Operation::OP_ADD,
   11949           2 :         GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
   11950           1 :                                *(GDALRasterBand::FromHandle(hBand)), -1.0),
   11951           1 :         constant);
   11952             : }
   11953             : 
   11954             : /************************************************************************/
   11955             : /*                             operator+()                              */
   11956             : /************************************************************************/
   11957             : 
   11958             : /** Add this band with another one.
   11959             :  *
   11960             :  * The resulting band is lazy evaluated. A reference is taken on both input
   11961             :  * datasets.
   11962             :  *
   11963             :  * @since 3.12
   11964             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   11965             :  */
   11966             : GDALComputedRasterBand
   11967           8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
   11968             : {
   11969           8 :     ThrowIfNotSameDimensions(*this, other);
   11970             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11971           7 :                                   *this, other);
   11972             : }
   11973             : 
   11974             : /************************************************************************/
   11975             : /*                             operator+()                              */
   11976             : /************************************************************************/
   11977             : 
   11978             : /** Add this band with a constant.
   11979             :  *
   11980             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11981             :  * dataset.
   11982             :  *
   11983             :  * @since 3.12
   11984             :  */
   11985          13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
   11986             : {
   11987             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   11988          13 :                                   *this, constant);
   11989             : }
   11990             : 
   11991             : /************************************************************************/
   11992             : /*                             operator+()                              */
   11993             : /************************************************************************/
   11994             : 
   11995             : /** Add a band with a constant.
   11996             :  *
   11997             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11998             :  * dataset.
   11999             :  *
   12000             :  * @since 3.12
   12001             :  */
   12002           1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
   12003             : {
   12004           1 :     return other + constant;
   12005             : }
   12006             : 
   12007             : /************************************************************************/
   12008             : /*                             operator-()                              */
   12009             : /************************************************************************/
   12010             : 
   12011             : /** Return a band whose value is the opposite value of the band for each
   12012             :  * pixel.
   12013             :  *
   12014             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12015             :  * dataset.
   12016             :  *
   12017             :  * @since 3.12
   12018             :  */
   12019           2 : GDALComputedRasterBand GDALRasterBand::operator-() const
   12020             : {
   12021           2 :     return 0 - *this;
   12022             : }
   12023             : 
   12024             : /************************************************************************/
   12025             : /*                             operator-()                              */
   12026             : /************************************************************************/
   12027             : 
   12028             : /** Subtract this band with another one.
   12029             :  *
   12030             :  * The resulting band is lazy evaluated. A reference is taken on both input
   12031             :  * datasets.
   12032             :  *
   12033             :  * @since 3.12
   12034             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   12035             :  */
   12036             : GDALComputedRasterBand
   12037           2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
   12038             : {
   12039           2 :     ThrowIfNotSameDimensions(*this, other);
   12040             :     return GDALComputedRasterBand(
   12041           2 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
   12042             : }
   12043             : 
   12044             : /************************************************************************/
   12045             : /*                             operator-()                              */
   12046             : /************************************************************************/
   12047             : 
   12048             : /** Subtract this band with a constant.
   12049             :  *
   12050             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12051             :  * dataset.
   12052             :  *
   12053             :  * @since 3.12
   12054             :  */
   12055           1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
   12056             : {
   12057             :     return GDALComputedRasterBand(
   12058           1 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
   12059             : }
   12060             : 
   12061             : /************************************************************************/
   12062             : /*                             operator-()                              */
   12063             : /************************************************************************/
   12064             : 
   12065             : /** Subtract a constant with a band.
   12066             :  *
   12067             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12068             :  * dataset.
   12069             :  *
   12070             :  * @since 3.12
   12071             :  */
   12072           3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
   12073             : {
   12074           6 :     return other * (-1.0) + constant;
   12075             : }
   12076             : 
   12077             : /************************************************************************/
   12078             : /*                             operator*()                              */
   12079             : /************************************************************************/
   12080             : 
   12081             : /** Multiply this band with another one.
   12082             :  *
   12083             :  * The resulting band is lazy evaluated. A reference is taken on both input
   12084             :  * datasets.
   12085             :  *
   12086             :  * @since 3.12
   12087             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   12088             :  */
   12089             : GDALComputedRasterBand
   12090           2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
   12091             : {
   12092           2 :     ThrowIfNotSameDimensions(*this, other);
   12093             :     return GDALComputedRasterBand(
   12094           2 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
   12095             : }
   12096             : 
   12097             : /************************************************************************/
   12098             : /*                             operator*()                              */
   12099             : /************************************************************************/
   12100             : 
   12101             : /** Multiply this band by a constant.
   12102             :  *
   12103             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12104             :  * dataset.
   12105             :  *
   12106             :  * @since 3.12
   12107             :  */
   12108          14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
   12109             : {
   12110             :     return GDALComputedRasterBand(
   12111          14 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
   12112             : }
   12113             : 
   12114             : /************************************************************************/
   12115             : /*                             operator*()                              */
   12116             : /************************************************************************/
   12117             : 
   12118             : /** Multiply a band with a constant.
   12119             :  *
   12120             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12121             :  * dataset.
   12122             :  *
   12123             :  * @since 3.12
   12124             :  */
   12125           2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
   12126             : {
   12127           2 :     return other * constant;
   12128             : }
   12129             : 
   12130             : /************************************************************************/
   12131             : /*                             operator/()                              */
   12132             : /************************************************************************/
   12133             : 
   12134             : /** Divide this band with another one.
   12135             :  *
   12136             :  * The resulting band is lazy evaluated. A reference is taken on both input
   12137             :  * datasets.
   12138             :  *
   12139             :  * @since 3.12
   12140             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   12141             :  */
   12142             : GDALComputedRasterBand
   12143           2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
   12144             : {
   12145           2 :     ThrowIfNotSameDimensions(*this, other);
   12146             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12147           2 :                                   *this, other);
   12148             : }
   12149             : 
   12150             : /************************************************************************/
   12151             : /*                             operator/()                              */
   12152             : /************************************************************************/
   12153             : 
   12154             : /** Divide this band by a constant.
   12155             :  *
   12156             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12157             :  * dataset.
   12158             :  *
   12159             :  * @since 3.12
   12160             :  */
   12161           0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
   12162             : {
   12163             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12164           0 :                                   *this, constant);
   12165             : }
   12166             : 
   12167             : /************************************************************************/
   12168             : /*                             operator/()                              */
   12169             : /************************************************************************/
   12170             : 
   12171             : /** Divide a constant by a band.
   12172             :  *
   12173             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12174             :  * dataset.
   12175             :  *
   12176             :  * @since 3.12
   12177             :  */
   12178           1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
   12179             : {
   12180             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   12181           1 :                                   constant, other);
   12182             : }
   12183             : 
   12184             : /************************************************************************/
   12185             : /*                         ThrowIfNotMuparser()                         */
   12186             : /************************************************************************/
   12187             : 
   12188             : #ifndef HAVE_MUPARSER
   12189             : static GDALComputedRasterBand ThrowIfNotMuparser()
   12190             : {
   12191             :     throw std::runtime_error("Operator not available on a "
   12192             :                              "GDAL build without muparser");
   12193             : }
   12194             : #endif
   12195             : 
   12196             : /************************************************************************/
   12197             : /*                             operator>()                              */
   12198             : /************************************************************************/
   12199             : 
   12200             : /** Return a band whose value is 1 if the pixel value of the left operand
   12201             :  * is greater than the pixel value of the right operand.
   12202             :  *
   12203             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12204             :  * dataset.
   12205             :  *
   12206             :  * @since 3.12
   12207             :  */
   12208             : GDALComputedRasterBand
   12209           3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
   12210             : {
   12211             : #ifndef HAVE_MUPARSER
   12212             :     (void)other;
   12213             :     return ThrowIfNotMuparser();
   12214             : #else
   12215           3 :     ThrowIfNotSameDimensions(*this, other);
   12216             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12217           2 :                                   *this, other);
   12218             : #endif
   12219             : }
   12220             : 
   12221             : /************************************************************************/
   12222             : /*                             operator>()                              */
   12223             : /************************************************************************/
   12224             : 
   12225             : /** Return a band whose value is 1 if the pixel value of the left operand
   12226             :  * is greater than the constant.
   12227             :  *
   12228             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12229             :  * dataset.
   12230             :  *
   12231             :  * @since 3.12
   12232             :  */
   12233           3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
   12234             : {
   12235             : #ifndef HAVE_MUPARSER
   12236             :     (void)constant;
   12237             :     return ThrowIfNotMuparser();
   12238             : #else
   12239             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12240           3 :                                   *this, constant);
   12241             : #endif
   12242             : }
   12243             : 
   12244             : /************************************************************************/
   12245             : /*                             operator>()                              */
   12246             : /************************************************************************/
   12247             : 
   12248             : /** Return a band whose value is 1 if the constant is greater than the pixel
   12249             :  * value of the right operand.
   12250             :  *
   12251             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12252             :  * dataset.
   12253             :  *
   12254             :  * @since 3.12
   12255             :  */
   12256           2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
   12257             : {
   12258             : #ifndef HAVE_MUPARSER
   12259             :     (void)constant;
   12260             :     (void)other;
   12261             :     return ThrowIfNotMuparser();
   12262             : #else
   12263             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   12264           2 :                                   constant, other);
   12265             : #endif
   12266             : }
   12267             : 
   12268             : /************************************************************************/
   12269             : /*                             operator>=()                             */
   12270             : /************************************************************************/
   12271             : 
   12272             : /** Return a band whose value is 1 if the pixel value of the left operand
   12273             :  * is greater or equal to the pixel value of the right operand.
   12274             :  *
   12275             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12276             :  * dataset.
   12277             :  *
   12278             :  * @since 3.12
   12279             :  */
   12280             : GDALComputedRasterBand
   12281           4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
   12282             : {
   12283             : #ifndef HAVE_MUPARSER
   12284             :     (void)other;
   12285             :     return ThrowIfNotMuparser();
   12286             : #else
   12287           4 :     ThrowIfNotSameDimensions(*this, other);
   12288             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12289           3 :                                   *this, other);
   12290             : #endif
   12291             : }
   12292             : 
   12293             : /************************************************************************/
   12294             : /*                             operator>=()                             */
   12295             : /************************************************************************/
   12296             : 
   12297             : /** Return a band whose value is 1 if the pixel value of the left operand
   12298             :  * is greater or equal to the constant.
   12299             :  *
   12300             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12301             :  * dataset.
   12302             :  *
   12303             :  * @since 3.12
   12304             :  */
   12305           3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
   12306             : {
   12307             : #ifndef HAVE_MUPARSER
   12308             :     (void)constant;
   12309             :     return ThrowIfNotMuparser();
   12310             : #else
   12311             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12312           3 :                                   *this, constant);
   12313             : #endif
   12314             : }
   12315             : 
   12316             : /************************************************************************/
   12317             : /*                             operator>=()                             */
   12318             : /************************************************************************/
   12319             : 
   12320             : /** Return a band whose value is 1 if the constant is greater or equal to
   12321             :  * the pixel value of the right operand.
   12322             :  *
   12323             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12324             :  * dataset.
   12325             :  *
   12326             :  * @since 3.12
   12327             :  */
   12328           2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
   12329             : {
   12330             : #ifndef HAVE_MUPARSER
   12331             :     (void)constant;
   12332             :     (void)other;
   12333             :     return ThrowIfNotMuparser();
   12334             : #else
   12335             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   12336           2 :                                   constant, other);
   12337             : #endif
   12338             : }
   12339             : 
   12340             : /************************************************************************/
   12341             : /*                             operator<()                              */
   12342             : /************************************************************************/
   12343             : 
   12344             : /** Return a band whose value is 1 if the pixel value of the left operand
   12345             :  * is lesser than the pixel value of the right operand.
   12346             :  *
   12347             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12348             :  * dataset.
   12349             :  *
   12350             :  * @since 3.12
   12351             :  */
   12352             : GDALComputedRasterBand
   12353           3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
   12354             : {
   12355             : #ifndef HAVE_MUPARSER
   12356             :     (void)other;
   12357             :     return ThrowIfNotMuparser();
   12358             : #else
   12359           3 :     ThrowIfNotSameDimensions(*this, other);
   12360             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12361           2 :                                   *this, other);
   12362             : #endif
   12363             : }
   12364             : 
   12365             : /************************************************************************/
   12366             : /*                             operator<()                              */
   12367             : /************************************************************************/
   12368             : 
   12369             : /** Return a band whose value is 1 if the pixel value of the left operand
   12370             :  * is lesser than the constant.
   12371             :  *
   12372             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12373             :  * dataset.
   12374             :  *
   12375             :  * @since 3.12
   12376             :  */
   12377           3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
   12378             : {
   12379             : #ifndef HAVE_MUPARSER
   12380             :     (void)constant;
   12381             :     return ThrowIfNotMuparser();
   12382             : #else
   12383             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12384           3 :                                   *this, constant);
   12385             : #endif
   12386             : }
   12387             : 
   12388             : /************************************************************************/
   12389             : /*                             operator<()                              */
   12390             : /************************************************************************/
   12391             : 
   12392             : /** Return a band whose value is 1 if the constant is lesser than the pixel
   12393             :  * value of the right operand.
   12394             :  *
   12395             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12396             :  * dataset.
   12397             :  *
   12398             :  * @since 3.12
   12399             :  */
   12400           2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
   12401             : {
   12402             : #ifndef HAVE_MUPARSER
   12403             :     (void)constant;
   12404             :     (void)other;
   12405             :     return ThrowIfNotMuparser();
   12406             : #else
   12407             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   12408           2 :                                   constant, other);
   12409             : #endif
   12410             : }
   12411             : 
   12412             : /************************************************************************/
   12413             : /*                             operator<=()                             */
   12414             : /************************************************************************/
   12415             : 
   12416             : /** Return a band whose value is 1 if the pixel value of the left operand
   12417             :  * is lesser or equal to the pixel value of the right operand.
   12418             :  *
   12419             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12420             :  * dataset.
   12421             :  *
   12422             :  * @since 3.12
   12423             :  */
   12424             : GDALComputedRasterBand
   12425           4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
   12426             : {
   12427             : #ifndef HAVE_MUPARSER
   12428             :     (void)other;
   12429             :     return ThrowIfNotMuparser();
   12430             : #else
   12431           4 :     ThrowIfNotSameDimensions(*this, other);
   12432             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12433           3 :                                   *this, other);
   12434             : #endif
   12435             : }
   12436             : 
   12437             : /************************************************************************/
   12438             : /*                             operator<=()                             */
   12439             : /************************************************************************/
   12440             : 
   12441             : /** Return a band whose value is 1 if the pixel value of the left operand
   12442             :  * is lesser or equal to the constant.
   12443             :  *
   12444             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12445             :  * dataset.
   12446             :  *
   12447             :  * @since 3.12
   12448             :  */
   12449           3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
   12450             : {
   12451             : #ifndef HAVE_MUPARSER
   12452             :     (void)constant;
   12453             :     return ThrowIfNotMuparser();
   12454             : #else
   12455             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12456           3 :                                   *this, constant);
   12457             : #endif
   12458             : }
   12459             : 
   12460             : /************************************************************************/
   12461             : /*                             operator<=()                             */
   12462             : /************************************************************************/
   12463             : 
   12464             : /** Return a band whose value is 1 if the constant is lesser or equal to
   12465             :  * the pixel value of the right operand.
   12466             :  *
   12467             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12468             :  * dataset.
   12469             :  *
   12470             :  * @since 3.12
   12471             :  */
   12472           2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
   12473             : {
   12474             : #ifndef HAVE_MUPARSER
   12475             :     (void)constant;
   12476             :     (void)other;
   12477             :     return ThrowIfNotMuparser();
   12478             : #else
   12479             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   12480           2 :                                   constant, other);
   12481             : #endif
   12482             : }
   12483             : 
   12484             : /************************************************************************/
   12485             : /*                             operator==()                             */
   12486             : /************************************************************************/
   12487             : 
   12488             : /** Return a band whose value is 1 if the pixel value of the left operand
   12489             :  * is equal to the pixel value of the right operand.
   12490             :  *
   12491             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12492             :  * dataset.
   12493             :  *
   12494             :  * @since 3.12
   12495             :  */
   12496             : GDALComputedRasterBand
   12497           3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
   12498             : {
   12499             : #ifndef HAVE_MUPARSER
   12500             :     (void)other;
   12501             :     return ThrowIfNotMuparser();
   12502             : #else
   12503           3 :     ThrowIfNotSameDimensions(*this, other);
   12504             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12505           2 :                                   *this, other);
   12506             : #endif
   12507             : }
   12508             : 
   12509             : /************************************************************************/
   12510             : /*                             operator==()                             */
   12511             : /************************************************************************/
   12512             : 
   12513             : /** Return a band whose value is 1 if the pixel value of the left operand
   12514             :  * is equal to the constant.
   12515             :  *
   12516             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12517             :  * dataset.
   12518             :  *
   12519             :  * @since 3.12
   12520             :  */
   12521           8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
   12522             : {
   12523             : #ifndef HAVE_MUPARSER
   12524             :     (void)constant;
   12525             :     return ThrowIfNotMuparser();
   12526             : #else
   12527             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12528           8 :                                   *this, constant);
   12529             : #endif
   12530             : }
   12531             : 
   12532             : /************************************************************************/
   12533             : /*                             operator==()                             */
   12534             : /************************************************************************/
   12535             : 
   12536             : /** Return a band whose value is 1 if the constant is equal to
   12537             :  * the pixel value of the right operand.
   12538             :  *
   12539             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12540             :  * dataset.
   12541             :  *
   12542             :  * @since 3.12
   12543             :  */
   12544           2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
   12545             : {
   12546             : #ifndef HAVE_MUPARSER
   12547             :     (void)constant;
   12548             :     (void)other;
   12549             :     return ThrowIfNotMuparser();
   12550             : #else
   12551             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   12552           2 :                                   constant, other);
   12553             : #endif
   12554             : }
   12555             : 
   12556             : /************************************************************************/
   12557             : /*                             operator!=()                             */
   12558             : /************************************************************************/
   12559             : 
   12560             : /** Return a band whose value is 1 if the pixel value of the left operand
   12561             :  * is different from the pixel value of the right operand.
   12562             :  *
   12563             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12564             :  * dataset.
   12565             :  *
   12566             :  * @since 3.12
   12567             :  */
   12568             : GDALComputedRasterBand
   12569           3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
   12570             : {
   12571             : #ifndef HAVE_MUPARSER
   12572             :     (void)other;
   12573             :     return ThrowIfNotMuparser();
   12574             : #else
   12575           3 :     ThrowIfNotSameDimensions(*this, other);
   12576             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12577           2 :                                   *this, other);
   12578             : #endif
   12579             : }
   12580             : 
   12581             : /************************************************************************/
   12582             : /*                             operator!=()                             */
   12583             : /************************************************************************/
   12584             : 
   12585             : /** Return a band whose value is 1 if the pixel value of the left operand
   12586             :  * is different from the constant.
   12587             :  *
   12588             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12589             :  * dataset.
   12590             :  *
   12591             :  * @since 3.12
   12592             :  */
   12593           6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
   12594             : {
   12595             : #ifndef HAVE_MUPARSER
   12596             :     (void)constant;
   12597             :     return ThrowIfNotMuparser();
   12598             : #else
   12599             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12600           6 :                                   *this, constant);
   12601             : #endif
   12602             : }
   12603             : 
   12604             : /************************************************************************/
   12605             : /*                             operator!=()                             */
   12606             : /************************************************************************/
   12607             : 
   12608             : /** Return a band whose value is 1 if the constant is different from
   12609             :  * the pixel value of the right operand.
   12610             :  *
   12611             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12612             :  * dataset.
   12613             :  *
   12614             :  * @since 3.12
   12615             :  */
   12616           2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
   12617             : {
   12618             : #ifndef HAVE_MUPARSER
   12619             :     (void)constant;
   12620             :     (void)other;
   12621             :     return ThrowIfNotMuparser();
   12622             : #else
   12623             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12624           2 :                                   constant, other);
   12625             : #endif
   12626             : }
   12627             : 
   12628             : #if defined(__GNUC__)
   12629             : #pragma GCC diagnostic push
   12630             : #pragma GCC diagnostic ignored "-Weffc++"
   12631             : #endif
   12632             : 
   12633             : /************************************************************************/
   12634             : /*                             operator&&()                             */
   12635             : /************************************************************************/
   12636             : 
   12637             : /** Return a band whose value is 1 if the pixel value of the left and right
   12638             :  * operands is true.
   12639             :  *
   12640             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12641             :  * dataset.
   12642             :  *
   12643             :  * @since 3.12
   12644             :  */
   12645             : GDALComputedRasterBand
   12646           3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
   12647             : {
   12648             : #ifndef HAVE_MUPARSER
   12649             :     (void)other;
   12650             :     return ThrowIfNotMuparser();
   12651             : #else
   12652           3 :     ThrowIfNotSameDimensions(*this, other);
   12653             :     return GDALComputedRasterBand(
   12654           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
   12655             : #endif
   12656             : }
   12657             : 
   12658             : /************************************************************************/
   12659             : /*                             operator&&()                             */
   12660             : /************************************************************************/
   12661             : 
   12662             : /** Return a band whose value is 1 if the pixel value of the left operand
   12663             :  * is true, as well as the constant
   12664             :  *
   12665             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12666             :  * dataset.
   12667             :  *
   12668             :  * @since 3.12
   12669             :  */
   12670           2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
   12671             : {
   12672             : #ifndef HAVE_MUPARSER
   12673             :     (void)constant;
   12674             :     return ThrowIfNotMuparser();
   12675             : #else
   12676             :     return GDALComputedRasterBand(
   12677           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
   12678             : #endif
   12679             : }
   12680             : 
   12681             : /************************************************************************/
   12682             : /*                             operator&&()                             */
   12683             : /************************************************************************/
   12684             : 
   12685             : /** Return a band whose value is 1 if the constant is true, as well as
   12686             :  * the pixel value of the right operand.
   12687             :  *
   12688             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12689             :  * dataset.
   12690             :  *
   12691             :  * @since 3.12
   12692             :  */
   12693           2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
   12694             : {
   12695             : #ifndef HAVE_MUPARSER
   12696             :     (void)constant;
   12697             :     (void)other;
   12698             :     return ThrowIfNotMuparser();
   12699             : #else
   12700             :     return GDALComputedRasterBand(
   12701           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
   12702             : #endif
   12703             : }
   12704             : 
   12705             : /************************************************************************/
   12706             : /*                             operator||()                             */
   12707             : /************************************************************************/
   12708             : 
   12709             : /** Return a band whose value is 1 if the pixel value of the left or right
   12710             :  * operands is true.
   12711             :  *
   12712             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12713             :  * dataset.
   12714             :  *
   12715             :  * @since 3.12
   12716             :  */
   12717             : GDALComputedRasterBand
   12718           4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
   12719             : {
   12720             : #ifndef HAVE_MUPARSER
   12721             :     (void)other;
   12722             :     return ThrowIfNotMuparser();
   12723             : #else
   12724           4 :     ThrowIfNotSameDimensions(*this, other);
   12725             :     return GDALComputedRasterBand(
   12726           3 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
   12727             : #endif
   12728             : }
   12729             : 
   12730             : /************************************************************************/
   12731             : /*                             operator||()                             */
   12732             : /************************************************************************/
   12733             : 
   12734             : /** Return a band whose value is 1 if the pixel value of the left operand
   12735             :  * is true, or if the constant is true
   12736             :  *
   12737             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12738             :  * dataset.
   12739             :  *
   12740             :  * @since 3.12
   12741             :  */
   12742           4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
   12743             : {
   12744             : #ifndef HAVE_MUPARSER
   12745             :     (void)constant;
   12746             :     return ThrowIfNotMuparser();
   12747             : #else
   12748             :     return GDALComputedRasterBand(
   12749           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
   12750             : #endif
   12751             : }
   12752             : 
   12753             : /************************************************************************/
   12754             : /*                             operator||()                             */
   12755             : /************************************************************************/
   12756             : 
   12757             : /** Return a band whose value is 1 if the constant is true, or
   12758             :  * the pixel value of the right operand is true
   12759             :  *
   12760             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12761             :  * dataset.
   12762             :  *
   12763             :  * @since 3.12
   12764             :  */
   12765           4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
   12766             : {
   12767             : #ifndef HAVE_MUPARSER
   12768             :     (void)constant;
   12769             :     (void)other;
   12770             :     return ThrowIfNotMuparser();
   12771             : #else
   12772             :     return GDALComputedRasterBand(
   12773           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
   12774             : #endif
   12775             : }
   12776             : 
   12777             : #if defined(__GNUC__)
   12778             : #pragma GCC diagnostic pop
   12779             : #endif
   12780             : 
   12781             : /************************************************************************/
   12782             : /*                             operator!()                              */
   12783             : /************************************************************************/
   12784             : 
   12785             : /** Return a band whose value is the logical negation of the pixel value
   12786             :  *
   12787             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12788             :  * dataset.
   12789             :  *
   12790             :  * @since 3.12
   12791             :  */
   12792           2 : GDALComputedRasterBand GDALRasterBand::operator!() const
   12793             : {
   12794             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   12795           2 :                                   *this, true);
   12796             : }
   12797             : 
   12798             : namespace gdal
   12799             : {
   12800             : 
   12801             : /************************************************************************/
   12802             : /*                             IfThenElse()                             */
   12803             : /************************************************************************/
   12804             : 
   12805             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12806             :  * is not zero, or the one from elseBand otherwise.
   12807             :  *
   12808             :  * Variants of this method exits where thenBand and/or elseBand can be double
   12809             :  * values.
   12810             :  *
   12811             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12812             :  * datasets.
   12813             :  *
   12814             :  * This method is the same as the C function GDALRasterBandIfThenElse()
   12815             :  *
   12816             :  * @since 3.12
   12817             :  */
   12818           5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12819             :                                   const GDALRasterBand &thenBand,
   12820             :                                   const GDALRasterBand &elseBand)
   12821             : {
   12822             : #ifndef HAVE_MUPARSER
   12823             :     (void)condBand;
   12824             :     (void)thenBand;
   12825             :     (void)elseBand;
   12826             :     return ThrowIfNotMuparser();
   12827             : #else
   12828           5 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12829           4 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12830             :     return GDALComputedRasterBand(
   12831             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12832           6 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12833             : #endif
   12834             : }
   12835             : 
   12836             : //! @cond Doxygen_Suppress
   12837             : 
   12838             : /************************************************************************/
   12839             : /*                             IfThenElse()                             */
   12840             : /************************************************************************/
   12841             : 
   12842             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12843             :  * is not zero, or the one from elseBand otherwise.
   12844             :  *
   12845             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12846             :  * datasets.
   12847             :  *
   12848             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12849             :  * with thenBand = (condBand * 0) + thenValue
   12850             :  *
   12851             :  * @since 3.12
   12852             :  */
   12853           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12854             :                                   double thenValue,
   12855             :                                   const GDALRasterBand &elseBand)
   12856             : {
   12857             : #ifndef HAVE_MUPARSER
   12858             :     (void)condBand;
   12859             :     (void)thenValue;
   12860             :     (void)elseBand;
   12861             :     return ThrowIfNotMuparser();
   12862             : #else
   12863           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12864             :     auto thenBand =
   12865           1 :         (condBand * 0)
   12866           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12867           1 :         thenValue;
   12868             :     return GDALComputedRasterBand(
   12869             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12870           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12871             : #endif
   12872             : }
   12873             : 
   12874             : /************************************************************************/
   12875             : /*                             IfThenElse()                             */
   12876             : /************************************************************************/
   12877             : 
   12878             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   12879             :  * is not zero, or the one from elseValue otherwise.
   12880             :  *
   12881             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12882             :  * datasets.
   12883             :  *
   12884             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12885             :  * with elseBand = (condBand * 0) + elseValue
   12886             : 
   12887             :  * @since 3.12
   12888             :  */
   12889           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12890             :                                   const GDALRasterBand &thenBand,
   12891             :                                   double elseValue)
   12892             : {
   12893             : #ifndef HAVE_MUPARSER
   12894             :     (void)condBand;
   12895             :     (void)thenBand;
   12896             :     (void)elseValue;
   12897             :     return ThrowIfNotMuparser();
   12898             : #else
   12899           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12900             :     auto elseBand =
   12901           1 :         (condBand * 0)
   12902           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12903           1 :         elseValue;
   12904             :     return GDALComputedRasterBand(
   12905             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12906           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12907             : #endif
   12908             : }
   12909             : 
   12910             : /************************************************************************/
   12911             : /*                             IfThenElse()                             */
   12912             : /************************************************************************/
   12913             : 
   12914             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   12915             :  * is not zero, or the one from elseValue otherwise.
   12916             :  *
   12917             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12918             :  * datasets.
   12919             :  *
   12920             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   12921             :  * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
   12922             :  *
   12923             :  * @since 3.12
   12924             :  */
   12925           3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   12926             :                                   double thenValue, double elseValue)
   12927             : {
   12928             : #ifndef HAVE_MUPARSER
   12929             :     (void)condBand;
   12930             :     (void)thenValue;
   12931             :     (void)elseValue;
   12932             :     return ThrowIfNotMuparser();
   12933             : #else
   12934             :     auto thenBand =
   12935           3 :         (condBand * 0)
   12936           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   12937           6 :         thenValue;
   12938             :     auto elseBand =
   12939           3 :         (condBand * 0)
   12940           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   12941           3 :         elseValue;
   12942             :     return GDALComputedRasterBand(
   12943             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12944           9 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12945             : #endif
   12946             : }
   12947             : 
   12948             : //! @endcond
   12949             : 
   12950             : }  // namespace gdal
   12951             : 
   12952             : /************************************************************************/
   12953             : /*                      GDALRasterBandIfThenElse()                      */
   12954             : /************************************************************************/
   12955             : 
   12956             : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
   12957             :  * is not zero, or the one from hElseBand otherwise.
   12958             :  *
   12959             :  * The resulting band is lazy evaluated. A reference is taken on the input
   12960             :  * datasets.
   12961             :  *
   12962             :  * This function is the same as the C++ method gdal::IfThenElse()
   12963             :  *
   12964             :  * @since 3.12
   12965             :  */
   12966          12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
   12967             :                                                  GDALRasterBandH hThenBand,
   12968             :                                                  GDALRasterBandH hElseBand)
   12969             : {
   12970          12 :     VALIDATE_POINTER1(hCondBand, __func__, nullptr);
   12971          12 :     VALIDATE_POINTER1(hThenBand, __func__, nullptr);
   12972          12 :     VALIDATE_POINTER1(hElseBand, __func__, nullptr);
   12973             : #ifndef HAVE_MUPARSER
   12974             :     CPLError(CE_Failure, CPLE_NotSupported,
   12975             :              "Band comparison operators not available on a GDAL build without "
   12976             :              "muparser");
   12977             :     return nullptr;
   12978             : #else
   12979             : 
   12980          12 :     auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
   12981          12 :     auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
   12982          12 :     auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
   12983             :     try
   12984             :     {
   12985          12 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   12986          11 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   12987             :     }
   12988           2 :     catch (const std::exception &e)
   12989             :     {
   12990           2 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   12991           2 :         return nullptr;
   12992             :     }
   12993             :     return new GDALComputedRasterBand(
   12994             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   12995          10 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   12996             : #endif
   12997             : }
   12998             : 
   12999             : /************************************************************************/
   13000             : /*                       GDALRasterBand::AsType()                       */
   13001             : /************************************************************************/
   13002             : 
   13003             : /** Cast this band to another type.
   13004             :  *
   13005             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13006             :  * dataset.
   13007             :  *
   13008             :  * This method is the same as the C function GDALRasterBandAsDataType()
   13009             :  *
   13010             :  * @since 3.12
   13011             :  */
   13012          10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
   13013             : {
   13014          10 :     if (dt == GDT_Unknown)
   13015             :     {
   13016           1 :         throw std::runtime_error("AsType(GDT_Unknown) is not supported");
   13017             :     }
   13018             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
   13019           9 :                                   *this, dt);
   13020             : }
   13021             : 
   13022             : /************************************************************************/
   13023             : /*                      GDALRasterBandAsDataType()                      */
   13024             : /************************************************************************/
   13025             : 
   13026             : /** Cast this band to another type.
   13027             :  *
   13028             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13029             :  * dataset.
   13030             :  *
   13031             :  * This function is the same as the C++ method GDALRasterBand::AsType()
   13032             :  *
   13033             :  * @since 3.12
   13034             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13035             :  */
   13036          16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
   13037             :                                                  GDALDataType eDT)
   13038             : {
   13039          16 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   13040          16 :     if (eDT == GDT_Unknown)
   13041             :     {
   13042           1 :         CPLError(CE_Failure, CPLE_NotSupported,
   13043             :                  "GDALRasterBandAsDataType(GDT_Unknown) not supported");
   13044           1 :         return nullptr;
   13045             :     }
   13046             :     return new GDALComputedRasterBand(
   13047             :         GDALComputedRasterBand::Operation::OP_CAST,
   13048          15 :         *(GDALRasterBand::FromHandle(hBand)), eDT);
   13049             : }
   13050             : 
   13051             : /************************************************************************/
   13052             : /*                           GetBandVector()                            */
   13053             : /************************************************************************/
   13054             : 
   13055             : static std::vector<const GDALRasterBand *>
   13056          10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
   13057             : {
   13058          10 :     std::vector<const GDALRasterBand *> bands;
   13059          27 :     for (size_t i = 0; i < nBandCount; ++i)
   13060             :     {
   13061          20 :         if (i > 0)
   13062             :         {
   13063          10 :             GDALRasterBand::ThrowIfNotSameDimensions(
   13064          10 :                 *(GDALRasterBand::FromHandle(pahBands[0])),
   13065          10 :                 *(GDALRasterBand::FromHandle(pahBands[i])));
   13066             :         }
   13067          17 :         bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
   13068             :     }
   13069           7 :     return bands;
   13070             : }
   13071             : 
   13072             : /************************************************************************/
   13073             : /*                       GDALOperationOnNBands()                        */
   13074             : /************************************************************************/
   13075             : 
   13076             : static GDALComputedRasterBandH
   13077          11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
   13078             :                       GDALRasterBandH *pahBands)
   13079             : {
   13080          11 :     VALIDATE_POINTER1(pahBands, __func__, nullptr);
   13081          11 :     if (nBandCount == 0)
   13082             :     {
   13083           1 :         CPLError(CE_Failure, CPLE_AppDefined,
   13084             :                  "At least one band should be passed");
   13085           1 :         return nullptr;
   13086             :     }
   13087             : 
   13088          20 :     std::vector<const GDALRasterBand *> bands;
   13089             :     try
   13090             :     {
   13091          10 :         bands = GetBandVector(nBandCount, pahBands);
   13092             :     }
   13093           3 :     catch (const std::exception &e)
   13094             :     {
   13095           3 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   13096           3 :         return nullptr;
   13097             :     }
   13098           7 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
   13099             : }
   13100             : 
   13101             : /************************************************************************/
   13102             : /*                        GDALMaximumOfNBands()                         */
   13103             : /************************************************************************/
   13104             : 
   13105             : /** Return a band whose each pixel value is the maximum of the corresponding
   13106             :  * pixel values in the input bands.
   13107             :  *
   13108             :  * The resulting band is lazy evaluated. A reference is taken on input
   13109             :  * datasets.
   13110             :  *
   13111             :  * This function is the same as the C ++ method gdal::max()
   13112             :  *
   13113             :  * @since 3.12
   13114             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13115             :  */
   13116           4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
   13117             :                                             GDALRasterBandH *pahBands)
   13118             : {
   13119           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
   13120           4 :                                  nBandCount, pahBands);
   13121             : }
   13122             : 
   13123             : /************************************************************************/
   13124             : /*                             gdal::max()                              */
   13125             : /************************************************************************/
   13126             : 
   13127             : namespace gdal
   13128             : {
   13129             : /** Return a band whose each pixel value is the maximum of the corresponding
   13130             :  * pixel values in the inputs (bands or constants)
   13131             :  *
   13132             :  * The resulting band is lazy evaluated. A reference is taken on input
   13133             :  * datasets.
   13134             :  *
   13135             :  * Two or more bands can be passed.
   13136             :  *
   13137             :  * This method is the same as the C function GDALMaximumOfNBands()
   13138             :  *
   13139             :  * @since 3.12
   13140             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13141             :  */
   13142           1 : GDALComputedRasterBand max(const GDALRasterBand &first,
   13143             :                            const GDALRasterBand &second)
   13144             : {
   13145           1 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13146             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
   13147           1 :                                   first, second);
   13148             : }
   13149             : }  // namespace gdal
   13150             : 
   13151             : /************************************************************************/
   13152             : /*                     GDALRasterBandMaxConstant()                      */
   13153             : /************************************************************************/
   13154             : 
   13155             : /** Return a band whose each pixel value is the maximum of the corresponding
   13156             :  * pixel values in the input band and the constant.
   13157             :  *
   13158             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13159             :  * dataset.
   13160             :  *
   13161             :  * This function is the same as the C ++ method gdal::max()
   13162             :  *
   13163             :  * @since 3.12
   13164             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13165             :  */
   13166           2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
   13167             :                                                   double dfConstant)
   13168             : {
   13169           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   13170             :         GDALComputedRasterBand::Operation::OP_MAX,
   13171           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   13172           6 :         dfConstant));
   13173             : }
   13174             : 
   13175             : /************************************************************************/
   13176             : /*                        GDALMinimumOfNBands()                         */
   13177             : /************************************************************************/
   13178             : 
   13179             : /** Return a band whose each pixel value is the minimum of the corresponding
   13180             :  * pixel values in the input bands.
   13181             :  *
   13182             :  * The resulting band is lazy evaluated. A reference is taken on input
   13183             :  * datasets.
   13184             :  *
   13185             :  * This function is the same as the C ++ method gdal::min()
   13186             :  *
   13187             :  * @since 3.12
   13188             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13189             :  */
   13190           4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
   13191             :                                             GDALRasterBandH *pahBands)
   13192             : {
   13193           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
   13194           4 :                                  nBandCount, pahBands);
   13195             : }
   13196             : 
   13197             : /************************************************************************/
   13198             : /*                             gdal::min()                              */
   13199             : /************************************************************************/
   13200             : 
   13201             : namespace gdal
   13202             : {
   13203             : /** Return a band whose each pixel value is the minimum of the corresponding
   13204             :  * pixel values in the inputs (bands or constants)
   13205             :  *
   13206             :  * The resulting band is lazy evaluated. A reference is taken on input
   13207             :  * datasets.
   13208             :  *
   13209             :  * Two or more bands can be passed.
   13210             :  *
   13211             :  * This method is the same as the C function GDALMinimumOfNBands()
   13212             :  *
   13213             :  * @since 3.12
   13214             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13215             :  */
   13216           0 : GDALComputedRasterBand min(const GDALRasterBand &first,
   13217             :                            const GDALRasterBand &second)
   13218             : {
   13219           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13220             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
   13221           0 :                                   first, second);
   13222             : }
   13223             : }  // namespace gdal
   13224             : 
   13225             : /************************************************************************/
   13226             : /*                     GDALRasterBandMinConstant()                      */
   13227             : /************************************************************************/
   13228             : 
   13229             : /** Return a band whose each pixel value is the minimum of the corresponding
   13230             :  * pixel values in the input band and the constant.
   13231             :  *
   13232             :  * The resulting band is lazy evaluated. A reference is taken on the input
   13233             :  * dataset.
   13234             :  *
   13235             :  * This function is the same as the C ++ method gdal::min()
   13236             :  *
   13237             :  * @since 3.12
   13238             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13239             :  */
   13240           2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
   13241             :                                                   double dfConstant)
   13242             : {
   13243           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   13244             :         GDALComputedRasterBand::Operation::OP_MIN,
   13245           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   13246           6 :         dfConstant));
   13247             : }
   13248             : 
   13249             : /************************************************************************/
   13250             : /*                          GDALMeanOfNBands()                          */
   13251             : /************************************************************************/
   13252             : 
   13253             : /** Return a band whose each pixel value is the arithmetic mean of the
   13254             :  * corresponding pixel values in the input bands.
   13255             :  *
   13256             :  * The resulting band is lazy evaluated. A reference is taken on input
   13257             :  * datasets.
   13258             :  *
   13259             :  * This function is the same as the C ++ method gdal::mean()
   13260             :  *
   13261             :  * @since 3.12
   13262             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   13263             :  */
   13264           3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
   13265             :                                          GDALRasterBandH *pahBands)
   13266             : {
   13267           3 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
   13268           3 :                                  nBandCount, pahBands);
   13269             : }
   13270             : 
   13271             : /************************************************************************/
   13272             : /*                             gdal::mean()                             */
   13273             : /************************************************************************/
   13274             : 
   13275             : namespace gdal
   13276             : {
   13277             : 
   13278             : /** Return a band whose each pixel value is the arithmetic mean of the
   13279             :  * corresponding pixel values in the input bands.
   13280             :  *
   13281             :  * The resulting band is lazy evaluated. A reference is taken on input
   13282             :  * datasets.
   13283             :  *
   13284             :  * Two or more bands can be passed.
   13285             :  *
   13286             :  * This method is the same as the C function GDALMeanOfNBands()
   13287             :  *
   13288             :  * @since 3.12
   13289             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13290             :  */
   13291           0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
   13292             :                             const GDALRasterBand &second)
   13293             : {
   13294           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   13295             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
   13296           0 :                                   first, second);
   13297             : }
   13298             : }  // namespace gdal
   13299             : 
   13300             : /************************************************************************/
   13301             : /*                             gdal::abs()                              */
   13302             : /************************************************************************/
   13303             : 
   13304             : namespace gdal
   13305             : {
   13306             : 
   13307             : /** Return a band whose each pixel value is the absolute value (or module
   13308             :  * for complex data type) of the corresponding pixel value in the input band.
   13309             :  *
   13310             :  * The resulting band is lazy evaluated. A reference is taken on input
   13311             :  * datasets.
   13312             :  *
   13313             :  * @since 3.12
   13314             :  */
   13315           1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
   13316             : {
   13317             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   13318           1 :                                   band);
   13319             : }
   13320             : }  // namespace gdal
   13321             : 
   13322             : /************************************************************************/
   13323             : /*                             gdal::fabs()                             */
   13324             : /************************************************************************/
   13325             : 
   13326             : namespace gdal
   13327             : {
   13328             : 
   13329             : /** Return a band whose each pixel value is the absolute value (or module
   13330             :  * for complex data type) of the corresponding pixel value in the input band.
   13331             :  *
   13332             :  * The resulting band is lazy evaluated. A reference is taken on input
   13333             :  * datasets.
   13334             :  *
   13335             :  * @since 3.12
   13336             :  */
   13337           1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
   13338             : {
   13339             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   13340           1 :                                   band);
   13341             : }
   13342             : }  // namespace gdal
   13343             : 
   13344             : /************************************************************************/
   13345             : /*                             gdal::sqrt()                             */
   13346             : /************************************************************************/
   13347             : 
   13348             : namespace gdal
   13349             : {
   13350             : 
   13351             : /** Return a band whose each pixel value is the square root of the
   13352             :  * corresponding pixel value in the input band.
   13353             :  *
   13354             :  * The resulting band is lazy evaluated. A reference is taken on input
   13355             :  * datasets.
   13356             :  *
   13357             :  * @since 3.12
   13358             :  */
   13359           1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
   13360             : {
   13361             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
   13362           1 :                                   band);
   13363             : }
   13364             : }  // namespace gdal
   13365             : 
   13366             : /************************************************************************/
   13367             : /*                             gdal::log()                              */
   13368             : /************************************************************************/
   13369             : 
   13370             : namespace gdal
   13371             : {
   13372             : 
   13373             : /** Return a band whose each pixel value is the natural logarithm of the
   13374             :  * corresponding pixel value in the input band.
   13375             :  *
   13376             :  * The resulting band is lazy evaluated. A reference is taken on input
   13377             :  * datasets.
   13378             :  *
   13379             :  * @since 3.12
   13380             :  */
   13381           1 : GDALComputedRasterBand log(const GDALRasterBand &band)
   13382             : {
   13383             : #ifndef HAVE_MUPARSER
   13384             :     (void)band;
   13385             :     return ThrowIfNotMuparser();
   13386             : #else
   13387             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
   13388           1 :                                   band);
   13389             : #endif
   13390             : }
   13391             : }  // namespace gdal
   13392             : 
   13393             : /************************************************************************/
   13394             : /*                            gdal::log10()                             */
   13395             : /************************************************************************/
   13396             : 
   13397             : namespace gdal
   13398             : {
   13399             : 
   13400             : /** Return a band whose each pixel value is the logarithm base 10 of the
   13401             :  * corresponding pixel value in the input band.
   13402             :  *
   13403             :  * The resulting band is lazy evaluated. A reference is taken on input
   13404             :  * datasets.
   13405             :  *
   13406             :  * @since 3.12
   13407             :  */
   13408           1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
   13409             : {
   13410             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
   13411           1 :                                   band);
   13412             : }
   13413             : }  // namespace gdal
   13414             : 
   13415             : /************************************************************************/
   13416             : /*                             gdal::pow()                              */
   13417             : /************************************************************************/
   13418             : 
   13419             : namespace gdal
   13420             : {
   13421             : 
   13422             : #ifndef DOXYGEN_SKIP
   13423             : /** Return a band whose each pixel value is the constant raised to the power of
   13424             :  * the corresponding pixel value in the input band.
   13425             :  *
   13426             :  * The resulting band is lazy evaluated. A reference is taken on input
   13427             :  * datasets.
   13428             :  *
   13429             :  * @since 3.12
   13430             :  */
   13431           1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
   13432             : {
   13433             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13434           1 :                                   constant, band);
   13435             : }
   13436             : #endif
   13437             : 
   13438             : }  // namespace gdal
   13439             : 
   13440             : /************************************************************************/
   13441             : /*                             gdal::pow()                              */
   13442             : /************************************************************************/
   13443             : 
   13444             : namespace gdal
   13445             : {
   13446             : 
   13447             : /** Return a band whose each pixel value is the the corresponding pixel value
   13448             :  * in the input band raised to the power of the constant.
   13449             :  *
   13450             :  * The resulting band is lazy evaluated. A reference is taken on input
   13451             :  * datasets.
   13452             :  *
   13453             :  * @since 3.12
   13454             :  */
   13455           1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
   13456             : {
   13457             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13458           1 :                                   band, constant);
   13459             : }
   13460             : }  // namespace gdal
   13461             : 
   13462             : /************************************************************************/
   13463             : /*                             gdal::pow()                              */
   13464             : /************************************************************************/
   13465             : 
   13466             : namespace gdal
   13467             : {
   13468             : 
   13469             : #ifndef DOXYGEN_SKIP
   13470             : /** Return a band whose each pixel value is the the corresponding pixel value
   13471             :  * in the input band1 raised to the power of the corresponding pixel value
   13472             :  * in the input band2
   13473             :  *
   13474             :  * The resulting band is lazy evaluated. A reference is taken on input
   13475             :  * datasets.
   13476             :  *
   13477             :  * @since 3.12
   13478             :  * @throw std::runtime_error if bands do not have the same dimensions.
   13479             :  */
   13480           2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
   13481             :                            const GDALRasterBand &band2)
   13482             : {
   13483             : #ifndef HAVE_MUPARSER
   13484             :     (void)band1;
   13485             :     (void)band2;
   13486             :     return ThrowIfNotMuparser();
   13487             : #else
   13488           2 :     GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
   13489             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   13490           1 :                                   band1, band2);
   13491             : #endif
   13492             : }
   13493             : #endif
   13494             : }  // namespace gdal

Generated by: LCOV version 1.14