LCOV - code coverage report
Current view: top level - frmts/zarr - zarr.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 238 238 100.0 %
Date: 2026-03-06 23:26:30 Functions: 84 84 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  Zarr driver
       5             :  * Author:   Even Rouault <even dot rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2021, Even Rouault <even dot rouault at spatialys.com>
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef ZARR_H
      14             : #define ZARR_H
      15             : 
      16             : #include "cpl_compressor.h"
      17             : #include "cpl_json.h"
      18             : #include "gdal_priv.h"
      19             : #include "gdal_pam_multidim.h"
      20             : #include "memmultidim.h"
      21             : 
      22             : #include <array>
      23             : #include <iterator>
      24             : #include <map>
      25             : #include <memory>
      26             : #include <mutex>
      27             : #include <numeric>
      28             : #include <set>
      29             : 
      30             : #define ZARR_DEBUG_KEY "ZARR"
      31             : 
      32             : #define CRS_ATTRIBUTE_NAME "_CRS"
      33             : 
      34             : // UUID identifying the multiscales zarr convention
      35             : // (https://github.com/zarr-conventions/multiscales)
      36             : constexpr const char *ZARR_MULTISCALES_UUID =
      37             :     "d35379db-88df-4056-af3a-620245f8e347";
      38             : 
      39             : const CPLCompressor *ZarrGetShuffleCompressor();
      40             : const CPLCompressor *ZarrGetShuffleDecompressor();
      41             : const CPLCompressor *ZarrGetQuantizeDecompressor();
      42             : const CPLCompressor *ZarrGetTIFFDecompressor();
      43             : const CPLCompressor *ZarrGetFixedScaleOffsetDecompressor();
      44             : 
      45             : /************************************************************************/
      46             : /*                          MultiplyElements()                          */
      47             : /************************************************************************/
      48             : 
      49             : /** Return the product of elements in the vector
      50             :  */
      51       69762 : template <class T> inline T MultiplyElements(const std::vector<T> &vector)
      52             : {
      53       69762 :     return std::reduce(vector.begin(), vector.end(), T{1},
      54       69762 :                        std::multiplies<T>{});
      55             : }
      56             : 
      57             : /************************************************************************/
      58             : /*                             ZarrDataset                              */
      59             : /************************************************************************/
      60             : 
      61             : class ZarrArray;
      62             : class ZarrGroupBase;
      63             : 
      64             : class ZarrDataset final : public GDALDataset
      65             : {
      66             :     friend class ZarrRasterBand;
      67             : 
      68             :     std::shared_ptr<ZarrGroupBase> m_poRootGroup{};
      69             :     CPLStringList m_aosSubdatasets{};
      70             :     GDALGeoTransform m_gt{};
      71             :     bool m_bHasGT = false;
      72             :     bool m_bSpatialProjConvention = false;
      73             :     std::shared_ptr<GDALDimension> m_poDimX{};
      74             :     std::shared_ptr<GDALDimension> m_poDimY{};
      75             :     std::shared_ptr<ZarrArray> m_poSingleArray{};
      76             : 
      77             :     static GDALDataset *OpenMultidim(const char *pszFilename, bool bUpdateMode,
      78             :                                      CSLConstList papszOpenOptions);
      79             : 
      80             :   public:
      81             :     explicit ZarrDataset(const std::shared_ptr<ZarrGroupBase> &poRootGroup);
      82             :     ~ZarrDataset() override;
      83             : 
      84             :     CPLErr FlushCache(bool bAtClosing = false) override;
      85             : 
      86             :     static GDALDataset *Open(GDALOpenInfo *poOpenInfo);
      87             :     static GDALDataset *
      88             :     CreateMultiDimensional(const char *pszFilename,
      89             :                            CSLConstList /*papszRootGroupOptions*/,
      90             :                            CSLConstList /*papszOptions*/);
      91             : 
      92             :     static GDALDataset *Create(const char *pszName, int nXSize, int nYSize,
      93             :                                int nBands, GDALDataType eType,
      94             :                                CSLConstList papszOptions);
      95             : 
      96             :     static GDALDataset *CreateCopy(const char *, GDALDataset *, int,
      97             :                                    CSLConstList papszOptions,
      98             :                                    GDALProgressFunc pfnProgress,
      99             :                                    void *pProgressData);
     100             : 
     101             :     const char *GetMetadataItem(const char *pszName,
     102             :                                 const char *pszDomain) override;
     103             :     CSLConstList GetMetadata(const char *pszDomain) override;
     104             : 
     105             :     CPLErr SetMetadata(CSLConstList papszMetadata,
     106             :                        const char *pszDomain) override;
     107             : 
     108             :     const OGRSpatialReference *GetSpatialRef() const override;
     109             :     CPLErr SetSpatialRef(const OGRSpatialReference *poSRS) override;
     110             : 
     111             :     CPLErr GetGeoTransform(GDALGeoTransform &gt) const override;
     112             :     CPLErr SetGeoTransform(const GDALGeoTransform &gt) override;
     113             : 
     114             :     std::shared_ptr<GDALGroup> GetRootGroup() const override;
     115             : 
     116             :   protected:
     117             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
     118             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
     119             :                      GDALDataType eBufType, int nBandCount,
     120             :                      BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
     121             :                      GSpacing nLineSpace, GSpacing nBandSpace,
     122             :                      GDALRasterIOExtraArg *psExtraArg) override;
     123             : };
     124             : 
     125             : /************************************************************************/
     126             : /*                            ZarrRasterBand                            */
     127             : /************************************************************************/
     128             : 
     129             : class ZarrRasterBand final : public GDALRasterBand
     130             : {
     131             :     friend class ZarrDataset;
     132             : 
     133             :     std::shared_ptr<GDALMDArray> m_poArray;
     134             :     GDALColorInterp m_eColorInterp = GCI_Undefined;
     135             : 
     136             :   protected:
     137             :     CPLErr IReadBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     138             :     CPLErr IWriteBlock(int nBlockXOff, int nBlockYOff, void *pData) override;
     139             :     CPLErr IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
     140             :                      int nYSize, void *pData, int nBufXSize, int nBufYSize,
     141             :                      GDALDataType eBufType, GSpacing nPixelSpaceBuf,
     142             :                      GSpacing nLineSpaceBuf,
     143             :                      GDALRasterIOExtraArg *psExtraArg) override;
     144             : 
     145             :   public:
     146             :     explicit ZarrRasterBand(const std::shared_ptr<GDALMDArray> &poArray);
     147             : 
     148             :     double GetNoDataValue(int *pbHasNoData) override;
     149             :     int64_t GetNoDataValueAsInt64(int *pbHasNoData) override;
     150             :     uint64_t GetNoDataValueAsUInt64(int *pbHasNoData) override;
     151             :     CPLErr SetNoDataValue(double dfNoData) override;
     152             :     CPLErr SetNoDataValueAsInt64(int64_t nNoData) override;
     153             :     CPLErr SetNoDataValueAsUInt64(uint64_t nNoData) override;
     154             :     double GetOffset(int *pbSuccess = nullptr) override;
     155             :     CPLErr SetOffset(double dfNewOffset) override;
     156             :     double GetScale(int *pbSuccess = nullptr) override;
     157             :     CPLErr SetScale(double dfNewScale) override;
     158             :     const char *GetUnitType() override;
     159             :     CPLErr SetUnitType(const char *pszNewValue) override;
     160             :     GDALColorInterp GetColorInterpretation() override;
     161             :     CPLErr SetColorInterpretation(GDALColorInterp eColorInterp) override;
     162             : };
     163             : 
     164             : /************************************************************************/
     165             : /*                         ZarrAttributeGroup()                         */
     166             : /************************************************************************/
     167             : 
     168             : class ZarrAttributeGroup
     169             : {
     170             :     // Use a MEMGroup as a convenient container for attributes.
     171             :     const bool m_bContainerIsGroup;
     172             :     std::shared_ptr<MEMGroup> m_poGroup;
     173             :     bool m_bModified = false;
     174             : 
     175             :   public:
     176             :     explicit ZarrAttributeGroup(const std::string &osParentName,
     177             :                                 bool bContainerIsGroup);
     178             : 
     179             :     bool Close();
     180             : 
     181             :     void Init(const CPLJSONObject &obj, bool bUpdatable);
     182             : 
     183        9112 :     std::shared_ptr<GDALAttribute> GetAttribute(const std::string &osName) const
     184             :     {
     185        9112 :         return m_poGroup->GetAttribute(osName);
     186             :     }
     187             : 
     188             :     std::vector<std::shared_ptr<GDALAttribute>>
     189         262 :     GetAttributes(CSLConstList papszOptions = nullptr) const
     190             :     {
     191         262 :         return m_poGroup->GetAttributes(papszOptions);
     192             :     }
     193             : 
     194             :     std::shared_ptr<GDALAttribute>
     195         229 :     CreateAttribute(const std::string &osName,
     196             :                     const std::vector<GUInt64> &anDimensions,
     197             :                     const GDALExtendedDataType &oDataType,
     198             :                     CSLConstList /* papszOptions */ = nullptr)
     199             :     {
     200         229 :         auto poAttr = m_poGroup->CreateAttribute(osName, anDimensions,
     201         229 :                                                  oDataType, nullptr);
     202         229 :         if (poAttr)
     203             :         {
     204         229 :             m_bModified = true;
     205             :         }
     206         229 :         return poAttr;
     207             :     }
     208             : 
     209          28 :     bool DeleteAttribute(const std::string &osName)
     210             :     {
     211          28 :         const bool bOK = m_poGroup->DeleteAttribute(osName, nullptr);
     212          28 :         if (bOK)
     213             :         {
     214          16 :             m_bModified = true;
     215             :         }
     216          28 :         return bOK;
     217             :     }
     218             : 
     219        4087 :     void SetUpdatable(bool bUpdatable)
     220             :     {
     221        8174 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     222        5021 :         for (auto &attr : attrs)
     223             :         {
     224        1868 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     225         934 :             if (memAttr)
     226         934 :                 memAttr->SetWritable(bUpdatable);
     227             :         }
     228        4087 :     }
     229             : 
     230         405 :     void UnsetModified()
     231             :     {
     232         405 :         m_bModified = false;
     233         810 :         auto attrs = m_poGroup->GetAttributes(nullptr);
     234         559 :         for (auto &attr : attrs)
     235             :         {
     236         308 :             auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     237         154 :             if (memAttr)
     238         154 :                 memAttr->SetModified(false);
     239             :         }
     240         405 :     }
     241             : 
     242       16238 :     bool IsModified() const
     243             :     {
     244       16238 :         if (m_bModified)
     245         261 :             return true;
     246       31954 :         const auto attrs = m_poGroup->GetAttributes(nullptr);
     247       18276 :         for (const auto &attr : attrs)
     248             :         {
     249        2330 :             const auto memAttr = std::dynamic_pointer_cast<MEMAttribute>(attr);
     250        2330 :             if (memAttr && memAttr->IsModified())
     251          31 :                 return true;
     252             :         }
     253       15946 :         return false;
     254             :     }
     255             : 
     256             :     CPLJSONObject Serialize() const;
     257             : 
     258             :     void ParentRenamed(const std::string &osNewParentFullName);
     259             : 
     260             :     void ParentDeleted();
     261             : };
     262             : 
     263             : /************************************************************************/
     264             : /*                          ZarrSharedResource                          */
     265             : /************************************************************************/
     266             : 
     267             : class ZarrSharedResource
     268             :     : public std::enable_shared_from_this<ZarrSharedResource>
     269             : {
     270             :   public:
     271             :     enum class ConsolidatedMetadataKind
     272             :     {
     273             :         NONE,
     274             :         EXTERNAL,  // Zarr V2 .zmetadata
     275             :         INTERNAL,  // Zarr V3 consolidated_metadata
     276             :     };
     277             : 
     278             :   private:
     279             :     bool m_bUpdatable = false;
     280             :     std::string m_osRootDirectoryName{};
     281             : 
     282             :     ConsolidatedMetadataKind m_eConsolidatedMetadataKind =
     283             :         ConsolidatedMetadataKind::NONE;
     284             :     CPLJSONObject m_oObjConsolidatedMetadata{};
     285             :     CPLJSONObject m_oRootAttributes{};
     286             :     bool m_bConsolidatedMetadataModified = false;
     287             : 
     288             :     std::shared_ptr<GDALPamMultiDim> m_poPAM{};
     289             :     CPLStringList m_aosOpenOptions{};
     290             :     std::weak_ptr<ZarrGroupBase> m_poWeakRootGroup{};
     291             :     std::set<std::string> m_oSetArrayInLoading{};
     292             :     std::map<std::string, std::shared_ptr<GDALMDArray>> m_oCacheIndexingVar{};
     293             :     std::string m_osKerchunkParquetPath{};
     294             : 
     295             :     explicit ZarrSharedResource(const std::string &osRootDirectoryName,
     296             :                                 bool bUpdatable);
     297             : 
     298             :     std::shared_ptr<ZarrGroupBase> OpenRootGroup();
     299             :     void InitConsolidatedMetadataIfNeeded();
     300             : 
     301             :   public:
     302             :     static std::shared_ptr<ZarrSharedResource>
     303             :     Create(const std::string &osRootDirectoryName, bool bUpdatable);
     304             : 
     305             :     ~ZarrSharedResource();
     306             : 
     307        5042 :     bool IsUpdatable() const
     308             :     {
     309        5042 :         return m_bUpdatable;
     310             :     }
     311             : 
     312          37 :     const CPLJSONObject &GetConsolidatedMetadataObj() const
     313             :     {
     314          37 :         return m_oObjConsolidatedMetadata;
     315             :     }
     316             : 
     317         305 :     bool IsConsolidatedMetadataEnabled() const
     318             :     {
     319         305 :         return m_eConsolidatedMetadataKind != ConsolidatedMetadataKind::NONE;
     320             :     }
     321             : 
     322         333 :     void EnableConsolidatedMetadata(ConsolidatedMetadataKind kind)
     323             :     {
     324         333 :         m_eConsolidatedMetadataKind = kind;
     325         333 :     }
     326             : 
     327             :     void SetZMetadataItem(const std::string &osFilename,
     328             :                           const CPLJSONObject &obj);
     329             : 
     330             :     void DeleteZMetadataItemRecursive(const std::string &osFilename);
     331             : 
     332             :     void RenameZMetadataRecursive(const std::string &osOldFilename,
     333             :                                   const std::string &osNewFilename);
     334             : 
     335        2402 :     const std::shared_ptr<GDALPamMultiDim> &GetPAM()
     336             :     {
     337        2402 :         return m_poPAM;
     338             :     }
     339             : 
     340          13 :     const std::string &GetRootDirectoryName() const
     341             :     {
     342          13 :         return m_osRootDirectoryName;
     343             :     }
     344             : 
     345        2862 :     const CPLStringList &GetOpenOptions() const
     346             :     {
     347        2862 :         return m_aosOpenOptions;
     348             :     }
     349             : 
     350        1614 :     void SetOpenOptions(CSLConstList papszOpenOptions)
     351             :     {
     352        1614 :         m_aosOpenOptions = papszOpenOptions;
     353        1614 :     }
     354             : 
     355             :     void
     356             :     UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poUpdatedDim);
     357             : 
     358             :     std::shared_ptr<ZarrGroupBase> GetRootGroup();
     359             : 
     360         108 :     const std::string &GetKerchunkParquetPath() const
     361             :     {
     362         108 :         return m_osKerchunkParquetPath;
     363             :     }
     364             : 
     365          90 :     void SetRootGroup(const std::shared_ptr<ZarrGroupBase> &poRootGroup)
     366             :     {
     367          90 :         m_poWeakRootGroup = poRootGroup;
     368          90 :     }
     369             : 
     370             :     bool AddArrayInLoading(const std::string &osZarrayFilename);
     371             :     void RemoveArrayInLoading(const std::string &osZarrayFilename);
     372             : 
     373             :     struct SetFilenameAdder
     374             :     {
     375             :         std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     376             :         const std::string m_osFilename;
     377             :         const bool m_bOK;
     378             : 
     379        1982 :         SetFilenameAdder(
     380             :             const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     381             :             const std::string &osFilename)
     382        1982 :             : m_poSharedResource(poSharedResource), m_osFilename(osFilename),
     383        1982 :               m_bOK(m_poSharedResource->AddArrayInLoading(m_osFilename))
     384             :         {
     385        1982 :         }
     386             : 
     387        1982 :         ~SetFilenameAdder()
     388        1982 :         {
     389        1982 :             if (m_bOK)
     390        1980 :                 m_poSharedResource->RemoveArrayInLoading(m_osFilename);
     391        1982 :         }
     392             : 
     393        1982 :         bool ok() const
     394             :         {
     395        1982 :             return m_bOK;
     396             :         }
     397             :     };
     398             : 
     399           8 :     void RegisterIndexingVariable(const std::string &osDimName,
     400             :                                   const std::shared_ptr<GDALMDArray> &poVar)
     401             :     {
     402           8 :         m_oCacheIndexingVar[osDimName] = poVar;
     403           8 :     }
     404             : };
     405             : 
     406             : /************************************************************************/
     407             : /*                              ZarrGroup                               */
     408             : /************************************************************************/
     409             : 
     410             : class ZarrArray;
     411             : class ZarrDimension;
     412             : 
     413             : class ZarrGroupBase CPL_NON_FINAL : public GDALGroup
     414             : {
     415             :   protected:
     416             :     friend class ZarrV2Group;
     417             :     friend class ZarrV3Group;
     418             : 
     419             :     // For ZarrV2, this is the directory of the group
     420             :     // For ZarrV3, this is the root directory of the dataset
     421             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     422             :     std::string m_osDirectoryName{};
     423             :     std::weak_ptr<ZarrGroupBase>
     424             :         m_poParent{};  // weak reference to owning parent
     425             :     std::shared_ptr<ZarrGroupBase>
     426             :         m_poParentStrongRef{};  // strong reference, used only when opening from
     427             :                                 // a subgroup
     428             :     mutable std::map<CPLString, std::shared_ptr<ZarrGroupBase>> m_oMapGroups{};
     429             :     mutable std::map<CPLString, std::shared_ptr<ZarrArray>> m_oMapMDArrays{};
     430             :     mutable std::map<CPLString, std::shared_ptr<ZarrDimension>>
     431             :         m_oMapDimensions{};
     432             :     mutable bool m_bDirectoryExplored = false;
     433             :     mutable std::set<std::string> m_oSetGroupNames{};
     434             :     mutable std::vector<std::string> m_aosGroups{};
     435             :     mutable std::set<std::string> m_oSetArrayNames{};
     436             :     mutable std::vector<std::string> m_aosArrays{};
     437             :     mutable ZarrAttributeGroup m_oAttrGroup;
     438             :     mutable bool m_bAttributesLoaded = false;
     439             :     bool m_bReadFromConsolidatedMetadata = false;
     440             :     mutable bool m_bDimensionsInstantiated = false;
     441             :     bool m_bUpdatable = false;
     442             :     bool m_bDimSizeInUpdate = false;
     443             : 
     444             :     virtual void ExploreDirectory() const = 0;
     445             :     virtual void LoadAttributes() const = 0;
     446             : 
     447        2406 :     ZarrGroupBase(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     448             :                   const std::string &osParentName, const std::string &osName)
     449        2406 :         : GDALGroup(osParentName, osName), m_poSharedResource(poSharedResource),
     450        2406 :           m_oAttrGroup(m_osFullName, /*bContainerIsGroup=*/true)
     451             :     {
     452        2406 :     }
     453             : 
     454             :   protected:
     455             :     friend class ZarrDimension;
     456             :     bool RenameDimension(const std::string &osOldName,
     457             :                          const std::string &osNewName);
     458             : 
     459             :     void NotifyChildrenOfRenaming() override;
     460             : 
     461             :     void NotifyChildrenOfDeletion() override;
     462             : 
     463             :   public:
     464             :     ~ZarrGroupBase() override;
     465             : 
     466             :     virtual bool Close();
     467             : 
     468             :     bool Flush();
     469             : 
     470             :     std::shared_ptr<GDALAttribute>
     471         408 :     GetAttribute(const std::string &osName) const override
     472             :     {
     473         408 :         LoadAttributes();
     474         408 :         return m_oAttrGroup.GetAttribute(osName);
     475             :     }
     476             : 
     477             :     std::vector<std::shared_ptr<GDALAttribute>>
     478          47 :     GetAttributes(CSLConstList papszOptions = nullptr) const override
     479             :     {
     480          47 :         LoadAttributes();
     481          47 :         return m_oAttrGroup.GetAttributes(papszOptions);
     482             :     }
     483             : 
     484             :     std::shared_ptr<GDALAttribute>
     485             :     CreateAttribute(const std::string &osName,
     486             :                     const std::vector<GUInt64> &anDimensions,
     487             :                     const GDALExtendedDataType &oDataType,
     488             :                     CSLConstList papszOptions = nullptr) override;
     489             : 
     490             :     bool DeleteAttribute(const std::string &osName,
     491             :                          CSLConstList papszOptions = nullptr) override;
     492             : 
     493             :     std::vector<std::shared_ptr<GDALDimension>>
     494             :     GetDimensions(CSLConstList papszOptions = nullptr) const override;
     495             : 
     496             :     std::shared_ptr<GDALDimension>
     497             :     CreateDimension(const std::string &osName, const std::string &osType,
     498             :                     const std::string &osDirection, GUInt64 nSize,
     499             :                     CSLConstList papszOptions = nullptr) override;
     500             : 
     501             :     std::vector<std::string>
     502             :     GetMDArrayNames(CSLConstList papszOptions = nullptr) const override;
     503             : 
     504             :     std::vector<std::string>
     505             :     GetGroupNames(CSLConstList papszOptions = nullptr) const override;
     506             : 
     507             :     virtual std::shared_ptr<ZarrGroupBase>
     508             :     OpenZarrGroup(const std::string &osName,
     509             :                   CSLConstList papszOptions = nullptr) const = 0;
     510             : 
     511             :     std::shared_ptr<GDALGroup>
     512        1432 :     OpenGroup(const std::string &osName,
     513             :               CSLConstList papszOptions = nullptr) const override
     514             :     {
     515             :         return std::static_pointer_cast<GDALGroup>(
     516        1432 :             OpenZarrGroup(osName, papszOptions));
     517             :     }
     518             : 
     519             :     bool DeleteGroup(const std::string &osName,
     520             :                      CSLConstList papszOptions = nullptr) override;
     521             : 
     522             :     std::shared_ptr<GDALMDArray>
     523        2151 :     OpenMDArray(const std::string &osName,
     524             :                 CSLConstList papszOptions = nullptr) const override
     525             :     {
     526             :         return std::static_pointer_cast<GDALMDArray>(
     527        2151 :             OpenZarrArray(osName, papszOptions));
     528             :     }
     529             : 
     530             :     bool DeleteMDArray(const std::string &osName,
     531             :                        CSLConstList papszOptions = nullptr) override;
     532             : 
     533             :     virtual std::shared_ptr<ZarrArray>
     534             :     OpenZarrArray(const std::string &osName,
     535             :                   CSLConstList papszOptions = nullptr) const = 0;
     536             : 
     537        1135 :     void SetDirectoryName(const std::string &osDirectoryName)
     538             :     {
     539        1135 :         m_osDirectoryName = osDirectoryName;
     540        1135 :     }
     541             : 
     542           9 :     const std::string &GetDirectoryName() const
     543             :     {
     544           9 :         return m_osDirectoryName;
     545             :     }
     546             : 
     547             :     void RegisterArray(const std::shared_ptr<ZarrArray> &array) const;
     548             : 
     549        2400 :     void SetUpdatable(bool bUpdatable)
     550             :     {
     551        2400 :         m_bUpdatable = bUpdatable;
     552        2400 :     }
     553             : 
     554             :     void UpdateDimensionSize(const std::shared_ptr<GDALDimension> &poDim);
     555             : 
     556             :     static bool IsValidObjectName(const std::string &osName);
     557             : 
     558             :     bool Rename(const std::string &osNewName) override;
     559             : 
     560             :     //! Returns false in case of error
     561             :     bool
     562             :     CheckArrayOrGroupWithSameNameDoesNotExist(const std::string &osName) const;
     563             : 
     564             :     void ParentRenamed(const std::string &osNewParentFullName) override;
     565             : 
     566             :     void NotifyArrayRenamed(const std::string &osOldName,
     567             :                             const std::string &osNewName);
     568             : 
     569             :     //! Return the group owning the array. Might be nullptr
     570             :     std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
     571             : 
     572        4292 :     std::shared_ptr<ZarrGroupBase> Self() const
     573             :     {
     574        4292 :         return std::dynamic_pointer_cast<ZarrGroupBase>(m_pSelf.lock());
     575             :     }
     576             : 
     577        2785 :     const ZarrAttributeGroup &GetAttributeGroup() const
     578             :     {
     579        2785 :         return m_oAttrGroup;
     580             :     }
     581             : };
     582             : 
     583             : /************************************************************************/
     584             : /*                             ZarrV2Group                              */
     585             : /************************************************************************/
     586             : 
     587             : class ZarrV2Group final : public ZarrGroupBase
     588             : {
     589             :     void ExploreDirectory() const override;
     590             :     void LoadAttributes() const override;
     591             : 
     592             :     std::shared_ptr<ZarrV2Group>
     593             :     GetOrCreateSubGroup(const std::string &osSubGroupFullname);
     594             : 
     595         997 :     ZarrV2Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     596             :                 const std::string &osParentName, const std::string &osName)
     597         997 :         : ZarrGroupBase(poSharedResource, osParentName, osName)
     598             :     {
     599         997 :     }
     600             : 
     601             :     bool Close() override;
     602             : 
     603             :   public:
     604             :     static std::shared_ptr<ZarrV2Group>
     605             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     606             :            const std::string &osParentName, const std::string &osName);
     607             : 
     608             :     ~ZarrV2Group() override;
     609             : 
     610             :     static std::shared_ptr<ZarrV2Group>
     611             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     612             :                  const std::string &osParentName, const std::string &osName,
     613             :                  const std::string &osDirectoryName);
     614             : 
     615             :     std::shared_ptr<ZarrArray>
     616             :     OpenZarrArray(const std::string &osName,
     617             :                   CSLConstList papszOptions = nullptr) const override;
     618             : 
     619             :     std::shared_ptr<ZarrGroupBase>
     620             :     OpenZarrGroup(const std::string &osName,
     621             :                   CSLConstList papszOptions = nullptr) const override;
     622             : 
     623             :     std::shared_ptr<GDALGroup>
     624             :     CreateGroup(const std::string &osName,
     625             :                 CSLConstList papszOptions = nullptr) override;
     626             : 
     627             :     std::shared_ptr<ZarrArray>
     628             :     LoadArray(const std::string &osArrayName,
     629             :               const std::string &osZarrayFilename, const CPLJSONObject &oRoot,
     630             :               bool bLoadedFromZMetadata,
     631             :               const CPLJSONObject &oAttributes) const;
     632             : 
     633             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     634             :         const std::string &osName,
     635             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     636             :         const GDALExtendedDataType &oDataType,
     637             :         CSLConstList papszOptions = nullptr) override;
     638             : 
     639             :     void InitFromConsolidatedMetadata(const CPLJSONObject &oRoot);
     640             : 
     641             :     bool InitFromZGroup(const CPLJSONObject &oRoot);
     642             : };
     643             : 
     644             : /************************************************************************/
     645             : /*                             ZarrV3Group                              */
     646             : /************************************************************************/
     647             : 
     648             : class ZarrV3Group final : public ZarrGroupBase
     649             : {
     650             :     bool m_bFileHasBeenWritten = false;
     651             : 
     652             :     void ExploreDirectory() const override;
     653             :     void LoadAttributes() const override;
     654             : 
     655             :     ZarrV3Group(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     656             :                 const std::string &osParentName, const std::string &osName,
     657             :                 const std::string &osDirectoryName);
     658             : 
     659             :     std::shared_ptr<ZarrV3Group>
     660             :     GetOrCreateSubGroup(const std::string &osSubGroupFullname);
     661             : 
     662             :     bool Close() override;
     663             : 
     664             :   public:
     665             :     ~ZarrV3Group() override;
     666             : 
     667             :     static std::shared_ptr<ZarrV3Group>
     668             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     669             :            const std::string &osParentName, const std::string &osName,
     670             :            const std::string &osDirectoryName);
     671             : 
     672             :     std::shared_ptr<ZarrArray>
     673             :     OpenZarrArray(const std::string &osName,
     674             :                   CSLConstList papszOptions = nullptr) const override;
     675             : 
     676             :     std::shared_ptr<ZarrGroupBase>
     677             :     OpenZarrGroup(const std::string &osName,
     678             :                   CSLConstList papszOptions = nullptr) const override;
     679             : 
     680             :     static std::shared_ptr<ZarrV3Group>
     681             :     CreateOnDisk(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     682             :                  const std::string &osParentFullName, const std::string &osName,
     683             :                  const std::string &osDirectoryName);
     684             : 
     685             :     std::shared_ptr<GDALGroup>
     686             :     CreateGroup(const std::string &osName,
     687             :                 CSLConstList papszOptions = nullptr) override;
     688             : 
     689             :     std::shared_ptr<ZarrArray> LoadArray(const std::string &osArrayName,
     690             :                                          const std::string &osZarrayFilename,
     691             :                                          const CPLJSONObject &oRoot) const;
     692             : 
     693             :     void GenerateMultiscalesMetadata(const char *pszResampling = nullptr);
     694             : 
     695             :     std::shared_ptr<GDALMDArray> CreateMDArray(
     696             :         const std::string &osName,
     697             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
     698             :         const GDALExtendedDataType &oDataType,
     699             :         CSLConstList papszOptions = nullptr) override;
     700             : 
     701         723 :     void SetExplored()
     702             :     {
     703         723 :         m_bDirectoryExplored = true;
     704         723 :     }
     705             : 
     706             :     void
     707             :     InitFromConsolidatedMetadata(const CPLJSONObject &oConsolidatedMetadata,
     708             :                                  const CPLJSONObject &oRootAttributes);
     709             : };
     710             : 
     711             : /************************************************************************/
     712             : /*                            ZarrDimension                             */
     713             : /************************************************************************/
     714             : 
     715             : class ZarrDimension final : public GDALDimensionWeakIndexingVar
     716             : {
     717             :     const bool m_bUpdatable;
     718             :     std::weak_ptr<ZarrGroupBase> m_poParentGroup;
     719             :     bool m_bModified = false;
     720             :     bool m_bXArrayDim = false;
     721             : 
     722             :   public:
     723        5042 :     ZarrDimension(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     724             :                   const std::weak_ptr<ZarrGroupBase> &poParentGroup,
     725             :                   const std::string &osParentName, const std::string &osName,
     726             :                   const std::string &osType, const std::string &osDirection,
     727             :                   GUInt64 nSize)
     728        5042 :         : GDALDimensionWeakIndexingVar(osParentName, osName, osType,
     729             :                                        osDirection, nSize),
     730        5042 :           m_bUpdatable(poSharedResource->IsUpdatable()),
     731       10084 :           m_poParentGroup(poParentGroup)
     732             :     {
     733        5042 :     }
     734             : 
     735             :     bool Rename(const std::string &osNewName) override;
     736             : 
     737        9722 :     bool IsModified() const
     738             :     {
     739        9722 :         return m_bModified;
     740             :     }
     741             : 
     742        1627 :     void SetXArrayDimension()
     743             :     {
     744        1627 :         m_bXArrayDim = true;
     745        1627 :     }
     746             : 
     747       14389 :     bool IsXArrayDimension() const
     748             :     {
     749       14389 :         return m_bXArrayDim;
     750             :     }
     751             : };
     752             : 
     753             : /************************************************************************/
     754             : /*                              DtypeElt()                              */
     755             : /************************************************************************/
     756             : 
     757             : struct DtypeElt
     758             : {
     759             :     enum class NativeType
     760             :     {
     761             :         BOOLEAN,
     762             :         UNSIGNED_INT,
     763             :         SIGNED_INT,
     764             :         IEEEFP,
     765             :         COMPLEX_IEEEFP,
     766             :         STRING_ASCII,
     767             :         STRING_UNICODE
     768             :     };
     769             : 
     770             :     NativeType nativeType = NativeType::BOOLEAN;
     771             :     size_t nativeOffset = 0;
     772             :     size_t nativeSize = 0;
     773             :     bool needByteSwapping = false;
     774             :     bool gdalTypeIsApproxOfNative = false;
     775             :     GDALExtendedDataType gdalType = GDALExtendedDataType::Create(GDT_Unknown);
     776             :     size_t gdalOffset = 0;
     777             :     size_t gdalSize = 0;
     778             : };
     779             : 
     780             : /************************************************************************/
     781             : /*                      ZarrByteVectorQuickResize                       */
     782             : /************************************************************************/
     783             : 
     784             : /* std::vector<GByte> with quick resizing (ie that doesn't zero out when
     785             :  * growing back to a previously reached greater size).
     786             :  */
     787      186477 : class ZarrByteVectorQuickResize
     788             : {
     789             :     std::vector<GByte> m_oVec{};
     790             :     size_t m_nSize = 0;
     791             : 
     792             :   public:
     793      117033 :     ZarrByteVectorQuickResize() = default;
     794             : 
     795             :     ZarrByteVectorQuickResize(const ZarrByteVectorQuickResize &) = delete;
     796             :     ZarrByteVectorQuickResize &
     797             :     operator=(const ZarrByteVectorQuickResize &) = delete;
     798             : 
     799       68870 :     ZarrByteVectorQuickResize(ZarrByteVectorQuickResize &&) = default;
     800             :     ZarrByteVectorQuickResize &
     801             :     operator=(ZarrByteVectorQuickResize &&) = default;
     802             : 
     803      222636 :     void resize(size_t nNewSize)
     804             :     {
     805      222636 :         if (nNewSize > m_oVec.size())
     806       69095 :             m_oVec.resize(nNewSize);
     807      222636 :         m_nSize = nNewSize;
     808      222636 :     }
     809             : 
     810        1603 :     inline void clear()
     811             :     {
     812        1603 :         m_nSize = 0;
     813        1603 :     }
     814             : 
     815         154 :     inline std::vector<GByte>::iterator begin()
     816             :     {
     817         154 :         return m_oVec.begin();
     818             :     }
     819             : 
     820        1188 :     inline std::vector<GByte>::const_iterator begin() const
     821             :     {
     822        1188 :         return m_oVec.begin();
     823             :     }
     824             : 
     825        1031 :     inline std::vector<GByte>::iterator end()
     826             :     {
     827        1031 :         return m_oVec.begin() + m_nSize;
     828             :     }
     829             : 
     830         184 :     inline std::vector<GByte>::const_iterator end() const
     831             :     {
     832         184 :         return m_oVec.begin() + m_nSize;
     833             :     }
     834             : 
     835             :     template <class InputIt>
     836             :     inline std::vector<GByte>::iterator
     837         877 :     insert(std::vector<GByte>::const_iterator pos, InputIt first, InputIt last)
     838             :     {
     839         877 :         const size_t nCount = std::distance(first, last);
     840         877 :         const auto &oVec = m_oVec;
     841         877 :         const size_t nStart = std::distance(oVec.begin(), pos);
     842         877 :         if (nStart == m_nSize && nStart + nCount <= m_oVec.size())
     843             :         {
     844             :             // Insert at end of user-visible vector, but fully inside the
     845             :             // container vector. We can just copy
     846         591 :             std::copy(first, last, m_oVec.begin() + nStart);
     847         591 :             m_nSize += nCount;
     848         591 :             return m_oVec.begin() + nStart;
     849             :         }
     850             :         else
     851             :         {
     852             :             // Generic case
     853         286 :             auto ret = m_oVec.insert(pos, first, last);
     854         286 :             m_nSize += nCount;
     855         286 :             return ret;
     856             :         }
     857             :     }
     858             : 
     859      294869 :     inline bool empty() const
     860             :     {
     861      294869 :         return m_nSize == 0;
     862             :     }
     863             : 
     864      257188 :     inline size_t size() const
     865             :     {
     866      257188 :         return m_nSize;
     867             :     }
     868             : 
     869       47055 :     inline size_t capacity() const
     870             :     {
     871             :         // Not a typo: the capacity of this object is the size
     872             :         // of the underlying std::vector
     873       47055 :         return m_oVec.size();
     874             :     }
     875             : 
     876      163038 :     inline GByte *data()
     877             :     {
     878      163038 :         return m_oVec.data();
     879             :     }
     880             : 
     881       65011 :     inline const GByte *data() const
     882             :     {
     883       65011 :         return m_oVec.data();
     884             :     }
     885             : 
     886        1898 :     inline GByte operator[](size_t idx) const
     887             :     {
     888        1898 :         return m_oVec[idx];
     889             :     }
     890             : 
     891       61251 :     inline GByte &operator[](size_t idx)
     892             :     {
     893       61251 :         return m_oVec[idx];
     894             :     }
     895             : };
     896             : 
     897             : /************************************************************************/
     898             : /*                              ZarrArray                               */
     899             : /************************************************************************/
     900             : 
     901             : class ZarrArray CPL_NON_FINAL : public GDALPamMDArray
     902             : {
     903             :   protected:
     904             :     std::shared_ptr<ZarrSharedResource> m_poSharedResource;
     905             : 
     906             :     //! weak reference to owning parent
     907             :     std::weak_ptr<ZarrGroupBase> m_poParent{};
     908             : 
     909             :     const std::vector<std::shared_ptr<GDALDimension>> m_aoDims;
     910             :     const GDALExtendedDataType m_oType;
     911             : 
     912             :     //! Array (several in case of compound data type) of native Zarr data types
     913             :     const std::vector<DtypeElt> m_aoDtypeElts;
     914             : 
     915             :     /** m_anOuterBlockSize is the chunk_size at the Zarr array level, which
     916             :      * determines the files/objects
     917             :      */
     918             :     const std::vector<GUInt64> m_anOuterBlockSize;
     919             : 
     920             :     /** m_anInnerBlockSize is the inner most block size of sharding, which
     921             :      * is the one exposed to the user with GetBlockSize()
     922             :      * When no sharding is involved m_anOuterBlockSize == m_anInnerBlockSize
     923             :      * Note that m_anOuterBlockSize might be equal to m_anInnerBlockSize, even
     924             :      * when sharding is involved, and it is actually a common use case.
     925             :      */
     926             :     const std::vector<GUInt64> m_anInnerBlockSize;
     927             : 
     928             :     /** m_anCountInnerBlockInOuter[i] = m_anOuterBlockSize[i] / m_anInnerBlockSize[i]
     929             :      * That is the number of inner blocks in one outer block
     930             :      */
     931             :     const std::vector<GUInt64> m_anCountInnerBlockInOuter;
     932             : 
     933             :     //! Total number of inner chunks in the array
     934             :     const uint64_t m_nTotalInnerChunkCount;
     935             : 
     936             :     //! Size in bytes of a inner chunk using the Zarr native data type
     937             :     const size_t m_nInnerBlockSizeBytes;
     938             : 
     939             :     mutable ZarrAttributeGroup m_oAttrGroup;
     940             : 
     941             :     const bool m_bUseOptimizedCodePaths;
     942             : 
     943             :     CPLStringList m_aosStructuralInfo{};
     944             :     CPLJSONObject m_dtype{};
     945             :     GByte *m_pabyNoData = nullptr;
     946             :     std::string m_osDimSeparator{"."};
     947             :     std::string m_osFilename{};
     948             :     mutable ZarrByteVectorQuickResize m_abyRawBlockData{};
     949             :     mutable ZarrByteVectorQuickResize m_abyDecodedBlockData{};
     950             : 
     951             :     /** Inner block index of the cached block
     952             :      * i.e. m_anCachedBlockIndices[i] < cpl::round_up(m_aoDims[i]->GetSize, m_anInnerBlockSize[i])
     953             :      */
     954             :     mutable std::vector<uint64_t> m_anCachedBlockIndices{};
     955             : 
     956             :     mutable bool m_bCachedBlockValid = false;
     957             :     mutable bool m_bCachedBlockEmpty = false;
     958             :     mutable bool m_bDirtyBlock = false;
     959             :     mutable std::shared_ptr<OGRSpatialReference> m_poSRS{};
     960             :     mutable bool m_bAllocateWorkingBuffersDone = false;
     961             :     mutable bool m_bWorkingBuffersOK = false;
     962             :     bool m_bUpdatable = false;
     963             :     bool m_bDefinitionModified = false;
     964             :     bool m_bSRSModified = false;
     965             :     bool m_bNew = false;
     966             :     std::string m_osUnit{};
     967             :     bool m_bUnitModified = false;
     968             :     double m_dfOffset = 0.0;
     969             :     bool m_bHasOffset = false;
     970             :     bool m_bOffsetModified = false;
     971             :     double m_dfScale = 1.0;
     972             :     bool m_bHasScale = false;
     973             :     bool m_bScaleModified = false;
     974             :     std::weak_ptr<ZarrGroupBase> m_poGroupWeak{};
     975             :     mutable bool m_bHasTriedBlockCachePresenceArray = false;
     976             :     mutable std::shared_ptr<GDALMDArray> m_poBlockCachePresenceArray{};
     977             :     mutable std::mutex m_oMutex{};
     978             :     CPLStringList m_aosCreationOptions{};
     979             : 
     980             :     struct CachedBlock
     981             :     {
     982             :         ZarrByteVectorQuickResize abyDecoded{};
     983             :     };
     984             : 
     985             :     mutable std::map<std::vector<uint64_t>, CachedBlock> m_oChunkCache{};
     986             : 
     987             :     //! Region covered by the last IAdviseRead (for subset check in IRead)
     988             :     mutable std::vector<GUInt64> m_anCachedAdviseReadStart{};
     989             :     mutable std::vector<size_t> m_anCachedAdviseReadCount{};
     990             : 
     991             :     static uint64_t
     992             :     ComputeBlockCount(const std::string &osName,
     993             :                       const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
     994             :                       const std::vector<GUInt64> &anBlockSize);
     995             : 
     996             :     ZarrArray(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
     997             :               const std::shared_ptr<ZarrGroupBase> &poParent,
     998             :               const std::string &osName,
     999             :               const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1000             :               const GDALExtendedDataType &oType,
    1001             :               const std::vector<DtypeElt> &aoDtypeElts,
    1002             :               const std::vector<GUInt64> &anOuterBlockSize,
    1003             :               const std::vector<GUInt64> &anInnerBlockSize);
    1004             : 
    1005             :     virtual bool LoadBlockData(const uint64_t *blockIndices,
    1006             :                                bool &bMissingBlockOut) const = 0;
    1007             : 
    1008             :     virtual bool AllocateWorkingBuffers() const = 0;
    1009             : 
    1010             :     void SerializeNumericNoData(CPLJSONObject &oRoot) const;
    1011             : 
    1012             :     void DeallocateDecodedBlockData();
    1013             : 
    1014             :     virtual std::string GetDataDirectory() const = 0;
    1015             : 
    1016             :     virtual CPLStringList
    1017             :     GetChunkIndicesFromFilename(const char *pszFilename) const = 0;
    1018             : 
    1019             :     virtual bool FlushDirtyBlock() const = 0;
    1020             : 
    1021             :     std::shared_ptr<GDALMDArray> OpenBlockPresenceCache(bool bCanCreate) const;
    1022             : 
    1023             :     void NotifyChildrenOfRenaming() override;
    1024             : 
    1025             :     void NotifyChildrenOfDeletion() override;
    1026             : 
    1027             :     static void EncodeElt(const std::vector<DtypeElt> &elts, const GByte *pSrc,
    1028             :                           GByte *pDst);
    1029             : 
    1030             :     // Disable copy constructor and assignment operator
    1031             :     ZarrArray(const ZarrArray &) = delete;
    1032             :     ZarrArray &operator=(const ZarrArray &) = delete;
    1033             : 
    1034             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1035             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1036             :                const GDALExtendedDataType &bufferDataType,
    1037             :                void *pDstBuffer) const override;
    1038             : 
    1039             :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    1040             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1041             :                 const GDALExtendedDataType &bufferDataType,
    1042             :                 const void *pSrcBuffer) override;
    1043             : 
    1044             :     bool IsEmptyBlock(const ZarrByteVectorQuickResize &abyBlock) const;
    1045             : 
    1046             :     bool IAdviseReadCommon(const GUInt64 *arrayStartIdx, const size_t *count,
    1047             :                            CSLConstList papszOptions,
    1048             :                            std::vector<uint64_t> &anIndicesCur,
    1049             :                            int &nThreadsMax,
    1050             :                            std::vector<uint64_t> &anReqBlocksIndices,
    1051             :                            size_t &nReqBlocks) const;
    1052             : 
    1053             :     CPLJSONObject SerializeSpecialAttributes();
    1054             : 
    1055             :     virtual std::string
    1056             :     BuildChunkFilename(const uint64_t *blockIndices) const = 0;
    1057             : 
    1058             :     bool SetStatistics(bool bApproxStats, double dfMin, double dfMax,
    1059             :                        double dfMean, double dfStdDev, GUInt64 nValidCount,
    1060             :                        CSLConstList papszOptions) override;
    1061             : 
    1062             :     bool IsBlockMissingFromCacheInfo(const std::string &osFilename,
    1063             :                                      const uint64_t *blockIndices) const;
    1064             : 
    1065             :     virtual CPLStringList GetRawBlockInfoInfo() const = 0;
    1066             : 
    1067             :   public:
    1068             :     ~ZarrArray() override;
    1069             : 
    1070             :     static bool ParseChunkSize(const CPLJSONArray &oChunks,
    1071             :                                const GDALExtendedDataType &oType,
    1072             :                                std::vector<GUInt64> &anBlockSize);
    1073             : 
    1074             :     static bool FillBlockSize(
    1075             :         const std::vector<std::shared_ptr<GDALDimension>> &aoDimensions,
    1076             :         const GDALExtendedDataType &oDataType,
    1077             :         std::vector<GUInt64> &anBlockSize, CSLConstList papszOptions);
    1078             : 
    1079         187 :     bool IsWritable() const override
    1080             :     {
    1081         187 :         return m_bUpdatable;
    1082             :     }
    1083             : 
    1084        4601 :     const std::string &GetFilename() const override
    1085             :     {
    1086        4601 :         return m_osFilename;
    1087             :     }
    1088             : 
    1089             :     const std::vector<std::shared_ptr<GDALDimension>> &
    1090       34716 :     GetDimensions() const override
    1091             :     {
    1092       34716 :         return m_aoDims;
    1093             :     }
    1094             : 
    1095       32369 :     const GDALExtendedDataType &GetDataType() const override
    1096             :     {
    1097       32369 :         return m_oType;
    1098             :     }
    1099             : 
    1100         715 :     std::vector<GUInt64> GetBlockSize() const override
    1101             :     {
    1102         715 :         return m_anInnerBlockSize;
    1103             :     }
    1104             : 
    1105          23 :     CSLConstList GetStructuralInfo() const override
    1106             :     {
    1107          23 :         return m_aosStructuralInfo.List();
    1108             :     }
    1109             : 
    1110       22783 :     const void *GetRawNoDataValue() const override
    1111             :     {
    1112       22783 :         return m_pabyNoData;
    1113             :     }
    1114             : 
    1115          85 :     const std::string &GetUnit() const override
    1116             :     {
    1117          85 :         return m_osUnit;
    1118             :     }
    1119             : 
    1120             :     bool SetUnit(const std::string &osUnit) override;
    1121             : 
    1122          55 :     void RegisterUnit(const std::string &osUnit)
    1123             :     {
    1124          55 :         m_osUnit = osUnit;
    1125          55 :     }
    1126             : 
    1127        2400 :     void RegisterGroup(const std::weak_ptr<ZarrGroupBase> &group)
    1128             :     {
    1129        2400 :         m_poGroupWeak = group;
    1130        2400 :     }
    1131             : 
    1132             :     double GetOffset(bool *pbHasOffset,
    1133             :                      GDALDataType *peStorageType) const override;
    1134             : 
    1135             :     double GetScale(bool *pbHasScale,
    1136             :                     GDALDataType *peStorageType) const override;
    1137             : 
    1138             :     bool SetOffset(double dfOffset, GDALDataType eStorageType) override;
    1139             : 
    1140             :     bool SetScale(double dfScale, GDALDataType eStorageType) override;
    1141             : 
    1142             :     std::vector<std::shared_ptr<GDALMDArray>>
    1143             :     GetCoordinateVariables() const override;
    1144             : 
    1145             :     bool IsRegularlySpaced(double &dfStart, double &dfIncrement) const override;
    1146             : 
    1147             :     bool Resize(const std::vector<GUInt64> &anNewDimSizes,
    1148             :                 CSLConstList) override;
    1149             : 
    1150           3 :     void RegisterOffset(double dfOffset)
    1151             :     {
    1152           3 :         m_bHasOffset = true;
    1153           3 :         m_dfOffset = dfOffset;
    1154           3 :     }
    1155             : 
    1156           3 :     void RegisterScale(double dfScale)
    1157             :     {
    1158           3 :         m_bHasScale = true;
    1159           3 :         m_dfScale = dfScale;
    1160           3 :     }
    1161             : 
    1162             :     bool SetRawNoDataValue(const void *pRawNoData) override;
    1163             : 
    1164             :     void RegisterNoDataValue(const void *);
    1165             : 
    1166        2400 :     void SetFilename(const std::string &osFilename)
    1167             :     {
    1168        2400 :         m_osFilename = osFilename;
    1169        2400 :     }
    1170             : 
    1171        2400 :     void SetDimSeparator(const std::string &osDimSeparator)
    1172             :     {
    1173        2400 :         m_osDimSeparator = osDimSeparator;
    1174        2400 :     }
    1175             : 
    1176             :     void SetAttributes(const std::shared_ptr<ZarrGroupBase> &poGroup,
    1177             :                        CPLJSONObject &oAttributes);
    1178             : 
    1179          51 :     void SetSRS(const std::shared_ptr<OGRSpatialReference> &srs)
    1180             :     {
    1181          51 :         m_poSRS = srs;
    1182          51 :     }
    1183             : 
    1184             :     std::shared_ptr<GDALAttribute>
    1185          77 :     GetAttribute(const std::string &osName) const override
    1186             :     {
    1187          77 :         return m_oAttrGroup.GetAttribute(osName);
    1188             :     }
    1189             : 
    1190             :     std::vector<std::shared_ptr<GDALAttribute>>
    1191         215 :     GetAttributes(CSLConstList papszOptions) const override
    1192             :     {
    1193         215 :         return m_oAttrGroup.GetAttributes(papszOptions);
    1194             :     }
    1195             : 
    1196             :     std::shared_ptr<GDALAttribute>
    1197             :     CreateAttribute(const std::string &osName,
    1198             :                     const std::vector<GUInt64> &anDimensions,
    1199             :                     const GDALExtendedDataType &oDataType,
    1200             :                     CSLConstList papszOptions = nullptr) override;
    1201             : 
    1202             :     bool DeleteAttribute(const std::string &osName,
    1203             :                          CSLConstList papszOptions = nullptr) override;
    1204             : 
    1205             :     std::shared_ptr<OGRSpatialReference> GetSpatialRef() const override;
    1206             : 
    1207             :     bool SetSpatialRef(const OGRSpatialReference *poSRS) override;
    1208             : 
    1209        2400 :     void SetUpdatable(bool bUpdatable)
    1210             :     {
    1211        2400 :         m_bUpdatable = bUpdatable;
    1212        2400 :     }
    1213             : 
    1214        2400 :     void SetDtype(const CPLJSONObject &dtype)
    1215             :     {
    1216        2400 :         m_dtype = dtype;
    1217        2400 :     }
    1218             : 
    1219         525 :     void SetDefinitionModified(bool bModified)
    1220             :     {
    1221         525 :         m_bDefinitionModified = bModified;
    1222         525 :     }
    1223             : 
    1224         510 :     void SetNew(bool bNew)
    1225             :     {
    1226         510 :         m_bNew = bNew;
    1227         510 :     }
    1228             : 
    1229             :     bool Rename(const std::string &osNewName) override;
    1230             : 
    1231             :     void ParentRenamed(const std::string &osNewParentFullName) override;
    1232             : 
    1233             :     virtual bool Flush() = 0;
    1234             : 
    1235             :     //! Return the group owning the array. Might be nullptr
    1236             :     std::shared_ptr<ZarrGroupBase> GetParentGroup() const;
    1237             : 
    1238             :     //! Return the root group. Might be nullptr
    1239        1952 :     std::shared_ptr<GDALGroup> GetRootGroup() const override
    1240             :     {
    1241        1952 :         return m_poSharedResource->GetRootGroup();
    1242             :     }
    1243             : 
    1244             :     bool GetRawBlockInfo(const uint64_t *panBlockCoordinates,
    1245             :                          GDALMDArrayRawBlockInfo &info) const override;
    1246             : 
    1247             :     bool BlockCachePresence();
    1248             : 
    1249         762 :     void SetStructuralInfo(const char *pszKey, const char *pszValue)
    1250             :     {
    1251         762 :         m_aosStructuralInfo.SetNameValue(pszKey, pszValue);
    1252         762 :     }
    1253             : 
    1254         510 :     void SetCreationOptions(CSLConstList papszOptions)
    1255             :     {
    1256         510 :         m_aosCreationOptions = papszOptions;
    1257         510 :     }
    1258             : 
    1259             :     static void DecodeSourceElt(const std::vector<DtypeElt> &elts,
    1260             :                                 const GByte *pSrc, GByte *pDst);
    1261             : 
    1262             :     static void GetDimensionTypeDirection(CPLJSONObject &oAttributes,
    1263             :                                           std::string &osType,
    1264             :                                           std::string &osDirection);
    1265             : };
    1266             : 
    1267             : /************************************************************************/
    1268             : /*                             ZarrV2Array                              */
    1269             : /************************************************************************/
    1270             : 
    1271             : class ZarrV2Array final : public ZarrArray
    1272             : {
    1273             :     CPLJSONObject m_oCompressorJSon{};
    1274             :     const CPLCompressor *m_psCompressor = nullptr;
    1275             :     std::string m_osDecompressorId{};
    1276             :     const CPLCompressor *m_psDecompressor = nullptr;
    1277             :     CPLJSONArray m_oFiltersArray{};  // ZarrV2 specific
    1278             :     bool m_bFortranOrder = false;
    1279             :     mutable ZarrByteVectorQuickResize
    1280             :         m_abyTmpRawBlockData{};  // used for Fortran order
    1281             : 
    1282             :     ZarrV2Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1283             :                 const std::shared_ptr<ZarrGroupBase> &poParent,
    1284             :                 const std::string &osName,
    1285             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1286             :                 const GDALExtendedDataType &oType,
    1287             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1288             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1289             :                 bool bFortranOrder);
    1290             : 
    1291             :     bool Serialize();
    1292             : 
    1293             :     bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
    1294             :                        const CPLCompressor *psDecompressor,
    1295             :                        ZarrByteVectorQuickResize &abyRawBlockData,
    1296             :                        ZarrByteVectorQuickResize &abyTmpRawBlockData,
    1297             :                        ZarrByteVectorQuickResize &abyDecodedBlockData,
    1298             :                        bool &bMissingBlockOut) const;
    1299             : 
    1300             :     bool NeedDecodedBuffer() const;
    1301             : 
    1302             :     bool AllocateWorkingBuffers(
    1303             :         ZarrByteVectorQuickResize &abyRawBlockData,
    1304             :         ZarrByteVectorQuickResize &abyTmpRawBlockData,
    1305             :         ZarrByteVectorQuickResize &abyDecodedBlockData) const;
    1306             : 
    1307             :     void BlockTranspose(const ZarrByteVectorQuickResize &abySrc,
    1308             :                         ZarrByteVectorQuickResize &abyDst, bool bDecode) const;
    1309             : 
    1310             :     // Disable copy constructor and assignment operator
    1311             :     ZarrV2Array(const ZarrV2Array &) = delete;
    1312             :     ZarrV2Array &operator=(const ZarrV2Array &) = delete;
    1313             : 
    1314             :   public:
    1315             :     ~ZarrV2Array() override;
    1316             : 
    1317             :     static std::shared_ptr<ZarrV2Array>
    1318             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1319             :            const std::shared_ptr<ZarrGroupBase> &poParent,
    1320             :            const std::string &osName,
    1321             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1322             :            const GDALExtendedDataType &oType,
    1323             :            const std::vector<DtypeElt> &aoDtypeElts,
    1324             :            const std::vector<GUInt64> &anBlockSize, bool bFortranOrder);
    1325             : 
    1326             :     void SetCompressorJson(const CPLJSONObject &oCompressor);
    1327             : 
    1328        1077 :     void SetCompressorDecompressor(const std::string &osDecompressorId,
    1329             :                                    const CPLCompressor *psComp,
    1330             :                                    const CPLCompressor *psDecomp)
    1331             :     {
    1332        1077 :         m_psCompressor = psComp;
    1333        1077 :         m_osDecompressorId = osDecompressorId;
    1334        1077 :         m_psDecompressor = psDecomp;
    1335        1077 :     }
    1336             : 
    1337             :     void SetFilters(const CPLJSONArray &oFiltersArray);
    1338             : 
    1339             :     bool Flush() override;
    1340             : 
    1341             :   protected:
    1342             :     std::string GetDataDirectory() const override;
    1343             : 
    1344             :     CPLStringList
    1345             :     GetChunkIndicesFromFilename(const char *pszFilename) const override;
    1346             : 
    1347             :     bool FlushDirtyBlock() const override;
    1348             : 
    1349             :     std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
    1350             : 
    1351             :     bool AllocateWorkingBuffers() const override;
    1352             : 
    1353             :     bool LoadBlockData(const uint64_t *blockIndices,
    1354             :                        bool &bMissingBlockOut) const override;
    1355             : 
    1356             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1357             :                      CSLConstList papszOptions) const override;
    1358             : 
    1359             :     CPLStringList GetRawBlockInfoInfo() const override;
    1360             : };
    1361             : 
    1362             : /************************************************************************/
    1363             : /*                             ZarrV3Array                              */
    1364             : /************************************************************************/
    1365             : 
    1366             : class ZarrV3CodecSequence;
    1367             : 
    1368             : class ZarrV3Array final : public ZarrArray
    1369             : {
    1370             :     bool m_bV2ChunkKeyEncoding = false;
    1371             :     std::unique_ptr<ZarrV3CodecSequence> m_poCodecs{};
    1372             :     CPLJSONArray m_oJSONCodecs{};
    1373             :     mutable bool m_bOverviewsLoaded = false;
    1374             :     mutable std::vector<std::shared_ptr<GDALMDArray>> m_apoOverviews{};
    1375             : 
    1376             :     /** Shard write cache: accumulates dirty inner chunks per shard, encodes
    1377             :      * each shard exactly once on FlushShardCache() (called from Flush()).
    1378             :      * Without this cache, FlushDirtyBlockSharded() would re-read, decode,
    1379             :      * overlay, re-encode, and write the entire shard for every inner chunk,
    1380             :      * resulting in O(N) encode cycles per shard where N = inner chunks/shard.
    1381             :      */
    1382             :     struct ShardWriteEntry
    1383             :     {
    1384             :         ZarrByteVectorQuickResize abyShardBuffer{};
    1385             :         std::vector<bool> abDirtyInnerChunks{};
    1386             :     };
    1387             : 
    1388             :     // Note: cache is unbounded - one entry per shard written. For very large
    1389             :     // rasters, consider adding LRU eviction in a follow-up.
    1390             :     mutable std::map<std::string, ShardWriteEntry> m_oShardWriteCache{};
    1391             : 
    1392             :     ZarrV3Array(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1393             :                 const std::shared_ptr<ZarrGroupBase> &poParent,
    1394             :                 const std::string &osName,
    1395             :                 const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1396             :                 const GDALExtendedDataType &oType,
    1397             :                 const std::vector<DtypeElt> &aoDtypeElts,
    1398             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1399             :                 const std::vector<GUInt64> &anInnerBlockSize);
    1400             : 
    1401             :     bool Serialize(const CPLJSONObject &oAttrs);
    1402             : 
    1403             :     bool NeedDecodedBuffer() const;
    1404             : 
    1405             :     bool AllocateWorkingBuffers(
    1406             :         ZarrByteVectorQuickResize &abyRawBlockData,
    1407             :         ZarrByteVectorQuickResize &abyDecodedBlockData) const;
    1408             : 
    1409             :     bool LoadBlockData(const uint64_t *blockIndices, bool bUseMutex,
    1410             :                        ZarrV3CodecSequence *poCodecs,
    1411             :                        ZarrByteVectorQuickResize &abyRawBlockData,
    1412             :                        ZarrByteVectorQuickResize &abyDecodedBlockData,
    1413             :                        bool &bMissingBlockOut) const;
    1414             : 
    1415             :     bool IRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1416             :                const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1417             :                const GDALExtendedDataType &bufferDataType,
    1418             :                void *pDstBuffer) const override;
    1419             : 
    1420             :     void PreloadShardedBlocks(const GUInt64 *arrayStartIdx,
    1421             :                               const size_t *count) const;
    1422             : 
    1423             :     bool IWrite(const GUInt64 *arrayStartIdx, const size_t *count,
    1424             :                 const GInt64 *arrayStep, const GPtrDiff_t *bufferStride,
    1425             :                 const GDALExtendedDataType &bufferDataType,
    1426             :                 const void *pSrcBuffer) override;
    1427             : 
    1428             :     bool WriteChunksThreadSafe(const GUInt64 *arrayStartIdx,
    1429             :                                const size_t *count, const GInt64 *arrayStep,
    1430             :                                const GPtrDiff_t *bufferStride,
    1431             :                                const GDALExtendedDataType &bufferDataType,
    1432             :                                const void *pSrcBuffer, const int iThread,
    1433             :                                const int nThreads,
    1434             :                                std::string &osErrorMsg) const;
    1435             : 
    1436             :     void LoadOverviews() const;
    1437             : 
    1438             :     void ReconstructCreationOptionsFromCodecs();
    1439             : 
    1440             :   public:
    1441             :     ~ZarrV3Array() override;
    1442             : 
    1443             :     static std::shared_ptr<ZarrV3Array>
    1444             :     Create(const std::shared_ptr<ZarrSharedResource> &poSharedResource,
    1445             :            const std::shared_ptr<ZarrGroupBase> &poParent,
    1446             :            const std::string &osName,
    1447             :            const std::vector<std::shared_ptr<GDALDimension>> &aoDims,
    1448             :            const GDALExtendedDataType &oType,
    1449             :            const std::vector<DtypeElt> &aoDtypeElts,
    1450             :            const std::vector<GUInt64> &anOuterBlockSize,
    1451             :            const std::vector<GUInt64> &anInnerBlockSize);
    1452             : 
    1453        1129 :     void SetIsV2ChunkKeyEncoding(bool b)
    1454             :     {
    1455        1129 :         m_bV2ChunkKeyEncoding = b;
    1456        1129 :     }
    1457             : 
    1458             :     void SetCodecs(const CPLJSONArray &oJSONCodecs,
    1459             :                    std::unique_ptr<ZarrV3CodecSequence> &&poCodecs);
    1460             : 
    1461             :     bool Flush() override;
    1462             : 
    1463             :     static std::unique_ptr<ZarrV3CodecSequence>
    1464             :     SetupCodecs(const CPLJSONArray &oCodecs,
    1465             :                 const std::vector<GUInt64> &anOuterBlockSize,
    1466             :                 std::vector<GUInt64> &anInnerBlockSize, DtypeElt &zarrDataType,
    1467             :                 const std::vector<GByte> &abyNoData);
    1468             :     int GetOverviewCount() const override;
    1469             : 
    1470             :     std::shared_ptr<GDALMDArray> GetOverview(int idx) const override;
    1471             : 
    1472             :     CPLErr BuildOverviews(const char *pszResampling, int nOverviews,
    1473             :                           const int *panOverviewList,
    1474             :                           GDALProgressFunc pfnProgress, void *pProgressData,
    1475             :                           CSLConstList papszOptions) override;
    1476             : 
    1477             :     static void
    1478             :     ExtractSubArrayFromLargerOne(const ZarrByteVectorQuickResize &abySrc,
    1479             :                                  const std::vector<size_t> &anSrcBlockSize,
    1480             :                                  const std::vector<size_t> &anInnerBlockSize,
    1481             :                                  const std::vector<size_t> &anInnerBlockIndices,
    1482             :                                  ZarrByteVectorQuickResize &abyChunk,
    1483             :                                  const size_t nDTSize);
    1484             : 
    1485             :   protected:
    1486             :     std::string GetDataDirectory() const override;
    1487             : 
    1488             :     CPLStringList
    1489             :     GetChunkIndicesFromFilename(const char *pszFilename) const override;
    1490             : 
    1491             :     bool AllocateWorkingBuffers() const override;
    1492             : 
    1493             :     bool FlushDirtyBlock() const override;
    1494             :     bool FlushDirtyBlockSharded() const;
    1495             :     bool FlushSingleShard(const std::string &osFilename,
    1496             :                           ShardWriteEntry &entry) const;
    1497             :     bool FlushShardCache() const;
    1498             : 
    1499             :     std::string BuildChunkFilename(const uint64_t *blockIndices) const override;
    1500             : 
    1501             :     bool LoadBlockData(const uint64_t *blockIndices,
    1502             :                        bool &bMissingBlockOut) const override;
    1503             : 
    1504             :     bool IAdviseRead(const GUInt64 *arrayStartIdx, const size_t *count,
    1505             :                      CSLConstList papszOptions) const override;
    1506             : 
    1507             :     CPLStringList GetRawBlockInfoInfo() const override;
    1508             : };
    1509             : 
    1510             : void ZarrClearCoordinateCache();
    1511             : void ZarrClearShardIndexCache();
    1512             : void ZarrEraseShardIndexFromCache(const std::string &osFilename);
    1513             : 
    1514             : #endif  // ZARR_H

Generated by: LCOV version 1.14