#pragma once #include #include #include namespace lzokay { enum class EResult { LookbehindOverrun = -4, OutputOverrun = -3, InputOverrun = -2, Error = -1, Success = 0, InputNotConsumed = 1, }; class DictBase { protected: static constexpr uint32_t HashSize = 0x4000; static constexpr uint32_t MaxDist = 0xbfff; static constexpr uint32_t MaxMatchLen = 0x800; static constexpr uint32_t BufSize = MaxDist + MaxMatchLen; /* List encoding of previous 3-byte data matches */ struct Match3 { uint16_t head[HashSize]; /* key -> chain-head-pos */ uint16_t chain_sz[HashSize]; /* key -> chain-size */ uint16_t chain[BufSize]; /* chain-pos -> next-chain-pos */ uint16_t best_len[BufSize]; /* chain-pos -> best-match-length */ }; /* Encoding of 2-byte data matches */ struct Match2 { uint16_t head[1 << 16]; /* 2-byte-data -> head-pos */ }; struct Data { Match3 match3; Match2 match2; /* Circular buffer caching enough data to access the maximum lookback * distance of 48K + maximum match length of 2K. An additional 2K is * allocated so the start of the buffer may be replicated at the end, * therefore providing efficient circular access. */ uint8_t buffer[BufSize + MaxMatchLen]; }; using storage_type = Data; storage_type* _storage; DictBase() = default; friend struct State; friend EResult compress(const uint8_t* src, std::size_t src_size, uint8_t* dst, std::size_t& dst_size, DictBase& dict); }; template class _Alloc = std::allocator> class Dict : public DictBase { _Alloc _allocator; public: Dict() { _storage = _allocator.allocate(1); } ~Dict() { _allocator.deallocate(_storage, 1); } }; EResult decompress(const uint8_t* src, std::size_t src_size, uint8_t* dst, std::size_t dst_size, std::size_t& out_size); EResult compress(const uint8_t* src, std::size_t src_size, uint8_t* dst, std::size_t dst_size, std::size_t& out_size, DictBase& dict); inline EResult compress(const uint8_t* src, std::size_t src_size, uint8_t* dst, std::size_t dst_size, std::size_t& out_size) { Dict<> dict; return compress(src, src_size, dst, dst_size, out_size, dict); } constexpr std::size_t compress_worst_size(std::size_t s) { return s + s / 16 + 64 + 3; } }