LCOV - code coverage report
Current view: top level - gcore - gdalmultidim_rat.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 205 222 92.3 %
Date: 2025-10-21 22:35:35 Functions: 32 32 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Name:     gdalmultidim_rat.cpp
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  GDALCreateRasterAttributeTableFromMDArrays() implementation
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Even Rouault <even.rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #include "gdal_priv.h"
      14             : #include "gdal_rat.h"
      15             : #include "gdalmultidim_priv.h"
      16             : 
      17             : /************************************************************************/
      18             : /*                 GDALRasterAttributeTableFromMDArrays()               */
      19             : /************************************************************************/
      20             : 
      21             : class GDALRasterAttributeTableFromMDArrays final
      22             :     : public GDALRasterAttributeTable
      23             : {
      24             :     const GDALRATTableType m_eTableType;
      25             :     const std::vector<std::shared_ptr<GDALMDArray>> m_apoArrays;
      26             :     const std::vector<GDALRATFieldUsage> m_aeUsages;
      27             : 
      28             :     mutable std::string m_osTmp{};
      29             :     mutable std::vector<GByte> m_abyWKB{};
      30             : 
      31             :   public:
      32             :     GDALRasterAttributeTableFromMDArrays(
      33             :         GDALRATTableType eTableType,
      34             :         const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
      35             :         const std::vector<GDALRATFieldUsage> &aeUsages);
      36             : 
      37             :     //
      38             :     GDALRasterAttributeTable *Clone() const override;
      39             : 
      40             :     //
      41          41 :     int GetColumnCount() const override
      42             :     {
      43          41 :         return static_cast<int>(m_apoArrays.size());
      44             :     }
      45             : 
      46           3 :     const char *GetNameOfCol(int iCol) const override
      47             :     {
      48           3 :         if (iCol < 0 || iCol >= GetColumnCount())
      49           2 :             return nullptr;
      50           1 :         return m_apoArrays[iCol]->GetName().c_str();
      51             :     }
      52             : 
      53             :     //
      54           9 :     GDALRATFieldUsage GetUsageOfCol(int iCol) const override
      55             :     {
      56           9 :         if (iCol < 0 || iCol >= GetColumnCount() || m_aeUsages.empty())
      57           3 :             return GFU_Generic;
      58           6 :         return m_aeUsages[iCol];
      59             :     }
      60             : 
      61             :     //
      62           5 :     GDALRATFieldType GetTypeOfCol(int iCol) const override
      63             :     {
      64           5 :         if (iCol < 0 || iCol >= GetColumnCount())
      65           2 :             return GFT_Integer;
      66           3 :         switch (m_apoArrays[iCol]->GetDataType().GetNumericDataType())
      67             :         {
      68           1 :             case GDT_Int8:
      69             :             case GDT_Byte:
      70             :             case GDT_UInt16:
      71             :             case GDT_Int16:
      72             :             case GDT_Int32:
      73           1 :                 return GFT_Integer;
      74           1 :             case GDT_UInt32:
      75             :             case GDT_Int64:
      76             :             case GDT_UInt64:
      77             :             case GDT_Float16:
      78             :             case GDT_Float32:
      79             :             case GDT_Float64:
      80           1 :                 return GFT_Real;
      81           1 :             default:
      82           1 :                 break;
      83             :         }
      84           1 :         return GFT_String;
      85             :     }
      86             : 
      87             :     //
      88           2 :     int GetColOfUsage(GDALRATFieldUsage eUsage) const override
      89             :     {
      90           2 :         const int nColCount = GetColumnCount();
      91           6 :         for (int i = 0; i < nColCount; i++)
      92             :         {
      93           5 :             if (GetUsageOfCol(i) == eUsage)
      94           1 :                 return i;
      95             :         }
      96             : 
      97           1 :         return -1;
      98             :     }
      99             : 
     100             :     //
     101          32 :     int GetRowCount() const override
     102             :     {
     103          32 :         return static_cast<int>(m_apoArrays[0]->GetDimensions()[0]->GetSize());
     104             :     }
     105             : 
     106             :     //
     107           4 :     const char *GetValueAsString(int iRow, int iField) const override
     108             :     {
     109           6 :         if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
     110           2 :             iField >= GetColumnCount())
     111           2 :             return nullptr;
     112             : 
     113           2 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
     114           2 :         const size_t count[1] = {1};
     115           2 :         const GInt64 arrayStep[1] = {1};
     116           2 :         const GPtrDiff_t bufferStride[1] = {1};
     117           2 :         char *pszStr = nullptr;
     118           2 :         void *pDstBuffer = &pszStr;
     119           4 :         if (!m_apoArrays[iField]->Read(
     120             :                 arrayStartIdx, count, arrayStep, bufferStride,
     121           4 :                 GDALExtendedDataType::CreateString(), pDstBuffer))
     122           0 :             return nullptr;
     123           2 :         if (!pszStr)
     124           0 :             return nullptr;
     125           2 :         m_osTmp = pszStr;
     126           2 :         CPLFree(pszStr);
     127           2 :         return m_osTmp.c_str();
     128             :     }
     129             : 
     130             :     //
     131           4 :     int GetValueAsInt(int iRow, int iField) const override
     132             :     {
     133           6 :         if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
     134           2 :             iField >= GetColumnCount())
     135           2 :             return 0;
     136             : 
     137           2 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
     138           2 :         const size_t count[1] = {1};
     139           2 :         const GInt64 arrayStep[1] = {1};
     140           2 :         const GPtrDiff_t bufferStride[1] = {1};
     141           2 :         int nVal = 0;
     142           2 :         void *pDstBuffer = &nVal;
     143           4 :         if (!m_apoArrays[iField]->Read(
     144             :                 arrayStartIdx, count, arrayStep, bufferStride,
     145           4 :                 GDALExtendedDataType::Create(GDT_Int32), pDstBuffer))
     146           0 :             return 0;
     147           2 :         return nVal;
     148             :     }
     149             : 
     150             :     //
     151           4 :     double GetValueAsDouble(int iRow, int iField) const override
     152             :     {
     153           6 :         if (iRow < 0 || iRow >= GetRowCount() || iField < 0 ||
     154           2 :             iField >= GetColumnCount())
     155           2 :             return 0;
     156             : 
     157           2 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iRow)};
     158           2 :         const size_t count[1] = {1};
     159           2 :         const GInt64 arrayStep[1] = {1};
     160           2 :         const GPtrDiff_t bufferStride[1] = {1};
     161           2 :         double dfVal = 0;
     162           2 :         void *pDstBuffer = &dfVal;
     163           4 :         if (!m_apoArrays[iField]->Read(
     164             :                 arrayStartIdx, count, arrayStep, bufferStride,
     165           4 :                 GDALExtendedDataType::Create(GDT_Float64), pDstBuffer))
     166           0 :             return 0;
     167           2 :         return dfVal;
     168             :     }
     169             : 
     170             :     //
     171           1 :     bool GetValueAsBoolean(int iRow, int iField) const override
     172             :     {
     173             :         // Let ValuesIO do the work.
     174           1 :         bool bValue = false;
     175           1 :         if (const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
     176           1 :                 GF_Read, iField, iRow, 1, &bValue) != CE_None)
     177             :         {
     178           0 :             return false;
     179             :         }
     180             : 
     181           1 :         return bValue;
     182             :     }
     183             : 
     184             :     //
     185           1 :     GDALRATDateTime GetValueAsDateTime(int iRow, int iField) const override
     186             :     {
     187             :         // Let ValuesIO do the work.
     188           1 :         GDALRATDateTime dt;
     189           1 :         const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
     190             :             GF_Read, iField, iRow, 1, &dt);
     191           1 :         return dt;
     192             :     }
     193             : 
     194             :     //
     195           1 :     const GByte *GetValueAsWKBGeometry(int iRow, int iField,
     196             :                                        size_t &nWKBSize) const override
     197             :     {
     198             :         // Let ValuesIO do the work.
     199           1 :         GByte *pabyWKB = nullptr;
     200           1 :         nWKBSize = 0;
     201           1 :         const_cast<GDALRasterAttributeTableFromMDArrays *>(this)->ValuesIO(
     202             :             GF_Read, iField, iRow, 1, &pabyWKB, &nWKBSize);
     203           1 :         if (pabyWKB)
     204           0 :             m_abyWKB.assign(pabyWKB, pabyWKB + nWKBSize);
     205           1 :         CPLFree(pabyWKB);
     206           1 :         return pabyWKB ? m_abyWKB.data() : nullptr;
     207             :     }
     208             : 
     209             :     //
     210           5 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     211             :                     double *pdfData) override
     212             :     {
     213           5 :         if (eRWFlag != GF_Read)
     214             :         {
     215           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     216             :                      "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
     217             :                      "eRWFlag != GF_Read not supported");
     218           0 :             return CE_Failure;
     219             :         }
     220           9 :         if (iStartRow < 0 || iLength <= 0 ||
     221           4 :             iStartRow > GetRowCount() - iLength)
     222             :         {
     223           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
     224           2 :             return CE_Failure;
     225             :         }
     226           3 :         if (iField < 0 || iField >= GetColumnCount())
     227             :         {
     228           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
     229           2 :             return CE_Failure;
     230             :         }
     231           1 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
     232           1 :         const size_t count[1] = {static_cast<size_t>(iLength)};
     233           1 :         const GInt64 arrayStep[1] = {1};
     234           1 :         const GPtrDiff_t bufferStride[1] = {1};
     235           2 :         if (!m_apoArrays[iField]->Read(
     236             :                 arrayStartIdx, count, arrayStep, bufferStride,
     237           2 :                 GDALExtendedDataType::Create(GDT_Float64), pdfData))
     238           0 :             return CE_Failure;
     239           1 :         return CE_None;
     240             :     }
     241             : 
     242             :     //
     243          10 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     244             :                     int *pnData) override
     245             :     {
     246          10 :         if (eRWFlag != GF_Read)
     247             :         {
     248           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     249             :                      "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
     250             :                      "eRWFlag != GF_Read not supported");
     251           0 :             return CE_Failure;
     252             :         }
     253          18 :         if (iStartRow < 0 || iLength <= 0 ||
     254           8 :             iStartRow > GetRowCount() - iLength)
     255             :         {
     256           4 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
     257           4 :             return CE_Failure;
     258             :         }
     259           6 :         if (iField < 0 || iField >= GetColumnCount())
     260             :         {
     261           4 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
     262           4 :             return CE_Failure;
     263             :         }
     264           2 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
     265           2 :         const size_t count[1] = {static_cast<size_t>(iLength)};
     266           2 :         const GInt64 arrayStep[1] = {1};
     267           2 :         const GPtrDiff_t bufferStride[1] = {1};
     268           4 :         if (!m_apoArrays[iField]->Read(
     269             :                 arrayStartIdx, count, arrayStep, bufferStride,
     270           4 :                 GDALExtendedDataType::Create(GDT_Int32), pnData))
     271           0 :             return CE_Failure;
     272           2 :         return CE_None;
     273             :     }
     274             : 
     275             :     //
     276           7 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     277             :                     char **papszStrList) override
     278             :     {
     279           7 :         if (eRWFlag != GF_Read)
     280             :         {
     281           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     282             :                      "GDALRasterAttributeTableFromMDArrays::ValuesIO(): "
     283             :                      "eRWFlag != GF_Read not supported");
     284           0 :             return CE_Failure;
     285             :         }
     286          13 :         if (iStartRow < 0 || iLength <= 0 ||
     287           6 :             iStartRow > GetRowCount() - iLength)
     288             :         {
     289           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iStartRow/iLength");
     290           2 :             return CE_Failure;
     291             :         }
     292           5 :         if (iField < 0 || iField >= GetColumnCount())
     293             :         {
     294           2 :             CPLError(CE_Failure, CPLE_AppDefined, "Invalid iField");
     295           2 :             return CE_Failure;
     296             :         }
     297           3 :         const GUInt64 arrayStartIdx[1] = {static_cast<GUInt64>(iStartRow)};
     298           3 :         const size_t count[1] = {static_cast<size_t>(iLength)};
     299           3 :         const GInt64 arrayStep[1] = {1};
     300           3 :         const GPtrDiff_t bufferStride[1] = {1};
     301           6 :         if (!m_apoArrays[iField]->Read(
     302             :                 arrayStartIdx, count, arrayStep, bufferStride,
     303           6 :                 GDALExtendedDataType::CreateString(), papszStrList))
     304           0 :             return CE_Failure;
     305           3 :         return CE_None;
     306             :     }
     307             : 
     308             :     //
     309           5 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     310             :                     bool *pbData) override
     311             :     {
     312           5 :         return ValuesIOBooleanFromIntoInt(eRWFlag, iField, iStartRow, iLength,
     313           5 :                                           pbData);
     314             :     }
     315             : 
     316             :     //
     317           1 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     318             :                     GDALRATDateTime *psDateTime) override
     319             :     {
     320           1 :         return ValuesIODateTimeFromIntoString(eRWFlag, iField, iStartRow,
     321           1 :                                               iLength, psDateTime);
     322             :     }
     323             : 
     324             :     //
     325           1 :     CPLErr ValuesIO(GDALRWFlag eRWFlag, int iField, int iStartRow, int iLength,
     326             :                     GByte **ppabyWKB, size_t *pnWKBSize) override
     327             :     {
     328           1 :         return ValuesIOWKBGeometryFromIntoString(eRWFlag, iField, iStartRow,
     329           1 :                                                  iLength, ppabyWKB, pnWKBSize);
     330             :     }
     331             : 
     332             :     //
     333           1 :     CPLErr SetValue(int, int, const char *) override
     334             :     {
     335           1 :         CPLError(
     336             :             CE_Failure, CPLE_NotSupported,
     337             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     338           1 :         return CE_Failure;
     339             :     }
     340             : 
     341             :     //
     342           1 :     CPLErr SetValue(int, int, int) override
     343             :     {
     344           1 :         CPLError(
     345             :             CE_Failure, CPLE_NotSupported,
     346             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     347           1 :         return CE_Failure;
     348             :     }
     349             : 
     350             :     //
     351           1 :     CPLErr SetValue(int, int, double) override
     352             :     {
     353           1 :         CPLError(
     354             :             CE_Failure, CPLE_NotSupported,
     355             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     356           1 :         return CE_Failure;
     357             :     }
     358             : 
     359             :     //
     360           1 :     CPLErr SetValue(int, int, bool) override
     361             :     {
     362           1 :         CPLError(
     363             :             CE_Failure, CPLE_NotSupported,
     364             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     365           1 :         return CE_Failure;
     366             :     }
     367             : 
     368             :     //
     369           1 :     CPLErr SetValue(int, int, const GDALRATDateTime &) override
     370             :     {
     371           1 :         CPLError(
     372             :             CE_Failure, CPLE_NotSupported,
     373             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     374           1 :         return CE_Failure;
     375             :     }
     376             : 
     377             :     //
     378           1 :     CPLErr SetValue(int, int, const void *, size_t) override
     379             :     {
     380           1 :         CPLError(
     381             :             CE_Failure, CPLE_NotSupported,
     382             :             "GDALRasterAttributeTableFromMDArrays::SetValue(): not supported");
     383           1 :         return CE_Failure;
     384             :     }
     385             : 
     386             :     //
     387           1 :     int ChangesAreWrittenToFile() override
     388             :     {
     389           1 :         return false;
     390             :     }
     391             : 
     392             :     //
     393           1 :     CPLErr SetTableType(const GDALRATTableType) override
     394             :     {
     395           1 :         CPLError(CE_Failure, CPLE_NotSupported,
     396             :                  "GDALRasterAttributeTableFromMDArrays::SetTableType(): not "
     397             :                  "supported");
     398           1 :         return CE_Failure;
     399             :     }
     400             : 
     401             :     //
     402           1 :     void RemoveStatistics() override
     403             :     {
     404           1 :     }
     405             : 
     406             :     //
     407           1 :     GDALRATTableType GetTableType() const override
     408             :     {
     409           1 :         return m_eTableType;
     410             :     }
     411             : };
     412             : 
     413             : //
     414           1 : GDALRasterAttributeTable *GDALRasterAttributeTableFromMDArrays::Clone() const
     415             : {
     416           1 :     return new GDALRasterAttributeTableFromMDArrays(m_eTableType, m_apoArrays,
     417           1 :                                                     m_aeUsages);
     418             : }
     419             : 
     420             : /************************************************************************/
     421             : /*               GDALRasterAttributeTableFromMDArrays()                 */
     422             : /************************************************************************/
     423             : 
     424           3 : GDALRasterAttributeTableFromMDArrays::GDALRasterAttributeTableFromMDArrays(
     425             :     GDALRATTableType eTableType,
     426             :     const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
     427           3 :     const std::vector<GDALRATFieldUsage> &aeUsages)
     428           3 :     : m_eTableType(eTableType), m_apoArrays(apoArrays), m_aeUsages(aeUsages)
     429             : {
     430           3 : }
     431             : 
     432             : /************************************************************************/
     433             : /*             GDALCreateRasterAttributeTableFromMDArrays()             */
     434             : /************************************************************************/
     435             : 
     436             : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
     437             :  *
     438             :  * All arrays must be single-dimensional and be indexed by the same dimension.
     439             :  *
     440             :  * This is the same as the C function GDALCreateRasterAttributeTableFromMDArrays().
     441             :  *
     442             :  * @param eTableType RAT table type
     443             :  * @param apoArrays Vector of GDALMDArray's (none of them should be nullptr)
     444             :  * @param aeUsages Vector of GDALRATFieldUsage (of the same size as apoArrays if non-empty), or empty vector to use defaults
     445             :  * @return a new Raster Attribute Table to free with delete, or nullptr in case of error
     446             :  * @since 3.9
     447             :  */
     448           5 : GDALRasterAttributeTable *GDALCreateRasterAttributeTableFromMDArrays(
     449             :     GDALRATTableType eTableType,
     450             :     const std::vector<std::shared_ptr<GDALMDArray>> &apoArrays,
     451             :     const std::vector<GDALRATFieldUsage> &aeUsages)
     452             : {
     453           5 :     if (apoArrays.empty())
     454             :     {
     455           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     456             :                  "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays "
     457             :                  "should not be empty");
     458           1 :         return nullptr;
     459             :     }
     460           4 :     if (!aeUsages.empty() && apoArrays.size() != aeUsages.size())
     461             :     {
     462           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     463             :                  "GDALCreateRasterAttributeTableFromMDArrays(): aeUsages "
     464             :                  "should be empty or have the same size as apoArrays");
     465           0 :         return nullptr;
     466             :     }
     467          11 :     for (size_t i = 0; i < apoArrays.size(); ++i)
     468             :     {
     469           9 :         if (apoArrays[i]->GetDimensionCount() != 1)
     470             :         {
     471           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     472             :                      "GDALCreateRasterAttributeTableFromMDArrays(): "
     473             :                      "apoArrays[%d] has a dimension count != 1",
     474             :                      static_cast<int>(i));
     475           1 :             return nullptr;
     476             :         }
     477          17 :         if (i > 0 && (apoArrays[i]->GetDimensions()[0]->GetFullName() !=
     478           9 :                           apoArrays[0]->GetDimensions()[0]->GetFullName() ||
     479           4 :                       apoArrays[i]->GetDimensions()[0]->GetSize() !=
     480           4 :                           apoArrays[0]->GetDimensions()[0]->GetSize()))
     481             :         {
     482           1 :             CPLError(
     483             :                 CE_Failure, CPLE_AppDefined,
     484             :                 "GDALCreateRasterAttributeTableFromMDArrays(): apoArrays[%d] "
     485             :                 "does not have the same dimension has apoArrays[0]",
     486             :                 static_cast<int>(i));
     487           1 :             return nullptr;
     488             :         }
     489             :     }
     490             :     return new GDALRasterAttributeTableFromMDArrays(eTableType, apoArrays,
     491           2 :                                                     aeUsages);
     492             : }
     493             : 
     494             : /************************************************************************/
     495             : /*             GDALCreateRasterAttributeTableFromMDArrays()             */
     496             : /************************************************************************/
     497             : 
     498             : /** Return a virtual Raster Attribute Table from several GDALMDArray's.
     499             :  *
     500             :  * All arrays must be single-dimensional and be indexed by the same dimension.
     501             :  *
     502             :  * This is the same as the C++ method GDALCreateRasterAttributeTableFromMDArrays().
     503             :  *
     504             :  * @param eTableType RAT table type
     505             :  * @param nArrays Number of elements in ahArrays parameter
     506             :  * @param ahArrays Array of nArrays GDALMDArray's (none of them should be nullptr)
     507             :  * @param paeUsages Array of nArray GDALRATFieldUsage, or nullptr to use defaults
     508             :  * @return a new Raster Attribute Table to free with GDALDestroyRasterAttributeTable(), or nullptr in case of error
     509             :  * @since 3.9
     510             :  */
     511           5 : GDALRasterAttributeTableH GDALCreateRasterAttributeTableFromMDArrays(
     512             :     GDALRATTableType eTableType, int nArrays, const GDALMDArrayH *ahArrays,
     513             :     const GDALRATFieldUsage *paeUsages)
     514             : {
     515           5 :     VALIDATE_POINTER1(ahArrays, __func__, nullptr);
     516          10 :     std::vector<std::shared_ptr<GDALMDArray>> apoArrays;
     517          10 :     std::vector<GDALRATFieldUsage> aeUsages;
     518          14 :     for (int i = 0; i < nArrays; ++i)
     519             :     {
     520           9 :         VALIDATE_POINTER1(ahArrays[i], __func__, nullptr);
     521           9 :         apoArrays.emplace_back(ahArrays[i]->m_poImpl);
     522           9 :         if (paeUsages)
     523           3 :             aeUsages.emplace_back(paeUsages[i]);
     524             :     }
     525           5 :     return GDALRasterAttributeTable::ToHandle(
     526             :         GDALCreateRasterAttributeTableFromMDArrays(eTableType, apoArrays,
     527           5 :                                                    aeUsages));
     528             : }

Generated by: LCOV version 1.14