LCOV - code coverage report
Current view: top level - gcore/multidim - gdalmultidim_array_regularly_spaced.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 68 76 89.5 %
Date: 2026-04-15 22:10:00 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Name:     gdalmultidim_array_regularly_spaced.cpp
       4             :  * Project:  GDAL Core
       5             :  * Purpose:  GDALMDArray::IsRegularlySpaced() and GDALMDArrayRegularlySpaced implementation
       6             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2019, Even Rouault <even.rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gdal_multidim.h"
      15             : 
      16             : #include <algorithm>
      17             : 
      18             : /************************************************************************/
      19             : /*                         IsRegularlySpaced()                          */
      20             : /************************************************************************/
      21             : 
      22             : /** Returns whether an array is a 1D regularly spaced array.
      23             :  *
      24             :  * @param[out] dfStart     First value in the array
      25             :  * @param[out] dfIncrement Increment/spacing between consecutive values.
      26             :  * @return true if the array is regularly spaced.
      27             :  */
      28         359 : bool GDALMDArray::IsRegularlySpaced(double &dfStart, double &dfIncrement) const
      29             : {
      30         359 :     dfStart = 0;
      31         359 :     dfIncrement = 0;
      32         359 :     if (GetDimensionCount() != 1 || GetDataType().GetClass() != GEDTC_NUMERIC)
      33           0 :         return false;
      34         359 :     const auto nSize = GetDimensions()[0]->GetSize();
      35         359 :     if (nSize <= 1 || nSize > 10 * 1000 * 1000)
      36           2 :         return false;
      37             : 
      38         357 :     size_t nCount = static_cast<size_t>(nSize);
      39         714 :     std::vector<double> adfTmp;
      40             :     try
      41             :     {
      42         357 :         adfTmp.resize(nCount);
      43             :     }
      44           0 :     catch (const std::exception &)
      45             :     {
      46           0 :         return false;
      47             :     }
      48             : 
      49         357 :     GUInt64 anStart[1] = {0};
      50         357 :     size_t anCount[1] = {nCount};
      51             : 
      52             :     const auto IsRegularlySpacedInternal =
      53       45773 :         [&dfStart, &dfIncrement, &anCount, &adfTmp]()
      54             :     {
      55         414 :         dfStart = adfTmp[0];
      56         414 :         dfIncrement = (adfTmp[anCount[0] - 1] - adfTmp[0]) / (anCount[0] - 1);
      57         414 :         if (dfIncrement == 0)
      58             :         {
      59           3 :             return false;
      60             :         }
      61       11327 :         for (size_t i = 1; i < anCount[0]; i++)
      62             :         {
      63       10930 :             if (fabs((adfTmp[i] - adfTmp[i - 1]) - dfIncrement) >
      64       10930 :                 1e-3 * fabs(dfIncrement))
      65             :             {
      66          14 :                 return false;
      67             :             }
      68             :         }
      69         397 :         return true;
      70         357 :     };
      71             : 
      72             :     // First try with the first block(s). This can avoid excessive processing
      73             :     // time, for example with Zarr datasets.
      74             :     // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=37636 and
      75             :     // https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=39273
      76         357 :     const auto nBlockSize = GetBlockSize()[0];
      77         357 :     if (nCount >= 5 && nBlockSize <= nCount / 2)
      78             :     {
      79             :         size_t nReducedCount =
      80          60 :             std::max<size_t>(3, static_cast<size_t>(nBlockSize));
      81         188 :         while (nReducedCount < 256 && nReducedCount <= (nCount - 2) / 2)
      82         128 :             nReducedCount *= 2;
      83          60 :         anCount[0] = nReducedCount;
      84          60 :         if (!Read(anStart, anCount, nullptr, nullptr,
      85         120 :                   GDALExtendedDataType::Create(GDT_Float64), &adfTmp[0]))
      86             :         {
      87           0 :             return false;
      88             :         }
      89          60 :         if (!IsRegularlySpacedInternal())
      90             :         {
      91           3 :             return false;
      92             :         }
      93             : 
      94             :         // Get next values
      95          57 :         anStart[0] = nReducedCount;
      96          57 :         anCount[0] = nCount - nReducedCount;
      97             :     }
      98             : 
      99         354 :     if (!Read(anStart, anCount, nullptr, nullptr,
     100         708 :               GDALExtendedDataType::Create(GDT_Float64),
     101         354 :               &adfTmp[static_cast<size_t>(anStart[0])]))
     102             :     {
     103           0 :         return false;
     104             :     }
     105             : 
     106         354 :     return IsRegularlySpacedInternal();
     107             : }
     108             : 
     109             : //! @cond Doxygen_Suppress
     110             : 
     111         388 : GDALMDArrayRegularlySpaced::GDALMDArrayRegularlySpaced(
     112             :     const std::string &osParentName, const std::string &osName,
     113             :     const std::shared_ptr<GDALDimension> &poDim, double dfStart,
     114         388 :     double dfIncrement, double dfOffsetInIncrement)
     115             :     : GDALAbstractMDArray(osParentName, osName),
     116             :       GDALMDArray(osParentName, osName), m_dfStart(dfStart),
     117             :       m_dfIncrement(dfIncrement), m_dfOffsetInIncrement(dfOffsetInIncrement),
     118         776 :       m_dims{poDim}
     119             : {
     120         388 : }
     121             : 
     122         388 : std::shared_ptr<GDALMDArrayRegularlySpaced> GDALMDArrayRegularlySpaced::Create(
     123             :     const std::string &osParentName, const std::string &osName,
     124             :     const std::shared_ptr<GDALDimension> &poDim, double dfStart,
     125             :     double dfIncrement, double dfOffsetInIncrement)
     126             : {
     127             :     auto poArray = std::make_shared<GDALMDArrayRegularlySpaced>(
     128         388 :         osParentName, osName, poDim, dfStart, dfIncrement, dfOffsetInIncrement);
     129         388 :     poArray->SetSelf(poArray);
     130         388 :     return poArray;
     131             : }
     132             : 
     133             : const std::vector<std::shared_ptr<GDALDimension>> &
     134        1892 : GDALMDArrayRegularlySpaced::GetDimensions() const
     135             : {
     136        1892 :     return m_dims;
     137             : }
     138             : 
     139         683 : const GDALExtendedDataType &GDALMDArrayRegularlySpaced::GetDataType() const
     140             : {
     141         683 :     return m_dt;
     142             : }
     143             : 
     144             : std::vector<std::shared_ptr<GDALAttribute>>
     145           8 : GDALMDArrayRegularlySpaced::GetAttributes(CSLConstList) const
     146             : {
     147           8 :     return m_attributes;
     148             : }
     149             : 
     150           0 : void GDALMDArrayRegularlySpaced::AddAttribute(
     151             :     const std::shared_ptr<GDALAttribute> &poAttr)
     152             : {
     153           0 :     m_attributes.emplace_back(poAttr);
     154           0 : }
     155             : 
     156         248 : bool GDALMDArrayRegularlySpaced::IRead(
     157             :     const GUInt64 *arrayStartIdx, const size_t *count, const GInt64 *arrayStep,
     158             :     const GPtrDiff_t *bufferStride, const GDALExtendedDataType &bufferDataType,
     159             :     void *pDstBuffer) const
     160             : {
     161         248 :     GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
     162        4690 :     for (size_t i = 0; i < count[0]; i++)
     163             :     {
     164        4442 :         const double dfVal =
     165        4442 :             m_dfStart +
     166        4442 :             (arrayStartIdx[0] + i * static_cast<double>(arrayStep[0]) +
     167        4442 :              m_dfOffsetInIncrement) *
     168        4442 :                 m_dfIncrement;
     169        4442 :         GDALExtendedDataType::CopyValue(&dfVal, m_dt, pabyDstBuffer,
     170             :                                         bufferDataType);
     171        4442 :         pabyDstBuffer += bufferStride[0] * bufferDataType.GetSize();
     172             :     }
     173         248 :     return true;
     174             : }
     175             : 
     176         268 : bool GDALMDArrayRegularlySpaced::IsRegularlySpaced(double &dfStart,
     177             :                                                    double &dfIncrement) const
     178             : {
     179         268 :     dfStart = m_dfStart + m_dfOffsetInIncrement * m_dfIncrement;
     180         268 :     dfIncrement = m_dfIncrement;
     181         268 :     return true;
     182             : }
     183             : 
     184             : //! @endcond

Generated by: LCOV version 1.14