LCOV - code coverage report
Current view: top level - frmts/zarr - zarr_v3_codec.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 60 60 100.0 %
Date: 2026-02-11 08:43:47 Functions: 25 26 96.2 %

          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_V3_CODEC_H
      14             : #define ZARR_V3_CODEC_H
      15             : 
      16             : #include "zarr.h"
      17             : 
      18             : struct VSIVirtualHandle;
      19             : 
      20             : /************************************************************************/
      21             : /*                          ZarrArrayMetadata                           */
      22             : /************************************************************************/
      23             : 
      24             : /** Array-related metadata needed for the good working of Zarr V3 codecs */
      25             : struct ZarrArrayMetadata
      26             : {
      27             :     /** Data type of the array */
      28             :     DtypeElt oElt{};
      29             : 
      30             :     /** Shape of a block/chunk */
      31             :     std::vector<size_t> anBlockSizes{};
      32             : 
      33             :     /** No data value of the array. Empty or abyNoData.size() == oElt.nNativeSize */
      34             :     std::vector<GByte> abyNoData{};
      35             : };
      36             : 
      37             : /************************************************************************/
      38             : /*                             ZarrV3Codec                              */
      39             : /************************************************************************/
      40             : 
      41             : /** Abstract class for a Zarr V3 codec */
      42        3879 : class ZarrV3Codec CPL_NON_FINAL
      43             : {
      44             :   protected:
      45             :     const std::string m_osName;
      46             :     CPLJSONObject m_oConfiguration{};
      47             :     ZarrArrayMetadata m_oInputArrayMetadata{};
      48             : 
      49             :     ZarrV3Codec(const std::string &osName);
      50             : 
      51             :   public:
      52             :     virtual ~ZarrV3Codec();
      53             : 
      54             :     enum class IOType
      55             :     {
      56             :         BYTES,
      57             :         ARRAY
      58             :     };
      59             : 
      60             :     virtual IOType GetInputType() const = 0;
      61             :     virtual IOType GetOutputType() const = 0;
      62             : 
      63             :     virtual bool
      64             :     InitFromConfiguration(const CPLJSONObject &configuration,
      65             :                           const ZarrArrayMetadata &oInputArrayMetadata,
      66             :                           ZarrArrayMetadata &oOutputArrayMetadata,
      67             :                           bool bEmitWarnings) = 0;
      68             : 
      69             :     virtual std::unique_ptr<ZarrV3Codec> Clone() const = 0;
      70             : 
      71        1966 :     virtual bool IsNoOp() const
      72             :     {
      73        1966 :         return false;
      74             :     }
      75             : 
      76             :     virtual bool Encode(const ZarrByteVectorQuickResize &abySrc,
      77             :                         ZarrByteVectorQuickResize &abyDst) const = 0;
      78             :     virtual bool Decode(const ZarrByteVectorQuickResize &abySrc,
      79             :                         ZarrByteVectorQuickResize &abyDst) const = 0;
      80             : 
      81             :     /** Partial decoding.
      82             :      * anStartIdx[i]: coordinate in pixel, within the array of an outer chunk,
      83             :      * that is < m_oInputArrayMetadata.anBlockSizes[i]
      84             :      * anCount[i]: number of pixels to extract <= m_oInputArrayMetadata.anBlockSizes[i]
      85             :      */
      86             :     virtual bool DecodePartial(VSIVirtualHandle *poFile,
      87             :                                const ZarrByteVectorQuickResize &abySrc,
      88             :                                ZarrByteVectorQuickResize &abyDst,
      89             :                                std::vector<size_t> &anStartIdx,
      90             :                                std::vector<size_t> &anCount);
      91             : 
      92       11558 :     const std::string &GetName() const
      93             :     {
      94       11558 :         return m_osName;
      95             :     }
      96             : 
      97             :     const CPLJSONObject &GetConfiguration() const
      98             :     {
      99             :         return m_oConfiguration;
     100             :     }
     101             : 
     102             :     virtual std::vector<size_t>
     103         243 :     GetInnerMostBlockSize(const std::vector<size_t> &input) const
     104             :     {
     105         243 :         return input;
     106             :     }
     107             : 
     108        1156 :     virtual void ChangeArrayShapeForward(std::vector<size_t> &anStartIdx,
     109             :                                          std::vector<size_t> &anCount)
     110             :     {
     111             :         (void)anStartIdx;
     112             :         (void)anCount;
     113        1156 :     }
     114             : };
     115             : 
     116             : /************************************************************************/
     117             : /*                    ZarrV3CodecAbstractCompressor                     */
     118             : /************************************************************************/
     119             : 
     120             : class ZarrV3CodecAbstractCompressor CPL_NON_FINAL : public ZarrV3Codec
     121             : {
     122             :   protected:
     123             :     CPLStringList m_aosCompressorOptions{};
     124             :     const CPLCompressor *m_pDecompressor = nullptr;
     125             :     const CPLCompressor *m_pCompressor = nullptr;
     126             : 
     127             :     explicit ZarrV3CodecAbstractCompressor(const std::string &osName);
     128             : 
     129             :     ZarrV3CodecAbstractCompressor(const ZarrV3CodecAbstractCompressor &) =
     130             :         delete;
     131             :     ZarrV3CodecAbstractCompressor &
     132             :     operator=(const ZarrV3CodecAbstractCompressor &) = delete;
     133             : 
     134             :   public:
     135         555 :     IOType GetInputType() const override
     136             :     {
     137         555 :         return IOType::BYTES;
     138             :     }
     139             : 
     140         555 :     IOType GetOutputType() const override
     141             :     {
     142         555 :         return IOType::BYTES;
     143             :     }
     144             : 
     145             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
     146             :                 ZarrByteVectorQuickResize &abyDst) const override;
     147             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
     148             :                 ZarrByteVectorQuickResize &abyDst) const override;
     149             : };
     150             : 
     151             : /************************************************************************/
     152             : /*                           ZarrV3CodecGZip                            */
     153             : /************************************************************************/
     154             : 
     155             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/gzip/v1.0.html
     156             : class ZarrV3CodecGZip final : public ZarrV3CodecAbstractCompressor
     157             : {
     158             :   public:
     159             :     static constexpr const char *NAME = "gzip";
     160             : 
     161             :     ZarrV3CodecGZip();
     162             : 
     163             :     static CPLJSONObject GetConfiguration(int nLevel);
     164             : 
     165             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     166             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     167             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     168             :                                bool bEmitWarnings) override;
     169             : 
     170             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     171             : };
     172             : 
     173             : /************************************************************************/
     174             : /*                           ZarrV3CodecBlosc                           */
     175             : /************************************************************************/
     176             : 
     177             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/blosc/v1.0.html
     178             : class ZarrV3CodecBlosc final : public ZarrV3CodecAbstractCompressor
     179             : {
     180             :   public:
     181             :     static constexpr const char *NAME = "blosc";
     182             : 
     183             :     ZarrV3CodecBlosc();
     184             : 
     185             :     static CPLJSONObject GetConfiguration(const char *cname, int clevel,
     186             :                                           const char *shuffle, int typesize,
     187             :                                           int blocksize);
     188             : 
     189             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     190             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     191             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     192             :                                bool bEmitWarnings) override;
     193             : 
     194             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     195             : };
     196             : 
     197             : /************************************************************************/
     198             : /*                           ZarrV3CodecZstd                            */
     199             : /************************************************************************/
     200             : 
     201             : // Implements https://github.com/zarr-developers/zarr-specs/pull/256
     202             : class ZarrV3CodecZstd final : public ZarrV3CodecAbstractCompressor
     203             : {
     204             :   public:
     205             :     static constexpr const char *NAME = "zstd";
     206             : 
     207             :     ZarrV3CodecZstd();
     208             : 
     209             :     static CPLJSONObject GetConfiguration(int level, bool checksum);
     210             : 
     211             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     212             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     213             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     214             :                                bool bEmitWarnings) override;
     215             : 
     216             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     217             : };
     218             : 
     219             : /************************************************************************/
     220             : /*                           ZarrV3CodecBytes                           */
     221             : /************************************************************************/
     222             : 
     223             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/bytes/v1.0.html
     224             : class ZarrV3CodecBytes final : public ZarrV3Codec
     225             : {
     226             :     bool m_bLittle = true;
     227             : 
     228             :   public:
     229             :     static constexpr const char *NAME = "bytes";
     230             : 
     231             :     ZarrV3CodecBytes();
     232             : 
     233        1799 :     IOType GetInputType() const override
     234             :     {
     235        1799 :         return IOType::ARRAY;
     236             :     }
     237             : 
     238        1800 :     IOType GetOutputType() const override
     239             :     {
     240        1800 :         return IOType::BYTES;
     241             :     }
     242             : 
     243             :     static CPLJSONObject GetConfiguration(bool bLittle);
     244             : 
     245             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     246             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     247             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     248             :                                bool bEmitWarnings) override;
     249             : 
     250           1 :     bool IsLittle() const
     251             :     {
     252           1 :         return m_bLittle;
     253             :     }
     254             : 
     255        1853 :     bool IsNoOp() const override
     256             :     {
     257             :         if constexpr (CPL_IS_LSB)
     258        1853 :             return m_oInputArrayMetadata.oElt.nativeSize == 1 || m_bLittle;
     259             :         else
     260             :             return m_oInputArrayMetadata.oElt.nativeSize == 1 || !m_bLittle;
     261             :     }
     262             : 
     263             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     264             : 
     265             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
     266             :                 ZarrByteVectorQuickResize &abyDst) const override;
     267             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
     268             :                 ZarrByteVectorQuickResize &abyDst) const override;
     269             : };
     270             : 
     271             : /************************************************************************/
     272             : /*                         ZarrV3CodecTranspose                         */
     273             : /************************************************************************/
     274             : 
     275             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/transpose/v1.0.html
     276             : class ZarrV3CodecTranspose final : public ZarrV3Codec
     277             : {
     278             :     // m_anOrder is such that dest_shape[i] = source_shape[m_anOrder[i]]
     279             :     // where source_shape[] is the size of the array before the Encode() operation
     280             :     // and dest_shape[] its size after.
     281             :     // m_anOrder[] describes a bijection of [0,N-1] to [0,N-1]
     282             :     std::vector<int> m_anOrder{};
     283             : 
     284             :     // m_anReverseOrder is such that m_anReverseOrder[m_anOrder[i]] = i
     285             :     std::vector<int> m_anReverseOrder{};
     286             : 
     287             :     bool Transpose(const ZarrByteVectorQuickResize &abySrc,
     288             :                    ZarrByteVectorQuickResize &abyDst, bool bEncodeDirection,
     289             :                    const std::vector<size_t> &anForwardBlockSizes) const;
     290             : 
     291             :   public:
     292             :     static constexpr const char *NAME = "transpose";
     293             : 
     294             :     ZarrV3CodecTranspose();
     295             : 
     296          83 :     IOType GetInputType() const override
     297             :     {
     298          83 :         return IOType::ARRAY;
     299             :     }
     300             : 
     301          83 :     IOType GetOutputType() const override
     302             :     {
     303          83 :         return IOType::ARRAY;
     304             :     }
     305             : 
     306             :     static CPLJSONObject GetConfiguration(const std::vector<int> &anOrder);
     307             : 
     308             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     309             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     310             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     311             :                                bool bEmitWarnings) override;
     312             : 
     313           1 :     const std::vector<int> &GetOrder() const
     314             :     {
     315           1 :         return m_anOrder;
     316             :     }
     317             : 
     318             :     bool IsNoOp() const override;
     319             : 
     320             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     321             : 
     322             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
     323             :                 ZarrByteVectorQuickResize &abyDst) const override;
     324             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
     325             :                 ZarrByteVectorQuickResize &abyDst) const override;
     326             : 
     327             :     bool DecodePartial(VSIVirtualHandle *poFile,
     328             :                        const ZarrByteVectorQuickResize &abySrc,
     329             :                        ZarrByteVectorQuickResize &abyDst,
     330             :                        std::vector<size_t> &anStartIdx,
     331             :                        std::vector<size_t> &anCount) override;
     332             : 
     333             :     std::vector<size_t>
     334             :     GetInnerMostBlockSize(const std::vector<size_t> &input) const override;
     335             : 
     336             :     template <class T>
     337          50 :     inline void Reorder1DForward(std::vector<T> &vector) const
     338             :     {
     339         100 :         std::vector<T> res;
     340         150 :         for (int idx : m_anOrder)
     341         100 :             res.push_back(vector[idx]);
     342          50 :         vector = std::move(res);
     343          50 :     }
     344             : 
     345             :     template <class T>
     346          50 :     inline void Reorder1DInverse(std::vector<T> &vector) const
     347             :     {
     348         100 :         std::vector<T> res;
     349         150 :         for (int idx : m_anReverseOrder)
     350         100 :             res.push_back(vector[idx]);
     351          50 :         vector = std::move(res);
     352          50 :     }
     353             : 
     354          25 :     void ChangeArrayShapeForward(std::vector<size_t> &anStartIdx,
     355             :                                  std::vector<size_t> &anCount) override
     356             :     {
     357          25 :         Reorder1DForward(anStartIdx);
     358          25 :         Reorder1DForward(anCount);
     359          25 :     }
     360             : };
     361             : 
     362             : /************************************************************************/
     363             : /*                          ZarrV3CodecCRC32C                           */
     364             : /************************************************************************/
     365             : 
     366             : // Implements https://zarr-specs.readthedocs.io/en/latest/v3/codecs/crc32c/index.html
     367             : class ZarrV3CodecCRC32C final : public ZarrV3Codec
     368             : {
     369             :     bool m_bCheckCRC = true;
     370             : 
     371             :   public:
     372             :     static constexpr const char *NAME = "crc32c";
     373             : 
     374             :     ZarrV3CodecCRC32C();
     375             : 
     376         773 :     IOType GetInputType() const override
     377             :     {
     378         773 :         return IOType::BYTES;
     379             :     }
     380             : 
     381         773 :     IOType GetOutputType() const override
     382             :     {
     383         773 :         return IOType::BYTES;
     384             :     }
     385             : 
     386             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     387             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     388             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     389             :                                bool bEmitWarnings) override;
     390             : 
     391             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     392             : 
     393             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
     394             :                 ZarrByteVectorQuickResize &abyDst) const override;
     395             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
     396             :                 ZarrByteVectorQuickResize &abyDst) const override;
     397             : };
     398             : 
     399             : /************************************************************************/
     400             : /*                      ZarrV3CodecShardingIndexed                      */
     401             : /************************************************************************/
     402             : 
     403             : class ZarrV3CodecSequence;
     404             : 
     405             : // https://zarr-specs.readthedocs.io/en/latest/v3/codecs/sharding-indexed/index.html
     406             : class ZarrV3CodecShardingIndexed final : public ZarrV3Codec
     407             : {
     408             :     std::unique_ptr<ZarrV3CodecSequence> m_poCodecSequence{};
     409             :     std::unique_ptr<ZarrV3CodecSequence> m_poIndexCodecSequence{};
     410             :     bool m_bIndexLocationAtEnd = true;
     411             :     bool m_bIndexHasCRC32 = false;
     412             :     std::vector<size_t> m_anInnerBlockSize{};
     413             : 
     414             :     struct Location
     415             :     {
     416             :         uint64_t nOffset;
     417             :         uint64_t nSize;
     418             :     };
     419             : 
     420             :   public:
     421             :     static constexpr const char *NAME = "sharding_indexed";
     422             : 
     423             :     ZarrV3CodecShardingIndexed();
     424             : 
     425         656 :     IOType GetInputType() const override
     426             :     {
     427         656 :         return IOType::ARRAY;
     428             :     }
     429             : 
     430         638 :     IOType GetOutputType() const override
     431             :     {
     432         638 :         return IOType::BYTES;
     433             :     }
     434             : 
     435             :     bool InitFromConfiguration(const CPLJSONObject &configuration,
     436             :                                const ZarrArrayMetadata &oInputArrayMetadata,
     437             :                                ZarrArrayMetadata &oOutputArrayMetadata,
     438             :                                bool bEmitWarnings) override;
     439             : 
     440             :     std::unique_ptr<ZarrV3Codec> Clone() const override;
     441             : 
     442             :     bool Encode(const ZarrByteVectorQuickResize &abySrc,
     443             :                 ZarrByteVectorQuickResize &abyDst) const override;
     444             :     bool Decode(const ZarrByteVectorQuickResize &abySrc,
     445             :                 ZarrByteVectorQuickResize &abyDst) const override;
     446             : 
     447             :     bool DecodePartial(VSIVirtualHandle *poFile,
     448             :                        const ZarrByteVectorQuickResize &abySrc,
     449             :                        ZarrByteVectorQuickResize &abyDst,
     450             :                        std::vector<size_t> &anStartIdx,
     451             :                        std::vector<size_t> &anCount) override;
     452             : 
     453             :     /** Batch-read multiple inner chunks from the same shard via two
     454             :      *  ReadMultiRange() passes (index entries, then data), then decode.
     455             :      *  No persistent state is kept — each call reads the needed index
     456             :      *  entries on demand.
     457             :      */
     458             :     bool BatchDecodePartial(
     459             :         VSIVirtualHandle *poFile,
     460             :         const std::vector<std::pair<std::vector<size_t>, std::vector<size_t>>>
     461             :             &anRequests,
     462             :         std::vector<ZarrByteVectorQuickResize> &aResults);
     463             : 
     464             :     std::vector<size_t>
     465             :     GetInnerMostBlockSize(const std::vector<size_t> &input) const override;
     466             : };
     467             : 
     468             : /************************************************************************/
     469             : /*                         ZarrV3CodecSequence                          */
     470             : /************************************************************************/
     471             : 
     472             : class ZarrV3CodecSequence
     473             : {
     474             :     const ZarrArrayMetadata m_oInputArrayMetadata;
     475             :     std::vector<std::unique_ptr<ZarrV3Codec>> m_apoCodecs{};
     476             :     CPLJSONObject m_oCodecArray{};
     477             :     ZarrByteVectorQuickResize m_abyTmp{};
     478             :     bool m_bPartialDecodingPossible = false;
     479             : 
     480             :     bool AllocateBuffer(ZarrByteVectorQuickResize &abyBuffer, size_t nEltCount);
     481             : 
     482             :   public:
     483        2478 :     explicit ZarrV3CodecSequence(const ZarrArrayMetadata &oInputArrayMetadata)
     484        2478 :         : m_oInputArrayMetadata(oInputArrayMetadata)
     485             :     {
     486        2478 :     }
     487             : 
     488             :     // This method is not thread safe due to cloning a JSON object
     489             :     std::unique_ptr<ZarrV3CodecSequence> Clone() const;
     490             : 
     491             :     bool InitFromJson(const CPLJSONObject &oCodecs,
     492             :                       ZarrArrayMetadata &oOutputArrayMetadata);
     493             : 
     494         147 :     const CPLJSONObject &GetJSon() const
     495             :     {
     496         147 :         return m_oCodecArray;
     497             :     }
     498             : 
     499       10837 :     const std::vector<std::unique_ptr<ZarrV3Codec>> &GetCodecs() const
     500             :     {
     501       10837 :         return m_apoCodecs;
     502             :     }
     503             : 
     504       38282 :     bool SupportsPartialDecoding() const
     505             :     {
     506       38282 :         return m_bPartialDecodingPossible;
     507             :     }
     508             : 
     509             :     bool Encode(ZarrByteVectorQuickResize &abyBuffer);
     510             :     bool Decode(ZarrByteVectorQuickResize &abyBuffer);
     511             : 
     512             :     /** Partial decoding.
     513             :      * anStartIdx[i]: coordinate in pixel, within the array of an outer chunk,
     514             :      * that is < m_oInputArrayMetadata.anBlockSizes[i]
     515             :      * anCount[i]: number of pixels to extract <= m_oInputArrayMetadata.anBlockSizes[i]
     516             :      */
     517             :     bool DecodePartial(VSIVirtualHandle *poFile,
     518             :                        ZarrByteVectorQuickResize &abyBuffer,
     519             :                        const std::vector<size_t> &anStartIdx,
     520             :                        const std::vector<size_t> &anCount);
     521             : 
     522             :     /** Batch-read multiple inner chunks via ReadMultiRange().
     523             :      *  Delegates to the sharding codec if present, otherwise falls back
     524             :      *  to sequential DecodePartial() calls.
     525             :      */
     526             :     bool BatchDecodePartial(
     527             :         VSIVirtualHandle *poFile,
     528             :         const std::vector<std::pair<std::vector<size_t>, std::vector<size_t>>>
     529             :             &anRequests,
     530             :         std::vector<ZarrByteVectorQuickResize> &aResults);
     531             : 
     532             :     std::vector<size_t>
     533             :     GetInnerMostBlockSize(const std::vector<size_t> &anOuterBlockSize) const;
     534             : };
     535             : 
     536             : #endif

Generated by: LCOV version 1.14