LCOV - code coverage report
Current view: top level - gcore - gdalrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2838 3520 80.6 %
Date: 2025-08-19 18:03:11 Functions: 300 329 91.2 %

          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             : #include "gdal_priv.h"
      18             : 
      19             : #include <climits>
      20             : #include <cmath>
      21             : #include <cstdarg>
      22             : #include <cstddef>
      23             : #include <cstdio>
      24             : #include <cstdlib>
      25             : #include <cstring>
      26             : #include <algorithm>
      27             : #include <limits>
      28             : #include <memory>
      29             : #include <new>
      30             : #include <type_traits>
      31             : 
      32             : #include "cpl_conv.h"
      33             : #include "cpl_error.h"
      34             : #include "cpl_float.h"
      35             : #include "cpl_progress.h"
      36             : #include "cpl_string.h"
      37             : #include "cpl_virtualmem.h"
      38             : #include "cpl_vsi.h"
      39             : #include "gdal.h"
      40             : #include "gdal_rat.h"
      41             : #include "gdal_priv_templates.hpp"
      42             : #include "gdal_interpolateatpoint.h"
      43             : #include "gdal_minmax_element.hpp"
      44             : 
      45             : /************************************************************************/
      46             : /*                           GDALRasterBand()                           */
      47             : /************************************************************************/
      48             : 
      49             : /*! Constructor. Applications should never create GDALRasterBands directly. */
      50             : 
      51     1640300 : GDALRasterBand::GDALRasterBand()
      52             :     : GDALRasterBand(
      53     1640300 :           CPLTestBool(CPLGetConfigOption("GDAL_FORCE_CACHING", "NO")))
      54             : {
      55     1640150 : }
      56             : 
      57             : /** Constructor. Applications should never create GDALRasterBands directly.
      58             :  * @param bForceCachedIOIn Whether cached IO should be forced.
      59             :  */
      60     1911390 : GDALRasterBand::GDALRasterBand(int bForceCachedIOIn)
      61     1911390 :     : bForceCachedIO(bForceCachedIOIn)
      62             : 
      63             : {
      64     1911250 : }
      65             : 
      66             : /************************************************************************/
      67             : /*                          ~GDALRasterBand()                           */
      68             : /************************************************************************/
      69             : 
      70             : /*! Destructor. Applications should never destroy GDALRasterBands directly,
      71             :     instead destroy the GDALDataset. */
      72             : 
      73     1911390 : GDALRasterBand::~GDALRasterBand()
      74             : 
      75             : {
      76     1911390 :     if (poDS && poDS->IsMarkedSuppressOnClose())
      77             :     {
      78         530 :         if (poBandBlockCache)
      79         461 :             poBandBlockCache->DisableDirtyBlockWriting();
      80             :     }
      81     1911390 :     GDALRasterBand::FlushCache(true);
      82             : 
      83     1911390 :     delete poBandBlockCache;
      84             : 
      85     1911390 :     if (static_cast<GIntBig>(nBlockReads) >
      86     1911390 :             static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn &&
      87         219 :         nBand == 1 && poDS != nullptr)
      88             :     {
      89         318 :         CPLDebug(
      90             :             "GDAL", "%d block reads on " CPL_FRMT_GIB " block band 1 of %s.",
      91         159 :             nBlockReads, static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn,
      92         159 :             poDS->GetDescription());
      93             :     }
      94             : 
      95     1911390 :     InvalidateMaskBand();
      96     1911390 :     nBand = -nBand;
      97             : 
      98     1911390 :     delete m_poPointsCache;
      99     1911390 : }
     100             : 
     101             : /************************************************************************/
     102             : /*                              RasterIO()                              */
     103             : /************************************************************************/
     104             : 
     105             : /**
     106             :  * \fn GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
     107             :  *                                int nXOff, int nYOff, int nXSize, int nYSize,
     108             :  *                                void * pData, int nBufXSize, int nBufYSize,
     109             :  *                                GDALDataType eBufType,
     110             :  *                                GSpacing nPixelSpace,
     111             :  *                                GSpacing nLineSpace,
     112             :  *                                GDALRasterIOExtraArg* psExtraArg )
     113             :  * \brief Read/write a region of image data for this band.
     114             :  *
     115             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     116             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     117             :  * automatically takes care of data type translation if the data type
     118             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     119             :  * The method also takes care of image decimation / replication if the
     120             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     121             :  * region being accessed (nXSize x nYSize).
     122             :  *
     123             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     124             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     125             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     126             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     127             :  * Or use nLineSpace and a possibly shifted pData value.
     128             :  *
     129             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     130             :  * writing from unusually organized buffers. This is primarily used
     131             :  * for buffers containing more than one bands raster data in interleaved
     132             :  * format.
     133             :  *
     134             :  * Some formats may efficiently implement decimation into a buffer by
     135             :  * reading from lower resolution overview images. The logic of the default
     136             :  * implementation in the base class GDALRasterBand is the following one. It
     137             :  * computes a target_downscaling_factor from the window of interest and buffer
     138             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     139             :  * It then walks through overviews and will select the first one whose
     140             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     141             :  *
     142             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     143             :  * The relationship between target_downscaling_factor and the select overview
     144             :  * level is the following one:
     145             :  *
     146             :  * target_downscaling_factor  | selected_overview
     147             :  * -------------------------  | -----------------
     148             :  * ]0,       2 / 1.2]         | full resolution band
     149             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     150             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     151             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     152             :  *
     153             :  * Note that starting with GDAL 3.9, this 1.2 oversampling factor can be
     154             :  * modified by setting the GDAL_OVERVIEW_OVERSAMPLING_THRESHOLD configuration
     155             :  * option. Also note that starting with GDAL 3.9, when the resampling algorithm
     156             :  * specified in psExtraArg->eResampleAlg is different from GRIORA_NearestNeighbour,
     157             :  * this oversampling threshold defaults to 1. Consequently if there are overviews
     158             :  * of downscaling factor 2, 4 and 8, and the desired downscaling factor is
     159             :  * 7.99, the overview of factor 4 will be selected for a non nearest resampling.
     160             :  *
     161             :  * For highest performance full resolution data access, read and write
     162             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     163             :  * ReadBlock() and WriteBlock() methods.
     164             :  *
     165             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     166             :  * functions.
     167             :  *
     168             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     169             :  * write a region of data.
     170             :  *
     171             :  * @param nXOff The pixel offset to the top left corner of the region
     172             :  * of the band to be accessed. This would be zero to start from the left side.
     173             :  *
     174             :  * @param nYOff The line offset to the top left corner of the region
     175             :  * of the band to be accessed. This would be zero to start from the top.
     176             :  *
     177             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     178             :  *
     179             :  * @param nYSize The height of the region of the band to be accessed in lines.
     180             :  *
     181             :  * @param pData The buffer into which the data should be read, or from which
     182             :  * it should be written. This buffer must contain at least nBufXSize *
     183             :  * nBufYSize words of type eBufType. It is organized in left to right,
     184             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     185             :  * and nLineSpace parameters.
     186             :  * Note that even with eRWFlag==GF_Write, the content of the buffer might be
     187             :  * temporarily modified during the execution of this method (and eventually
     188             :  * restored back to its original content), so it is not safe to use a buffer
     189             :  * stored in a read-only section of the calling program.
     190             :  *
     191             :  * @param nBufXSize the width of the buffer image into which the desired region
     192             :  * is to be read, or from which it is to be written.
     193             :  *
     194             :  * @param nBufYSize the height of the buffer image into which the desired region
     195             :  * is to be read, or from which it is to be written.
     196             :  *
     197             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     198             :  * pixel values will automatically be translated to/from the GDALRasterBand
     199             :  * data type as needed. Most driver implementations will use GDALCopyWords64()
     200             :  * to perform data type translation.
     201             :  *
     202             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     203             :  * pData to the start of the next pixel value within a scanline. If defaulted
     204             :  * (0) the size of the datatype eBufType is used.
     205             :  *
     206             :  * @param nLineSpace The byte offset from the start of one scanline in
     207             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     208             :  * eBufType * nBufXSize is used.
     209             :  *
     210             :  * @param psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     211             :  * structure with additional arguments to specify resampling and progress
     212             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     213             :  * configuration option can also be defined to override the default resampling
     214             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     215             :  *
     216             :  * @return CE_Failure if the access fails, otherwise CE_None.
     217             :  */
     218             : 
     219             : /**
     220             :  * \brief Read/write a region of image data for this band.
     221             :  *
     222             :  * This method allows reading a region of a GDALRasterBand into a buffer,
     223             :  * or writing data from a buffer into a region of a GDALRasterBand. It
     224             :  * automatically takes care of data type translation if the data type
     225             :  * (eBufType) of the buffer is different than that of the GDALRasterBand.
     226             :  * The method also takes care of image decimation / replication if the
     227             :  * buffer size (nBufXSize x nBufYSize) is different than the size of the
     228             :  * region being accessed (nXSize x nYSize).
     229             :  *
     230             :  * The window of interest expressed by (nXOff, nYOff, nXSize, nYSize) should be
     231             :  * fully within the raster space, that is nXOff >= 0, nYOff >= 0,
     232             :  * nXOff + nXSize <= GetXSize() and nYOff + nYSize <= GetYSize().
     233             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     234             :  * Or use nLineSpace and a possibly shifted pData value.
     235             :  *
     236             :  * The nPixelSpace and nLineSpace parameters allow reading into or
     237             :  * writing from unusually organized buffers. This is primarily used
     238             :  * for buffers containing more than one bands raster data in interleaved
     239             :  * format.
     240             :  *
     241             :  * Some formats may efficiently implement decimation into a buffer by
     242             :  * reading from lower resolution overview images. The logic of the default
     243             :  * implementation in the base class GDALRasterBand is the following one. It
     244             :  * computes a target_downscaling_factor from the window of interest and buffer
     245             :  * size which is min(nXSize/nBufXSize, nYSize/nBufYSize).
     246             :  * It then walks through overviews and will select the first one whose
     247             :  * downscaling factor is greater than target_downscaling_factor / 1.2.
     248             :  *
     249             :  * Let's assume we have overviews at downscaling factors 2, 4 and 8.
     250             :  * The relationship between target_downscaling_factor and the select overview
     251             :  * level is the following one:
     252             :  *
     253             :  * target_downscaling_factor  | selected_overview
     254             :  * -------------------------  | -----------------
     255             :  * ]0,       2 / 1.2]         | full resolution band
     256             :  * ]2 / 1.2, 4 / 1.2]         | 2x downsampled band
     257             :  * ]4 / 1.2, 8 / 1.2]         | 4x downsampled band
     258             :  * ]8 / 1.2, infinity[        | 8x downsampled band
     259             :  *
     260             :  * For highest performance full resolution data access, read and write
     261             :  * on "block boundaries" as returned by GetBlockSize(), or use the
     262             :  * ReadBlock() and WriteBlock() methods.
     263             :  *
     264             :  * This method is the same as the C GDALRasterIO() or GDALRasterIOEx()
     265             :  * functions.
     266             :  *
     267             :  * Starting with GDAL 3.10, the GDALRasterBand::ReadRaster() methods may be
     268             :  * more convenient to use for most common use cases.
     269             :  *
     270             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     271             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     272             :  * instance of this dataset) concurrently from several threads.
     273             :  *
     274             :  * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to
     275             :  * write a region of data.
     276             :  *
     277             :  * @param nXOff The pixel offset to the top left corner of the region
     278             :  * of the band to be accessed. This would be zero to start from the left side.
     279             :  *
     280             :  * @param nYOff The line offset to the top left corner of the region
     281             :  * of the band to be accessed. This would be zero to start from the top.
     282             :  *
     283             :  * @param nXSize The width of the region of the band to be accessed in pixels.
     284             :  *
     285             :  * @param nYSize The height of the region of the band to be accessed in lines.
     286             :  *
     287             :  * @param[in,out] pData The buffer into which the data should be read, or from
     288             :  * which it should be written. This buffer must contain at least nBufXSize *
     289             :  * nBufYSize words of type eBufType. It is organized in left to right,
     290             :  * top to bottom pixel order. Spacing is controlled by the nPixelSpace,
     291             :  * and nLineSpace parameters.
     292             :  *
     293             :  * @param nBufXSize the width of the buffer image into which the desired region
     294             :  * is to be read, or from which it is to be written.
     295             :  *
     296             :  * @param nBufYSize the height of the buffer image into which the desired region
     297             :  * is to be read, or from which it is to be written.
     298             :  *
     299             :  * @param eBufType the type of the pixel values in the pData data buffer. The
     300             :  * pixel values will automatically be translated to/from the GDALRasterBand
     301             :  * data type as needed.
     302             :  *
     303             :  * @param nPixelSpace The byte offset from the start of one pixel value in
     304             :  * pData to the start of the next pixel value within a scanline. If defaulted
     305             :  * (0) the size of the datatype eBufType is used.
     306             :  *
     307             :  * @param nLineSpace The byte offset from the start of one scanline in
     308             :  * pData to the start of the next. If defaulted (0) the size of the datatype
     309             :  * eBufType * nBufXSize is used.
     310             :  *
     311             :  * @param[in] psExtraArg (new in GDAL 2.0) pointer to a GDALRasterIOExtraArg
     312             :  * structure with additional arguments to specify resampling and progress
     313             :  * callback, or NULL for default behavior. The GDAL_RASTERIO_RESAMPLING
     314             :  * configuration option can also be defined to override the default resampling
     315             :  * to one of BILINEAR, CUBIC, CUBICSPLINE, LANCZOS, AVERAGE or MODE.
     316             :  *
     317             :  * @return CE_Failure if the access fails, otherwise CE_None.
     318             :  *
     319             :  * @see GDALRasterBand::ReadRaster()
     320             :  */
     321             : 
     322     4416200 : CPLErr GDALRasterBand::RasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     323             :                                 int nXSize, int nYSize, void *pData,
     324             :                                 int nBufXSize, int nBufYSize,
     325             :                                 GDALDataType eBufType, GSpacing nPixelSpace,
     326             :                                 GSpacing nLineSpace,
     327             :                                 GDALRasterIOExtraArg *psExtraArg)
     328             : 
     329             : {
     330             :     GDALRasterIOExtraArg sExtraArg;
     331     4416200 :     if (psExtraArg == nullptr)
     332             :     {
     333     3819760 :         INIT_RASTERIO_EXTRA_ARG(sExtraArg);
     334     3819760 :         psExtraArg = &sExtraArg;
     335             :     }
     336      596444 :     else if (CPL_UNLIKELY(psExtraArg->nVersion >
     337             :                           RASTERIO_EXTRA_ARG_CURRENT_VERSION))
     338             :     {
     339           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     340             :                     "Unhandled version of GDALRasterIOExtraArg");
     341           0 :         return CE_Failure;
     342             :     }
     343             : 
     344     4416200 :     GDALRasterIOExtraArgSetResampleAlg(psExtraArg, nXSize, nYSize, nBufXSize,
     345             :                                        nBufYSize);
     346             : 
     347     4416480 :     if (CPL_UNLIKELY(nullptr == pData))
     348             :     {
     349           0 :         ReportError(CE_Failure, CPLE_AppDefined,
     350             :                     "The buffer into which the data should be read is null");
     351           0 :         return CE_Failure;
     352             :     }
     353             : 
     354             :     /* -------------------------------------------------------------------- */
     355             :     /*      Some size values are "noop".  Lets just return to avoid         */
     356             :     /*      stressing lower level functions.                                */
     357             :     /* -------------------------------------------------------------------- */
     358     4416480 :     if (CPL_UNLIKELY(nXSize < 1 || nYSize < 1 || nBufXSize < 1 ||
     359             :                      nBufYSize < 1))
     360             :     {
     361           2 :         CPLDebug("GDAL",
     362             :                  "RasterIO() skipped for odd window or buffer size.\n"
     363             :                  "  Window = (%d,%d)x%dx%d\n"
     364             :                  "  Buffer = %dx%d\n",
     365             :                  nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
     366             : 
     367           2 :         return CE_None;
     368             :     }
     369             : 
     370     4416480 :     if (eRWFlag == GF_Write)
     371             :     {
     372      359461 :         if (CPL_UNLIKELY(eFlushBlockErr != CE_None))
     373             :         {
     374           0 :             ReportError(eFlushBlockErr, CPLE_AppDefined,
     375             :                         "An error occurred while writing a dirty block "
     376             :                         "from GDALRasterBand::RasterIO");
     377           0 :             CPLErr eErr = eFlushBlockErr;
     378           0 :             eFlushBlockErr = CE_None;
     379           0 :             return eErr;
     380             :         }
     381      359461 :         if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::RasterIO()"))
     382             :         {
     383           7 :             return CE_Failure;
     384             :         }
     385             :     }
     386             : 
     387             :     /* -------------------------------------------------------------------- */
     388             :     /*      If pixel and line spacing are defaulted assign reasonable      */
     389             :     /*      value assuming a packed buffer.                                 */
     390             :     /* -------------------------------------------------------------------- */
     391     4416910 :     if (nPixelSpace == 0)
     392             :     {
     393     4015080 :         nPixelSpace = GDALGetDataTypeSizeBytes(eBufType);
     394             :     }
     395             : 
     396     4415640 :     if (nLineSpace == 0)
     397             :     {
     398     4003020 :         nLineSpace = nPixelSpace * nBufXSize;
     399             :     }
     400             : 
     401             :     /* -------------------------------------------------------------------- */
     402             :     /*      Do some validation of parameters.                               */
     403             :     /* -------------------------------------------------------------------- */
     404     4415640 :     if (CPL_UNLIKELY(nXOff < 0 || nXOff > INT_MAX - nXSize ||
     405             :                      nXOff + nXSize > nRasterXSize || nYOff < 0 ||
     406             :                      nYOff > INT_MAX - nYSize || nYOff + nYSize > nRasterYSize))
     407             :     {
     408          15 :         ReportError(CE_Failure, CPLE_IllegalArg,
     409             :                     "Access window out of range in RasterIO().  Requested\n"
     410             :                     "(%d,%d) of size %dx%d on raster of %dx%d.",
     411             :                     nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize);
     412          15 :         return CE_Failure;
     413             :     }
     414             : 
     415     4415620 :     if (CPL_UNLIKELY(eRWFlag != GF_Read && eRWFlag != GF_Write))
     416             :     {
     417           0 :         ReportError(
     418             :             CE_Failure, CPLE_IllegalArg,
     419             :             "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.",
     420             :             eRWFlag);
     421           0 :         return CE_Failure;
     422             :     }
     423     4415620 :     if (CPL_UNLIKELY(eBufType == GDT_Unknown || eBufType == GDT_TypeCount))
     424             :     {
     425           2 :         ReportError(CE_Failure, CPLE_IllegalArg,
     426             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
     427           2 :         return CE_Failure;
     428             :     }
     429             : 
     430     4415620 :     return RasterIOInternal(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     431             :                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
     432     4414420 :                             nLineSpace, psExtraArg);
     433             : }
     434             : 
     435             : /************************************************************************/
     436             : /*                         RasterIOInternal()                           */
     437             : /************************************************************************/
     438             : 
     439     4413420 : CPLErr GDALRasterBand::RasterIOInternal(
     440             :     GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
     441             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
     442             :     GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
     443             : {
     444             :     /* -------------------------------------------------------------------- */
     445             :     /*      Call the format specific function.                              */
     446             :     /* -------------------------------------------------------------------- */
     447             : 
     448     4413420 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(eRWFlag));
     449             : 
     450             :     CPLErr eErr;
     451     4414360 :     if (bForceCachedIO)
     452          23 :         eErr = GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
     453             :                                          pData, nBufXSize, nBufYSize, eBufType,
     454             :                                          nPixelSpace, nLineSpace, psExtraArg);
     455             :     else
     456             :         eErr =
     457     4415600 :             IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     458     4414340 :                       nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
     459             : 
     460     4415620 :     if (bCallLeaveReadWrite)
     461      599570 :         LeaveReadWrite();
     462             : 
     463     4411300 :     return eErr;
     464             : }
     465             : 
     466             : /************************************************************************/
     467             : /*                            GDALRasterIO()                            */
     468             : /************************************************************************/
     469             : 
     470             : /**
     471             :  * \brief Read/write a region of image data for this band.
     472             :  *
     473             :  * Use GDALRasterIOEx() if 64 bit spacings or extra arguments (resampling
     474             :  * resolution, progress callback, etc. are needed)
     475             :  *
     476             :  * @see GDALRasterBand::RasterIO()
     477             :  */
     478             : 
     479     3410200 : CPLErr CPL_STDCALL GDALRasterIO(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     480             :                                 int nXOff, int nYOff, int nXSize, int nYSize,
     481             :                                 void *pData, int nBufXSize, int nBufYSize,
     482             :                                 GDALDataType eBufType, int nPixelSpace,
     483             :                                 int nLineSpace)
     484             : 
     485             : {
     486     3410200 :     VALIDATE_POINTER1(hBand, "GDALRasterIO", CE_Failure);
     487             : 
     488     3410200 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     489             : 
     490     3411860 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     491             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     492     3403120 :                              nLineSpace, nullptr));
     493             : }
     494             : 
     495             : /************************************************************************/
     496             : /*                            GDALRasterIOEx()                          */
     497             : /************************************************************************/
     498             : 
     499             : /**
     500             :  * \brief Read/write a region of image data for this band.
     501             :  *
     502             :  * @see GDALRasterBand::RasterIO()
     503             :  * @since GDAL 2.0
     504             :  */
     505             : 
     506       39487 : CPLErr CPL_STDCALL GDALRasterIOEx(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
     507             :                                   int nXOff, int nYOff, int nXSize, int nYSize,
     508             :                                   void *pData, int nBufXSize, int nBufYSize,
     509             :                                   GDALDataType eBufType, GSpacing nPixelSpace,
     510             :                                   GSpacing nLineSpace,
     511             :                                   GDALRasterIOExtraArg *psExtraArg)
     512             : 
     513             : {
     514       39487 :     VALIDATE_POINTER1(hBand, "GDALRasterIOEx", CE_Failure);
     515             : 
     516       39487 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
     517             : 
     518       39487 :     return (poBand->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     519             :                              nBufXSize, nBufYSize, eBufType, nPixelSpace,
     520       39482 :                              nLineSpace, psExtraArg));
     521             : }
     522             : 
     523             : /************************************************************************/
     524             : /*                           GetGDTFromCppType()                        */
     525             : /************************************************************************/
     526             : 
     527             : namespace
     528             : {
     529             : template <class T> struct GetGDTFromCppType;
     530             : 
     531             : #define DEFINE_GetGDTFromCppType(T, eDT)                                       \
     532             :     template <> struct GetGDTFromCppType<T>                                    \
     533             :     {                                                                          \
     534             :         static constexpr GDALDataType GDT = eDT;                               \
     535             :     }
     536             : 
     537             : DEFINE_GetGDTFromCppType(uint8_t, GDT_Byte);
     538             : DEFINE_GetGDTFromCppType(int8_t, GDT_Int8);
     539             : DEFINE_GetGDTFromCppType(uint16_t, GDT_UInt16);
     540             : DEFINE_GetGDTFromCppType(int16_t, GDT_Int16);
     541             : DEFINE_GetGDTFromCppType(uint32_t, GDT_UInt32);
     542             : DEFINE_GetGDTFromCppType(int32_t, GDT_Int32);
     543             : DEFINE_GetGDTFromCppType(uint64_t, GDT_UInt64);
     544             : DEFINE_GetGDTFromCppType(int64_t, GDT_Int64);
     545             : DEFINE_GetGDTFromCppType(GFloat16, GDT_Float16);
     546             : DEFINE_GetGDTFromCppType(float, GDT_Float32);
     547             : DEFINE_GetGDTFromCppType(double, GDT_Float64);
     548             : // Not allowed by C++ standard
     549             : //DEFINE_GetGDTFromCppType(std::complex<int16_t>, GDT_CInt16);
     550             : //DEFINE_GetGDTFromCppType(std::complex<int32_t>, GDT_CInt32);
     551             : DEFINE_GetGDTFromCppType(std::complex<float>, GDT_CFloat32);
     552             : DEFINE_GetGDTFromCppType(std::complex<double>, GDT_CFloat64);
     553             : }  // namespace
     554             : 
     555             : /************************************************************************/
     556             : /*                           ReadRaster()                               */
     557             : /************************************************************************/
     558             : 
     559             : // clang-format off
     560             : /** Read a region of image data for this band.
     561             :  *
     562             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     563             :  * for common use cases, like reading a whole band.
     564             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     565             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     566             :  * float, double, std::complex<float|double>.
     567             :  *
     568             :  * 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>&,
     569             :  * and can allocate memory automatically.
     570             :  *
     571             :  * To read a whole band (assuming it fits into memory), as an array of double:
     572             :  *
     573             : \code{.cpp}
     574             :  double* myArray = static_cast<double*>(
     575             :      VSI_MALLOC3_VERBOSE(sizeof(double), poBand->GetXSize(), poBand->GetYSize()));
     576             :  // TODO: check here that myArray != nullptr
     577             :  const size_t nArrayEltCount =
     578             :      static_cast<size_t>(poBand->GetXSize()) * poBand->GetYSize());
     579             :  if (poBand->ReadRaster(myArray, nArrayEltCount) == CE_None)
     580             :  {
     581             :      // do something
     582             :  }
     583             :  VSIFree(myArray)
     584             : \endcode
     585             :  *
     586             :  * To read 128x128 pixels starting at (col=12, line=24) as an array of double:
     587             :  *
     588             : \code{.cpp}
     589             :  double* myArray = static_cast<double*>(
     590             :      VSI_MALLOC3_VERBOSE(sizeof(double), 128, 128));
     591             :  // TODO: check here that myArray != nullptr
     592             :  const size_t nArrayEltCount = 128 * 128;
     593             :  if (poBand->ReadRaster(myArray, nArrayEltCount, 12, 24, 128, 128) == CE_None)
     594             :  {
     595             :      // do something
     596             :  }
     597             :  VSIFree(myArray)
     598             : \endcode
     599             :  *
     600             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     601             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     602             :  * instance of this dataset) concurrently from several threads.
     603             :  *
     604             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     605             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     606             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     607             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     608             :  * Or use nLineSpace and a possibly shifted pData value.
     609             :  *
     610             :  * @param[out] pData The buffer into which the data should be written.
     611             :  * This buffer must contain at least nBufXSize *
     612             :  * nBufYSize words of type T. It is organized in left to right,
     613             :  * top to bottom pixel order, and fully packed.
     614             :  * The type of the buffer does not need to be the one of GetDataType(). The
     615             :  * method will perform data type translation (with potential rounding, clamping)
     616             :  * if needed.
     617             :  *
     618             :  * @param nArrayEltCount Number of values of pData. If non zero, the method will
     619             :  * check that it is at least greater or equal to nBufXSize * nBufYSize, and
     620             :  * return in error if it is not. If set to zero, then pData is trusted to be
     621             :  * large enough.
     622             :  *
     623             :  * @param dfXOff The pixel offset to the top left corner of the region
     624             :  * of the band to be accessed. This would be zero to start from the left side.
     625             :  * Defaults to 0.
     626             :  *
     627             :  * @param dfYOff The line offset to the top left corner of the region
     628             :  * of the band to be accessed. This would be zero to start from the top.
     629             :  * Defaults to 0.
     630             :  *
     631             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     632             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     633             :  * dfXSize is set to the band width.
     634             :  *
     635             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     636             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     637             :  * dfYSize is set to the band height.
     638             :  *
     639             :  * @param nBufXSize the width of the buffer image into which the desired region
     640             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     641             :  * then nBufXSize is initialized with dfXSize.
     642             :  *
     643             :  * @param nBufYSize the height of the buffer image into which the desired region
     644             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     645             :  * then nBufYSize is initialized with dfYSize.
     646             :  *
     647             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     648             :  *
     649             :  * @param pfnProgress Progress function. May be nullptr.
     650             :  *
     651             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     652             :  *
     653             :  * @return CE_Failure if the access fails, otherwise CE_None.
     654             :  *
     655             :  * @see GDALRasterBand::RasterIO()
     656             :  * @since GDAL 3.10
     657             :  */
     658             : // clang-format on
     659             : 
     660             : template <class T>
     661          20 : CPLErr GDALRasterBand::ReadRaster(T *pData, size_t nArrayEltCount,
     662             :                                   double dfXOff, double dfYOff, double dfXSize,
     663             :                                   double dfYSize, size_t nBufXSize,
     664             :                                   size_t nBufYSize,
     665             :                                   GDALRIOResampleAlg eResampleAlg,
     666             :                                   GDALProgressFunc pfnProgress,
     667             :                                   void *pProgressData) const
     668             : {
     669          20 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     670             :     {
     671           2 :         return CE_Failure;
     672             :     }
     673             : 
     674          18 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     675             :     {
     676          16 :         dfXSize = nRasterXSize;
     677          16 :         dfYSize = nRasterYSize;
     678             :     }
     679           2 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     680           2 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     681           2 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     682           2 :              dfYOff + dfYSize > INT_MAX)
     683             :     {
     684           0 :         return CE_Failure;
     685             :     }
     686             : 
     687             :     GDALRasterIOExtraArg sExtraArg;
     688          18 :     sExtraArg.nVersion = 1;
     689          18 :     sExtraArg.eResampleAlg = eResampleAlg;
     690          18 :     sExtraArg.pfnProgress = pfnProgress;
     691          18 :     sExtraArg.pProgressData = pProgressData;
     692          18 :     sExtraArg.bFloatingPointWindowValidity = true;
     693          18 :     sExtraArg.dfXOff = dfXOff;
     694          18 :     sExtraArg.dfYOff = dfYOff;
     695          18 :     sExtraArg.dfXSize = dfXSize;
     696          18 :     sExtraArg.dfYSize = dfYSize;
     697          18 :     const int nXOff = static_cast<int>(dfXOff);
     698          18 :     const int nYOff = static_cast<int>(dfYOff);
     699          18 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     700          18 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     701          18 :     if (nBufXSize == 0 && nBufYSize == 0)
     702             :     {
     703          17 :         if (static_cast<int>(dfXSize) == dfXSize &&
     704          17 :             static_cast<int>(dfYSize) == dfYSize)
     705             :         {
     706          17 :             nBufXSize = static_cast<int>(dfXSize);
     707          17 :             nBufYSize = static_cast<int>(dfYSize);
     708             :         }
     709             :         else
     710             :         {
     711           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     712             :                      "nBufXSize and nBufYSize must be provided if dfXSize or "
     713             :                      "dfYSize is not an integer value");
     714           0 :             return CE_Failure;
     715             :         }
     716             :     }
     717          18 :     if (nBufXSize == 0 || nBufYSize == 0)
     718             :     {
     719           0 :         CPLDebug("GDAL",
     720             :                  "RasterIO() skipped for odd window or buffer size.\n"
     721             :                  "  Window = (%d,%d)x%dx%d\n"
     722             :                  "  Buffer = %dx%d\n",
     723             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     724             :                  static_cast<int>(nBufYSize));
     725             : 
     726           0 :         return CE_None;
     727             :     }
     728             : 
     729          18 :     if (nArrayEltCount > 0 && nBufXSize > nArrayEltCount / nBufYSize)
     730             :     {
     731           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     732             :                  "Provided array is not large enough");
     733           1 :         return CE_Failure;
     734             :     }
     735             : 
     736          17 :     constexpr GSpacing nPixelSpace = sizeof(T);
     737          17 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     738          17 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     739             : 
     740          17 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     741             : 
     742             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
     743             :                                    static_cast<int>(nBufXSize),
     744             :                                    static_cast<int>(nBufYSize), eBufType,
     745          17 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     746             : }
     747             : 
     748             : //! @cond Doxygen_Suppress
     749             : 
     750             : #define INSTANTIATE_READ_RASTER(T)                                             \
     751             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     752             :         T *vData, size_t nArrayEltCount, double dfXOff, double dfYOff,         \
     753             :         double dfXSize, double dfYSize, size_t nBufXSize, size_t nBufYSize,    \
     754             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     755             :         void *pProgressData) const;
     756             : 
     757             : INSTANTIATE_READ_RASTER(uint8_t)
     758             : INSTANTIATE_READ_RASTER(int8_t)
     759             : INSTANTIATE_READ_RASTER(uint16_t)
     760             : INSTANTIATE_READ_RASTER(int16_t)
     761             : INSTANTIATE_READ_RASTER(uint32_t)
     762             : INSTANTIATE_READ_RASTER(int32_t)
     763             : INSTANTIATE_READ_RASTER(uint64_t)
     764             : INSTANTIATE_READ_RASTER(int64_t)
     765             : INSTANTIATE_READ_RASTER(GFloat16)
     766             : INSTANTIATE_READ_RASTER(float)
     767             : INSTANTIATE_READ_RASTER(double)
     768             : // Not allowed by C++ standard
     769             : // INSTANTIATE_READ_RASTER(std::complex<int16_t>)
     770             : // INSTANTIATE_READ_RASTER(std::complex<int32_t>)
     771             : INSTANTIATE_READ_RASTER(std::complex<float>)
     772             : INSTANTIATE_READ_RASTER(std::complex<double>)
     773             : 
     774             : //! @endcond
     775             : 
     776             : /************************************************************************/
     777             : /*                           ReadRaster()                               */
     778             : /************************************************************************/
     779             : 
     780             : /** Read a region of image data for this band.
     781             :  *
     782             :  * This is a slightly more convenient alternative to GDALRasterBand::RasterIO()
     783             :  * for common use cases, like reading a whole band.
     784             :  * It infers the GDAL data type of the buffer from the C/C++ type of the buffer.
     785             :  * This template is instantiated for the following types: [u?]int[8|16|32|64]_t,
     786             :  * float, double, std::complex<float|double>.
     787             :  *
     788             :  * To read a whole band (assuming it fits into memory), as a vector of double:
     789             :  *
     790             : \code
     791             :  std::vector<double> myArray;
     792             :  if (poBand->ReadRaster(myArray) == CE_None)
     793             :  {
     794             :      // do something
     795             :  }
     796             : \endcode
     797             :  *
     798             :  * To read 128x128 pixels starting at (col=12, line=24) as a vector of double:
     799             :  *
     800             : \code{.cpp}
     801             :  std::vector<double> myArray;
     802             :  if (poBand->ReadRaster(myArray, 12, 24, 128, 128) == CE_None)
     803             :  {
     804             :      // do something
     805             :  }
     806             : \endcode
     807             :  *
     808             :  * As nearly all GDAL methods, this method is *NOT* thread-safe, that is it cannot
     809             :  * be called on the same GDALRasterBand instance (or another GDALRasterBand
     810             :  * instance of this dataset) concurrently from several threads.
     811             :  *
     812             :  * The window of interest expressed by (dfXOff, dfYOff, dfXSize, dfYSize) should be
     813             :  * fully within the raster space, that is dfXOff >= 0, dfYOff >= 0,
     814             :  * dfXOff + dfXSize <= GetXSize() and dfYOff + dfYSize <= GetYSize().
     815             :  * If reads larger than the raster space are wished, GDALTranslate() might be used.
     816             :  * Or use nLineSpace and a possibly shifted pData value.
     817             :  *
     818             :  * @param[out] vData The vector into which the data should be written.
     819             :  * The vector will be resized, if needed, to contain at least nBufXSize *
     820             :  * nBufYSize values. The values in the vector are organized in left to right,
     821             :  * top to bottom pixel order, and fully packed.
     822             :  * The type of the vector does not need to be the one of GetDataType(). The
     823             :  * method will perform data type translation (with potential rounding, clamping)
     824             :  * if needed.
     825             :  *
     826             :  * @param dfXOff The pixel offset to the top left corner of the region
     827             :  * of the band to be accessed. This would be zero to start from the left side.
     828             :  * Defaults to 0.
     829             :  *
     830             :  * @param dfYOff The line offset to the top left corner of the region
     831             :  * of the band to be accessed. This would be zero to start from the top.
     832             :  * Defaults to 0.
     833             :  *
     834             :  * @param dfXSize The width of the region of the band to be accessed in pixels.
     835             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     836             :  * dfXSize is set to the band width.
     837             :  *
     838             :  * @param dfYSize The height of the region of the band to be accessed in lines.
     839             :  * If all of dfXOff, dfYOff, dfXSize and dfYSize are left to their zero default value,
     840             :  * dfYSize is set to the band height.
     841             :  *
     842             :  * @param nBufXSize the width of the buffer image into which the desired region
     843             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     844             :  * then nBufXSize is initialized with dfXSize.
     845             :  *
     846             :  * @param nBufYSize the height of the buffer image into which the desired region
     847             :  * is to be read. If set to zero, and both dfXSize and dfYSize are integer values,
     848             :  * then nBufYSize is initialized with dfYSize.
     849             :  *
     850             :  * @param eResampleAlg Resampling algorithm. Defaults to GRIORA_NearestNeighbour.
     851             :  *
     852             :  * @param pfnProgress Progress function. May be nullptr.
     853             :  *
     854             :  * @param pProgressData User data of pfnProgress. May be nullptr.
     855             :  *
     856             :  * @return CE_Failure if the access fails, otherwise CE_None.
     857             :  *
     858             :  * @see GDALRasterBand::RasterIO()
     859             :  * @since GDAL 3.10
     860             :  */
     861             : template <class T>
     862          22 : CPLErr GDALRasterBand::ReadRaster(std::vector<T> &vData, double dfXOff,
     863             :                                   double dfYOff, double dfXSize, double dfYSize,
     864             :                                   size_t nBufXSize, size_t nBufYSize,
     865             :                                   GDALRIOResampleAlg eResampleAlg,
     866             :                                   GDALProgressFunc pfnProgress,
     867             :                                   void *pProgressData) const
     868             : {
     869          22 :     if (((nBufXSize | nBufYSize) >> 31) != 0)
     870             :     {
     871           2 :         return CE_Failure;
     872             :     }
     873             : 
     874          20 :     if (dfXOff == 0 && dfYOff == 0 && dfXSize == 0 && dfYSize == 0)
     875             :     {
     876          13 :         dfXSize = nRasterXSize;
     877          13 :         dfYSize = nRasterYSize;
     878             :     }
     879           7 :     else if (!(dfXOff >= 0 && dfXOff <= INT_MAX) ||
     880           7 :              !(dfYOff >= 0 && dfYOff <= INT_MAX) || !(dfXSize >= 0) ||
     881           7 :              !(dfYSize >= 0) || dfXOff + dfXSize > INT_MAX ||
     882           7 :              dfYOff + dfYSize > INT_MAX)
     883             :     {
     884           0 :         return CE_Failure;
     885             :     }
     886             : 
     887             :     GDALRasterIOExtraArg sExtraArg;
     888          20 :     sExtraArg.nVersion = 1;
     889          20 :     sExtraArg.eResampleAlg = eResampleAlg;
     890          20 :     sExtraArg.pfnProgress = pfnProgress;
     891          20 :     sExtraArg.pProgressData = pProgressData;
     892          20 :     sExtraArg.bFloatingPointWindowValidity = true;
     893          20 :     sExtraArg.dfXOff = dfXOff;
     894          20 :     sExtraArg.dfYOff = dfYOff;
     895          20 :     sExtraArg.dfXSize = dfXSize;
     896          20 :     sExtraArg.dfYSize = dfYSize;
     897          20 :     const int nXOff = static_cast<int>(dfXOff);
     898          20 :     const int nYOff = static_cast<int>(dfYOff);
     899          20 :     const int nXSize = std::max(1, static_cast<int>(dfXSize + 0.5));
     900          20 :     const int nYSize = std::max(1, static_cast<int>(dfYSize + 0.5));
     901          20 :     if (nBufXSize == 0 && nBufYSize == 0)
     902             :     {
     903          16 :         if (static_cast<int>(dfXSize) == dfXSize &&
     904          15 :             static_cast<int>(dfYSize) == dfYSize)
     905             :         {
     906          15 :             nBufXSize = static_cast<int>(dfXSize);
     907          15 :             nBufYSize = static_cast<int>(dfYSize);
     908             :         }
     909             :         else
     910             :         {
     911           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     912             :                      "nBufXSize and nBufYSize must be provided if "
     913             :                      "dfXSize or dfYSize is not an integer value");
     914           1 :             return CE_Failure;
     915             :         }
     916             :     }
     917          19 :     if (nBufXSize == 0 || nBufYSize == 0)
     918             :     {
     919           0 :         CPLDebug("GDAL",
     920             :                  "RasterIO() skipped for odd window or buffer size.\n"
     921             :                  "  Window = (%d,%d)x%dx%d\n"
     922             :                  "  Buffer = %dx%d\n",
     923             :                  nXOff, nYOff, nXSize, nYSize, static_cast<int>(nBufXSize),
     924             :                  static_cast<int>(nBufYSize));
     925             : 
     926           0 :         return CE_None;
     927             :     }
     928             : 
     929             :     if constexpr (SIZEOF_VOIDP < 8)
     930             :     {
     931             :         if (nBufXSize > std::numeric_limits<size_t>::max() / nBufYSize)
     932             :         {
     933             :             CPLError(CE_Failure, CPLE_OutOfMemory, "Too large buffer");
     934             :             return CE_Failure;
     935             :         }
     936             :     }
     937             : 
     938          19 :     if (vData.size() < nBufXSize * nBufYSize)
     939             :     {
     940             :         try
     941             :         {
     942          17 :             vData.resize(nBufXSize * nBufYSize);
     943             :         }
     944           1 :         catch (const std::exception &)
     945             :         {
     946           1 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Cannot resize array");
     947           1 :             return CE_Failure;
     948             :         }
     949             :     }
     950             : 
     951          18 :     constexpr GSpacing nPixelSpace = sizeof(T);
     952          18 :     const GSpacing nLineSpace = nPixelSpace * nBufXSize;
     953          18 :     constexpr GDALDataType eBufType = GetGDTFromCppType<T>::GDT;
     954             : 
     955          18 :     GDALRasterBand *pThis = const_cast<GDALRasterBand *>(this);
     956             : 
     957             :     return pThis->RasterIOInternal(GF_Read, nXOff, nYOff, nXSize, nYSize,
     958             :                                    vData.data(), static_cast<int>(nBufXSize),
     959             :                                    static_cast<int>(nBufYSize), eBufType,
     960          18 :                                    nPixelSpace, nLineSpace, &sExtraArg);
     961             : }
     962             : 
     963             : //! @cond Doxygen_Suppress
     964             : 
     965             : #define INSTANTIATE_READ_RASTER_VECTOR(T)                                      \
     966             :     template CPLErr CPL_DLL GDALRasterBand::ReadRaster(                        \
     967             :         std::vector<T> &vData, double dfXOff, double dfYOff, double dfXSize,   \
     968             :         double dfYSize, size_t nBufXSize, size_t nBufYSize,                    \
     969             :         GDALRIOResampleAlg eResampleAlg, GDALProgressFunc pfnProgress,         \
     970             :         void *pProgressData) const;
     971             : 
     972             : INSTANTIATE_READ_RASTER_VECTOR(uint8_t)
     973             : INSTANTIATE_READ_RASTER_VECTOR(int8_t)
     974             : INSTANTIATE_READ_RASTER_VECTOR(uint16_t)
     975             : INSTANTIATE_READ_RASTER_VECTOR(int16_t)
     976             : INSTANTIATE_READ_RASTER_VECTOR(uint32_t)
     977             : INSTANTIATE_READ_RASTER_VECTOR(int32_t)
     978             : INSTANTIATE_READ_RASTER_VECTOR(uint64_t)
     979             : INSTANTIATE_READ_RASTER_VECTOR(int64_t)
     980             : INSTANTIATE_READ_RASTER_VECTOR(GFloat16)
     981             : INSTANTIATE_READ_RASTER_VECTOR(float)
     982             : INSTANTIATE_READ_RASTER_VECTOR(double)
     983             : // Not allowed by C++ standard
     984             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int16_t>)
     985             : // INSTANTIATE_READ_RASTER_VECTOR(std::complex<int32_t>)
     986             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<float>)
     987             : INSTANTIATE_READ_RASTER_VECTOR(std::complex<double>)
     988             : 
     989             : //! @endcond
     990             : 
     991             : /************************************************************************/
     992             : /*                             ReadBlock()                              */
     993             : /************************************************************************/
     994             : 
     995             : /**
     996             :  * \brief Read a block of image data efficiently.
     997             :  *
     998             :  * This method accesses a "natural" block from the raster band without
     999             :  * resampling, or data type conversion.  For a more generalized, but
    1000             :  * potentially less efficient access use RasterIO().
    1001             :  *
    1002             :  * This method is the same as the C GDALReadBlock() function.
    1003             :  *
    1004             :  * See the GetLockedBlockRef() method for a way of accessing internally cached
    1005             :  * block oriented data without an extra copy into an application buffer.
    1006             :  *
    1007             :  * The following code would efficiently compute a histogram of eight bit
    1008             :  * raster data.  Note that the final block may be partial ... data beyond
    1009             :  * the edge of the underlying raster band in these edge blocks is of an
    1010             :  * undetermined value.
    1011             :  *
    1012             : \code{.cpp}
    1013             :  CPLErr GetHistogram( GDALRasterBand *poBand, GUIntBig *panHistogram )
    1014             : 
    1015             :  {
    1016             :      memset( panHistogram, 0, sizeof(GUIntBig) * 256 );
    1017             : 
    1018             :      CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
    1019             : 
    1020             :      int nXBlockSize, nYBlockSize;
    1021             : 
    1022             :      poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
    1023             :      int nXBlocks = DIV_ROUND_UP(poBand->GetXSize(), nXBlockSize);
    1024             :      int nYBlocks = DIV_ROUND_UP(poBand->GetYSize(), nYBlockSize);
    1025             : 
    1026             :      GByte *pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
    1027             : 
    1028             :      for( int iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
    1029             :      {
    1030             :          for( int iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
    1031             :          {
    1032             :              int        nXValid, nYValid;
    1033             : 
    1034             :              poBand->ReadBlock( iXBlock, iYBlock, pabyData );
    1035             : 
    1036             :              // Compute the portion of the block that is valid
    1037             :              // for partial edge blocks.
    1038             :              poBand->GetActualBlockSize(iXBlock, iYBlock, &nXValid, &nYValid)
    1039             : 
    1040             :              // Collect the histogram counts.
    1041             :              for( int iY = 0; iY < nYValid; iY++ )
    1042             :              {
    1043             :                  for( int iX = 0; iX < nXValid; iX++ )
    1044             :                  {
    1045             :                      panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
    1046             :                  }
    1047             :              }
    1048             :          }
    1049             :      }
    1050             :  }
    1051             : \endcode
    1052             :  *
    1053             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1054             :  * the left most block, 1 the next block and so forth.
    1055             :  *
    1056             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1057             :  * the top most block, 1 the next block and so forth.
    1058             :  *
    1059             :  * @param pImage the buffer into which the data will be read.  The buffer
    1060             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1061             :  * of type GetRasterDataType().
    1062             :  *
    1063             :  * @return CE_None on success or CE_Failure on an error.
    1064             :  */
    1065             : 
    1066         894 : CPLErr GDALRasterBand::ReadBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1067             : 
    1068             : {
    1069             :     /* -------------------------------------------------------------------- */
    1070             :     /*      Validate arguments.                                             */
    1071             :     /* -------------------------------------------------------------------- */
    1072         894 :     CPLAssert(pImage != nullptr);
    1073             : 
    1074         894 :     if (!InitBlockInfo())
    1075           0 :         return CE_Failure;
    1076             : 
    1077         894 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1078             :     {
    1079           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1080             :                     "Illegal nXBlockOff value (%d) in "
    1081             :                     "GDALRasterBand::ReadBlock()\n",
    1082             :                     nXBlockOff);
    1083             : 
    1084           0 :         return (CE_Failure);
    1085             :     }
    1086             : 
    1087         894 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1088             :     {
    1089           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1090             :                     "Illegal nYBlockOff value (%d) in "
    1091             :                     "GDALRasterBand::ReadBlock()\n",
    1092             :                     nYBlockOff);
    1093             : 
    1094           0 :         return (CE_Failure);
    1095             :     }
    1096             : 
    1097             :     /* -------------------------------------------------------------------- */
    1098             :     /*      Invoke underlying implementation method.                        */
    1099             :     /* -------------------------------------------------------------------- */
    1100             : 
    1101         894 :     int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    1102         894 :     CPLErr eErr = IReadBlock(nXBlockOff, nYBlockOff, pImage);
    1103         894 :     if (bCallLeaveReadWrite)
    1104           4 :         LeaveReadWrite();
    1105         894 :     return eErr;
    1106             : }
    1107             : 
    1108             : /************************************************************************/
    1109             : /*                           GDALReadBlock()                            */
    1110             : /************************************************************************/
    1111             : 
    1112             : /**
    1113             :  * \brief Read a block of image data efficiently.
    1114             :  *
    1115             :  * @see GDALRasterBand::ReadBlock()
    1116             :  */
    1117             : 
    1118          77 : CPLErr CPL_STDCALL GDALReadBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1119             :                                  void *pData)
    1120             : 
    1121             : {
    1122          77 :     VALIDATE_POINTER1(hBand, "GDALReadBlock", CE_Failure);
    1123             : 
    1124          77 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1125          77 :     return (poBand->ReadBlock(nXOff, nYOff, pData));
    1126             : }
    1127             : 
    1128             : /************************************************************************/
    1129             : /*                            IReadBlock()                             */
    1130             : /************************************************************************/
    1131             : 
    1132             : /** \fn GDALRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void *pData
    1133             :  * ) \brief Read a block of data.
    1134             :  *
    1135             :  * Default internal implementation ... to be overridden by
    1136             :  * subclasses that support reading.
    1137             :  * @param nBlockXOff Block X Offset
    1138             :  * @param nBlockYOff Block Y Offset
    1139             :  * @param pData Pixel buffer into which to place read data.
    1140             :  * @return CE_None on success or CE_Failure on an error.
    1141             :  */
    1142             : 
    1143             : /************************************************************************/
    1144             : /*                            IWriteBlock()                             */
    1145             : /************************************************************************/
    1146             : 
    1147             : /**
    1148             :  * \fn GDALRasterBand::IWriteBlock(int, int, void*)
    1149             :  * Write a block of data.
    1150             :  *
    1151             :  * Default internal implementation ... to be overridden by
    1152             :  * subclasses that support writing.
    1153             :  * @param nBlockXOff Block X Offset
    1154             :  * @param nBlockYOff Block Y Offset
    1155             :  * @param pData Pixel buffer to write
    1156             :  * @return CE_None on success or CE_Failure on an error.
    1157             :  */
    1158             : 
    1159             : /**/
    1160             : /**/
    1161             : 
    1162           0 : CPLErr GDALRasterBand::IWriteBlock(int /*nBlockXOff*/, int /*nBlockYOff*/,
    1163             :                                    void * /*pData*/)
    1164             : 
    1165             : {
    1166           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    1167           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    1168             :                     "WriteBlock() not supported for this dataset.");
    1169             : 
    1170           0 :     return (CE_Failure);
    1171             : }
    1172             : 
    1173             : /************************************************************************/
    1174             : /*                             WriteBlock()                             */
    1175             : /************************************************************************/
    1176             : 
    1177             : /**
    1178             :  * \brief Write a block of image data efficiently.
    1179             :  *
    1180             :  * This method accesses a "natural" block from the raster band without
    1181             :  * resampling, or data type conversion.  For a more generalized, but
    1182             :  * potentially less efficient access use RasterIO().
    1183             :  *
    1184             :  * This method is the same as the C GDALWriteBlock() function.
    1185             :  *
    1186             :  * See ReadBlock() for an example of block oriented data access.
    1187             :  *
    1188             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1189             :  * the left most block, 1 the next block and so forth.
    1190             :  *
    1191             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1192             :  * the left most block, 1 the next block and so forth.
    1193             :  *
    1194             :  * @param pImage the buffer from which the data will be written.  The buffer
    1195             :  * must be large enough to hold GetBlockXSize()*GetBlockYSize() words
    1196             :  * of type GetRasterDataType(). Note that the content of the buffer might be
    1197             :  * temporarily modified during the execution of this method (and eventually
    1198             :  * restored back to its original content), so it is not safe to use a buffer
    1199             :  * stored in a read-only section of the calling program.
    1200             :  *
    1201             :  * @return CE_None on success or CE_Failure on an error.
    1202             :  */
    1203             : 
    1204        4888 : CPLErr GDALRasterBand::WriteBlock(int nXBlockOff, int nYBlockOff, void *pImage)
    1205             : 
    1206             : {
    1207             :     /* -------------------------------------------------------------------- */
    1208             :     /*      Validate arguments.                                             */
    1209             :     /* -------------------------------------------------------------------- */
    1210        4888 :     CPLAssert(pImage != nullptr);
    1211             : 
    1212        4888 :     if (!InitBlockInfo())
    1213           0 :         return CE_Failure;
    1214             : 
    1215        4888 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1216             :     {
    1217           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1218             :                     "Illegal nXBlockOff value (%d) in "
    1219             :                     "GDALRasterBand::WriteBlock()\n",
    1220             :                     nXBlockOff);
    1221             : 
    1222           0 :         return (CE_Failure);
    1223             :     }
    1224             : 
    1225        4888 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1226             :     {
    1227           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1228             :                     "Illegal nYBlockOff value (%d) in "
    1229             :                     "GDALRasterBand::WriteBlock()\n",
    1230             :                     nYBlockOff);
    1231             : 
    1232           0 :         return (CE_Failure);
    1233             :     }
    1234             : 
    1235        4888 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::WriteBlock()"))
    1236             :     {
    1237           0 :         return CE_Failure;
    1238             :     }
    1239             : 
    1240        4888 :     if (eFlushBlockErr != CE_None)
    1241             :     {
    1242           0 :         ReportError(eFlushBlockErr, CPLE_AppDefined,
    1243             :                     "An error occurred while writing a dirty block "
    1244             :                     "from GDALRasterBand::WriteBlock");
    1245           0 :         CPLErr eErr = eFlushBlockErr;
    1246           0 :         eFlushBlockErr = CE_None;
    1247           0 :         return eErr;
    1248             :     }
    1249             : 
    1250             :     /* -------------------------------------------------------------------- */
    1251             :     /*      Invoke underlying implementation method.                        */
    1252             :     /* -------------------------------------------------------------------- */
    1253             : 
    1254        4888 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    1255        4888 :     CPLErr eErr = IWriteBlock(nXBlockOff, nYBlockOff, pImage);
    1256        4888 :     if (bCallLeaveReadWrite)
    1257        4888 :         LeaveReadWrite();
    1258             : 
    1259        4888 :     return eErr;
    1260             : }
    1261             : 
    1262             : /************************************************************************/
    1263             : /*                           GDALWriteBlock()                           */
    1264             : /************************************************************************/
    1265             : 
    1266             : /**
    1267             :  * \brief Write a block of image data efficiently.
    1268             :  *
    1269             :  * @see GDALRasterBand::WriteBlock()
    1270             :  */
    1271             : 
    1272           0 : CPLErr CPL_STDCALL GDALWriteBlock(GDALRasterBandH hBand, int nXOff, int nYOff,
    1273             :                                   void *pData)
    1274             : 
    1275             : {
    1276           0 :     VALIDATE_POINTER1(hBand, "GDALWriteBlock", CE_Failure);
    1277             : 
    1278           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1279           0 :     return (poBand->WriteBlock(nXOff, nYOff, pData));
    1280             : }
    1281             : 
    1282             : /************************************************************************/
    1283             : /*                   EmitErrorMessageIfWriteNotSupported()              */
    1284             : /************************************************************************/
    1285             : 
    1286             : /**
    1287             :  * Emit an error message if a write operation to this band is not supported.
    1288             :  *
    1289             :  * The base implementation will emit an error message if the access mode is
    1290             :  * read-only. Derived classes may implement it to provide a custom message.
    1291             :  *
    1292             :  * @param pszCaller Calling function.
    1293             :  * @return true if an error message has been emitted.
    1294             :  */
    1295      633252 : bool GDALRasterBand::EmitErrorMessageIfWriteNotSupported(
    1296             :     const char *pszCaller) const
    1297             : {
    1298      633252 :     if (eAccess == GA_ReadOnly)
    1299             :     {
    1300           4 :         ReportError(CE_Failure, CPLE_NoWriteAccess,
    1301             :                     "%s: attempt to write to dataset opened in read-only mode.",
    1302             :                     pszCaller);
    1303             : 
    1304           4 :         return true;
    1305             :     }
    1306      633248 :     return false;
    1307             : }
    1308             : 
    1309             : /************************************************************************/
    1310             : /*                         GetActualBlockSize()                         */
    1311             : /************************************************************************/
    1312             : /**
    1313             :  * \brief Fetch the actual block size for a given block offset.
    1314             :  *
    1315             :  * Handles partial blocks at the edges of the raster and returns the true
    1316             :  * number of pixels
    1317             :  *
    1318             :  * @param nXBlockOff the horizontal block offset for which to calculate the
    1319             :  * number of valid pixels, with zero indicating the left most block, 1 the next
    1320             :  * block and so forth.
    1321             :  *
    1322             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1323             :  * the top most block, 1 the next block and so forth.
    1324             :  *
    1325             :  * @param pnXValid pointer to an integer in which the number of valid pixels in
    1326             :  * the x direction will be stored
    1327             :  *
    1328             :  * @param pnYValid pointer to an integer in which the number of valid pixels in
    1329             :  * the y direction will be stored
    1330             :  *
    1331             :  * @return CE_None if the input parameters are valid, CE_Failure otherwise
    1332             :  *
    1333             :  * @since GDAL 2.2
    1334             :  */
    1335       51518 : CPLErr GDALRasterBand::GetActualBlockSize(int nXBlockOff, int nYBlockOff,
    1336             :                                           int *pnXValid, int *pnYValid) const
    1337             : {
    1338      103035 :     if (nXBlockOff < 0 || nBlockXSize == 0 ||
    1339      103033 :         nXBlockOff >= DIV_ROUND_UP(nRasterXSize, nBlockXSize) ||
    1340      103030 :         nYBlockOff < 0 || nBlockYSize == 0 ||
    1341       51515 :         nYBlockOff >= DIV_ROUND_UP(nRasterYSize, nBlockYSize))
    1342             :     {
    1343           4 :         return CE_Failure;
    1344             :     }
    1345             : 
    1346       51514 :     const int nXPixelOff = nXBlockOff * nBlockXSize;
    1347       51514 :     const int nYPixelOff = nYBlockOff * nBlockYSize;
    1348             : 
    1349       51514 :     *pnXValid = nBlockXSize;
    1350       51514 :     *pnYValid = nBlockYSize;
    1351             : 
    1352       51514 :     if (nXPixelOff >= nRasterXSize - nBlockXSize)
    1353             :     {
    1354       50126 :         *pnXValid = nRasterXSize - nXPixelOff;
    1355             :     }
    1356             : 
    1357       51514 :     if (nYPixelOff >= nRasterYSize - nBlockYSize)
    1358             :     {
    1359        3517 :         *pnYValid = nRasterYSize - nYPixelOff;
    1360             :     }
    1361             : 
    1362       51514 :     return CE_None;
    1363             : }
    1364             : 
    1365             : /************************************************************************/
    1366             : /*                           GDALGetActualBlockSize()                   */
    1367             : /************************************************************************/
    1368             : 
    1369             : /**
    1370             :  * \brief Retrieve the actual block size for a given block offset.
    1371             :  *
    1372             :  * @see GDALRasterBand::GetActualBlockSize()
    1373             :  */
    1374             : 
    1375           6 : CPLErr CPL_STDCALL GDALGetActualBlockSize(GDALRasterBandH hBand, int nXBlockOff,
    1376             :                                           int nYBlockOff, int *pnXValid,
    1377             :                                           int *pnYValid)
    1378             : 
    1379             : {
    1380           6 :     VALIDATE_POINTER1(hBand, "GDALGetActualBlockSize", CE_Failure);
    1381             : 
    1382           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1383             :     return (
    1384           6 :         poBand->GetActualBlockSize(nXBlockOff, nYBlockOff, pnXValid, pnYValid));
    1385             : }
    1386             : 
    1387             : /************************************************************************/
    1388             : /*                     GetSuggestedBlockAccessPattern()                 */
    1389             : /************************************************************************/
    1390             : 
    1391             : /**
    1392             :  * \brief Return the suggested/most efficient access pattern to blocks
    1393             :  *        (for read operations).
    1394             :  *
    1395             :  * While all GDAL drivers have to expose a block size, not all can guarantee
    1396             :  * efficient random access (GSBAP_RANDOM) to any block.
    1397             :  * Some drivers for example decompress sequentially a compressed stream from
    1398             :  * top raster to bottom (GSBAP_TOP_TO_BOTTOM), in which
    1399             :  * case best performance will be achieved while reading blocks in that order.
    1400             :  * (accessing blocks in random access in such rasters typically causes the
    1401             :  * decoding to be re-initialized from the start if accessing blocks in
    1402             :  * a non-sequential order)
    1403             :  *
    1404             :  * The base implementation returns GSBAP_UNKNOWN, which can also be explicitly
    1405             :  * returned by drivers that expose a somewhat artificial block size, because
    1406             :  * they can extract any part of a raster, but in a rather inefficient way.
    1407             :  *
    1408             :  * The GSBAP_LARGEST_CHUNK_POSSIBLE value can be combined as a logical bitmask
    1409             :  * with other enumeration values (GSBAP_UNKNOWN, GSBAP_RANDOM,
    1410             :  * GSBAP_TOP_TO_BOTTOM, GSBAP_BOTTOM_TO_TOP). When a driver sets this flag, the
    1411             :  * most efficient strategy is to read as many pixels as possible in the less
    1412             :  * RasterIO() operations.
    1413             :  *
    1414             :  * The return of this method is for example used to determine the swath size
    1415             :  * used by GDALDatasetCopyWholeRaster() and GDALRasterBandCopyWholeRaster().
    1416             :  *
    1417             :  * @since GDAL 3.6
    1418             :  */
    1419             : 
    1420             : GDALSuggestedBlockAccessPattern
    1421        2357 : GDALRasterBand::GetSuggestedBlockAccessPattern() const
    1422             : {
    1423        2357 :     return GSBAP_UNKNOWN;
    1424             : }
    1425             : 
    1426             : /************************************************************************/
    1427             : /*                         GetRasterDataType()                          */
    1428             : /************************************************************************/
    1429             : 
    1430             : /**
    1431             :  * \brief Fetch the pixel data type for this band.
    1432             :  *
    1433             :  * This method is the same as the C function GDALGetRasterDataType().
    1434             :  *
    1435             :  * @return the data type of pixels for this band.
    1436             :  */
    1437             : 
    1438     9018490 : GDALDataType GDALRasterBand::GetRasterDataType() const
    1439             : 
    1440             : {
    1441     9018490 :     return eDataType;
    1442             : }
    1443             : 
    1444             : /************************************************************************/
    1445             : /*                       GDALGetRasterDataType()                        */
    1446             : /************************************************************************/
    1447             : 
    1448             : /**
    1449             :  * \brief Fetch the pixel data type for this band.
    1450             :  *
    1451             :  * @see GDALRasterBand::GetRasterDataType()
    1452             :  */
    1453             : 
    1454      904167 : GDALDataType CPL_STDCALL GDALGetRasterDataType(GDALRasterBandH hBand)
    1455             : 
    1456             : {
    1457      904167 :     VALIDATE_POINTER1(hBand, "GDALGetRasterDataType", GDT_Unknown);
    1458             : 
    1459      904167 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1460      904167 :     return poBand->GetRasterDataType();
    1461             : }
    1462             : 
    1463             : /************************************************************************/
    1464             : /*                            GetBlockSize()                            */
    1465             : /************************************************************************/
    1466             : 
    1467             : /**
    1468             :  * \brief Fetch the "natural" block size of this band.
    1469             :  *
    1470             :  * GDAL contains a concept of the natural block size of rasters so that
    1471             :  * applications can organized data access efficiently for some file formats.
    1472             :  * The natural block size is the block size that is most efficient for
    1473             :  * accessing the format.  For many formats this is simple a whole scanline
    1474             :  * in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
    1475             :  *
    1476             :  * However, for tiled images this will typically be the tile size.
    1477             :  *
    1478             :  * Note that the X and Y block sizes don't have to divide the image size
    1479             :  * evenly, meaning that right and bottom edge blocks may be incomplete.
    1480             :  * See ReadBlock() for an example of code dealing with these issues.
    1481             :  *
    1482             :  * This method is the same as the C function GDALGetBlockSize().
    1483             :  *
    1484             :  * @param pnXSize integer to put the X block size into or NULL.
    1485             :  *
    1486             :  * @param pnYSize integer to put the Y block size into or NULL.
    1487             :  */
    1488             : 
    1489     5547730 : void GDALRasterBand::GetBlockSize(int *pnXSize, int *pnYSize) const
    1490             : 
    1491             : {
    1492     5547730 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1493             :     {
    1494        7322 :         ReportError(CE_Failure, CPLE_AppDefined,
    1495        7322 :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1496        7322 :                     nBlockYSize);
    1497           0 :         if (pnXSize != nullptr)
    1498           0 :             *pnXSize = 0;
    1499           0 :         if (pnYSize != nullptr)
    1500           0 :             *pnYSize = 0;
    1501             :     }
    1502             :     else
    1503             :     {
    1504     5540400 :         if (pnXSize != nullptr)
    1505     5538160 :             *pnXSize = nBlockXSize;
    1506     5540400 :         if (pnYSize != nullptr)
    1507     5541600 :             *pnYSize = nBlockYSize;
    1508             :     }
    1509     5540400 : }
    1510             : 
    1511             : /************************************************************************/
    1512             : /*                          GDALGetBlockSize()                          */
    1513             : /************************************************************************/
    1514             : 
    1515             : /**
    1516             :  * \brief Fetch the "natural" block size of this band.
    1517             :  *
    1518             :  * @see GDALRasterBand::GetBlockSize()
    1519             :  */
    1520             : 
    1521       41109 : void CPL_STDCALL GDALGetBlockSize(GDALRasterBandH hBand, int *pnXSize,
    1522             :                                   int *pnYSize)
    1523             : 
    1524             : {
    1525       41109 :     VALIDATE_POINTER0(hBand, "GDALGetBlockSize");
    1526             : 
    1527       41109 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    1528       41109 :     poBand->GetBlockSize(pnXSize, pnYSize);
    1529             : }
    1530             : 
    1531             : /************************************************************************/
    1532             : /*                           InitBlockInfo()                            */
    1533             : /************************************************************************/
    1534             : 
    1535             : //! @cond Doxygen_Suppress
    1536     3668120 : int GDALRasterBand::InitBlockInfo()
    1537             : 
    1538             : {
    1539     3668120 :     if (poBandBlockCache != nullptr)
    1540     3430400 :         return poBandBlockCache->IsInitOK();
    1541             : 
    1542             :     /* Do some validation of raster and block dimensions in case the driver */
    1543             :     /* would have neglected to do it itself */
    1544      237722 :     if (nBlockXSize <= 0 || nBlockYSize <= 0)
    1545             :     {
    1546           4 :         ReportError(CE_Failure, CPLE_AppDefined,
    1547             :                     "Invalid block dimension : %d * %d", nBlockXSize,
    1548             :                     nBlockYSize);
    1549           0 :         return FALSE;
    1550             :     }
    1551             : 
    1552      237718 :     if (nRasterXSize <= 0 || nRasterYSize <= 0)
    1553             :     {
    1554           1 :         ReportError(CE_Failure, CPLE_AppDefined,
    1555             :                     "Invalid raster dimension : %d * %d", nRasterXSize,
    1556             :                     nRasterYSize);
    1557           0 :         return FALSE;
    1558             :     }
    1559             : 
    1560      237717 :     const int nDataTypeSize = GDALGetDataTypeSizeBytes(eDataType);
    1561      237717 :     if (nDataTypeSize == 0)
    1562             :     {
    1563           0 :         ReportError(CE_Failure, CPLE_AppDefined, "Invalid data type");
    1564           0 :         return FALSE;
    1565             :     }
    1566             : 
    1567             : #if SIZEOF_VOIDP == 4
    1568             :     if (nBlockXSize >= 10000 || nBlockYSize >= 10000)
    1569             :     {
    1570             :         /* As 10000 * 10000 * 16 < INT_MAX, we don't need to do the
    1571             :          * multiplication in other cases */
    1572             :         if (nBlockXSize > INT_MAX / nDataTypeSize ||
    1573             :             nBlockYSize > INT_MAX / (nDataTypeSize * nBlockXSize))
    1574             :         {
    1575             :             ReportError(CE_Failure, CPLE_NotSupported,
    1576             :                         "Too big block : %d * %d for 32-bit build", nBlockXSize,
    1577             :                         nBlockYSize);
    1578             :             return FALSE;
    1579             :         }
    1580             :     }
    1581             : #endif
    1582             : 
    1583      237717 :     nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
    1584      237717 :     nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
    1585             : 
    1586             :     const char *pszBlockStrategy =
    1587      237717 :         CPLGetConfigOption("GDAL_BAND_BLOCK_CACHE", nullptr);
    1588      237721 :     bool bUseArray = true;
    1589      237721 :     if (pszBlockStrategy == nullptr || EQUAL(pszBlockStrategy, "AUTO"))
    1590             :     {
    1591      237681 :         if (poDS == nullptr || (poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1592             :                                    GDAL_OF_DEFAULT_BLOCK_ACCESS)
    1593             :         {
    1594      237662 :             GUIntBig nBlockCount =
    1595      237662 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    1596      237662 :             if (poDS != nullptr)
    1597      237462 :                 nBlockCount *= poDS->GetRasterCount();
    1598      237663 :             bUseArray = (nBlockCount < 1024 * 1024);
    1599             :         }
    1600          19 :         else if ((poDS->nOpenFlags & GDAL_OF_BLOCK_ACCESS_MASK) ==
    1601             :                  GDAL_OF_HASHSET_BLOCK_ACCESS)
    1602             :         {
    1603           0 :             bUseArray = false;
    1604      237682 :         }
    1605             :     }
    1606          40 :     else if (EQUAL(pszBlockStrategy, "HASHSET"))
    1607          40 :         bUseArray = false;
    1608           0 :     else if (!EQUAL(pszBlockStrategy, "ARRAY"))
    1609           0 :         CPLError(CE_Warning, CPLE_AppDefined, "Unknown block cache method: %s",
    1610             :                  pszBlockStrategy);
    1611             : 
    1612      237719 :     if (bUseArray)
    1613      237648 :         poBandBlockCache = GDALArrayBandBlockCacheCreate(this);
    1614             :     else
    1615             :     {
    1616          71 :         if (nBand == 1)
    1617          26 :             CPLDebug("GDAL", "Use hashset band block cache");
    1618          71 :         poBandBlockCache = GDALHashSetBandBlockCacheCreate(this);
    1619             :     }
    1620      237721 :     if (poBandBlockCache == nullptr)
    1621           0 :         return FALSE;
    1622      237721 :     return poBandBlockCache->Init();
    1623             : }
    1624             : 
    1625             : //! @endcond
    1626             : 
    1627             : /************************************************************************/
    1628             : /*                             FlushCache()                             */
    1629             : /************************************************************************/
    1630             : 
    1631             : /**
    1632             :  * \brief Flush raster data cache.
    1633             :  *
    1634             :  * This call will recover memory used to cache data blocks for this raster
    1635             :  * band, and ensure that new requests are referred to the underlying driver.
    1636             :  *
    1637             :  * This method is the same as the C function GDALFlushRasterCache().
    1638             :  *
    1639             :  * @param bAtClosing Whether this is called from a GDALDataset destructor
    1640             :  * @return CE_None on success.
    1641             :  */
    1642             : 
    1643     5701820 : CPLErr GDALRasterBand::FlushCache(bool bAtClosing)
    1644             : 
    1645             : {
    1646     5815120 :     if (bAtClosing && poDS && poDS->IsMarkedSuppressOnClose() &&
    1647      113306 :         poBandBlockCache)
    1648        2920 :         poBandBlockCache->DisableDirtyBlockWriting();
    1649             : 
    1650     5701200 :     CPLErr eGlobalErr = eFlushBlockErr;
    1651             : 
    1652     5701200 :     if (eFlushBlockErr != CE_None)
    1653             :     {
    1654           0 :         ReportError(
    1655             :             eFlushBlockErr, CPLE_AppDefined,
    1656             :             "An error occurred while writing a dirty block from FlushCache");
    1657           0 :         eFlushBlockErr = CE_None;
    1658             :     }
    1659             : 
    1660     5701200 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1661     4937300 :         return eGlobalErr;
    1662             : 
    1663      763906 :     return poBandBlockCache->FlushCache();
    1664             : }
    1665             : 
    1666             : /************************************************************************/
    1667             : /*                        GDALFlushRasterCache()                        */
    1668             : /************************************************************************/
    1669             : 
    1670             : /**
    1671             :  * \brief Flush raster data cache.
    1672             :  *
    1673             :  * @see GDALRasterBand::FlushCache()
    1674             :  */
    1675             : 
    1676         487 : CPLErr CPL_STDCALL GDALFlushRasterCache(GDALRasterBandH hBand)
    1677             : 
    1678             : {
    1679         487 :     VALIDATE_POINTER1(hBand, "GDALFlushRasterCache", CE_Failure);
    1680             : 
    1681         487 :     return GDALRasterBand::FromHandle(hBand)->FlushCache(false);
    1682             : }
    1683             : 
    1684             : /************************************************************************/
    1685             : /*                             DropCache()                              */
    1686             : /************************************************************************/
    1687             : 
    1688             : /**
    1689             : * \brief Drop raster data cache : data in cache will be lost.
    1690             : *
    1691             : * This call will recover memory used to cache data blocks for this raster
    1692             : * band, and ensure that new requests are referred to the underlying driver.
    1693             : *
    1694             : * This method is the same as the C function GDALDropRasterCache().
    1695             : *
    1696             : * @return CE_None on success.
    1697             : * @since 3.9
    1698             : */
    1699             : 
    1700           1 : CPLErr GDALRasterBand::DropCache()
    1701             : 
    1702             : {
    1703           1 :     CPLErr result = CE_None;
    1704             : 
    1705           1 :     if (poBandBlockCache)
    1706           1 :         poBandBlockCache->DisableDirtyBlockWriting();
    1707             : 
    1708           1 :     CPLErr eGlobalErr = eFlushBlockErr;
    1709             : 
    1710           1 :     if (eFlushBlockErr != CE_None)
    1711             :     {
    1712           0 :         ReportError(
    1713             :             eFlushBlockErr, CPLE_AppDefined,
    1714             :             "An error occurred while writing a dirty block from DropCache");
    1715           0 :         eFlushBlockErr = CE_None;
    1716             :     }
    1717             : 
    1718           1 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1719           0 :         result = eGlobalErr;
    1720             :     else
    1721           1 :         result = poBandBlockCache->FlushCache();
    1722             : 
    1723           1 :     if (poBandBlockCache)
    1724           1 :         poBandBlockCache->EnableDirtyBlockWriting();
    1725             : 
    1726           1 :     return result;
    1727             : }
    1728             : 
    1729             : /************************************************************************/
    1730             : /*                        GDALDropRasterCache()                         */
    1731             : /************************************************************************/
    1732             : 
    1733             : /**
    1734             : * \brief Drop raster data cache.
    1735             : *
    1736             : * @see GDALRasterBand::DropCache()
    1737             : * @since 3.9
    1738             : */
    1739             : 
    1740           0 : CPLErr CPL_STDCALL GDALDropRasterCache(GDALRasterBandH hBand)
    1741             : 
    1742             : {
    1743           0 :     VALIDATE_POINTER1(hBand, "GDALDropRasterCache", CE_Failure);
    1744             : 
    1745           0 :     return GDALRasterBand::FromHandle(hBand)->DropCache();
    1746             : }
    1747             : 
    1748             : /************************************************************************/
    1749             : /*                        UnreferenceBlock()                            */
    1750             : /*                                                                      */
    1751             : /*      Unreference the block from our array of blocks                  */
    1752             : /*      This method should only be called by                            */
    1753             : /*      GDALRasterBlock::Internalize() and FlushCacheBlock() (and under */
    1754             : /*      the block cache mutex)                                          */
    1755             : /************************************************************************/
    1756             : 
    1757       29820 : CPLErr GDALRasterBand::UnreferenceBlock(GDALRasterBlock *poBlock)
    1758             : {
    1759             : #ifdef notdef
    1760             :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1761             :     {
    1762             :         if (poBandBlockCache == nullptr)
    1763             :             printf("poBandBlockCache == NULL\n"); /*ok*/
    1764             :         else
    1765             :             printf("!poBandBlockCache->IsInitOK()\n"); /*ok*/
    1766             :         printf("caller = %s\n", pszCaller);            /*ok*/
    1767             :         printf("GDALRasterBand: %p\n", this);          /*ok*/
    1768             :         printf("GDALRasterBand: nBand=%d\n", nBand);   /*ok*/
    1769             :         printf("nRasterXSize = %d\n", nRasterXSize);   /*ok*/
    1770             :         printf("nRasterYSize = %d\n", nRasterYSize);   /*ok*/
    1771             :         printf("nBlockXSize = %d\n", nBlockXSize);     /*ok*/
    1772             :         printf("nBlockYSize = %d\n", nBlockYSize);     /*ok*/
    1773             :         poBlock->DumpBlock();
    1774             :         if (GetDataset() != nullptr)
    1775             :             printf("Dataset: %s\n", GetDataset()->GetDescription()); /*ok*/
    1776             :         GDALRasterBlock::Verify();
    1777             :         abort();
    1778             :     }
    1779             : #endif
    1780       29820 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1781       29820 :     return poBandBlockCache->UnreferenceBlock(poBlock);
    1782             : }
    1783             : 
    1784             : /************************************************************************/
    1785             : /*                        AddBlockToFreeList()                          */
    1786             : /*                                                                      */
    1787             : /*      When GDALRasterBlock::Internalize() or FlushCacheBlock() are    */
    1788             : /*      finished with a block about to be free'd, they pass it to that  */
    1789             : /*      method.                                                         */
    1790             : /************************************************************************/
    1791             : 
    1792             : //! @cond Doxygen_Suppress
    1793       29820 : void GDALRasterBand::AddBlockToFreeList(GDALRasterBlock *poBlock)
    1794             : {
    1795       29820 :     CPLAssert(poBandBlockCache && poBandBlockCache->IsInitOK());
    1796       29820 :     return poBandBlockCache->AddBlockToFreeList(poBlock);
    1797             : }
    1798             : 
    1799             : //! @endcond
    1800             : 
    1801             : /************************************************************************/
    1802             : /*                             FlushBlock()                             */
    1803             : /************************************************************************/
    1804             : 
    1805             : /** Flush a block out of the block cache.
    1806             :  * @param nXBlockOff block x offset
    1807             :  * @param nYBlockOff blocky offset
    1808             :  * @param bWriteDirtyBlock whether the block should be written to disk if dirty.
    1809             :  * @return CE_None in case of success, an error code otherwise.
    1810             :  */
    1811        2310 : CPLErr GDALRasterBand::FlushBlock(int nXBlockOff, int nYBlockOff,
    1812             :                                   int bWriteDirtyBlock)
    1813             : 
    1814             : {
    1815        2310 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1816           0 :         return (CE_Failure);
    1817             : 
    1818             :     /* -------------------------------------------------------------------- */
    1819             :     /*      Validate the request                                            */
    1820             :     /* -------------------------------------------------------------------- */
    1821        2310 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1822             :     {
    1823           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1824             :                     "Illegal nBlockXOff value (%d) in "
    1825             :                     "GDALRasterBand::FlushBlock()\n",
    1826             :                     nXBlockOff);
    1827             : 
    1828           0 :         return (CE_Failure);
    1829             :     }
    1830             : 
    1831        2310 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1832             :     {
    1833           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1834             :                     "Illegal nBlockYOff value (%d) in "
    1835             :                     "GDALRasterBand::FlushBlock()\n",
    1836             :                     nYBlockOff);
    1837             : 
    1838           0 :         return (CE_Failure);
    1839             :     }
    1840             : 
    1841        2310 :     return poBandBlockCache->FlushBlock(nXBlockOff, nYBlockOff,
    1842        2310 :                                         bWriteDirtyBlock);
    1843             : }
    1844             : 
    1845             : /************************************************************************/
    1846             : /*                        TryGetLockedBlockRef()                        */
    1847             : /************************************************************************/
    1848             : 
    1849             : /**
    1850             :  * \brief Try fetching block ref.
    1851             :  *
    1852             :  * This method will returned the requested block (locked) if it is already
    1853             :  * in the block cache for the layer.  If not, nullptr is returned.
    1854             :  *
    1855             :  * If a non-NULL value is returned, then a lock for the block will have been
    1856             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1857             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1858             :  * severe problems may result.
    1859             :  *
    1860             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1861             :  * the left most block, 1 the next block and so forth.
    1862             :  *
    1863             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1864             :  * the top most block, 1 the next block and so forth.
    1865             :  *
    1866             :  * @return NULL if block not available, or locked block pointer.
    1867             :  */
    1868             : 
    1869    10655000 : GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef(int nXBlockOff,
    1870             :                                                       int nYBlockOff)
    1871             : 
    1872             : {
    1873    10655000 :     if (poBandBlockCache == nullptr || !poBandBlockCache->IsInitOK())
    1874      171618 :         return nullptr;
    1875             : 
    1876             :     /* -------------------------------------------------------------------- */
    1877             :     /*      Validate the request                                            */
    1878             :     /* -------------------------------------------------------------------- */
    1879    10484700 :     if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1880             :     {
    1881         797 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1882             :                     "Illegal nBlockXOff value (%d) in "
    1883             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1884             :                     nXBlockOff);
    1885             : 
    1886           0 :         return (nullptr);
    1887             :     }
    1888             : 
    1889    10483900 :     if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1890             :     {
    1891           0 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1892             :                     "Illegal nBlockYOff value (%d) in "
    1893             :                     "GDALRasterBand::TryGetLockedBlockRef()\n",
    1894             :                     nYBlockOff);
    1895             : 
    1896           0 :         return (nullptr);
    1897             :     }
    1898             : 
    1899    10483900 :     return poBandBlockCache->TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1900             : }
    1901             : 
    1902             : /************************************************************************/
    1903             : /*                         GetLockedBlockRef()                          */
    1904             : /************************************************************************/
    1905             : 
    1906             : /**
    1907             :  * \brief Fetch a pointer to an internally cached raster block.
    1908             :  *
    1909             :  * This method will returned the requested block (locked) if it is already
    1910             :  * in the block cache for the layer.  If not, the block will be read from
    1911             :  * the driver, and placed in the layer block cached, then returned.  If an
    1912             :  * error occurs reading the block from the driver, a NULL value will be
    1913             :  * returned.
    1914             :  *
    1915             :  * If a non-NULL value is returned, then a lock for the block will have been
    1916             :  * acquired on behalf of the caller.  It is absolutely imperative that the
    1917             :  * caller release this lock (with GDALRasterBlock::DropLock()) or else
    1918             :  * severe problems may result.
    1919             :  *
    1920             :  * Note that calling GetLockedBlockRef() on a previously uncached band will
    1921             :  * enable caching.
    1922             :  *
    1923             :  * @param nXBlockOff the horizontal block offset, with zero indicating
    1924             :  * the left most block, 1 the next block and so forth.
    1925             :  *
    1926             :  * @param nYBlockOff the vertical block offset, with zero indicating
    1927             :  * the top most block, 1 the next block and so forth.
    1928             :  *
    1929             :  * @param bJustInitialize If TRUE the block will be allocated and initialized,
    1930             :  * but not actually read from the source.  This is useful when it will just
    1931             :  * be completely set and written back.
    1932             :  *
    1933             :  * @return pointer to the block object, or NULL on failure.
    1934             :  */
    1935             : 
    1936    10345900 : GDALRasterBlock *GDALRasterBand::GetLockedBlockRef(int nXBlockOff,
    1937             :                                                    int nYBlockOff,
    1938             :                                                    int bJustInitialize)
    1939             : 
    1940             : {
    1941             :     /* -------------------------------------------------------------------- */
    1942             :     /*      Try and fetch from cache.                                       */
    1943             :     /* -------------------------------------------------------------------- */
    1944    10345900 :     GDALRasterBlock *poBlock = TryGetLockedBlockRef(nXBlockOff, nYBlockOff);
    1945             : 
    1946             :     /* -------------------------------------------------------------------- */
    1947             :     /*      If we didn't find it in our memory cache, instantiate a         */
    1948             :     /*      block (potentially load from disk) and "adopt" it into the      */
    1949             :     /*      cache.                                                          */
    1950             :     /* -------------------------------------------------------------------- */
    1951    10349900 :     if (poBlock == nullptr)
    1952             :     {
    1953     3391430 :         if (!InitBlockInfo())
    1954           0 :             return (nullptr);
    1955             : 
    1956             :         /* --------------------------------------------------------------------
    1957             :          */
    1958             :         /*      Validate the request */
    1959             :         /* --------------------------------------------------------------------
    1960             :          */
    1961     3391420 :         if (nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow)
    1962             :         {
    1963          33 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1964             :                         "Illegal nBlockXOff value (%d) in "
    1965             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1966             :                         nXBlockOff);
    1967             : 
    1968           0 :             return (nullptr);
    1969             :         }
    1970             : 
    1971     3391390 :         if (nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn)
    1972             :         {
    1973           0 :             ReportError(CE_Failure, CPLE_IllegalArg,
    1974             :                         "Illegal nBlockYOff value (%d) in "
    1975             :                         "GDALRasterBand::GetLockedBlockRef()\n",
    1976             :                         nYBlockOff);
    1977             : 
    1978           0 :             return (nullptr);
    1979             :         }
    1980             : 
    1981     3391410 :         poBlock = poBandBlockCache->CreateBlock(nXBlockOff, nYBlockOff);
    1982     3391420 :         if (poBlock == nullptr)
    1983           0 :             return nullptr;
    1984             : 
    1985     3391420 :         poBlock->AddLock();
    1986             : 
    1987             :         /* We need to temporarily drop the read-write lock in the following */
    1988             :         /*scenario. Imagine 2 threads T1 and T2 that respectively write dataset
    1989             :          */
    1990             :         /* D1 and D2. T1 will take the mutex on D1 and T2 on D2. Now when the */
    1991             :         /* block cache fills, T1 might need to flush dirty blocks of D2 in the
    1992             :          */
    1993             :         /* below Internalize(), which will cause GDALRasterBlock::Write() to be
    1994             :          */
    1995             :         /* called and attempt at taking the lock on T2 (already taken).
    1996             :          * Similarly */
    1997             :         /* for T2 with D1, hence a deadlock situation (#6163) */
    1998             :         /* But this may open the door to other problems... */
    1999     3391420 :         if (poDS)
    2000     3390690 :             poDS->TemporarilyDropReadWriteLock();
    2001             :         /* allocate data space */
    2002     3391430 :         CPLErr eErr = poBlock->Internalize();
    2003     3391450 :         if (poDS)
    2004     3390710 :             poDS->ReacquireReadWriteLock();
    2005     3391440 :         if (eErr != CE_None)
    2006             :         {
    2007           0 :             poBlock->DropLock();
    2008           0 :             delete poBlock;
    2009           0 :             return nullptr;
    2010             :         }
    2011             : 
    2012     3391440 :         if (poBandBlockCache->AdoptBlock(poBlock) != CE_None)
    2013             :         {
    2014           0 :             poBlock->DropLock();
    2015           0 :             delete poBlock;
    2016           0 :             return nullptr;
    2017             :         }
    2018             : 
    2019     3391440 :         if (!bJustInitialize)
    2020             :         {
    2021     2904040 :             const GUInt32 nErrorCounter = CPLGetErrorCounter();
    2022     2904030 :             int bCallLeaveReadWrite = EnterReadWrite(GF_Read);
    2023     2903670 :             eErr = IReadBlock(nXBlockOff, nYBlockOff, poBlock->GetDataRef());
    2024     2904030 :             if (bCallLeaveReadWrite)
    2025      129988 :                 LeaveReadWrite();
    2026     2904020 :             if (eErr != CE_None)
    2027             :             {
    2028        1160 :                 poBlock->DropLock();
    2029        1160 :                 FlushBlock(nXBlockOff, nYBlockOff);
    2030        1160 :                 ReportError(CE_Failure, CPLE_AppDefined,
    2031             :                             "IReadBlock failed at X offset %d, Y offset %d%s",
    2032             :                             nXBlockOff, nYBlockOff,
    2033        1160 :                             (nErrorCounter != CPLGetErrorCounter())
    2034        1158 :                                 ? CPLSPrintf(": %s", CPLGetLastErrorMsg())
    2035             :                                 : "");
    2036        1160 :                 return nullptr;
    2037             :             }
    2038             : 
    2039     2902860 :             nBlockReads++;
    2040     2902860 :             if (static_cast<GIntBig>(nBlockReads) ==
    2041     2902860 :                     static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn +
    2042         219 :                         1 &&
    2043         219 :                 nBand == 1 && poDS != nullptr)
    2044             :             {
    2045         159 :                 CPLDebug("GDAL", "Potential thrashing on band %d of %s.", nBand,
    2046         159 :                          poDS->GetDescription());
    2047             :             }
    2048             :         }
    2049             :     }
    2050             : 
    2051    10348800 :     return poBlock;
    2052             : }
    2053             : 
    2054             : /************************************************************************/
    2055             : /*                               Fill()                                 */
    2056             : /************************************************************************/
    2057             : 
    2058             : /**
    2059             :  * \brief Fill this band with a constant value.
    2060             :  *
    2061             :  * GDAL makes no guarantees
    2062             :  * about what values pixels in newly created files are set to, so this
    2063             :  * method can be used to clear a band to a specified "default" value.
    2064             :  * The fill value is passed in as a double but this will be converted
    2065             :  * to the underlying type before writing to the file. An optional
    2066             :  * second argument allows the imaginary component of a complex
    2067             :  * constant value to be specified.
    2068             :  *
    2069             :  * This method is the same as the C function GDALFillRaster().
    2070             :  *
    2071             :  * @param dfRealValue Real component of fill value
    2072             :  * @param dfImaginaryValue Imaginary component of fill value, defaults to zero
    2073             :  *
    2074             :  * @return CE_Failure if the write fails, otherwise CE_None
    2075             :  */
    2076      268645 : CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue)
    2077             : {
    2078             : 
    2079             :     // General approach is to construct a source block of the file's
    2080             :     // native type containing the appropriate value and then copy this
    2081             :     // to each block in the image via the RasterBlock cache. Using
    2082             :     // the cache means we avoid file I/O if it is not necessary, at the
    2083             :     // expense of some extra memcpy's (since we write to the
    2084             :     // RasterBlock cache, which is then at some point written to the
    2085             :     // underlying file, rather than simply directly to the underlying
    2086             :     // file.)
    2087             : 
    2088             :     // Check we can write to the file.
    2089      268645 :     if (EmitErrorMessageIfWriteNotSupported("GDALRasterBand::Fill()"))
    2090             :     {
    2091           6 :         return CE_Failure;
    2092             :     }
    2093             : 
    2094             :     // Make sure block parameters are set.
    2095      268639 :     if (!InitBlockInfo())
    2096           0 :         return CE_Failure;
    2097             : 
    2098             :     // Allocate the source block.
    2099      268639 :     auto blockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
    2100      268639 :     int elementSize = GDALGetDataTypeSizeBytes(eDataType);
    2101      268639 :     auto blockByteSize = blockSize * elementSize;
    2102             :     unsigned char *srcBlock =
    2103      268639 :         static_cast<unsigned char *>(VSIMalloc(blockByteSize));
    2104      268639 :     if (srcBlock == nullptr)
    2105             :     {
    2106           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    2107             :                     "GDALRasterBand::Fill(): Out of memory "
    2108             :                     "allocating " CPL_FRMT_GUIB " bytes.\n",
    2109             :                     static_cast<GUIntBig>(blockByteSize));
    2110           0 :         return CE_Failure;
    2111             :     }
    2112             : 
    2113             :     // Initialize the source block.
    2114      268639 :     double complexSrc[2] = {dfRealValue, dfImaginaryValue};
    2115      268639 :     GDALCopyWords64(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType,
    2116             :                     elementSize, blockSize);
    2117             : 
    2118      268639 :     const bool bCallLeaveReadWrite = CPL_TO_BOOL(EnterReadWrite(GF_Write));
    2119             : 
    2120             :     // Write block to block cache
    2121      874182 :     for (int j = 0; j < nBlocksPerColumn; ++j)
    2122             :     {
    2123     1505420 :         for (int i = 0; i < nBlocksPerRow; ++i)
    2124             :         {
    2125      899876 :             GDALRasterBlock *destBlock = GetLockedBlockRef(i, j, TRUE);
    2126      899876 :             if (destBlock == nullptr)
    2127             :             {
    2128           0 :                 ReportError(CE_Failure, CPLE_OutOfMemory,
    2129             :                             "GDALRasterBand::Fill(): Error "
    2130             :                             "while retrieving cache block.");
    2131           0 :                 VSIFree(srcBlock);
    2132           0 :                 return CE_Failure;
    2133             :             }
    2134      899876 :             memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
    2135      899876 :             destBlock->MarkDirty();
    2136      899876 :             destBlock->DropLock();
    2137             :         }
    2138             :     }
    2139             : 
    2140      268639 :     if (bCallLeaveReadWrite)
    2141      267628 :         LeaveReadWrite();
    2142             : 
    2143             :     // Free up the source block
    2144      268639 :     VSIFree(srcBlock);
    2145             : 
    2146      268639 :     return CE_None;
    2147             : }
    2148             : 
    2149             : /************************************************************************/
    2150             : /*                         GDALFillRaster()                             */
    2151             : /************************************************************************/
    2152             : 
    2153             : /**
    2154             :  * \brief Fill this band with a constant value.
    2155             :  *
    2156             :  * @see GDALRasterBand::Fill()
    2157             :  */
    2158      268582 : CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
    2159             :                                   double dfImaginaryValue)
    2160             : {
    2161      268582 :     VALIDATE_POINTER1(hBand, "GDALFillRaster", CE_Failure);
    2162             : 
    2163      268582 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2164      268582 :     return poBand->Fill(dfRealValue, dfImaginaryValue);
    2165             : }
    2166             : 
    2167             : /************************************************************************/
    2168             : /*                             GetAccess()                              */
    2169             : /************************************************************************/
    2170             : 
    2171             : /**
    2172             :  * \brief Find out if we have update permission for this band.
    2173             :  *
    2174             :  * This method is the same as the C function GDALGetRasterAccess().
    2175             :  *
    2176             :  * @return Either GA_Update or GA_ReadOnly.
    2177             :  */
    2178             : 
    2179        2907 : GDALAccess GDALRasterBand::GetAccess()
    2180             : 
    2181             : {
    2182        2907 :     return eAccess;
    2183             : }
    2184             : 
    2185             : /************************************************************************/
    2186             : /*                        GDALGetRasterAccess()                         */
    2187             : /************************************************************************/
    2188             : 
    2189             : /**
    2190             :  * \brief Find out if we have update permission for this band.
    2191             :  *
    2192             :  * @see GDALRasterBand::GetAccess()
    2193             :  */
    2194             : 
    2195        2258 : GDALAccess CPL_STDCALL GDALGetRasterAccess(GDALRasterBandH hBand)
    2196             : 
    2197             : {
    2198        2258 :     VALIDATE_POINTER1(hBand, "GDALGetRasterAccess", GA_ReadOnly);
    2199             : 
    2200        2258 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2201        2258 :     return poBand->GetAccess();
    2202             : }
    2203             : 
    2204             : /************************************************************************/
    2205             : /*                          GetCategoryNames()                          */
    2206             : /************************************************************************/
    2207             : 
    2208             : /**
    2209             :  * \brief Fetch the list of category names for this raster.
    2210             :  *
    2211             :  * The return list is a "StringList" in the sense of the CPL functions.
    2212             :  * That is a NULL terminated array of strings.  Raster values without
    2213             :  * associated names will have an empty string in the returned list.  The
    2214             :  * first entry in the list is for raster values of zero, and so on.
    2215             :  *
    2216             :  * The returned stringlist should not be altered or freed by the application.
    2217             :  * It may change on the next GDAL call, so please copy it if it is needed
    2218             :  * for any period of time.
    2219             :  *
    2220             :  * This method is the same as the C function GDALGetRasterCategoryNames().
    2221             :  *
    2222             :  * @return list of names, or NULL if none.
    2223             :  */
    2224             : 
    2225         294 : char **GDALRasterBand::GetCategoryNames()
    2226             : 
    2227             : {
    2228         294 :     return nullptr;
    2229             : }
    2230             : 
    2231             : /************************************************************************/
    2232             : /*                     GDALGetRasterCategoryNames()                     */
    2233             : /************************************************************************/
    2234             : 
    2235             : /**
    2236             :  * \brief Fetch the list of category names for this raster.
    2237             :  *
    2238             :  * @see GDALRasterBand::GetCategoryNames()
    2239             :  */
    2240             : 
    2241         191 : char **CPL_STDCALL GDALGetRasterCategoryNames(GDALRasterBandH hBand)
    2242             : 
    2243             : {
    2244         191 :     VALIDATE_POINTER1(hBand, "GDALGetRasterCategoryNames", nullptr);
    2245             : 
    2246         191 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2247         191 :     return poBand->GetCategoryNames();
    2248             : }
    2249             : 
    2250             : /************************************************************************/
    2251             : /*                          SetCategoryNames()                          */
    2252             : /************************************************************************/
    2253             : 
    2254             : /**
    2255             :  * \fn GDALRasterBand::SetCategoryNames(char**)
    2256             :  * \brief Set the category names for this band.
    2257             :  *
    2258             :  * See the GetCategoryNames() method for more on the interpretation of
    2259             :  * category names.
    2260             :  *
    2261             :  * This method is the same as the C function GDALSetRasterCategoryNames().
    2262             :  *
    2263             :  * @param papszNames the NULL terminated StringList of category names.  May
    2264             :  * be NULL to just clear the existing list.
    2265             :  *
    2266             :  * @return CE_None on success of CE_Failure on failure.  If unsupported
    2267             :  * by the driver CE_Failure is returned, but no error message is reported.
    2268             :  */
    2269             : 
    2270             : /**/
    2271             : /**/
    2272             : 
    2273           0 : CPLErr GDALRasterBand::SetCategoryNames(char ** /*papszNames*/)
    2274             : {
    2275           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2276           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2277             :                     "SetCategoryNames() not supported for this dataset.");
    2278             : 
    2279           0 :     return CE_Failure;
    2280             : }
    2281             : 
    2282             : /************************************************************************/
    2283             : /*                        GDALSetCategoryNames()                        */
    2284             : /************************************************************************/
    2285             : 
    2286             : /**
    2287             :  * \brief Set the category names for this band.
    2288             :  *
    2289             :  * @see GDALRasterBand::SetCategoryNames()
    2290             :  */
    2291             : 
    2292           2 : CPLErr CPL_STDCALL GDALSetRasterCategoryNames(GDALRasterBandH hBand,
    2293             :                                               CSLConstList papszNames)
    2294             : 
    2295             : {
    2296           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterCategoryNames", CE_Failure);
    2297             : 
    2298           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2299           2 :     return poBand->SetCategoryNames(const_cast<char **>(papszNames));
    2300             : }
    2301             : 
    2302             : /************************************************************************/
    2303             : /*                           GetNoDataValue()                           */
    2304             : /************************************************************************/
    2305             : 
    2306             : /**
    2307             :  * \brief Fetch the no data value for this band.
    2308             :  *
    2309             :  * If there is no out of data value, an out of range value will generally
    2310             :  * be returned.  The no data value for a band is generally a special marker
    2311             :  * value used to mark pixels that are not valid data.  Such pixels should
    2312             :  * generally not be displayed, nor contribute to analysis operations.
    2313             :  *
    2314             :  * The no data value returned is 'raw', meaning that it has no offset and
    2315             :  * scale applied.
    2316             :  *
    2317             :  * For rasters of type GDT_Int64 or GDT_UInt64, using this method might be
    2318             :  * lossy if the nodata value cannot exactly been represented by a double.
    2319             :  * Use GetNoDataValueAsInt64() or GetNoDataValueAsUInt64() instead.
    2320             :  *
    2321             :  * This method is the same as the C function GDALGetRasterNoDataValue().
    2322             :  *
    2323             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2324             :  * is actually associated with this layer.  May be NULL (default).
    2325             :  *
    2326             :  * @return the nodata value for this band.
    2327             :  */
    2328             : 
    2329       31573 : double GDALRasterBand::GetNoDataValue(int *pbSuccess)
    2330             : 
    2331             : {
    2332       31573 :     if (pbSuccess != nullptr)
    2333       31573 :         *pbSuccess = FALSE;
    2334             : 
    2335       31573 :     return -1e10;
    2336             : }
    2337             : 
    2338             : /************************************************************************/
    2339             : /*                      GDALGetRasterNoDataValue()                      */
    2340             : /************************************************************************/
    2341             : 
    2342             : /**
    2343             :  * \brief Fetch the no data value for this band.
    2344             :  *
    2345             :  * @see GDALRasterBand::GetNoDataValue()
    2346             :  */
    2347             : 
    2348      414251 : double CPL_STDCALL GDALGetRasterNoDataValue(GDALRasterBandH hBand,
    2349             :                                             int *pbSuccess)
    2350             : 
    2351             : {
    2352      414251 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValue", 0);
    2353             : 
    2354      414251 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2355      414251 :     return poBand->GetNoDataValue(pbSuccess);
    2356             : }
    2357             : 
    2358             : /************************************************************************/
    2359             : /*                       GetNoDataValueAsInt64()                        */
    2360             : /************************************************************************/
    2361             : 
    2362             : /**
    2363             :  * \brief Fetch the no data value for this band.
    2364             :  *
    2365             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2366             :  *
    2367             :  * If there is no out of data value, an out of range value will generally
    2368             :  * be returned.  The no data value for a band is generally a special marker
    2369             :  * value used to mark pixels that are not valid data.  Such pixels should
    2370             :  * generally not be displayed, nor contribute to analysis operations.
    2371             :  *
    2372             :  * The no data value returned is 'raw', meaning that it has no offset and
    2373             :  * scale applied.
    2374             :  *
    2375             :  * This method is the same as the C function GDALGetRasterNoDataValueAsInt64().
    2376             :  *
    2377             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2378             :  * is actually associated with this layer.  May be NULL (default).
    2379             :  *
    2380             :  * @return the nodata value for this band.
    2381             :  *
    2382             :  * @since GDAL 3.5
    2383             :  */
    2384             : 
    2385           4 : int64_t GDALRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    2386             : 
    2387             : {
    2388           4 :     if (pbSuccess != nullptr)
    2389           4 :         *pbSuccess = FALSE;
    2390             : 
    2391           4 :     return std::numeric_limits<int64_t>::min();
    2392             : }
    2393             : 
    2394             : /************************************************************************/
    2395             : /*                   GDALGetRasterNoDataValueAsInt64()                  */
    2396             : /************************************************************************/
    2397             : 
    2398             : /**
    2399             :  * \brief Fetch the no data value for this band.
    2400             :  *
    2401             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2402             :  *
    2403             :  * @see GDALRasterBand::GetNoDataValueAsInt64()
    2404             :  *
    2405             :  * @since GDAL 3.5
    2406             :  */
    2407             : 
    2408          27 : int64_t CPL_STDCALL GDALGetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2409             :                                                     int *pbSuccess)
    2410             : 
    2411             : {
    2412          27 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsInt64",
    2413             :                       std::numeric_limits<int64_t>::min());
    2414             : 
    2415          27 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2416          27 :     return poBand->GetNoDataValueAsInt64(pbSuccess);
    2417             : }
    2418             : 
    2419             : /************************************************************************/
    2420             : /*                       GetNoDataValueAsUInt64()                        */
    2421             : /************************************************************************/
    2422             : 
    2423             : /**
    2424             :  * \brief Fetch the no data value for this band.
    2425             :  *
    2426             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2427             :  *
    2428             :  * If there is no out of data value, an out of range value will generally
    2429             :  * be returned.  The no data value for a band is generally a special marker
    2430             :  * value used to mark pixels that are not valid data.  Such pixels should
    2431             :  * generally not be displayed, nor contribute to analysis operations.
    2432             :  *
    2433             :  * The no data value returned is 'raw', meaning that it has no offset and
    2434             :  * scale applied.
    2435             :  *
    2436             :  * This method is the same as the C function GDALGetRasterNoDataValueAsUInt64().
    2437             :  *
    2438             :  * @param pbSuccess pointer to a boolean to use to indicate if a value
    2439             :  * is actually associated with this layer.  May be NULL (default).
    2440             :  *
    2441             :  * @return the nodata value for this band.
    2442             :  *
    2443             :  * @since GDAL 3.5
    2444             :  */
    2445             : 
    2446           3 : uint64_t GDALRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    2447             : 
    2448             : {
    2449           3 :     if (pbSuccess != nullptr)
    2450           3 :         *pbSuccess = FALSE;
    2451             : 
    2452           3 :     return std::numeric_limits<uint64_t>::max();
    2453             : }
    2454             : 
    2455             : /************************************************************************/
    2456             : /*                   GDALGetRasterNoDataValueAsUInt64()                  */
    2457             : /************************************************************************/
    2458             : 
    2459             : /**
    2460             :  * \brief Fetch the no data value for this band.
    2461             :  *
    2462             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2463             :  *
    2464             :  * @see GDALRasterBand::GetNoDataValueAsUInt64()
    2465             :  *
    2466             :  * @since GDAL 3.5
    2467             :  */
    2468             : 
    2469          18 : uint64_t CPL_STDCALL GDALGetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2470             :                                                       int *pbSuccess)
    2471             : 
    2472             : {
    2473          18 :     VALIDATE_POINTER1(hBand, "GDALGetRasterNoDataValueAsUInt64",
    2474             :                       std::numeric_limits<uint64_t>::max());
    2475             : 
    2476          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2477          18 :     return poBand->GetNoDataValueAsUInt64(pbSuccess);
    2478             : }
    2479             : 
    2480             : /************************************************************************/
    2481             : /*                        SetNoDataValueAsString()                      */
    2482             : /************************************************************************/
    2483             : 
    2484             : /**
    2485             :  * \brief Set the no data value for this band.
    2486             :  *
    2487             :  * Depending on drivers, changing the no data value may or may not have an
    2488             :  * effect on the pixel values of a raster that has just been created. It is
    2489             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2490             :  * the raster to the nodata value.
    2491             :  * In any case, changing an existing no data value, when one already exists and
    2492             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2493             :  * value matched the previous nodata value.
    2494             :  *
    2495             :  * To clear the nodata value, use DeleteNoDataValue().
    2496             :  *
    2497             :  * @param pszNoData the value to set.
    2498             :  * @param[out] pbCannotBeExactlyRepresented Pointer to a boolean, or nullptr.
    2499             :  *             If the value cannot be exactly represented on the output data
    2500             :  *             type, *pbCannotBeExactlyRepresented will be set to true.
    2501             :  *
    2502             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2503             :  * by the driver, CE_Failure is returned but no error message will have
    2504             :  * been emitted.
    2505             :  *
    2506             :  * @since 3.11
    2507             :  */
    2508             : 
    2509             : CPLErr
    2510         123 : GDALRasterBand::SetNoDataValueAsString(const char *pszNoData,
    2511             :                                        bool *pbCannotBeExactlyRepresented)
    2512             : {
    2513         123 :     if (pbCannotBeExactlyRepresented)
    2514         123 :         *pbCannotBeExactlyRepresented = false;
    2515         123 :     if (eDataType == GDT_Int64)
    2516             :     {
    2517           8 :         if (strchr(pszNoData, '.') ||
    2518           3 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2519             :         {
    2520           2 :             char *endptr = nullptr;
    2521           2 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2522           4 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2523           2 :                 GDALIsValueExactAs<int64_t>(dfVal))
    2524             :             {
    2525           0 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(dfVal));
    2526             :             }
    2527             :         }
    2528             :         else
    2529             :         {
    2530             :             try
    2531             :             {
    2532           7 :                 const auto val = std::stoll(pszNoData);
    2533           1 :                 return SetNoDataValueAsInt64(static_cast<int64_t>(val));
    2534             :             }
    2535           2 :             catch (const std::exception &)
    2536             :             {
    2537             :             }
    2538             :         }
    2539             :     }
    2540         118 :     else if (eDataType == GDT_UInt64)
    2541             :     {
    2542           2 :         if (strchr(pszNoData, '.') ||
    2543           1 :             CPLGetValueType(pszNoData) == CPL_VALUE_STRING)
    2544             :         {
    2545           0 :             char *endptr = nullptr;
    2546           0 :             const double dfVal = CPLStrtod(pszNoData, &endptr);
    2547           0 :             if (endptr == pszNoData + strlen(pszNoData) &&
    2548           0 :                 GDALIsValueExactAs<uint64_t>(dfVal))
    2549             :             {
    2550           0 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(dfVal));
    2551             :             }
    2552             :         }
    2553             :         else
    2554             :         {
    2555             :             try
    2556             :             {
    2557           1 :                 const auto val = std::stoull(pszNoData);
    2558           1 :                 return SetNoDataValueAsUInt64(static_cast<uint64_t>(val));
    2559             :             }
    2560           0 :             catch (const std::exception &)
    2561             :             {
    2562             :             }
    2563             :         }
    2564             :     }
    2565         117 :     else if (eDataType == GDT_Float32)
    2566             :     {
    2567          10 :         char *endptr = nullptr;
    2568          10 :         const float fVal = CPLStrtof(pszNoData, &endptr);
    2569          10 :         if (endptr == pszNoData + strlen(pszNoData))
    2570             :         {
    2571          10 :             return SetNoDataValue(fVal);
    2572             :         }
    2573             :     }
    2574             :     else
    2575             :     {
    2576         107 :         char *endptr = nullptr;
    2577         107 :         const double dfVal = CPLStrtod(pszNoData, &endptr);
    2578         214 :         if (endptr == pszNoData + strlen(pszNoData) &&
    2579         107 :             GDALIsValueExactAs(dfVal, eDataType))
    2580             :         {
    2581         106 :             return SetNoDataValue(dfVal);
    2582             :         }
    2583             :     }
    2584           5 :     if (pbCannotBeExactlyRepresented)
    2585           5 :         *pbCannotBeExactlyRepresented = true;
    2586           5 :     return CE_Failure;
    2587             : }
    2588             : 
    2589             : /************************************************************************/
    2590             : /*                           SetNoDataValue()                           */
    2591             : /************************************************************************/
    2592             : 
    2593             : /**
    2594             :  * \fn GDALRasterBand::SetNoDataValue(double)
    2595             :  * \brief Set the no data value for this band.
    2596             :  *
    2597             :  * Depending on drivers, changing the no data value may or may not have an
    2598             :  * effect on the pixel values of a raster that has just been created. It is
    2599             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2600             :  * the raster to the nodata value.
    2601             :  * In any case, changing an existing no data value, when one already exists and
    2602             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2603             :  * value matched the previous nodata value.
    2604             :  *
    2605             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2606             :  * be represented by a double, use SetNoDataValueAsInt64() or
    2607             :  * SetNoDataValueAsUInt64() instead.
    2608             :  *
    2609             :  * To clear the nodata value, use DeleteNoDataValue().
    2610             :  *
    2611             :  * This method is the same as the C function GDALSetRasterNoDataValue().
    2612             :  *
    2613             :  * @param dfNoData the value to set.
    2614             :  *
    2615             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2616             :  * by the driver, CE_Failure is returned but no error message will have
    2617             :  * been emitted.
    2618             :  */
    2619             : 
    2620             : /**/
    2621             : /**/
    2622             : 
    2623           0 : CPLErr GDALRasterBand::SetNoDataValue(double /*dfNoData*/)
    2624             : 
    2625             : {
    2626           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2627           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2628             :                     "SetNoDataValue() not supported for this dataset.");
    2629             : 
    2630           0 :     return CE_Failure;
    2631             : }
    2632             : 
    2633             : /************************************************************************/
    2634             : /*                         GDALSetRasterNoDataValue()                   */
    2635             : /************************************************************************/
    2636             : 
    2637             : /**
    2638             :  * \brief Set the no data value for this band.
    2639             :  *
    2640             :  * Depending on drivers, changing the no data value may or may not have an
    2641             :  * effect on the pixel values of a raster that has just been created. It is
    2642             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2643             :  * the raster to the nodata value.
    2644             :  * In any case, changing an existing no data value, when one already exists and
    2645             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2646             :  * value matched the previous nodata value.
    2647             :  *
    2648             :  * For rasters of type GDT_Int64 or GDT_UInt64, whose nodata value cannot always
    2649             :  * be represented by a double, use GDALSetRasterNoDataValueAsInt64() or
    2650             :  * GDALSetRasterNoDataValueAsUInt64() instead.
    2651             :  *
    2652             :  * @see GDALRasterBand::SetNoDataValue()
    2653             :  */
    2654             : 
    2655         850 : CPLErr CPL_STDCALL GDALSetRasterNoDataValue(GDALRasterBandH hBand,
    2656             :                                             double dfValue)
    2657             : 
    2658             : {
    2659         850 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValue", CE_Failure);
    2660             : 
    2661         850 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2662         850 :     return poBand->SetNoDataValue(dfValue);
    2663             : }
    2664             : 
    2665             : /************************************************************************/
    2666             : /*                       SetNoDataValueAsInt64()                        */
    2667             : /************************************************************************/
    2668             : 
    2669             : /**
    2670             :  * \brief Set the no data value for this band.
    2671             :  *
    2672             :  * This method should ONLY be called on rasters whose data type is GDT_Int64.
    2673             :  *
    2674             :  * Depending on drivers, changing the no data value may or may not have an
    2675             :  * effect on the pixel values of a raster that has just been created. It is
    2676             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2677             :  * the raster to the nodata value.
    2678             :  * In ay case, changing an existing no data value, when one already exists and
    2679             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2680             :  * value matched the previous nodata value.
    2681             :  *
    2682             :  * To clear the nodata value, use DeleteNoDataValue().
    2683             :  *
    2684             :  * This method is the same as the C function GDALSetRasterNoDataValueAsInt64().
    2685             :  *
    2686             :  * @param nNoDataValue the value to set.
    2687             :  *
    2688             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2689             :  * by the driver, CE_Failure is returned but no error message will have
    2690             :  * been emitted.
    2691             :  *
    2692             :  * @since GDAL 3.5
    2693             :  */
    2694             : 
    2695           0 : CPLErr GDALRasterBand::SetNoDataValueAsInt64(CPL_UNUSED int64_t nNoDataValue)
    2696             : 
    2697             : {
    2698           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2699           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2700             :                     "SetNoDataValueAsInt64() not supported for this dataset.");
    2701             : 
    2702           0 :     return CE_Failure;
    2703             : }
    2704             : 
    2705             : /************************************************************************/
    2706             : /*                 GDALSetRasterNoDataValueAsInt64()                    */
    2707             : /************************************************************************/
    2708             : 
    2709             : /**
    2710             :  * \brief Set the no data value for this band.
    2711             :  *
    2712             :  * This function should ONLY be called on rasters whose data type is GDT_Int64.
    2713             :  *
    2714             :  * Depending on drivers, changing the no data value may or may not have an
    2715             :  * effect on the pixel values of a raster that has just been created. It is
    2716             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2717             :  * the raster to the nodata value.
    2718             :  * In ay case, changing an existing no data value, when one already exists and
    2719             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2720             :  * value matched the previous nodata value.
    2721             :  *
    2722             :  * @see GDALRasterBand::SetNoDataValueAsInt64()
    2723             :  *
    2724             :  * @since GDAL 3.5
    2725             :  */
    2726             : 
    2727          20 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsInt64(GDALRasterBandH hBand,
    2728             :                                                    int64_t nValue)
    2729             : 
    2730             : {
    2731          20 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsInt64", CE_Failure);
    2732             : 
    2733          20 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2734          20 :     return poBand->SetNoDataValueAsInt64(nValue);
    2735             : }
    2736             : 
    2737             : /************************************************************************/
    2738             : /*                       SetNoDataValueAsUInt64()                       */
    2739             : /************************************************************************/
    2740             : 
    2741             : /**
    2742             :  * \brief Set the no data value for this band.
    2743             :  *
    2744             :  * This method should ONLY be called on rasters whose data type is GDT_UInt64.
    2745             :  *
    2746             :  * Depending on drivers, changing the no data value may or may not have an
    2747             :  * effect on the pixel values of a raster that has just been created. It is
    2748             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2749             :  * the raster to the nodata value.
    2750             :  * In ay case, changing an existing no data value, when one already exists and
    2751             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2752             :  * value matched the previous nodata value.
    2753             :  *
    2754             :  * To clear the nodata value, use DeleteNoDataValue().
    2755             :  *
    2756             :  * This method is the same as the C function GDALSetRasterNoDataValueAsUInt64().
    2757             :  *
    2758             :  * @param nNoDataValue the value to set.
    2759             :  *
    2760             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2761             :  * by the driver, CE_Failure is returned but no error message will have
    2762             :  * been emitted.
    2763             :  *
    2764             :  * @since GDAL 3.5
    2765             :  */
    2766             : 
    2767           0 : CPLErr GDALRasterBand::SetNoDataValueAsUInt64(CPL_UNUSED uint64_t nNoDataValue)
    2768             : 
    2769             : {
    2770           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2771           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2772             :                     "SetNoDataValueAsUInt64() not supported for this dataset.");
    2773             : 
    2774           0 :     return CE_Failure;
    2775             : }
    2776             : 
    2777             : /************************************************************************/
    2778             : /*                 GDALSetRasterNoDataValueAsUInt64()                    */
    2779             : /************************************************************************/
    2780             : 
    2781             : /**
    2782             :  * \brief Set the no data value for this band.
    2783             :  *
    2784             :  * This function should ONLY be called on rasters whose data type is GDT_UInt64.
    2785             :  *
    2786             :  * Depending on drivers, changing the no data value may or may not have an
    2787             :  * effect on the pixel values of a raster that has just been created. It is
    2788             :  * thus advised to explicitly called Fill() if the intent is to initialize
    2789             :  * the raster to the nodata value.
    2790             :  * In ay case, changing an existing no data value, when one already exists and
    2791             :  * the dataset exists or has been initialized, has no effect on the pixel whose
    2792             :  * value matched the previous nodata value.
    2793             :  *
    2794             :  * @see GDALRasterBand::SetNoDataValueAsUInt64()
    2795             :  *
    2796             :  * @since GDAL 3.5
    2797             :  */
    2798             : 
    2799          18 : CPLErr CPL_STDCALL GDALSetRasterNoDataValueAsUInt64(GDALRasterBandH hBand,
    2800             :                                                     uint64_t nValue)
    2801             : 
    2802             : {
    2803          18 :     VALIDATE_POINTER1(hBand, "GDALSetRasterNoDataValueAsUInt64", CE_Failure);
    2804             : 
    2805          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2806          18 :     return poBand->SetNoDataValueAsUInt64(nValue);
    2807             : }
    2808             : 
    2809             : /************************************************************************/
    2810             : /*                        DeleteNoDataValue()                           */
    2811             : /************************************************************************/
    2812             : 
    2813             : /**
    2814             :  * \brief Remove the no data value for this band.
    2815             :  *
    2816             :  * This method is the same as the C function GDALDeleteRasterNoDataValue().
    2817             :  *
    2818             :  * @return CE_None on success, or CE_Failure on failure.  If unsupported
    2819             :  * by the driver, CE_Failure is returned but no error message will have
    2820             :  * been emitted.
    2821             :  *
    2822             :  * @since GDAL 2.1
    2823             :  */
    2824             : 
    2825           0 : CPLErr GDALRasterBand::DeleteNoDataValue()
    2826             : 
    2827             : {
    2828           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    2829           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    2830             :                     "DeleteNoDataValue() not supported for this dataset.");
    2831             : 
    2832           0 :     return CE_Failure;
    2833             : }
    2834             : 
    2835             : /************************************************************************/
    2836             : /*                       GDALDeleteRasterNoDataValue()                  */
    2837             : /************************************************************************/
    2838             : 
    2839             : /**
    2840             :  * \brief Remove the no data value for this band.
    2841             :  *
    2842             :  * @see GDALRasterBand::DeleteNoDataValue()
    2843             :  *
    2844             :  * @since GDAL 2.1
    2845             :  */
    2846             : 
    2847          53 : CPLErr CPL_STDCALL GDALDeleteRasterNoDataValue(GDALRasterBandH hBand)
    2848             : 
    2849             : {
    2850          53 :     VALIDATE_POINTER1(hBand, "GDALDeleteRasterNoDataValue", CE_Failure);
    2851             : 
    2852          53 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2853          53 :     return poBand->DeleteNoDataValue();
    2854             : }
    2855             : 
    2856             : /************************************************************************/
    2857             : /*                             GetMaximum()                             */
    2858             : /************************************************************************/
    2859             : 
    2860             : /**
    2861             :  * \brief Fetch the maximum value for this band.
    2862             :  *
    2863             :  * For file formats that don't know this intrinsically, the maximum supported
    2864             :  * value for the data type will generally be returned.
    2865             :  *
    2866             :  * This method is the same as the C function GDALGetRasterMaximum().
    2867             :  *
    2868             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2869             :  * returned value is a tight maximum or not.  May be NULL (default).
    2870             :  *
    2871             :  * @return the maximum raster value (excluding no data pixels)
    2872             :  */
    2873             : 
    2874         525 : double GDALRasterBand::GetMaximum(int *pbSuccess)
    2875             : 
    2876             : {
    2877         525 :     const char *pszValue = nullptr;
    2878             : 
    2879         525 :     if ((pszValue = GetMetadataItem("STATISTICS_MAXIMUM")) != nullptr)
    2880             :     {
    2881          47 :         if (pbSuccess != nullptr)
    2882          42 :             *pbSuccess = TRUE;
    2883             : 
    2884          47 :         return CPLAtofM(pszValue);
    2885             :     }
    2886             : 
    2887         478 :     if (pbSuccess != nullptr)
    2888         474 :         *pbSuccess = FALSE;
    2889             : 
    2890         478 :     switch (eDataType)
    2891             :     {
    2892         327 :         case GDT_Byte:
    2893             :         {
    2894         327 :             EnablePixelTypeSignedByteWarning(false);
    2895             :             const char *pszPixelType =
    2896         327 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    2897         327 :             EnablePixelTypeSignedByteWarning(true);
    2898         327 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    2899           0 :                 return 127;
    2900             : 
    2901         327 :             return 255;
    2902             :         }
    2903             : 
    2904           1 :         case GDT_Int8:
    2905           1 :             return 127;
    2906             : 
    2907          21 :         case GDT_UInt16:
    2908          21 :             return 65535;
    2909             : 
    2910          24 :         case GDT_Int16:
    2911             :         case GDT_CInt16:
    2912          24 :             return 32767;
    2913             : 
    2914          39 :         case GDT_Int32:
    2915             :         case GDT_CInt32:
    2916          39 :             return 2147483647.0;
    2917             : 
    2918          12 :         case GDT_UInt32:
    2919          12 :             return 4294967295.0;
    2920             : 
    2921           1 :         case GDT_Int64:
    2922           1 :             return static_cast<double>(std::numeric_limits<GInt64>::max());
    2923             : 
    2924           1 :         case GDT_UInt64:
    2925           1 :             return static_cast<double>(std::numeric_limits<GUInt64>::max());
    2926             : 
    2927           0 :         case GDT_Float16:
    2928             :         case GDT_CFloat16:
    2929           0 :             return 65504.0;
    2930             : 
    2931          30 :         case GDT_Float32:
    2932             :         case GDT_CFloat32:
    2933          30 :             return 4294967295.0;  // Not actually accurate.
    2934             : 
    2935          22 :         case GDT_Float64:
    2936             :         case GDT_CFloat64:
    2937          22 :             return 4294967295.0;  // Not actually accurate.
    2938             : 
    2939           0 :         case GDT_Unknown:
    2940             :         case GDT_TypeCount:
    2941           0 :             break;
    2942             :     }
    2943           0 :     return 4294967295.0;  // Not actually accurate.
    2944             : }
    2945             : 
    2946             : /************************************************************************/
    2947             : /*                        GDALGetRasterMaximum()                        */
    2948             : /************************************************************************/
    2949             : 
    2950             : /**
    2951             :  * \brief Fetch the maximum value for this band.
    2952             :  *
    2953             :  * @see GDALRasterBand::GetMaximum()
    2954             :  */
    2955             : 
    2956         289 : double CPL_STDCALL GDALGetRasterMaximum(GDALRasterBandH hBand, int *pbSuccess)
    2957             : 
    2958             : {
    2959         289 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMaximum", 0);
    2960             : 
    2961         289 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    2962         289 :     return poBand->GetMaximum(pbSuccess);
    2963             : }
    2964             : 
    2965             : /************************************************************************/
    2966             : /*                             GetMinimum()                             */
    2967             : /************************************************************************/
    2968             : 
    2969             : /**
    2970             :  * \brief Fetch the minimum value for this band.
    2971             :  *
    2972             :  * For file formats that don't know this intrinsically, the minimum supported
    2973             :  * value for the data type will generally be returned.
    2974             :  *
    2975             :  * This method is the same as the C function GDALGetRasterMinimum().
    2976             :  *
    2977             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    2978             :  * returned value is a tight minimum or not.  May be NULL (default).
    2979             :  *
    2980             :  * @return the minimum raster value (excluding no data pixels)
    2981             :  */
    2982             : 
    2983         533 : double GDALRasterBand::GetMinimum(int *pbSuccess)
    2984             : 
    2985             : {
    2986         533 :     const char *pszValue = nullptr;
    2987             : 
    2988         533 :     if ((pszValue = GetMetadataItem("STATISTICS_MINIMUM")) != nullptr)
    2989             :     {
    2990          52 :         if (pbSuccess != nullptr)
    2991          47 :             *pbSuccess = TRUE;
    2992             : 
    2993          52 :         return CPLAtofM(pszValue);
    2994             :     }
    2995             : 
    2996         481 :     if (pbSuccess != nullptr)
    2997         477 :         *pbSuccess = FALSE;
    2998             : 
    2999         481 :     switch (eDataType)
    3000             :     {
    3001         330 :         case GDT_Byte:
    3002             :         {
    3003         330 :             EnablePixelTypeSignedByteWarning(false);
    3004             :             const char *pszPixelType =
    3005         330 :                 GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    3006         330 :             EnablePixelTypeSignedByteWarning(true);
    3007         330 :             if (pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE"))
    3008           0 :                 return -128;
    3009             : 
    3010         330 :             return 0;
    3011             :         }
    3012             : 
    3013           1 :         case GDT_Int8:
    3014           1 :             return -128;
    3015             :             break;
    3016             : 
    3017          21 :         case GDT_UInt16:
    3018          21 :             return 0;
    3019             : 
    3020          24 :         case GDT_Int16:
    3021             :         case GDT_CInt16:
    3022          24 :             return -32768;
    3023             : 
    3024          39 :         case GDT_Int32:
    3025             :         case GDT_CInt32:
    3026          39 :             return -2147483648.0;
    3027             : 
    3028          12 :         case GDT_UInt32:
    3029          12 :             return 0;
    3030             : 
    3031           1 :         case GDT_Int64:
    3032           1 :             return static_cast<double>(std::numeric_limits<GInt64>::lowest());
    3033             : 
    3034           1 :         case GDT_UInt64:
    3035           1 :             return 0;
    3036             : 
    3037           0 :         case GDT_Float16:
    3038             :         case GDT_CFloat16:
    3039           0 :             return -65504.0;
    3040             : 
    3041          30 :         case GDT_Float32:
    3042             :         case GDT_CFloat32:
    3043          30 :             return -4294967295.0;  // Not actually accurate.
    3044             : 
    3045          22 :         case GDT_Float64:
    3046             :         case GDT_CFloat64:
    3047          22 :             return -4294967295.0;  // Not actually accurate.
    3048             : 
    3049           0 :         case GDT_Unknown:
    3050             :         case GDT_TypeCount:
    3051           0 :             break;
    3052             :     }
    3053           0 :     return -4294967295.0;  // Not actually accurate.
    3054             : }
    3055             : 
    3056             : /************************************************************************/
    3057             : /*                        GDALGetRasterMinimum()                        */
    3058             : /************************************************************************/
    3059             : 
    3060             : /**
    3061             :  * \brief Fetch the minimum value for this band.
    3062             :  *
    3063             :  * @see GDALRasterBand::GetMinimum()
    3064             :  */
    3065             : 
    3066         299 : double CPL_STDCALL GDALGetRasterMinimum(GDALRasterBandH hBand, int *pbSuccess)
    3067             : 
    3068             : {
    3069         299 :     VALIDATE_POINTER1(hBand, "GDALGetRasterMinimum", 0);
    3070             : 
    3071         299 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3072         299 :     return poBand->GetMinimum(pbSuccess);
    3073             : }
    3074             : 
    3075             : /************************************************************************/
    3076             : /*                       GetColorInterpretation()                       */
    3077             : /************************************************************************/
    3078             : 
    3079             : /**
    3080             :  * \brief How should this band be interpreted as color?
    3081             :  *
    3082             :  * GCI_Undefined is returned when the format doesn't know anything
    3083             :  * about the color interpretation.
    3084             :  *
    3085             :  * This method is the same as the C function
    3086             :  * GDALGetRasterColorInterpretation().
    3087             :  *
    3088             :  * @return color interpretation value for band.
    3089             :  */
    3090             : 
    3091         163 : GDALColorInterp GDALRasterBand::GetColorInterpretation()
    3092             : 
    3093             : {
    3094         163 :     return GCI_Undefined;
    3095             : }
    3096             : 
    3097             : /************************************************************************/
    3098             : /*                  GDALGetRasterColorInterpretation()                  */
    3099             : /************************************************************************/
    3100             : 
    3101             : /**
    3102             :  * \brief How should this band be interpreted as color?
    3103             :  *
    3104             :  * @see GDALRasterBand::GetColorInterpretation()
    3105             :  */
    3106             : 
    3107             : GDALColorInterp CPL_STDCALL
    3108        5456 : GDALGetRasterColorInterpretation(GDALRasterBandH hBand)
    3109             : 
    3110             : {
    3111        5456 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorInterpretation", GCI_Undefined);
    3112             : 
    3113        5456 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3114        5456 :     return poBand->GetColorInterpretation();
    3115             : }
    3116             : 
    3117             : /************************************************************************/
    3118             : /*                       SetColorInterpretation()                       */
    3119             : /************************************************************************/
    3120             : 
    3121             : /**
    3122             :  * \fn GDALRasterBand::SetColorInterpretation(GDALColorInterp)
    3123             :  * \brief Set color interpretation of a band.
    3124             :  *
    3125             :  * This method is the same as the C function GDALSetRasterColorInterpretation().
    3126             :  *
    3127             :  * @param eColorInterp the new color interpretation to apply to this band.
    3128             :  *
    3129             :  * @return CE_None on success or CE_Failure if method is unsupported by format.
    3130             :  */
    3131             : 
    3132             : /**/
    3133             : /**/
    3134             : 
    3135           3 : CPLErr GDALRasterBand::SetColorInterpretation(GDALColorInterp /*eColorInterp*/)
    3136             : 
    3137             : {
    3138           3 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3139           3 :         ReportError(CE_Failure, CPLE_NotSupported,
    3140             :                     "SetColorInterpretation() not supported for this dataset.");
    3141           3 :     return CE_Failure;
    3142             : }
    3143             : 
    3144             : /************************************************************************/
    3145             : /*                  GDALSetRasterColorInterpretation()                  */
    3146             : /************************************************************************/
    3147             : 
    3148             : /**
    3149             :  * \brief Set color interpretation of a band.
    3150             :  *
    3151             :  * @see GDALRasterBand::SetColorInterpretation()
    3152             :  */
    3153             : 
    3154        1831 : CPLErr CPL_STDCALL GDALSetRasterColorInterpretation(
    3155             :     GDALRasterBandH hBand, GDALColorInterp eColorInterp)
    3156             : 
    3157             : {
    3158        1831 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorInterpretation", CE_Failure);
    3159             : 
    3160        1831 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3161        1831 :     return poBand->SetColorInterpretation(eColorInterp);
    3162             : }
    3163             : 
    3164             : /************************************************************************/
    3165             : /*                           GetColorTable()                            */
    3166             : /************************************************************************/
    3167             : 
    3168             : /**
    3169             :  * \brief Fetch the color table associated with band.
    3170             :  *
    3171             :  * If there is no associated color table, the return result is NULL.  The
    3172             :  * returned color table remains owned by the GDALRasterBand, and can't
    3173             :  * be depended on for long, nor should it ever be modified by the caller.
    3174             :  *
    3175             :  * This method is the same as the C function GDALGetRasterColorTable().
    3176             :  *
    3177             :  * @return internal color table, or NULL.
    3178             :  */
    3179             : 
    3180         231 : GDALColorTable *GDALRasterBand::GetColorTable()
    3181             : 
    3182             : {
    3183         231 :     return nullptr;
    3184             : }
    3185             : 
    3186             : /************************************************************************/
    3187             : /*                      GDALGetRasterColorTable()                       */
    3188             : /************************************************************************/
    3189             : 
    3190             : /**
    3191             :  * \brief Fetch the color table associated with band.
    3192             :  *
    3193             :  * @see GDALRasterBand::GetColorTable()
    3194             :  */
    3195             : 
    3196        1893 : GDALColorTableH CPL_STDCALL GDALGetRasterColorTable(GDALRasterBandH hBand)
    3197             : 
    3198             : {
    3199        1893 :     VALIDATE_POINTER1(hBand, "GDALGetRasterColorTable", nullptr);
    3200             : 
    3201        1893 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3202        1893 :     return GDALColorTable::ToHandle(poBand->GetColorTable());
    3203             : }
    3204             : 
    3205             : /************************************************************************/
    3206             : /*                           SetColorTable()                            */
    3207             : /************************************************************************/
    3208             : 
    3209             : /**
    3210             :  * \fn GDALRasterBand::SetColorTable(GDALColorTable*)
    3211             :  * \brief Set the raster color table.
    3212             :  *
    3213             :  * The driver will make a copy of all desired data in the colortable.  It
    3214             :  * remains owned by the caller after the call.
    3215             :  *
    3216             :  * This method is the same as the C function GDALSetRasterColorTable().
    3217             :  *
    3218             :  * @param poCT the color table to apply.  This may be NULL to clear the color
    3219             :  * table (where supported).
    3220             :  *
    3221             :  * @return CE_None on success, or CE_Failure on failure.  If the action is
    3222             :  * unsupported by the driver, a value of CE_Failure is returned, but no
    3223             :  * error is issued.
    3224             :  */
    3225             : 
    3226             : /**/
    3227             : /**/
    3228             : 
    3229           0 : CPLErr GDALRasterBand::SetColorTable(GDALColorTable * /*poCT*/)
    3230             : 
    3231             : {
    3232           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3233           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3234             :                     "SetColorTable() not supported for this dataset.");
    3235           0 :     return CE_Failure;
    3236             : }
    3237             : 
    3238             : /************************************************************************/
    3239             : /*                      GDALSetRasterColorTable()                       */
    3240             : /************************************************************************/
    3241             : 
    3242             : /**
    3243             :  * \brief Set the raster color table.
    3244             :  *
    3245             :  * @see GDALRasterBand::SetColorTable()
    3246             :  */
    3247             : 
    3248          78 : CPLErr CPL_STDCALL GDALSetRasterColorTable(GDALRasterBandH hBand,
    3249             :                                            GDALColorTableH hCT)
    3250             : 
    3251             : {
    3252          78 :     VALIDATE_POINTER1(hBand, "GDALSetRasterColorTable", CE_Failure);
    3253             : 
    3254          78 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3255          78 :     return poBand->SetColorTable(GDALColorTable::FromHandle(hCT));
    3256             : }
    3257             : 
    3258             : /************************************************************************/
    3259             : /*                       HasArbitraryOverviews()                        */
    3260             : /************************************************************************/
    3261             : 
    3262             : /**
    3263             :  * \brief Check for arbitrary overviews.
    3264             :  *
    3265             :  * This returns TRUE if the underlying datastore can compute arbitrary
    3266             :  * overviews efficiently, such as is the case with OGDI over a network.
    3267             :  * Datastores with arbitrary overviews don't generally have any fixed
    3268             :  * overviews, but the RasterIO() method can be used in downsampling mode
    3269             :  * to get overview data efficiently.
    3270             :  *
    3271             :  * This method is the same as the C function GDALHasArbitraryOverviews(),
    3272             :  *
    3273             :  * @return TRUE if arbitrary overviews available (efficiently), otherwise
    3274             :  * FALSE.
    3275             :  */
    3276             : 
    3277         260 : int GDALRasterBand::HasArbitraryOverviews()
    3278             : 
    3279             : {
    3280         260 :     return FALSE;
    3281             : }
    3282             : 
    3283             : /************************************************************************/
    3284             : /*                     GDALHasArbitraryOverviews()                      */
    3285             : /************************************************************************/
    3286             : 
    3287             : /**
    3288             :  * \brief Check for arbitrary overviews.
    3289             :  *
    3290             :  * @see GDALRasterBand::HasArbitraryOverviews()
    3291             :  */
    3292             : 
    3293         181 : int CPL_STDCALL GDALHasArbitraryOverviews(GDALRasterBandH hBand)
    3294             : 
    3295             : {
    3296         181 :     VALIDATE_POINTER1(hBand, "GDALHasArbitraryOverviews", 0);
    3297             : 
    3298         181 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3299         181 :     return poBand->HasArbitraryOverviews();
    3300             : }
    3301             : 
    3302             : /************************************************************************/
    3303             : /*                          GetOverviewCount()                          */
    3304             : /************************************************************************/
    3305             : 
    3306             : /**
    3307             :  * \brief Return the number of overview layers available.
    3308             :  *
    3309             :  * This method is the same as the C function GDALGetOverviewCount().
    3310             :  *
    3311             :  * @return overview count, zero if none.
    3312             :  */
    3313             : 
    3314     1065940 : int GDALRasterBand::GetOverviewCount()
    3315             : 
    3316             : {
    3317     1722450 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3318      656515 :         poDS->AreOverviewsEnabled())
    3319      656515 :         return poDS->oOvManager.GetOverviewCount(nBand);
    3320             : 
    3321      409424 :     return 0;
    3322             : }
    3323             : 
    3324             : /************************************************************************/
    3325             : /*                        GDALGetOverviewCount()                        */
    3326             : /************************************************************************/
    3327             : 
    3328             : /**
    3329             :  * \brief Return the number of overview layers available.
    3330             :  *
    3331             :  * @see GDALRasterBand::GetOverviewCount()
    3332             :  */
    3333             : 
    3334        3283 : int CPL_STDCALL GDALGetOverviewCount(GDALRasterBandH hBand)
    3335             : 
    3336             : {
    3337        3283 :     VALIDATE_POINTER1(hBand, "GDALGetOverviewCount", 0);
    3338             : 
    3339        3283 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3340        3283 :     return poBand->GetOverviewCount();
    3341             : }
    3342             : 
    3343             : /************************************************************************/
    3344             : /*                            GetOverview()                             */
    3345             : /************************************************************************/
    3346             : 
    3347             : /**
    3348             :  * \brief Fetch overview raster band object.
    3349             :  *
    3350             :  * This method is the same as the C function GDALGetOverview().
    3351             :  *
    3352             :  * @param i overview index between 0 and GetOverviewCount()-1.
    3353             :  *
    3354             :  * @return overview GDALRasterBand.
    3355             :  */
    3356             : 
    3357         844 : GDALRasterBand *GDALRasterBand::GetOverview(int i)
    3358             : 
    3359             : {
    3360        1633 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized() &&
    3361         789 :         poDS->AreOverviewsEnabled())
    3362         789 :         return poDS->oOvManager.GetOverview(nBand, i);
    3363             : 
    3364          55 :     return nullptr;
    3365             : }
    3366             : 
    3367             : /************************************************************************/
    3368             : /*                          GDALGetOverview()                           */
    3369             : /************************************************************************/
    3370             : 
    3371             : /**
    3372             :  * \brief Fetch overview raster band object.
    3373             :  *
    3374             :  * @see GDALRasterBand::GetOverview()
    3375             :  */
    3376             : 
    3377        5654 : GDALRasterBandH CPL_STDCALL GDALGetOverview(GDALRasterBandH hBand, int i)
    3378             : 
    3379             : {
    3380        5654 :     VALIDATE_POINTER1(hBand, "GDALGetOverview", nullptr);
    3381             : 
    3382        5654 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3383        5654 :     return GDALRasterBand::ToHandle(poBand->GetOverview(i));
    3384             : }
    3385             : 
    3386             : /************************************************************************/
    3387             : /*                      GetRasterSampleOverview()                       */
    3388             : /************************************************************************/
    3389             : 
    3390             : /**
    3391             :  * \brief Fetch best sampling overview.
    3392             :  *
    3393             :  * Returns the most reduced overview of the given band that still satisfies
    3394             :  * the desired number of samples.  This function can be used with zero
    3395             :  * as the number of desired samples to fetch the most reduced overview.
    3396             :  * The same band as was passed in will be returned if it has not overviews,
    3397             :  * or if none of the overviews have enough samples.
    3398             :  *
    3399             :  * This method is the same as the C functions GDALGetRasterSampleOverview()
    3400             :  * and GDALGetRasterSampleOverviewEx().
    3401             :  *
    3402             :  * @param nDesiredSamples the returned band will have at least this many
    3403             :  * pixels.
    3404             :  *
    3405             :  * @return optimal overview or the band itself.
    3406             :  */
    3407             : 
    3408             : GDALRasterBand *
    3409        2006 : GDALRasterBand::GetRasterSampleOverview(GUIntBig nDesiredSamples)
    3410             : 
    3411             : {
    3412        2006 :     GDALRasterBand *poBestBand = this;
    3413             : 
    3414        2006 :     double dfBestSamples = GetXSize() * static_cast<double>(GetYSize());
    3415             : 
    3416        4023 :     for (int iOverview = 0; iOverview < GetOverviewCount(); iOverview++)
    3417             :     {
    3418        2017 :         GDALRasterBand *poOBand = GetOverview(iOverview);
    3419             : 
    3420        2017 :         if (poOBand == nullptr)
    3421           0 :             continue;
    3422             : 
    3423             :         const double dfOSamples =
    3424        2017 :             poOBand->GetXSize() * static_cast<double>(poOBand->GetYSize());
    3425             : 
    3426        2017 :         if (dfOSamples < dfBestSamples && dfOSamples > nDesiredSamples)
    3427             :         {
    3428        2014 :             dfBestSamples = dfOSamples;
    3429        2014 :             poBestBand = poOBand;
    3430             :         }
    3431             :     }
    3432             : 
    3433        2006 :     return poBestBand;
    3434             : }
    3435             : 
    3436             : /************************************************************************/
    3437             : /*                    GDALGetRasterSampleOverview()                     */
    3438             : /************************************************************************/
    3439             : 
    3440             : /**
    3441             :  * \brief Fetch best sampling overview.
    3442             :  *
    3443             :  * Use GDALGetRasterSampleOverviewEx() to be able to specify more than 2
    3444             :  * billion samples.
    3445             :  *
    3446             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3447             :  * @see GDALGetRasterSampleOverviewEx()
    3448             :  */
    3449             : 
    3450           0 : GDALRasterBandH CPL_STDCALL GDALGetRasterSampleOverview(GDALRasterBandH hBand,
    3451             :                                                         int nDesiredSamples)
    3452             : 
    3453             : {
    3454           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverview", nullptr);
    3455             : 
    3456           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3457           0 :     return GDALRasterBand::ToHandle(poBand->GetRasterSampleOverview(
    3458           0 :         nDesiredSamples < 0 ? 0 : static_cast<GUIntBig>(nDesiredSamples)));
    3459             : }
    3460             : 
    3461             : /************************************************************************/
    3462             : /*                    GDALGetRasterSampleOverviewEx()                   */
    3463             : /************************************************************************/
    3464             : 
    3465             : /**
    3466             :  * \brief Fetch best sampling overview.
    3467             :  *
    3468             :  * @see GDALRasterBand::GetRasterSampleOverview()
    3469             :  * @since GDAL 2.0
    3470             :  */
    3471             : 
    3472             : GDALRasterBandH CPL_STDCALL
    3473        2000 : GDALGetRasterSampleOverviewEx(GDALRasterBandH hBand, GUIntBig nDesiredSamples)
    3474             : 
    3475             : {
    3476        2000 :     VALIDATE_POINTER1(hBand, "GDALGetRasterSampleOverviewEx", nullptr);
    3477             : 
    3478        2000 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3479        2000 :     return GDALRasterBand::ToHandle(
    3480        4000 :         poBand->GetRasterSampleOverview(nDesiredSamples));
    3481             : }
    3482             : 
    3483             : /************************************************************************/
    3484             : /*                           BuildOverviews()                           */
    3485             : /************************************************************************/
    3486             : 
    3487             : /**
    3488             :  * \fn GDALRasterBand::BuildOverviews(const char*, int, const int*,
    3489             :  * GDALProgressFunc, void*) \brief Build raster overview(s)
    3490             :  *
    3491             :  * If the operation is unsupported for the indicated dataset, then
    3492             :  * CE_Failure is returned, and CPLGetLastErrorNo() will return
    3493             :  * CPLE_NotSupported.
    3494             :  *
    3495             :  * WARNING: Most formats don't support per-band overview computation, but
    3496             :  * require that overviews are computed for all bands of a dataset, using
    3497             :  * GDALDataset::BuildOverviews(). The only exception for official GDAL drivers
    3498             :  * is the HFA driver which supports this method.
    3499             :  *
    3500             :  * @param pszResampling one of "NEAREST", "GAUSS", "CUBIC", "AVERAGE", "MODE",
    3501             :  * "AVERAGE_MAGPHASE" "RMS" or "NONE" controlling the downsampling method
    3502             :  * applied.
    3503             :  * @param nOverviews number of overviews to build.
    3504             :  * @param panOverviewList the list of overview decimation factors to build.
    3505             :  * @param pfnProgress a function to call to report progress, or NULL.
    3506             :  * @param pProgressData application data to pass to the progress function.
    3507             :  * @param papszOptions (GDAL >= 3.6) NULL terminated list of options as
    3508             :  *                     key=value pairs, or NULL
    3509             :  *
    3510             :  * @return CE_None on success or CE_Failure if the operation doesn't work.
    3511             :  */
    3512             : 
    3513             : /**/
    3514             : /**/
    3515             : 
    3516           0 : CPLErr GDALRasterBand::BuildOverviews(const char * /*pszResampling*/,
    3517             :                                       int /*nOverviews*/,
    3518             :                                       const int * /*panOverviewList*/,
    3519             :                                       GDALProgressFunc /*pfnProgress*/,
    3520             :                                       void * /*pProgressData*/,
    3521             :                                       CSLConstList /* papszOptions */)
    3522             : 
    3523             : {
    3524           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    3525             :                 "BuildOverviews() not supported for this dataset.");
    3526             : 
    3527           0 :     return (CE_Failure);
    3528             : }
    3529             : 
    3530             : /************************************************************************/
    3531             : /*                             GetOffset()                              */
    3532             : /************************************************************************/
    3533             : 
    3534             : /**
    3535             :  * \brief Fetch the raster value offset.
    3536             :  *
    3537             :  * This value (in combination with the GetScale() value) can be used to
    3538             :  * transform raw pixel values into the units returned by GetUnitType().
    3539             :  * For example this might be used to store elevations in GUInt16 bands
    3540             :  * with a precision of 0.1, and starting from -100.
    3541             :  *
    3542             :  * Units value = (raw value * scale) + offset
    3543             :  *
    3544             :  * Note that applying scale and offset is of the responsibility of the user,
    3545             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3546             :  *
    3547             :  * For file formats that don't know this intrinsically a value of zero
    3548             :  * is returned.
    3549             :  *
    3550             :  * This method is the same as the C function GDALGetRasterOffset().
    3551             :  *
    3552             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3553             :  * returned value is meaningful or not.  May be NULL (default).
    3554             :  *
    3555             :  * @return the raster offset.
    3556             :  */
    3557             : 
    3558         460 : double GDALRasterBand::GetOffset(int *pbSuccess)
    3559             : 
    3560             : {
    3561         460 :     if (pbSuccess != nullptr)
    3562         351 :         *pbSuccess = FALSE;
    3563             : 
    3564         460 :     return 0.0;
    3565             : }
    3566             : 
    3567             : /************************************************************************/
    3568             : /*                        GDALGetRasterOffset()                         */
    3569             : /************************************************************************/
    3570             : 
    3571             : /**
    3572             :  * \brief Fetch the raster value offset.
    3573             :  *
    3574             :  * @see GDALRasterBand::GetOffset()
    3575             :  */
    3576             : 
    3577         385 : double CPL_STDCALL GDALGetRasterOffset(GDALRasterBandH hBand, int *pbSuccess)
    3578             : 
    3579             : {
    3580         385 :     VALIDATE_POINTER1(hBand, "GDALGetRasterOffset", 0);
    3581             : 
    3582         385 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3583         385 :     return poBand->GetOffset(pbSuccess);
    3584             : }
    3585             : 
    3586             : /************************************************************************/
    3587             : /*                             SetOffset()                              */
    3588             : /************************************************************************/
    3589             : 
    3590             : /**
    3591             :  * \fn GDALRasterBand::SetOffset(double)
    3592             :  * \brief Set scaling offset.
    3593             :  *
    3594             :  * Very few formats implement this method.   When not implemented it will
    3595             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3596             :  *
    3597             :  * This method is the same as the C function GDALSetRasterOffset().
    3598             :  *
    3599             :  * @param dfNewOffset the new offset.
    3600             :  *
    3601             :  * @return CE_None or success or CE_Failure on failure.
    3602             :  */
    3603             : 
    3604             : /**/
    3605             : /**/
    3606             : 
    3607           0 : CPLErr GDALRasterBand::SetOffset(double /*dfNewOffset*/)
    3608             : {
    3609           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3610           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3611             :                     "SetOffset() not supported on this raster band.");
    3612             : 
    3613           0 :     return CE_Failure;
    3614             : }
    3615             : 
    3616             : /************************************************************************/
    3617             : /*                        GDALSetRasterOffset()                         */
    3618             : /************************************************************************/
    3619             : 
    3620             : /**
    3621             :  * \brief Set scaling offset.
    3622             :  *
    3623             :  * @see GDALRasterBand::SetOffset()
    3624             :  */
    3625             : 
    3626          75 : CPLErr CPL_STDCALL GDALSetRasterOffset(GDALRasterBandH hBand,
    3627             :                                        double dfNewOffset)
    3628             : 
    3629             : {
    3630          75 :     VALIDATE_POINTER1(hBand, "GDALSetRasterOffset", CE_Failure);
    3631             : 
    3632          75 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3633          75 :     return poBand->SetOffset(dfNewOffset);
    3634             : }
    3635             : 
    3636             : /************************************************************************/
    3637             : /*                              GetScale()                              */
    3638             : /************************************************************************/
    3639             : 
    3640             : /**
    3641             :  * \brief Fetch the raster value scale.
    3642             :  *
    3643             :  * This value (in combination with the GetOffset() value) can be used to
    3644             :  * transform raw pixel values into the units returned by GetUnitType().
    3645             :  * For example this might be used to store elevations in GUInt16 bands
    3646             :  * with a precision of 0.1, and starting from -100.
    3647             :  *
    3648             :  * Units value = (raw value * scale) + offset
    3649             :  *
    3650             :  * Note that applying scale and offset is of the responsibility of the user,
    3651             :  * and is not done by methods such as RasterIO() or ReadBlock().
    3652             :  *
    3653             :  * For file formats that don't know this intrinsically a value of one
    3654             :  * is returned.
    3655             :  *
    3656             :  * This method is the same as the C function GDALGetRasterScale().
    3657             :  *
    3658             :  * @param pbSuccess pointer to a boolean to use to indicate if the
    3659             :  * returned value is meaningful or not.  May be NULL (default).
    3660             :  *
    3661             :  * @return the raster scale.
    3662             :  */
    3663             : 
    3664         460 : double GDALRasterBand::GetScale(int *pbSuccess)
    3665             : 
    3666             : {
    3667         460 :     if (pbSuccess != nullptr)
    3668         351 :         *pbSuccess = FALSE;
    3669             : 
    3670         460 :     return 1.0;
    3671             : }
    3672             : 
    3673             : /************************************************************************/
    3674             : /*                         GDALGetRasterScale()                         */
    3675             : /************************************************************************/
    3676             : 
    3677             : /**
    3678             :  * \brief Fetch the raster value scale.
    3679             :  *
    3680             :  * @see GDALRasterBand::GetScale()
    3681             :  */
    3682             : 
    3683         383 : double CPL_STDCALL GDALGetRasterScale(GDALRasterBandH hBand, int *pbSuccess)
    3684             : 
    3685             : {
    3686         383 :     VALIDATE_POINTER1(hBand, "GDALGetRasterScale", 0);
    3687             : 
    3688         383 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3689         383 :     return poBand->GetScale(pbSuccess);
    3690             : }
    3691             : 
    3692             : /************************************************************************/
    3693             : /*                              SetScale()                              */
    3694             : /************************************************************************/
    3695             : 
    3696             : /**
    3697             :  * \fn GDALRasterBand::SetScale(double)
    3698             :  * \brief Set scaling ratio.
    3699             :  *
    3700             :  * Very few formats implement this method.   When not implemented it will
    3701             :  * issue a CPLE_NotSupported error and return CE_Failure.
    3702             :  *
    3703             :  * This method is the same as the C function GDALSetRasterScale().
    3704             :  *
    3705             :  * @param dfNewScale the new scale.
    3706             :  *
    3707             :  * @return CE_None or success or CE_Failure on failure.
    3708             :  */
    3709             : 
    3710             : /**/
    3711             : /**/
    3712             : 
    3713           0 : CPLErr GDALRasterBand::SetScale(double /*dfNewScale*/)
    3714             : 
    3715             : {
    3716           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3717           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3718             :                     "SetScale() not supported on this raster band.");
    3719             : 
    3720           0 :     return CE_Failure;
    3721             : }
    3722             : 
    3723             : /************************************************************************/
    3724             : /*                        GDALSetRasterScale()                          */
    3725             : /************************************************************************/
    3726             : 
    3727             : /**
    3728             :  * \brief Set scaling ratio.
    3729             :  *
    3730             :  * @see GDALRasterBand::SetScale()
    3731             :  */
    3732             : 
    3733          76 : CPLErr CPL_STDCALL GDALSetRasterScale(GDALRasterBandH hBand, double dfNewOffset)
    3734             : 
    3735             : {
    3736          76 :     VALIDATE_POINTER1(hBand, "GDALSetRasterScale", CE_Failure);
    3737             : 
    3738          76 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3739          76 :     return poBand->SetScale(dfNewOffset);
    3740             : }
    3741             : 
    3742             : /************************************************************************/
    3743             : /*                            GetUnitType()                             */
    3744             : /************************************************************************/
    3745             : 
    3746             : /**
    3747             :  * \brief Return raster unit type.
    3748             :  *
    3749             :  * Return a name for the units of this raster's values.  For instance, it
    3750             :  * might be "m" for an elevation model in meters, or "ft" for feet.  If no
    3751             :  * units are available, a value of "" will be returned.  The returned string
    3752             :  * should not be modified, nor freed by the calling application.
    3753             :  *
    3754             :  * This method is the same as the C function GDALGetRasterUnitType().
    3755             :  *
    3756             :  * @return unit name string.
    3757             :  */
    3758             : 
    3759         183 : const char *GDALRasterBand::GetUnitType()
    3760             : 
    3761             : {
    3762         183 :     return "";
    3763             : }
    3764             : 
    3765             : /************************************************************************/
    3766             : /*                       GDALGetRasterUnitType()                        */
    3767             : /************************************************************************/
    3768             : 
    3769             : /**
    3770             :  * \brief Return raster unit type.
    3771             :  *
    3772             :  * @see GDALRasterBand::GetUnitType()
    3773             :  */
    3774             : 
    3775        1427 : const char *CPL_STDCALL GDALGetRasterUnitType(GDALRasterBandH hBand)
    3776             : 
    3777             : {
    3778        1427 :     VALIDATE_POINTER1(hBand, "GDALGetRasterUnitType", nullptr);
    3779             : 
    3780        1427 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3781        1427 :     return poBand->GetUnitType();
    3782             : }
    3783             : 
    3784             : /************************************************************************/
    3785             : /*                            SetUnitType()                             */
    3786             : /************************************************************************/
    3787             : 
    3788             : /**
    3789             :  * \fn GDALRasterBand::SetUnitType(const char*)
    3790             :  * \brief Set unit type.
    3791             :  *
    3792             :  * Set the unit type for a raster band.  Values should be one of
    3793             :  * "" (the default indicating it is unknown), "m" indicating meters,
    3794             :  * or "ft" indicating feet, though other nonstandard values are allowed.
    3795             :  *
    3796             :  * This method is the same as the C function GDALSetRasterUnitType().
    3797             :  *
    3798             :  * @param pszNewValue the new unit type value.
    3799             :  *
    3800             :  * @return CE_None on success or CE_Failure if not successful, or
    3801             :  * unsupported.
    3802             :  */
    3803             : 
    3804             : /**/
    3805             : /**/
    3806             : 
    3807           0 : CPLErr GDALRasterBand::SetUnitType(const char * /*pszNewValue*/)
    3808             : 
    3809             : {
    3810           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    3811           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    3812             :                     "SetUnitType() not supported on this raster band.");
    3813           0 :     return CE_Failure;
    3814             : }
    3815             : 
    3816             : /************************************************************************/
    3817             : /*                       GDALSetRasterUnitType()                        */
    3818             : /************************************************************************/
    3819             : 
    3820             : /**
    3821             :  * \brief Set unit type.
    3822             :  *
    3823             :  * @see GDALRasterBand::SetUnitType()
    3824             :  *
    3825             :  * @since GDAL 1.8.0
    3826             :  */
    3827             : 
    3828          75 : CPLErr CPL_STDCALL GDALSetRasterUnitType(GDALRasterBandH hBand,
    3829             :                                          const char *pszNewValue)
    3830             : 
    3831             : {
    3832          75 :     VALIDATE_POINTER1(hBand, "GDALSetRasterUnitType", CE_Failure);
    3833             : 
    3834          75 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3835          75 :     return poBand->SetUnitType(pszNewValue);
    3836             : }
    3837             : 
    3838             : /************************************************************************/
    3839             : /*                              GetXSize()                              */
    3840             : /************************************************************************/
    3841             : 
    3842             : /**
    3843             :  * \brief Fetch XSize of raster.
    3844             :  *
    3845             :  * This method is the same as the C function GDALGetRasterBandXSize().
    3846             :  *
    3847             :  * @return the width in pixels of this band.
    3848             :  */
    3849             : 
    3850     8445040 : int GDALRasterBand::GetXSize() const
    3851             : 
    3852             : {
    3853     8445040 :     return nRasterXSize;
    3854             : }
    3855             : 
    3856             : /************************************************************************/
    3857             : /*                       GDALGetRasterBandXSize()                       */
    3858             : /************************************************************************/
    3859             : 
    3860             : /**
    3861             :  * \brief Fetch XSize of raster.
    3862             :  *
    3863             :  * @see GDALRasterBand::GetXSize()
    3864             :  */
    3865             : 
    3866       57595 : int CPL_STDCALL GDALGetRasterBandXSize(GDALRasterBandH hBand)
    3867             : 
    3868             : {
    3869       57595 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandXSize", 0);
    3870             : 
    3871       57595 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3872       57595 :     return poBand->GetXSize();
    3873             : }
    3874             : 
    3875             : /************************************************************************/
    3876             : /*                              GetYSize()                              */
    3877             : /************************************************************************/
    3878             : 
    3879             : /**
    3880             :  * \brief Fetch YSize of raster.
    3881             :  *
    3882             :  * This method is the same as the C function GDALGetRasterBandYSize().
    3883             :  *
    3884             :  * @return the height in pixels of this band.
    3885             :  */
    3886             : 
    3887     4665280 : int GDALRasterBand::GetYSize() const
    3888             : 
    3889             : {
    3890     4665280 :     return nRasterYSize;
    3891             : }
    3892             : 
    3893             : /************************************************************************/
    3894             : /*                       GDALGetRasterBandYSize()                       */
    3895             : /************************************************************************/
    3896             : 
    3897             : /**
    3898             :  * \brief Fetch YSize of raster.
    3899             :  *
    3900             :  * @see GDALRasterBand::GetYSize()
    3901             :  */
    3902             : 
    3903       56454 : int CPL_STDCALL GDALGetRasterBandYSize(GDALRasterBandH hBand)
    3904             : 
    3905             : {
    3906       56454 :     VALIDATE_POINTER1(hBand, "GDALGetRasterBandYSize", 0);
    3907             : 
    3908       56454 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3909       56454 :     return poBand->GetYSize();
    3910             : }
    3911             : 
    3912             : /************************************************************************/
    3913             : /*                              GetBand()                               */
    3914             : /************************************************************************/
    3915             : 
    3916             : /**
    3917             :  * \brief Fetch the band number.
    3918             :  *
    3919             :  * This method returns the band that this GDALRasterBand objects represents
    3920             :  * within its dataset.  This method may return a value of 0 to indicate
    3921             :  * GDALRasterBand objects without an apparently relationship to a dataset,
    3922             :  * such as GDALRasterBands serving as overviews.
    3923             :  *
    3924             :  * This method is the same as the C function GDALGetBandNumber().
    3925             :  *
    3926             :  * @return band number (1+) or 0 if the band number isn't known.
    3927             :  */
    3928             : 
    3929      151775 : int GDALRasterBand::GetBand() const
    3930             : 
    3931             : {
    3932      151775 :     return nBand;
    3933             : }
    3934             : 
    3935             : /************************************************************************/
    3936             : /*                         GDALGetBandNumber()                          */
    3937             : /************************************************************************/
    3938             : 
    3939             : /**
    3940             :  * \brief Fetch the band number.
    3941             :  *
    3942             :  * @see GDALRasterBand::GetBand()
    3943             :  */
    3944             : 
    3945         202 : int CPL_STDCALL GDALGetBandNumber(GDALRasterBandH hBand)
    3946             : 
    3947             : {
    3948         202 :     VALIDATE_POINTER1(hBand, "GDALGetBandNumber", 0);
    3949             : 
    3950         202 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3951         202 :     return poBand->GetBand();
    3952             : }
    3953             : 
    3954             : /************************************************************************/
    3955             : /*                             GetDataset()                             */
    3956             : /************************************************************************/
    3957             : 
    3958             : /**
    3959             :  * \brief Fetch the owning dataset handle.
    3960             :  *
    3961             :  * Note that some GDALRasterBands are not considered to be a part of a dataset,
    3962             :  * such as overviews or other "freestanding" bands.
    3963             :  *
    3964             :  * This method is the same as the C function GDALGetBandDataset().
    3965             :  *
    3966             :  * @return the pointer to the GDALDataset to which this band belongs, or
    3967             :  * NULL if this cannot be determined.
    3968             :  */
    3969             : 
    3970     5301230 : GDALDataset *GDALRasterBand::GetDataset() const
    3971             : 
    3972             : {
    3973     5301230 :     return poDS;
    3974             : }
    3975             : 
    3976             : /************************************************************************/
    3977             : /*                         GDALGetBandDataset()                         */
    3978             : /************************************************************************/
    3979             : 
    3980             : /**
    3981             :  * \brief Fetch the owning dataset handle.
    3982             :  *
    3983             :  * @see GDALRasterBand::GetDataset()
    3984             :  */
    3985             : 
    3986         445 : GDALDatasetH CPL_STDCALL GDALGetBandDataset(GDALRasterBandH hBand)
    3987             : 
    3988             : {
    3989         445 :     VALIDATE_POINTER1(hBand, "GDALGetBandDataset", nullptr);
    3990             : 
    3991         445 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    3992         445 :     return GDALDataset::ToHandle(poBand->GetDataset());
    3993             : }
    3994             : 
    3995             : /************************************************************************/
    3996             : /*                        ComputeFloat16NoDataValue()                     */
    3997             : /************************************************************************/
    3998             : 
    3999        2231 : static inline void ComputeFloat16NoDataValue(GDALDataType eDataType,
    4000             :                                              double dfNoDataValue,
    4001             :                                              int &bGotNoDataValue,
    4002             :                                              GFloat16 &fNoDataValue,
    4003             :                                              bool &bGotFloat16NoDataValue)
    4004             : {
    4005        2231 :     if (eDataType == GDT_Float16 && bGotNoDataValue)
    4006             :     {
    4007           0 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4008           0 :         if (GDALIsValueInRange<GFloat16>(dfNoDataValue))
    4009             :         {
    4010           0 :             fNoDataValue = static_cast<GFloat16>(dfNoDataValue);
    4011           0 :             bGotFloat16NoDataValue = true;
    4012           0 :             bGotNoDataValue = false;
    4013             :         }
    4014             :     }
    4015        2231 : }
    4016             : 
    4017             : /************************************************************************/
    4018             : /*                        ComputeFloatNoDataValue()                     */
    4019             : /************************************************************************/
    4020             : 
    4021        2231 : static inline void ComputeFloatNoDataValue(GDALDataType eDataType,
    4022             :                                            double dfNoDataValue,
    4023             :                                            int &bGotNoDataValue,
    4024             :                                            float &fNoDataValue,
    4025             :                                            bool &bGotFloatNoDataValue)
    4026             : {
    4027        2231 :     if (eDataType == GDT_Float32 && bGotNoDataValue)
    4028             :     {
    4029          84 :         dfNoDataValue = GDALAdjustNoDataCloseToFloatMax(dfNoDataValue);
    4030          84 :         if (GDALIsValueInRange<float>(dfNoDataValue))
    4031             :         {
    4032          84 :             fNoDataValue = static_cast<float>(dfNoDataValue);
    4033          84 :             bGotFloatNoDataValue = true;
    4034          84 :             bGotNoDataValue = false;
    4035             :         }
    4036             :     }
    4037        2231 : }
    4038             : 
    4039             : /************************************************************************/
    4040             : /*                        struct GDALNoDataValues                       */
    4041             : /************************************************************************/
    4042             : 
    4043             : /**
    4044             :  * \brief No-data-values for all types
    4045             :  *
    4046             :  * The functions below pass various no-data-values around. To avoid
    4047             :  * long argument lists, this struct collects the no-data-values for
    4048             :  * all types into a single, convenient place.
    4049             :  **/
    4050             : 
    4051             : struct GDALNoDataValues
    4052             : {
    4053             :     int bGotNoDataValue;
    4054             :     double dfNoDataValue;
    4055             : 
    4056             :     bool bGotInt64NoDataValue;
    4057             :     int64_t nInt64NoDataValue;
    4058             : 
    4059             :     bool bGotUInt64NoDataValue;
    4060             :     uint64_t nUInt64NoDataValue;
    4061             : 
    4062             :     bool bGotFloatNoDataValue;
    4063             :     float fNoDataValue;
    4064             : 
    4065             :     bool bGotFloat16NoDataValue;
    4066             :     GFloat16 hfNoDataValue;
    4067             : 
    4068        2275 :     GDALNoDataValues(GDALRasterBand *poRasterBand, GDALDataType eDataType)
    4069        2275 :         : bGotNoDataValue(FALSE), dfNoDataValue(0.0),
    4070             :           bGotInt64NoDataValue(false), nInt64NoDataValue(0),
    4071             :           bGotUInt64NoDataValue(false), nUInt64NoDataValue(0),
    4072             :           bGotFloatNoDataValue(false), fNoDataValue(0.0f),
    4073        2275 :           bGotFloat16NoDataValue(false), hfNoDataValue(GFloat16(0.0f))
    4074             :     {
    4075        2275 :         if (eDataType == GDT_Int64)
    4076             :         {
    4077          28 :             int nGot = false;
    4078          28 :             nInt64NoDataValue = poRasterBand->GetNoDataValueAsInt64(&nGot);
    4079          28 :             bGotInt64NoDataValue = CPL_TO_BOOL(nGot);
    4080          28 :             if (bGotInt64NoDataValue)
    4081             :             {
    4082           3 :                 dfNoDataValue = static_cast<double>(nInt64NoDataValue);
    4083           3 :                 bGotNoDataValue =
    4084           3 :                     nInt64NoDataValue <=
    4085           6 :                         std::numeric_limits<int64_t>::max() - 1024 &&
    4086           3 :                     static_cast<int64_t>(dfNoDataValue) == nInt64NoDataValue;
    4087             :             }
    4088             :             else
    4089          25 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4090             :         }
    4091        2247 :         else if (eDataType == GDT_UInt64)
    4092             :         {
    4093          16 :             int nGot = false;
    4094          16 :             nUInt64NoDataValue = poRasterBand->GetNoDataValueAsUInt64(&nGot);
    4095          16 :             bGotUInt64NoDataValue = CPL_TO_BOOL(nGot);
    4096          16 :             if (bGotUInt64NoDataValue)
    4097             :             {
    4098           3 :                 dfNoDataValue = static_cast<double>(nUInt64NoDataValue);
    4099           3 :                 bGotNoDataValue =
    4100           3 :                     nUInt64NoDataValue <=
    4101           6 :                         std::numeric_limits<uint64_t>::max() - 2048 &&
    4102           3 :                     static_cast<uint64_t>(dfNoDataValue) == nUInt64NoDataValue;
    4103             :             }
    4104             :             else
    4105          13 :                 dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4106             :         }
    4107             :         else
    4108             :         {
    4109        2231 :             dfNoDataValue = poRasterBand->GetNoDataValue(&bGotNoDataValue);
    4110        2231 :             bGotNoDataValue = bGotNoDataValue && !std::isnan(dfNoDataValue);
    4111             : 
    4112        2231 :             ComputeFloatNoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4113        2231 :                                     fNoDataValue, bGotFloatNoDataValue);
    4114             : 
    4115        2231 :             ComputeFloat16NoDataValue(eDataType, dfNoDataValue, bGotNoDataValue,
    4116        2231 :                                       hfNoDataValue, bGotFloat16NoDataValue);
    4117             :         }
    4118        2275 :     }
    4119             : };
    4120             : 
    4121             : /************************************************************************/
    4122             : /*                            ARE_REAL_EQUAL()                          */
    4123             : /************************************************************************/
    4124             : 
    4125           0 : inline bool ARE_REAL_EQUAL(GFloat16 dfVal1, GFloat16 dfVal2, int ulp = 2)
    4126             : {
    4127             :     using std::abs;
    4128           0 :     return dfVal1 == dfVal2 || /* Should cover infinity */
    4129           0 :            abs(dfVal1 - dfVal2) < cpl::NumericLimits<GFloat16>::epsilon() *
    4130           0 :                                       abs(dfVal1 + dfVal2) * ulp;
    4131             : }
    4132             : 
    4133             : /************************************************************************/
    4134             : /*                            GetHistogram()                            */
    4135             : /************************************************************************/
    4136             : 
    4137             : /**
    4138             :  * \brief Compute raster histogram.
    4139             :  *
    4140             :  * Note that the bucket size is (dfMax-dfMin) / nBuckets.
    4141             :  *
    4142             :  * For example to compute a simple 256 entry histogram of eight bit data,
    4143             :  * the following would be suitable.  The unusual bounds are to ensure that
    4144             :  * bucket boundaries don't fall right on integer values causing possible errors
    4145             :  * due to rounding after scaling.
    4146             : \code{.cpp}
    4147             :     GUIntBig anHistogram[256];
    4148             : 
    4149             :     poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
    4150             :                           GDALDummyProgress, nullptr );
    4151             : \endcode
    4152             :  *
    4153             :  * Note that setting bApproxOK will generally result in a subsampling of the
    4154             :  * file, and will utilize overviews if available.  It should generally
    4155             :  * produce a representative histogram for the data that is suitable for use
    4156             :  * in generating histogram based luts for instance.  Generally bApproxOK is
    4157             :  * much faster than an exactly computed histogram.
    4158             :  *
    4159             :  * This method is the same as the C functions GDALGetRasterHistogram() and
    4160             :  * GDALGetRasterHistogramEx().
    4161             :  *
    4162             :  * @param dfMin the lower bound of the histogram.
    4163             :  * @param dfMax the upper bound of the histogram.
    4164             :  * @param nBuckets the number of buckets in panHistogram.
    4165             :  * @param panHistogram array into which the histogram totals are placed.
    4166             :  * @param bIncludeOutOfRange if TRUE values below the histogram range will
    4167             :  * mapped into panHistogram[0], and values above will be mapped into
    4168             :  * panHistogram[nBuckets-1] otherwise out of range values are discarded.
    4169             :  * @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
    4170             :  * @param pfnProgress function to report progress to completion.
    4171             :  * @param pProgressData application data to pass to pfnProgress.
    4172             :  *
    4173             :  * @return CE_None on success, or CE_Failure if something goes wrong.
    4174             :  */
    4175             : 
    4176          42 : CPLErr GDALRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
    4177             :                                     GUIntBig *panHistogram,
    4178             :                                     int bIncludeOutOfRange, int bApproxOK,
    4179             :                                     GDALProgressFunc pfnProgress,
    4180             :                                     void *pProgressData)
    4181             : 
    4182             : {
    4183          42 :     CPLAssert(nullptr != panHistogram);
    4184             : 
    4185          42 :     if (pfnProgress == nullptr)
    4186          29 :         pfnProgress = GDALDummyProgress;
    4187             : 
    4188             :     /* -------------------------------------------------------------------- */
    4189             :     /*      If we have overviews, use them for the histogram.               */
    4190             :     /* -------------------------------------------------------------------- */
    4191          42 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    4192             :     {
    4193             :         // FIXME: should we use the most reduced overview here or use some
    4194             :         // minimum number of samples like GDALRasterBand::ComputeStatistics()
    4195             :         // does?
    4196           0 :         GDALRasterBand *poBestOverview = GetRasterSampleOverview(0);
    4197             : 
    4198           0 :         if (poBestOverview != this)
    4199             :         {
    4200           0 :             return poBestOverview->GetHistogram(
    4201             :                 dfMin, dfMax, nBuckets, panHistogram, bIncludeOutOfRange,
    4202           0 :                 bApproxOK, pfnProgress, pProgressData);
    4203             :         }
    4204             :     }
    4205             : 
    4206             :     /* -------------------------------------------------------------------- */
    4207             :     /*      Read actual data and build histogram.                           */
    4208             :     /* -------------------------------------------------------------------- */
    4209          42 :     if (!pfnProgress(0.0, "Compute Histogram", pProgressData))
    4210             :     {
    4211           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    4212           0 :         return CE_Failure;
    4213             :     }
    4214             : 
    4215             :     // Written this way to deal with NaN
    4216          42 :     if (!(dfMax > dfMin))
    4217             :     {
    4218           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4219             :                     "dfMax should be strictly greater than dfMin");
    4220           5 :         return CE_Failure;
    4221             :     }
    4222             : 
    4223             :     GDALRasterIOExtraArg sExtraArg;
    4224          37 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    4225             : 
    4226          37 :     const double dfScale = nBuckets / (dfMax - dfMin);
    4227          37 :     if (dfScale == 0 || !std::isfinite(dfScale))
    4228             :     {
    4229           5 :         ReportError(CE_Failure, CPLE_IllegalArg,
    4230             :                     "dfMin and dfMax should be finite values such that "
    4231             :                     "nBuckets / (dfMax - dfMin) is non-zero");
    4232           5 :         return CE_Failure;
    4233             :     }
    4234          32 :     memset(panHistogram, 0, sizeof(GUIntBig) * nBuckets);
    4235             : 
    4236          32 :     GDALNoDataValues sNoDataValues(this, eDataType);
    4237          32 :     GDALRasterBand *poMaskBand = nullptr;
    4238          32 :     if (!sNoDataValues.bGotNoDataValue)
    4239             :     {
    4240          31 :         const int l_nMaskFlags = GetMaskFlags();
    4241          33 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    4242           2 :             GetColorInterpretation() != GCI_AlphaBand)
    4243             :         {
    4244           2 :             poMaskBand = GetMaskBand();
    4245             :         }
    4246             :     }
    4247             : 
    4248          32 :     bool bSignedByte = false;
    4249          32 :     if (eDataType == GDT_Byte)
    4250             :     {
    4251          23 :         EnablePixelTypeSignedByteWarning(false);
    4252             :         const char *pszPixelType =
    4253          23 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4254          23 :         EnablePixelTypeSignedByteWarning(true);
    4255          23 :         bSignedByte =
    4256          23 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4257             :     }
    4258             : 
    4259          32 :     if (bApproxOK && HasArbitraryOverviews())
    4260             :     {
    4261             :         /* --------------------------------------------------------------------
    4262             :          */
    4263             :         /*      Figure out how much the image should be reduced to get an */
    4264             :         /*      approximate value. */
    4265             :         /* --------------------------------------------------------------------
    4266             :          */
    4267             :         const double dfReduction =
    4268           0 :             sqrt(static_cast<double>(nRasterXSize) * nRasterYSize /
    4269             :                  GDALSTAT_APPROX_NUMSAMPLES);
    4270             : 
    4271           0 :         int nXReduced = nRasterXSize;
    4272           0 :         int nYReduced = nRasterYSize;
    4273           0 :         if (dfReduction > 1.0)
    4274             :         {
    4275           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    4276           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    4277             : 
    4278             :             // Catch the case of huge resizing ratios here
    4279           0 :             if (nXReduced == 0)
    4280           0 :                 nXReduced = 1;
    4281           0 :             if (nYReduced == 0)
    4282           0 :                 nYReduced = 1;
    4283             :         }
    4284             : 
    4285           0 :         void *pData = VSI_MALLOC3_VERBOSE(GDALGetDataTypeSizeBytes(eDataType),
    4286             :                                           nXReduced, nYReduced);
    4287           0 :         if (!pData)
    4288           0 :             return CE_Failure;
    4289             : 
    4290             :         const CPLErr eErr =
    4291           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    4292           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    4293           0 :         if (eErr != CE_None)
    4294             :         {
    4295           0 :             CPLFree(pData);
    4296           0 :             return eErr;
    4297             :         }
    4298             : 
    4299           0 :         GByte *pabyMaskData = nullptr;
    4300           0 :         if (poMaskBand)
    4301             :         {
    4302             :             pabyMaskData =
    4303           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    4304           0 :             if (!pabyMaskData)
    4305             :             {
    4306           0 :                 CPLFree(pData);
    4307           0 :                 return CE_Failure;
    4308             :             }
    4309             : 
    4310           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    4311             :                                      pabyMaskData, nXReduced, nYReduced,
    4312           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    4313             :             {
    4314           0 :                 CPLFree(pData);
    4315           0 :                 CPLFree(pabyMaskData);
    4316           0 :                 return CE_Failure;
    4317             :             }
    4318             :         }
    4319             : 
    4320             :         // This isn't the fastest way to do this, but is easier for now.
    4321           0 :         for (int iY = 0; iY < nYReduced; iY++)
    4322             :         {
    4323           0 :             for (int iX = 0; iX < nXReduced; iX++)
    4324             :             {
    4325           0 :                 const int iOffset = iX + iY * nXReduced;
    4326           0 :                 double dfValue = 0.0;
    4327             : 
    4328           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4329           0 :                     continue;
    4330             : 
    4331           0 :                 switch (eDataType)
    4332             :                 {
    4333           0 :                     case GDT_Byte:
    4334             :                     {
    4335           0 :                         if (bSignedByte)
    4336           0 :                             dfValue =
    4337           0 :                                 static_cast<signed char *>(pData)[iOffset];
    4338             :                         else
    4339           0 :                             dfValue = static_cast<GByte *>(pData)[iOffset];
    4340           0 :                         break;
    4341             :                     }
    4342           0 :                     case GDT_Int8:
    4343           0 :                         dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4344           0 :                         break;
    4345           0 :                     case GDT_UInt16:
    4346           0 :                         dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4347           0 :                         break;
    4348           0 :                     case GDT_Int16:
    4349           0 :                         dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4350           0 :                         break;
    4351           0 :                     case GDT_UInt32:
    4352           0 :                         dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4353           0 :                         break;
    4354           0 :                     case GDT_Int32:
    4355           0 :                         dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4356           0 :                         break;
    4357           0 :                     case GDT_UInt64:
    4358           0 :                         dfValue = static_cast<double>(
    4359           0 :                             static_cast<GUInt64 *>(pData)[iOffset]);
    4360           0 :                         break;
    4361           0 :                     case GDT_Int64:
    4362           0 :                         dfValue = static_cast<double>(
    4363           0 :                             static_cast<GInt64 *>(pData)[iOffset]);
    4364           0 :                         break;
    4365           0 :                     case GDT_Float16:
    4366             :                     {
    4367             :                         using namespace std;
    4368           0 :                         const GFloat16 hfValue =
    4369           0 :                             static_cast<GFloat16 *>(pData)[iOffset];
    4370           0 :                         if (isnan(hfValue) ||
    4371           0 :                             (sNoDataValues.bGotFloat16NoDataValue &&
    4372           0 :                              ARE_REAL_EQUAL(hfValue,
    4373             :                                             sNoDataValues.hfNoDataValue)))
    4374           0 :                             continue;
    4375           0 :                         dfValue = hfValue;
    4376           0 :                         break;
    4377             :                     }
    4378           0 :                     case GDT_Float32:
    4379             :                     {
    4380           0 :                         const float fValue =
    4381           0 :                             static_cast<float *>(pData)[iOffset];
    4382           0 :                         if (std::isnan(fValue) ||
    4383           0 :                             (sNoDataValues.bGotFloatNoDataValue &&
    4384           0 :                              ARE_REAL_EQUAL(fValue,
    4385             :                                             sNoDataValues.fNoDataValue)))
    4386           0 :                             continue;
    4387           0 :                         dfValue = fValue;
    4388           0 :                         break;
    4389             :                     }
    4390           0 :                     case GDT_Float64:
    4391           0 :                         dfValue = static_cast<double *>(pData)[iOffset];
    4392           0 :                         if (std::isnan(dfValue))
    4393           0 :                             continue;
    4394           0 :                         break;
    4395           0 :                     case GDT_CInt16:
    4396             :                     {
    4397           0 :                         const double dfReal =
    4398           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2];
    4399           0 :                         const double dfImag =
    4400           0 :                             static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4401           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4402           0 :                             continue;
    4403           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4404             :                     }
    4405           0 :                     break;
    4406           0 :                     case GDT_CInt32:
    4407             :                     {
    4408           0 :                         const double dfReal =
    4409           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2];
    4410           0 :                         const double dfImag =
    4411           0 :                             static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4412           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4413           0 :                             continue;
    4414           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4415             :                     }
    4416           0 :                     break;
    4417           0 :                     case GDT_CFloat16:
    4418             :                     {
    4419             :                         const double dfReal =
    4420           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2];
    4421             :                         const double dfImag =
    4422           0 :                             static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4423           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4424           0 :                             continue;
    4425           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4426           0 :                         break;
    4427             :                     }
    4428           0 :                     case GDT_CFloat32:
    4429             :                     {
    4430           0 :                         const double dfReal =
    4431           0 :                             static_cast<float *>(pData)[iOffset * 2];
    4432           0 :                         const double dfImag =
    4433           0 :                             static_cast<float *>(pData)[iOffset * 2 + 1];
    4434           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4435           0 :                             continue;
    4436           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4437           0 :                         break;
    4438             :                     }
    4439           0 :                     case GDT_CFloat64:
    4440             :                     {
    4441           0 :                         const double dfReal =
    4442           0 :                             static_cast<double *>(pData)[iOffset * 2];
    4443           0 :                         const double dfImag =
    4444           0 :                             static_cast<double *>(pData)[iOffset * 2 + 1];
    4445           0 :                         if (std::isnan(dfReal) || std::isnan(dfImag))
    4446           0 :                             continue;
    4447           0 :                         dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4448           0 :                         break;
    4449             :                     }
    4450           0 :                     case GDT_Unknown:
    4451             :                     case GDT_TypeCount:
    4452           0 :                         CPLAssert(false);
    4453             :                 }
    4454             : 
    4455           0 :                 if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4456           0 :                     sNoDataValues.bGotNoDataValue &&
    4457           0 :                     ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4458           0 :                     continue;
    4459             : 
    4460             :                 // Given that dfValue and dfMin are not NaN, and dfScale > 0 and
    4461             :                 // finite, the result of the multiplication cannot be NaN
    4462           0 :                 const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4463             : 
    4464           0 :                 if (dfIndex < 0)
    4465             :                 {
    4466           0 :                     if (bIncludeOutOfRange)
    4467           0 :                         panHistogram[0]++;
    4468             :                 }
    4469           0 :                 else if (dfIndex >= nBuckets)
    4470             :                 {
    4471           0 :                     if (bIncludeOutOfRange)
    4472           0 :                         ++panHistogram[nBuckets - 1];
    4473             :                 }
    4474             :                 else
    4475             :                 {
    4476           0 :                     ++panHistogram[static_cast<int>(dfIndex)];
    4477             :                 }
    4478             :             }
    4479             :         }
    4480             : 
    4481           0 :         CPLFree(pData);
    4482           0 :         CPLFree(pabyMaskData);
    4483             :     }
    4484             :     else  // No arbitrary overviews.
    4485             :     {
    4486          32 :         if (!InitBlockInfo())
    4487           0 :             return CE_Failure;
    4488             : 
    4489             :         /* --------------------------------------------------------------------
    4490             :          */
    4491             :         /*      Figure out the ratio of blocks we will read to get an */
    4492             :         /*      approximate value. */
    4493             :         /* --------------------------------------------------------------------
    4494             :          */
    4495             : 
    4496          32 :         int nSampleRate = 1;
    4497          32 :         if (bApproxOK)
    4498             :         {
    4499           8 :             nSampleRate = static_cast<int>(std::max(
    4500          16 :                 1.0,
    4501           8 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    4502             :             // We want to avoid probing only the first column of blocks for
    4503             :             // a square shaped raster, because it is not unlikely that it may
    4504             :             // be padding only (#6378).
    4505           8 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    4506           1 :                 nSampleRate += 1;
    4507             :         }
    4508             : 
    4509          32 :         GByte *pabyMaskData = nullptr;
    4510          32 :         if (poMaskBand)
    4511             :         {
    4512             :             pabyMaskData = static_cast<GByte *>(
    4513           2 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    4514           2 :             if (!pabyMaskData)
    4515             :             {
    4516           0 :                 return CE_Failure;
    4517             :             }
    4518             :         }
    4519             : 
    4520             :         /* --------------------------------------------------------------------
    4521             :          */
    4522             :         /*      Read the blocks, and add to histogram. */
    4523             :         /* --------------------------------------------------------------------
    4524             :          */
    4525          32 :         for (GIntBig iSampleBlock = 0;
    4526         154 :              iSampleBlock <
    4527         154 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    4528         122 :              iSampleBlock += nSampleRate)
    4529             :         {
    4530         122 :             if (!pfnProgress(
    4531         122 :                     static_cast<double>(iSampleBlock) /
    4532         122 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    4533             :                     "Compute Histogram", pProgressData))
    4534             :             {
    4535           0 :                 CPLFree(pabyMaskData);
    4536           0 :                 return CE_Failure;
    4537             :             }
    4538             : 
    4539         122 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    4540         122 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    4541             : 
    4542         122 :             int nXCheck = 0, nYCheck = 0;
    4543         122 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    4544             : 
    4545         124 :             if (poMaskBand &&
    4546           2 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    4547           2 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    4548             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    4549           2 :                                      0, nBlockXSize, nullptr) != CE_None)
    4550             :             {
    4551           0 :                 CPLFree(pabyMaskData);
    4552           0 :                 return CE_Failure;
    4553             :             }
    4554             : 
    4555         122 :             GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    4556         122 :             if (poBlock == nullptr)
    4557             :             {
    4558           0 :                 CPLFree(pabyMaskData);
    4559           0 :                 return CE_Failure;
    4560             :             }
    4561             : 
    4562         122 :             void *pData = poBlock->GetDataRef();
    4563             : 
    4564             :             // this is a special case for a common situation.
    4565         122 :             if (eDataType == GDT_Byte && !bSignedByte && dfScale == 1.0 &&
    4566          86 :                 (dfMin >= -0.5 && dfMin <= 0.5) && nYCheck == nBlockYSize &&
    4567          83 :                 nXCheck == nBlockXSize && nBuckets == 256)
    4568             :             {
    4569          83 :                 const GPtrDiff_t nPixels =
    4570          83 :                     static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    4571          83 :                 GByte *pabyData = static_cast<GByte *>(pData);
    4572             : 
    4573       72137 :                 for (GPtrDiff_t i = 0; i < nPixels; i++)
    4574             :                 {
    4575       72054 :                     if (pabyMaskData && pabyMaskData[i] == 0)
    4576           0 :                         continue;
    4577       72054 :                     if (!(sNoDataValues.bGotNoDataValue &&
    4578         512 :                           (pabyData[i] ==
    4579         512 :                            static_cast<GByte>(sNoDataValues.dfNoDataValue))))
    4580             :                     {
    4581       71798 :                         panHistogram[pabyData[i]]++;
    4582             :                     }
    4583             :                 }
    4584             : 
    4585          83 :                 poBlock->DropLock();
    4586          83 :                 continue;  // To next sample block.
    4587             :             }
    4588             : 
    4589             :             // This isn't the fastest way to do this, but is easier for now.
    4590         257 :             for (int iY = 0; iY < nYCheck; iY++)
    4591             :             {
    4592       36389 :                 for (int iX = 0; iX < nXCheck; iX++)
    4593             :                 {
    4594       36171 :                     const GPtrDiff_t iOffset =
    4595       36171 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    4596             : 
    4597       36171 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    4598           2 :                         continue;
    4599             : 
    4600       36169 :                     double dfValue = 0.0;
    4601             : 
    4602       36169 :                     switch (eDataType)
    4603             :                     {
    4604       19716 :                         case GDT_Byte:
    4605             :                         {
    4606       19716 :                             if (bSignedByte)
    4607           0 :                                 dfValue =
    4608           0 :                                     static_cast<signed char *>(pData)[iOffset];
    4609             :                             else
    4610       19716 :                                 dfValue = static_cast<GByte *>(pData)[iOffset];
    4611       19716 :                             break;
    4612             :                         }
    4613           1 :                         case GDT_Int8:
    4614           1 :                             dfValue = static_cast<GInt8 *>(pData)[iOffset];
    4615           1 :                             break;
    4616       16384 :                         case GDT_UInt16:
    4617       16384 :                             dfValue = static_cast<GUInt16 *>(pData)[iOffset];
    4618       16384 :                             break;
    4619           3 :                         case GDT_Int16:
    4620           3 :                             dfValue = static_cast<GInt16 *>(pData)[iOffset];
    4621           3 :                             break;
    4622           0 :                         case GDT_UInt32:
    4623           0 :                             dfValue = static_cast<GUInt32 *>(pData)[iOffset];
    4624           0 :                             break;
    4625          60 :                         case GDT_Int32:
    4626          60 :                             dfValue = static_cast<GInt32 *>(pData)[iOffset];
    4627          60 :                             break;
    4628           0 :                         case GDT_UInt64:
    4629           0 :                             dfValue = static_cast<double>(
    4630           0 :                                 static_cast<GUInt64 *>(pData)[iOffset]);
    4631           0 :                             break;
    4632           0 :                         case GDT_Int64:
    4633           0 :                             dfValue = static_cast<double>(
    4634           0 :                                 static_cast<GInt64 *>(pData)[iOffset]);
    4635           0 :                             break;
    4636           0 :                         case GDT_Float16:
    4637             :                         {
    4638             :                             using namespace std;
    4639           0 :                             const GFloat16 hfValue =
    4640           0 :                                 static_cast<GFloat16 *>(pData)[iOffset];
    4641           0 :                             if (isnan(hfValue) ||
    4642           0 :                                 (sNoDataValues.bGotFloat16NoDataValue &&
    4643           0 :                                  ARE_REAL_EQUAL(hfValue,
    4644             :                                                 sNoDataValues.hfNoDataValue)))
    4645           0 :                                 continue;
    4646           0 :                             dfValue = hfValue;
    4647           0 :                             break;
    4648             :                         }
    4649           3 :                         case GDT_Float32:
    4650             :                         {
    4651           3 :                             const float fValue =
    4652           3 :                                 static_cast<float *>(pData)[iOffset];
    4653           6 :                             if (std::isnan(fValue) ||
    4654           6 :                                 (sNoDataValues.bGotFloatNoDataValue &&
    4655           3 :                                  ARE_REAL_EQUAL(fValue,
    4656             :                                                 sNoDataValues.fNoDataValue)))
    4657           0 :                                 continue;
    4658           3 :                             dfValue = fValue;
    4659           3 :                             break;
    4660             :                         }
    4661           2 :                         case GDT_Float64:
    4662           2 :                             dfValue = static_cast<double *>(pData)[iOffset];
    4663           2 :                             if (std::isnan(dfValue))
    4664           0 :                                 continue;
    4665           2 :                             break;
    4666           0 :                         case GDT_CInt16:
    4667             :                         {
    4668           0 :                             double dfReal =
    4669           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2];
    4670           0 :                             double dfImag =
    4671           0 :                                 static_cast<GInt16 *>(pData)[iOffset * 2 + 1];
    4672           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4673           0 :                             break;
    4674             :                         }
    4675           0 :                         case GDT_CInt32:
    4676             :                         {
    4677           0 :                             double dfReal =
    4678           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2];
    4679           0 :                             double dfImag =
    4680           0 :                                 static_cast<GInt32 *>(pData)[iOffset * 2 + 1];
    4681           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4682           0 :                             break;
    4683             :                         }
    4684           0 :                         case GDT_CFloat16:
    4685             :                         {
    4686             :                             double dfReal =
    4687           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2];
    4688             :                             double dfImag =
    4689           0 :                                 static_cast<GFloat16 *>(pData)[iOffset * 2 + 1];
    4690           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4691           0 :                                 continue;
    4692           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4693           0 :                             break;
    4694             :                         }
    4695           0 :                         case GDT_CFloat32:
    4696             :                         {
    4697           0 :                             double dfReal =
    4698           0 :                                 static_cast<float *>(pData)[iOffset * 2];
    4699           0 :                             double dfImag =
    4700           0 :                                 static_cast<float *>(pData)[iOffset * 2 + 1];
    4701           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4702           0 :                                 continue;
    4703           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4704           0 :                             break;
    4705             :                         }
    4706           0 :                         case GDT_CFloat64:
    4707             :                         {
    4708           0 :                             double dfReal =
    4709           0 :                                 static_cast<double *>(pData)[iOffset * 2];
    4710           0 :                             double dfImag =
    4711           0 :                                 static_cast<double *>(pData)[iOffset * 2 + 1];
    4712           0 :                             if (std::isnan(dfReal) || std::isnan(dfImag))
    4713           0 :                                 continue;
    4714           0 :                             dfValue = sqrt(dfReal * dfReal + dfImag * dfImag);
    4715           0 :                             break;
    4716             :                         }
    4717           0 :                         case GDT_Unknown:
    4718             :                         case GDT_TypeCount:
    4719           0 :                             CPLAssert(false);
    4720             :                             CPLFree(pabyMaskData);
    4721             :                             return CE_Failure;
    4722             :                     }
    4723             : 
    4724       36169 :                     if (eDataType != GDT_Float16 && eDataType != GDT_Float32 &&
    4725       72338 :                         sNoDataValues.bGotNoDataValue &&
    4726           0 :                         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    4727           0 :                         continue;
    4728             : 
    4729             :                     // Given that dfValue and dfMin are not NaN, and dfScale > 0
    4730             :                     // and finite, the result of the multiplication cannot be
    4731             :                     // NaN
    4732       36169 :                     const double dfIndex = floor((dfValue - dfMin) * dfScale);
    4733             : 
    4734       36169 :                     if (dfIndex < 0)
    4735             :                     {
    4736           1 :                         if (bIncludeOutOfRange)
    4737           1 :                             panHistogram[0]++;
    4738             :                     }
    4739       36168 :                     else if (dfIndex >= nBuckets)
    4740             :                     {
    4741           7 :                         if (bIncludeOutOfRange)
    4742           4 :                             ++panHistogram[nBuckets - 1];
    4743             :                     }
    4744             :                     else
    4745             :                     {
    4746       36161 :                         ++panHistogram[static_cast<int>(dfIndex)];
    4747             :                     }
    4748             :                 }
    4749             :             }
    4750             : 
    4751          39 :             poBlock->DropLock();
    4752             :         }
    4753             : 
    4754          32 :         CPLFree(pabyMaskData);
    4755             :     }
    4756             : 
    4757          32 :     pfnProgress(1.0, "Compute Histogram", pProgressData);
    4758             : 
    4759          32 :     return CE_None;
    4760             : }
    4761             : 
    4762             : /************************************************************************/
    4763             : /*                       GDALGetRasterHistogram()                       */
    4764             : /************************************************************************/
    4765             : 
    4766             : /**
    4767             :  * \brief Compute raster histogram.
    4768             :  *
    4769             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4770             :  * exceeding 2 billion.
    4771             :  *
    4772             :  * @see GDALRasterBand::GetHistogram()
    4773             :  * @see GDALGetRasterHistogramEx()
    4774             :  */
    4775             : 
    4776           0 : CPLErr CPL_STDCALL GDALGetRasterHistogram(GDALRasterBandH hBand, double dfMin,
    4777             :                                           double dfMax, int nBuckets,
    4778             :                                           int *panHistogram,
    4779             :                                           int bIncludeOutOfRange, int bApproxOK,
    4780             :                                           GDALProgressFunc pfnProgress,
    4781             :                                           void *pProgressData)
    4782             : 
    4783             : {
    4784           0 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogram", CE_Failure);
    4785           0 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogram", CE_Failure);
    4786             : 
    4787           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4788             : 
    4789             :     GUIntBig *panHistogramTemp =
    4790           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    4791           0 :     if (panHistogramTemp == nullptr)
    4792             :     {
    4793           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    4794             :                             "Out of memory in GDALGetRasterHistogram().");
    4795           0 :         return CE_Failure;
    4796             :     }
    4797             : 
    4798           0 :     CPLErr eErr = poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogramTemp,
    4799             :                                        bIncludeOutOfRange, bApproxOK,
    4800           0 :                                        pfnProgress, pProgressData);
    4801             : 
    4802           0 :     if (eErr == CE_None)
    4803             :     {
    4804           0 :         for (int i = 0; i < nBuckets; i++)
    4805             :         {
    4806           0 :             if (panHistogramTemp[i] > INT_MAX)
    4807             :             {
    4808           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    4809             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    4810             :                          " exceeds maximum 32 bit value",
    4811           0 :                          i, panHistogramTemp[i]);
    4812           0 :                 panHistogram[i] = INT_MAX;
    4813             :             }
    4814             :             else
    4815             :             {
    4816           0 :                 panHistogram[i] = static_cast<int>(panHistogramTemp[i]);
    4817             :             }
    4818             :         }
    4819             :     }
    4820             : 
    4821           0 :     CPLFree(panHistogramTemp);
    4822             : 
    4823           0 :     return eErr;
    4824             : }
    4825             : 
    4826             : /************************************************************************/
    4827             : /*                      GDALGetRasterHistogramEx()                      */
    4828             : /************************************************************************/
    4829             : 
    4830             : /**
    4831             :  * \brief Compute raster histogram.
    4832             :  *
    4833             :  * @see GDALRasterBand::GetHistogram()
    4834             :  *
    4835             :  * @since GDAL 2.0
    4836             :  */
    4837             : 
    4838          26 : CPLErr CPL_STDCALL GDALGetRasterHistogramEx(
    4839             :     GDALRasterBandH hBand, double dfMin, double dfMax, int nBuckets,
    4840             :     GUIntBig *panHistogram, int bIncludeOutOfRange, int bApproxOK,
    4841             :     GDALProgressFunc pfnProgress, void *pProgressData)
    4842             : 
    4843             : {
    4844          26 :     VALIDATE_POINTER1(hBand, "GDALGetRasterHistogramEx", CE_Failure);
    4845          26 :     VALIDATE_POINTER1(panHistogram, "GDALGetRasterHistogramEx", CE_Failure);
    4846             : 
    4847          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    4848             : 
    4849          26 :     return poBand->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
    4850             :                                 bIncludeOutOfRange, bApproxOK, pfnProgress,
    4851          26 :                                 pProgressData);
    4852             : }
    4853             : 
    4854             : /************************************************************************/
    4855             : /*                        GetDefaultHistogram()                         */
    4856             : /************************************************************************/
    4857             : 
    4858             : /**
    4859             :  * \brief Fetch default raster histogram.
    4860             :  *
    4861             :  * The default method in GDALRasterBand will compute a default histogram. This
    4862             :  * method is overridden by derived classes (such as GDALPamRasterBand,
    4863             :  * VRTDataset, HFADataset...) that may be able to fetch efficiently an already
    4864             :  * stored histogram.
    4865             :  *
    4866             :  * This method is the same as the C functions GDALGetDefaultHistogram() and
    4867             :  * GDALGetDefaultHistogramEx().
    4868             :  *
    4869             :  * @param pdfMin pointer to double value that will contain the lower bound of
    4870             :  * the histogram.
    4871             :  * @param pdfMax pointer to double value that will contain the upper bound of
    4872             :  * the histogram.
    4873             :  * @param pnBuckets pointer to int value that will contain the number of buckets
    4874             :  * in *ppanHistogram.
    4875             :  * @param ppanHistogram pointer to array into which the histogram totals are
    4876             :  * placed. To be freed with VSIFree
    4877             :  * @param bForce TRUE to force the computation. If FALSE and no default
    4878             :  * histogram is available, the method will return CE_Warning
    4879             :  * @param pfnProgress function to report progress to completion.
    4880             :  * @param pProgressData application data to pass to pfnProgress.
    4881             :  *
    4882             :  * @return CE_None on success, CE_Failure if something goes wrong, or
    4883             :  * CE_Warning if no default histogram is available.
    4884             :  */
    4885             : 
    4886          24 : CPLErr GDALRasterBand::GetDefaultHistogram(double *pdfMin, double *pdfMax,
    4887             :                                            int *pnBuckets,
    4888             :                                            GUIntBig **ppanHistogram, int bForce,
    4889             :                                            GDALProgressFunc pfnProgress,
    4890             :                                            void *pProgressData)
    4891             : 
    4892             : {
    4893          24 :     CPLAssert(nullptr != pnBuckets);
    4894          24 :     CPLAssert(nullptr != ppanHistogram);
    4895          24 :     CPLAssert(nullptr != pdfMin);
    4896          24 :     CPLAssert(nullptr != pdfMax);
    4897             : 
    4898          24 :     *pnBuckets = 0;
    4899          24 :     *ppanHistogram = nullptr;
    4900             : 
    4901          24 :     if (!bForce)
    4902           5 :         return CE_Warning;
    4903             : 
    4904          19 :     int nBuckets = 256;
    4905             : 
    4906          19 :     bool bSignedByte = false;
    4907          19 :     if (eDataType == GDT_Byte)
    4908             :     {
    4909          17 :         EnablePixelTypeSignedByteWarning(false);
    4910             :         const char *pszPixelType =
    4911          17 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    4912          17 :         EnablePixelTypeSignedByteWarning(true);
    4913          17 :         bSignedByte =
    4914          17 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    4915             :     }
    4916             : 
    4917          19 :     if (GetRasterDataType() == GDT_Byte && !bSignedByte)
    4918             :     {
    4919          17 :         *pdfMin = -0.5;
    4920          17 :         *pdfMax = 255.5;
    4921             :     }
    4922           2 :     else if (GetRasterDataType() == GDT_Int8)
    4923             :     {
    4924           1 :         *pdfMin = -128 - 0.5;
    4925           1 :         *pdfMax = 127 + 0.5;
    4926             :     }
    4927             :     else
    4928             :     {
    4929             : 
    4930             :         const CPLErr eErr =
    4931           1 :             GetStatistics(TRUE, TRUE, pdfMin, pdfMax, nullptr, nullptr);
    4932           1 :         if (eErr != CE_None)
    4933           0 :             return eErr;
    4934           1 :         if (*pdfMin == *pdfMax)
    4935             :         {
    4936           1 :             nBuckets = 1;
    4937           1 :             *pdfMin -= 0.5;
    4938           1 :             *pdfMax += 0.5;
    4939             :         }
    4940             :         else
    4941             :         {
    4942           0 :             const double dfHalfBucket =
    4943           0 :                 (*pdfMax - *pdfMin) / (2 * (nBuckets - 1));
    4944           0 :             *pdfMin -= dfHalfBucket;
    4945           0 :             *pdfMax += dfHalfBucket;
    4946             :         }
    4947             :     }
    4948             : 
    4949          19 :     *ppanHistogram =
    4950          19 :         static_cast<GUIntBig *>(VSICalloc(sizeof(GUIntBig), nBuckets));
    4951          19 :     if (*ppanHistogram == nullptr)
    4952             :     {
    4953           0 :         ReportError(CE_Failure, CPLE_OutOfMemory,
    4954             :                     "Out of memory in InitBlockInfo().");
    4955           0 :         return CE_Failure;
    4956             :     }
    4957             : 
    4958          19 :     *pnBuckets = nBuckets;
    4959          38 :     CPLErr eErr = GetHistogram(*pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
    4960          19 :                                TRUE, FALSE, pfnProgress, pProgressData);
    4961          19 :     if (eErr != CE_None)
    4962             :     {
    4963           0 :         *pnBuckets = 0;
    4964             :     }
    4965          19 :     return eErr;
    4966             : }
    4967             : 
    4968             : /************************************************************************/
    4969             : /*                      GDALGetDefaultHistogram()                       */
    4970             : /************************************************************************/
    4971             : 
    4972             : /**
    4973             :  * \brief Fetch default raster histogram.
    4974             :  *
    4975             :  * Use GDALGetRasterHistogramEx() instead to get correct counts for values
    4976             :  * exceeding 2 billion.
    4977             :  *
    4978             :  * @see GDALRasterBand::GDALGetDefaultHistogram()
    4979             :  * @see GDALGetRasterHistogramEx()
    4980             :  */
    4981             : 
    4982           0 : CPLErr CPL_STDCALL GDALGetDefaultHistogram(GDALRasterBandH hBand,
    4983             :                                            double *pdfMin, double *pdfMax,
    4984             :                                            int *pnBuckets, int **ppanHistogram,
    4985             :                                            int bForce,
    4986             :                                            GDALProgressFunc pfnProgress,
    4987             :                                            void *pProgressData)
    4988             : 
    4989             : {
    4990           0 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    4991           0 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    4992           0 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    4993           0 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    4994           0 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    4995             : 
    4996           0 :     GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
    4997           0 :     GUIntBig *panHistogramTemp = nullptr;
    4998           0 :     CPLErr eErr = poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
    4999             :                                               &panHistogramTemp, bForce,
    5000           0 :                                               pfnProgress, pProgressData);
    5001           0 :     if (eErr == CE_None)
    5002             :     {
    5003           0 :         const int nBuckets = *pnBuckets;
    5004           0 :         *ppanHistogram = static_cast<int *>(VSIMalloc2(sizeof(int), nBuckets));
    5005           0 :         if (*ppanHistogram == nullptr)
    5006             :         {
    5007           0 :             poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    5008             :                                 "Out of memory in GDALGetDefaultHistogram().");
    5009           0 :             VSIFree(panHistogramTemp);
    5010           0 :             return CE_Failure;
    5011             :         }
    5012             : 
    5013           0 :         for (int i = 0; i < nBuckets; ++i)
    5014             :         {
    5015           0 :             if (panHistogramTemp[i] > INT_MAX)
    5016             :             {
    5017           0 :                 CPLError(CE_Warning, CPLE_AppDefined,
    5018             :                          "Count for bucket %d, which is " CPL_FRMT_GUIB
    5019             :                          " exceeds maximum 32 bit value",
    5020           0 :                          i, panHistogramTemp[i]);
    5021           0 :                 (*ppanHistogram)[i] = INT_MAX;
    5022             :             }
    5023             :             else
    5024             :             {
    5025           0 :                 (*ppanHistogram)[i] = static_cast<int>(panHistogramTemp[i]);
    5026             :             }
    5027             :         }
    5028             : 
    5029           0 :         CPLFree(panHistogramTemp);
    5030             :     }
    5031             :     else
    5032             :     {
    5033           0 :         *ppanHistogram = nullptr;
    5034             :     }
    5035             : 
    5036           0 :     return eErr;
    5037             : }
    5038             : 
    5039             : /************************************************************************/
    5040             : /*                      GDALGetDefaultHistogramEx()                     */
    5041             : /************************************************************************/
    5042             : 
    5043             : /**
    5044             :  * \brief Fetch default raster histogram.
    5045             :  *
    5046             :  * @see GDALRasterBand::GetDefaultHistogram()
    5047             :  *
    5048             :  * @since GDAL 2.0
    5049             :  */
    5050             : 
    5051             : CPLErr CPL_STDCALL
    5052          30 : GDALGetDefaultHistogramEx(GDALRasterBandH hBand, double *pdfMin, double *pdfMax,
    5053             :                           int *pnBuckets, GUIntBig **ppanHistogram, int bForce,
    5054             :                           GDALProgressFunc pfnProgress, void *pProgressData)
    5055             : 
    5056             : {
    5057          30 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultHistogram", CE_Failure);
    5058          30 :     VALIDATE_POINTER1(pdfMin, "GDALGetDefaultHistogram", CE_Failure);
    5059          30 :     VALIDATE_POINTER1(pdfMax, "GDALGetDefaultHistogram", CE_Failure);
    5060          30 :     VALIDATE_POINTER1(pnBuckets, "GDALGetDefaultHistogram", CE_Failure);
    5061          30 :     VALIDATE_POINTER1(ppanHistogram, "GDALGetDefaultHistogram", CE_Failure);
    5062             : 
    5063          30 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5064          30 :     return poBand->GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram,
    5065          30 :                                        bForce, pfnProgress, pProgressData);
    5066             : }
    5067             : 
    5068             : /************************************************************************/
    5069             : /*                             AdviseRead()                             */
    5070             : /************************************************************************/
    5071             : 
    5072             : /**
    5073             :  * \fn GDALRasterBand::AdviseRead(int,int,int,int,int,int,GDALDataType,char**)
    5074             :  * \brief Advise driver of upcoming read requests.
    5075             :  *
    5076             :  * Some GDAL drivers operate more efficiently if they know in advance what
    5077             :  * set of upcoming read requests will be made.  The AdviseRead() method allows
    5078             :  * an application to notify the driver of the region of interest,
    5079             :  * and at what resolution the region will be read.
    5080             :  *
    5081             :  * Many drivers just ignore the AdviseRead() call, but it can dramatically
    5082             :  * accelerate access via some drivers.
    5083             :  *
    5084             :  * Depending on call paths, drivers might receive several calls to
    5085             :  * AdviseRead() with the same parameters.
    5086             :  *
    5087             :  * @param nXOff The pixel offset to the top left corner of the region
    5088             :  * of the band to be accessed.  This would be zero to start from the left side.
    5089             :  *
    5090             :  * @param nYOff The line offset to the top left corner of the region
    5091             :  * of the band to be accessed.  This would be zero to start from the top.
    5092             :  *
    5093             :  * @param nXSize The width of the region of the band to be accessed in pixels.
    5094             :  *
    5095             :  * @param nYSize The height of the region of the band to be accessed in lines.
    5096             :  *
    5097             :  * @param nBufXSize the width of the buffer image into which the desired region
    5098             :  * is to be read, or from which it is to be written.
    5099             :  *
    5100             :  * @param nBufYSize the height of the buffer image into which the desired
    5101             :  * region is to be read, or from which it is to be written.
    5102             :  *
    5103             :  * @param eBufType the type of the pixel values in the pData data buffer.  The
    5104             :  * pixel values will automatically be translated to/from the GDALRasterBand
    5105             :  * data type as needed.
    5106             :  *
    5107             :  * @param papszOptions a list of name=value strings with special control
    5108             :  * options.  Normally this is NULL.
    5109             :  *
    5110             :  * @return CE_Failure if the request is invalid and CE_None if it works or
    5111             :  * is ignored.
    5112             :  */
    5113             : 
    5114             : /**/
    5115             : /**/
    5116             : 
    5117      113437 : CPLErr GDALRasterBand::AdviseRead(int /*nXOff*/, int /*nYOff*/, int /*nXSize*/,
    5118             :                                   int /*nYSize*/, int /*nBufXSize*/,
    5119             :                                   int /*nBufYSize*/, GDALDataType /*eBufType*/,
    5120             :                                   char ** /*papszOptions*/)
    5121             : {
    5122      113437 :     return CE_None;
    5123             : }
    5124             : 
    5125             : /************************************************************************/
    5126             : /*                        GDALRasterAdviseRead()                        */
    5127             : /************************************************************************/
    5128             : 
    5129             : /**
    5130             :  * \brief Advise driver of upcoming read requests.
    5131             :  *
    5132             :  * @see GDALRasterBand::AdviseRead()
    5133             :  */
    5134             : 
    5135           2 : CPLErr CPL_STDCALL GDALRasterAdviseRead(GDALRasterBandH hBand, int nXOff,
    5136             :                                         int nYOff, int nXSize, int nYSize,
    5137             :                                         int nBufXSize, int nBufYSize,
    5138             :                                         GDALDataType eDT,
    5139             :                                         CSLConstList papszOptions)
    5140             : 
    5141             : {
    5142           2 :     VALIDATE_POINTER1(hBand, "GDALRasterAdviseRead", CE_Failure);
    5143             : 
    5144           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5145           2 :     return poBand->AdviseRead(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    5146             :                               nBufYSize, eDT,
    5147           2 :                               const_cast<char **>(papszOptions));
    5148             : }
    5149             : 
    5150             : /************************************************************************/
    5151             : /*                           GetStatistics()                            */
    5152             : /************************************************************************/
    5153             : 
    5154             : /**
    5155             :  * \brief Fetch image statistics.
    5156             :  *
    5157             :  * Returns the minimum, maximum, mean and standard deviation of all
    5158             :  * pixel values in this band.  If approximate statistics are sufficient,
    5159             :  * the bApproxOK flag can be set to true in which case overviews, or a
    5160             :  * subset of image tiles may be used in computing the statistics.
    5161             :  *
    5162             :  * If bForce is FALSE results will only be returned if it can be done
    5163             :  * quickly (i.e. without scanning the image, typically by using pre-existing
    5164             :  * STATISTICS_xxx metadata items). If bForce is FALSE and results cannot be
    5165             :  * returned efficiently, the method will return CE_Warning but no warning will
    5166             :  * be issued. This is a non-standard use of the CE_Warning return value
    5167             :  * to indicate "nothing done".
    5168             :  *
    5169             :  * If bForce is TRUE, and results are quickly available without scanning the
    5170             :  * image, they will be used. If bForce is TRUE and results are not quickly
    5171             :  * available, GetStatistics() forwards the computation to ComputeStatistics(),
    5172             :  * which will scan the image.
    5173             :  *
    5174             :  * To always force recomputation of statistics, use ComputeStatistics() instead
    5175             :  * of this method.
    5176             :  *
    5177             :  * Note that file formats using PAM (Persistent Auxiliary Metadata) services
    5178             :  * will generally cache statistics in the .pam file allowing fast fetch
    5179             :  * after the first request.
    5180             :  *
    5181             :  * This method is the same as the C function GDALGetRasterStatistics().
    5182             :  *
    5183             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    5184             :  * or a subset of all tiles.
    5185             :  *
    5186             :  * @param bForce If FALSE statistics will only be returned if it can
    5187             :  * be done without rescanning the image. If TRUE, statistics computation will
    5188             :  * be forced if pre-existing values are not quickly available.
    5189             :  *
    5190             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    5191             :  *
    5192             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    5193             :  *
    5194             :  * @param pdfMean Location into which to load image mean (may be NULL).
    5195             :  *
    5196             :  * @param pdfStdDev Location into which to load image standard deviation
    5197             :  * (may be NULL).
    5198             :  *
    5199             :  * @return CE_None on success, CE_Warning if no values returned,
    5200             :  * CE_Failure if an error occurs.
    5201             :  */
    5202             : 
    5203         628 : CPLErr GDALRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
    5204             :                                      double *pdfMax, double *pdfMean,
    5205             :                                      double *pdfStdDev)
    5206             : 
    5207             : {
    5208             :     /* -------------------------------------------------------------------- */
    5209             :     /*      Do we already have metadata items for the requested values?     */
    5210             :     /* -------------------------------------------------------------------- */
    5211        1256 :     if ((pdfMin == nullptr ||
    5212         628 :          GetMetadataItem("STATISTICS_MINIMUM") != nullptr) &&
    5213         203 :         (pdfMax == nullptr ||
    5214         203 :          GetMetadataItem("STATISTICS_MAXIMUM") != nullptr) &&
    5215        1459 :         (pdfMean == nullptr || GetMetadataItem("STATISTICS_MEAN") != nullptr) &&
    5216         203 :         (pdfStdDev == nullptr ||
    5217         203 :          GetMetadataItem("STATISTICS_STDDEV") != nullptr))
    5218             :     {
    5219         203 :         if (!(GetMetadataItem("STATISTICS_APPROXIMATE") && !bApproxOK))
    5220             :         {
    5221         196 :             if (pdfMin != nullptr)
    5222         196 :                 *pdfMin = CPLAtofM(GetMetadataItem("STATISTICS_MINIMUM"));
    5223         196 :             if (pdfMax != nullptr)
    5224         196 :                 *pdfMax = CPLAtofM(GetMetadataItem("STATISTICS_MAXIMUM"));
    5225         196 :             if (pdfMean != nullptr)
    5226         196 :                 *pdfMean = CPLAtofM(GetMetadataItem("STATISTICS_MEAN"));
    5227         196 :             if (pdfStdDev != nullptr)
    5228         196 :                 *pdfStdDev = CPLAtofM(GetMetadataItem("STATISTICS_STDDEV"));
    5229             : 
    5230         196 :             return CE_None;
    5231             :         }
    5232             :     }
    5233             : 
    5234             :     /* -------------------------------------------------------------------- */
    5235             :     /*      Does the driver already know the min/max?                       */
    5236             :     /* -------------------------------------------------------------------- */
    5237         432 :     if (bApproxOK && pdfMean == nullptr && pdfStdDev == nullptr)
    5238             :     {
    5239           1 :         int bSuccessMin = FALSE;
    5240           1 :         int bSuccessMax = FALSE;
    5241             : 
    5242           1 :         const double dfMin = GetMinimum(&bSuccessMin);
    5243           1 :         const double dfMax = GetMaximum(&bSuccessMax);
    5244             : 
    5245           1 :         if (bSuccessMin && bSuccessMax)
    5246             :         {
    5247           0 :             if (pdfMin != nullptr)
    5248           0 :                 *pdfMin = dfMin;
    5249           0 :             if (pdfMax != nullptr)
    5250           0 :                 *pdfMax = dfMax;
    5251           0 :             return CE_None;
    5252             :         }
    5253             :     }
    5254             : 
    5255             :     /* -------------------------------------------------------------------- */
    5256             :     /*      Either return without results, or force computation.            */
    5257             :     /* -------------------------------------------------------------------- */
    5258         432 :     if (!bForce)
    5259         176 :         return CE_Warning;
    5260             :     else
    5261         256 :         return ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
    5262         256 :                                  GDALDummyProgress, nullptr);
    5263             : }
    5264             : 
    5265             : /************************************************************************/
    5266             : /*                      GDALGetRasterStatistics()                       */
    5267             : /************************************************************************/
    5268             : 
    5269             : /**
    5270             :  * \brief Fetch image statistics.
    5271             :  *
    5272             :  * @see GDALRasterBand::GetStatistics()
    5273             :  */
    5274             : 
    5275         276 : CPLErr CPL_STDCALL GDALGetRasterStatistics(GDALRasterBandH hBand, int bApproxOK,
    5276             :                                            int bForce, double *pdfMin,
    5277             :                                            double *pdfMax, double *pdfMean,
    5278             :                                            double *pdfStdDev)
    5279             : 
    5280             : {
    5281         276 :     VALIDATE_POINTER1(hBand, "GDALGetRasterStatistics", CE_Failure);
    5282             : 
    5283         276 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    5284         276 :     return poBand->GetStatistics(bApproxOK, bForce, pdfMin, pdfMax, pdfMean,
    5285         276 :                                  pdfStdDev);
    5286             : }
    5287             : 
    5288             : /************************************************************************/
    5289             : /*                         GDALUInt128                                  */
    5290             : /************************************************************************/
    5291             : 
    5292             : #ifdef HAVE_UINT128_T
    5293             : class GDALUInt128
    5294             : {
    5295             :     __uint128_t val;
    5296             : 
    5297         642 :     explicit GDALUInt128(__uint128_t valIn) : val(valIn)
    5298             :     {
    5299         642 :     }
    5300             : 
    5301             :   public:
    5302         428 :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5303             :     {
    5304             :         // Evaluates to just a single mul on x86_64
    5305         428 :         return GDALUInt128(static_cast<__uint128_t>(first) * second);
    5306             :     }
    5307             : 
    5308         214 :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5309             :     {
    5310         214 :         return GDALUInt128(val - other.val);
    5311             :     }
    5312             : 
    5313         205 :     operator double() const
    5314             :     {
    5315         205 :         return static_cast<double>(val);
    5316             :     }
    5317             : };
    5318             : #else
    5319             : 
    5320             : #if defined(_MSC_VER) && defined(_M_X64)
    5321             : #include <intrin.h>
    5322             : #endif
    5323             : 
    5324             : class GDALUInt128
    5325             : {
    5326             :     GUIntBig low, high;
    5327             : 
    5328             :     GDALUInt128(GUIntBig lowIn, GUIntBig highIn) : low(lowIn), high(highIn)
    5329             :     {
    5330             :     }
    5331             : 
    5332             :   public:
    5333             :     static GDALUInt128 Mul(GUIntBig first, GUIntBig second)
    5334             :     {
    5335             : #if defined(_MSC_VER) && defined(_M_X64)
    5336             :         GUIntBig highRes;
    5337             :         GUIntBig lowRes = _umul128(first, second, &highRes);
    5338             :         return GDALUInt128(lowRes, highRes);
    5339             : #else
    5340             :         const GUInt32 firstLow = static_cast<GUInt32>(first);
    5341             :         const GUInt32 firstHigh = static_cast<GUInt32>(first >> 32);
    5342             :         const GUInt32 secondLow = static_cast<GUInt32>(second);
    5343             :         const GUInt32 secondHigh = static_cast<GUInt32>(second >> 32);
    5344             :         GUIntBig highRes = 0;
    5345             :         const GUIntBig firstLowSecondHigh =
    5346             :             static_cast<GUIntBig>(firstLow) * secondHigh;
    5347             :         const GUIntBig firstHighSecondLow =
    5348             :             static_cast<GUIntBig>(firstHigh) * secondLow;
    5349             :         const GUIntBig middleTerm = firstLowSecondHigh + firstHighSecondLow;
    5350             :         if (middleTerm < firstLowSecondHigh)  // check for overflow
    5351             :             highRes += static_cast<GUIntBig>(1) << 32;
    5352             :         const GUIntBig firstLowSecondLow =
    5353             :             static_cast<GUIntBig>(firstLow) * secondLow;
    5354             :         GUIntBig lowRes = firstLowSecondLow + (middleTerm << 32);
    5355             :         if (lowRes < firstLowSecondLow)  // check for overflow
    5356             :             highRes++;
    5357             :         highRes +=
    5358             :             (middleTerm >> 32) + static_cast<GUIntBig>(firstHigh) * secondHigh;
    5359             :         return GDALUInt128(lowRes, highRes);
    5360             : #endif
    5361             :     }
    5362             : 
    5363             :     GDALUInt128 operator-(const GDALUInt128 &other) const
    5364             :     {
    5365             :         GUIntBig highRes = high - other.high;
    5366             :         GUIntBig lowRes = low - other.low;
    5367             :         if (lowRes > low)  // check for underflow
    5368             :             --highRes;
    5369             :         return GDALUInt128(lowRes, highRes);
    5370             :     }
    5371             : 
    5372             :     operator double() const
    5373             :     {
    5374             :         const double twoPow64 = 18446744073709551616.0;
    5375             :         return high * twoPow64 + low;
    5376             :     }
    5377             : };
    5378             : #endif
    5379             : 
    5380             : /************************************************************************/
    5381             : /*                    ComputeStatisticsInternal()                       */
    5382             : /************************************************************************/
    5383             : 
    5384             : // Just to make coverity scan happy w.r.t overflow_before_widen, but otherwise
    5385             : // not needed.
    5386             : #define static_cast_for_coverity_scan static_cast
    5387             : 
    5388             : // The rationale for below optimizations is detailed in statistics.txt
    5389             : 
    5390             : // Use with T = GByte or GUInt16 only !
    5391             : template <class T, bool COMPUTE_OTHER_STATS>
    5392             : struct ComputeStatisticsInternalGeneric
    5393             : {
    5394         208 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5395             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5396             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5397             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5398             :     {
    5399             :         static_assert(std::is_same<T, GByte>::value ||
    5400             :                           std::is_same<T, GUInt16>::value,
    5401             :                       "bad type for T");
    5402         208 :         if (bHasNoData)
    5403             :         {
    5404             :             // General case
    5405         386 :             for (int iY = 0; iY < nYCheck; iY++)
    5406             :             {
    5407       81751 :                 for (int iX = 0; iX < nXCheck; iX++)
    5408             :                 {
    5409       81468 :                     const GPtrDiff_t iOffset =
    5410       81468 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5411       81468 :                     const GUInt32 nValue = pData[iOffset];
    5412       81468 :                     if (nValue == nNoDataValue)
    5413         175 :                         continue;
    5414       81293 :                     if (nValue < nMin)
    5415          26 :                         nMin = nValue;
    5416       81293 :                     if (nValue > nMax)
    5417          57 :                         nMax = nValue;
    5418             :                     if constexpr (COMPUTE_OTHER_STATS)
    5419             :                     {
    5420       79657 :                         nValidCount++;
    5421       79657 :                         nSum += nValue;
    5422       79657 :                         nSumSquare +=
    5423       79657 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5424       79657 :                             nValue;
    5425             :                     }
    5426             :                 }
    5427             :             }
    5428             :             if constexpr (COMPUTE_OTHER_STATS)
    5429             :             {
    5430          20 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5431             :             }
    5432             :         }
    5433         115 :         else if (nMin == std::numeric_limits<T>::lowest() &&
    5434          10 :                  nMax == std::numeric_limits<T>::max())
    5435             :         {
    5436             :             if constexpr (COMPUTE_OTHER_STATS)
    5437             :             {
    5438             :                 // Optimization when there is no nodata and we know we have already
    5439             :                 // reached the min and max
    5440         208 :                 for (int iY = 0; iY < nYCheck; iY++)
    5441             :                 {
    5442             :                     int iX;
    5443        1002 :                     for (iX = 0; iX + 3 < nXCheck; iX += 4)
    5444             :                     {
    5445         800 :                         const GPtrDiff_t iOffset =
    5446         800 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5447         800 :                         const GUIntBig nValue = pData[iOffset];
    5448         800 :                         const GUIntBig nValue2 = pData[iOffset + 1];
    5449         800 :                         const GUIntBig nValue3 = pData[iOffset + 2];
    5450         800 :                         const GUIntBig nValue4 = pData[iOffset + 3];
    5451         800 :                         nSum += nValue;
    5452         800 :                         nSumSquare += nValue * nValue;
    5453         800 :                         nSum += nValue2;
    5454         800 :                         nSumSquare += nValue2 * nValue2;
    5455         800 :                         nSum += nValue3;
    5456         800 :                         nSumSquare += nValue3 * nValue3;
    5457         800 :                         nSum += nValue4;
    5458         800 :                         nSumSquare += nValue4 * nValue4;
    5459             :                     }
    5460         207 :                     for (; iX < nXCheck; ++iX)
    5461             :                     {
    5462           5 :                         const GPtrDiff_t iOffset =
    5463           5 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5464           5 :                         const GUIntBig nValue = pData[iOffset];
    5465           5 :                         nSum += nValue;
    5466           5 :                         nSumSquare += nValue * nValue;
    5467             :                     }
    5468             :                 }
    5469           6 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5470           6 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5471             :             }
    5472             :         }
    5473             :         else
    5474             :         {
    5475        3434 :             for (int iY = 0; iY < nYCheck; iY++)
    5476             :             {
    5477             :                 int iX;
    5478      643297 :                 for (iX = 0; iX + 1 < nXCheck; iX += 2)
    5479             :                 {
    5480      639962 :                     const GPtrDiff_t iOffset =
    5481      639962 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5482      639962 :                     const GUInt32 nValue = pData[iOffset];
    5483      639962 :                     const GUInt32 nValue2 = pData[iOffset + 1];
    5484      639962 :                     if (nValue < nValue2)
    5485             :                     {
    5486        2320 :                         if (nValue < nMin)
    5487          48 :                             nMin = nValue;
    5488        2320 :                         if (nValue2 > nMax)
    5489         116 :                             nMax = nValue2;
    5490             :                     }
    5491             :                     else
    5492             :                     {
    5493      637642 :                         if (nValue2 < nMin)
    5494          66 :                             nMin = nValue2;
    5495      637642 :                         if (nValue > nMax)
    5496         215 :                             nMax = nValue;
    5497             :                     }
    5498             :                     if constexpr (COMPUTE_OTHER_STATS)
    5499             :                     {
    5500      632911 :                         nSum += nValue;
    5501      632911 :                         nSumSquare +=
    5502      632911 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5503      632911 :                             nValue;
    5504      632911 :                         nSum += nValue2;
    5505      632911 :                         nSumSquare +=
    5506      632911 :                             static_cast_for_coverity_scan<GUIntBig>(nValue2) *
    5507      632911 :                             nValue2;
    5508             :                     }
    5509             :                 }
    5510        3335 :                 if (iX < nXCheck)
    5511             :                 {
    5512          18 :                     const GPtrDiff_t iOffset =
    5513          18 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5514          18 :                     const GUInt32 nValue = pData[iOffset];
    5515          18 :                     if (nValue < nMin)
    5516          13 :                         nMin = nValue;
    5517          18 :                     if (nValue > nMax)
    5518          14 :                         nMax = nValue;
    5519             :                     if (COMPUTE_OTHER_STATS)
    5520             :                     {
    5521           9 :                         nSum += nValue;
    5522           9 :                         nSumSquare +=
    5523           9 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5524           9 :                             nValue;
    5525             :                     }
    5526             :                 }
    5527             :             }
    5528             :             if constexpr (COMPUTE_OTHER_STATS)
    5529             :             {
    5530          44 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5531          44 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5532             :             }
    5533             :         }
    5534         208 :     }
    5535             : };
    5536             : 
    5537             : // Specialization for Byte that is mostly 32 bit friendly as it avoids
    5538             : // using 64bit accumulators in internal loops. This also slightly helps in
    5539             : // 64bit mode.
    5540             : template <bool COMPUTE_OTHER_STATS>
    5541             : struct ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>
    5542             : {
    5543       13697 :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const GByte *pData,
    5544             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5545             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5546             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5547             :     {
    5548       13697 :         int nOuterLoops = nXCheck / 65536;
    5549       13697 :         if (nXCheck % 65536)
    5550       13697 :             nOuterLoops++;
    5551             : 
    5552       13697 :         if (bHasNoData)
    5553             :         {
    5554             :             // General case
    5555       23475 :             for (int iY = 0; iY < nYCheck; iY++)
    5556             :             {
    5557       12901 :                 int iX = 0;
    5558       25802 :                 for (int k = 0; k < nOuterLoops; k++)
    5559             :                 {
    5560       12901 :                     int iMax = iX + 65536;
    5561       12901 :                     if (iMax > nXCheck)
    5562       12901 :                         iMax = nXCheck;
    5563       12901 :                     GUInt32 nSum32bit = 0;
    5564       12901 :                     GUInt32 nSumSquare32bit = 0;
    5565       12901 :                     GUInt32 nValidCount32bit = 0;
    5566       12901 :                     GUInt32 nSampleCount32bit = 0;
    5567    20707205 :                     for (; iX < iMax; iX++)
    5568             :                     {
    5569    20694353 :                         const GPtrDiff_t iOffset =
    5570    20694353 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5571    20694353 :                         const GUInt32 nValue = pData[iOffset];
    5572             : 
    5573    20694353 :                         nSampleCount32bit++;
    5574    20694353 :                         if (nValue == nNoDataValue)
    5575    20353480 :                             continue;
    5576      340818 :                         if (nValue < nMin)
    5577         357 :                             nMin = nValue;
    5578      340818 :                         if (nValue > nMax)
    5579         813 :                             nMax = nValue;
    5580             :                         if constexpr (COMPUTE_OTHER_STATS)
    5581             :                         {
    5582       17073 :                             nValidCount32bit++;
    5583       17073 :                             nSum32bit += nValue;
    5584       17073 :                             nSumSquare32bit += nValue * nValue;
    5585             :                         }
    5586             :                     }
    5587             :                     if constexpr (COMPUTE_OTHER_STATS)
    5588             :                     {
    5589         652 :                         nSampleCount += nSampleCount32bit;
    5590         652 :                         nValidCount += nValidCount32bit;
    5591         652 :                         nSum += nSum32bit;
    5592         652 :                         nSumSquare += nSumSquare32bit;
    5593             :                     }
    5594             :                 }
    5595             :             }
    5596             :         }
    5597        3123 :         else if (nMin == 0 && nMax == 255)
    5598             :         {
    5599             :             if constexpr (COMPUTE_OTHER_STATS)
    5600             :             {
    5601             :                 // Optimization when there is no nodata and we know we have already
    5602             :                 // reached the min and max
    5603        2644 :                 for (int iY = 0; iY < nYCheck; iY++)
    5604             :                 {
    5605        2617 :                     int iX = 0;
    5606        5234 :                     for (int k = 0; k < nOuterLoops; k++)
    5607             :                     {
    5608        2617 :                         int iMax = iX + 65536;
    5609        2617 :                         if (iMax > nXCheck)
    5610        2617 :                             iMax = nXCheck;
    5611        2617 :                         GUInt32 nSum32bit = 0;
    5612        2617 :                         GUInt32 nSumSquare32bit = 0;
    5613      176297 :                         for (; iX + 3 < iMax; iX += 4)
    5614             :                         {
    5615      173680 :                             const GPtrDiff_t iOffset =
    5616      173680 :                                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5617      173680 :                             const GUInt32 nValue = pData[iOffset];
    5618      173680 :                             const GUInt32 nValue2 = pData[iOffset + 1];
    5619      173680 :                             const GUInt32 nValue3 = pData[iOffset + 2];
    5620      173680 :                             const GUInt32 nValue4 = pData[iOffset + 3];
    5621      173680 :                             nSum32bit += nValue;
    5622      173680 :                             nSumSquare32bit += nValue * nValue;
    5623      173680 :                             nSum32bit += nValue2;
    5624      173680 :                             nSumSquare32bit += nValue2 * nValue2;
    5625      173680 :                             nSum32bit += nValue3;
    5626      173680 :                             nSumSquare32bit += nValue3 * nValue3;
    5627      173680 :                             nSum32bit += nValue4;
    5628      173680 :                             nSumSquare32bit += nValue4 * nValue4;
    5629             :                         }
    5630        2617 :                         nSum += nSum32bit;
    5631        2617 :                         nSumSquare += nSumSquare32bit;
    5632             :                     }
    5633        2620 :                     for (; iX < nXCheck; ++iX)
    5634             :                     {
    5635           3 :                         const GPtrDiff_t iOffset =
    5636           3 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5637           3 :                         const GUIntBig nValue = pData[iOffset];
    5638           3 :                         nSum += nValue;
    5639           3 :                         nSumSquare += nValue * nValue;
    5640             :                     }
    5641             :                 }
    5642          27 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5643          27 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5644          27 :             }
    5645             :         }
    5646             :         else
    5647             :         {
    5648        7883 :             for (int iY = 0; iY < nYCheck; iY++)
    5649             :             {
    5650        4787 :                 int iX = 0;
    5651        9574 :                 for (int k = 0; k < nOuterLoops; k++)
    5652             :                 {
    5653        4787 :                     int iMax = iX + 65536;
    5654        4787 :                     if (iMax > nXCheck)
    5655        4787 :                         iMax = nXCheck;
    5656        4787 :                     GUInt32 nSum32bit = 0;
    5657        4787 :                     GUInt32 nSumSquare32bit = 0;
    5658      159415 :                     for (; iX + 1 < iMax; iX += 2)
    5659             :                     {
    5660      154628 :                         const GPtrDiff_t iOffset =
    5661      154628 :                             iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5662      154628 :                         const GUInt32 nValue = pData[iOffset];
    5663      154628 :                         const GUInt32 nValue2 = pData[iOffset + 1];
    5664      154628 :                         if (nValue < nValue2)
    5665             :                         {
    5666        8047 :                             if (nValue < nMin)
    5667         230 :                                 nMin = nValue;
    5668        8047 :                             if (nValue2 > nMax)
    5669         219 :                                 nMax = nValue2;
    5670             :                         }
    5671             :                         else
    5672             :                         {
    5673      146581 :                             if (nValue2 < nMin)
    5674         359 :                                 nMin = nValue2;
    5675      146581 :                             if (nValue > nMax)
    5676         828 :                                 nMax = nValue;
    5677             :                         }
    5678             :                         if constexpr (COMPUTE_OTHER_STATS)
    5679             :                         {
    5680      132491 :                             nSum32bit += nValue;
    5681      132491 :                             nSumSquare32bit += nValue * nValue;
    5682      132491 :                             nSum32bit += nValue2;
    5683      132491 :                             nSumSquare32bit += nValue2 * nValue2;
    5684             :                         }
    5685             :                     }
    5686             :                     if constexpr (COMPUTE_OTHER_STATS)
    5687             :                     {
    5688        1610 :                         nSum += nSum32bit;
    5689        1610 :                         nSumSquare += nSumSquare32bit;
    5690             :                     }
    5691             :                 }
    5692        4787 :                 if (iX < nXCheck)
    5693             :                 {
    5694        1515 :                     const GPtrDiff_t iOffset =
    5695        1515 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    5696        1515 :                     const GUInt32 nValue = pData[iOffset];
    5697        1515 :                     if (nValue < nMin)
    5698         108 :                         nMin = nValue;
    5699        1515 :                     if (nValue > nMax)
    5700          95 :                         nMax = nValue;
    5701             :                     if constexpr (COMPUTE_OTHER_STATS)
    5702             :                     {
    5703         313 :                         nSum += nValue;
    5704         313 :                         nSumSquare +=
    5705         313 :                             static_cast_for_coverity_scan<GUIntBig>(nValue) *
    5706         313 :                             nValue;
    5707             :                     }
    5708             :                 }
    5709             :             }
    5710             :             if constexpr (COMPUTE_OTHER_STATS)
    5711             :             {
    5712         909 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5713         909 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    5714             :             }
    5715             :         }
    5716       13697 :     }
    5717             : };
    5718             : 
    5719             : template <class T, bool COMPUTE_OTHER_STATS> struct ComputeStatisticsInternal
    5720             : {
    5721             :     static void f(int nXCheck, int nBlockXSize, int nYCheck, const T *pData,
    5722             :                   bool bHasNoData, GUInt32 nNoDataValue, GUInt32 &nMin,
    5723             :                   GUInt32 &nMax, GUIntBig &nSum, GUIntBig &nSumSquare,
    5724             :                   GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5725             :     {
    5726             :         ComputeStatisticsInternalGeneric<T, COMPUTE_OTHER_STATS>::f(
    5727             :             nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    5728             :             nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    5729             :     }
    5730             : };
    5731             : 
    5732             : #if (defined(__x86_64__) || defined(_M_X64)) &&                                \
    5733             :     (defined(__GNUC__) || defined(_MSC_VER))
    5734             : 
    5735             : #include "gdal_avx2_emulation.hpp"
    5736             : 
    5737             : #define ZERO256 GDALmm256_setzero_si256()
    5738             : 
    5739             : template <bool COMPUTE_MIN, bool COMPUTE_MAX, bool COMPUTE_OTHER_STATS>
    5740             : static void
    5741       21335 : ComputeStatisticsByteNoNodata(GPtrDiff_t nBlockPixels,
    5742             :                               // assumed to be aligned on 256 bits
    5743             :                               const GByte *pData, GUInt32 &nMin, GUInt32 &nMax,
    5744             :                               GUIntBig &nSum, GUIntBig &nSumSquare,
    5745             :                               GUIntBig &nSampleCount, GUIntBig &nValidCount)
    5746             : {
    5747             :     // 32-byte alignment may not be enforced by linker, so do it at hand
    5748             :     GByte
    5749             :         aby32ByteUnaligned[32 + 32 + 32 + (COMPUTE_OTHER_STATS ? 32 + 32 : 0)];
    5750       21335 :     GByte *paby32ByteAligned =
    5751             :         aby32ByteUnaligned +
    5752       21335 :         (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5753       21335 :     GByte *pabyMin = paby32ByteAligned;
    5754       21335 :     GByte *pabyMax = paby32ByteAligned + 32;
    5755       21335 :     GUInt32 *panSum =
    5756             :         COMPUTE_OTHER_STATS
    5757             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2)
    5758             :             : nullptr;
    5759       21335 :     GUInt32 *panSumSquare =
    5760             :         COMPUTE_OTHER_STATS
    5761             :             ? reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3)
    5762             :             : nullptr;
    5763             : 
    5764       21335 :     CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5765             : 
    5766       21335 :     GPtrDiff_t i = 0;
    5767             :     // Make sure that sumSquare can fit on uint32
    5768             :     // * 8 since we can hold 8 sums per vector register
    5769       21335 :     const int nMaxIterationsPerInnerLoop =
    5770             :         8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5771       21335 :     GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5772       21335 :     if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5773       21335 :         nOuterLoops++;
    5774             : 
    5775             :     GDALm256i ymm_min =
    5776       21335 :         GDALmm256_load_si256(reinterpret_cast<const GDALm256i *>(pData + i));
    5777       21335 :     GDALm256i ymm_max = ymm_min;
    5778       21335 :     [[maybe_unused]] const auto ymm_mask_8bits = GDALmm256_set1_epi16(0xFF);
    5779             : 
    5780       42670 :     for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5781             :     {
    5782       21335 :         const auto iMax =
    5783       21335 :             std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5784             : 
    5785             :         // holds 4 uint32 sums in [0], [2], [4] and [6]
    5786       21335 :         [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5787             :         [[maybe_unused]] GDALm256i ymm_sumsquare =
    5788       21335 :             ZERO256;  // holds 8 uint32 sums
    5789      717110 :         for (; i + 31 < iMax; i += 32)
    5790             :         {
    5791      695775 :             const GDALm256i ymm = GDALmm256_load_si256(
    5792      695775 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    5793             :             if (COMPUTE_MIN)
    5794             :             {
    5795      237938 :                 ymm_min = GDALmm256_min_epu8(ymm_min, ymm);
    5796             :             }
    5797             :             if (COMPUTE_MAX)
    5798             :             {
    5799      604834 :                 ymm_max = GDALmm256_max_epu8(ymm_max, ymm);
    5800             :             }
    5801             : 
    5802             :             if constexpr (COMPUTE_OTHER_STATS)
    5803             :             {
    5804             :                 // Extract even-8bit values
    5805             :                 const GDALm256i ymm_even =
    5806      493495 :                     GDALmm256_and_si256(ymm, ymm_mask_8bits);
    5807             :                 // Compute square of those 16 values as 32 bit result
    5808             :                 // and add adjacent pairs
    5809             :                 const GDALm256i ymm_even_square =
    5810      493495 :                     GDALmm256_madd_epi16(ymm_even, ymm_even);
    5811             :                 // Add to the sumsquare accumulator
    5812             :                 ymm_sumsquare =
    5813      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    5814             : 
    5815             :                 // Extract odd-8bit values
    5816      493495 :                 const GDALm256i ymm_odd = GDALmm256_srli_epi16(ymm, 8);
    5817             :                 const GDALm256i ymm_odd_square =
    5818      493495 :                     GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    5819             :                 ymm_sumsquare =
    5820      493495 :                     GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    5821             : 
    5822             :                 // Now compute the sums
    5823      493495 :                 ymm_sum = GDALmm256_add_epi32(ymm_sum,
    5824             :                                               GDALmm256_sad_epu8(ymm, ZERO256));
    5825             :             }
    5826             :         }
    5827             : 
    5828             :         if constexpr (COMPUTE_OTHER_STATS)
    5829             :         {
    5830       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    5831             :                                   ymm_sum);
    5832       10649 :             GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSumSquare),
    5833             :                                   ymm_sumsquare);
    5834             : 
    5835       10649 :             nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    5836       10649 :             nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    5837       10649 :                           panSumSquare[1] + panSumSquare[2] + panSumSquare[3] +
    5838       10649 :                           panSumSquare[4] + panSumSquare[5] + panSumSquare[6] +
    5839             :                           panSumSquare[7];
    5840             :         }
    5841             :     }
    5842             : 
    5843             :     if constexpr (COMPUTE_MIN)
    5844             :     {
    5845        8461 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin), ymm_min);
    5846             :     }
    5847             :     if constexpr (COMPUTE_MAX)
    5848             :     {
    5849       17338 :         GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax), ymm_max);
    5850             :     }
    5851             :     if constexpr (COMPUTE_MIN || COMPUTE_MAX)
    5852             :     {
    5853      589644 :         for (int j = 0; j < 32; j++)
    5854             :         {
    5855             :             if constexpr (COMPUTE_MIN)
    5856             :             {
    5857      270752 :                 if (pabyMin[j] < nMin)
    5858        1263 :                     nMin = pabyMin[j];
    5859             :             }
    5860             :             if constexpr (COMPUTE_MAX)
    5861             :             {
    5862      554816 :                 if (pabyMax[j] > nMax)
    5863        1814 :                     nMax = pabyMax[j];
    5864             :             }
    5865             :         }
    5866             :     }
    5867             : 
    5868      234401 :     for (; i < nBlockPixels; i++)
    5869             :     {
    5870      213066 :         const GUInt32 nValue = pData[i];
    5871             :         if constexpr (COMPUTE_MIN)
    5872             :         {
    5873       88390 :             if (nValue < nMin)
    5874           1 :                 nMin = nValue;
    5875             :         }
    5876             :         if constexpr (COMPUTE_MAX)
    5877             :         {
    5878      210291 :             if (nValue > nMax)
    5879        1149 :                 nMax = nValue;
    5880             :         }
    5881             :         if constexpr (COMPUTE_OTHER_STATS)
    5882             :         {
    5883       77195 :             nSum += nValue;
    5884       77195 :             nSumSquare +=
    5885       77195 :                 static_cast_for_coverity_scan<GUIntBig>(nValue) * nValue;
    5886             :         }
    5887             :     }
    5888             : 
    5889             :     if constexpr (COMPUTE_OTHER_STATS)
    5890             :     {
    5891       10649 :         nSampleCount += static_cast<GUIntBig>(nBlockPixels);
    5892       10649 :         nValidCount += static_cast<GUIntBig>(nBlockPixels);
    5893             :     }
    5894       21335 : }
    5895             : 
    5896             : // SSE2/AVX2 optimization for GByte case
    5897             : // In pure SSE2, this relies on gdal_avx2_emulation.hpp. There is no
    5898             : // penaly in using the emulation, because, given the mm256 intrinsics used here,
    5899             : // there are strictly equivalent to 2 parallel SSE2 streams.
    5900             : template <bool COMPUTE_OTHER_STATS>
    5901             : struct ComputeStatisticsInternal<GByte, COMPUTE_OTHER_STATS>
    5902             : {
    5903       30168 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    5904             :                   // assumed to be aligned on 256 bits
    5905             :                   const GByte *pData, bool bHasNoData, GUInt32 nNoDataValue,
    5906             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    5907             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    5908             :                   GUIntBig &nValidCount)
    5909             :     {
    5910       30168 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    5911       30168 :         if (bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32 &&
    5912       11574 :             nMin <= nMax)
    5913             :         {
    5914             :             // 32-byte alignment may not be enforced by linker, so do it at hand
    5915             :             GByte aby32ByteUnaligned[32 + 32 + 32 + 32 + 32];
    5916        1459 :             GByte *paby32ByteAligned =
    5917             :                 aby32ByteUnaligned +
    5918        1459 :                 (32 - (reinterpret_cast<GUIntptr_t>(aby32ByteUnaligned) % 32));
    5919        1459 :             GByte *pabyMin = paby32ByteAligned;
    5920        1459 :             GByte *pabyMax = paby32ByteAligned + 32;
    5921        1459 :             GUInt32 *panSum =
    5922             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 2);
    5923        1459 :             GUInt32 *panSumSquare =
    5924             :                 reinterpret_cast<GUInt32 *>(paby32ByteAligned + 32 * 3);
    5925             : 
    5926        1459 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 32) == 0);
    5927             : 
    5928        1459 :             GPtrDiff_t i = 0;
    5929             :             // Make sure that sumSquare can fit on uint32
    5930             :             // * 8 since we can hold 8 sums per vector register
    5931        1459 :             const int nMaxIterationsPerInnerLoop =
    5932             :                 8 * ((std::numeric_limits<GUInt32>::max() / (255 * 255)) & ~31);
    5933        1459 :             auto nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    5934        1459 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    5935        1459 :                 nOuterLoops++;
    5936             : 
    5937             :             const GDALm256i ymm_nodata =
    5938        1459 :                 GDALmm256_set1_epi8(static_cast<GByte>(nNoDataValue));
    5939             :             // any non noData value in [min,max] would do.
    5940             :             const GDALm256i ymm_neutral =
    5941        1459 :                 GDALmm256_set1_epi8(static_cast<GByte>(nMin));
    5942        1459 :             GDALm256i ymm_min = ymm_neutral;
    5943        1459 :             GDALm256i ymm_max = ymm_neutral;
    5944             :             [[maybe_unused]] const auto ymm_mask_8bits =
    5945        1459 :                 GDALmm256_set1_epi16(0xFF);
    5946             : 
    5947        1459 :             const GUInt32 nMinThreshold = (nNoDataValue == 0) ? 1 : 0;
    5948        1459 :             const GUInt32 nMaxThreshold = (nNoDataValue == 255) ? 254 : 255;
    5949        1459 :             const bool bComputeMinMax =
    5950        1459 :                 nMin > nMinThreshold || nMax < nMaxThreshold;
    5951             : 
    5952        2918 :             for (GPtrDiff_t k = 0; k < nOuterLoops; k++)
    5953             :             {
    5954        1459 :                 const auto iMax =
    5955        1459 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    5956             : 
    5957             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5958        1459 :                 [[maybe_unused]] GDALm256i ymm_sum = ZERO256;
    5959             :                 // holds 8 uint32 sums
    5960        1459 :                 [[maybe_unused]] GDALm256i ymm_sumsquare = ZERO256;
    5961             :                 // holds 4 uint32 sums in [0], [2], [4] and [6]
    5962        1459 :                 [[maybe_unused]] GDALm256i ymm_count_nodata_mul_255 = ZERO256;
    5963        1459 :                 const auto iInit = i;
    5964       14435 :                 for (; i + 31 < iMax; i += 32)
    5965             :                 {
    5966       12976 :                     const GDALm256i ymm = GDALmm256_load_si256(
    5967       12976 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    5968             : 
    5969             :                     // Check which values are nodata
    5970             :                     const GDALm256i ymm_eq_nodata =
    5971       12976 :                         GDALmm256_cmpeq_epi8(ymm, ymm_nodata);
    5972             :                     if constexpr (COMPUTE_OTHER_STATS)
    5973             :                     {
    5974             :                         // Count how many values are nodata (due to cmpeq
    5975             :                         // putting 255 when condition is met, this will actually
    5976             :                         // be 255 times the number of nodata value, spread in 4
    5977             :                         // 64 bits words). We can use add_epi32 as the counter
    5978             :                         // will not overflow uint32
    5979        4634 :                         ymm_count_nodata_mul_255 = GDALmm256_add_epi32(
    5980             :                             ymm_count_nodata_mul_255,
    5981             :                             GDALmm256_sad_epu8(ymm_eq_nodata, ZERO256));
    5982             :                     }
    5983             :                     // Replace all nodata values by zero for the purpose of sum
    5984             :                     // and sumquare.
    5985             :                     const GDALm256i ymm_nodata_by_zero =
    5986       12976 :                         GDALmm256_andnot_si256(ymm_eq_nodata, ymm);
    5987       12976 :                     if (bComputeMinMax)
    5988             :                     {
    5989             :                         // Replace all nodata values by a neutral value for the
    5990             :                         // purpose of min and max.
    5991             :                         const GDALm256i ymm_nodata_by_neutral =
    5992        8591 :                             GDALmm256_or_si256(
    5993             :                                 GDALmm256_and_si256(ymm_eq_nodata, ymm_neutral),
    5994             :                                 ymm_nodata_by_zero);
    5995             : 
    5996             :                         ymm_min =
    5997        8591 :                             GDALmm256_min_epu8(ymm_min, ymm_nodata_by_neutral);
    5998             :                         ymm_max =
    5999        8591 :                             GDALmm256_max_epu8(ymm_max, ymm_nodata_by_neutral);
    6000             :                     }
    6001             : 
    6002             :                     if constexpr (COMPUTE_OTHER_STATS)
    6003             :                     {
    6004             :                         // Extract even-8bit values
    6005        4634 :                         const GDALm256i ymm_even = GDALmm256_and_si256(
    6006             :                             ymm_nodata_by_zero, ymm_mask_8bits);
    6007             :                         // Compute square of those 16 values as 32 bit result
    6008             :                         // and add adjacent pairs
    6009             :                         const GDALm256i ymm_even_square =
    6010        4634 :                             GDALmm256_madd_epi16(ymm_even, ymm_even);
    6011             :                         // Add to the sumsquare accumulator
    6012             :                         ymm_sumsquare =
    6013        4634 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_even_square);
    6014             : 
    6015             :                         // Extract odd-8bit values
    6016             :                         const GDALm256i ymm_odd =
    6017        4634 :                             GDALmm256_srli_epi16(ymm_nodata_by_zero, 8);
    6018             :                         const GDALm256i ymm_odd_square =
    6019        4634 :                             GDALmm256_madd_epi16(ymm_odd, ymm_odd);
    6020             :                         ymm_sumsquare =
    6021        4634 :                             GDALmm256_add_epi32(ymm_sumsquare, ymm_odd_square);
    6022             : 
    6023             :                         // Now compute the sums
    6024        4634 :                         ymm_sum = GDALmm256_add_epi32(
    6025             :                             ymm_sum,
    6026             :                             GDALmm256_sad_epu8(ymm_nodata_by_zero, ZERO256));
    6027             :                     }
    6028             :                 }
    6029             : 
    6030             :                 if constexpr (COMPUTE_OTHER_STATS)
    6031             :                 {
    6032         153 :                     GUInt32 *panCoutNoDataMul255 = panSum;
    6033         153 :                     GDALmm256_store_si256(
    6034             :                         reinterpret_cast<GDALm256i *>(panCoutNoDataMul255),
    6035             :                         ymm_count_nodata_mul_255);
    6036             : 
    6037         153 :                     nSampleCount += (i - iInit);
    6038             : 
    6039         153 :                     nValidCount +=
    6040         153 :                         (i - iInit) -
    6041         153 :                         (panCoutNoDataMul255[0] + panCoutNoDataMul255[2] +
    6042         153 :                          panCoutNoDataMul255[4] + panCoutNoDataMul255[6]) /
    6043             :                             255;
    6044             : 
    6045         153 :                     GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(panSum),
    6046             :                                           ymm_sum);
    6047         153 :                     GDALmm256_store_si256(
    6048             :                         reinterpret_cast<GDALm256i *>(panSumSquare),
    6049             :                         ymm_sumsquare);
    6050         153 :                     nSum += panSum[0] + panSum[2] + panSum[4] + panSum[6];
    6051         153 :                     nSumSquare += static_cast<GUIntBig>(panSumSquare[0]) +
    6052         153 :                                   panSumSquare[1] + panSumSquare[2] +
    6053         153 :                                   panSumSquare[3] + panSumSquare[4] +
    6054         153 :                                   panSumSquare[5] + panSumSquare[6] +
    6055             :                                   panSumSquare[7];
    6056             :                 }
    6057             :             }
    6058             : 
    6059        1459 :             if (bComputeMinMax)
    6060             :             {
    6061        1428 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMin),
    6062             :                                       ymm_min);
    6063        1428 :                 GDALmm256_store_si256(reinterpret_cast<GDALm256i *>(pabyMax),
    6064             :                                       ymm_max);
    6065       47124 :                 for (int j = 0; j < 32; j++)
    6066             :                 {
    6067       45696 :                     if (pabyMin[j] < nMin)
    6068          40 :                         nMin = pabyMin[j];
    6069       45696 :                     if (pabyMax[j] > nMax)
    6070         159 :                         nMax = pabyMax[j];
    6071             :                 }
    6072             :             }
    6073             : 
    6074             :             if constexpr (COMPUTE_OTHER_STATS)
    6075             :             {
    6076         153 :                 nSampleCount += nBlockPixels - i;
    6077             :             }
    6078       33905 :             for (; i < nBlockPixels; i++)
    6079             :             {
    6080       32446 :                 const GUInt32 nValue = pData[i];
    6081       32446 :                 if (nValue == nNoDataValue)
    6082       24923 :                     continue;
    6083        7523 :                 if (nValue < nMin)
    6084           1 :                     nMin = nValue;
    6085        7523 :                 if (nValue > nMax)
    6086          13 :                     nMax = nValue;
    6087             :                 if constexpr (COMPUTE_OTHER_STATS)
    6088             :                 {
    6089        3590 :                     nValidCount++;
    6090        3590 :                     nSum += nValue;
    6091        3590 :                     nSumSquare +=
    6092        3590 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6093        3590 :                         nValue;
    6094             :                 }
    6095        1459 :             }
    6096             :         }
    6097       28709 :         else if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 32)
    6098             :         {
    6099       14979 :             if (nMin > 0)
    6100             :             {
    6101        2105 :                 if (nMax < 255)
    6102             :                 {
    6103             :                     ComputeStatisticsByteNoNodata<true, true,
    6104        1575 :                                                   COMPUTE_OTHER_STATS>(
    6105             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6106             :                         nSampleCount, nValidCount);
    6107             :                 }
    6108             :                 else
    6109             :                 {
    6110             :                     ComputeStatisticsByteNoNodata<true, false,
    6111         530 :                                                   COMPUTE_OTHER_STATS>(
    6112             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6113             :                         nSampleCount, nValidCount);
    6114             :                 }
    6115             :             }
    6116             :             else
    6117             :             {
    6118       12874 :                 if (nMax < 255)
    6119             :                 {
    6120             :                     ComputeStatisticsByteNoNodata<false, true,
    6121        9407 :                                                   COMPUTE_OTHER_STATS>(
    6122             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6123             :                         nSampleCount, nValidCount);
    6124             :                 }
    6125             :                 else
    6126             :                 {
    6127             :                     ComputeStatisticsByteNoNodata<false, false,
    6128        3467 :                                                   COMPUTE_OTHER_STATS>(
    6129             :                         nBlockPixels, pData, nMin, nMax, nSum, nSumSquare,
    6130             :                         nSampleCount, nValidCount);
    6131             :                 }
    6132             :             }
    6133             :         }
    6134       12475 :         else if (!COMPUTE_OTHER_STATS && !bHasNoData && nXCheck >= 32 &&
    6135          33 :                  (nBlockXSize % 32) == 0)
    6136             :         {
    6137        6389 :             for (int iY = 0; iY < nYCheck; iY++)
    6138             :             {
    6139        6356 :                 ComputeStatisticsByteNoNodata<true, true, COMPUTE_OTHER_STATS>(
    6140        6356 :                     nXCheck, pData + static_cast<size_t>(iY) * nBlockXSize,
    6141             :                     nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6142          33 :             }
    6143             :         }
    6144             :         else
    6145             :         {
    6146       13697 :             ComputeStatisticsInternalGeneric<GByte, COMPUTE_OTHER_STATS>::f(
    6147             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6148             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6149             :         }
    6150       30168 :     }
    6151             : };
    6152             : 
    6153             : CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
    6154         400 : static void UnshiftSumSquare(GUIntBig &nSumSquare, GUIntBig nSumThis,
    6155             :                              GUIntBig i)
    6156             : {
    6157         400 :     nSumSquare += 32768 * (2 * nSumThis - i * 32768);
    6158         400 : }
    6159             : 
    6160             : // AVX2/SSE2 optimization for GUInt16 case
    6161             : template <bool COMPUTE_OTHER_STATS>
    6162             : struct ComputeStatisticsInternal<GUInt16, COMPUTE_OTHER_STATS>
    6163             : {
    6164        1882 :     static void f(int nXCheck, int nBlockXSize, int nYCheck,
    6165             :                   // assumed to be aligned on 128 bits
    6166             :                   const GUInt16 *pData, bool bHasNoData, GUInt32 nNoDataValue,
    6167             :                   GUInt32 &nMin, GUInt32 &nMax, GUIntBig &nSum,
    6168             :                   GUIntBig &nSumSquare, GUIntBig &nSampleCount,
    6169             :                   GUIntBig &nValidCount)
    6170             :     {
    6171        1882 :         const auto nBlockPixels = static_cast<GPtrDiff_t>(nXCheck) * nYCheck;
    6172        1882 :         if (!bHasNoData && nXCheck == nBlockXSize && nBlockPixels >= 16)
    6173             :         {
    6174        1674 :             CPLAssert((reinterpret_cast<uintptr_t>(pData) % 16) == 0);
    6175             : 
    6176        1674 :             GPtrDiff_t i = 0;
    6177             :             // In SSE2, min_epu16 and max_epu16 do not exist, so shift from
    6178             :             // UInt16 to SInt16 to be able to use min_epi16 and max_epi16.
    6179             :             // Furthermore the shift is also needed to use madd_epi16
    6180        1674 :             const GDALm256i ymm_m32768 = GDALmm256_set1_epi16(-32768);
    6181        1674 :             GDALm256i ymm_min = GDALmm256_load_si256(
    6182        1674 :                 reinterpret_cast<const GDALm256i *>(pData + i));
    6183        1674 :             ymm_min = GDALmm256_add_epi16(ymm_min, ymm_m32768);
    6184        1674 :             GDALm256i ymm_max = ymm_min;
    6185             :             [[maybe_unused]] GDALm256i ymm_sumsquare =
    6186        1674 :                 ZERO256;  // holds 4 uint64 sums
    6187             : 
    6188             :             // Make sure that sum can fit on uint32
    6189             :             // * 8 since we can hold 8 sums per vector register
    6190        1674 :             const int nMaxIterationsPerInnerLoop =
    6191             :                 8 * ((std::numeric_limits<GUInt32>::max() / 65535) & ~15);
    6192        1674 :             GPtrDiff_t nOuterLoops = nBlockPixels / nMaxIterationsPerInnerLoop;
    6193        1674 :             if ((nBlockPixels % nMaxIterationsPerInnerLoop) != 0)
    6194        1674 :                 nOuterLoops++;
    6195             : 
    6196        1674 :             const bool bComputeMinMax = nMin > 0 || nMax < 65535;
    6197             :             [[maybe_unused]] const auto ymm_mask_16bits =
    6198        1674 :                 GDALmm256_set1_epi32(0xFFFF);
    6199             :             [[maybe_unused]] const auto ymm_mask_32bits =
    6200        1674 :                 GDALmm256_set1_epi64x(0xFFFFFFFF);
    6201             : 
    6202        1674 :             GUIntBig nSumThis = 0;
    6203        3372 :             for (int k = 0; k < nOuterLoops; k++)
    6204             :             {
    6205        1698 :                 const auto iMax =
    6206        1698 :                     std::min(nBlockPixels, i + nMaxIterationsPerInnerLoop);
    6207             : 
    6208             :                 [[maybe_unused]] GDALm256i ymm_sum =
    6209        1698 :                     ZERO256;  // holds 8 uint32 sums
    6210      964126 :                 for (; i + 15 < iMax; i += 16)
    6211             :                 {
    6212      962428 :                     const GDALm256i ymm = GDALmm256_load_si256(
    6213      962428 :                         reinterpret_cast<const GDALm256i *>(pData + i));
    6214             :                     const GDALm256i ymm_shifted =
    6215      962428 :                         GDALmm256_add_epi16(ymm, ymm_m32768);
    6216      962428 :                     if (bComputeMinMax)
    6217             :                     {
    6218      953409 :                         ymm_min = GDALmm256_min_epi16(ymm_min, ymm_shifted);
    6219      953409 :                         ymm_max = GDALmm256_max_epi16(ymm_max, ymm_shifted);
    6220             :                     }
    6221             : 
    6222             :                     if constexpr (COMPUTE_OTHER_STATS)
    6223             :                     {
    6224             :                         // Note: the int32 range can overflow for (0-32768)^2 +
    6225             :                         // (0-32768)^2 = 0x80000000, but as we know the result
    6226             :                         // is positive, this is OK as we interpret is a uint32.
    6227             :                         const GDALm256i ymm_square =
    6228       95410 :                             GDALmm256_madd_epi16(ymm_shifted, ymm_shifted);
    6229       95410 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6230             :                             ymm_sumsquare,
    6231             :                             GDALmm256_and_si256(ymm_square, ymm_mask_32bits));
    6232       95410 :                         ymm_sumsquare = GDALmm256_add_epi64(
    6233             :                             ymm_sumsquare,
    6234             :                             GDALmm256_srli_epi64(ymm_square, 32));
    6235             : 
    6236             :                         // Now compute the sums
    6237       95410 :                         ymm_sum = GDALmm256_add_epi32(
    6238             :                             ymm_sum, GDALmm256_and_si256(ymm, ymm_mask_16bits));
    6239       95410 :                         ymm_sum = GDALmm256_add_epi32(
    6240             :                             ymm_sum, GDALmm256_srli_epi32(ymm, 16));
    6241             :                     }
    6242             :                 }
    6243             : 
    6244             :                 if constexpr (COMPUTE_OTHER_STATS)
    6245             :                 {
    6246             :                     GUInt32 anSum[8];
    6247         400 :                     GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anSum),
    6248             :                                            ymm_sum);
    6249         400 :                     nSumThis += static_cast<GUIntBig>(anSum[0]) + anSum[1] +
    6250         400 :                                 anSum[2] + anSum[3] + anSum[4] + anSum[5] +
    6251         400 :                                 anSum[6] + anSum[7];
    6252             :                 }
    6253             :             }
    6254             : 
    6255        1674 :             if (bComputeMinMax)
    6256             :             {
    6257             :                 GUInt16 anMin[16];
    6258             :                 GUInt16 anMax[16];
    6259             : 
    6260             :                 // Unshift the result
    6261        1633 :                 ymm_min = GDALmm256_sub_epi16(ymm_min, ymm_m32768);
    6262        1633 :                 ymm_max = GDALmm256_sub_epi16(ymm_max, ymm_m32768);
    6263        1633 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMin),
    6264             :                                        ymm_min);
    6265        1633 :                 GDALmm256_storeu_si256(reinterpret_cast<GDALm256i *>(anMax),
    6266             :                                        ymm_max);
    6267       27761 :                 for (int j = 0; j < 16; j++)
    6268             :                 {
    6269       26128 :                     if (anMin[j] < nMin)
    6270         342 :                         nMin = anMin[j];
    6271       26128 :                     if (anMax[j] > nMax)
    6272         482 :                         nMax = anMax[j];
    6273             :                 }
    6274             :             }
    6275             : 
    6276             :             if constexpr (COMPUTE_OTHER_STATS)
    6277             :             {
    6278             :                 GUIntBig anSumSquare[4];
    6279         400 :                 GDALmm256_storeu_si256(
    6280             :                     reinterpret_cast<GDALm256i *>(anSumSquare), ymm_sumsquare);
    6281         400 :                 nSumSquare += anSumSquare[0] + anSumSquare[1] + anSumSquare[2] +
    6282             :                               anSumSquare[3];
    6283             : 
    6284             :                 // Unshift the sum of squares
    6285         400 :                 UnshiftSumSquare(nSumSquare, nSumThis,
    6286             :                                  static_cast<GUIntBig>(i));
    6287             : 
    6288         400 :                 nSum += nSumThis;
    6289             : 
    6290         722 :                 for (; i < nBlockPixels; i++)
    6291             :                 {
    6292         322 :                     const GUInt32 nValue = pData[i];
    6293         322 :                     if (nValue < nMin)
    6294           1 :                         nMin = nValue;
    6295         322 :                     if (nValue > nMax)
    6296           1 :                         nMax = nValue;
    6297         322 :                     nSum += nValue;
    6298         322 :                     nSumSquare +=
    6299         322 :                         static_cast_for_coverity_scan<GUIntBig>(nValue) *
    6300         322 :                         nValue;
    6301             :                 }
    6302             : 
    6303         400 :                 nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6304         400 :                 nValidCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6305        1674 :             }
    6306             :         }
    6307             :         else
    6308             :         {
    6309         208 :             ComputeStatisticsInternalGeneric<GUInt16, COMPUTE_OTHER_STATS>::f(
    6310             :                 nXCheck, nBlockXSize, nYCheck, pData, bHasNoData, nNoDataValue,
    6311             :                 nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6312             :         }
    6313        1882 :     }
    6314             : };
    6315             : 
    6316             : #endif
    6317             : // (defined(__x86_64__) || defined(_M_X64)) && (defined(__GNUC__) ||
    6318             : // defined(_MSC_VER))
    6319             : 
    6320             : /************************************************************************/
    6321             : /*                          GetPixelValue()                             */
    6322             : /************************************************************************/
    6323             : 
    6324    23815700 : static inline double GetPixelValue(GDALDataType eDataType, bool bSignedByte,
    6325             :                                    const void *pData, GPtrDiff_t iOffset,
    6326             :                                    const GDALNoDataValues &sNoDataValues,
    6327             :                                    bool &bValid)
    6328             : {
    6329    23815700 :     bValid = true;
    6330    23815700 :     double dfValue = 0;
    6331    23815700 :     switch (eDataType)
    6332             :     {
    6333     1413690 :         case GDT_Byte:
    6334             :         {
    6335     1413690 :             if (bSignedByte)
    6336         192 :                 dfValue = static_cast<const signed char *>(pData)[iOffset];
    6337             :             else
    6338     1413500 :                 dfValue = static_cast<const GByte *>(pData)[iOffset];
    6339     1413690 :             break;
    6340             :         }
    6341       10409 :         case GDT_Int8:
    6342       10409 :             dfValue = static_cast<const GInt8 *>(pData)[iOffset];
    6343       10409 :             break;
    6344      200608 :         case GDT_UInt16:
    6345      200608 :             dfValue = static_cast<const GUInt16 *>(pData)[iOffset];
    6346      200608 :             break;
    6347       60193 :         case GDT_Int16:
    6348       60193 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset];
    6349       60193 :             break;
    6350       27600 :         case GDT_UInt32:
    6351       27600 :             dfValue = static_cast<const GUInt32 *>(pData)[iOffset];
    6352       27600 :             break;
    6353      455610 :         case GDT_Int32:
    6354      455610 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset];
    6355      455610 :             break;
    6356        2604 :         case GDT_UInt64:
    6357        2604 :             dfValue = static_cast<double>(
    6358        2604 :                 static_cast<const std::uint64_t *>(pData)[iOffset]);
    6359        2604 :             break;
    6360        7404 :         case GDT_Int64:
    6361        7404 :             dfValue = static_cast<double>(
    6362        7404 :                 static_cast<const std::int64_t *>(pData)[iOffset]);
    6363        7404 :             break;
    6364           0 :         case GDT_Float16:
    6365             :         {
    6366             :             using namespace std;
    6367           0 :             const GFloat16 hfValue =
    6368           0 :                 static_cast<const GFloat16 *>(pData)[iOffset];
    6369           0 :             if (isnan(hfValue) ||
    6370           0 :                 (sNoDataValues.bGotFloat16NoDataValue &&
    6371           0 :                  ARE_REAL_EQUAL(hfValue, sNoDataValues.hfNoDataValue)))
    6372             :             {
    6373           0 :                 bValid = false;
    6374           0 :                 return 0.0;
    6375             :             }
    6376           0 :             dfValue = hfValue;
    6377           0 :             return dfValue;
    6378             :         }
    6379    17931500 :         case GDT_Float32:
    6380             :         {
    6381    17931500 :             const float fValue = static_cast<const float *>(pData)[iOffset];
    6382    35836200 :             if (std::isnan(fValue) ||
    6383    31039800 :                 (sNoDataValues.bGotFloatNoDataValue &&
    6384    13135100 :                  ARE_REAL_EQUAL(fValue, sNoDataValues.fNoDataValue)))
    6385             :             {
    6386       26881 :                 bValid = false;
    6387       26881 :                 return 0.0;
    6388             :             }
    6389    17904700 :             dfValue = fValue;
    6390    17904700 :             return dfValue;
    6391             :         }
    6392     3688930 :         case GDT_Float64:
    6393     3688930 :             dfValue = static_cast<const double *>(pData)[iOffset];
    6394     3688930 :             if (std::isnan(dfValue))
    6395             :             {
    6396          52 :                 bValid = false;
    6397          52 :                 return 0.0;
    6398             :             }
    6399     3688880 :             break;
    6400        2692 :         case GDT_CInt16:
    6401        2692 :             dfValue = static_cast<const GInt16 *>(pData)[iOffset * 2];
    6402        2692 :             break;
    6403        2692 :         case GDT_CInt32:
    6404        2692 :             dfValue = static_cast<const GInt32 *>(pData)[iOffset * 2];
    6405        2692 :             break;
    6406           0 :         case GDT_CFloat16:
    6407           0 :             dfValue = static_cast<const GFloat16 *>(pData)[iOffset * 2];
    6408           0 :             if (std::isnan(dfValue))
    6409             :             {
    6410           0 :                 bValid = false;
    6411           0 :                 return 0.0;
    6412             :             }
    6413           0 :             break;
    6414        5812 :         case GDT_CFloat32:
    6415        5812 :             dfValue = static_cast<const float *>(pData)[iOffset * 2];
    6416        5812 :             if (std::isnan(dfValue))
    6417             :             {
    6418           0 :                 bValid = false;
    6419           0 :                 return 0.0;
    6420             :             }
    6421        5812 :             break;
    6422        5892 :         case GDT_CFloat64:
    6423        5892 :             dfValue = static_cast<const double *>(pData)[iOffset * 2];
    6424        5892 :             if (std::isnan(dfValue))
    6425             :             {
    6426           0 :                 bValid = false;
    6427           0 :                 return 0.0;
    6428             :             }
    6429        5892 :             break;
    6430           0 :         case GDT_Unknown:
    6431             :         case GDT_TypeCount:
    6432           0 :             CPLAssert(false);
    6433             :             break;
    6434             :     }
    6435             : 
    6436     9624280 :     if (sNoDataValues.bGotNoDataValue &&
    6437     3740190 :         ARE_REAL_EQUAL(dfValue, sNoDataValues.dfNoDataValue))
    6438             :     {
    6439     3346220 :         bValid = false;
    6440     3346220 :         return 0.0;
    6441             :     }
    6442     2537860 :     return dfValue;
    6443             : }
    6444             : 
    6445             : /************************************************************************/
    6446             : /*                         SetValidPercent()                            */
    6447             : /************************************************************************/
    6448             : 
    6449             : //! @cond Doxygen_Suppress
    6450             : /**
    6451             :  * \brief Set percentage of valid (not nodata) pixels.
    6452             :  *
    6453             :  * Stores the percentage of valid pixels in the metadata item
    6454             :  * STATISTICS_VALID_PERCENT
    6455             :  *
    6456             :  * @param nSampleCount Number of sampled pixels.
    6457             :  *
    6458             :  * @param nValidCount Number of valid pixels.
    6459             :  */
    6460             : 
    6461         495 : void GDALRasterBand::SetValidPercent(GUIntBig nSampleCount,
    6462             :                                      GUIntBig nValidCount)
    6463             : {
    6464         495 :     if (nValidCount == 0)
    6465             :     {
    6466          12 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "0");
    6467             :     }
    6468         483 :     else if (nValidCount == nSampleCount)
    6469             :     {
    6470         436 :         SetMetadataItem("STATISTICS_VALID_PERCENT", "100");
    6471             :     }
    6472             :     else /* nValidCount < nSampleCount */
    6473             :     {
    6474          47 :         char szValue[128] = {0};
    6475             : 
    6476             :         /* percentage is only an indicator: limit precision */
    6477          47 :         CPLsnprintf(szValue, sizeof(szValue), "%.4g",
    6478          47 :                     100. * static_cast<double>(nValidCount) / nSampleCount);
    6479             : 
    6480          47 :         if (EQUAL(szValue, "100"))
    6481             :         {
    6482             :             /* don't set 100 percent valid
    6483             :              * because some of the sampled pixels were nodata */
    6484           0 :             SetMetadataItem("STATISTICS_VALID_PERCENT", "99.999");
    6485             :         }
    6486             :         else
    6487             :         {
    6488          47 :             SetMetadataItem("STATISTICS_VALID_PERCENT", szValue);
    6489             :         }
    6490             :     }
    6491         495 : }
    6492             : 
    6493             : //! @endcond
    6494             : 
    6495             : /************************************************************************/
    6496             : /*                         ComputeStatistics()                          */
    6497             : /************************************************************************/
    6498             : 
    6499             : /**
    6500             :  * \brief Compute image statistics.
    6501             :  *
    6502             :  * Returns the minimum, maximum, mean and standard deviation of all
    6503             :  * pixel values in this band.  If approximate statistics are sufficient,
    6504             :  * the bApproxOK flag can be set to true in which case overviews, or a
    6505             :  * subset of image tiles may be used in computing the statistics.
    6506             :  *
    6507             :  * Once computed, the statistics will generally be "set" back on the
    6508             :  * raster band using SetStatistics().
    6509             :  *
    6510             :  * Cached statistics can be cleared with GDALDataset::ClearStatistics().
    6511             :  *
    6512             :  * This method is the same as the C function GDALComputeRasterStatistics().
    6513             :  *
    6514             :  * @param bApproxOK If TRUE statistics may be computed based on overviews
    6515             :  * or a subset of all tiles.
    6516             :  *
    6517             :  * @param pdfMin Location into which to load image minimum (may be NULL).
    6518             :  *
    6519             :  * @param pdfMax Location into which to load image maximum (may be NULL).-
    6520             :  *
    6521             :  * @param pdfMean Location into which to load image mean (may be NULL).
    6522             :  *
    6523             :  * @param pdfStdDev Location into which to load image standard deviation
    6524             :  * (may be NULL).
    6525             :  *
    6526             :  * @param pfnProgress a function to call to report progress, or NULL.
    6527             :  *
    6528             :  * @param pProgressData application data to pass to the progress function.
    6529             :  *
    6530             :  * @return CE_None on success, or CE_Failure if an error occurs or processing
    6531             :  * is terminated by the user.
    6532             :  */
    6533             : 
    6534         473 : CPLErr GDALRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
    6535             :                                          double *pdfMax, double *pdfMean,
    6536             :                                          double *pdfStdDev,
    6537             :                                          GDALProgressFunc pfnProgress,
    6538             :                                          void *pProgressData)
    6539             : 
    6540             : {
    6541         473 :     if (pfnProgress == nullptr)
    6542         171 :         pfnProgress = GDALDummyProgress;
    6543             : 
    6544             :     /* -------------------------------------------------------------------- */
    6545             :     /*      If we have overview bands, use them for statistics.             */
    6546             :     /* -------------------------------------------------------------------- */
    6547         473 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    6548             :     {
    6549             :         GDALRasterBand *poBand =
    6550           3 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    6551             : 
    6552           3 :         if (poBand != this)
    6553             :         {
    6554           6 :             CPLErr eErr = poBand->ComputeStatistics(FALSE, pdfMin, pdfMax,
    6555             :                                                     pdfMean, pdfStdDev,
    6556           3 :                                                     pfnProgress, pProgressData);
    6557           3 :             if (eErr == CE_None)
    6558             :             {
    6559           3 :                 if (pdfMin && pdfMax && pdfMean && pdfStdDev)
    6560             :                 {
    6561           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6562           3 :                     SetStatistics(*pdfMin, *pdfMax, *pdfMean, *pdfStdDev);
    6563             :                 }
    6564             : 
    6565             :                 /* transfer metadata from overview band to this */
    6566             :                 const char *pszPercentValid =
    6567           3 :                     poBand->GetMetadataItem("STATISTICS_VALID_PERCENT");
    6568             : 
    6569           3 :                 if (pszPercentValid != nullptr)
    6570             :                 {
    6571           3 :                     SetMetadataItem("STATISTICS_VALID_PERCENT",
    6572           3 :                                     pszPercentValid);
    6573             :                 }
    6574             :             }
    6575           3 :             return eErr;
    6576             :         }
    6577             :     }
    6578             : 
    6579         470 :     if (!pfnProgress(0.0, "Compute Statistics", pProgressData))
    6580             :     {
    6581           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6582           0 :         return CE_Failure;
    6583             :     }
    6584             : 
    6585             :     /* -------------------------------------------------------------------- */
    6586             :     /*      Read actual data and compute statistics.                        */
    6587             :     /* -------------------------------------------------------------------- */
    6588             :     // Using Welford algorithm:
    6589             :     // http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance
    6590             :     // to compute standard deviation in a more numerically robust way than
    6591             :     // the difference of the sum of square values with the square of the sum.
    6592             :     // dfMean and dfM2 are updated at each sample.
    6593             :     // dfM2 is the sum of square of differences to the current mean.
    6594         470 :     double dfMin = std::numeric_limits<double>::infinity();
    6595         470 :     double dfMax = -std::numeric_limits<double>::infinity();
    6596         470 :     double dfMean = 0.0;
    6597         470 :     double dfM2 = 0.0;
    6598             : 
    6599             :     GDALRasterIOExtraArg sExtraArg;
    6600         470 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    6601             : 
    6602         470 :     GDALNoDataValues sNoDataValues(this, eDataType);
    6603         470 :     GDALRasterBand *poMaskBand = nullptr;
    6604         470 :     if (!sNoDataValues.bGotNoDataValue)
    6605             :     {
    6606         443 :         const int l_nMaskFlags = GetMaskFlags();
    6607         488 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    6608          45 :             GetColorInterpretation() != GCI_AlphaBand)
    6609             :         {
    6610          45 :             poMaskBand = GetMaskBand();
    6611             :         }
    6612             :     }
    6613             : 
    6614         470 :     bool bSignedByte = false;
    6615         470 :     if (eDataType == GDT_Byte)
    6616             :     {
    6617         203 :         EnablePixelTypeSignedByteWarning(false);
    6618             :         const char *pszPixelType =
    6619         203 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    6620         203 :         EnablePixelTypeSignedByteWarning(true);
    6621         203 :         bSignedByte =
    6622         203 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    6623             :     }
    6624             : 
    6625         470 :     GUIntBig nSampleCount = 0;
    6626         470 :     GUIntBig nValidCount = 0;
    6627             : 
    6628         470 :     if (bApproxOK && HasArbitraryOverviews())
    6629             :     {
    6630             :         /* --------------------------------------------------------------------
    6631             :          */
    6632             :         /*      Figure out how much the image should be reduced to get an */
    6633             :         /*      approximate value. */
    6634             :         /* --------------------------------------------------------------------
    6635             :          */
    6636           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    6637           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    6638             : 
    6639           0 :         int nXReduced = nRasterXSize;
    6640           0 :         int nYReduced = nRasterYSize;
    6641           0 :         if (dfReduction > 1.0)
    6642             :         {
    6643           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    6644           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    6645             : 
    6646             :             // Catch the case of huge resizing ratios here
    6647           0 :             if (nXReduced == 0)
    6648           0 :                 nXReduced = 1;
    6649           0 :             if (nYReduced == 0)
    6650           0 :                 nYReduced = 1;
    6651             :         }
    6652             : 
    6653           0 :         void *pData = CPLMalloc(cpl::fits_on<int>(
    6654           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    6655             : 
    6656             :         const CPLErr eErr =
    6657           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    6658           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    6659           0 :         if (eErr != CE_None)
    6660             :         {
    6661           0 :             CPLFree(pData);
    6662           0 :             return eErr;
    6663             :         }
    6664             : 
    6665           0 :         GByte *pabyMaskData = nullptr;
    6666           0 :         if (poMaskBand)
    6667             :         {
    6668             :             pabyMaskData =
    6669           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    6670           0 :             if (!pabyMaskData)
    6671             :             {
    6672           0 :                 CPLFree(pData);
    6673           0 :                 return CE_Failure;
    6674             :             }
    6675             : 
    6676           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    6677             :                                      pabyMaskData, nXReduced, nYReduced,
    6678           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    6679             :             {
    6680           0 :                 CPLFree(pData);
    6681           0 :                 CPLFree(pabyMaskData);
    6682           0 :                 return CE_Failure;
    6683             :             }
    6684             :         }
    6685             : 
    6686             :         /* this isn't the fastest way to do this, but is easier for now */
    6687           0 :         for (int iY = 0; iY < nYReduced; iY++)
    6688             :         {
    6689           0 :             for (int iX = 0; iX < nXReduced; iX++)
    6690             :             {
    6691           0 :                 const int iOffset = iX + iY * nXReduced;
    6692           0 :                 if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6693           0 :                     continue;
    6694             : 
    6695           0 :                 bool bValid = true;
    6696           0 :                 double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    6697           0 :                                                iOffset, sNoDataValues, bValid);
    6698           0 :                 if (!bValid)
    6699           0 :                     continue;
    6700             : 
    6701           0 :                 dfMin = std::min(dfMin, dfValue);
    6702           0 :                 dfMax = std::max(dfMax, dfValue);
    6703             : 
    6704           0 :                 nValidCount++;
    6705           0 :                 if (dfMin == dfMax)
    6706             :                 {
    6707           0 :                     if (nValidCount == 1)
    6708           0 :                         dfMean = dfMin;
    6709             :                 }
    6710             :                 else
    6711             :                 {
    6712           0 :                     const double dfDelta = dfValue - dfMean;
    6713           0 :                     dfMean += dfDelta / nValidCount;
    6714           0 :                     dfM2 += dfDelta * (dfValue - dfMean);
    6715             :                 }
    6716             :             }
    6717             :         }
    6718             : 
    6719           0 :         nSampleCount = static_cast<GUIntBig>(nXReduced) * nYReduced;
    6720             : 
    6721           0 :         CPLFree(pData);
    6722           0 :         CPLFree(pabyMaskData);
    6723             :     }
    6724             : 
    6725             :     else  // No arbitrary overviews.
    6726             :     {
    6727         470 :         if (!InitBlockInfo())
    6728           0 :             return CE_Failure;
    6729             : 
    6730             :         /* --------------------------------------------------------------------
    6731             :          */
    6732             :         /*      Figure out the ratio of blocks we will read to get an */
    6733             :         /*      approximate value. */
    6734             :         /* --------------------------------------------------------------------
    6735             :          */
    6736         470 :         int nSampleRate = 1;
    6737         470 :         if (bApproxOK)
    6738             :         {
    6739          43 :             nSampleRate = static_cast<int>(std::max(
    6740          86 :                 1.0,
    6741          43 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    6742             :             // We want to avoid probing only the first column of blocks for
    6743             :             // a square shaped raster, because it is not unlikely that it may
    6744             :             // be padding only (#6378)
    6745          43 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    6746           1 :                 nSampleRate += 1;
    6747             :         }
    6748         470 :         if (nSampleRate == 1)
    6749         436 :             bApproxOK = false;
    6750             : 
    6751             :         // Particular case for GDT_Byte that only use integral types for all
    6752             :         // intermediate computations. Only possible if the number of pixels
    6753             :         // explored is lower than GUINTBIG_MAX / (255*255), so that nSumSquare
    6754             :         // can fit on a uint64. Should be 99.99999% of cases.
    6755             :         // For GUInt16, this limits to raster of 4 giga pixels
    6756         470 :         if ((!poMaskBand && eDataType == GDT_Byte && !bSignedByte &&
    6757         185 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6758         185 :                      nSampleRate <
    6759         185 :                  GUINTBIG_MAX / (255U * 255U) /
    6760         185 :                      (static_cast<GUInt64>(nBlockXSize) *
    6761         185 :                       static_cast<GUInt64>(nBlockYSize))) ||
    6762         285 :             (eDataType == GDT_UInt16 &&
    6763          29 :              static_cast<GUIntBig>(nBlocksPerRow) * nBlocksPerColumn /
    6764          29 :                      nSampleRate <
    6765          29 :                  GUINTBIG_MAX / (65535U * 65535U) /
    6766          29 :                      (static_cast<GUInt64>(nBlockXSize) *
    6767          29 :                       static_cast<GUInt64>(nBlockYSize))))
    6768             :         {
    6769         214 :             const GUInt32 nMaxValueType = (eDataType == GDT_Byte) ? 255 : 65535;
    6770         214 :             GUInt32 nMin = nMaxValueType;
    6771         214 :             GUInt32 nMax = 0;
    6772         214 :             GUIntBig nSum = 0;
    6773         214 :             GUIntBig nSumSquare = 0;
    6774             :             // If no valid nodata, map to invalid value (256 for Byte)
    6775         214 :             const GUInt32 nNoDataValue =
    6776         237 :                 (sNoDataValues.bGotNoDataValue &&
    6777          23 :                  sNoDataValues.dfNoDataValue >= 0 &&
    6778          23 :                  sNoDataValues.dfNoDataValue <= nMaxValueType &&
    6779          23 :                  fabs(sNoDataValues.dfNoDataValue -
    6780          23 :                       static_cast<GUInt32>(sNoDataValues.dfNoDataValue +
    6781             :                                            1e-10)) < 1e-10)
    6782         237 :                     ? static_cast<GUInt32>(sNoDataValues.dfNoDataValue + 1e-10)
    6783             :                     : nMaxValueType + 1;
    6784             : 
    6785         214 :             for (GIntBig iSampleBlock = 0;
    6786       12741 :                  iSampleBlock <
    6787       12741 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6788       12527 :                  iSampleBlock += nSampleRate)
    6789             :             {
    6790       12527 :                 const int iYBlock =
    6791       12527 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    6792       12527 :                 const int iXBlock =
    6793       12527 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    6794             : 
    6795             :                 GDALRasterBlock *const poBlock =
    6796       12527 :                     GetLockedBlockRef(iXBlock, iYBlock);
    6797       12527 :                 if (poBlock == nullptr)
    6798           0 :                     return CE_Failure;
    6799             : 
    6800       12527 :                 void *const pData = poBlock->GetDataRef();
    6801             : 
    6802       12527 :                 int nXCheck = 0, nYCheck = 0;
    6803       12527 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6804             : 
    6805       12527 :                 if (eDataType == GDT_Byte)
    6806             :                 {
    6807             :                     ComputeStatisticsInternal<
    6808             :                         GByte, /* COMPUTE_OTHER_STATS = */ true>::
    6809       12057 :                         f(nXCheck, nBlockXSize, nYCheck,
    6810             :                           static_cast<const GByte *>(pData),
    6811             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6812             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6813             :                 }
    6814             :                 else
    6815             :                 {
    6816             :                     ComputeStatisticsInternal<
    6817             :                         GUInt16, /* COMPUTE_OTHER_STATS = */ true>::
    6818         470 :                         f(nXCheck, nBlockXSize, nYCheck,
    6819             :                           static_cast<const GUInt16 *>(pData),
    6820             :                           nNoDataValue <= nMaxValueType, nNoDataValue, nMin,
    6821             :                           nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    6822             :                 }
    6823             : 
    6824       12527 :                 poBlock->DropLock();
    6825             : 
    6826       12527 :                 if (!pfnProgress(static_cast<double>(iSampleBlock) /
    6827       12527 :                                      (static_cast<double>(nBlocksPerRow) *
    6828       12527 :                                       nBlocksPerColumn),
    6829             :                                  "Compute Statistics", pProgressData))
    6830             :                 {
    6831           0 :                     ReportError(CE_Failure, CPLE_UserInterrupt,
    6832             :                                 "User terminated");
    6833           0 :                     return CE_Failure;
    6834             :                 }
    6835             :             }
    6836             : 
    6837         214 :             if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6838             :             {
    6839           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6840           0 :                 return CE_Failure;
    6841             :             }
    6842             : 
    6843             :             /* --------------------------------------------------------------------
    6844             :              */
    6845             :             /*      Save computed information. */
    6846             :             /* --------------------------------------------------------------------
    6847             :              */
    6848         214 :             if (nValidCount)
    6849         205 :                 dfMean = static_cast<double>(nSum) / nValidCount;
    6850             : 
    6851             :             // To avoid potential precision issues when doing the difference,
    6852             :             // we need to do that computation on 128 bit rather than casting
    6853             :             // to double
    6854             :             const GDALUInt128 nTmpForStdDev(
    6855         214 :                 GDALUInt128::Mul(nSumSquare, nValidCount) -
    6856         428 :                 GDALUInt128::Mul(nSum, nSum));
    6857             :             const double dfStdDev =
    6858         214 :                 nValidCount > 0
    6859         214 :                     ? sqrt(static_cast<double>(nTmpForStdDev)) / nValidCount
    6860         214 :                     : 0.0;
    6861             : 
    6862         214 :             if (nValidCount > 0)
    6863             :             {
    6864         205 :                 if (bApproxOK)
    6865             :                 {
    6866          24 :                     SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    6867             :                 }
    6868         181 :                 else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    6869             :                 {
    6870           3 :                     SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    6871             :                 }
    6872         205 :                 SetStatistics(nMin, nMax, dfMean, dfStdDev);
    6873             :             }
    6874             : 
    6875         214 :             SetValidPercent(nSampleCount, nValidCount);
    6876             : 
    6877             :             /* --------------------------------------------------------------------
    6878             :              */
    6879             :             /*      Record results. */
    6880             :             /* --------------------------------------------------------------------
    6881             :              */
    6882         214 :             if (pdfMin != nullptr)
    6883         211 :                 *pdfMin = nValidCount ? nMin : 0;
    6884         214 :             if (pdfMax != nullptr)
    6885         211 :                 *pdfMax = nValidCount ? nMax : 0;
    6886             : 
    6887         214 :             if (pdfMean != nullptr)
    6888         207 :                 *pdfMean = dfMean;
    6889             : 
    6890         214 :             if (pdfStdDev != nullptr)
    6891         207 :                 *pdfStdDev = dfStdDev;
    6892             : 
    6893         214 :             if (nValidCount > 0)
    6894         205 :                 return CE_None;
    6895             : 
    6896           9 :             ReportError(CE_Failure, CPLE_AppDefined,
    6897             :                         "Failed to compute statistics, no valid pixels found "
    6898             :                         "in sampling.");
    6899           9 :             return CE_Failure;
    6900             :         }
    6901             : 
    6902         256 :         GByte *pabyMaskData = nullptr;
    6903         256 :         if (poMaskBand)
    6904             :         {
    6905             :             pabyMaskData = static_cast<GByte *>(
    6906          45 :                 VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    6907          45 :             if (!pabyMaskData)
    6908             :             {
    6909           0 :                 return CE_Failure;
    6910             :             }
    6911             :         }
    6912             : 
    6913         256 :         for (GIntBig iSampleBlock = 0;
    6914        5891 :              iSampleBlock <
    6915        5891 :              static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    6916        5635 :              iSampleBlock += nSampleRate)
    6917             :         {
    6918        5635 :             const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    6919        5635 :             const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    6920             : 
    6921        5635 :             int nXCheck = 0, nYCheck = 0;
    6922        5635 :             GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    6923             : 
    6924        6220 :             if (poMaskBand &&
    6925         585 :                 poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    6926         585 :                                      iYBlock * nBlockYSize, nXCheck, nYCheck,
    6927             :                                      pabyMaskData, nXCheck, nYCheck, GDT_Byte,
    6928         585 :                                      0, nBlockXSize, nullptr) != CE_None)
    6929             :             {
    6930           0 :                 CPLFree(pabyMaskData);
    6931           0 :                 return CE_Failure;
    6932             :             }
    6933             : 
    6934             :             GDALRasterBlock *const poBlock =
    6935        5635 :                 GetLockedBlockRef(iXBlock, iYBlock);
    6936        5635 :             if (poBlock == nullptr)
    6937             :             {
    6938           0 :                 CPLFree(pabyMaskData);
    6939           0 :                 return CE_Failure;
    6940             :             }
    6941             : 
    6942        5635 :             void *const pData = poBlock->GetDataRef();
    6943             : 
    6944             :             // This isn't the fastest way to do this, but is easier for now.
    6945       13494 :             for (int iY = 0; iY < nYCheck; iY++)
    6946             :             {
    6947     4891200 :                 for (int iX = 0; iX < nXCheck; iX++)
    6948             :                 {
    6949     4883340 :                     const GPtrDiff_t iOffset =
    6950     4883340 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    6951     4883340 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    6952      111829 :                         continue;
    6953             : 
    6954     4779080 :                     bool bValid = true;
    6955             :                     double dfValue =
    6956     4779080 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    6957     4779080 :                                       sNoDataValues, bValid);
    6958             : 
    6959     4779080 :                     if (!bValid)
    6960        7574 :                         continue;
    6961             : 
    6962     4771510 :                     dfMin = std::min(dfMin, dfValue);
    6963     4771510 :                     dfMax = std::max(dfMax, dfValue);
    6964             : 
    6965     4771510 :                     nValidCount++;
    6966     4771510 :                     if (dfMin == dfMax)
    6967             :                     {
    6968     2173320 :                         if (nValidCount == 1)
    6969         255 :                             dfMean = dfMin;
    6970             :                     }
    6971             :                     else
    6972             :                     {
    6973     2598180 :                         const double dfDelta = dfValue - dfMean;
    6974     2598180 :                         dfMean += dfDelta / nValidCount;
    6975     2598180 :                         dfM2 += dfDelta * (dfValue - dfMean);
    6976             :                     }
    6977             :                 }
    6978             :             }
    6979             : 
    6980        5635 :             nSampleCount += static_cast<GUIntBig>(nXCheck) * nYCheck;
    6981             : 
    6982        5635 :             poBlock->DropLock();
    6983             : 
    6984        5635 :             if (!pfnProgress(
    6985        5635 :                     static_cast<double>(iSampleBlock) /
    6986        5635 :                         (static_cast<double>(nBlocksPerRow) * nBlocksPerColumn),
    6987             :                     "Compute Statistics", pProgressData))
    6988             :             {
    6989           0 :                 ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    6990           0 :                 CPLFree(pabyMaskData);
    6991           0 :                 return CE_Failure;
    6992             :             }
    6993             :         }
    6994             : 
    6995         256 :         CPLFree(pabyMaskData);
    6996             :     }
    6997             : 
    6998         256 :     if (!pfnProgress(1.0, "Compute Statistics", pProgressData))
    6999             :     {
    7000           0 :         ReportError(CE_Failure, CPLE_UserInterrupt, "User terminated");
    7001           0 :         return CE_Failure;
    7002             :     }
    7003             : 
    7004             :     /* -------------------------------------------------------------------- */
    7005             :     /*      Save computed information.                                      */
    7006             :     /* -------------------------------------------------------------------- */
    7007         256 :     const double dfStdDev = nValidCount > 0 ? sqrt(dfM2 / nValidCount) : 0.0;
    7008             : 
    7009         256 :     if (nValidCount > 0)
    7010             :     {
    7011         255 :         if (bApproxOK)
    7012             :         {
    7013           8 :             SetMetadataItem("STATISTICS_APPROXIMATE", "YES");
    7014             :         }
    7015         247 :         else if (GetMetadataItem("STATISTICS_APPROXIMATE"))
    7016             :         {
    7017           2 :             SetMetadataItem("STATISTICS_APPROXIMATE", nullptr);
    7018             :         }
    7019         255 :         SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    7020             :     }
    7021             :     else
    7022             :     {
    7023           1 :         dfMin = 0.0;
    7024           1 :         dfMax = 0.0;
    7025             :     }
    7026             : 
    7027         256 :     SetValidPercent(nSampleCount, nValidCount);
    7028             : 
    7029             :     /* -------------------------------------------------------------------- */
    7030             :     /*      Record results.                                                 */
    7031             :     /* -------------------------------------------------------------------- */
    7032         256 :     if (pdfMin != nullptr)
    7033         253 :         *pdfMin = dfMin;
    7034         256 :     if (pdfMax != nullptr)
    7035         253 :         *pdfMax = dfMax;
    7036             : 
    7037         256 :     if (pdfMean != nullptr)
    7038         250 :         *pdfMean = dfMean;
    7039             : 
    7040         256 :     if (pdfStdDev != nullptr)
    7041         250 :         *pdfStdDev = dfStdDev;
    7042             : 
    7043         256 :     if (nValidCount > 0)
    7044         255 :         return CE_None;
    7045             : 
    7046           1 :     ReportError(
    7047             :         CE_Failure, CPLE_AppDefined,
    7048             :         "Failed to compute statistics, no valid pixels found in sampling.");
    7049           1 :     return CE_Failure;
    7050             : }
    7051             : 
    7052             : /************************************************************************/
    7053             : /*                    GDALComputeRasterStatistics()                     */
    7054             : /************************************************************************/
    7055             : 
    7056             : /**
    7057             :  * \brief Compute image statistics.
    7058             :  *
    7059             :  * @see GDALRasterBand::ComputeStatistics()
    7060             :  */
    7061             : 
    7062         157 : CPLErr CPL_STDCALL GDALComputeRasterStatistics(GDALRasterBandH hBand,
    7063             :                                                int bApproxOK, double *pdfMin,
    7064             :                                                double *pdfMax, double *pdfMean,
    7065             :                                                double *pdfStdDev,
    7066             :                                                GDALProgressFunc pfnProgress,
    7067             :                                                void *pProgressData)
    7068             : 
    7069             : {
    7070         157 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterStatistics", CE_Failure);
    7071             : 
    7072         157 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7073             : 
    7074         157 :     return poBand->ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
    7075         157 :                                      pdfStdDev, pfnProgress, pProgressData);
    7076             : }
    7077             : 
    7078             : /************************************************************************/
    7079             : /*                           SetStatistics()                            */
    7080             : /************************************************************************/
    7081             : 
    7082             : /**
    7083             :  * \brief Set statistics on band.
    7084             :  *
    7085             :  * This method can be used to store min/max/mean/standard deviation
    7086             :  * statistics on a raster band.
    7087             :  *
    7088             :  * The default implementation stores them as metadata, and will only work
    7089             :  * on formats that can save arbitrary metadata.  This method cannot detect
    7090             :  * whether metadata will be properly saved and so may return CE_None even
    7091             :  * if the statistics will never be saved.
    7092             :  *
    7093             :  * This method is the same as the C function GDALSetRasterStatistics().
    7094             :  *
    7095             :  * @param dfMin minimum pixel value.
    7096             :  *
    7097             :  * @param dfMax maximum pixel value.
    7098             :  *
    7099             :  * @param dfMean mean (average) of all pixel values.
    7100             :  *
    7101             :  * @param dfStdDev Standard deviation of all pixel values.
    7102             :  *
    7103             :  * @return CE_None on success or CE_Failure on failure.
    7104             :  */
    7105             : 
    7106         493 : CPLErr GDALRasterBand::SetStatistics(double dfMin, double dfMax, double dfMean,
    7107             :                                      double dfStdDev)
    7108             : 
    7109             : {
    7110         493 :     char szValue[128] = {0};
    7111             : 
    7112         493 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMin);
    7113         493 :     SetMetadataItem("STATISTICS_MINIMUM", szValue);
    7114             : 
    7115         493 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMax);
    7116         493 :     SetMetadataItem("STATISTICS_MAXIMUM", szValue);
    7117             : 
    7118         493 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfMean);
    7119         493 :     SetMetadataItem("STATISTICS_MEAN", szValue);
    7120             : 
    7121         493 :     CPLsnprintf(szValue, sizeof(szValue), "%.14g", dfStdDev);
    7122         493 :     SetMetadataItem("STATISTICS_STDDEV", szValue);
    7123             : 
    7124         493 :     return CE_None;
    7125             : }
    7126             : 
    7127             : /************************************************************************/
    7128             : /*                      GDALSetRasterStatistics()                       */
    7129             : /************************************************************************/
    7130             : 
    7131             : /**
    7132             :  * \brief Set statistics on band.
    7133             :  *
    7134             :  * @see GDALRasterBand::SetStatistics()
    7135             :  */
    7136             : 
    7137           2 : CPLErr CPL_STDCALL GDALSetRasterStatistics(GDALRasterBandH hBand, double dfMin,
    7138             :                                            double dfMax, double dfMean,
    7139             :                                            double dfStdDev)
    7140             : 
    7141             : {
    7142           2 :     VALIDATE_POINTER1(hBand, "GDALSetRasterStatistics", CE_Failure);
    7143             : 
    7144           2 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7145           2 :     return poBand->SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
    7146             : }
    7147             : 
    7148             : /************************************************************************/
    7149             : /*                        ComputeRasterMinMax()                         */
    7150             : /************************************************************************/
    7151             : 
    7152             : template <class T, bool HAS_NODATA>
    7153      120175 : static void ComputeMinMax(const T *buffer, size_t nElts, T nodataValue, T *pMin,
    7154             :                           T *pMax)
    7155             : {
    7156      120175 :     T min0 = *pMin;
    7157      120175 :     T max0 = *pMax;
    7158      120175 :     T min1 = *pMin;
    7159      120175 :     T max1 = *pMax;
    7160             :     size_t i;
    7161      214453 :     for (i = 0; i + 1 < nElts; i += 2)
    7162             :     {
    7163       81892 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7164             :         {
    7165       94278 :             min0 = std::min(min0, buffer[i]);
    7166       94278 :             max0 = std::max(max0, buffer[i]);
    7167             :         }
    7168       81892 :         if (!HAS_NODATA || buffer[i + 1] != nodataValue)
    7169             :         {
    7170       94278 :             min1 = std::min(min1, buffer[i + 1]);
    7171       94278 :             max1 = std::max(max1, buffer[i + 1]);
    7172             :         }
    7173             :     }
    7174      120175 :     T min = std::min(min0, min1);
    7175      120175 :     T max = std::max(max0, max1);
    7176      120175 :     if (i < nElts)
    7177             :     {
    7178      118460 :         if (!HAS_NODATA || buffer[i] != nodataValue)
    7179             :         {
    7180      118480 :             min = std::min(min, buffer[i]);
    7181      118480 :             max = std::max(max, buffer[i]);
    7182             :         }
    7183             :     }
    7184      120175 :     *pMin = min;
    7185      120175 :     *pMax = max;
    7186      120175 : }
    7187             : 
    7188             : template <GDALDataType eDataType, bool bSignedByte>
    7189             : static void
    7190       12191 : ComputeMinMaxGeneric(const void *pData, int nXCheck, int nYCheck,
    7191             :                      int nBlockXSize, const GDALNoDataValues &sNoDataValues,
    7192             :                      const GByte *pabyMaskData, double &dfMin, double &dfMax)
    7193             : {
    7194       12191 :     double dfLocalMin = dfMin;
    7195       12191 :     double dfLocalMax = dfMax;
    7196             : 
    7197       42531 :     for (int iY = 0; iY < nYCheck; iY++)
    7198             :     {
    7199    19161629 :         for (int iX = 0; iX < nXCheck; iX++)
    7200             :         {
    7201    19131303 :             const GPtrDiff_t iOffset =
    7202    19131303 :                 iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7203    19131303 :             if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7204     3460312 :                 continue;
    7205    19036560 :             bool bValid = true;
    7206    19036560 :             double dfValue = GetPixelValue(eDataType, bSignedByte, pData,
    7207             :                                            iOffset, sNoDataValues, bValid);
    7208    19036560 :             if (!bValid)
    7209     3365580 :                 continue;
    7210             : 
    7211    15670953 :             dfLocalMin = std::min(dfLocalMin, dfValue);
    7212    15670953 :             dfLocalMax = std::max(dfLocalMax, dfValue);
    7213             :         }
    7214             :     }
    7215             : 
    7216       12191 :     dfMin = dfLocalMin;
    7217       12191 :     dfMax = dfLocalMax;
    7218       12191 : }
    7219             : 
    7220       12191 : static void ComputeMinMaxGeneric(const void *pData, GDALDataType eDataType,
    7221             :                                  bool bSignedByte, int nXCheck, int nYCheck,
    7222             :                                  int nBlockXSize,
    7223             :                                  const GDALNoDataValues &sNoDataValues,
    7224             :                                  const GByte *pabyMaskData, double &dfMin,
    7225             :                                  double &dfMax)
    7226             : {
    7227       12191 :     switch (eDataType)
    7228             :     {
    7229           0 :         case GDT_Unknown:
    7230           0 :             CPLAssert(false);
    7231             :             break;
    7232         672 :         case GDT_Byte:
    7233         672 :             if (bSignedByte)
    7234             :             {
    7235           3 :                 ComputeMinMaxGeneric<GDT_Byte, true>(
    7236             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7237             :                     pabyMaskData, dfMin, dfMax);
    7238             :             }
    7239             :             else
    7240             :             {
    7241         669 :                 ComputeMinMaxGeneric<GDT_Byte, false>(
    7242             :                     pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7243             :                     pabyMaskData, dfMin, dfMax);
    7244             :             }
    7245         672 :             break;
    7246         106 :         case GDT_Int8:
    7247         106 :             ComputeMinMaxGeneric<GDT_Int8, false>(pData, nXCheck, nYCheck,
    7248             :                                                   nBlockXSize, sNoDataValues,
    7249             :                                                   pabyMaskData, dfMin, dfMax);
    7250         106 :             break;
    7251         968 :         case GDT_UInt16:
    7252         968 :             ComputeMinMaxGeneric<GDT_UInt16, false>(pData, nXCheck, nYCheck,
    7253             :                                                     nBlockXSize, sNoDataValues,
    7254             :                                                     pabyMaskData, dfMin, dfMax);
    7255         968 :             break;
    7256           1 :         case GDT_Int16:
    7257           1 :             ComputeMinMaxGeneric<GDT_Int16, false>(pData, nXCheck, nYCheck,
    7258             :                                                    nBlockXSize, sNoDataValues,
    7259             :                                                    pabyMaskData, dfMin, dfMax);
    7260           1 :             break;
    7261         201 :         case GDT_UInt32:
    7262         201 :             ComputeMinMaxGeneric<GDT_UInt32, false>(pData, nXCheck, nYCheck,
    7263             :                                                     nBlockXSize, sNoDataValues,
    7264             :                                                     pabyMaskData, dfMin, dfMax);
    7265         201 :             break;
    7266        1048 :         case GDT_Int32:
    7267        1048 :             ComputeMinMaxGeneric<GDT_Int32, false>(pData, nXCheck, nYCheck,
    7268             :                                                    nBlockXSize, sNoDataValues,
    7269             :                                                    pabyMaskData, dfMin, dfMax);
    7270        1048 :             break;
    7271          17 :         case GDT_UInt64:
    7272          17 :             ComputeMinMaxGeneric<GDT_UInt64, false>(pData, nXCheck, nYCheck,
    7273             :                                                     nBlockXSize, sNoDataValues,
    7274             :                                                     pabyMaskData, dfMin, dfMax);
    7275          17 :             break;
    7276          29 :         case GDT_Int64:
    7277          29 :             ComputeMinMaxGeneric<GDT_Int64, false>(pData, nXCheck, nYCheck,
    7278             :                                                    nBlockXSize, sNoDataValues,
    7279             :                                                    pabyMaskData, dfMin, dfMax);
    7280          29 :             break;
    7281           0 :         case GDT_Float16:
    7282           0 :             ComputeMinMaxGeneric<GDT_Float16, false>(
    7283             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7284             :                 pabyMaskData, dfMin, dfMax);
    7285           0 :             break;
    7286        5552 :         case GDT_Float32:
    7287        5552 :             ComputeMinMaxGeneric<GDT_Float32, false>(
    7288             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7289             :                 pabyMaskData, dfMin, dfMax);
    7290        5552 :             break;
    7291        3487 :         case GDT_Float64:
    7292        3487 :             ComputeMinMaxGeneric<GDT_Float64, false>(
    7293             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7294             :                 pabyMaskData, dfMin, dfMax);
    7295        3487 :             break;
    7296           9 :         case GDT_CInt16:
    7297           9 :             ComputeMinMaxGeneric<GDT_CInt16, false>(pData, nXCheck, nYCheck,
    7298             :                                                     nBlockXSize, sNoDataValues,
    7299             :                                                     pabyMaskData, dfMin, dfMax);
    7300           9 :             break;
    7301           9 :         case GDT_CInt32:
    7302           9 :             ComputeMinMaxGeneric<GDT_CInt32, false>(pData, nXCheck, nYCheck,
    7303             :                                                     nBlockXSize, sNoDataValues,
    7304             :                                                     pabyMaskData, dfMin, dfMax);
    7305           9 :             break;
    7306           0 :         case GDT_CFloat16:
    7307           0 :             ComputeMinMaxGeneric<GDT_CFloat16, false>(
    7308             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7309             :                 pabyMaskData, dfMin, dfMax);
    7310           0 :             break;
    7311          75 :         case GDT_CFloat32:
    7312          75 :             ComputeMinMaxGeneric<GDT_CFloat32, false>(
    7313             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7314             :                 pabyMaskData, dfMin, dfMax);
    7315          75 :             break;
    7316          17 :         case GDT_CFloat64:
    7317          17 :             ComputeMinMaxGeneric<GDT_CFloat64, false>(
    7318             :                 pData, nXCheck, nYCheck, nBlockXSize, sNoDataValues,
    7319             :                 pabyMaskData, dfMin, dfMax);
    7320          17 :             break;
    7321           0 :         case GDT_TypeCount:
    7322           0 :             CPLAssert(false);
    7323             :             break;
    7324             :     }
    7325       12191 : }
    7326             : 
    7327         775 : static bool ComputeMinMaxGenericIterBlocks(
    7328             :     GDALRasterBand *poBand, GDALDataType eDataType, bool bSignedByte,
    7329             :     GIntBig nTotalBlocks, int nSampleRate, int nBlocksPerRow,
    7330             :     const GDALNoDataValues &sNoDataValues, GDALRasterBand *poMaskBand,
    7331             :     double &dfMin, double &dfMax)
    7332             : 
    7333             : {
    7334         775 :     GByte *pabyMaskData = nullptr;
    7335             :     int nBlockXSize, nBlockYSize;
    7336         775 :     poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    7337             : 
    7338         775 :     if (poMaskBand)
    7339             :     {
    7340             :         pabyMaskData =
    7341         109 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7342         109 :         if (!pabyMaskData)
    7343             :         {
    7344           0 :             return false;
    7345             :         }
    7346             :     }
    7347             : 
    7348       12966 :     for (GIntBig iSampleBlock = 0; iSampleBlock < nTotalBlocks;
    7349       12191 :          iSampleBlock += nSampleRate)
    7350             :     {
    7351       12191 :         const int iYBlock = static_cast<int>(iSampleBlock / nBlocksPerRow);
    7352       12191 :         const int iXBlock = static_cast<int>(iSampleBlock % nBlocksPerRow);
    7353             : 
    7354       12191 :         int nXCheck = 0, nYCheck = 0;
    7355       12191 :         poBand->GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7356             : 
    7357       18691 :         if (poMaskBand &&
    7358        6500 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7359             :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7360             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7361             :                                  nBlockXSize, nullptr) != CE_None)
    7362             :         {
    7363           0 :             CPLFree(pabyMaskData);
    7364           0 :             return false;
    7365             :         }
    7366             : 
    7367       12191 :         GDALRasterBlock *poBlock = poBand->GetLockedBlockRef(iXBlock, iYBlock);
    7368       12191 :         if (poBlock == nullptr)
    7369             :         {
    7370           0 :             CPLFree(pabyMaskData);
    7371           0 :             return false;
    7372             :         }
    7373             : 
    7374       12191 :         void *const pData = poBlock->GetDataRef();
    7375             : 
    7376       12191 :         ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXCheck, nYCheck,
    7377             :                              nBlockXSize, sNoDataValues, pabyMaskData, dfMin,
    7378             :                              dfMax);
    7379             : 
    7380       12191 :         poBlock->DropLock();
    7381             :     }
    7382             : 
    7383         775 :     CPLFree(pabyMaskData);
    7384         775 :     return true;
    7385             : }
    7386             : 
    7387             : /**
    7388             :  * \brief Compute the min/max values for a band.
    7389             :  *
    7390             :  * If approximate is OK, then the band's GetMinimum()/GetMaximum() will
    7391             :  * be trusted.  If it doesn't work, a subsample of blocks will be read to
    7392             :  * get an approximate min/max.  If the band has a nodata value it will
    7393             :  * be excluded from the minimum and maximum.
    7394             :  *
    7395             :  * If bApprox is FALSE, then all pixels will be read and used to compute
    7396             :  * an exact range.
    7397             :  *
    7398             :  * This method is the same as the C function GDALComputeRasterMinMax().
    7399             :  *
    7400             :  * @param bApproxOK TRUE if an approximate (faster) answer is OK, otherwise
    7401             :  * FALSE.
    7402             :  * @param adfMinMax the array in which the minimum (adfMinMax[0]) and the
    7403             :  * maximum (adfMinMax[1]) are returned.
    7404             :  *
    7405             :  * @return CE_None on success or CE_Failure on failure.
    7406             :  */
    7407             : 
    7408        1766 : CPLErr GDALRasterBand::ComputeRasterMinMax(int bApproxOK, double *adfMinMax)
    7409             : {
    7410             :     /* -------------------------------------------------------------------- */
    7411             :     /*      Does the driver already know the min/max?                       */
    7412             :     /* -------------------------------------------------------------------- */
    7413        1766 :     if (bApproxOK)
    7414             :     {
    7415          23 :         int bSuccessMin = FALSE;
    7416          23 :         int bSuccessMax = FALSE;
    7417             : 
    7418          23 :         double dfMin = GetMinimum(&bSuccessMin);
    7419          23 :         double dfMax = GetMaximum(&bSuccessMax);
    7420             : 
    7421          23 :         if (bSuccessMin && bSuccessMax)
    7422             :         {
    7423           1 :             adfMinMax[0] = dfMin;
    7424           1 :             adfMinMax[1] = dfMax;
    7425           1 :             return CE_None;
    7426             :         }
    7427             :     }
    7428             : 
    7429             :     /* -------------------------------------------------------------------- */
    7430             :     /*      If we have overview bands, use them for min/max.                */
    7431             :     /* -------------------------------------------------------------------- */
    7432             :     // cppcheck-suppress knownConditionTrueFalse
    7433        1765 :     if (bApproxOK && GetOverviewCount() > 0 && !HasArbitraryOverviews())
    7434             :     {
    7435             :         GDALRasterBand *poBand =
    7436           0 :             GetRasterSampleOverview(GDALSTAT_APPROX_NUMSAMPLES);
    7437             : 
    7438           0 :         if (poBand != this)
    7439           0 :             return poBand->ComputeRasterMinMax(FALSE, adfMinMax);
    7440             :     }
    7441             : 
    7442             :     /* -------------------------------------------------------------------- */
    7443             :     /*      Read actual data and compute minimum and maximum.               */
    7444             :     /* -------------------------------------------------------------------- */
    7445        1765 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7446        1765 :     GDALRasterBand *poMaskBand = nullptr;
    7447        1765 :     if (!sNoDataValues.bGotNoDataValue)
    7448             :     {
    7449        1516 :         const int l_nMaskFlags = GetMaskFlags();
    7450        1625 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    7451         109 :             GetColorInterpretation() != GCI_AlphaBand)
    7452             :         {
    7453         109 :             poMaskBand = GetMaskBand();
    7454             :         }
    7455             :     }
    7456             : 
    7457        1765 :     bool bSignedByte = false;
    7458        1765 :     if (eDataType == GDT_Byte)
    7459             :     {
    7460         779 :         EnablePixelTypeSignedByteWarning(false);
    7461             :         const char *pszPixelType =
    7462         779 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7463         779 :         EnablePixelTypeSignedByteWarning(true);
    7464         779 :         bSignedByte =
    7465         779 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7466             :     }
    7467             : 
    7468             :     GDALRasterIOExtraArg sExtraArg;
    7469        1765 :     INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    7470             : 
    7471        3530 :     GUInt32 nMin = (eDataType == GDT_Byte)
    7472        1765 :                        ? 255
    7473             :                        : 65535;  // used for GByte & GUInt16 cases
    7474        1765 :     GUInt32 nMax = 0;            // used for GByte & GUInt16 cases
    7475        1765 :     GInt16 nMinInt16 =
    7476             :         std::numeric_limits<GInt16>::max();  // used for GInt16 case
    7477        1765 :     GInt16 nMaxInt16 =
    7478             :         std::numeric_limits<GInt16>::lowest();  // used for GInt16 case
    7479        1765 :     double dfMin =
    7480             :         std::numeric_limits<double>::infinity();  // used for generic code path
    7481        1765 :     double dfMax =
    7482             :         -std::numeric_limits<double>::infinity();  // used for generic code path
    7483        1765 :     const bool bUseOptimizedPath =
    7484        2673 :         !poMaskBand && ((eDataType == GDT_Byte && !bSignedByte) ||
    7485         908 :                         eDataType == GDT_Int16 || eDataType == GDT_UInt16);
    7486             : 
    7487             :     const auto ComputeMinMaxForBlock =
    7488       20911 :         [this, bSignedByte, &sNoDataValues, &nMin, &nMax, &nMinInt16,
    7489             :          &nMaxInt16](const void *pData, int nXCheck, int nBufferWidth,
    7490      242393 :                      int nYCheck)
    7491             :     {
    7492       20911 :         if (eDataType == GDT_Byte && !bSignedByte)
    7493             :         {
    7494             :             const bool bHasNoData =
    7495       11561 :                 sNoDataValues.bGotNoDataValue &&
    7496       29672 :                 GDALIsValueInRange<GByte>(sNoDataValues.dfNoDataValue) &&
    7497       11561 :                 static_cast<GByte>(sNoDataValues.dfNoDataValue) ==
    7498       11561 :                     sNoDataValues.dfNoDataValue;
    7499       18111 :             const GUInt32 nNoDataValue =
    7500       18111 :                 bHasNoData ? static_cast<GByte>(sNoDataValues.dfNoDataValue)
    7501             :                            : 0;
    7502             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7503             :             ComputeStatisticsInternal<GByte,
    7504             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7505       18111 :                 f(nXCheck, nBufferWidth, nYCheck,
    7506             :                   static_cast<const GByte *>(pData), bHasNoData, nNoDataValue,
    7507       18111 :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7508             :         }
    7509        2800 :         else if (eDataType == GDT_UInt16)
    7510             :         {
    7511             :             const bool bHasNoData =
    7512          83 :                 sNoDataValues.bGotNoDataValue &&
    7513        1495 :                 GDALIsValueInRange<GUInt16>(sNoDataValues.dfNoDataValue) &&
    7514          83 :                 static_cast<GUInt16>(sNoDataValues.dfNoDataValue) ==
    7515          83 :                     sNoDataValues.dfNoDataValue;
    7516        1412 :             const GUInt32 nNoDataValue =
    7517        1412 :                 bHasNoData ? static_cast<GUInt16>(sNoDataValues.dfNoDataValue)
    7518             :                            : 0;
    7519             :             GUIntBig nSum, nSumSquare, nSampleCount, nValidCount;  // unused
    7520             :             ComputeStatisticsInternal<GUInt16,
    7521             :                                       /* COMPUTE_OTHER_STATS = */ false>::
    7522        1412 :                 f(nXCheck, nBufferWidth, nYCheck,
    7523             :                   static_cast<const GUInt16 *>(pData), bHasNoData, nNoDataValue,
    7524             :                   nMin, nMax, nSum, nSumSquare, nSampleCount, nValidCount);
    7525             :         }
    7526        1388 :         else if (eDataType == GDT_Int16)
    7527             :         {
    7528             :             const bool bHasNoData =
    7529        1214 :                 sNoDataValues.bGotNoDataValue &&
    7530        2602 :                 GDALIsValueInRange<int16_t>(sNoDataValues.dfNoDataValue) &&
    7531        1214 :                 static_cast<int16_t>(sNoDataValues.dfNoDataValue) ==
    7532        1214 :                     sNoDataValues.dfNoDataValue;
    7533        1388 :             if (bHasNoData)
    7534             :             {
    7535        1214 :                 const int16_t nNoDataValue =
    7536        1214 :                     static_cast<int16_t>(sNoDataValues.dfNoDataValue);
    7537      120117 :                 for (int iY = 0; iY < nYCheck; iY++)
    7538             :                 {
    7539      118903 :                     ComputeMinMax<int16_t, true>(
    7540      118903 :                         static_cast<const int16_t *>(pData) +
    7541      118903 :                             static_cast<size_t>(iY) * nBufferWidth,
    7542             :                         nXCheck, nNoDataValue, &nMinInt16, &nMaxInt16);
    7543             :                 }
    7544             :             }
    7545             :             else
    7546             :             {
    7547        1446 :                 for (int iY = 0; iY < nYCheck; iY++)
    7548             :                 {
    7549        1272 :                     ComputeMinMax<int16_t, false>(
    7550        1272 :                         static_cast<const int16_t *>(pData) +
    7551        1272 :                             static_cast<size_t>(iY) * nBufferWidth,
    7552             :                         nXCheck, 0, &nMinInt16, &nMaxInt16);
    7553             :                 }
    7554             :             }
    7555             :         }
    7556       20911 :     };
    7557             : 
    7558        1765 :     if (bApproxOK && HasArbitraryOverviews())
    7559             :     {
    7560             :         /* --------------------------------------------------------------------
    7561             :          */
    7562             :         /*      Figure out how much the image should be reduced to get an */
    7563             :         /*      approximate value. */
    7564             :         /* --------------------------------------------------------------------
    7565             :          */
    7566           0 :         double dfReduction = sqrt(static_cast<double>(nRasterXSize) *
    7567           0 :                                   nRasterYSize / GDALSTAT_APPROX_NUMSAMPLES);
    7568             : 
    7569           0 :         int nXReduced = nRasterXSize;
    7570           0 :         int nYReduced = nRasterYSize;
    7571           0 :         if (dfReduction > 1.0)
    7572             :         {
    7573           0 :             nXReduced = static_cast<int>(nRasterXSize / dfReduction);
    7574           0 :             nYReduced = static_cast<int>(nRasterYSize / dfReduction);
    7575             : 
    7576             :             // Catch the case of huge resizing ratios here
    7577           0 :             if (nXReduced == 0)
    7578           0 :                 nXReduced = 1;
    7579           0 :             if (nYReduced == 0)
    7580           0 :                 nYReduced = 1;
    7581             :         }
    7582             : 
    7583           0 :         void *const pData = CPLMalloc(cpl::fits_on<int>(
    7584           0 :             GDALGetDataTypeSizeBytes(eDataType) * nXReduced * nYReduced));
    7585             : 
    7586             :         const CPLErr eErr =
    7587           0 :             IRasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize, pData,
    7588           0 :                       nXReduced, nYReduced, eDataType, 0, 0, &sExtraArg);
    7589           0 :         if (eErr != CE_None)
    7590             :         {
    7591           0 :             CPLFree(pData);
    7592           0 :             return eErr;
    7593             :         }
    7594             : 
    7595           0 :         GByte *pabyMaskData = nullptr;
    7596           0 :         if (poMaskBand)
    7597             :         {
    7598             :             pabyMaskData =
    7599           0 :                 static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nXReduced, nYReduced));
    7600           0 :             if (!pabyMaskData)
    7601             :             {
    7602           0 :                 CPLFree(pData);
    7603           0 :                 return CE_Failure;
    7604             :             }
    7605             : 
    7606           0 :             if (poMaskBand->RasterIO(GF_Read, 0, 0, nRasterXSize, nRasterYSize,
    7607             :                                      pabyMaskData, nXReduced, nYReduced,
    7608           0 :                                      GDT_Byte, 0, 0, nullptr) != CE_None)
    7609             :             {
    7610           0 :                 CPLFree(pData);
    7611           0 :                 CPLFree(pabyMaskData);
    7612           0 :                 return CE_Failure;
    7613             :             }
    7614             :         }
    7615             : 
    7616           0 :         if (bUseOptimizedPath)
    7617             :         {
    7618           0 :             ComputeMinMaxForBlock(pData, nXReduced, nXReduced, nYReduced);
    7619             :         }
    7620             :         else
    7621             :         {
    7622           0 :             ComputeMinMaxGeneric(pData, eDataType, bSignedByte, nXReduced,
    7623             :                                  nYReduced, nXReduced, sNoDataValues,
    7624             :                                  pabyMaskData, dfMin, dfMax);
    7625             :         }
    7626             : 
    7627           0 :         CPLFree(pData);
    7628           0 :         CPLFree(pabyMaskData);
    7629             :     }
    7630             : 
    7631             :     else  // No arbitrary overviews
    7632             :     {
    7633        1765 :         if (!InitBlockInfo())
    7634           0 :             return CE_Failure;
    7635             : 
    7636             :         /* --------------------------------------------------------------------
    7637             :          */
    7638             :         /*      Figure out the ratio of blocks we will read to get an */
    7639             :         /*      approximate value. */
    7640             :         /* --------------------------------------------------------------------
    7641             :          */
    7642        1765 :         int nSampleRate = 1;
    7643             : 
    7644        1765 :         if (bApproxOK)
    7645             :         {
    7646          22 :             nSampleRate = static_cast<int>(std::max(
    7647          44 :                 1.0,
    7648          22 :                 sqrt(static_cast<double>(nBlocksPerRow) * nBlocksPerColumn)));
    7649             :             // We want to avoid probing only the first column of blocks for
    7650             :             // a square shaped raster, because it is not unlikely that it may
    7651             :             // be padding only (#6378).
    7652          22 :             if (nSampleRate == nBlocksPerRow && nBlocksPerRow > 1)
    7653           0 :                 nSampleRate += 1;
    7654             :         }
    7655             : 
    7656        1765 :         if (bUseOptimizedPath)
    7657             :         {
    7658         990 :             for (GIntBig iSampleBlock = 0;
    7659       21823 :                  iSampleBlock <
    7660       21823 :                  static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7661       20833 :                  iSampleBlock += nSampleRate)
    7662             :             {
    7663       20912 :                 const int iYBlock =
    7664       20912 :                     static_cast<int>(iSampleBlock / nBlocksPerRow);
    7665       20912 :                 const int iXBlock =
    7666       20912 :                     static_cast<int>(iSampleBlock % nBlocksPerRow);
    7667             : 
    7668       20912 :                 GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7669       20912 :                 if (poBlock == nullptr)
    7670           1 :                     return CE_Failure;
    7671             : 
    7672       20911 :                 void *const pData = poBlock->GetDataRef();
    7673             : 
    7674       20911 :                 int nXCheck = 0, nYCheck = 0;
    7675       20911 :                 GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7676             : 
    7677       20911 :                 ComputeMinMaxForBlock(pData, nXCheck, nBlockXSize, nYCheck);
    7678             : 
    7679       20911 :                 poBlock->DropLock();
    7680             : 
    7681       20911 :                 if (eDataType == GDT_Byte && !bSignedByte && nMin == 0 &&
    7682        4110 :                     nMax == 255)
    7683          78 :                     break;
    7684             :             }
    7685             :         }
    7686             :         else
    7687             :         {
    7688         775 :             const GIntBig nTotalBlocks =
    7689         775 :                 static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7690         775 :             if (!ComputeMinMaxGenericIterBlocks(
    7691             :                     this, eDataType, bSignedByte, nTotalBlocks, nSampleRate,
    7692             :                     nBlocksPerRow, sNoDataValues, poMaskBand, dfMin, dfMax))
    7693             :             {
    7694           0 :                 return CE_Failure;
    7695             :             }
    7696             :         }
    7697             :     }
    7698             : 
    7699        1764 :     if (bUseOptimizedPath)
    7700             :     {
    7701         989 :         if ((eDataType == GDT_Byte && !bSignedByte) || eDataType == GDT_UInt16)
    7702             :         {
    7703         887 :             dfMin = nMin;
    7704         887 :             dfMax = nMax;
    7705             :         }
    7706         102 :         else if (eDataType == GDT_Int16)
    7707             :         {
    7708         102 :             dfMin = nMinInt16;
    7709         102 :             dfMax = nMaxInt16;
    7710             :         }
    7711             :     }
    7712             : 
    7713        1764 :     if (dfMin > dfMax)
    7714             :     {
    7715           9 :         adfMinMax[0] = 0;
    7716           9 :         adfMinMax[1] = 0;
    7717           9 :         ReportError(
    7718             :             CE_Failure, CPLE_AppDefined,
    7719             :             "Failed to compute min/max, no valid pixels found in sampling.");
    7720           9 :         return CE_Failure;
    7721             :     }
    7722             : 
    7723        1755 :     adfMinMax[0] = dfMin;
    7724        1755 :     adfMinMax[1] = dfMax;
    7725             : 
    7726        1755 :     return CE_None;
    7727             : }
    7728             : 
    7729             : /************************************************************************/
    7730             : /*                      GDALComputeRasterMinMax()                       */
    7731             : /************************************************************************/
    7732             : 
    7733             : /**
    7734             :  * \brief Compute the min/max values for a band.
    7735             :  *
    7736             :  * @see GDALRasterBand::ComputeRasterMinMax()
    7737             :  *
    7738             :  * @note Prior to GDAL 3.6, this function returned void
    7739             :  */
    7740             : 
    7741        1615 : CPLErr CPL_STDCALL GDALComputeRasterMinMax(GDALRasterBandH hBand, int bApproxOK,
    7742             :                                            double adfMinMax[2])
    7743             : 
    7744             : {
    7745        1615 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMax", CE_Failure);
    7746             : 
    7747        1615 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    7748        1615 :     return poBand->ComputeRasterMinMax(bApproxOK, adfMinMax);
    7749             : }
    7750             : 
    7751             : /************************************************************************/
    7752             : /*                    ComputeRasterMinMaxLocation()                     */
    7753             : /************************************************************************/
    7754             : 
    7755             : /**
    7756             :  * \brief Compute the min/max values for a band, and their location.
    7757             :  *
    7758             :  * Pixels whose value matches the nodata value or are masked by the mask
    7759             :  * band are ignored.
    7760             :  *
    7761             :  * If the minimum or maximum value is hit in several locations, it is not
    7762             :  * specified which one will be returned.
    7763             :  *
    7764             :  * @param[out] pdfMin Pointer to the minimum value.
    7765             :  * @param[out] pdfMax Pointer to the maximum value.
    7766             :  * @param[out] pnMinX Pointer to the column where the minimum value is hit.
    7767             :  * @param[out] pnMinY Pointer to the line where the minimum value is hit.
    7768             :  * @param[out] pnMaxX Pointer to the column where the maximum value is hit.
    7769             :  * @param[out] pnMaxY Pointer to the line where the maximum value is hit.
    7770             :  *
    7771             :  * @return CE_None in case of success, CE_Warning if there are no valid values,
    7772             :  *         CE_Failure in case of error.
    7773             :  *
    7774             :  * @since GDAL 3.11
    7775             :  */
    7776             : 
    7777           8 : CPLErr GDALRasterBand::ComputeRasterMinMaxLocation(double *pdfMin,
    7778             :                                                    double *pdfMax, int *pnMinX,
    7779             :                                                    int *pnMinY, int *pnMaxX,
    7780             :                                                    int *pnMaxY)
    7781             : {
    7782           8 :     int nMinX = -1;
    7783           8 :     int nMinY = -1;
    7784           8 :     int nMaxX = -1;
    7785           8 :     int nMaxY = -1;
    7786           8 :     double dfMin = std::numeric_limits<double>::infinity();
    7787           8 :     double dfMax = -std::numeric_limits<double>::infinity();
    7788           8 :     if (pdfMin)
    7789           5 :         *pdfMin = dfMin;
    7790           8 :     if (pdfMax)
    7791           5 :         *pdfMax = dfMax;
    7792           8 :     if (pnMinX)
    7793           6 :         *pnMinX = nMinX;
    7794           8 :     if (pnMinY)
    7795           6 :         *pnMinY = nMinY;
    7796           8 :     if (pnMaxX)
    7797           6 :         *pnMaxX = nMaxX;
    7798           8 :     if (pnMaxY)
    7799           6 :         *pnMaxY = nMaxY;
    7800             : 
    7801           8 :     if (GDALDataTypeIsComplex(eDataType))
    7802             :     {
    7803           0 :         CPLError(CE_Failure, CPLE_NotSupported,
    7804             :                  "Complex data type not supported");
    7805           0 :         return CE_Failure;
    7806             :     }
    7807             : 
    7808           8 :     if (!InitBlockInfo())
    7809           0 :         return CE_Failure;
    7810             : 
    7811           8 :     GDALNoDataValues sNoDataValues(this, eDataType);
    7812           8 :     GDALRasterBand *poMaskBand = nullptr;
    7813           8 :     if (!sNoDataValues.bGotNoDataValue)
    7814             :     {
    7815           8 :         const int l_nMaskFlags = GetMaskFlags();
    7816           9 :         if (l_nMaskFlags != GMF_ALL_VALID &&
    7817           1 :             GetColorInterpretation() != GCI_AlphaBand)
    7818             :         {
    7819           1 :             poMaskBand = GetMaskBand();
    7820             :         }
    7821             :     }
    7822             : 
    7823           8 :     bool bSignedByte = false;
    7824           8 :     if (eDataType == GDT_Byte)
    7825             :     {
    7826           7 :         EnablePixelTypeSignedByteWarning(false);
    7827             :         const char *pszPixelType =
    7828           7 :             GetMetadataItem("PIXELTYPE", "IMAGE_STRUCTURE");
    7829           7 :         EnablePixelTypeSignedByteWarning(true);
    7830           7 :         bSignedByte =
    7831           7 :             pszPixelType != nullptr && EQUAL(pszPixelType, "SIGNEDBYTE");
    7832             :     }
    7833             : 
    7834           8 :     GByte *pabyMaskData = nullptr;
    7835           8 :     if (poMaskBand)
    7836             :     {
    7837             :         pabyMaskData =
    7838           1 :             static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBlockXSize, nBlockYSize));
    7839           1 :         if (!pabyMaskData)
    7840             :         {
    7841           0 :             return CE_Failure;
    7842             :         }
    7843             :     }
    7844             : 
    7845           8 :     const GIntBig nTotalBlocks =
    7846           8 :         static_cast<GIntBig>(nBlocksPerRow) * nBlocksPerColumn;
    7847           8 :     bool bNeedsMin = pdfMin || pnMinX || pnMinY;
    7848           8 :     bool bNeedsMax = pdfMax || pnMaxX || pnMaxY;
    7849          16 :     for (GIntBig iBlock = 0; iBlock < nTotalBlocks; ++iBlock)
    7850             :     {
    7851          11 :         const int iYBlock = static_cast<int>(iBlock / nBlocksPerRow);
    7852          11 :         const int iXBlock = static_cast<int>(iBlock % nBlocksPerRow);
    7853             : 
    7854          11 :         int nXCheck = 0, nYCheck = 0;
    7855          11 :         GetActualBlockSize(iXBlock, iYBlock, &nXCheck, &nYCheck);
    7856             : 
    7857          13 :         if (poMaskBand &&
    7858           2 :             poMaskBand->RasterIO(GF_Read, iXBlock * nBlockXSize,
    7859           2 :                                  iYBlock * nBlockYSize, nXCheck, nYCheck,
    7860             :                                  pabyMaskData, nXCheck, nYCheck, GDT_Byte, 0,
    7861           2 :                                  nBlockXSize, nullptr) != CE_None)
    7862             :         {
    7863           0 :             CPLFree(pabyMaskData);
    7864           0 :             return CE_Failure;
    7865             :         }
    7866             : 
    7867          11 :         GDALRasterBlock *poBlock = GetLockedBlockRef(iXBlock, iYBlock);
    7868          11 :         if (poBlock == nullptr)
    7869             :         {
    7870           0 :             CPLFree(pabyMaskData);
    7871           0 :             return CE_Failure;
    7872             :         }
    7873             : 
    7874          11 :         void *const pData = poBlock->GetDataRef();
    7875             : 
    7876          11 :         if (poMaskBand || nYCheck < nBlockYSize || nXCheck < nBlockXSize)
    7877             :         {
    7878           4 :             for (int iY = 0; iY < nYCheck; ++iY)
    7879             :             {
    7880           6 :                 for (int iX = 0; iX < nXCheck; ++iX)
    7881             :                 {
    7882           4 :                     const GPtrDiff_t iOffset =
    7883           4 :                         iX + static_cast<GPtrDiff_t>(iY) * nBlockXSize;
    7884           4 :                     if (pabyMaskData && pabyMaskData[iOffset] == 0)
    7885           2 :                         continue;
    7886           2 :                     bool bValid = true;
    7887             :                     double dfValue =
    7888           2 :                         GetPixelValue(eDataType, bSignedByte, pData, iOffset,
    7889             :                                       sNoDataValues, bValid);
    7890           2 :                     if (!bValid)
    7891           0 :                         continue;
    7892           2 :                     if (dfValue < dfMin)
    7893             :                     {
    7894           2 :                         dfMin = dfValue;
    7895           2 :                         nMinX = iXBlock * nBlockXSize + iX;
    7896           2 :                         nMinY = iYBlock * nBlockYSize + iY;
    7897             :                     }
    7898           2 :                     if (dfValue > dfMax)
    7899             :                     {
    7900           1 :                         dfMax = dfValue;
    7901           1 :                         nMaxX = iXBlock * nBlockXSize + iX;
    7902           1 :                         nMaxY = iYBlock * nBlockYSize + iY;
    7903             :                     }
    7904             :                 }
    7905           2 :             }
    7906             :         }
    7907             :         else
    7908             :         {
    7909           9 :             size_t pos_min = 0;
    7910           9 :             size_t pos_max = 0;
    7911           9 :             const auto eEffectiveDT = bSignedByte ? GDT_Int8 : eDataType;
    7912           9 :             if (bNeedsMin && bNeedsMax)
    7913             :             {
    7914          10 :                 std::tie(pos_min, pos_max) = gdal::minmax_element(
    7915           5 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7916           5 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7917          10 :                     sNoDataValues.dfNoDataValue);
    7918             :             }
    7919           4 :             else if (bNeedsMin)
    7920             :             {
    7921           1 :                 pos_min = gdal::min_element(
    7922           1 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7923           1 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7924             :                     sNoDataValues.dfNoDataValue);
    7925             :             }
    7926           3 :             else if (bNeedsMax)
    7927             :             {
    7928           2 :                 pos_max = gdal::max_element(
    7929           2 :                     pData, static_cast<size_t>(nBlockXSize) * nBlockYSize,
    7930           2 :                     eEffectiveDT, sNoDataValues.bGotNoDataValue,
    7931             :                     sNoDataValues.dfNoDataValue);
    7932             :             }
    7933             : 
    7934           9 :             if (bNeedsMin)
    7935             :             {
    7936           6 :                 const int nMinXBlock = static_cast<int>(pos_min % nBlockXSize);
    7937           6 :                 const int nMinYBlock = static_cast<int>(pos_min / nBlockXSize);
    7938           6 :                 bool bValid = true;
    7939             :                 const double dfMinValueBlock =
    7940           6 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_min,
    7941             :                                   sNoDataValues, bValid);
    7942           6 :                 if (bValid && dfMinValueBlock < dfMin)
    7943             :                 {
    7944           5 :                     dfMin = dfMinValueBlock;
    7945           5 :                     nMinX = iXBlock * nBlockXSize + nMinXBlock;
    7946           5 :                     nMinY = iYBlock * nBlockYSize + nMinYBlock;
    7947             :                 }
    7948             :             }
    7949             : 
    7950           9 :             if (bNeedsMax)
    7951             :             {
    7952           7 :                 const int nMaxXBlock = static_cast<int>(pos_max % nBlockXSize);
    7953           7 :                 const int nMaxYBlock = static_cast<int>(pos_max / nBlockXSize);
    7954           7 :                 bool bValid = true;
    7955             :                 const double dfMaxValueBlock =
    7956           7 :                     GetPixelValue(eDataType, bSignedByte, pData, pos_max,
    7957             :                                   sNoDataValues, bValid);
    7958           7 :                 if (bValid && dfMaxValueBlock > dfMax)
    7959             :                 {
    7960           5 :                     dfMax = dfMaxValueBlock;
    7961           5 :                     nMaxX = iXBlock * nBlockXSize + nMaxXBlock;
    7962           5 :                     nMaxY = iYBlock * nBlockYSize + nMaxYBlock;
    7963             :                 }
    7964             :             }
    7965             :         }
    7966             : 
    7967          11 :         poBlock->DropLock();
    7968             : 
    7969          11 :         if (eDataType == GDT_Byte)
    7970             :         {
    7971          10 :             if (bNeedsMin && dfMin == 0)
    7972             :             {
    7973           1 :                 bNeedsMin = false;
    7974             :             }
    7975          10 :             if (bNeedsMax && dfMax == 255)
    7976             :             {
    7977           4 :                 bNeedsMax = false;
    7978             :             }
    7979          10 :             if (!bNeedsMin && !bNeedsMax)
    7980             :             {
    7981           3 :                 break;
    7982             :             }
    7983             :         }
    7984             :     }
    7985             : 
    7986           8 :     CPLFree(pabyMaskData);
    7987             : 
    7988           8 :     if (pdfMin)
    7989           5 :         *pdfMin = dfMin;
    7990           8 :     if (pdfMax)
    7991           5 :         *pdfMax = dfMax;
    7992           8 :     if (pnMinX)
    7993           6 :         *pnMinX = nMinX;
    7994           8 :     if (pnMinY)
    7995           6 :         *pnMinY = nMinY;
    7996           8 :     if (pnMaxX)
    7997           6 :         *pnMaxX = nMaxX;
    7998           8 :     if (pnMaxY)
    7999           6 :         *pnMaxY = nMaxY;
    8000           8 :     return ((bNeedsMin && nMinX < 0) || (bNeedsMax && nMaxX < 0)) ? CE_Warning
    8001           8 :                                                                   : CE_None;
    8002             : }
    8003             : 
    8004             : /************************************************************************/
    8005             : /*                    GDALComputeRasterMinMaxLocation()                 */
    8006             : /************************************************************************/
    8007             : 
    8008             : /**
    8009             :  * \brief Compute the min/max values for a band, and their location.
    8010             :  *
    8011             :  * @see GDALRasterBand::ComputeRasterMinMax()
    8012             :  * @since GDAL 3.11
    8013             :  */
    8014             : 
    8015           6 : CPLErr GDALComputeRasterMinMaxLocation(GDALRasterBandH hBand, double *pdfMin,
    8016             :                                        double *pdfMax, int *pnMinX, int *pnMinY,
    8017             :                                        int *pnMaxX, int *pnMaxY)
    8018             : 
    8019             : {
    8020           6 :     VALIDATE_POINTER1(hBand, "GDALComputeRasterMinMaxLocation", CE_Failure);
    8021             : 
    8022           6 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8023           6 :     return poBand->ComputeRasterMinMaxLocation(pdfMin, pdfMax, pnMinX, pnMinY,
    8024           6 :                                                pnMaxX, pnMaxY);
    8025             : }
    8026             : 
    8027             : /************************************************************************/
    8028             : /*                        SetDefaultHistogram()                         */
    8029             : /************************************************************************/
    8030             : 
    8031             : /* FIXME : add proper documentation */
    8032             : /**
    8033             :  * \brief Set default histogram.
    8034             :  *
    8035             :  * This method is the same as the C function GDALSetDefaultHistogram() and
    8036             :  * GDALSetDefaultHistogramEx()
    8037             :  */
    8038           0 : CPLErr GDALRasterBand::SetDefaultHistogram(double /* dfMin */,
    8039             :                                            double /* dfMax */,
    8040             :                                            int /* nBuckets */,
    8041             :                                            GUIntBig * /* panHistogram */)
    8042             : 
    8043             : {
    8044           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    8045           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    8046             :                     "SetDefaultHistogram() not implemented for this format.");
    8047             : 
    8048           0 :     return CE_Failure;
    8049             : }
    8050             : 
    8051             : /************************************************************************/
    8052             : /*                      GDALSetDefaultHistogram()                       */
    8053             : /************************************************************************/
    8054             : 
    8055             : /**
    8056             :  * \brief Set default histogram.
    8057             :  *
    8058             :  * Use GDALSetRasterHistogramEx() instead to be able to set counts exceeding
    8059             :  * 2 billion.
    8060             :  *
    8061             :  * @see GDALRasterBand::SetDefaultHistogram()
    8062             :  * @see GDALSetRasterHistogramEx()
    8063             :  */
    8064             : 
    8065           0 : CPLErr CPL_STDCALL GDALSetDefaultHistogram(GDALRasterBandH hBand, double dfMin,
    8066             :                                            double dfMax, int nBuckets,
    8067             :                                            int *panHistogram)
    8068             : 
    8069             : {
    8070           0 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogram", CE_Failure);
    8071             : 
    8072           0 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8073             : 
    8074             :     GUIntBig *panHistogramTemp =
    8075           0 :         static_cast<GUIntBig *>(VSIMalloc2(sizeof(GUIntBig), nBuckets));
    8076           0 :     if (panHistogramTemp == nullptr)
    8077             :     {
    8078           0 :         poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
    8079             :                             "Out of memory in GDALSetDefaultHistogram().");
    8080           0 :         return CE_Failure;
    8081             :     }
    8082             : 
    8083           0 :     for (int i = 0; i < nBuckets; ++i)
    8084             :     {
    8085           0 :         panHistogramTemp[i] = static_cast<GUIntBig>(panHistogram[i]);
    8086             :     }
    8087             : 
    8088             :     const CPLErr eErr =
    8089           0 :         poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogramTemp);
    8090             : 
    8091           0 :     CPLFree(panHistogramTemp);
    8092             : 
    8093           0 :     return eErr;
    8094             : }
    8095             : 
    8096             : /************************************************************************/
    8097             : /*                     GDALSetDefaultHistogramEx()                      */
    8098             : /************************************************************************/
    8099             : 
    8100             : /**
    8101             :  * \brief Set default histogram.
    8102             :  *
    8103             :  * @see GDALRasterBand::SetDefaultHistogram()
    8104             :  *
    8105             :  * @since GDAL 2.0
    8106             :  */
    8107             : 
    8108           5 : CPLErr CPL_STDCALL GDALSetDefaultHistogramEx(GDALRasterBandH hBand,
    8109             :                                              double dfMin, double dfMax,
    8110             :                                              int nBuckets,
    8111             :                                              GUIntBig *panHistogram)
    8112             : 
    8113             : {
    8114           5 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultHistogramEx", CE_Failure);
    8115             : 
    8116           5 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8117           5 :     return poBand->SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
    8118             : }
    8119             : 
    8120             : /************************************************************************/
    8121             : /*                           GetDefaultRAT()                            */
    8122             : /************************************************************************/
    8123             : 
    8124             : /**
    8125             :  * \brief Fetch default Raster Attribute Table.
    8126             :  *
    8127             :  * A RAT will be returned if there is a default one associated with the
    8128             :  * band, otherwise NULL is returned.  The returned RAT is owned by the
    8129             :  * band and should not be deleted by the application.
    8130             :  *
    8131             :  * This method is the same as the C function GDALGetDefaultRAT().
    8132             :  *
    8133             :  * @return NULL, or a pointer to an internal RAT owned by the band.
    8134             :  */
    8135             : 
    8136         173 : GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
    8137             : 
    8138             : {
    8139         173 :     return nullptr;
    8140             : }
    8141             : 
    8142             : /************************************************************************/
    8143             : /*                         GDALGetDefaultRAT()                          */
    8144             : /************************************************************************/
    8145             : 
    8146             : /**
    8147             :  * \brief Fetch default Raster Attribute Table.
    8148             :  *
    8149             :  * @see GDALRasterBand::GetDefaultRAT()
    8150             :  */
    8151             : 
    8152        1074 : GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT(GDALRasterBandH hBand)
    8153             : 
    8154             : {
    8155        1074 :     VALIDATE_POINTER1(hBand, "GDALGetDefaultRAT", nullptr);
    8156             : 
    8157        1074 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8158        1074 :     return GDALRasterAttributeTable::ToHandle(poBand->GetDefaultRAT());
    8159             : }
    8160             : 
    8161             : /************************************************************************/
    8162             : /*                           SetDefaultRAT()                            */
    8163             : /************************************************************************/
    8164             : 
    8165             : /**
    8166             :  * \fn GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable*)
    8167             :  * \brief Set default Raster Attribute Table.
    8168             :  *
    8169             :  * Associates a default RAT with the band.  If not implemented for the
    8170             :  * format a CPLE_NotSupported error will be issued.  If successful a copy
    8171             :  * of the RAT is made, the original remains owned by the caller.
    8172             :  *
    8173             :  * This method is the same as the C function GDALSetDefaultRAT().
    8174             :  *
    8175             :  * @param poRAT the RAT to assign to the band.
    8176             :  *
    8177             :  * @return CE_None on success or CE_Failure if unsupported or otherwise
    8178             :  * failing.
    8179             :  */
    8180             : 
    8181             : /**/
    8182             : /**/
    8183             : 
    8184             : CPLErr
    8185           0 : GDALRasterBand::SetDefaultRAT(const GDALRasterAttributeTable * /* poRAT */)
    8186             : {
    8187           0 :     if (!(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED))
    8188             :     {
    8189           0 :         CPLPushErrorHandler(CPLQuietErrorHandler);
    8190           0 :         ReportError(CE_Failure, CPLE_NotSupported,
    8191             :                     "SetDefaultRAT() not implemented for this format.");
    8192           0 :         CPLPopErrorHandler();
    8193             :     }
    8194           0 :     return CE_Failure;
    8195             : }
    8196             : 
    8197             : /************************************************************************/
    8198             : /*                         GDALSetDefaultRAT()                          */
    8199             : /************************************************************************/
    8200             : 
    8201             : /**
    8202             :  * \brief Set default Raster Attribute Table.
    8203             :  *
    8204             :  * @see GDALRasterBand::GDALSetDefaultRAT()
    8205             :  */
    8206             : 
    8207          18 : CPLErr CPL_STDCALL GDALSetDefaultRAT(GDALRasterBandH hBand,
    8208             :                                      GDALRasterAttributeTableH hRAT)
    8209             : 
    8210             : {
    8211          18 :     VALIDATE_POINTER1(hBand, "GDALSetDefaultRAT", CE_Failure);
    8212             : 
    8213          18 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8214             : 
    8215          18 :     return poBand->SetDefaultRAT(GDALRasterAttributeTable::FromHandle(hRAT));
    8216             : }
    8217             : 
    8218             : /************************************************************************/
    8219             : /*                            GetMaskBand()                             */
    8220             : /************************************************************************/
    8221             : 
    8222             : /**
    8223             :  * \brief Return the mask band associated with the band.
    8224             :  *
    8225             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8226             :  * that returns one of four default implementations :
    8227             :  * <ul>
    8228             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8229             :  * </li>
    8230             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8231             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8232             :  * GMF_NODATA | GMF_PER_DATASET.
    8233             :  * </li>
    8234             :  * <li>If the band has a nodata value set, an instance of the new
    8235             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8236             :  * GMF_NODATA.
    8237             :  * </li>
    8238             :  * <li>If there is no nodata value, but the dataset has an alpha band that seems
    8239             :  * to apply to this band (specific rules yet to be determined) and that is of
    8240             :  * type GDT_Byte then that alpha band will be returned, and the flags
    8241             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8242             :  * </li>
    8243             :  * <li>If neither of the above apply, an instance of the new
    8244             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8245             :  * pixels. The null flags will return GMF_ALL_VALID.
    8246             :  * </li>
    8247             :  * </ul>
    8248             :  *
    8249             :  * Note that the GetMaskBand() should always return a GDALRasterBand mask, even
    8250             :  * if it is only an all 255 mask with the flags indicating GMF_ALL_VALID.
    8251             :  *
    8252             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8253             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8254             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8255             :  * main dataset.
    8256             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8257             :  * level, where xx matches the band number of a band of the main dataset. The
    8258             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8259             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8260             :  * a band, then the other rules explained above will be used to generate a
    8261             :  * on-the-fly mask band.
    8262             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8263             :  *
    8264             :  * This method is the same as the C function GDALGetMaskBand().
    8265             :  *
    8266             :  * @return a valid mask band.
    8267             :  *
    8268             :  * @since GDAL 1.5.0
    8269             :  *
    8270             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8271             :  *
    8272             :  */
    8273      804952 : GDALRasterBand *GDALRasterBand::GetMaskBand()
    8274             : 
    8275             : {
    8276      386085 :     const auto HasNoData = [this]()
    8277             :     {
    8278      128363 :         int bHaveNoDataRaw = FALSE;
    8279      128363 :         bool bHaveNoData = false;
    8280      128363 :         if (eDataType == GDT_Int64)
    8281             :         {
    8282          66 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsInt64(&bHaveNoDataRaw));
    8283          66 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8284             :         }
    8285      128297 :         else if (eDataType == GDT_UInt64)
    8286             :         {
    8287          48 :             CPL_IGNORE_RET_VAL(GetNoDataValueAsUInt64(&bHaveNoDataRaw));
    8288          48 :             bHaveNoData = CPL_TO_BOOL(bHaveNoDataRaw);
    8289             :         }
    8290             :         else
    8291             :         {
    8292      128249 :             const double dfNoDataValue = GetNoDataValue(&bHaveNoDataRaw);
    8293      128255 :             if (bHaveNoDataRaw &&
    8294      128255 :                 GDALNoDataMaskBand::IsNoDataInRange(dfNoDataValue, eDataType))
    8295             :             {
    8296        1021 :                 bHaveNoData = true;
    8297             :             }
    8298             :         }
    8299      128370 :         return bHaveNoData;
    8300      804952 :     };
    8301             : 
    8302      804952 :     if (poMask != nullptr)
    8303             :     {
    8304      700788 :         if (poMask.IsOwned())
    8305             :         {
    8306      333520 :             if (dynamic_cast<GDALAllValidMaskBand *>(poMask.get()) != nullptr)
    8307             :             {
    8308       33353 :                 if (HasNoData())
    8309             :                 {
    8310           9 :                     InvalidateMaskBand();
    8311             :                 }
    8312             :             }
    8313      300467 :             else if (auto poNoDataMaskBand =
    8314      300226 :                          dynamic_cast<GDALNoDataMaskBand *>(poMask.get()))
    8315             :             {
    8316         388 :                 int bHaveNoDataRaw = FALSE;
    8317         388 :                 bool bIsSame = false;
    8318         388 :                 if (eDataType == GDT_Int64)
    8319          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueInt64 ==
    8320          27 :                                   GetNoDataValueAsInt64(&bHaveNoDataRaw) &&
    8321          10 :                               bHaveNoDataRaw;
    8322         371 :                 else if (eDataType == GDT_UInt64)
    8323          17 :                     bIsSame = poNoDataMaskBand->m_nNoDataValueUInt64 ==
    8324          27 :                                   GetNoDataValueAsUInt64(&bHaveNoDataRaw) &&
    8325          10 :                               bHaveNoDataRaw;
    8326             :                 else
    8327             :                 {
    8328             :                     const double dfNoDataValue =
    8329         354 :                         GetNoDataValue(&bHaveNoDataRaw);
    8330         354 :                     if (bHaveNoDataRaw)
    8331             :                     {
    8332         351 :                         bIsSame =
    8333         351 :                             std::isnan(dfNoDataValue)
    8334         351 :                                 ? std::isnan(poNoDataMaskBand->m_dfNoDataValue)
    8335         316 :                                 : poNoDataMaskBand->m_dfNoDataValue ==
    8336             :                                       dfNoDataValue;
    8337             :                     }
    8338             :                 }
    8339         388 :                 if (!bIsSame)
    8340          23 :                     InvalidateMaskBand();
    8341             :             }
    8342             :         }
    8343             : 
    8344      704261 :         if (poMask)
    8345      706955 :             return poMask.get();
    8346             :     }
    8347             : 
    8348             :     /* -------------------------------------------------------------------- */
    8349             :     /*      Check for a mask in a .msk file.                                */
    8350             :     /* -------------------------------------------------------------------- */
    8351       95130 :     if (poDS != nullptr && poDS->oOvManager.HaveMaskFile())
    8352             :     {
    8353          46 :         poMask.resetNotOwned(poDS->oOvManager.GetMaskBand(nBand));
    8354          46 :         if (poMask != nullptr)
    8355             :         {
    8356          44 :             nMaskFlags = poDS->oOvManager.GetMaskFlags(nBand);
    8357          44 :             return poMask.get();
    8358             :         }
    8359             :     }
    8360             : 
    8361             :     /* -------------------------------------------------------------------- */
    8362             :     /*      Check for NODATA_VALUES metadata.                               */
    8363             :     /* -------------------------------------------------------------------- */
    8364       95084 :     if (poDS != nullptr)
    8365             :     {
    8366             :         const char *pszGDALNoDataValues =
    8367       95071 :             poDS->GetMetadataItem("NODATA_VALUES");
    8368       95071 :         if (pszGDALNoDataValues != nullptr)
    8369             :         {
    8370          68 :             char **papszGDALNoDataValues = CSLTokenizeStringComplex(
    8371             :                 pszGDALNoDataValues, " ", FALSE, FALSE);
    8372             : 
    8373             :             // Make sure we have as many values as bands.
    8374         136 :             if (CSLCount(papszGDALNoDataValues) == poDS->GetRasterCount() &&
    8375          68 :                 poDS->GetRasterCount() != 0)
    8376             :             {
    8377             :                 // Make sure that all bands have the same data type
    8378             :                 // This is clearly not a fundamental condition, just a
    8379             :                 // condition to make implementation easier.
    8380          68 :                 GDALDataType eDT = GDT_Unknown;
    8381          68 :                 int i = 0;  // Used after for.
    8382         270 :                 for (; i < poDS->GetRasterCount(); ++i)
    8383             :                 {
    8384         202 :                     if (i == 0)
    8385          68 :                         eDT = poDS->GetRasterBand(1)->GetRasterDataType();
    8386         134 :                     else if (eDT !=
    8387         134 :                              poDS->GetRasterBand(i + 1)->GetRasterDataType())
    8388             :                     {
    8389           0 :                         break;
    8390             :                     }
    8391             :                 }
    8392          68 :                 if (i == poDS->GetRasterCount())
    8393             :                 {
    8394          68 :                     nMaskFlags = GMF_NODATA | GMF_PER_DATASET;
    8395             :                     try
    8396             :                     {
    8397          68 :                         poMask.reset(
    8398         136 :                             std::make_unique<GDALNoDataValuesMaskBand>(poDS));
    8399             :                     }
    8400           0 :                     catch (const std::bad_alloc &)
    8401             :                     {
    8402           0 :                         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8403           0 :                         poMask.reset();
    8404             :                     }
    8405          68 :                     CSLDestroy(papszGDALNoDataValues);
    8406          68 :                     return poMask.get();
    8407             :                 }
    8408             :                 else
    8409             :                 {
    8410           0 :                     ReportError(CE_Warning, CPLE_AppDefined,
    8411             :                                 "All bands should have the same type in "
    8412             :                                 "order the NODATA_VALUES metadata item "
    8413             :                                 "to be used as a mask.");
    8414             :                 }
    8415             :             }
    8416             :             else
    8417             :             {
    8418           0 :                 ReportError(
    8419             :                     CE_Warning, CPLE_AppDefined,
    8420             :                     "NODATA_VALUES metadata item doesn't have the same number "
    8421             :                     "of values as the number of bands.  "
    8422             :                     "Ignoring it for mask.");
    8423             :             }
    8424             : 
    8425           0 :             CSLDestroy(papszGDALNoDataValues);
    8426             :         }
    8427             :     }
    8428             : 
    8429             :     /* -------------------------------------------------------------------- */
    8430             :     /*      Check for nodata case.                                          */
    8431             :     /* -------------------------------------------------------------------- */
    8432       95016 :     if (HasNoData())
    8433             :     {
    8434        1047 :         nMaskFlags = GMF_NODATA;
    8435             :         try
    8436             :         {
    8437        1047 :             poMask.reset(std::make_unique<GDALNoDataMaskBand>(this));
    8438             :         }
    8439           0 :         catch (const std::bad_alloc &)
    8440             :         {
    8441           0 :             CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8442           0 :             poMask.reset();
    8443             :         }
    8444        1047 :         return poMask.get();
    8445             :     }
    8446             : 
    8447             :     /* -------------------------------------------------------------------- */
    8448             :     /*      Check for alpha case.                                           */
    8449             :     /* -------------------------------------------------------------------- */
    8450       93955 :     if (poDS != nullptr && poDS->GetRasterCount() == 2 &&
    8451      188511 :         this == poDS->GetRasterBand(1) &&
    8452         587 :         poDS->GetRasterBand(2)->GetColorInterpretation() == GCI_AlphaBand)
    8453             :     {
    8454         223 :         if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_Byte)
    8455             :         {
    8456         179 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8457         179 :             poMask.resetNotOwned(poDS->GetRasterBand(2));
    8458         179 :             return poMask.get();
    8459             :         }
    8460          44 :         else if (poDS->GetRasterBand(2)->GetRasterDataType() == GDT_UInt16)
    8461             :         {
    8462          23 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8463             :             try
    8464             :             {
    8465          23 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    8466          46 :                     poDS->GetRasterBand(2)));
    8467             :             }
    8468           0 :             catch (const std::bad_alloc &)
    8469             :             {
    8470           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8471           0 :                 poMask.reset();
    8472             :             }
    8473          23 :             return poMask.get();
    8474             :         }
    8475             :     }
    8476             : 
    8477       93752 :     if (poDS != nullptr && poDS->GetRasterCount() == 4 &&
    8478        3001 :         (this == poDS->GetRasterBand(1) || this == poDS->GetRasterBand(2) ||
    8479      188238 :          this == poDS->GetRasterBand(3)) &&
    8480        2337 :         poDS->GetRasterBand(4)->GetColorInterpretation() == GCI_AlphaBand)
    8481             :     {
    8482        1459 :         if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_Byte)
    8483             :         {
    8484        1408 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8485        1408 :             poMask.resetNotOwned(poDS->GetRasterBand(4));
    8486        1408 :             return poMask.get();
    8487             :         }
    8488          51 :         else if (poDS->GetRasterBand(4)->GetRasterDataType() == GDT_UInt16)
    8489             :         {
    8490          38 :             nMaskFlags = GMF_ALPHA | GMF_PER_DATASET;
    8491             :             try
    8492             :             {
    8493          38 :                 poMask.reset(std::make_unique<GDALRescaledAlphaBand>(
    8494          76 :                     poDS->GetRasterBand(4)));
    8495             :             }
    8496           0 :             catch (const std::bad_alloc &)
    8497             :             {
    8498           0 :                 CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8499           0 :                 poMask.reset();
    8500             :             }
    8501          38 :             return poMask.get();
    8502             :         }
    8503             :     }
    8504             : 
    8505             :     /* -------------------------------------------------------------------- */
    8506             :     /*      Fallback to all valid case.                                     */
    8507             :     /* -------------------------------------------------------------------- */
    8508       92320 :     nMaskFlags = GMF_ALL_VALID;
    8509             :     try
    8510             :     {
    8511       92320 :         poMask.reset(std::make_unique<GDALAllValidMaskBand>(this));
    8512             :     }
    8513           0 :     catch (const std::bad_alloc &)
    8514             :     {
    8515           0 :         CPLError(CE_Failure, CPLE_OutOfMemory, "Out of memory");
    8516           0 :         poMask.reset();
    8517             :     }
    8518             : 
    8519       92320 :     return poMask.get();
    8520             : }
    8521             : 
    8522             : /************************************************************************/
    8523             : /*                          GDALGetMaskBand()                           */
    8524             : /************************************************************************/
    8525             : 
    8526             : /**
    8527             :  * \brief Return the mask band associated with the band.
    8528             :  *
    8529             :  * @see GDALRasterBand::GetMaskBand()
    8530             :  */
    8531             : 
    8532       11042 : GDALRasterBandH CPL_STDCALL GDALGetMaskBand(GDALRasterBandH hBand)
    8533             : 
    8534             : {
    8535       11042 :     VALIDATE_POINTER1(hBand, "GDALGetMaskBand", nullptr);
    8536             : 
    8537       11042 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8538       11042 :     return poBand->GetMaskBand();
    8539             : }
    8540             : 
    8541             : /************************************************************************/
    8542             : /*                            GetMaskFlags()                            */
    8543             : /************************************************************************/
    8544             : 
    8545             : /**
    8546             :  * \brief Return the status flags of the mask band associated with the band.
    8547             :  *
    8548             :  * The GetMaskFlags() method returns an bitwise OR-ed set of status flags with
    8549             :  * the following available definitions that may be extended in the future:
    8550             :  * <ul>
    8551             :  * <li>GMF_ALL_VALID(0x01): There are no invalid pixels, all mask values will be
    8552             :  * 255. When used this will normally be the only flag set.
    8553             :  * </li>
    8554             :  * <li>GMF_PER_DATASET(0x02): The mask band is shared between all bands on the
    8555             :  * dataset.
    8556             :  * </li>
    8557             :  * <li>GMF_ALPHA(0x04): The mask band is actually an alpha band
    8558             :  * and may have values other than 0 and 255.
    8559             :  * </li>
    8560             :  * <li>GMF_NODATA(0x08): Indicates the mask is actually being generated from
    8561             :  * nodata values. (mutually exclusive of GMF_ALPHA)
    8562             :  * </li>
    8563             :  * </ul>
    8564             :  *
    8565             :  * The GDALRasterBand class includes a default implementation of GetMaskBand()
    8566             :  * that returns one of four default implementations:
    8567             :  * <ul>
    8568             :  * <li>If a corresponding .msk file exists it will be used for the mask band.
    8569             :  * </li>
    8570             :  * <li>If the dataset has a NODATA_VALUES metadata item, an instance of the new
    8571             :  * GDALNoDataValuesMaskBand class will be returned. GetMaskFlags() will return
    8572             :  * GMF_NODATA | GMF_PER_DATASET.
    8573             :  * </li>
    8574             :  * <li>If the band has a nodata value set, an instance of the new
    8575             :  * GDALNodataMaskRasterBand class will be returned. GetMaskFlags() will return
    8576             :  * GMF_NODATA.
    8577             :  * </li>
    8578             :  * <li>If there is no nodata value, but the dataset has an alpha band that
    8579             :  * seems to apply to this band (specific rules yet to be determined) and that is
    8580             :  * of type GDT_Byte then that alpha band will be returned, and the flags
    8581             :  * GMF_PER_DATASET and GMF_ALPHA will be returned in the flags.
    8582             :  * </li>
    8583             :  * <li>If neither of the above apply, an instance of the new
    8584             :  * GDALAllValidRasterBand class will be returned that has 255 values for all
    8585             :  * pixels. The null flags will return GMF_ALL_VALID.
    8586             :  * </li>
    8587             :  * </ul>
    8588             :  *
    8589             :  * For an external .msk file to be recognized by GDAL, it must be a valid GDAL
    8590             :  * dataset, with the same name as the main dataset and suffixed with .msk,
    8591             :  * with either one band (in the GMF_PER_DATASET case), or as many bands as the
    8592             :  * main dataset.
    8593             :  * It must have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8594             :  * level, where xx matches the band number of a band of the main dataset. The
    8595             :  * value of those items is a combination of the flags GMF_ALL_VALID,
    8596             :  * GMF_PER_DATASET, GMF_ALPHA and GMF_NODATA. If a metadata item is missing for
    8597             :  * a band, then the other rules explained above will be used to generate a
    8598             :  * on-the-fly mask band.
    8599             :  * \see CreateMaskBand() for the characteristics of .msk files created by GDAL.
    8600             :  *
    8601             :  * This method is the same as the C function GDALGetMaskFlags().
    8602             :  *
    8603             :  * @since GDAL 1.5.0
    8604             :  *
    8605             :  * @return a valid mask band.
    8606             :  *
    8607             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8608             :  *
    8609             :  */
    8610      150267 : int GDALRasterBand::GetMaskFlags()
    8611             : 
    8612             : {
    8613             :     // If we don't have a band yet, force this now so that the masks value
    8614             :     // will be initialized.
    8615             : 
    8616      150267 :     if (poMask == nullptr)
    8617       93832 :         GetMaskBand();
    8618             : 
    8619      150264 :     return nMaskFlags;
    8620             : }
    8621             : 
    8622             : /************************************************************************/
    8623             : /*                          GDALGetMaskFlags()                          */
    8624             : /************************************************************************/
    8625             : 
    8626             : /**
    8627             :  * \brief Return the status flags of the mask band associated with the band.
    8628             :  *
    8629             :  * @see GDALRasterBand::GetMaskFlags()
    8630             :  */
    8631             : 
    8632        6963 : int CPL_STDCALL GDALGetMaskFlags(GDALRasterBandH hBand)
    8633             : 
    8634             : {
    8635        6963 :     VALIDATE_POINTER1(hBand, "GDALGetMaskFlags", GMF_ALL_VALID);
    8636             : 
    8637        6963 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8638        6963 :     return poBand->GetMaskFlags();
    8639             : }
    8640             : 
    8641             : /************************************************************************/
    8642             : /*                         InvalidateMaskBand()                         */
    8643             : /************************************************************************/
    8644             : 
    8645             : //! @cond Doxygen_Suppress
    8646     1911520 : void GDALRasterBand::InvalidateMaskBand()
    8647             : {
    8648     1911520 :     poMask.reset();
    8649     1911520 :     nMaskFlags = 0;
    8650     1911520 : }
    8651             : 
    8652             : //! @endcond
    8653             : 
    8654             : /************************************************************************/
    8655             : /*                           CreateMaskBand()                           */
    8656             : /************************************************************************/
    8657             : 
    8658             : /**
    8659             :  * \brief Adds a mask band to the current band
    8660             :  *
    8661             :  * The default implementation of the CreateMaskBand() method is implemented
    8662             :  * based on similar rules to the .ovr handling implemented using the
    8663             :  * GDALDefaultOverviews object. A TIFF file with the extension .msk will
    8664             :  * be created with the same basename as the original file, and it will have
    8665             :  * as many bands as the original image (or just one for GMF_PER_DATASET).
    8666             :  * The mask images will be deflate compressed tiled images with the same
    8667             :  * block size as the original image if possible.
    8668             :  * It will have INTERNAL_MASK_FLAGS_xx metadata items set at the dataset
    8669             :  * level, where xx matches the band number of a band of the main dataset. The
    8670             :  * value of those items will be the one of the nFlagsIn parameter.
    8671             :  *
    8672             :  * Note that if you got a mask band with a previous call to GetMaskBand(),
    8673             :  * it might be invalidated by CreateMaskBand(). So you have to call
    8674             :  * GetMaskBand() again.
    8675             :  *
    8676             :  * This method is the same as the C function GDALCreateMaskBand().
    8677             :  *
    8678             :  * @since GDAL 1.5.0
    8679             :  *
    8680             :  * @param nFlagsIn 0 or combination of GMF_PER_DATASET / GMF_ALPHA.
    8681             :  *
    8682             :  * @return CE_None on success or CE_Failure on an error.
    8683             :  *
    8684             :  * @see https://gdal.org/development/rfc/rfc15_nodatabitmask.html
    8685             :  * @see GDALDataset::CreateMaskBand()
    8686             :  *
    8687             :  */
    8688             : 
    8689           9 : CPLErr GDALRasterBand::CreateMaskBand(int nFlagsIn)
    8690             : 
    8691             : {
    8692           9 :     if (poDS != nullptr && poDS->oOvManager.IsInitialized())
    8693             :     {
    8694           9 :         const CPLErr eErr = poDS->oOvManager.CreateMaskBand(nFlagsIn, nBand);
    8695           9 :         if (eErr != CE_None)
    8696           1 :             return eErr;
    8697             : 
    8698           8 :         InvalidateMaskBand();
    8699             : 
    8700           8 :         return CE_None;
    8701             :     }
    8702             : 
    8703           0 :     ReportError(CE_Failure, CPLE_NotSupported,
    8704             :                 "CreateMaskBand() not supported for this band.");
    8705             : 
    8706           0 :     return CE_Failure;
    8707             : }
    8708             : 
    8709             : /************************************************************************/
    8710             : /*                         GDALCreateMaskBand()                         */
    8711             : /************************************************************************/
    8712             : 
    8713             : /**
    8714             :  * \brief Adds a mask band to the current band
    8715             :  *
    8716             :  * @see GDALRasterBand::CreateMaskBand()
    8717             :  */
    8718             : 
    8719          33 : CPLErr CPL_STDCALL GDALCreateMaskBand(GDALRasterBandH hBand, int nFlags)
    8720             : 
    8721             : {
    8722          33 :     VALIDATE_POINTER1(hBand, "GDALCreateMaskBand", CE_Failure);
    8723             : 
    8724          33 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8725          33 :     return poBand->CreateMaskBand(nFlags);
    8726             : }
    8727             : 
    8728             : /************************************************************************/
    8729             : /*                            IsMaskBand()                              */
    8730             : /************************************************************************/
    8731             : 
    8732             : /**
    8733             :  * \brief Returns whether a band is a mask band.
    8734             :  *
    8735             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8736             :  * mask band, an alpha band, or an implicit mask band.
    8737             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8738             :  *
    8739             :  * This method is the same as the C function GDALIsMaskBand().
    8740             :  *
    8741             :  * @return true if the band is a mask band.
    8742             :  *
    8743             :  * @see GDALDataset::CreateMaskBand()
    8744             :  *
    8745             :  * @since GDAL 3.5.0
    8746             :  *
    8747             :  */
    8748             : 
    8749         439 : bool GDALRasterBand::IsMaskBand() const
    8750             : {
    8751             :     // The GeoTIFF driver, among others, override this method to
    8752             :     // also handle external .msk bands.
    8753         439 :     return const_cast<GDALRasterBand *>(this)->GetColorInterpretation() ==
    8754         439 :            GCI_AlphaBand;
    8755             : }
    8756             : 
    8757             : /************************************************************************/
    8758             : /*                            GDALIsMaskBand()                          */
    8759             : /************************************************************************/
    8760             : 
    8761             : /**
    8762             :  * \brief Returns whether a band is a mask band.
    8763             :  *
    8764             :  * Mask band must be understood in the broad term: it can be a per-dataset
    8765             :  * mask band, an alpha band, or an implicit mask band.
    8766             :  * Typically the return of GetMaskBand()->IsMaskBand() should be true.
    8767             :  *
    8768             :  * This function is the same as the C++ method GDALRasterBand::IsMaskBand()
    8769             :  *
    8770             :  * @return true if the band is a mask band.
    8771             :  *
    8772             :  * @see GDALRasterBand::IsMaskBand()
    8773             :  *
    8774             :  * @since GDAL 3.5.0
    8775             :  *
    8776             :  */
    8777             : 
    8778          37 : bool GDALIsMaskBand(GDALRasterBandH hBand)
    8779             : 
    8780             : {
    8781          37 :     VALIDATE_POINTER1(hBand, "GDALIsMaskBand", false);
    8782             : 
    8783          37 :     const GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    8784          37 :     return poBand->IsMaskBand();
    8785             : }
    8786             : 
    8787             : /************************************************************************/
    8788             : /*                         GetMaskValueRange()                          */
    8789             : /************************************************************************/
    8790             : 
    8791             : /**
    8792             :  * \brief Returns the range of values that a mask band can take.
    8793             :  *
    8794             :  * @return the range of values that a mask band can take.
    8795             :  *
    8796             :  * @since GDAL 3.5.0
    8797             :  *
    8798             :  */
    8799             : 
    8800           0 : GDALMaskValueRange GDALRasterBand::GetMaskValueRange() const
    8801             : {
    8802           0 :     return GMVR_UNKNOWN;
    8803             : }
    8804             : 
    8805             : /************************************************************************/
    8806             : /*                    GetIndexColorTranslationTo()                      */
    8807             : /************************************************************************/
    8808             : 
    8809             : /**
    8810             :  * \brief Compute translation table for color tables.
    8811             :  *
    8812             :  * When the raster band has a palette index, it may be useful to compute
    8813             :  * the "translation" of this palette to the palette of another band.
    8814             :  * The translation tries to do exact matching first, and then approximate
    8815             :  * matching if no exact matching is possible.
    8816             :  * This method returns a table such that table[i] = j where i is an index
    8817             :  * of the 'this' rasterband and j the corresponding index for the reference
    8818             :  * rasterband.
    8819             :  *
    8820             :  * This method is thought as internal to GDAL and is used for drivers
    8821             :  * like RPFTOC.
    8822             :  *
    8823             :  * The implementation only supports 1-byte palette rasterbands.
    8824             :  *
    8825             :  * @param poReferenceBand the raster band
    8826             :  * @param pTranslationTable an already allocated translation table (at least 256
    8827             :  * bytes), or NULL to let the method allocate it
    8828             :  * @param pApproximateMatching a pointer to a flag that is set if the matching
    8829             :  *                              is approximate. May be NULL.
    8830             :  *
    8831             :  * @return a translation table if the two bands are palette index and that they
    8832             :  * do not match or NULL in other cases. The table must be freed with CPLFree if
    8833             :  * NULL was passed for pTranslationTable.
    8834             :  */
    8835             : 
    8836             : unsigned char *
    8837           4 : GDALRasterBand::GetIndexColorTranslationTo(GDALRasterBand *poReferenceBand,
    8838             :                                            unsigned char *pTranslationTable,
    8839             :                                            int *pApproximateMatching)
    8840             : {
    8841           4 :     if (poReferenceBand == nullptr)
    8842           0 :         return nullptr;
    8843             : 
    8844             :     // cppcheck-suppress knownConditionTrueFalse
    8845           4 :     if (poReferenceBand->GetColorInterpretation() == GCI_PaletteIndex &&
    8846             :         // cppcheck-suppress knownConditionTrueFalse
    8847           4 :         GetColorInterpretation() == GCI_PaletteIndex &&
    8848          12 :         poReferenceBand->GetRasterDataType() == GDT_Byte &&
    8849           4 :         GetRasterDataType() == GDT_Byte)
    8850             :     {
    8851           4 :         const GDALColorTable *srcColorTable = GetColorTable();
    8852           4 :         GDALColorTable *destColorTable = poReferenceBand->GetColorTable();
    8853           4 :         if (srcColorTable != nullptr && destColorTable != nullptr)
    8854             :         {
    8855           4 :             const int nEntries = srcColorTable->GetColorEntryCount();
    8856           4 :             const int nRefEntries = destColorTable->GetColorEntryCount();
    8857             : 
    8858           4 :             int bHasNoDataValueSrc = FALSE;
    8859           4 :             double dfNoDataValueSrc = GetNoDataValue(&bHasNoDataValueSrc);
    8860           4 :             if (!(bHasNoDataValueSrc && dfNoDataValueSrc >= 0 &&
    8861           4 :                   dfNoDataValueSrc <= 255 &&
    8862           4 :                   dfNoDataValueSrc == static_cast<int>(dfNoDataValueSrc)))
    8863           0 :                 bHasNoDataValueSrc = FALSE;
    8864           4 :             const int noDataValueSrc =
    8865           4 :                 bHasNoDataValueSrc ? static_cast<int>(dfNoDataValueSrc) : 0;
    8866             : 
    8867           4 :             int bHasNoDataValueRef = FALSE;
    8868             :             const double dfNoDataValueRef =
    8869           4 :                 poReferenceBand->GetNoDataValue(&bHasNoDataValueRef);
    8870           4 :             if (!(bHasNoDataValueRef && dfNoDataValueRef >= 0 &&
    8871           3 :                   dfNoDataValueRef <= 255 &&
    8872           3 :                   dfNoDataValueRef == static_cast<int>(dfNoDataValueRef)))
    8873           1 :                 bHasNoDataValueRef = FALSE;
    8874           4 :             const int noDataValueRef =
    8875           4 :                 bHasNoDataValueRef ? static_cast<int>(dfNoDataValueRef) : 0;
    8876             : 
    8877           4 :             bool samePalette = false;
    8878             : 
    8879           4 :             if (pApproximateMatching)
    8880           3 :                 *pApproximateMatching = FALSE;
    8881             : 
    8882           4 :             if (nEntries == nRefEntries &&
    8883           3 :                 bHasNoDataValueSrc == bHasNoDataValueRef &&
    8884           3 :                 (bHasNoDataValueSrc == FALSE ||
    8885             :                  noDataValueSrc == noDataValueRef))
    8886             :             {
    8887           3 :                 samePalette = true;
    8888         654 :                 for (int i = 0; i < nEntries; ++i)
    8889             :                 {
    8890         651 :                     if (noDataValueSrc == i)
    8891           3 :                         continue;
    8892             :                     const GDALColorEntry *entry =
    8893         648 :                         srcColorTable->GetColorEntry(i);
    8894             :                     const GDALColorEntry *entryRef =
    8895         648 :                         destColorTable->GetColorEntry(i);
    8896         648 :                     if (entry->c1 != entryRef->c1 ||
    8897         648 :                         entry->c2 != entryRef->c2 || entry->c3 != entryRef->c3)
    8898             :                     {
    8899           0 :                         samePalette = false;
    8900             :                     }
    8901             :                 }
    8902             :             }
    8903             : 
    8904           4 :             if (!samePalette)
    8905             :             {
    8906           1 :                 if (pTranslationTable == nullptr)
    8907             :                 {
    8908             :                     pTranslationTable = static_cast<unsigned char *>(
    8909           1 :                         VSI_CALLOC_VERBOSE(1, std::max(256, nEntries)));
    8910           1 :                     if (pTranslationTable == nullptr)
    8911           1 :                         return nullptr;
    8912             :                 }
    8913             : 
    8914             :                 // Trying to remap the product palette on the subdataset
    8915             :                 // palette.
    8916           5 :                 for (int i = 0; i < nEntries; ++i)
    8917             :                 {
    8918           4 :                     if (bHasNoDataValueSrc && bHasNoDataValueRef &&
    8919             :                         noDataValueSrc == i)
    8920           0 :                         continue;
    8921             :                     const GDALColorEntry *entry =
    8922           4 :                         srcColorTable->GetColorEntry(i);
    8923           4 :                     bool bMatchFound = false;
    8924          13 :                     for (int j = 0; j < nRefEntries; ++j)
    8925             :                     {
    8926          10 :                         if (bHasNoDataValueRef && noDataValueRef == j)
    8927           0 :                             continue;
    8928             :                         const GDALColorEntry *entryRef =
    8929          10 :                             destColorTable->GetColorEntry(j);
    8930          10 :                         if (entry->c1 == entryRef->c1 &&
    8931           2 :                             entry->c2 == entryRef->c2 &&
    8932           2 :                             entry->c3 == entryRef->c3)
    8933             :                         {
    8934           1 :                             pTranslationTable[i] =
    8935             :                                 static_cast<unsigned char>(j);
    8936           1 :                             bMatchFound = true;
    8937           1 :                             break;
    8938             :                         }
    8939             :                     }
    8940           4 :                     if (!bMatchFound)
    8941             :                     {
    8942             :                         // No exact match. Looking for closest color now.
    8943           3 :                         int best_j = 0;
    8944           3 :                         int best_distance = 0;
    8945           3 :                         if (pApproximateMatching)
    8946           0 :                             *pApproximateMatching = TRUE;
    8947          12 :                         for (int j = 0; j < nRefEntries; ++j)
    8948             :                         {
    8949             :                             const GDALColorEntry *entryRef =
    8950           9 :                                 destColorTable->GetColorEntry(j);
    8951           9 :                             int distance = (entry->c1 - entryRef->c1) *
    8952           9 :                                                (entry->c1 - entryRef->c1) +
    8953           9 :                                            (entry->c2 - entryRef->c2) *
    8954           9 :                                                (entry->c2 - entryRef->c2) +
    8955           9 :                                            (entry->c3 - entryRef->c3) *
    8956           9 :                                                (entry->c3 - entryRef->c3);
    8957           9 :                             if (j == 0 || distance < best_distance)
    8958             :                             {
    8959           7 :                                 best_j = j;
    8960           7 :                                 best_distance = distance;
    8961             :                             }
    8962             :                         }
    8963           3 :                         pTranslationTable[i] =
    8964             :                             static_cast<unsigned char>(best_j);
    8965             :                     }
    8966             :                 }
    8967           1 :                 if (bHasNoDataValueRef && bHasNoDataValueSrc)
    8968           0 :                     pTranslationTable[noDataValueSrc] =
    8969             :                         static_cast<unsigned char>(noDataValueRef);
    8970             : 
    8971           1 :                 return pTranslationTable;
    8972             :             }
    8973             :         }
    8974             :     }
    8975           3 :     return nullptr;
    8976             : }
    8977             : 
    8978             : /************************************************************************/
    8979             : /*                         SetFlushBlockErr()                           */
    8980             : /************************************************************************/
    8981             : 
    8982             : /**
    8983             :  * \brief Store that an error occurred while writing a dirty block.
    8984             :  *
    8985             :  * This function stores the fact that an error occurred while writing a dirty
    8986             :  * block from GDALRasterBlock::FlushCacheBlock(). Indeed when dirty blocks are
    8987             :  * flushed when the block cache get full, it is not convenient/possible to
    8988             :  * report that a dirty block could not be written correctly. This function
    8989             :  * remembers the error and re-issue it from GDALRasterBand::FlushCache(),
    8990             :  * GDALRasterBand::WriteBlock() and GDALRasterBand::RasterIO(), which are
    8991             :  * places where the user can easily match the error with the relevant dataset.
    8992             :  */
    8993             : 
    8994           0 : void GDALRasterBand::SetFlushBlockErr(CPLErr eErr)
    8995             : {
    8996           0 :     eFlushBlockErr = eErr;
    8997           0 : }
    8998             : 
    8999             : /************************************************************************/
    9000             : /*                         IncDirtyBlocks()                             */
    9001             : /************************************************************************/
    9002             : 
    9003             : /**
    9004             :  * \brief Increment/decrement the number of dirty blocks
    9005             :  */
    9006             : 
    9007      800501 : void GDALRasterBand::IncDirtyBlocks(int nInc)
    9008             : {
    9009      800501 :     if (poBandBlockCache)
    9010      800500 :         poBandBlockCache->IncDirtyBlocks(nInc);
    9011      800503 : }
    9012             : 
    9013             : /************************************************************************/
    9014             : /*                            ReportError()                             */
    9015             : /************************************************************************/
    9016             : 
    9017             : #ifndef DOXYGEN_XML
    9018             : /**
    9019             :  * \brief Emits an error related to a raster band.
    9020             :  *
    9021             :  * This function is a wrapper for regular CPLError(). The only difference
    9022             :  * with CPLError() is that it prepends the error message with the dataset
    9023             :  * name and the band number.
    9024             :  *
    9025             :  * @param eErrClass one of CE_Warning, CE_Failure or CE_Fatal.
    9026             :  * @param err_no the error number (CPLE_*) from cpl_error.h.
    9027             :  * @param fmt a printf() style format string.  Any additional arguments
    9028             :  * will be treated as arguments to fill in this format in a manner
    9029             :  * similar to printf().
    9030             :  *
    9031             :  * @since GDAL 1.9.0
    9032             :  */
    9033             : 
    9034        2469 : void GDALRasterBand::ReportError(CPLErr eErrClass, CPLErrorNum err_no,
    9035             :                                  const char *fmt, ...) const
    9036             : {
    9037             :     va_list args;
    9038             : 
    9039        2469 :     va_start(args, fmt);
    9040             : 
    9041        2469 :     const char *pszDSName = poDS ? poDS->GetDescription() : "";
    9042        2469 :     pszDSName = CPLGetFilename(pszDSName);
    9043        2469 :     if (pszDSName[0] != '\0')
    9044             :     {
    9045        2402 :         CPLError(eErrClass, err_no, "%s",
    9046        4804 :                  CPLString()
    9047        2402 :                      .Printf("%s, band %d: ", pszDSName, GetBand())
    9048        4804 :                      .append(CPLString().vPrintf(fmt, args))
    9049             :                      .c_str());
    9050             :     }
    9051             :     else
    9052             :     {
    9053          67 :         CPLErrorV(eErrClass, err_no, fmt, args);
    9054             :     }
    9055             : 
    9056        2469 :     va_end(args);
    9057        2469 : }
    9058             : #endif
    9059             : 
    9060             : /************************************************************************/
    9061             : /*                           GetVirtualMemAuto()                        */
    9062             : /************************************************************************/
    9063             : 
    9064             : /** \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9065             :  *
    9066             :  * Only supported on Linux and Unix systems with mmap() for now.
    9067             :  *
    9068             :  * This method allows creating a virtual memory object for a GDALRasterBand,
    9069             :  * that exposes the whole image data as a virtual array.
    9070             :  *
    9071             :  * The default implementation relies on GDALRasterBandGetVirtualMem(), but
    9072             :  * specialized implementation, such as for raw files, may also directly use
    9073             :  * mechanisms of the operating system to create a view of the underlying file
    9074             :  * into virtual memory ( CPLVirtualMemFileMapNew() )
    9075             :  *
    9076             :  * At the time of writing, the GeoTIFF driver and "raw" drivers (EHdr, ...)
    9077             :  * offer a specialized implementation with direct file mapping, provided that
    9078             :  * some requirements are met :
    9079             :  *   - for all drivers, the dataset must be backed by a "real" file in the file
    9080             :  *     system, and the byte ordering of multi-byte datatypes (Int16, etc.)
    9081             :  *     must match the native ordering of the CPU.
    9082             :  *   - in addition, for the GeoTIFF driver, the GeoTIFF file must be
    9083             :  * uncompressed, scanline oriented (i.e. not tiled). Strips must be organized in
    9084             :  * the file in sequential order, and be equally spaced (which is generally the
    9085             :  * case). Only power-of-two bit depths are supported (8 for GDT_Bye, 16 for
    9086             :  * GDT_Int16/GDT_UInt16/GDT_Float16, 32 for GDT_Float32 and 64 for GDT_Float64)
    9087             :  *
    9088             :  * The pointer returned remains valid until CPLVirtualMemFree() is called.
    9089             :  * CPLVirtualMemFree() must be called before the raster band object is
    9090             :  * destroyed.
    9091             :  *
    9092             :  * If p is such a pointer and base_type the type matching
    9093             :  * GDALGetRasterDataType(), the element of image coordinates (x, y) can be
    9094             :  * accessed with
    9095             :  * *(base_type*) ((GByte*)p + x * *pnPixelSpace + y * *pnLineSpace)
    9096             :  *
    9097             :  * This method is the same as the C GDALGetVirtualMemAuto() function.
    9098             :  *
    9099             :  * @param eRWFlag Either GF_Read to read the band, or GF_Write to
    9100             :  * read/write the band.
    9101             :  *
    9102             :  * @param pnPixelSpace Output parameter giving the byte offset from the start of
    9103             :  * one pixel value in the buffer to the start of the next pixel value within a
    9104             :  * scanline.
    9105             :  *
    9106             :  * @param pnLineSpace Output parameter giving the byte offset from the start of
    9107             :  * one scanline in the buffer to the start of the next.
    9108             :  *
    9109             :  * @param papszOptions NULL terminated list of options.
    9110             :  *                     If a specialized implementation exists, defining
    9111             :  * USE_DEFAULT_IMPLEMENTATION=YES will cause the default implementation to be
    9112             :  * used. On the contrary, starting with GDAL 2.2, defining
    9113             :  * USE_DEFAULT_IMPLEMENTATION=NO will prevent the default implementation from
    9114             :  * being used (thus only allowing efficient implementations to be used). When
    9115             :  * requiring or falling back to the default implementation, the following
    9116             :  *                     options are available : CACHE_SIZE (in bytes, defaults to
    9117             :  * 40 MB), PAGE_SIZE_HINT (in bytes), SINGLE_THREAD ("FALSE" / "TRUE", defaults
    9118             :  * to FALSE)
    9119             :  *
    9120             :  * @return a virtual memory object that must be unreferenced by
    9121             :  * CPLVirtualMemFree(), or NULL in case of failure.
    9122             :  *
    9123             :  * @since GDAL 1.11
    9124             :  */
    9125             : 
    9126           9 : CPLVirtualMem *GDALRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
    9127             :                                                  int *pnPixelSpace,
    9128             :                                                  GIntBig *pnLineSpace,
    9129             :                                                  char **papszOptions)
    9130             : {
    9131           9 :     const char *pszImpl = CSLFetchNameValueDef(
    9132             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
    9133           9 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
    9134           8 :         EQUAL(pszImpl, "FALSE"))
    9135             :     {
    9136           1 :         return nullptr;
    9137             :     }
    9138             : 
    9139           8 :     const int nPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
    9140           8 :     const GIntBig nLineSpace = static_cast<GIntBig>(nRasterXSize) * nPixelSpace;
    9141           8 :     if (pnPixelSpace)
    9142           8 :         *pnPixelSpace = nPixelSpace;
    9143           8 :     if (pnLineSpace)
    9144           8 :         *pnLineSpace = nLineSpace;
    9145             :     const size_t nCacheSize =
    9146           8 :         atoi(CSLFetchNameValueDef(papszOptions, "CACHE_SIZE", "40000000"));
    9147             :     const size_t nPageSizeHint =
    9148           8 :         atoi(CSLFetchNameValueDef(papszOptions, "PAGE_SIZE_HINT", "0"));
    9149           8 :     const bool bSingleThreadUsage = CPLTestBool(
    9150             :         CSLFetchNameValueDef(papszOptions, "SINGLE_THREAD", "FALSE"));
    9151           8 :     return GDALRasterBandGetVirtualMem(
    9152             :         GDALRasterBand::ToHandle(this), eRWFlag, 0, 0, nRasterXSize,
    9153             :         nRasterYSize, nRasterXSize, nRasterYSize, eDataType, nPixelSpace,
    9154             :         nLineSpace, nCacheSize, nPageSizeHint, bSingleThreadUsage,
    9155           8 :         papszOptions);
    9156             : }
    9157             : 
    9158             : /************************************************************************/
    9159             : /*                         GDALGetVirtualMemAuto()                      */
    9160             : /************************************************************************/
    9161             : 
    9162             : /**
    9163             :  * \brief Create a CPLVirtualMem object from a GDAL raster band object.
    9164             :  *
    9165             :  * @see GDALRasterBand::GetVirtualMemAuto()
    9166             :  */
    9167             : 
    9168          31 : CPLVirtualMem *GDALGetVirtualMemAuto(GDALRasterBandH hBand, GDALRWFlag eRWFlag,
    9169             :                                      int *pnPixelSpace, GIntBig *pnLineSpace,
    9170             :                                      CSLConstList papszOptions)
    9171             : {
    9172          31 :     VALIDATE_POINTER1(hBand, "GDALGetVirtualMemAuto", nullptr);
    9173             : 
    9174          31 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9175             : 
    9176          31 :     return poBand->GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
    9177          31 :                                      const_cast<char **>(papszOptions));
    9178             : }
    9179             : 
    9180             : /************************************************************************/
    9181             : /*                        GDALGetDataCoverageStatus()                   */
    9182             : /************************************************************************/
    9183             : 
    9184             : /**
    9185             :  * \brief Get the coverage status of a sub-window of the raster.
    9186             :  *
    9187             :  * Returns whether a sub-window of the raster contains only data, only empty
    9188             :  * blocks or a mix of both. This function can be used to determine quickly
    9189             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9190             :  * be sparse.
    9191             :  *
    9192             :  * Empty blocks are blocks that are generally not physically present in the
    9193             :  * file, and when read through GDAL, contain only pixels whose value is the
    9194             :  * nodata value when it is set, or whose value is 0 when the nodata value is
    9195             :  * not set.
    9196             :  *
    9197             :  * The query is done in an efficient way without reading the actual pixel
    9198             :  * values. If not possible, or not implemented at all by the driver,
    9199             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9200             :  * be returned.
    9201             :  *
    9202             :  * The values that can be returned by the function are the following,
    9203             :  * potentially combined with the binary or operator :
    9204             :  * <ul>
    9205             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9206             :  * GetDataCoverageStatus(). This flag should be returned together with
    9207             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9208             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9209             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9210             :  * the queried window. This is typically identified by the concept of missing
    9211             :  * block in formats that supports it.
    9212             :  * </li>
    9213             :  * </ul>
    9214             :  *
    9215             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9216             :  * should be interpreted more as hint of potential presence of data. For example
    9217             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9218             :  * nodata value), instead of using the missing block mechanism,
    9219             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9220             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9221             :  *
    9222             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9223             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9224             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9225             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9226             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9227             :  * the function will exit, so that you can potentially refine the requested area
    9228             :  * to find which particular region(s) have missing blocks.
    9229             :  *
    9230             :  * @see GDALRasterBand::GetDataCoverageStatus()
    9231             :  *
    9232             :  * @param hBand raster band
    9233             :  *
    9234             :  * @param nXOff The pixel offset to the top left corner of the region
    9235             :  * of the band to be queried. This would be zero to start from the left side.
    9236             :  *
    9237             :  * @param nYOff The line offset to the top left corner of the region
    9238             :  * of the band to be queried. This would be zero to start from the top.
    9239             :  *
    9240             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9241             :  *
    9242             :  * @param nYSize The height of the region of the band to be queried in lines.
    9243             :  *
    9244             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9245             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9246             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9247             :  * as the computation of the coverage matches the mask, the computation will be
    9248             :  * stopped. *pdfDataPct will not be valid in that case.
    9249             :  *
    9250             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9251             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9252             :  * sub-window that have valid values. The implementation might not always be
    9253             :  * able to compute it, in which case it will be set to a negative value.
    9254             :  *
    9255             :  * @return a binary-or'ed combination of possible values
    9256             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9257             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9258             :  *
    9259             :  * @note Added in GDAL 2.2
    9260             :  */
    9261             : 
    9262          26 : int CPL_STDCALL GDALGetDataCoverageStatus(GDALRasterBandH hBand, int nXOff,
    9263             :                                           int nYOff, int nXSize, int nYSize,
    9264             :                                           int nMaskFlagStop, double *pdfDataPct)
    9265             : {
    9266          26 :     VALIDATE_POINTER1(hBand, "GDALGetDataCoverageStatus",
    9267             :                       GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED);
    9268             : 
    9269          26 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
    9270             : 
    9271          26 :     return poBand->GetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize,
    9272          26 :                                          nMaskFlagStop, pdfDataPct);
    9273             : }
    9274             : 
    9275             : /************************************************************************/
    9276             : /*                          GetDataCoverageStatus()                     */
    9277             : /************************************************************************/
    9278             : 
    9279             : /**
    9280             :  * \fn GDALRasterBand::IGetDataCoverageStatus( int nXOff,
    9281             :  *                                           int nYOff,
    9282             :  *                                           int nXSize,
    9283             :  *                                           int nYSize,
    9284             :  *                                           int nMaskFlagStop,
    9285             :  *                                           double* pdfDataPct)
    9286             :  * \brief Get the coverage status of a sub-window of the raster.
    9287             :  *
    9288             :  * Returns whether a sub-window of the raster contains only data, only empty
    9289             :  * blocks or a mix of both. This function can be used to determine quickly
    9290             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9291             :  * be sparse.
    9292             :  *
    9293             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9294             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9295             :  *
    9296             :  * The query is done in an efficient way without reading the actual pixel
    9297             :  * values. If not possible, or not implemented at all by the driver,
    9298             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9299             :  * be returned.
    9300             :  *
    9301             :  * The values that can be returned by the function are the following,
    9302             :  * potentially combined with the binary or operator :
    9303             :  * <ul>
    9304             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9305             :  * GetDataCoverageStatus(). This flag should be returned together with
    9306             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9307             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9308             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9309             :  * the queried window. This is typically identified by the concept of missing
    9310             :  * block in formats that supports it.
    9311             :  * </li>
    9312             :  * </ul>
    9313             :  *
    9314             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9315             :  * should be interpreted more as hint of potential presence of data. For example
    9316             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9317             :  * nodata value), instead of using the missing block mechanism,
    9318             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9319             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9320             :  *
    9321             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9322             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9323             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9324             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9325             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9326             :  * the function will exit, so that you can potentially refine the requested area
    9327             :  * to find which particular region(s) have missing blocks.
    9328             :  *
    9329             :  * @see GDALGetDataCoverageStatus()
    9330             :  *
    9331             :  * @param nXOff The pixel offset to the top left corner of the region
    9332             :  * of the band to be queried. This would be zero to start from the left side.
    9333             :  *
    9334             :  * @param nYOff The line offset to the top left corner of the region
    9335             :  * of the band to be queried. This would be zero to start from the top.
    9336             :  *
    9337             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9338             :  *
    9339             :  * @param nYSize The height of the region of the band to be queried in lines.
    9340             :  *
    9341             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9342             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9343             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9344             :  * as the computation of the coverage matches the mask, the computation will be
    9345             :  * stopped. *pdfDataPct will not be valid in that case.
    9346             :  *
    9347             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9348             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9349             :  * sub-window that have valid values. The implementation might not always be
    9350             :  * able to compute it, in which case it will be set to a negative value.
    9351             :  *
    9352             :  * @return a binary-or'ed combination of possible values
    9353             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9354             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9355             :  *
    9356             :  * @note Added in GDAL 2.2
    9357             :  */
    9358             : 
    9359             : /**
    9360             :  * \brief Get the coverage status of a sub-window of the raster.
    9361             :  *
    9362             :  * Returns whether a sub-window of the raster contains only data, only empty
    9363             :  * blocks or a mix of both. This function can be used to determine quickly
    9364             :  * if it is worth issuing RasterIO / ReadBlock requests in datasets that may
    9365             :  * be sparse.
    9366             :  *
    9367             :  * Empty blocks are blocks that contain only pixels whose value is the nodata
    9368             :  * value when it is set, or whose value is 0 when the nodata value is not set.
    9369             :  *
    9370             :  * The query is done in an efficient way without reading the actual pixel
    9371             :  * values. If not possible, or not implemented at all by the driver,
    9372             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED | GDAL_DATA_COVERAGE_STATUS_DATA will
    9373             :  * be returned.
    9374             :  *
    9375             :  * The values that can be returned by the function are the following,
    9376             :  * potentially combined with the binary or operator :
    9377             :  * <ul>
    9378             :  * <li>GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED : the driver does not implement
    9379             :  * GetDataCoverageStatus(). This flag should be returned together with
    9380             :  * GDAL_DATA_COVERAGE_STATUS_DATA.</li>
    9381             :  * <li>GDAL_DATA_COVERAGE_STATUS_DATA: There is (potentially) data in the
    9382             :  * queried window.</li> <li>GDAL_DATA_COVERAGE_STATUS_EMPTY: There is nodata in
    9383             :  * the queried window. This is typically identified by the concept of missing
    9384             :  * block in formats that supports it.
    9385             :  * </li>
    9386             :  * </ul>
    9387             :  *
    9388             :  * Note that GDAL_DATA_COVERAGE_STATUS_DATA might have false positives and
    9389             :  * should be interpreted more as hint of potential presence of data. For example
    9390             :  * if a GeoTIFF file is created with blocks filled with zeroes (or set to the
    9391             :  * nodata value), instead of using the missing block mechanism,
    9392             :  * GDAL_DATA_COVERAGE_STATUS_DATA will be returned. On the contrary,
    9393             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY should have no false positives.
    9394             :  *
    9395             :  * The nMaskFlagStop should be generally set to 0. It can be set to a
    9396             :  * binary-or'ed mask of the above mentioned values to enable a quick exiting of
    9397             :  * the function as soon as the computed mask matches the nMaskFlagStop. For
    9398             :  * example, you can issue a request on the whole raster with nMaskFlagStop =
    9399             :  * GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon as one missing block is encountered,
    9400             :  * the function will exit, so that you can potentially refine the requested area
    9401             :  * to find which particular region(s) have missing blocks.
    9402             :  *
    9403             :  * @see GDALGetDataCoverageStatus()
    9404             :  *
    9405             :  * @param nXOff The pixel offset to the top left corner of the region
    9406             :  * of the band to be queried. This would be zero to start from the left side.
    9407             :  *
    9408             :  * @param nYOff The line offset to the top left corner of the region
    9409             :  * of the band to be queried. This would be zero to start from the top.
    9410             :  *
    9411             :  * @param nXSize The width of the region of the band to be queried in pixels.
    9412             :  *
    9413             :  * @param nYSize The height of the region of the band to be queried in lines.
    9414             :  *
    9415             :  * @param nMaskFlagStop 0, or a binary-or'ed mask of possible values
    9416             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9417             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY. As soon
    9418             :  * as the computation of the coverage matches the mask, the computation will be
    9419             :  * stopped. *pdfDataPct will not be valid in that case.
    9420             :  *
    9421             :  * @param pdfDataPct Optional output parameter whose pointed value will be set
    9422             :  * to the (approximate) percentage in [0,100] of pixels in the queried
    9423             :  * sub-window that have valid values. The implementation might not always be
    9424             :  * able to compute it, in which case it will be set to a negative value.
    9425             :  *
    9426             :  * @return a binary-or'ed combination of possible values
    9427             :  * GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED,
    9428             :  * GDAL_DATA_COVERAGE_STATUS_DATA and GDAL_DATA_COVERAGE_STATUS_EMPTY
    9429             :  *
    9430             :  * @note Added in GDAL 2.2
    9431             :  */
    9432             : 
    9433        4620 : int GDALRasterBand::GetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
    9434             :                                           int nYSize, int nMaskFlagStop,
    9435             :                                           double *pdfDataPct)
    9436             : {
    9437        4620 :     if (nXOff < 0 || nYOff < 0 || nXSize > INT_MAX - nXOff ||
    9438        4620 :         nYSize > INT_MAX - nYOff || nXOff + nXSize > nRasterXSize ||
    9439        4620 :         nYOff + nYSize > nRasterYSize)
    9440             :     {
    9441           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Bad window");
    9442           0 :         if (pdfDataPct)
    9443           0 :             *pdfDataPct = 0.0;
    9444             :         return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9445           0 :                GDAL_DATA_COVERAGE_STATUS_EMPTY;
    9446             :     }
    9447        4620 :     return IGetDataCoverageStatus(nXOff, nYOff, nXSize, nYSize, nMaskFlagStop,
    9448        4620 :                                   pdfDataPct);
    9449             : }
    9450             : 
    9451             : /************************************************************************/
    9452             : /*                         IGetDataCoverageStatus()                     */
    9453             : /************************************************************************/
    9454             : 
    9455         684 : int GDALRasterBand::IGetDataCoverageStatus(int /*nXOff*/, int /*nYOff*/,
    9456             :                                            int /*nXSize*/, int /*nYSize*/,
    9457             :                                            int /*nMaskFlagStop*/,
    9458             :                                            double *pdfDataPct)
    9459             : {
    9460         684 :     if (pdfDataPct != nullptr)
    9461           0 :         *pdfDataPct = 100.0;
    9462             :     return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
    9463         684 :            GDAL_DATA_COVERAGE_STATUS_DATA;
    9464             : }
    9465             : 
    9466             : //! @cond Doxygen_Suppress
    9467             : /************************************************************************/
    9468             : /*                          EnterReadWrite()                            */
    9469             : /************************************************************************/
    9470             : 
    9471     7824010 : int GDALRasterBand::EnterReadWrite(GDALRWFlag eRWFlag)
    9472             : {
    9473     7824010 :     if (poDS != nullptr)
    9474     7060390 :         return poDS->EnterReadWrite(eRWFlag);
    9475      763627 :     return FALSE;
    9476             : }
    9477             : 
    9478             : /************************************************************************/
    9479             : /*                         LeaveReadWrite()                             */
    9480             : /************************************************************************/
    9481             : 
    9482     1127310 : void GDALRasterBand::LeaveReadWrite()
    9483             : {
    9484     1127310 :     if (poDS != nullptr)
    9485     1127020 :         poDS->LeaveReadWrite();
    9486     1127530 : }
    9487             : 
    9488             : /************************************************************************/
    9489             : /*                           InitRWLock()                               */
    9490             : /************************************************************************/
    9491             : 
    9492     3980140 : void GDALRasterBand::InitRWLock()
    9493             : {
    9494     3980140 :     if (poDS != nullptr)
    9495     3979730 :         poDS->InitRWLock();
    9496     3980140 : }
    9497             : 
    9498             : //! @endcond
    9499             : 
    9500             : // clang-format off
    9501             : 
    9502             : /**
    9503             :  * \fn GDALRasterBand::SetMetadata( char ** papszMetadata, const char * pszDomain)
    9504             :  * \brief Set metadata.
    9505             :  *
    9506             :  * CAUTION: depending on the format, older values of the updated information
    9507             :  * might still be found in the file in a "ghost" state, even if no longer
    9508             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9509             :  * format (this is not a exhaustive list)
    9510             :  *
    9511             :  * The C function GDALSetMetadata() does the same thing as this method.
    9512             :  *
    9513             :  * @param papszMetadata the metadata in name=value string list format to
    9514             :  * apply.
    9515             :  * @param pszDomain the domain of interest.  Use "" or NULL for the default
    9516             :  * domain.
    9517             :  * @return CE_None on success, CE_Failure on failure and CE_Warning if the
    9518             :  * metadata has been accepted, but is likely not maintained persistently
    9519             :  * by the underlying object between sessions.
    9520             :  */
    9521             : 
    9522             : /**
    9523             :  * \fn GDALRasterBand::SetMetadataItem( const char * pszName, const char * pszValue, const char * pszDomain)
    9524             :  * \brief Set single metadata item.
    9525             :  *
    9526             :  * CAUTION: depending on the format, older values of the updated information
    9527             :  * might still be found in the file in a "ghost" state, even if no longer
    9528             :  * accessible through the GDAL API. This is for example the case of the GTiff
    9529             :  * format (this is not a exhaustive list)
    9530             :  *
    9531             :  * The C function GDALSetMetadataItem() does the same thing as this method.
    9532             :  *
    9533             :  * @param pszName the key for the metadata item to fetch.
    9534             :  * @param pszValue the value to assign to the key.
    9535             :  * @param pszDomain the domain to set within, use NULL for the default domain.
    9536             :  *
    9537             :  * @return CE_None on success, or an error code on failure.
    9538             :  */
    9539             : 
    9540             : // clang-format on
    9541             : 
    9542             : //! @cond Doxygen_Suppress
    9543             : /************************************************************************/
    9544             : /*                    EnablePixelTypeSignedByteWarning()                */
    9545             : /************************************************************************/
    9546             : 
    9547      156224 : void GDALRasterBand::EnablePixelTypeSignedByteWarning(bool b)
    9548             : {
    9549      156224 :     m_bEnablePixelTypeSignedByteWarning = b;
    9550      156224 : }
    9551             : 
    9552        4884 : void GDALEnablePixelTypeSignedByteWarning(GDALRasterBandH hBand, bool b)
    9553             : {
    9554        4884 :     GDALRasterBand::FromHandle(hBand)->EnablePixelTypeSignedByteWarning(b);
    9555        4884 : }
    9556             : 
    9557             : //! @endcond
    9558             : 
    9559             : /************************************************************************/
    9560             : /*                           GetMetadataItem()                          */
    9561             : /************************************************************************/
    9562             : 
    9563      619271 : const char *GDALRasterBand::GetMetadataItem(const char *pszName,
    9564             :                                             const char *pszDomain)
    9565             : {
    9566             :     // TODO (GDAL 4.0?): remove this when GDAL 3.7 has been widely adopted.
    9567      619271 :     if (m_bEnablePixelTypeSignedByteWarning && eDataType == GDT_Byte &&
    9568      461729 :         pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE") &&
    9569      321396 :         EQUAL(pszName, "PIXELTYPE"))
    9570             :     {
    9571           2 :         CPLError(CE_Warning, CPLE_AppDefined,
    9572             :                  "Starting with GDAL 3.7, PIXELTYPE=SIGNEDBYTE is no longer "
    9573             :                  "used to signal signed 8-bit raster. Change your code to "
    9574             :                  "test for the new GDT_Int8 data type instead.");
    9575             :     }
    9576      619271 :     return GDALMajorObject::GetMetadataItem(pszName, pszDomain);
    9577             : }
    9578             : 
    9579             : /************************************************************************/
    9580             : /*                            WindowIterator                            */
    9581             : /************************************************************************/
    9582             : 
    9583             : //! @cond Doxygen_Suppress
    9584             : 
    9585           2 : GDALRasterBand::WindowIterator::WindowIterator(int nRasterXSize,
    9586             :                                                int nRasterYSize,
    9587             :                                                int nBlockXSize, int nBlockYSize,
    9588           2 :                                                int nRow, int nCol)
    9589             :     : m_nRasterXSize(nRasterXSize), m_nRasterYSize(nRasterYSize),
    9590             :       m_nBlockXSize(nBlockXSize), m_nBlockYSize(nBlockYSize), m_row(nRow),
    9591           2 :       m_col(nCol)
    9592             : {
    9593           2 : }
    9594             : 
    9595          10 : bool GDALRasterBand::WindowIterator::operator==(
    9596             :     const WindowIterator &other) const
    9597             : {
    9598           1 :     return m_row == other.m_row && m_col == other.m_col &&
    9599           1 :            m_nRasterXSize == other.m_nRasterXSize &&
    9600           1 :            m_nRasterYSize == other.m_nRasterYSize &&
    9601          12 :            m_nBlockXSize == other.m_nBlockXSize &&
    9602          11 :            m_nBlockYSize == other.m_nBlockYSize;
    9603             : }
    9604             : 
    9605          10 : bool GDALRasterBand::WindowIterator::operator!=(
    9606             :     const WindowIterator &other) const
    9607             : {
    9608          10 :     return !(*this == other);
    9609             : }
    9610             : 
    9611             : GDALRasterBand::WindowIterator::value_type
    9612           9 : GDALRasterBand::WindowIterator::operator*() const
    9613             : {
    9614             :     GDALRasterWindow ret;
    9615           9 :     ret.nXOff = m_col * m_nBlockXSize;
    9616           9 :     ret.nYOff = m_row * m_nBlockYSize;
    9617           9 :     ret.nXSize = std::min(m_nBlockXSize, m_nRasterXSize - ret.nXOff);
    9618           9 :     ret.nYSize = std::min(m_nBlockYSize, m_nRasterYSize - ret.nYOff);
    9619             : 
    9620           9 :     return ret;
    9621             : }
    9622             : 
    9623           9 : GDALRasterBand::WindowIterator &GDALRasterBand::WindowIterator::operator++()
    9624             : {
    9625           9 :     m_col++;
    9626           9 :     if (m_col >= DIV_ROUND_UP(m_nRasterXSize, m_nBlockXSize))
    9627             :     {
    9628           3 :         m_col = 0;
    9629           3 :         m_row++;
    9630             :     }
    9631           9 :     return *this;
    9632             : }
    9633             : 
    9634           2 : GDALRasterBand::WindowIteratorWrapper::WindowIteratorWrapper(
    9635           2 :     const GDALRasterBand &band)
    9636           2 :     : m_nRasterXSize(band.GetXSize()), m_nRasterYSize(band.GetYSize()),
    9637           2 :       m_nBlockXSize(-1), m_nBlockYSize(-1)
    9638             : {
    9639           2 :     band.GetBlockSize(&m_nBlockXSize, &m_nBlockYSize);
    9640           2 : }
    9641             : 
    9642             : GDALRasterBand::WindowIterator
    9643           1 : GDALRasterBand::WindowIteratorWrapper::begin() const
    9644             : {
    9645           1 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
    9646           1 :                           m_nBlockYSize, 0, 0);
    9647             : }
    9648             : 
    9649             : GDALRasterBand::WindowIterator
    9650           1 : GDALRasterBand::WindowIteratorWrapper::end() const
    9651             : {
    9652           1 :     return WindowIterator(m_nRasterXSize, m_nRasterYSize, m_nBlockXSize,
    9653           1 :                           m_nBlockYSize,
    9654           1 :                           DIV_ROUND_UP(m_nRasterYSize, m_nBlockYSize), 0);
    9655             : }
    9656             : 
    9657             : //! @endcond
    9658             : 
    9659             : /** Return an object whose begin() and end() methods can be used to iterate
    9660             :  *  over a GDALRasterWindow for each block in this raster band. The iteration
    9661             :  *  order is from left to right, then from top to bottom.
    9662             :  *
    9663             : \code{.cpp}
    9664             :     std::vector<double> pixelValues;
    9665             :     for (const auto& window : poBand->IterateWindows()) {
    9666             :         CPLErr eErr = poBand->ReadRaster(pixelValues, window.nXOff, window.nYOff,
    9667             :                                          window.nXSize, window.nYSize);
    9668             :         // check eErr
    9669             :     }
    9670             : \endcode
    9671             :  *
    9672             :  *
    9673             :  *  @since GDAL 3.12
    9674             :  */
    9675           2 : GDALRasterBand::WindowIteratorWrapper GDALRasterBand::IterateWindows() const
    9676             : {
    9677           2 :     return WindowIteratorWrapper(*this);
    9678             : }
    9679             : 
    9680             : /************************************************************************/
    9681             : /*                     GDALMDArrayFromRasterBand                        */
    9682             : /************************************************************************/
    9683             : 
    9684             : class GDALMDArrayFromRasterBand final : public GDALMDArray
    9685             : {
    9686             :     CPL_DISALLOW_COPY_ASSIGN(GDALMDArrayFromRasterBand)
    9687             : 
    9688             :     GDALDataset *m_poDS;
    9689             :     GDALRasterBand *m_poBand;
    9690             :     GDALExtendedDataType m_dt;
    9691             :     std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9692             :     std::string m_osUnit;
    9693             :     std::vector<GByte> m_pabyNoData{};
    9694             :     std::shared_ptr<GDALMDArray> m_varX{};
    9695             :     std::shared_ptr<GDALMDArray> m_varY{};
    9696             :     std::string m_osFilename{};
    9697             : 
    9698             :     bool ReadWrite(GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx,
    9699             :                    const size_t *count, const GInt64 *arrayStep,
    9700             :                    const GPtrDiff_t *bufferStride,
    9701             :                    const GDALExtendedDataType &bufferDataType,
    9702             :                    void *pBuffer) const;
    9703             : 
    9704             :   protected:
    9705          23 :     GDALMDArrayFromRasterBand(GDALDataset *poDS, GDALRasterBand *poBand)
    9706          46 :         : GDALAbstractMDArray(std::string(),
    9707          46 :                               std::string(poDS->GetDescription()) +
    9708             :                                   CPLSPrintf(" band %d", poBand->GetBand())),
    9709          46 :           GDALMDArray(std::string(),
    9710          46 :                       std::string(poDS->GetDescription()) +
    9711             :                           CPLSPrintf(" band %d", poBand->GetBand())),
    9712             :           m_poDS(poDS), m_poBand(poBand),
    9713             :           m_dt(GDALExtendedDataType::Create(poBand->GetRasterDataType())),
    9714         115 :           m_osUnit(poBand->GetUnitType()), m_osFilename(poDS->GetDescription())
    9715             :     {
    9716          23 :         m_poDS->Reference();
    9717             : 
    9718          23 :         int bHasNoData = false;
    9719          23 :         if (m_poBand->GetRasterDataType() == GDT_Int64)
    9720             :         {
    9721           0 :             const auto nNoData = m_poBand->GetNoDataValueAsInt64(&bHasNoData);
    9722           0 :             if (bHasNoData)
    9723             :             {
    9724           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9725           0 :                 GDALCopyWords64(&nNoData, GDT_Int64, 0, &m_pabyNoData[0],
    9726             :                                 m_dt.GetNumericDataType(), 0, 1);
    9727             :             }
    9728             :         }
    9729          23 :         else if (m_poBand->GetRasterDataType() == GDT_UInt64)
    9730             :         {
    9731           0 :             const auto nNoData = m_poBand->GetNoDataValueAsUInt64(&bHasNoData);
    9732           0 :             if (bHasNoData)
    9733             :             {
    9734           0 :                 m_pabyNoData.resize(m_dt.GetSize());
    9735           0 :                 GDALCopyWords64(&nNoData, GDT_UInt64, 0, &m_pabyNoData[0],
    9736             :                                 m_dt.GetNumericDataType(), 0, 1);
    9737             :             }
    9738             :         }
    9739             :         else
    9740             :         {
    9741          23 :             const auto dfNoData = m_poBand->GetNoDataValue(&bHasNoData);
    9742          23 :             if (bHasNoData)
    9743             :             {
    9744           1 :                 m_pabyNoData.resize(m_dt.GetSize());
    9745           1 :                 GDALCopyWords64(&dfNoData, GDT_Float64, 0, &m_pabyNoData[0],
    9746             :                                 m_dt.GetNumericDataType(), 0, 1);
    9747             :             }
    9748             :         }
    9749             : 
    9750          23 :         const int nXSize = poBand->GetXSize();
    9751          23 :         const int nYSize = poBand->GetYSize();
    9752             : 
    9753          23 :         auto poSRS = m_poDS->GetSpatialRef();
    9754          46 :         std::string osTypeY;
    9755          46 :         std::string osTypeX;
    9756          46 :         std::string osDirectionY;
    9757          46 :         std::string osDirectionX;
    9758          23 :         if (poSRS && poSRS->GetAxesCount() == 2)
    9759             :         {
    9760          21 :             const auto &mapping = poSRS->GetDataAxisToSRSAxisMapping();
    9761          21 :             OGRAxisOrientation eOrientation1 = OAO_Other;
    9762          21 :             poSRS->GetAxis(nullptr, 0, &eOrientation1);
    9763          21 :             OGRAxisOrientation eOrientation2 = OAO_Other;
    9764          21 :             poSRS->GetAxis(nullptr, 1, &eOrientation2);
    9765          21 :             if (eOrientation1 == OAO_East && eOrientation2 == OAO_North)
    9766             :             {
    9767           5 :                 if (mapping == std::vector<int>{1, 2})
    9768             :                 {
    9769           5 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9770           5 :                     osDirectionY = "NORTH";
    9771           5 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9772           5 :                     osDirectionX = "EAST";
    9773             :                 }
    9774             :             }
    9775          16 :             else if (eOrientation1 == OAO_North && eOrientation2 == OAO_East)
    9776             :             {
    9777          16 :                 if (mapping == std::vector<int>{2, 1})
    9778             :                 {
    9779          16 :                     osTypeY = GDAL_DIM_TYPE_HORIZONTAL_Y;
    9780          16 :                     osDirectionY = "NORTH";
    9781          16 :                     osTypeX = GDAL_DIM_TYPE_HORIZONTAL_X;
    9782          16 :                     osDirectionX = "EAST";
    9783             :                 }
    9784             :             }
    9785             :         }
    9786             : 
    9787         115 :         m_dims = {std::make_shared<GDALDimensionWeakIndexingVar>(
    9788             :                       "/", "Y", osTypeY, osDirectionY, nYSize),
    9789          46 :                   std::make_shared<GDALDimensionWeakIndexingVar>(
    9790          69 :                       "/", "X", osTypeX, osDirectionX, nXSize)};
    9791             : 
    9792          23 :         GDALGeoTransform gt;
    9793          23 :         if (m_poDS->GetGeoTransform(gt) == CE_None && gt[2] == 0 && gt[4] == 0)
    9794             :         {
    9795          44 :             m_varX = GDALMDArrayRegularlySpaced::Create("/", "X", m_dims[1],
    9796          44 :                                                         gt[0], gt[1], 0.5);
    9797          22 :             m_dims[1]->SetIndexingVariable(m_varX);
    9798             : 
    9799          44 :             m_varY = GDALMDArrayRegularlySpaced::Create("/", "Y", m_dims[0],
    9800          44 :                                                         gt[3], gt[5], 0.5);
    9801          22 :             m_dims[0]->SetIndexingVariable(m_varY);
    9802             :         }
    9803          23 :     }
    9804             : 
    9805             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    9806             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9807             :                const GDALExtendedDataType &bufferDataType,
    9808             :                void *pDstBuffer) const override;
    9809             : 
    9810           1 :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    9811             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9812             :                 const GDALExtendedDataType &bufferDataType,
    9813             :                 const void *pSrcBuffer) override
    9814             :     {
    9815           1 :         return ReadWrite(GF_Write, arrayStartIdx, count, arrayStep,
    9816             :                          bufferStride, bufferDataType,
    9817           1 :                          const_cast<void *>(pSrcBuffer));
    9818             :     }
    9819             : 
    9820             :   public:
    9821          46 :     ~GDALMDArrayFromRasterBand()
    9822          23 :     {
    9823          23 :         m_poDS->ReleaseRef();
    9824          46 :     }
    9825             : 
    9826          23 :     static std::shared_ptr<GDALMDArray> Create(GDALDataset *poDS,
    9827             :                                                GDALRasterBand *poBand)
    9828             :     {
    9829             :         auto array(std::shared_ptr<GDALMDArrayFromRasterBand>(
    9830          46 :             new GDALMDArrayFromRasterBand(poDS, poBand)));
    9831          23 :         array->SetSelf(array);
    9832          46 :         return array;
    9833             :     }
    9834             : 
    9835           2 :     bool IsWritable() const override
    9836             :     {
    9837           2 :         return m_poDS->GetAccess() == GA_Update;
    9838             :     }
    9839             : 
    9840          97 :     const std::string &GetFilename() const override
    9841             :     {
    9842          97 :         return m_osFilename;
    9843             :     }
    9844             : 
    9845             :     const std::vector<std::shared_ptr<GDALDimension>> &
    9846         299 :     GetDimensions() const override
    9847             :     {
    9848         299 :         return m_dims;
    9849             :     }
    9850             : 
    9851         138 :     const GDALExtendedDataType &GetDataType() const override
    9852             :     {
    9853         138 :         return m_dt;
    9854             :     }
    9855             : 
    9856           3 :     const std::string &GetUnit() const override
    9857             :     {
    9858           3 :         return m_osUnit;
    9859             :     }
    9860             : 
    9861          29 :     const void *GetRawNoDataValue() const override
    9862             :     {
    9863          29 :         return m_pabyNoData.empty() ? nullptr : m_pabyNoData.data();
    9864             :     }
    9865             : 
    9866           2 :     double GetOffset(bool *pbHasOffset,
    9867             :                      GDALDataType *peStorageType) const override
    9868             :     {
    9869           2 :         int bHasOffset = false;
    9870           2 :         double dfRes = m_poBand->GetOffset(&bHasOffset);
    9871           2 :         if (pbHasOffset)
    9872           2 :             *pbHasOffset = CPL_TO_BOOL(bHasOffset);
    9873           2 :         if (peStorageType)
    9874           1 :             *peStorageType = GDT_Unknown;
    9875           2 :         return dfRes;
    9876             :     }
    9877             : 
    9878           2 :     double GetScale(bool *pbHasScale,
    9879             :                     GDALDataType *peStorageType) const override
    9880             :     {
    9881           2 :         int bHasScale = false;
    9882           2 :         double dfRes = m_poBand->GetScale(&bHasScale);
    9883           2 :         if (pbHasScale)
    9884           2 :             *pbHasScale = CPL_TO_BOOL(bHasScale);
    9885           2 :         if (peStorageType)
    9886           1 :             *peStorageType = GDT_Unknown;
    9887           2 :         return dfRes;
    9888             :     }
    9889             : 
    9890          84 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
    9891             :     {
    9892          84 :         auto poSrcSRS = m_poDS->GetSpatialRef();
    9893          84 :         if (!poSrcSRS)
    9894           2 :             return nullptr;
    9895         164 :         auto poSRS = std::shared_ptr<OGRSpatialReference>(poSrcSRS->Clone());
    9896             : 
    9897         164 :         auto axisMapping = poSRS->GetDataAxisToSRSAxisMapping();
    9898          82 :         constexpr int iYDim = 0;
    9899          82 :         constexpr int iXDim = 1;
    9900         246 :         for (auto &m : axisMapping)
    9901             :         {
    9902         164 :             if (m == 1)
    9903          82 :                 m = iXDim + 1;
    9904          82 :             else if (m == 2)
    9905          82 :                 m = iYDim + 1;
    9906             :             else
    9907           0 :                 m = 0;
    9908             :         }
    9909          82 :         poSRS->SetDataAxisToSRSAxisMapping(axisMapping);
    9910          82 :         return poSRS;
    9911             :     }
    9912             : 
    9913          29 :     std::vector<GUInt64> GetBlockSize() const override
    9914             :     {
    9915          29 :         int nBlockXSize = 0;
    9916          29 :         int nBlockYSize = 0;
    9917          29 :         m_poBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    9918          29 :         return std::vector<GUInt64>{static_cast<GUInt64>(nBlockYSize),
    9919          29 :                                     static_cast<GUInt64>(nBlockXSize)};
    9920             :     }
    9921             : 
    9922             :     class MDIAsAttribute : public GDALAttribute
    9923             :     {
    9924             :         std::vector<std::shared_ptr<GDALDimension>> m_dims{};
    9925             :         const GDALExtendedDataType m_dt = GDALExtendedDataType::CreateString();
    9926             :         std::string m_osValue;
    9927             : 
    9928             :       public:
    9929           2 :         MDIAsAttribute(const std::string &name, const std::string &value)
    9930           2 :             : GDALAbstractMDArray(std::string(), name),
    9931           4 :               GDALAttribute(std::string(), name), m_osValue(value)
    9932             :         {
    9933           2 :         }
    9934             : 
    9935             :         const std::vector<std::shared_ptr<GDALDimension>> &
    9936             :         GetDimensions() const override;
    9937             : 
    9938           2 :         const GDALExtendedDataType &GetDataType() const override
    9939             :         {
    9940           2 :             return m_dt;
    9941             :         }
    9942             : 
    9943           1 :         bool IRead(const GUInt64 *, const size_t *, const GInt64 *,
    9944             :                    const GPtrDiff_t *,
    9945             :                    const GDALExtendedDataType &bufferDataType,
    9946             :                    void *pDstBuffer) const override
    9947             :         {
    9948           1 :             const char *pszStr = m_osValue.c_str();
    9949           1 :             GDALExtendedDataType::CopyValue(&pszStr, m_dt, pDstBuffer,
    9950             :                                             bufferDataType);
    9951           1 :             return true;
    9952             :         }
    9953             :     };
    9954             : 
    9955             :     std::vector<std::shared_ptr<GDALAttribute>>
    9956          14 :     GetAttributes(CSLConstList) const override
    9957             :     {
    9958          14 :         std::vector<std::shared_ptr<GDALAttribute>> res;
    9959          14 :         auto papszMD = m_poBand->GetMetadata();
    9960          16 :         for (auto iter = papszMD; iter && iter[0]; ++iter)
    9961             :         {
    9962           2 :             char *pszKey = nullptr;
    9963           2 :             const char *pszValue = CPLParseNameValue(*iter, &pszKey);
    9964           2 :             if (pszKey && pszValue)
    9965             :             {
    9966             :                 res.emplace_back(
    9967           2 :                     std::make_shared<MDIAsAttribute>(pszKey, pszValue));
    9968             :             }
    9969           2 :             CPLFree(pszKey);
    9970             :         }
    9971          14 :         return res;
    9972             :     }
    9973             : };
    9974             : 
    9975          31 : bool GDALMDArrayFromRasterBand::IRead(
    9976             :     const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
    9977             :     const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
    9978             :     void *pDstBuffer) const
    9979             : {
    9980          31 :     return ReadWrite(GF_Read, arrayStartIdx, count, arrayStep, bufferStride,
    9981          31 :                      bufferDataType, pDstBuffer);
    9982             : }
    9983             : 
    9984             : const std::vector<std::shared_ptr<GDALDimension>> &
    9985           3 : GDALMDArrayFromRasterBand::MDIAsAttribute::GetDimensions() const
    9986             : {
    9987           3 :     return m_dims;
    9988             : }
    9989             : 
    9990             : /************************************************************************/
    9991             : /*                            ReadWrite()                               */
    9992             : /************************************************************************/
    9993             : 
    9994          32 : bool GDALMDArrayFromRasterBand::ReadWrite(
    9995             :     GDALRWFlag eRWFlag, const GUInt64 *arrayStartIdx, const size_t *count,
    9996             :     const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    9997             :     const GDALExtendedDataType &bufferDataType, void *pBuffer) const
    9998             : {
    9999          32 :     constexpr size_t iDimX = 1;
   10000          32 :     constexpr size_t iDimY = 0;
   10001          32 :     return GDALMDRasterIOFromBand(m_poBand, eRWFlag, iDimX, iDimY,
   10002             :                                   arrayStartIdx, count, arrayStep, bufferStride,
   10003          32 :                                   bufferDataType, pBuffer);
   10004             : }
   10005             : 
   10006             : /************************************************************************/
   10007             : /*                       GDALMDRasterIOFromBand()                       */
   10008             : /************************************************************************/
   10009             : 
   10010          65 : bool GDALMDRasterIOFromBand(GDALRasterBand *poBand, GDALRWFlag eRWFlag,
   10011             :                             size_t iDimX, size_t iDimY,
   10012             :                             const GUInt64 *arrayStartIdx, const size_t *count,
   10013             :                             const GInt64 *arrayStep,
   10014             :                             const GPtrDiff_t *bufferStride,
   10015             :                             const GDALExtendedDataType &bufferDataType,
   10016             :                             void *pBuffer)
   10017             : {
   10018          65 :     const auto eDT(bufferDataType.GetNumericDataType());
   10019          65 :     const auto nDTSize(GDALGetDataTypeSizeBytes(eDT));
   10020          65 :     const int nX =
   10021          65 :         arrayStep[iDimX] > 0
   10022          65 :             ? static_cast<int>(arrayStartIdx[iDimX])
   10023           2 :             : static_cast<int>(arrayStartIdx[iDimX] -
   10024           2 :                                (count[iDimX] - 1) * -arrayStep[iDimX]);
   10025          65 :     const int nY =
   10026          65 :         arrayStep[iDimY] > 0
   10027          65 :             ? static_cast<int>(arrayStartIdx[iDimY])
   10028           2 :             : static_cast<int>(arrayStartIdx[iDimY] -
   10029           2 :                                (count[iDimY] - 1) * -arrayStep[iDimY]);
   10030          65 :     const int nSizeX = static_cast<int>(count[iDimX] * ABS(arrayStep[iDimX]));
   10031          65 :     const int nSizeY = static_cast<int>(count[iDimY] * ABS(arrayStep[iDimY]));
   10032          65 :     GByte *pabyBuffer = static_cast<GByte *>(pBuffer);
   10033          65 :     int nStrideXSign = 1;
   10034          65 :     if (arrayStep[iDimX] < 0)
   10035             :     {
   10036           2 :         pabyBuffer += (count[iDimX] - 1) * bufferStride[iDimX] * nDTSize;
   10037           2 :         nStrideXSign = -1;
   10038             :     }
   10039          65 :     int nStrideYSign = 1;
   10040          65 :     if (arrayStep[iDimY] < 0)
   10041             :     {
   10042           2 :         pabyBuffer += (count[iDimY] - 1) * bufferStride[iDimY] * nDTSize;
   10043           2 :         nStrideYSign = -1;
   10044             :     }
   10045             : 
   10046         130 :     return poBand->RasterIO(eRWFlag, nX, nY, nSizeX, nSizeY, pabyBuffer,
   10047          65 :                             static_cast<int>(count[iDimX]),
   10048          65 :                             static_cast<int>(count[iDimY]), eDT,
   10049             :                             static_cast<GSpacing>(
   10050          65 :                                 nStrideXSign * bufferStride[iDimX] * nDTSize),
   10051             :                             static_cast<GSpacing>(
   10052          65 :                                 nStrideYSign * bufferStride[iDimY] * nDTSize),
   10053          65 :                             nullptr) == CE_None;
   10054             : }
   10055             : 
   10056             : /************************************************************************/
   10057             : /*                            AsMDArray()                               */
   10058             : /************************************************************************/
   10059             : 
   10060             : /** Return a view of this raster band as a 2D multidimensional GDALMDArray.
   10061             :  *
   10062             :  * The band must be linked to a GDALDataset. If this dataset is not already
   10063             :  * marked as shared, it will be, so that the returned array holds a reference
   10064             :  * to it.
   10065             :  *
   10066             :  * If the dataset has a geotransform attached, the X and Y dimensions of the
   10067             :  * returned array will have an associated indexing variable.
   10068             :  *
   10069             :  * This is the same as the C function GDALRasterBandAsMDArray().
   10070             :  *
   10071             :  * The "reverse" method is GDALMDArray::AsClassicDataset().
   10072             :  *
   10073             :  * @return a new array, or nullptr.
   10074             :  *
   10075             :  * @since GDAL 3.1
   10076             :  */
   10077          23 : std::shared_ptr<GDALMDArray> GDALRasterBand::AsMDArray() const
   10078             : {
   10079          23 :     if (!poDS)
   10080             :     {
   10081           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Band not attached to a dataset");
   10082           0 :         return nullptr;
   10083             :     }
   10084          23 :     if (!poDS->GetShared())
   10085             :     {
   10086          23 :         poDS->MarkAsShared();
   10087             :     }
   10088             :     return GDALMDArrayFromRasterBand::Create(
   10089          23 :         poDS, const_cast<GDALRasterBand *>(this));
   10090             : }
   10091             : 
   10092             : /************************************************************************/
   10093             : /*                             InterpolateAtPoint()                     */
   10094             : /************************************************************************/
   10095             : 
   10096             : /**
   10097             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10098             :  * taking pixel/line coordinates as input.
   10099             :  *
   10100             :  * @param dfPixel pixel coordinate as a double, where interpolation should be done.
   10101             :  * @param dfLine line coordinate as a double, where interpolation should be done.
   10102             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   10103             :  * @param pdfRealValue pointer to real part of interpolated value
   10104             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   10105             :  *
   10106             :  * @return CE_None on success, or an error code on failure.
   10107             :  * @since GDAL 3.10
   10108             :  */
   10109             : 
   10110         167 : CPLErr GDALRasterBand::InterpolateAtPoint(double dfPixel, double dfLine,
   10111             :                                           GDALRIOResampleAlg eInterpolation,
   10112             :                                           double *pdfRealValue,
   10113             :                                           double *pdfImagValue) const
   10114             : {
   10115         167 :     if (eInterpolation != GRIORA_NearestNeighbour &&
   10116          33 :         eInterpolation != GRIORA_Bilinear && eInterpolation != GRIORA_Cubic &&
   10117             :         eInterpolation != GRIORA_CubicSpline)
   10118             :     {
   10119           2 :         CPLError(CE_Failure, CPLE_AppDefined,
   10120             :                  "Only nearest, bilinear, cubic and cubicspline interpolation "
   10121             :                  "methods "
   10122             :                  "allowed");
   10123             : 
   10124           2 :         return CE_Failure;
   10125             :     }
   10126             : 
   10127         165 :     GDALRasterBand *pBand = const_cast<GDALRasterBand *>(this);
   10128         165 :     if (!m_poPointsCache)
   10129          85 :         m_poPointsCache = new GDALDoublePointsCache();
   10130             : 
   10131             :     const bool res =
   10132         165 :         GDALInterpolateAtPoint(pBand, eInterpolation, m_poPointsCache->cache,
   10133             :                                dfPixel, dfLine, pdfRealValue, pdfImagValue);
   10134             : 
   10135         165 :     return res ? CE_None : CE_Failure;
   10136             : }
   10137             : 
   10138             : /************************************************************************/
   10139             : /*                        GDALRasterInterpolateAtPoint()                */
   10140             : /************************************************************************/
   10141             : 
   10142             : /**
   10143             :  * \brief Interpolates the value between pixels using
   10144             :  * a resampling algorithm
   10145             :  *
   10146             :  * @see GDALRasterBand::InterpolateAtPoint()
   10147             :  * @since GDAL 3.10
   10148             :  */
   10149             : 
   10150         144 : CPLErr GDALRasterInterpolateAtPoint(GDALRasterBandH hBand, double dfPixel,
   10151             :                                     double dfLine,
   10152             :                                     GDALRIOResampleAlg eInterpolation,
   10153             :                                     double *pdfRealValue, double *pdfImagValue)
   10154             : {
   10155         144 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtPoint", CE_Failure);
   10156             : 
   10157         144 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10158         144 :     return poBand->InterpolateAtPoint(dfPixel, dfLine, eInterpolation,
   10159         144 :                                       pdfRealValue, pdfImagValue);
   10160             : }
   10161             : 
   10162             : /************************************************************************/
   10163             : /*                    InterpolateAtGeolocation()                        */
   10164             : /************************************************************************/
   10165             : 
   10166             : /**
   10167             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10168             :  * taking georeferenced coordinates as input.
   10169             :  *
   10170             :  * When poSRS is null, those georeferenced coordinates (dfGeolocX, dfGeolocY)
   10171             :  * must be in the "natural" SRS of the dataset, that is the one returned by
   10172             :  * GetSpatialRef() if there is a geotransform, GetGCPSpatialRef() if there are
   10173             :  * GCPs, WGS 84 if there are RPC coefficients, or the SRS of the geolocation
   10174             :  * array (generally WGS 84) if there is a geolocation array.
   10175             :  * If that natural SRS is a geographic one, dfGeolocX must be a longitude, and
   10176             :  * dfGeolocY a latitude. If that natural SRS is a projected one, dfGeolocX must
   10177             :  * be a easting, and dfGeolocY a northing.
   10178             :  *
   10179             :  * When poSRS is set to a non-null value, (dfGeolocX, dfGeolocY) must be
   10180             :  * expressed in that CRS, and that tuple must be conformant with the
   10181             :  * data-axis-to-crs-axis setting of poSRS, that is the one returned by
   10182             :  * the OGRSpatialReference::GetDataAxisToSRSAxisMapping(). If you want to be sure
   10183             :  * of the axis order, then make sure to call poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER)
   10184             :  * before calling this method, and in that case, dfGeolocX must be a longitude
   10185             :  * or an easting value, and dfGeolocX a latitude or a northing value.
   10186             :  *
   10187             :  * The GDALDataset::GeolocationToPixelLine() will be used to transform from
   10188             :  * (dfGeolocX,dfGeolocY) georeferenced coordinates to (pixel, line). Refer to
   10189             :  * it for details on how that transformation is done.
   10190             :  *
   10191             :  * @param dfGeolocX X coordinate of the position (longitude or easting if poSRS
   10192             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   10193             :  * where interpolation should be done.
   10194             :  * @param dfGeolocY Y coordinate of the position (latitude or northing if poSRS
   10195             :  * is null, otherwise consistent with poSRS data-axis-to-crs-axis mapping),
   10196             :  * where interpolation should be done.
   10197             :  * @param poSRS If set, override the natural CRS in which dfGeolocX, dfGeolocY are expressed
   10198             :  * @param eInterpolation interpolation type. Only near, bilinear, cubic and cubicspline are allowed.
   10199             :  * @param pdfRealValue pointer to real part of interpolated value
   10200             :  * @param pdfImagValue pointer to imaginary part of interpolated value (may be null if not needed)
   10201             :  * @param papszTransformerOptions Options accepted by GDALDataset::GeolocationToPixelLine() (GDALCreateGenImgProjTransformer2()), or nullptr.
   10202             :  *
   10203             :  * @return CE_None on success, or an error code on failure.
   10204             :  * @since GDAL 3.11
   10205             :  */
   10206             : 
   10207          15 : CPLErr GDALRasterBand::InterpolateAtGeolocation(
   10208             :     double dfGeolocX, double dfGeolocY, const OGRSpatialReference *poSRS,
   10209             :     GDALRIOResampleAlg eInterpolation, double *pdfRealValue,
   10210             :     double *pdfImagValue, CSLConstList papszTransformerOptions) const
   10211             : {
   10212             :     double dfPixel;
   10213             :     double dfLine;
   10214          15 :     if (poDS->GeolocationToPixelLine(dfGeolocX, dfGeolocY, poSRS, &dfPixel,
   10215             :                                      &dfLine,
   10216          15 :                                      papszTransformerOptions) != CE_None)
   10217             :     {
   10218           1 :         return CE_Failure;
   10219             :     }
   10220          14 :     return InterpolateAtPoint(dfPixel, dfLine, eInterpolation, pdfRealValue,
   10221          14 :                               pdfImagValue);
   10222             : }
   10223             : 
   10224             : /************************************************************************/
   10225             : /*                  GDALRasterInterpolateAtGeolocation()                */
   10226             : /************************************************************************/
   10227             : 
   10228             : /**
   10229             :  * \brief Interpolates the value between pixels using a resampling algorithm,
   10230             :  * taking georeferenced coordinates as input.
   10231             :  *
   10232             :  * @see GDALRasterBand::InterpolateAtGeolocation()
   10233             :  * @since GDAL 3.11
   10234             :  */
   10235             : 
   10236          15 : CPLErr GDALRasterInterpolateAtGeolocation(GDALRasterBandH hBand,
   10237             :                                           double dfGeolocX, double dfGeolocY,
   10238             :                                           OGRSpatialReferenceH hSRS,
   10239             :                                           GDALRIOResampleAlg eInterpolation,
   10240             :                                           double *pdfRealValue,
   10241             :                                           double *pdfImagValue,
   10242             :                                           CSLConstList papszTransformerOptions)
   10243             : {
   10244          15 :     VALIDATE_POINTER1(hBand, "GDALRasterInterpolateAtGeolocation", CE_Failure);
   10245             : 
   10246          15 :     GDALRasterBand *poBand = GDALRasterBand::FromHandle(hBand);
   10247          15 :     return poBand->InterpolateAtGeolocation(
   10248          15 :         dfGeolocX, dfGeolocY, OGRSpatialReference::FromHandle(hSRS),
   10249          15 :         eInterpolation, pdfRealValue, pdfImagValue, papszTransformerOptions);
   10250             : }
   10251             : 
   10252             : /************************************************************************/
   10253             : /*                    GDALRasterBand::SplitRasterIO()                   */
   10254             : /************************************************************************/
   10255             : 
   10256             : //! @cond Doxygen_Suppress
   10257             : 
   10258             : /** Implements IRasterIO() by dividing the request in 2.
   10259             :  *
   10260             :  * Should only be called when nBufXSize == nXSize && nBufYSize == nYSize
   10261             :  *
   10262             :  * Return CE_Warning if the split could not be done, CE_None in case of
   10263             :  * success and CE_Failure in case of error.
   10264             :  *
   10265             :  * @since 3.12
   10266             :  */
   10267         999 : CPLErr GDALRasterBand::SplitRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
   10268             :                                      [[maybe_unused]] int nXSize,
   10269             :                                      [[maybe_unused]] int nYSize, void *pData,
   10270             :                                      int nBufXSize, int nBufYSize,
   10271             :                                      GDALDataType eBufType,
   10272             :                                      GSpacing nPixelSpace, GSpacing nLineSpace,
   10273             :                                      GDALRasterIOExtraArg *psExtraArg)
   10274             : {
   10275         999 :     CPLAssert(nBufXSize == nXSize && nBufYSize == nYSize);
   10276             : 
   10277         999 :     GByte *pabyData = static_cast<GByte *>(pData);
   10278         999 :     if ((nBufXSize == nRasterXSize || nBufYSize >= nBufXSize) && nBufYSize >= 2)
   10279             :     {
   10280             :         GDALRasterIOExtraArg sArg;
   10281         499 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   10282         499 :         const int nHalfHeight = nBufYSize / 2;
   10283             : 
   10284         499 :         sArg.pfnProgress = GDALScaledProgress;
   10285         499 :         sArg.pProgressData = GDALCreateScaledProgress(
   10286             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   10287         499 :         if (sArg.pProgressData == nullptr)
   10288         499 :             sArg.pfnProgress = nullptr;
   10289         998 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nBufXSize, nHalfHeight,
   10290             :                                 pabyData, nBufXSize, nHalfHeight, eBufType,
   10291         499 :                                 nPixelSpace, nLineSpace, &sArg);
   10292         499 :         GDALDestroyScaledProgress(sArg.pProgressData);
   10293             : 
   10294         499 :         if (eErr == CE_None)
   10295             :         {
   10296         499 :             sArg.pfnProgress = GDALScaledProgress;
   10297         499 :             sArg.pProgressData = GDALCreateScaledProgress(
   10298             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   10299         499 :             if (sArg.pProgressData == nullptr)
   10300         499 :                 sArg.pfnProgress = nullptr;
   10301         998 :             eErr = IRasterIO(eRWFlag, nXOff, nYOff + nHalfHeight, nBufXSize,
   10302             :                              nBufYSize - nHalfHeight,
   10303         499 :                              pabyData + nHalfHeight * nLineSpace, nBufXSize,
   10304             :                              nBufYSize - nHalfHeight, eBufType, nPixelSpace,
   10305         499 :                              nLineSpace, &sArg);
   10306         499 :             GDALDestroyScaledProgress(sArg.pProgressData);
   10307             :         }
   10308         499 :         return eErr;
   10309             :     }
   10310         500 :     else if (nBufXSize >= 2)
   10311             :     {
   10312             :         GDALRasterIOExtraArg sArg;
   10313         500 :         INIT_RASTERIO_EXTRA_ARG(sArg);
   10314         500 :         const int nHalfWidth = nBufXSize / 2;
   10315             : 
   10316         500 :         sArg.pfnProgress = GDALScaledProgress;
   10317         500 :         sArg.pProgressData = GDALCreateScaledProgress(
   10318             :             0, 0.5, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   10319         500 :         if (sArg.pProgressData == nullptr)
   10320         500 :             sArg.pfnProgress = nullptr;
   10321        1000 :         CPLErr eErr = IRasterIO(eRWFlag, nXOff, nYOff, nHalfWidth, nBufYSize,
   10322             :                                 pabyData, nHalfWidth, nBufYSize, eBufType,
   10323         500 :                                 nPixelSpace, nLineSpace, &sArg);
   10324         500 :         GDALDestroyScaledProgress(sArg.pProgressData);
   10325             : 
   10326         500 :         if (eErr == CE_None)
   10327             :         {
   10328         500 :             sArg.pfnProgress = GDALScaledProgress;
   10329         500 :             sArg.pProgressData = GDALCreateScaledProgress(
   10330             :                 0.5, 1, psExtraArg->pfnProgress, psExtraArg->pProgressData);
   10331         500 :             if (sArg.pProgressData == nullptr)
   10332         500 :                 sArg.pfnProgress = nullptr;
   10333        1000 :             eErr = IRasterIO(eRWFlag, nXOff + nHalfWidth, nYOff,
   10334             :                              nBufXSize - nHalfWidth, nBufYSize,
   10335         500 :                              pabyData + nHalfWidth * nPixelSpace,
   10336             :                              nBufXSize - nHalfWidth, nBufYSize, eBufType,
   10337         500 :                              nPixelSpace, nLineSpace, &sArg);
   10338         500 :             GDALDestroyScaledProgress(sArg.pProgressData);
   10339             :         }
   10340         500 :         return eErr;
   10341             :     }
   10342             : 
   10343           0 :     return CE_Warning;
   10344             : }
   10345             : 
   10346             : //! @endcond
   10347             : 
   10348             : /************************************************************************/
   10349             : /*                         ThrowIfNotSameDimensions()                   */
   10350             : /************************************************************************/
   10351             : 
   10352             : //! @cond Doxygen_Suppress
   10353             : /* static */
   10354         169 : void GDALRasterBand::ThrowIfNotSameDimensions(const GDALRasterBand &first,
   10355             :                                               const GDALRasterBand &second)
   10356             : {
   10357         320 :     if (first.GetXSize() != second.GetXSize() ||
   10358         151 :         first.GetYSize() != second.GetYSize())
   10359             :     {
   10360          36 :         throw std::runtime_error("Bands do not have the same dimensions");
   10361             :     }
   10362         133 : }
   10363             : 
   10364             : //! @endcond
   10365             : 
   10366             : /************************************************************************/
   10367             : /*                          GDALRasterBandUnaryOp()                     */
   10368             : /************************************************************************/
   10369             : 
   10370             : /** Apply a unary operation on this band.
   10371             :  *
   10372             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10373             :  * dataset.
   10374             :  *
   10375             :  * @since 3.12
   10376             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   10377             :  */
   10378             : GDALComputedRasterBandH
   10379           6 : GDALRasterBandUnaryOp(GDALRasterBandH hBand,
   10380             :                       GDALRasterAlgebraUnaryOperation eOp)
   10381             : {
   10382           6 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   10383           6 :     GDALComputedRasterBand::Operation cppOp{};
   10384           6 :     switch (eOp)
   10385             :     {
   10386           2 :         case GRAUO_LOGICAL_NOT:
   10387             :             return new GDALComputedRasterBand(
   10388             :                 GDALComputedRasterBand::Operation::OP_NE,
   10389           2 :                 *(GDALRasterBand::FromHandle(hBand)), true);
   10390           1 :         case GRAUO_ABS:
   10391           1 :             cppOp = GDALComputedRasterBand::Operation::OP_ABS;
   10392           1 :             break;
   10393           1 :         case GRAUO_SQRT:
   10394           1 :             cppOp = GDALComputedRasterBand::Operation::OP_SQRT;
   10395           1 :             break;
   10396           1 :         case GRAUO_LOG:
   10397             : #ifndef HAVE_MUPARSER
   10398             :             CPLError(
   10399             :                 CE_Failure, CPLE_NotSupported,
   10400             :                 "log(band) not available on a GDAL build without muparser");
   10401             :             return nullptr;
   10402             : #else
   10403           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG;
   10404           1 :             break;
   10405             : #endif
   10406           1 :         case GRAUO_LOG10:
   10407           1 :             cppOp = GDALComputedRasterBand::Operation::OP_LOG10;
   10408           1 :             break;
   10409             :     }
   10410             :     return new GDALComputedRasterBand(cppOp,
   10411           4 :                                       *(GDALRasterBand::FromHandle(hBand)));
   10412             : }
   10413             : 
   10414             : /************************************************************************/
   10415             : /*            ConvertGDALRasterAlgebraBinaryOperationToCpp()            */
   10416             : /************************************************************************/
   10417             : 
   10418             : static GDALComputedRasterBand::Operation
   10419         120 : ConvertGDALRasterAlgebraBinaryOperationToCpp(
   10420             :     GDALRasterAlgebraBinaryOperation eOp)
   10421             : {
   10422         120 :     switch (eOp)
   10423             :     {
   10424          26 :         case GRABO_ADD:
   10425          26 :             return GDALComputedRasterBand::Operation::OP_ADD;
   10426           2 :         case GRABO_SUB:
   10427           2 :             return GDALComputedRasterBand::Operation::OP_SUBTRACT;
   10428          24 :         case GRABO_MUL:
   10429          24 :             return GDALComputedRasterBand::Operation::OP_MULTIPLY;
   10430           3 :         case GRABO_DIV:
   10431           3 :             return GDALComputedRasterBand::Operation::OP_DIVIDE;
   10432           6 :         case GRABO_GT:
   10433           6 :             return GDALComputedRasterBand::Operation::OP_GT;
   10434           8 :         case GRABO_GE:
   10435           8 :             return GDALComputedRasterBand::Operation::OP_GE;
   10436           6 :         case GRABO_LT:
   10437           6 :             return GDALComputedRasterBand::Operation::OP_LT;
   10438           6 :         case GRABO_LE:
   10439           6 :             return GDALComputedRasterBand::Operation::OP_LE;
   10440           6 :         case GRABO_EQ:
   10441           6 :             return GDALComputedRasterBand::Operation::OP_EQ;
   10442           6 :         case GRABO_NE:
   10443           6 :             break;
   10444          12 :         case GRABO_LOGICAL_AND:
   10445          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_AND;
   10446          12 :         case GRABO_LOGICAL_OR:
   10447          12 :             return GDALComputedRasterBand::Operation::OP_LOGICAL_OR;
   10448           3 :         case GRABO_POW:
   10449           3 :             return GDALComputedRasterBand::Operation::OP_POW;
   10450             :     }
   10451           6 :     return GDALComputedRasterBand::Operation::OP_NE;
   10452             : }
   10453             : 
   10454             : /************************************************************************/
   10455             : /*                     GDALRasterBandBinaryOpBand()                     */
   10456             : /************************************************************************/
   10457             : 
   10458             : /** Apply a binary operation on this band with another one.
   10459             :  *
   10460             :  * e.g. GDALRasterBandBinaryOpBand(hBand1, GRABO_SUB, hBand2) performs
   10461             :  * "hBand1 - hBand2".
   10462             :  *
   10463             :  * The resulting band is lazy evaluated. A reference is taken on both input
   10464             :  * datasets.
   10465             :  *
   10466             :  * @since 3.12
   10467             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   10468             :  */
   10469             : GDALComputedRasterBandH
   10470          57 : GDALRasterBandBinaryOpBand(GDALRasterBandH hBand,
   10471             :                            GDALRasterAlgebraBinaryOperation eOp,
   10472             :                            GDALRasterBandH hOtherBand)
   10473             : {
   10474          57 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   10475          57 :     VALIDATE_POINTER1(hOtherBand, __func__, nullptr);
   10476             : #ifndef HAVE_MUPARSER
   10477             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   10478             :     {
   10479             :         CPLError(
   10480             :             CE_Failure, CPLE_NotSupported,
   10481             :             "Band comparison operators not available on a GDAL build without "
   10482             :             "muparser");
   10483             :         return nullptr;
   10484             :     }
   10485             :     else if (eOp == GRABO_POW)
   10486             :     {
   10487             :         CPLError(
   10488             :             CE_Failure, CPLE_NotSupported,
   10489             :             "pow(band, band) not available on a GDAL build without muparser");
   10490             :         return nullptr;
   10491             :     }
   10492             : #endif
   10493          57 :     auto &firstBand = *(GDALRasterBand::FromHandle(hBand));
   10494          57 :     auto &secondBand = *(GDALRasterBand::FromHandle(hOtherBand));
   10495             :     try
   10496             :     {
   10497          57 :         GDALRasterBand::ThrowIfNotSameDimensions(firstBand, secondBand);
   10498             :     }
   10499          13 :     catch (const std::exception &e)
   10500             :     {
   10501          13 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   10502          13 :         return nullptr;
   10503             :     }
   10504             :     return new GDALComputedRasterBand(
   10505          44 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), firstBand,
   10506          44 :         secondBand);
   10507             : }
   10508             : 
   10509             : /************************************************************************/
   10510             : /*                     GDALRasterBandBinaryOpDouble()                   */
   10511             : /************************************************************************/
   10512             : 
   10513             : /** Apply a binary operation on this band with a constant
   10514             :  *
   10515             :  * e.g. GDALRasterBandBinaryOpDouble(hBand, GRABO_SUB, constant) performs
   10516             :  * "hBand - constant".
   10517             :  *
   10518             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10519             :  * dataset.
   10520             :  *
   10521             :  * @since 3.12
   10522             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   10523             :  */
   10524             : GDALComputedRasterBandH
   10525          59 : GDALRasterBandBinaryOpDouble(GDALRasterBandH hBand,
   10526             :                              GDALRasterAlgebraBinaryOperation eOp,
   10527             :                              double constant)
   10528             : {
   10529          59 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   10530             : #ifndef HAVE_MUPARSER
   10531             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   10532             :     {
   10533             :         CPLError(
   10534             :             CE_Failure, CPLE_NotSupported,
   10535             :             "Band comparison operators not available on a GDAL build without "
   10536             :             "muparser");
   10537             :         return nullptr;
   10538             :     }
   10539             : #endif
   10540             :     return new GDALComputedRasterBand(
   10541          59 :         ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   10542          59 :         *(GDALRasterBand::FromHandle(hBand)), constant);
   10543             : }
   10544             : 
   10545             : /************************************************************************/
   10546             : /*                   GDALRasterBandBinaryOpDoubleToBand()               */
   10547             : /************************************************************************/
   10548             : 
   10549             : /** Apply a binary operation on the constant with this band
   10550             :  *
   10551             :  * e.g. GDALRasterBandBinaryOpDoubleToBand(constant, GRABO_SUB, hBand) performs
   10552             :  * "constant - hBand".
   10553             :  *
   10554             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10555             :  * dataset.
   10556             :  *
   10557             :  * @since 3.12
   10558             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   10559             :  */
   10560             : GDALComputedRasterBandH
   10561          18 : GDALRasterBandBinaryOpDoubleToBand(double constant,
   10562             :                                    GDALRasterAlgebraBinaryOperation eOp,
   10563             :                                    GDALRasterBandH hBand)
   10564             : {
   10565          18 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   10566             : #ifndef HAVE_MUPARSER
   10567             :     if (eOp >= GRABO_GT && eOp <= GRABO_NE)
   10568             :     {
   10569             :         CPLError(
   10570             :             CE_Failure, CPLE_NotSupported,
   10571             :             "Band comparison operators not available on a GDAL build without "
   10572             :             "muparser");
   10573             :         return nullptr;
   10574             :     }
   10575             : #endif
   10576          18 :     switch (eOp)
   10577             :     {
   10578          15 :         case GRABO_ADD:
   10579             :         case GRABO_MUL:
   10580             :         {
   10581             :             return new GDALComputedRasterBand(
   10582          15 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp),
   10583          15 :                 *(GDALRasterBand::FromHandle(hBand)), constant);
   10584             :         }
   10585             : 
   10586           2 :         case GRABO_DIV:
   10587             :         case GRABO_GT:
   10588             :         case GRABO_GE:
   10589             :         case GRABO_LT:
   10590             :         case GRABO_LE:
   10591             :         case GRABO_EQ:
   10592             :         case GRABO_NE:
   10593             :         case GRABO_LOGICAL_AND:
   10594             :         case GRABO_LOGICAL_OR:
   10595             :         case GRABO_POW:
   10596             :         {
   10597             :             return new GDALComputedRasterBand(
   10598           2 :                 ConvertGDALRasterAlgebraBinaryOperationToCpp(eOp), constant,
   10599           2 :                 *(GDALRasterBand::FromHandle(hBand)));
   10600             :         }
   10601             : 
   10602           1 :         case GRABO_SUB:
   10603             :         {
   10604           1 :             break;
   10605             :         }
   10606             :     }
   10607             : 
   10608             :     return new GDALComputedRasterBand(
   10609             :         GDALComputedRasterBand::Operation::OP_ADD,
   10610           2 :         GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MULTIPLY,
   10611           1 :                                *(GDALRasterBand::FromHandle(hBand)), -1.0),
   10612           1 :         constant);
   10613             : }
   10614             : 
   10615             : /************************************************************************/
   10616             : /*                           operator+()                                */
   10617             : /************************************************************************/
   10618             : 
   10619             : /** Add this band with another one.
   10620             :  *
   10621             :  * The resulting band is lazy evaluated. A reference is taken on both input
   10622             :  * datasets.
   10623             :  *
   10624             :  * @since 3.12
   10625             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   10626             :  */
   10627             : GDALComputedRasterBand
   10628           8 : GDALRasterBand::operator+(const GDALRasterBand &other) const
   10629             : {
   10630           8 :     ThrowIfNotSameDimensions(*this, other);
   10631             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   10632           7 :                                   *this, other);
   10633             : }
   10634             : 
   10635             : /************************************************************************/
   10636             : /*                           operator+()                                */
   10637             : /************************************************************************/
   10638             : 
   10639             : /** Add this band with a constant.
   10640             :  *
   10641             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10642             :  * dataset.
   10643             :  *
   10644             :  * @since 3.12
   10645             :  */
   10646          13 : GDALComputedRasterBand GDALRasterBand::operator+(double constant) const
   10647             : {
   10648             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ADD,
   10649          13 :                                   *this, constant);
   10650             : }
   10651             : 
   10652             : /************************************************************************/
   10653             : /*                           operator+()                                */
   10654             : /************************************************************************/
   10655             : 
   10656             : /** Add a band with a constant.
   10657             :  *
   10658             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10659             :  * dataset.
   10660             :  *
   10661             :  * @since 3.12
   10662             :  */
   10663           1 : GDALComputedRasterBand operator+(double constant, const GDALRasterBand &other)
   10664             : {
   10665           1 :     return other + constant;
   10666             : }
   10667             : 
   10668             : /************************************************************************/
   10669             : /*                           operator-()                                */
   10670             : /************************************************************************/
   10671             : 
   10672             : /** Return a band whose value is the opposite value of the band for each
   10673             :  * pixel.
   10674             :  *
   10675             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10676             :  * dataset.
   10677             :  *
   10678             :  * @since 3.12
   10679             :  */
   10680           2 : GDALComputedRasterBand GDALRasterBand::operator-() const
   10681             : {
   10682           2 :     return 0 - *this;
   10683             : }
   10684             : 
   10685             : /************************************************************************/
   10686             : /*                           operator-()                                */
   10687             : /************************************************************************/
   10688             : 
   10689             : /** Subtract this band with another one.
   10690             :  *
   10691             :  * The resulting band is lazy evaluated. A reference is taken on both input
   10692             :  * datasets.
   10693             :  *
   10694             :  * @since 3.12
   10695             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   10696             :  */
   10697             : GDALComputedRasterBand
   10698           2 : GDALRasterBand::operator-(const GDALRasterBand &other) const
   10699             : {
   10700           2 :     ThrowIfNotSameDimensions(*this, other);
   10701             :     return GDALComputedRasterBand(
   10702           2 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, other);
   10703             : }
   10704             : 
   10705             : /************************************************************************/
   10706             : /*                           operator-()                                */
   10707             : /************************************************************************/
   10708             : 
   10709             : /** Subtract this band with a constant.
   10710             :  *
   10711             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10712             :  * dataset.
   10713             :  *
   10714             :  * @since 3.12
   10715             :  */
   10716           1 : GDALComputedRasterBand GDALRasterBand::operator-(double constant) const
   10717             : {
   10718             :     return GDALComputedRasterBand(
   10719           1 :         GDALComputedRasterBand::Operation::OP_SUBTRACT, *this, constant);
   10720             : }
   10721             : 
   10722             : /************************************************************************/
   10723             : /*                           operator-()                                */
   10724             : /************************************************************************/
   10725             : 
   10726             : /** Subtract a constant with a band.
   10727             :  *
   10728             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10729             :  * dataset.
   10730             :  *
   10731             :  * @since 3.12
   10732             :  */
   10733           3 : GDALComputedRasterBand operator-(double constant, const GDALRasterBand &other)
   10734             : {
   10735           6 :     return other * (-1.0) + constant;
   10736             : }
   10737             : 
   10738             : /************************************************************************/
   10739             : /*                           operator*()                                */
   10740             : /************************************************************************/
   10741             : 
   10742             : /** Multiply this band with another one.
   10743             :  *
   10744             :  * The resulting band is lazy evaluated. A reference is taken on both input
   10745             :  * datasets.
   10746             :  *
   10747             :  * @since 3.12
   10748             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   10749             :  */
   10750             : GDALComputedRasterBand
   10751           2 : GDALRasterBand::operator*(const GDALRasterBand &other) const
   10752             : {
   10753           2 :     ThrowIfNotSameDimensions(*this, other);
   10754             :     return GDALComputedRasterBand(
   10755           2 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, other);
   10756             : }
   10757             : 
   10758             : /************************************************************************/
   10759             : /*                           operator*()                                */
   10760             : /************************************************************************/
   10761             : 
   10762             : /** Multiply this band by a constant.
   10763             :  *
   10764             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10765             :  * dataset.
   10766             :  *
   10767             :  * @since 3.12
   10768             :  */
   10769          14 : GDALComputedRasterBand GDALRasterBand::operator*(double constant) const
   10770             : {
   10771             :     return GDALComputedRasterBand(
   10772          14 :         GDALComputedRasterBand::Operation::OP_MULTIPLY, *this, constant);
   10773             : }
   10774             : 
   10775             : /************************************************************************/
   10776             : /*                           operator*()                                */
   10777             : /************************************************************************/
   10778             : 
   10779             : /** Multiply a band with a constant.
   10780             :  *
   10781             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10782             :  * dataset.
   10783             :  *
   10784             :  * @since 3.12
   10785             :  */
   10786           2 : GDALComputedRasterBand operator*(double constant, const GDALRasterBand &other)
   10787             : {
   10788           2 :     return other * constant;
   10789             : }
   10790             : 
   10791             : /************************************************************************/
   10792             : /*                           operator/()                                */
   10793             : /************************************************************************/
   10794             : 
   10795             : /** Divide this band with another one.
   10796             :  *
   10797             :  * The resulting band is lazy evaluated. A reference is taken on both input
   10798             :  * datasets.
   10799             :  *
   10800             :  * @since 3.12
   10801             :  * @throw std::runtime_error if both bands do not have the same dimensions.
   10802             :  */
   10803             : GDALComputedRasterBand
   10804           2 : GDALRasterBand::operator/(const GDALRasterBand &other) const
   10805             : {
   10806           2 :     ThrowIfNotSameDimensions(*this, other);
   10807             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   10808           2 :                                   *this, other);
   10809             : }
   10810             : 
   10811             : /************************************************************************/
   10812             : /*                           operator/()                                */
   10813             : /************************************************************************/
   10814             : 
   10815             : /** Divide this band by a constant.
   10816             :  *
   10817             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10818             :  * dataset.
   10819             :  *
   10820             :  * @since 3.12
   10821             :  */
   10822           0 : GDALComputedRasterBand GDALRasterBand::operator/(double constant) const
   10823             : {
   10824             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   10825           0 :                                   *this, constant);
   10826             : }
   10827             : 
   10828             : /************************************************************************/
   10829             : /*                           operator/()                                */
   10830             : /************************************************************************/
   10831             : 
   10832             : /** Divide a constant by a band.
   10833             :  *
   10834             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10835             :  * dataset.
   10836             :  *
   10837             :  * @since 3.12
   10838             :  */
   10839           1 : GDALComputedRasterBand operator/(double constant, const GDALRasterBand &other)
   10840             : {
   10841             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_DIVIDE,
   10842           1 :                                   constant, other);
   10843             : }
   10844             : 
   10845             : /************************************************************************/
   10846             : /*                          ThrowIfNotMuparser()                        */
   10847             : /************************************************************************/
   10848             : 
   10849             : #ifndef HAVE_MUPARSER
   10850             : static GDALComputedRasterBand ThrowIfNotMuparser()
   10851             : {
   10852             :     throw std::runtime_error("Operator not available on a "
   10853             :                              "GDAL build without muparser");
   10854             : }
   10855             : #endif
   10856             : 
   10857             : /************************************************************************/
   10858             : /*                           operator>()                                */
   10859             : /************************************************************************/
   10860             : 
   10861             : /** Return a band whose value is 1 if the pixel value of the left operand
   10862             :  * is greater than the pixel value of the right operand.
   10863             :  *
   10864             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10865             :  * dataset.
   10866             :  *
   10867             :  * @since 3.12
   10868             :  */
   10869             : GDALComputedRasterBand
   10870           3 : GDALRasterBand::operator>(const GDALRasterBand &other) const
   10871             : {
   10872             : #ifndef HAVE_MUPARSER
   10873             :     (void)other;
   10874             :     return ThrowIfNotMuparser();
   10875             : #else
   10876           3 :     ThrowIfNotSameDimensions(*this, other);
   10877             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   10878           2 :                                   *this, other);
   10879             : #endif
   10880             : }
   10881             : 
   10882             : /************************************************************************/
   10883             : /*                           operator>()                                */
   10884             : /************************************************************************/
   10885             : 
   10886             : /** Return a band whose value is 1 if the pixel value of the left operand
   10887             :  * is greater than the constant.
   10888             :  *
   10889             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10890             :  * dataset.
   10891             :  *
   10892             :  * @since 3.12
   10893             :  */
   10894           3 : GDALComputedRasterBand GDALRasterBand::operator>(double constant) const
   10895             : {
   10896             : #ifndef HAVE_MUPARSER
   10897             :     (void)constant;
   10898             :     return ThrowIfNotMuparser();
   10899             : #else
   10900             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   10901           3 :                                   *this, constant);
   10902             : #endif
   10903             : }
   10904             : 
   10905             : /************************************************************************/
   10906             : /*                           operator>()                                */
   10907             : /************************************************************************/
   10908             : 
   10909             : /** Return a band whose value is 1 if the constant is greater than the pixel
   10910             :  * value of the right operand.
   10911             :  *
   10912             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10913             :  * dataset.
   10914             :  *
   10915             :  * @since 3.12
   10916             :  */
   10917           2 : GDALComputedRasterBand operator>(double constant, const GDALRasterBand &other)
   10918             : {
   10919             : #ifndef HAVE_MUPARSER
   10920             :     (void)constant;
   10921             :     (void)other;
   10922             :     return ThrowIfNotMuparser();
   10923             : #else
   10924             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GT,
   10925           2 :                                   constant, other);
   10926             : #endif
   10927             : }
   10928             : 
   10929             : /************************************************************************/
   10930             : /*                           operator>=()                               */
   10931             : /************************************************************************/
   10932             : 
   10933             : /** Return a band whose value is 1 if the pixel value of the left operand
   10934             :  * is greater or equal to the pixel value of the right operand.
   10935             :  *
   10936             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10937             :  * dataset.
   10938             :  *
   10939             :  * @since 3.12
   10940             :  */
   10941             : GDALComputedRasterBand
   10942           4 : GDALRasterBand::operator>=(const GDALRasterBand &other) const
   10943             : {
   10944             : #ifndef HAVE_MUPARSER
   10945             :     (void)other;
   10946             :     return ThrowIfNotMuparser();
   10947             : #else
   10948           4 :     ThrowIfNotSameDimensions(*this, other);
   10949             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   10950           3 :                                   *this, other);
   10951             : #endif
   10952             : }
   10953             : 
   10954             : /************************************************************************/
   10955             : /*                           operator>=()                               */
   10956             : /************************************************************************/
   10957             : 
   10958             : /** Return a band whose value is 1 if the pixel value of the left operand
   10959             :  * is greater or equal to the constant.
   10960             :  *
   10961             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10962             :  * dataset.
   10963             :  *
   10964             :  * @since 3.12
   10965             :  */
   10966           3 : GDALComputedRasterBand GDALRasterBand::operator>=(double constant) const
   10967             : {
   10968             : #ifndef HAVE_MUPARSER
   10969             :     (void)constant;
   10970             :     return ThrowIfNotMuparser();
   10971             : #else
   10972             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   10973           3 :                                   *this, constant);
   10974             : #endif
   10975             : }
   10976             : 
   10977             : /************************************************************************/
   10978             : /*                           operator>=()                               */
   10979             : /************************************************************************/
   10980             : 
   10981             : /** Return a band whose value is 1 if the constant is greater or equal to
   10982             :  * the pixel value of the right operand.
   10983             :  *
   10984             :  * The resulting band is lazy evaluated. A reference is taken on the input
   10985             :  * dataset.
   10986             :  *
   10987             :  * @since 3.12
   10988             :  */
   10989           2 : GDALComputedRasterBand operator>=(double constant, const GDALRasterBand &other)
   10990             : {
   10991             : #ifndef HAVE_MUPARSER
   10992             :     (void)constant;
   10993             :     (void)other;
   10994             :     return ThrowIfNotMuparser();
   10995             : #else
   10996             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_GE,
   10997           2 :                                   constant, other);
   10998             : #endif
   10999             : }
   11000             : 
   11001             : /************************************************************************/
   11002             : /*                           operator<()                                */
   11003             : /************************************************************************/
   11004             : 
   11005             : /** Return a band whose value is 1 if the pixel value of the left operand
   11006             :  * is lesser than the pixel value of the right operand.
   11007             :  *
   11008             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11009             :  * dataset.
   11010             :  *
   11011             :  * @since 3.12
   11012             :  */
   11013             : GDALComputedRasterBand
   11014           3 : GDALRasterBand::operator<(const GDALRasterBand &other) const
   11015             : {
   11016             : #ifndef HAVE_MUPARSER
   11017             :     (void)other;
   11018             :     return ThrowIfNotMuparser();
   11019             : #else
   11020           3 :     ThrowIfNotSameDimensions(*this, other);
   11021             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11022           2 :                                   *this, other);
   11023             : #endif
   11024             : }
   11025             : 
   11026             : /************************************************************************/
   11027             : /*                           operator<()                                */
   11028             : /************************************************************************/
   11029             : 
   11030             : /** Return a band whose value is 1 if the pixel value of the left operand
   11031             :  * is lesser than the constant.
   11032             :  *
   11033             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11034             :  * dataset.
   11035             :  *
   11036             :  * @since 3.12
   11037             :  */
   11038           3 : GDALComputedRasterBand GDALRasterBand::operator<(double constant) const
   11039             : {
   11040             : #ifndef HAVE_MUPARSER
   11041             :     (void)constant;
   11042             :     return ThrowIfNotMuparser();
   11043             : #else
   11044             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11045           3 :                                   *this, constant);
   11046             : #endif
   11047             : }
   11048             : 
   11049             : /************************************************************************/
   11050             : /*                           operator<()                                */
   11051             : /************************************************************************/
   11052             : 
   11053             : /** Return a band whose value is 1 if the constant is lesser than the pixel
   11054             :  * value of the right operand.
   11055             :  *
   11056             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11057             :  * dataset.
   11058             :  *
   11059             :  * @since 3.12
   11060             :  */
   11061           2 : GDALComputedRasterBand operator<(double constant, const GDALRasterBand &other)
   11062             : {
   11063             : #ifndef HAVE_MUPARSER
   11064             :     (void)constant;
   11065             :     (void)other;
   11066             :     return ThrowIfNotMuparser();
   11067             : #else
   11068             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LT,
   11069           2 :                                   constant, other);
   11070             : #endif
   11071             : }
   11072             : 
   11073             : /************************************************************************/
   11074             : /*                           operator<=()                               */
   11075             : /************************************************************************/
   11076             : 
   11077             : /** Return a band whose value is 1 if the pixel value of the left operand
   11078             :  * is lesser or equal to the pixel value of the right operand.
   11079             :  *
   11080             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11081             :  * dataset.
   11082             :  *
   11083             :  * @since 3.12
   11084             :  */
   11085             : GDALComputedRasterBand
   11086           4 : GDALRasterBand::operator<=(const GDALRasterBand &other) const
   11087             : {
   11088             : #ifndef HAVE_MUPARSER
   11089             :     (void)other;
   11090             :     return ThrowIfNotMuparser();
   11091             : #else
   11092           4 :     ThrowIfNotSameDimensions(*this, other);
   11093             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11094           3 :                                   *this, other);
   11095             : #endif
   11096             : }
   11097             : 
   11098             : /************************************************************************/
   11099             : /*                           operator<=()                               */
   11100             : /************************************************************************/
   11101             : 
   11102             : /** Return a band whose value is 1 if the pixel value of the left operand
   11103             :  * is lesser or equal to the constant.
   11104             :  *
   11105             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11106             :  * dataset.
   11107             :  *
   11108             :  * @since 3.12
   11109             :  */
   11110           3 : GDALComputedRasterBand GDALRasterBand::operator<=(double constant) const
   11111             : {
   11112             : #ifndef HAVE_MUPARSER
   11113             :     (void)constant;
   11114             :     return ThrowIfNotMuparser();
   11115             : #else
   11116             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11117           3 :                                   *this, constant);
   11118             : #endif
   11119             : }
   11120             : 
   11121             : /************************************************************************/
   11122             : /*                           operator<=()                               */
   11123             : /************************************************************************/
   11124             : 
   11125             : /** Return a band whose value is 1 if the constant is lesser or equal to
   11126             :  * the pixel value of the right operand.
   11127             :  *
   11128             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11129             :  * dataset.
   11130             :  *
   11131             :  * @since 3.12
   11132             :  */
   11133           2 : GDALComputedRasterBand operator<=(double constant, const GDALRasterBand &other)
   11134             : {
   11135             : #ifndef HAVE_MUPARSER
   11136             :     (void)constant;
   11137             :     (void)other;
   11138             :     return ThrowIfNotMuparser();
   11139             : #else
   11140             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LE,
   11141           2 :                                   constant, other);
   11142             : #endif
   11143             : }
   11144             : 
   11145             : /************************************************************************/
   11146             : /*                           operator==()                               */
   11147             : /************************************************************************/
   11148             : 
   11149             : /** Return a band whose value is 1 if the pixel value of the left operand
   11150             :  * is equal to the pixel value of the right operand.
   11151             :  *
   11152             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11153             :  * dataset.
   11154             :  *
   11155             :  * @since 3.12
   11156             :  */
   11157             : GDALComputedRasterBand
   11158           3 : GDALRasterBand::operator==(const GDALRasterBand &other) const
   11159             : {
   11160             : #ifndef HAVE_MUPARSER
   11161             :     (void)other;
   11162             :     return ThrowIfNotMuparser();
   11163             : #else
   11164           3 :     ThrowIfNotSameDimensions(*this, other);
   11165             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   11166           2 :                                   *this, other);
   11167             : #endif
   11168             : }
   11169             : 
   11170             : /************************************************************************/
   11171             : /*                           operator==()                               */
   11172             : /************************************************************************/
   11173             : 
   11174             : /** Return a band whose value is 1 if the pixel value of the left operand
   11175             :  * is equal to the constant.
   11176             :  *
   11177             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11178             :  * dataset.
   11179             :  *
   11180             :  * @since 3.12
   11181             :  */
   11182           8 : GDALComputedRasterBand GDALRasterBand::operator==(double constant) const
   11183             : {
   11184             : #ifndef HAVE_MUPARSER
   11185             :     (void)constant;
   11186             :     return ThrowIfNotMuparser();
   11187             : #else
   11188             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   11189           8 :                                   *this, constant);
   11190             : #endif
   11191             : }
   11192             : 
   11193             : /************************************************************************/
   11194             : /*                           operator==()                               */
   11195             : /************************************************************************/
   11196             : 
   11197             : /** Return a band whose value is 1 if the constant is equal to
   11198             :  * the pixel value of the right operand.
   11199             :  *
   11200             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11201             :  * dataset.
   11202             :  *
   11203             :  * @since 3.12
   11204             :  */
   11205           2 : GDALComputedRasterBand operator==(double constant, const GDALRasterBand &other)
   11206             : {
   11207             : #ifndef HAVE_MUPARSER
   11208             :     (void)constant;
   11209             :     (void)other;
   11210             :     return ThrowIfNotMuparser();
   11211             : #else
   11212             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_EQ,
   11213           2 :                                   constant, other);
   11214             : #endif
   11215             : }
   11216             : 
   11217             : /************************************************************************/
   11218             : /*                           operator!=()                               */
   11219             : /************************************************************************/
   11220             : 
   11221             : /** Return a band whose value is 1 if the pixel value of the left operand
   11222             :  * is different from the pixel value of the right operand.
   11223             :  *
   11224             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11225             :  * dataset.
   11226             :  *
   11227             :  * @since 3.12
   11228             :  */
   11229             : GDALComputedRasterBand
   11230           3 : GDALRasterBand::operator!=(const GDALRasterBand &other) const
   11231             : {
   11232             : #ifndef HAVE_MUPARSER
   11233             :     (void)other;
   11234             :     return ThrowIfNotMuparser();
   11235             : #else
   11236           3 :     ThrowIfNotSameDimensions(*this, other);
   11237             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   11238           2 :                                   *this, other);
   11239             : #endif
   11240             : }
   11241             : 
   11242             : /************************************************************************/
   11243             : /*                           operator!=()                               */
   11244             : /************************************************************************/
   11245             : 
   11246             : /** Return a band whose value is 1 if the pixel value of the left operand
   11247             :  * is different from the constant.
   11248             :  *
   11249             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11250             :  * dataset.
   11251             :  *
   11252             :  * @since 3.12
   11253             :  */
   11254           6 : GDALComputedRasterBand GDALRasterBand::operator!=(double constant) const
   11255             : {
   11256             : #ifndef HAVE_MUPARSER
   11257             :     (void)constant;
   11258             :     return ThrowIfNotMuparser();
   11259             : #else
   11260             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   11261           6 :                                   *this, constant);
   11262             : #endif
   11263             : }
   11264             : 
   11265             : /************************************************************************/
   11266             : /*                           operator!=()                               */
   11267             : /************************************************************************/
   11268             : 
   11269             : /** Return a band whose value is 1 if the constant is different from
   11270             :  * the pixel value of the right operand.
   11271             :  *
   11272             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11273             :  * dataset.
   11274             :  *
   11275             :  * @since 3.12
   11276             :  */
   11277           2 : GDALComputedRasterBand operator!=(double constant, const GDALRasterBand &other)
   11278             : {
   11279             : #ifndef HAVE_MUPARSER
   11280             :     (void)constant;
   11281             :     (void)other;
   11282             :     return ThrowIfNotMuparser();
   11283             : #else
   11284             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   11285           2 :                                   constant, other);
   11286             : #endif
   11287             : }
   11288             : 
   11289             : #if defined(__GNUC__)
   11290             : #pragma GCC diagnostic push
   11291             : #pragma GCC diagnostic ignored "-Weffc++"
   11292             : #endif
   11293             : 
   11294             : /************************************************************************/
   11295             : /*                           operator&&()                               */
   11296             : /************************************************************************/
   11297             : 
   11298             : /** Return a band whose value is 1 if the pixel value of the left and right
   11299             :  * operands is true.
   11300             :  *
   11301             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11302             :  * dataset.
   11303             :  *
   11304             :  * @since 3.12
   11305             :  */
   11306             : GDALComputedRasterBand
   11307           3 : GDALRasterBand::operator&&(const GDALRasterBand &other) const
   11308             : {
   11309             : #ifndef HAVE_MUPARSER
   11310             :     (void)other;
   11311             :     return ThrowIfNotMuparser();
   11312             : #else
   11313           3 :     ThrowIfNotSameDimensions(*this, other);
   11314             :     return GDALComputedRasterBand(
   11315           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, other);
   11316             : #endif
   11317             : }
   11318             : 
   11319             : /************************************************************************/
   11320             : /*                           operator&&()                               */
   11321             : /************************************************************************/
   11322             : 
   11323             : /** Return a band whose value is 1 if the pixel value of the left operand
   11324             :  * is true, as well as the constant
   11325             :  *
   11326             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11327             :  * dataset.
   11328             :  *
   11329             :  * @since 3.12
   11330             :  */
   11331           2 : GDALComputedRasterBand GDALRasterBand::operator&&(bool constant) const
   11332             : {
   11333             : #ifndef HAVE_MUPARSER
   11334             :     (void)constant;
   11335             :     return ThrowIfNotMuparser();
   11336             : #else
   11337             :     return GDALComputedRasterBand(
   11338           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, *this, constant);
   11339             : #endif
   11340             : }
   11341             : 
   11342             : /************************************************************************/
   11343             : /*                           operator&&()                               */
   11344             : /************************************************************************/
   11345             : 
   11346             : /** Return a band whose value is 1 if the constant is true, as well as
   11347             :  * the pixel value of the right operand.
   11348             :  *
   11349             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11350             :  * dataset.
   11351             :  *
   11352             :  * @since 3.12
   11353             :  */
   11354           2 : GDALComputedRasterBand operator&&(bool constant, const GDALRasterBand &other)
   11355             : {
   11356             : #ifndef HAVE_MUPARSER
   11357             :     (void)constant;
   11358             :     (void)other;
   11359             :     return ThrowIfNotMuparser();
   11360             : #else
   11361             :     return GDALComputedRasterBand(
   11362           2 :         GDALComputedRasterBand::Operation::OP_LOGICAL_AND, constant, other);
   11363             : #endif
   11364             : }
   11365             : 
   11366             : /************************************************************************/
   11367             : /*                           operator||()                               */
   11368             : /************************************************************************/
   11369             : 
   11370             : /** Return a band whose value is 1 if the pixel value of the left or right
   11371             :  * operands is true.
   11372             :  *
   11373             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11374             :  * dataset.
   11375             :  *
   11376             :  * @since 3.12
   11377             :  */
   11378             : GDALComputedRasterBand
   11379           4 : GDALRasterBand::operator||(const GDALRasterBand &other) const
   11380             : {
   11381             : #ifndef HAVE_MUPARSER
   11382             :     (void)other;
   11383             :     return ThrowIfNotMuparser();
   11384             : #else
   11385           4 :     ThrowIfNotSameDimensions(*this, other);
   11386             :     return GDALComputedRasterBand(
   11387           3 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, other);
   11388             : #endif
   11389             : }
   11390             : 
   11391             : /************************************************************************/
   11392             : /*                           operator||()                               */
   11393             : /************************************************************************/
   11394             : 
   11395             : /** Return a band whose value is 1 if the pixel value of the left operand
   11396             :  * is true, or if the constant is true
   11397             :  *
   11398             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11399             :  * dataset.
   11400             :  *
   11401             :  * @since 3.12
   11402             :  */
   11403           4 : GDALComputedRasterBand GDALRasterBand::operator||(bool constant) const
   11404             : {
   11405             : #ifndef HAVE_MUPARSER
   11406             :     (void)constant;
   11407             :     return ThrowIfNotMuparser();
   11408             : #else
   11409             :     return GDALComputedRasterBand(
   11410           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, *this, constant);
   11411             : #endif
   11412             : }
   11413             : 
   11414             : /************************************************************************/
   11415             : /*                           operator||()                               */
   11416             : /************************************************************************/
   11417             : 
   11418             : /** Return a band whose value is 1 if the constant is true, or
   11419             :  * the pixel value of the right operand is true
   11420             :  *
   11421             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11422             :  * dataset.
   11423             :  *
   11424             :  * @since 3.12
   11425             :  */
   11426           4 : GDALComputedRasterBand operator||(bool constant, const GDALRasterBand &other)
   11427             : {
   11428             : #ifndef HAVE_MUPARSER
   11429             :     (void)constant;
   11430             :     (void)other;
   11431             :     return ThrowIfNotMuparser();
   11432             : #else
   11433             :     return GDALComputedRasterBand(
   11434           4 :         GDALComputedRasterBand::Operation::OP_LOGICAL_OR, constant, other);
   11435             : #endif
   11436             : }
   11437             : 
   11438             : #if defined(__GNUC__)
   11439             : #pragma GCC diagnostic pop
   11440             : #endif
   11441             : 
   11442             : /************************************************************************/
   11443             : /*                            operator!()                               */
   11444             : /************************************************************************/
   11445             : 
   11446             : /** Return a band whose value is the logical negation of the pixel value
   11447             :  *
   11448             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11449             :  * dataset.
   11450             :  *
   11451             :  * @since 3.12
   11452             :  */
   11453           2 : GDALComputedRasterBand GDALRasterBand::operator!() const
   11454             : {
   11455             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_NE,
   11456           2 :                                   *this, true);
   11457             : }
   11458             : 
   11459             : namespace gdal
   11460             : {
   11461             : 
   11462             : /************************************************************************/
   11463             : /*                           IfThenElse()                               */
   11464             : /************************************************************************/
   11465             : 
   11466             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   11467             :  * is not zero, or the one from elseBand otherwise.
   11468             :  *
   11469             :  * Variants of this method exits where thenBand and/or elseBand can be double
   11470             :  * values.
   11471             :  *
   11472             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11473             :  * datasets.
   11474             :  *
   11475             :  * This method is the same as the C function GDALRasterBandIfThenElse()
   11476             :  *
   11477             :  * @since 3.12
   11478             :  */
   11479           5 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   11480             :                                   const GDALRasterBand &thenBand,
   11481             :                                   const GDALRasterBand &elseBand)
   11482             : {
   11483             : #ifndef HAVE_MUPARSER
   11484             :     (void)condBand;
   11485             :     (void)thenBand;
   11486             :     (void)elseBand;
   11487             :     return ThrowIfNotMuparser();
   11488             : #else
   11489           5 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   11490           4 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   11491             :     return GDALComputedRasterBand(
   11492             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   11493           6 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   11494             : #endif
   11495             : }
   11496             : 
   11497             : //! @cond Doxygen_Suppress
   11498             : 
   11499             : /************************************************************************/
   11500             : /*                           IfThenElse()                               */
   11501             : /************************************************************************/
   11502             : 
   11503             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   11504             :  * is not zero, or the one from elseBand otherwise.
   11505             :  *
   11506             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11507             :  * datasets.
   11508             :  *
   11509             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   11510             :  * with thenBand = (condBand * 0) + thenValue
   11511             :  *
   11512             :  * @since 3.12
   11513             :  */
   11514           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   11515             :                                   double thenValue,
   11516             :                                   const GDALRasterBand &elseBand)
   11517             : {
   11518             : #ifndef HAVE_MUPARSER
   11519             :     (void)condBand;
   11520             :     (void)thenValue;
   11521             :     (void)elseBand;
   11522             :     return ThrowIfNotMuparser();
   11523             : #else
   11524           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   11525             :     auto thenBand =
   11526           1 :         (condBand * 0)
   11527           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   11528           1 :         thenValue;
   11529             :     return GDALComputedRasterBand(
   11530             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   11531           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   11532             : #endif
   11533             : }
   11534             : 
   11535             : /************************************************************************/
   11536             : /*                           IfThenElse()                               */
   11537             : /************************************************************************/
   11538             : 
   11539             : /** Return a band whose value is thenBand if the corresponding pixel in condBand
   11540             :  * is not zero, or the one from elseValue otherwise.
   11541             :  *
   11542             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11543             :  * datasets.
   11544             :  *
   11545             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   11546             :  * with elseBand = (condBand * 0) + elseValue
   11547             : 
   11548             :  * @since 3.12
   11549             :  */
   11550           1 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   11551             :                                   const GDALRasterBand &thenBand,
   11552             :                                   double elseValue)
   11553             : {
   11554             : #ifndef HAVE_MUPARSER
   11555             :     (void)condBand;
   11556             :     (void)thenBand;
   11557             :     (void)elseValue;
   11558             :     return ThrowIfNotMuparser();
   11559             : #else
   11560           1 :     GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   11561             :     auto elseBand =
   11562           1 :         (condBand * 0)
   11563           2 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   11564           1 :         elseValue;
   11565             :     return GDALComputedRasterBand(
   11566             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   11567           3 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   11568             : #endif
   11569             : }
   11570             : 
   11571             : /************************************************************************/
   11572             : /*                           IfThenElse()                               */
   11573             : /************************************************************************/
   11574             : 
   11575             : /** Return a band whose value is thenValue if the corresponding pixel in condBand
   11576             :  * is not zero, or the one from elseValue otherwise.
   11577             :  *
   11578             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11579             :  * datasets.
   11580             :  *
   11581             :  * This method is the same as the C function GDALRasterBandIfThenElse(),
   11582             :  * with thenBand = (condBand * 0) + thenValue and elseBand = (condBand * 0) + elseValue
   11583             :  *
   11584             :  * @since 3.12
   11585             :  */
   11586           3 : GDALComputedRasterBand IfThenElse(const GDALRasterBand &condBand,
   11587             :                                   double thenValue, double elseValue)
   11588             : {
   11589             : #ifndef HAVE_MUPARSER
   11590             :     (void)condBand;
   11591             :     (void)thenValue;
   11592             :     (void)elseValue;
   11593             :     return ThrowIfNotMuparser();
   11594             : #else
   11595             :     auto thenBand =
   11596           3 :         (condBand * 0)
   11597           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, thenValue, false)) +
   11598           6 :         thenValue;
   11599             :     auto elseBand =
   11600           3 :         (condBand * 0)
   11601           6 :             .AsType(GDALDataTypeUnionWithValue(GDT_Unknown, elseValue, false)) +
   11602           3 :         elseValue;
   11603             :     return GDALComputedRasterBand(
   11604             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   11605           9 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   11606             : #endif
   11607             : }
   11608             : 
   11609             : //! @endcond
   11610             : 
   11611             : }  // namespace gdal
   11612             : 
   11613             : /************************************************************************/
   11614             : /*                     GDALRasterBandIfThenElse()                       */
   11615             : /************************************************************************/
   11616             : 
   11617             : /** Return a band whose value is hThenBand if the corresponding pixel in hCondBand
   11618             :  * is not zero, or the one from hElseBand otherwise.
   11619             :  *
   11620             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11621             :  * datasets.
   11622             :  *
   11623             :  * This function is the same as the C++ method gdal::IfThenElse()
   11624             :  *
   11625             :  * @since 3.12
   11626             :  */
   11627          12 : GDALComputedRasterBandH GDALRasterBandIfThenElse(GDALRasterBandH hCondBand,
   11628             :                                                  GDALRasterBandH hThenBand,
   11629             :                                                  GDALRasterBandH hElseBand)
   11630             : {
   11631          12 :     VALIDATE_POINTER1(hCondBand, __func__, nullptr);
   11632          12 :     VALIDATE_POINTER1(hThenBand, __func__, nullptr);
   11633          12 :     VALIDATE_POINTER1(hElseBand, __func__, nullptr);
   11634             : #ifndef HAVE_MUPARSER
   11635             :     CPLError(CE_Failure, CPLE_NotSupported,
   11636             :              "Band comparison operators not available on a GDAL build without "
   11637             :              "muparser");
   11638             :     return nullptr;
   11639             : #else
   11640             : 
   11641          12 :     auto &condBand = *(GDALRasterBand::FromHandle(hCondBand));
   11642          12 :     auto &thenBand = *(GDALRasterBand::FromHandle(hThenBand));
   11643          12 :     auto &elseBand = *(GDALRasterBand::FromHandle(hElseBand));
   11644             :     try
   11645             :     {
   11646          12 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, thenBand);
   11647          11 :         GDALRasterBand::ThrowIfNotSameDimensions(condBand, elseBand);
   11648             :     }
   11649           2 :     catch (const std::exception &e)
   11650             :     {
   11651           2 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   11652           2 :         return nullptr;
   11653             :     }
   11654             :     return new GDALComputedRasterBand(
   11655             :         GDALComputedRasterBand::Operation::OP_TERNARY,
   11656          10 :         std::vector<const GDALRasterBand *>{&condBand, &thenBand, &elseBand});
   11657             : #endif
   11658             : }
   11659             : 
   11660             : /************************************************************************/
   11661             : /*                       GDALRasterBand::AsType()                       */
   11662             : /************************************************************************/
   11663             : 
   11664             : /** Cast this band to another type.
   11665             :  *
   11666             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11667             :  * dataset.
   11668             :  *
   11669             :  * This method is the same as the C function GDALRasterBandAsDataType()
   11670             :  *
   11671             :  * @since 3.12
   11672             :  */
   11673          10 : GDALComputedRasterBand GDALRasterBand::AsType(GDALDataType dt) const
   11674             : {
   11675          10 :     if (dt == GDT_Unknown)
   11676             :     {
   11677           1 :         throw std::runtime_error("AsType(GDT_Unknown) is not supported");
   11678             :     }
   11679             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_CAST,
   11680           9 :                                   *this, dt);
   11681             : }
   11682             : 
   11683             : /************************************************************************/
   11684             : /*                       GDALRasterBandAsDataType()                     */
   11685             : /************************************************************************/
   11686             : 
   11687             : /** Cast this band to another type.
   11688             :  *
   11689             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11690             :  * dataset.
   11691             :  *
   11692             :  * This function is the same as the C++ method GDALRasterBand::AsType()
   11693             :  *
   11694             :  * @since 3.12
   11695             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11696             :  */
   11697          16 : GDALComputedRasterBandH GDALRasterBandAsDataType(GDALRasterBandH hBand,
   11698             :                                                  GDALDataType eDT)
   11699             : {
   11700          16 :     VALIDATE_POINTER1(hBand, __func__, nullptr);
   11701          16 :     if (eDT == GDT_Unknown)
   11702             :     {
   11703           1 :         CPLError(CE_Failure, CPLE_NotSupported,
   11704             :                  "GDALRasterBandAsDataType(GDT_Unknown) not supported");
   11705           1 :         return nullptr;
   11706             :     }
   11707             :     return new GDALComputedRasterBand(
   11708             :         GDALComputedRasterBand::Operation::OP_CAST,
   11709          15 :         *(GDALRasterBand::FromHandle(hBand)), eDT);
   11710             : }
   11711             : 
   11712             : /************************************************************************/
   11713             : /*                         GetBandVector()                              */
   11714             : /************************************************************************/
   11715             : 
   11716             : static std::vector<const GDALRasterBand *>
   11717          10 : GetBandVector(size_t nBandCount, GDALRasterBandH *pahBands)
   11718             : {
   11719          10 :     std::vector<const GDALRasterBand *> bands;
   11720          27 :     for (size_t i = 0; i < nBandCount; ++i)
   11721             :     {
   11722          20 :         if (i > 0)
   11723             :         {
   11724          10 :             GDALRasterBand::ThrowIfNotSameDimensions(
   11725          10 :                 *(GDALRasterBand::FromHandle(pahBands[0])),
   11726          10 :                 *(GDALRasterBand::FromHandle(pahBands[i])));
   11727             :         }
   11728          17 :         bands.push_back(GDALRasterBand::FromHandle(pahBands[i]));
   11729             :     }
   11730           7 :     return bands;
   11731             : }
   11732             : 
   11733             : /************************************************************************/
   11734             : /*                       GDALOperationOnNBands()                        */
   11735             : /************************************************************************/
   11736             : 
   11737             : static GDALComputedRasterBandH
   11738          11 : GDALOperationOnNBands(GDALComputedRasterBand::Operation op, size_t nBandCount,
   11739             :                       GDALRasterBandH *pahBands)
   11740             : {
   11741          11 :     VALIDATE_POINTER1(pahBands, __func__, nullptr);
   11742          11 :     if (nBandCount == 0)
   11743             :     {
   11744           1 :         CPLError(CE_Failure, CPLE_AppDefined,
   11745             :                  "At least one band should be passed");
   11746           1 :         return nullptr;
   11747             :     }
   11748             : 
   11749          20 :     std::vector<const GDALRasterBand *> bands;
   11750             :     try
   11751             :     {
   11752          10 :         bands = GetBandVector(nBandCount, pahBands);
   11753             :     }
   11754           3 :     catch (const std::exception &e)
   11755             :     {
   11756           3 :         CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
   11757           3 :         return nullptr;
   11758             :     }
   11759           7 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(op, bands));
   11760             : }
   11761             : 
   11762             : /************************************************************************/
   11763             : /*                       GDALMaximumOfNBands()                          */
   11764             : /************************************************************************/
   11765             : 
   11766             : /** Return a band whose each pixel value is the maximum of the corresponding
   11767             :  * pixel values in the input bands.
   11768             :  *
   11769             :  * The resulting band is lazy evaluated. A reference is taken on input
   11770             :  * datasets.
   11771             :  *
   11772             :  * This function is the same as the C ++ method gdal::max()
   11773             :  *
   11774             :  * @since 3.12
   11775             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11776             :  */
   11777           4 : GDALComputedRasterBandH GDALMaximumOfNBands(size_t nBandCount,
   11778             :                                             GDALRasterBandH *pahBands)
   11779             : {
   11780           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MAX,
   11781           4 :                                  nBandCount, pahBands);
   11782             : }
   11783             : 
   11784             : /************************************************************************/
   11785             : /*                               gdal::max()                            */
   11786             : /************************************************************************/
   11787             : 
   11788             : namespace gdal
   11789             : {
   11790             : /** Return a band whose each pixel value is the maximum of the corresponding
   11791             :  * pixel values in the inputs (bands or constants)
   11792             :  *
   11793             :  * The resulting band is lazy evaluated. A reference is taken on input
   11794             :  * datasets.
   11795             :  *
   11796             :  * Two or more bands can be passed.
   11797             :  *
   11798             :  * This method is the same as the C function GDALMaximumOfNBands()
   11799             :  *
   11800             :  * @since 3.12
   11801             :  * @throw std::runtime_error if bands do not have the same dimensions.
   11802             :  */
   11803           1 : GDALComputedRasterBand max(const GDALRasterBand &first,
   11804             :                            const GDALRasterBand &second)
   11805             : {
   11806           1 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   11807             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MAX,
   11808           1 :                                   first, second);
   11809             : }
   11810             : }  // namespace gdal
   11811             : 
   11812             : /************************************************************************/
   11813             : /*                     GDALRasterBandMaxConstant()                      */
   11814             : /************************************************************************/
   11815             : 
   11816             : /** Return a band whose each pixel value is the maximum of the corresponding
   11817             :  * pixel values in the input band and the constant.
   11818             :  *
   11819             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11820             :  * dataset.
   11821             :  *
   11822             :  * This function is the same as the C ++ method gdal::max()
   11823             :  *
   11824             :  * @since 3.12
   11825             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11826             :  */
   11827           2 : GDALComputedRasterBandH GDALRasterBandMaxConstant(GDALRasterBandH hBand,
   11828             :                                                   double dfConstant)
   11829             : {
   11830           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   11831             :         GDALComputedRasterBand::Operation::OP_MAX,
   11832           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   11833           6 :         dfConstant));
   11834             : }
   11835             : 
   11836             : /************************************************************************/
   11837             : /*                       GDALMinimumOfNBands()                          */
   11838             : /************************************************************************/
   11839             : 
   11840             : /** Return a band whose each pixel value is the minimum of the corresponding
   11841             :  * pixel values in the input bands.
   11842             :  *
   11843             :  * The resulting band is lazy evaluated. A reference is taken on input
   11844             :  * datasets.
   11845             :  *
   11846             :  * This function is the same as the C ++ method gdal::min()
   11847             :  *
   11848             :  * @since 3.12
   11849             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11850             :  */
   11851           4 : GDALComputedRasterBandH GDALMinimumOfNBands(size_t nBandCount,
   11852             :                                             GDALRasterBandH *pahBands)
   11853             : {
   11854           4 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MIN,
   11855           4 :                                  nBandCount, pahBands);
   11856             : }
   11857             : 
   11858             : /************************************************************************/
   11859             : /*                               gdal::min()                            */
   11860             : /************************************************************************/
   11861             : 
   11862             : namespace gdal
   11863             : {
   11864             : /** Return a band whose each pixel value is the minimum of the corresponding
   11865             :  * pixel values in the inputs (bands or constants)
   11866             :  *
   11867             :  * The resulting band is lazy evaluated. A reference is taken on input
   11868             :  * datasets.
   11869             :  *
   11870             :  * Two or more bands can be passed.
   11871             :  *
   11872             :  * This method is the same as the C function GDALMinimumOfNBands()
   11873             :  *
   11874             :  * @since 3.12
   11875             :  * @throw std::runtime_error if bands do not have the same dimensions.
   11876             :  */
   11877           0 : GDALComputedRasterBand min(const GDALRasterBand &first,
   11878             :                            const GDALRasterBand &second)
   11879             : {
   11880           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   11881             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MIN,
   11882           0 :                                   first, second);
   11883             : }
   11884             : }  // namespace gdal
   11885             : 
   11886             : /************************************************************************/
   11887             : /*                     GDALRasterBandMinConstant()                      */
   11888             : /************************************************************************/
   11889             : 
   11890             : /** Return a band whose each pixel value is the minimum of the corresponding
   11891             :  * pixel values in the input band and the constant.
   11892             :  *
   11893             :  * The resulting band is lazy evaluated. A reference is taken on the input
   11894             :  * dataset.
   11895             :  *
   11896             :  * This function is the same as the C ++ method gdal::min()
   11897             :  *
   11898             :  * @since 3.12
   11899             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11900             :  */
   11901           2 : GDALComputedRasterBandH GDALRasterBandMinConstant(GDALRasterBandH hBand,
   11902             :                                                   double dfConstant)
   11903             : {
   11904           2 :     return GDALRasterBand::ToHandle(new GDALComputedRasterBand(
   11905             :         GDALComputedRasterBand::Operation::OP_MIN,
   11906           4 :         std::vector<const GDALRasterBand *>{GDALRasterBand::FromHandle(hBand)},
   11907           6 :         dfConstant));
   11908             : }
   11909             : 
   11910             : /************************************************************************/
   11911             : /*                         GDALMeanOfNBands()                           */
   11912             : /************************************************************************/
   11913             : 
   11914             : /** Return a band whose each pixel value is the arithmetic mean of the
   11915             :  * corresponding pixel values in the input bands.
   11916             :  *
   11917             :  * The resulting band is lazy evaluated. A reference is taken on input
   11918             :  * datasets.
   11919             :  *
   11920             :  * This function is the same as the C ++ method gdal::mean()
   11921             :  *
   11922             :  * @since 3.12
   11923             :  * @return a handle to free with GDALComputedRasterBandRelease(), or nullptr if error.
   11924             :  */
   11925           3 : GDALComputedRasterBandH GDALMeanOfNBands(size_t nBandCount,
   11926             :                                          GDALRasterBandH *pahBands)
   11927             : {
   11928           3 :     return GDALOperationOnNBands(GDALComputedRasterBand::Operation::OP_MEAN,
   11929           3 :                                  nBandCount, pahBands);
   11930             : }
   11931             : 
   11932             : /************************************************************************/
   11933             : /*                              gdal::mean()                            */
   11934             : /************************************************************************/
   11935             : 
   11936             : namespace gdal
   11937             : {
   11938             : 
   11939             : /** Return a band whose each pixel value is the arithmetic mean of the
   11940             :  * corresponding pixel values in the input bands.
   11941             :  *
   11942             :  * The resulting band is lazy evaluated. A reference is taken on input
   11943             :  * datasets.
   11944             :  *
   11945             :  * Two or more bands can be passed.
   11946             :  *
   11947             :  * This method is the same as the C function GDALMeanOfNBands()
   11948             :  *
   11949             :  * @since 3.12
   11950             :  * @throw std::runtime_error if bands do not have the same dimensions.
   11951             :  */
   11952           0 : GDALComputedRasterBand mean(const GDALRasterBand &first,
   11953             :                             const GDALRasterBand &second)
   11954             : {
   11955           0 :     GDALRasterBand::ThrowIfNotSameDimensions(first, second);
   11956             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_MEAN,
   11957           0 :                                   first, second);
   11958             : }
   11959             : }  // namespace gdal
   11960             : 
   11961             : /************************************************************************/
   11962             : /*                              gdal::abs()                             */
   11963             : /************************************************************************/
   11964             : 
   11965             : namespace gdal
   11966             : {
   11967             : 
   11968             : /** Return a band whose each pixel value is the absolute value (or module
   11969             :  * for complex data type) of the corresponding pixel value in the input band.
   11970             :  *
   11971             :  * The resulting band is lazy evaluated. A reference is taken on input
   11972             :  * datasets.
   11973             :  *
   11974             :  * @since 3.12
   11975             :  */
   11976           1 : GDALComputedRasterBand abs(const GDALRasterBand &band)
   11977             : {
   11978             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   11979           1 :                                   band);
   11980             : }
   11981             : }  // namespace gdal
   11982             : 
   11983             : /************************************************************************/
   11984             : /*                             gdal::fabs()                             */
   11985             : /************************************************************************/
   11986             : 
   11987             : namespace gdal
   11988             : {
   11989             : 
   11990             : /** Return a band whose each pixel value is the absolute value (or module
   11991             :  * for complex data type) of the corresponding pixel value in the input band.
   11992             :  *
   11993             :  * The resulting band is lazy evaluated. A reference is taken on input
   11994             :  * datasets.
   11995             :  *
   11996             :  * @since 3.12
   11997             :  */
   11998           1 : GDALComputedRasterBand fabs(const GDALRasterBand &band)
   11999             : {
   12000             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_ABS,
   12001           1 :                                   band);
   12002             : }
   12003             : }  // namespace gdal
   12004             : 
   12005             : /************************************************************************/
   12006             : /*                             gdal::sqrt()                             */
   12007             : /************************************************************************/
   12008             : 
   12009             : namespace gdal
   12010             : {
   12011             : 
   12012             : /** Return a band whose each pixel value is the square root of the
   12013             :  * corresponding pixel value in the input band.
   12014             :  *
   12015             :  * The resulting band is lazy evaluated. A reference is taken on input
   12016             :  * datasets.
   12017             :  *
   12018             :  * @since 3.12
   12019             :  */
   12020           1 : GDALComputedRasterBand sqrt(const GDALRasterBand &band)
   12021             : {
   12022             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_SQRT,
   12023           1 :                                   band);
   12024             : }
   12025             : }  // namespace gdal
   12026             : 
   12027             : /************************************************************************/
   12028             : /*                             gdal::log()                              */
   12029             : /************************************************************************/
   12030             : 
   12031             : namespace gdal
   12032             : {
   12033             : 
   12034             : /** Return a band whose each pixel value is the natural logarithm of the
   12035             :  * corresponding pixel value in the input band.
   12036             :  *
   12037             :  * The resulting band is lazy evaluated. A reference is taken on input
   12038             :  * datasets.
   12039             :  *
   12040             :  * @since 3.12
   12041             :  */
   12042           1 : GDALComputedRasterBand log(const GDALRasterBand &band)
   12043             : {
   12044             : #ifndef HAVE_MUPARSER
   12045             :     (void)band;
   12046             :     return ThrowIfNotMuparser();
   12047             : #else
   12048             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG,
   12049           1 :                                   band);
   12050             : #endif
   12051             : }
   12052             : }  // namespace gdal
   12053             : 
   12054             : /************************************************************************/
   12055             : /*                             gdal::log10()                            */
   12056             : /************************************************************************/
   12057             : 
   12058             : namespace gdal
   12059             : {
   12060             : 
   12061             : /** Return a band whose each pixel value is the logarithm base 10 of the
   12062             :  * corresponding pixel value in the input band.
   12063             :  *
   12064             :  * The resulting band is lazy evaluated. A reference is taken on input
   12065             :  * datasets.
   12066             :  *
   12067             :  * @since 3.12
   12068             :  */
   12069           1 : GDALComputedRasterBand log10(const GDALRasterBand &band)
   12070             : {
   12071             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_LOG10,
   12072           1 :                                   band);
   12073             : }
   12074             : }  // namespace gdal
   12075             : 
   12076             : /************************************************************************/
   12077             : /*                             gdal::pow()                              */
   12078             : /************************************************************************/
   12079             : 
   12080             : namespace gdal
   12081             : {
   12082             : 
   12083             : #ifndef DOXYGEN_SKIP
   12084             : /** Return a band whose each pixel value is the constant raised to the power of
   12085             :  * the corresponding pixel value in the input band.
   12086             :  *
   12087             :  * The resulting band is lazy evaluated. A reference is taken on input
   12088             :  * datasets.
   12089             :  *
   12090             :  * @since 3.12
   12091             :  */
   12092           1 : GDALComputedRasterBand pow(double constant, const GDALRasterBand &band)
   12093             : {
   12094             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12095           1 :                                   constant, band);
   12096             : }
   12097             : #endif
   12098             : 
   12099             : }  // namespace gdal
   12100             : 
   12101             : /************************************************************************/
   12102             : /*                             gdal::pow()                              */
   12103             : /************************************************************************/
   12104             : 
   12105             : namespace gdal
   12106             : {
   12107             : 
   12108             : /** Return a band whose each pixel value is the the corresponding pixel value
   12109             :  * in the input band raised to the power of the constant.
   12110             :  *
   12111             :  * The resulting band is lazy evaluated. A reference is taken on input
   12112             :  * datasets.
   12113             :  *
   12114             :  * @since 3.12
   12115             :  */
   12116           1 : GDALComputedRasterBand pow(const GDALRasterBand &band, double constant)
   12117             : {
   12118             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12119           1 :                                   band, constant);
   12120             : }
   12121             : }  // namespace gdal
   12122             : 
   12123             : /************************************************************************/
   12124             : /*                             gdal::pow()                              */
   12125             : /************************************************************************/
   12126             : 
   12127             : namespace gdal
   12128             : {
   12129             : 
   12130             : #ifndef DOXYGEN_SKIP
   12131             : /** Return a band whose each pixel value is the the corresponding pixel value
   12132             :  * in the input band1 raised to the power of the corresponding pixel value
   12133             :  * in the input band2
   12134             :  *
   12135             :  * The resulting band is lazy evaluated. A reference is taken on input
   12136             :  * datasets.
   12137             :  *
   12138             :  * @since 3.12
   12139             :  * @throw std::runtime_error if bands do not have the same dimensions.
   12140             :  */
   12141           2 : GDALComputedRasterBand pow(const GDALRasterBand &band1,
   12142             :                            const GDALRasterBand &band2)
   12143             : {
   12144             : #ifndef HAVE_MUPARSER
   12145             :     (void)band1;
   12146             :     (void)band2;
   12147             :     return ThrowIfNotMuparser();
   12148             : #else
   12149           2 :     GDALRasterBand::ThrowIfNotSameDimensions(band1, band2);
   12150             :     return GDALComputedRasterBand(GDALComputedRasterBand::Operation::OP_POW,
   12151           1 :                                   band1, band2);
   12152             : #endif
   12153             : }
   12154             : #endif
   12155             : }  // namespace gdal

Generated by: LCOV version 1.14