LCOV - code coverage report
Current view: top level - gcore - gdalmultidim_subsetdimension.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 218 228 95.6 %
Date: 2024-11-21 22:18:42 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * Name:     gdalmultidim_subsetdimension.cpp
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  GDALGroup::SubsetDimensionFromSelection() 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_pam.h"
      15             : 
      16             : #include <algorithm>
      17             : 
      18             : /************************************************************************/
      19             : /*                           GetParentName()                            */
      20             : /************************************************************************/
      21             : 
      22          42 : static std::string GetParentName(const std::string &osPath)
      23             : {
      24          42 :     if (osPath == "/" || osPath.rfind('/') == 0)
      25          36 :         return "/";
      26           6 :     return osPath.substr(0, osPath.rfind('/'));
      27             : }
      28             : 
      29             : /************************************************************************/
      30             : /*                   GDALSubsetGroupSharedResources                     */
      31             : /************************************************************************/
      32             : 
      33             : struct GDALSubsetGroupSharedResources
      34             : {
      35             :     std::shared_ptr<GDALGroup> m_poRootGroup{};  // may be nullptr
      36             :     std::string m_osDimFullName{};
      37             :     std::vector<int> m_anMapNewDimToOldDim{};
      38             :     std::string m_osSelection{};
      39             :     std::shared_ptr<GDALDimension> m_poNewDim{};
      40             :     std::shared_ptr<GDALMDArray> m_poNewIndexingVar{};
      41             : };
      42             : 
      43             : /************************************************************************/
      44             : /*                          CreateContext()                             */
      45             : /************************************************************************/
      46             : 
      47             : static std::string
      48          14 : CreateContext(const std::string &osParentContext,
      49             :               const std::shared_ptr<GDALSubsetGroupSharedResources> &poShared)
      50             : {
      51          14 :     std::string osRet(osParentContext);
      52          14 :     if (!osRet.empty())
      53           0 :         osRet += ". ";
      54          14 :     osRet += "Selection ";
      55          14 :     osRet += poShared->m_osSelection;
      56          14 :     return osRet;
      57             : }
      58             : 
      59             : /************************************************************************/
      60             : /*                           GDALSubsetGroup                            */
      61             : /************************************************************************/
      62             : 
      63             : class GDALSubsetGroup final : public GDALGroup
      64             : {
      65             :     std::shared_ptr<GDALGroup> m_poParent{};
      66             :     std::shared_ptr<GDALSubsetGroupSharedResources> m_poShared{};
      67             : 
      68           9 :     GDALSubsetGroup(
      69             :         const std::shared_ptr<GDALGroup> &poParent,
      70             :         const std::shared_ptr<GDALSubsetGroupSharedResources> &poShared)
      71          18 :         : GDALGroup(GetParentName(poParent->GetFullName()), poParent->GetName(),
      72          18 :                     CreateContext(poParent->GetContext(), poShared)),
      73          36 :           m_poParent(std::move(poParent)), m_poShared(std::move(poShared))
      74             :     {
      75           9 :     }
      76             : 
      77             :   public:
      78             :     static std::shared_ptr<GDALGroup>
      79           9 :     Create(const std::shared_ptr<GDALGroup> &poParent,
      80             :            const std::shared_ptr<GDALSubsetGroupSharedResources> &poShared)
      81             :     {
      82             :         auto poGroup = std::shared_ptr<GDALSubsetGroup>(
      83          18 :             new GDALSubsetGroup(poParent, poShared));
      84           9 :         poGroup->SetSelf(poGroup);
      85          18 :         return poGroup;
      86             :     }
      87             : 
      88             :     std::vector<std::string>
      89           2 :     GetMDArrayNames(CSLConstList papszOptions = nullptr) const override
      90             :     {
      91           2 :         return m_poParent->GetMDArrayNames(papszOptions);
      92             :     }
      93             : 
      94             :     std::shared_ptr<GDALMDArray>
      95             :     OpenMDArray(const std::string &osName,
      96             :                 CSLConstList papszOptions = nullptr) const override;
      97             : 
      98             :     std::vector<std::string>
      99           1 :     GetGroupNames(CSLConstList papszOptions = nullptr) const override
     100             :     {
     101           1 :         return m_poParent->GetGroupNames(papszOptions);
     102             :     }
     103             : 
     104             :     std::shared_ptr<GDALGroup>
     105             :     OpenGroup(const std::string &osName,
     106             :               CSLConstList papszOptions = nullptr) const override;
     107             : 
     108             :     std::vector<std::shared_ptr<GDALDimension>>
     109             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     110             : 
     111             :     std::shared_ptr<GDALAttribute>
     112           2 :     GetAttribute(const std::string &osName) const override
     113             :     {
     114           2 :         return m_poParent->GetAttribute(osName);
     115             :     }
     116             : 
     117             :     std::vector<std::shared_ptr<GDALAttribute>>
     118           1 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     119             :     {
     120           1 :         return m_poParent->GetAttributes(papszOptions);
     121             :     }
     122             : };
     123             : 
     124             : /************************************************************************/
     125             : /*                           GDALSubsetArray                            */
     126             : /************************************************************************/
     127             : 
     128             : class GDALSubsetArray final : public GDALPamMDArray
     129             : {
     130             :   private:
     131             :     std::shared_ptr<GDALMDArray> m_poParent{};
     132             :     std::shared_ptr<GDALSubsetGroupSharedResources> m_poShared{};
     133             :     std::vector<std::shared_ptr<GDALDimension>> m_apoDims{};
     134             :     std::vector<bool> m_abPatchedDim{};
     135             :     bool m_bPatchedDimIsFirst = false;
     136             : 
     137             :   protected:
     138          14 :     GDALSubsetArray(
     139             :         const std::shared_ptr<GDALMDArray> &poParent,
     140             :         const std::shared_ptr<GDALSubsetGroupSharedResources> &poShared,
     141             :         const std::string &osContext)
     142          28 :         : GDALAbstractMDArray(GetParentName(poParent->GetFullName()),
     143          14 :                               poParent->GetName()),
     144          28 :           GDALPamMDArray(GetParentName(poParent->GetFullName()),
     145          28 :                          poParent->GetName(), GDALPamMultiDim::GetPAM(poParent),
     146             :                          osContext),
     147          84 :           m_poParent(std::move(poParent)), m_poShared(std::move(poShared))
     148             :     {
     149          14 :         m_apoDims = m_poParent->GetDimensions();
     150          39 :         for (size_t i = 0; i < m_apoDims.size(); ++i)
     151             :         {
     152          25 :             auto &poDim = m_apoDims[i];
     153          25 :             if (poDim->GetFullName() == m_poShared->m_osDimFullName)
     154             :             {
     155          15 :                 m_bPatchedDimIsFirst = (i == 0);
     156          15 :                 poDim = m_poShared->m_poNewDim;
     157          15 :                 m_abPatchedDim.push_back(true);
     158             :             }
     159             :             else
     160             :             {
     161          10 :                 m_abPatchedDim.push_back(false);
     162             :             }
     163             :         }
     164          14 :     }
     165             : 
     166             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     167             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
     168             :                const GDALExtendedDataType &bufferDataType,
     169             :                void *pDstBuffer) const override;
     170             : 
     171             :   public:
     172             :     static std::shared_ptr<GDALSubsetArray>
     173          14 :     Create(const std::shared_ptr<GDALMDArray> &poParent,
     174             :            const std::shared_ptr<GDALSubsetGroupSharedResources> &poShared,
     175             :            const std::string &osContext)
     176             :     {
     177             :         auto newAr(std::shared_ptr<GDALSubsetArray>(
     178          14 :             new GDALSubsetArray(poParent, poShared, osContext)));
     179          14 :         newAr->SetSelf(newAr);
     180          14 :         return newAr;
     181             :     }
     182             : 
     183           2 :     bool IsWritable() const override
     184             :     {
     185           2 :         return false;
     186             :     }
     187             : 
     188          19 :     const std::string &GetFilename() const override
     189             :     {
     190          19 :         return m_poParent->GetFilename();
     191             :     }
     192             : 
     193             :     const std::vector<std::shared_ptr<GDALDimension>> &
     194         109 :     GetDimensions() const override
     195             :     {
     196         109 :         return m_apoDims;
     197             :     }
     198             : 
     199          62 :     const GDALExtendedDataType &GetDataType() const override
     200             :     {
     201          62 :         return m_poParent->GetDataType();
     202             :     }
     203             : 
     204           3 :     const std::string &GetUnit() const override
     205             :     {
     206           3 :         return m_poParent->GetUnit();
     207             :     }
     208             : 
     209           1 :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override
     210             :     {
     211           1 :         return m_poParent->GetSpatialRef();
     212             :     }
     213             : 
     214           8 :     const void *GetRawNoDataValue() const override
     215             :     {
     216           8 :         return m_poParent->GetRawNoDataValue();
     217             :     }
     218             : 
     219           4 :     std::vector<GUInt64> GetBlockSize() const override
     220             :     {
     221           4 :         std::vector<GUInt64> ret(m_poParent->GetBlockSize());
     222          13 :         for (size_t i = 0; i < m_apoDims.size(); ++i)
     223             :         {
     224           9 :             if (m_abPatchedDim[i])
     225           4 :                 ret[1] = 1;
     226             :         }
     227           4 :         return ret;
     228             :     }
     229             : 
     230             :     std::shared_ptr<GDALAttribute>
     231           8 :     GetAttribute(const std::string &osName) const override
     232             :     {
     233           8 :         return m_poParent->GetAttribute(osName);
     234             :     }
     235             : 
     236             :     std::vector<std::shared_ptr<GDALAttribute>>
     237           3 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     238             :     {
     239           3 :         return m_poParent->GetAttributes(papszOptions);
     240             :     }
     241             : 
     242           1 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
     243             :     {
     244           1 :         if (m_poShared->m_poRootGroup)
     245             :         {
     246           2 :             return GDALSubsetGroup::Create(m_poShared->m_poRootGroup,
     247           1 :                                            m_poShared);
     248             :         }
     249           0 :         return nullptr;
     250             :     }
     251             : };
     252             : 
     253             : /************************************************************************/
     254             : /*                            OpenMDArray()                             */
     255             : /************************************************************************/
     256             : 
     257             : std::shared_ptr<GDALMDArray>
     258          12 : GDALSubsetGroup::OpenMDArray(const std::string &osName,
     259             :                              CSLConstList papszOptions) const
     260             : {
     261          24 :     auto poArray = m_poParent->OpenMDArray(osName, papszOptions);
     262          12 :     if (poArray)
     263             :     {
     264          22 :         for (const auto &poDim : poArray->GetDimensions())
     265             :         {
     266          20 :             if (poDim->GetFullName() == m_poShared->m_osDimFullName)
     267             :             {
     268          18 :                 return GDALSubsetArray::Create(poArray, m_poShared,
     269           9 :                                                GetContext());
     270             :             }
     271             :         }
     272             :     }
     273           3 :     return poArray;
     274             : }
     275             : 
     276             : /************************************************************************/
     277             : /*                             OpenGroup()                              */
     278             : /************************************************************************/
     279             : 
     280             : std::shared_ptr<GDALGroup>
     281           5 : GDALSubsetGroup::OpenGroup(const std::string &osName,
     282             :                            CSLConstList papszOptions) const
     283             : {
     284           5 :     auto poSubGroup = m_poParent->OpenGroup(osName, papszOptions);
     285           5 :     if (poSubGroup)
     286             :     {
     287           3 :         poSubGroup = GDALSubsetGroup::Create(poSubGroup, m_poShared);
     288             :     }
     289           5 :     return poSubGroup;
     290             : }
     291             : 
     292             : /************************************************************************/
     293             : /*                             GetDimensions()                          */
     294             : /************************************************************************/
     295             : 
     296             : std::vector<std::shared_ptr<GDALDimension>>
     297           1 : GDALSubsetGroup::GetDimensions(CSLConstList papszOptions) const
     298             : {
     299           1 :     auto apoDims = m_poParent->GetDimensions(papszOptions);
     300           5 :     for (auto &poDim : apoDims)
     301             :     {
     302           4 :         if (poDim->GetFullName() == m_poShared->m_osDimFullName)
     303             :         {
     304           1 :             poDim = m_poShared->m_poNewDim;
     305             :         }
     306             :     }
     307           1 :     return apoDims;
     308             : }
     309             : 
     310             : /************************************************************************/
     311             : /*                             IRead()                                  */
     312             : /************************************************************************/
     313             : 
     314          28 : bool GDALSubsetArray::IRead(const GUInt64 *arrayStartIdx, const size_t *count,
     315             :                             const GInt64 *arrayStep,
     316             :                             const GPtrDiff_t *bufferStride,
     317             :                             const GDALExtendedDataType &bufferDataType,
     318             :                             void *pDstBuffer) const
     319             : {
     320          28 :     const auto nDims = m_apoDims.size();
     321          56 :     std::vector<GUInt64> newArrayStartIdx(nDims);
     322             :     // the +1 in nDims + 1 is to make happy -Werror=null-dereference when
     323             :     // doing newCount[0] = 1 and newArrayStep[0] = 1
     324          56 :     std::vector<size_t> newCount(nDims + 1, 1);
     325          56 :     std::vector<GInt64> newArrayStep(nDims + 1, 1);
     326          28 :     const size_t nBufferDTSize = bufferDataType.GetSize();
     327             : 
     328          28 :     if (m_bPatchedDimIsFirst)
     329             :     {
     330             :         // Optimized case when the only patched dimension is the first one.
     331           3 :         std::copy_n(arrayStartIdx, nDims, newArrayStartIdx.data());
     332           3 :         std::copy_n(count, nDims, newCount.data());
     333           3 :         std::copy_n(arrayStep, nDims, newArrayStep.data());
     334           3 :         GUInt64 arrayIdx = arrayStartIdx[0];
     335           3 :         GByte *pabyDstBuffer = static_cast<GByte *>(pDstBuffer);
     336             : #if defined(__GNUC__)
     337             : #pragma GCC diagnostic push
     338             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     339             : #endif
     340           3 :         newCount[0] = 1;
     341           3 :         newArrayStep[0] = 1;
     342             : #if defined(__GNUC__)
     343             : #pragma GCC diagnostic pop
     344             : #endif
     345           9 :         for (size_t i = 0; i < count[0]; ++i)
     346             :         {
     347           6 :             if (i > 0)
     348             :             {
     349           3 :                 if (arrayStep[0] > 0)
     350           2 :                     arrayIdx += arrayStep[0];
     351             :                 else
     352           1 :                     arrayIdx -= static_cast<GUInt64>(-arrayStep[0]);
     353           3 :                 pabyDstBuffer += bufferStride[0] * nBufferDTSize;
     354             :             }
     355           6 :             newArrayStartIdx[0] =
     356           6 :                 m_poShared->m_anMapNewDimToOldDim[static_cast<int>(arrayIdx)];
     357          12 :             if (!m_poParent->Read(newArrayStartIdx.data(), newCount.data(),
     358           6 :                                   newArrayStep.data(), bufferStride,
     359             :                                   bufferDataType, pabyDstBuffer))
     360             :             {
     361           0 :                 return false;
     362             :             }
     363             :         }
     364           3 :         return true;
     365             :     }
     366             : 
     367             :     // Slow/unoptimized case
     368          50 :     std::vector<size_t> anStackIter(nDims);
     369          50 :     std::vector<GUInt64> anStackArrayIdx(nDims);
     370          50 :     std::vector<GByte *> pabyDstBufferStack(nDims + 1);
     371             : #if defined(__GNUC__)
     372             : #pragma GCC diagnostic push
     373             : #pragma GCC diagnostic ignored "-Wnull-dereference"
     374             : #endif
     375          25 :     pabyDstBufferStack[0] = static_cast<GByte *>(pDstBuffer);
     376             : #if defined(__GNUC__)
     377             : #pragma GCC diagnostic pop
     378             : #endif
     379          25 :     size_t iDim = 0;
     380         183 : lbl_next_depth:
     381         183 :     if (iDim == nDims)
     382             :     {
     383         160 :         if (!m_poParent->Read(newArrayStartIdx.data(), newCount.data(),
     384          80 :                               newArrayStep.data(), bufferStride, bufferDataType,
     385          80 :                               pabyDstBufferStack[iDim]))
     386             :         {
     387           0 :             return false;
     388             :         }
     389             :     }
     390             :     else
     391             :     {
     392         103 :         anStackIter[iDim] = 0;
     393         103 :         anStackArrayIdx[iDim] = arrayStartIdx[iDim];
     394             :         while (true)
     395             :         {
     396         158 :             if (m_abPatchedDim[iDim])
     397             :             {
     398          84 :                 newArrayStartIdx[iDim] =
     399          84 :                     m_poShared->m_anMapNewDimToOldDim[static_cast<int>(
     400          84 :                         anStackArrayIdx[iDim])];
     401             :             }
     402             :             else
     403             :             {
     404          74 :                 newArrayStartIdx[iDim] = anStackArrayIdx[iDim];
     405             :             }
     406         158 :             ++iDim;
     407         158 :             pabyDstBufferStack[iDim] = pabyDstBufferStack[iDim - 1];
     408         158 :             goto lbl_next_depth;
     409         158 :         lbl_return_to_caller_in_loop:
     410         158 :             --iDim;
     411         158 :             ++anStackIter[iDim];
     412         158 :             if (anStackIter[iDim] == count[iDim])
     413         103 :                 break;
     414          55 :             if (arrayStep[iDim] > 0)
     415          54 :                 anStackArrayIdx[iDim] += arrayStep[iDim];
     416             :             else
     417           1 :                 anStackArrayIdx[iDim] -= -arrayStep[iDim];
     418          55 :             pabyDstBufferStack[iDim] += bufferStride[iDim] * nBufferDTSize;
     419             :         }
     420             :     }
     421         183 :     if (iDim > 0)
     422         158 :         goto lbl_return_to_caller_in_loop;
     423             : 
     424          25 :     return true;
     425             : }
     426             : 
     427             : /************************************************************************/
     428             : /*                   SubsetDimensionFromSelection()                     */
     429             : /************************************************************************/
     430             : 
     431             : /** Return a virtual group whose one dimension has been subset according to a
     432             :  * selection.
     433             :  *
     434             :  * The selection criterion is currently restricted to the form
     435             :  * "/path/to/array=numeric_value" (no spaces around equal)
     436             :  *
     437             :  * This is similar to XArray indexing by name and label on a XArray Dataset
     438             :  * using the sel() method.
     439             :  * Cf https://docs.xarray.dev/en/latest/user-guide/indexing.html#quick-overview
     440             :  *
     441             :  * For example on a EMIT L2A product
     442             :  * (https://github.com/nasa/EMIT-Data-Resources/blob/main/python/tutorials/Exploring_EMIT_L2A_Reflectance.ipynb),
     443             :  * this can be used to keep only valid bands with
     444             :  * SubsetDimensionFromSelection("/sensor_band_parameters/good_wavelengths=1")
     445             :  *
     446             :  * This is the same as the C function GDALGroupSubsetDimensionFromSelection().
     447             :  *
     448             :  * @param osSelection Selection criterion.
     449             :  * @return a virtual group, or nullptr in case of error
     450             :  * @since 3.8
     451             :  */
     452             : std::shared_ptr<GDALGroup>
     453          14 : GDALGroup::SubsetDimensionFromSelection(const std::string &osSelection) const
     454             : {
     455          28 :     auto self = std::dynamic_pointer_cast<GDALGroup>(m_pSelf.lock());
     456          14 :     if (!self)
     457             :     {
     458           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     459             :                  "Driver implementation issue: m_pSelf not set !");
     460           0 :         return nullptr;
     461             :     }
     462             : 
     463          14 :     const auto nEqualPos = osSelection.find('=');
     464          14 :     if (nEqualPos == std::string::npos)
     465             :     {
     466           2 :         CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for selection");
     467           2 :         return nullptr;
     468             :     }
     469          24 :     const auto osArrayName = osSelection.substr(0, nEqualPos);
     470          24 :     const auto osValue = osSelection.substr(nEqualPos + 1);
     471          13 :     if (CPLGetValueType(osValue.c_str()) != CPL_VALUE_INTEGER &&
     472           1 :         CPLGetValueType(osValue.c_str()) != CPL_VALUE_REAL)
     473             :     {
     474           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     475             :                  "Non-numeric value in selection criterion");
     476           1 :         return nullptr;
     477             :     }
     478          22 :     auto poArray = OpenMDArrayFromFullname(osArrayName);
     479          11 :     if (!poArray)
     480             :     {
     481           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Cannot find array %s",
     482             :                  osArrayName.c_str());
     483           1 :         return nullptr;
     484             :     }
     485          10 :     if (poArray->GetDimensionCount() != 1)
     486             :     {
     487           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     488             :                  "Array %s is not single dimensional", osArrayName.c_str());
     489           1 :         return nullptr;
     490             :     }
     491           9 :     if (poArray->GetDataType().GetClass() != GEDTC_NUMERIC)
     492             :     {
     493           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Array %s is not of numeric type",
     494             :                  osArrayName.c_str());
     495           1 :         return nullptr;
     496             :     }
     497             : 
     498           8 :     const auto nElts = poArray->GetTotalElementsCount();
     499           8 :     if (nElts > 10 * 1024 * 1024)
     500             :     {
     501           1 :         CPLError(CE_Failure, CPLE_AppDefined, "Too many values in %s",
     502             :                  osArrayName.c_str());
     503           1 :         return nullptr;
     504             :     }
     505          14 :     std::vector<double> values;
     506             :     try
     507             :     {
     508           7 :         values.resize(static_cast<size_t>(nElts));
     509             :     }
     510           0 :     catch (const std::bad_alloc &e)
     511             :     {
     512           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Out of memory: %s", e.what());
     513           0 :         return nullptr;
     514             :     }
     515           7 :     const GUInt64 startIdx[1] = {0};
     516           7 :     const size_t count[1] = {values.size()};
     517          14 :     if (!poArray->Read(startIdx, count, nullptr, nullptr,
     518          14 :                        GDALExtendedDataType::Create(GDT_Float64), &values[0],
     519           7 :                        values.data(), values.size() * sizeof(values[0])))
     520             :     {
     521           0 :         return nullptr;
     522             :     }
     523           7 :     const double dfSelectionValue = CPLAtof(osValue.c_str());
     524          14 :     std::vector<int> anMapNewDimToOldDim;
     525          77 :     for (int i = 0; i < static_cast<int>(nElts); ++i)
     526             :     {
     527          70 :         if (values[i] == dfSelectionValue)
     528           8 :             anMapNewDimToOldDim.push_back(i);
     529             :     }
     530           7 :     if (anMapNewDimToOldDim.empty())
     531             :     {
     532           1 :         CPLError(CE_Failure, CPLE_AppDefined, "No value in %s matching %f",
     533             :                  osArrayName.c_str(), dfSelectionValue);
     534           1 :         return nullptr;
     535             :     }
     536           6 :     if (anMapNewDimToOldDim.size() == nElts)
     537             :     {
     538           1 :         return self;
     539             :     }
     540             : 
     541          10 :     auto poDim = poArray->GetDimensions()[0];
     542          10 :     auto poShared = std::make_shared<GDALSubsetGroupSharedResources>();
     543           5 :     if (GetFullName() == "/")
     544           5 :         poShared->m_poRootGroup = self;
     545           5 :     poShared->m_osSelection = osSelection;
     546           5 :     poShared->m_osDimFullName = poArray->GetDimensions()[0]->GetFullName();
     547           5 :     poShared->m_anMapNewDimToOldDim = std::move(anMapNewDimToOldDim);
     548             : 
     549             :     // Create a modified dimension of reduced size
     550             :     auto poNewDim = std::make_shared<GDALDimensionWeakIndexingVar>(
     551           5 :         GetParentName(poDim->GetFullName()), poDim->GetName(), poDim->GetType(),
     552          15 :         poDim->GetDirection(), poShared->m_anMapNewDimToOldDim.size());
     553           5 :     poShared->m_poNewDim = poNewDim;
     554             : 
     555          10 :     auto poIndexingVar = poDim->GetIndexingVariable();
     556           5 :     if (poIndexingVar)
     557             :     {
     558             :         // poNewIndexingVar must be created with a different GDALSubsetGroupSharedResources
     559             :         // instance than poShared, to avoid cross reference, that would result in
     560             :         // objects not being freed !
     561             :         auto poSpecificShared =
     562          10 :             std::make_shared<GDALSubsetGroupSharedResources>();
     563           5 :         poSpecificShared->m_poRootGroup = poShared->m_poRootGroup;
     564           5 :         poSpecificShared->m_osSelection = osSelection;
     565           5 :         poSpecificShared->m_osDimFullName =
     566          10 :             poArray->GetDimensions()[0]->GetFullName();
     567           5 :         poSpecificShared->m_anMapNewDimToOldDim =
     568           5 :             poShared->m_anMapNewDimToOldDim;
     569           5 :         poSpecificShared->m_poNewDim = poNewDim;
     570             :         auto poNewIndexingVar =
     571             :             GDALSubsetArray::Create(poIndexingVar, poSpecificShared,
     572          10 :                                     CreateContext(GetContext(), poShared));
     573           5 :         poNewDim->SetIndexingVariable(poNewIndexingVar);
     574           5 :         poShared->m_poNewIndexingVar = poNewIndexingVar;
     575             :     }
     576             : 
     577           5 :     return GDALSubsetGroup::Create(self, poShared);
     578             : }

Generated by: LCOV version 1.14