1717
1818#include < cstdint>
1919#include < cstring>
20+ #include < functional>
2021#include < vector>
2122#include < array>
2223#include < algorithm>
2324#include < memory>
25+ #include < utility>
2426
2527#if defined(__GNUC__) || defined(__clang__)
2628#define PZIP_FORCE_INLINE __attribute__ ((always_inline)) inline
@@ -304,6 +306,13 @@ class HuffmanEncoder {
304306class HuffmanBitWriter {
305307public:
306308 explicit HuffmanBitWriter ();
309+ ~HuffmanBitWriter () = default ;
310+
311+ HuffmanBitWriter (const HuffmanBitWriter&) = delete ;
312+ HuffmanBitWriter& operator =(const HuffmanBitWriter&) = delete ;
313+
314+ HuffmanBitWriter (HuffmanBitWriter&&) = default ;
315+ HuffmanBitWriter& operator =(HuffmanBitWriter&&) = default ;
307316
308317 void reset ();
309318 void flush ();
@@ -330,32 +339,46 @@ class HuffmanBitWriter {
330339
331340 void writeBlock (Tokens* tokens, bool eof, const uint8_t * input, size_t inputLen);
332341 void writeBlockDynamic (Tokens* tokens, bool eof, const uint8_t * input, size_t inputLen, bool sync);
342+ void writeBlockHuff (bool eof, const uint8_t * input, size_t inputLen, bool sync);
333343
334344 void writeTokens (const Token* tokens, size_t n, const HCode* leCodes, const HCode* oeCodes);
335345
336346 const std::vector<uint8_t >& data () const { return output_; }
337347 std::vector<uint8_t >& data () { return output_; }
338348
349+ void setLogNewTablePenalty (int penalty) { logNewTablePenalty_ = penalty; }
350+
339351private:
340352 void writeOutBits ();
341353 void indexTokens (Tokens* t, bool alwaysEOB);
342354 void generate ();
343355 int extraBitSize ();
344356 int fixedSize (int extraBits);
345357 int storedSize (const uint8_t * input, size_t len, bool * storable);
358+ void histogram (const uint8_t * input, size_t len);
359+ std::pair<int , int > headerSize ();
360+ void generateCodegen (int numLiterals, int numOffsets, HuffmanEncoder* litEnc, HuffmanEncoder* offEnc);
361+ int codegens ();
362+ void writeDynamicHeader (int numLiterals, int numOffsets, int numCodegens, bool isEof);
346363
347364 std::vector<uint8_t > output_;
348365 uint64_t bits_ = 0 ;
349366 uint8_t nbits_ = 0 ;
350367 uint8_t nbytes_ = 0 ;
351368 int lastHeader_ = 0 ;
369+ bool lastHuffMan_ = false ;
370+ int logNewTablePenalty_ = 7 ;
352371
353372 std::array<uint8_t , 256 + 8 > bytes_;
354373 std::array<uint16_t , LENGTH_CODES_START + 32 > literalFreq_;
355374 std::array<uint16_t , 32 > offsetFreq_;
375+ std::array<uint16_t , 19 > codegenFreq_;
376+ std::array<uint8_t , LITERAL_COUNT + OFFSET_CODE_COUNT + 1 > codegen_;
356377
357378 std::unique_ptr<HuffmanEncoder> literalEncoding_;
358379 std::unique_ptr<HuffmanEncoder> offsetEncoding_;
380+ std::unique_ptr<HuffmanEncoder> tmpLitEncoding_;
381+ std::unique_ptr<HuffmanEncoder> codegenEncoding_;
359382};
360383
361384// ============================================================================
@@ -375,9 +398,13 @@ class FastGen {
375398 FastGen () : cur_(MAX_STORE_BLOCK_SIZE ) {
376399 hist_.reserve (ALLOC_HISTORY );
377400 }
401+ virtual ~FastGen () = default ;
378402
379403 int32_t addBlock (const uint8_t * src, size_t len);
380- void reset ();
404+ virtual void reset ();
405+
406+ // 纯虚函数,由子类实现
407+ virtual void encode (Tokens* dst, const uint8_t * src, size_t len) = 0;
381408
382409protected:
383410 std::vector<uint8_t > hist_;
@@ -392,8 +419,8 @@ class FastEncL1 : public FastGen {
392419public:
393420 FastEncL1 () { table_.fill ({}); }
394421
395- void encode (Tokens* dst, const uint8_t * src, size_t len);
396- void reset ();
422+ void encode (Tokens* dst, const uint8_t * src, size_t len) override ;
423+ void reset () override ;
397424
398425private:
399426 std::array<TableEntry, TABLE_SIZE > table_;
@@ -410,8 +437,8 @@ class FastEncL4 : public FastGen {
410437 bTable_.fill ({});
411438 }
412439
413- void encode (Tokens* dst, const uint8_t * src, size_t len);
414- void reset ();
440+ void encode (Tokens* dst, const uint8_t * src, size_t len) override ;
441+ void reset () override ;
415442
416443private:
417444 std::array<TableEntry, TABLE_SIZE > table_;
@@ -448,22 +475,46 @@ size_t deflateCompress(const uint8_t* input, size_t inputSize,
448475 CompressionLevel level = CompressionLevel::DefaultCompression);
449476
450477// ============================================================================
451- // DeflateStream
478+ // FlateWriter - 流式压缩器(参照 Go klauspost/compress flate.Writer)
452479// ============================================================================
453480
454- class DeflateStream {
481+ // 输出回调类型(参照 Go io.Writer)
482+ using WriteFunc = std::function<void (const uint8_t *, size_t )>;
483+
484+ class FlateWriter {
455485public:
456- explicit DeflateStream (CompressionLevel level = CompressionLevel::DefaultCompression);
457- ~DeflateStream ();
486+ // 接收输出目标(参照 Go flate.NewWriter(w io.Writer, level int))
487+ explicit FlateWriter (WriteFunc output, CompressionLevel level = CompressionLevel::BestSpeed);
488+ ~FlateWriter () = default ;
458489
490+ // 流式写入数据(参照 Go compressor.write)
459491 size_t write (const uint8_t * data, size_t size);
460- size_t finish (std::vector<uint8_t >& output);
461- void reset ();
492+
493+ // 完成压缩(参照 Go compressor.Close)
494+ void close ();
495+
496+ // 重置并设置新的输出目标(参照 Go compressor.Reset)
497+ void reset (WriteFunc output);
462498
463499private:
464- std::unique_ptr<FastDeflate> deflate_;
465- std::vector<uint8_t > buffer_;
466- static constexpr size_t BUFFER_SIZE = 128 * 1024 ;
500+ void storeFast ();
501+ size_t fillBlock (const uint8_t * data, size_t size);
502+ void flushOutput ();
503+
504+ // 获取当前使用的编码器
505+ FastGen* encoder () const { return useL1_ ? static_cast <FastGen*>(encoderL1_.get ())
506+ : static_cast <FastGen*>(encoderL4_.get ()); }
507+
508+ WriteFunc output_;
509+ std::vector<uint8_t > window_;
510+ size_t windowEnd_ = 0 ;
511+
512+ CompressionLevel level_;
513+ bool useL1_ = true ; // Level 1-3 使用 L1,Level 4+ 使用 L4
514+ std::unique_ptr<FastEncL1> encoderL1_;
515+ std::unique_ptr<FastEncL4> encoderL4_;
516+ std::unique_ptr<HuffmanBitWriter> writer_;
517+ Tokens tokens_;
467518};
468519
469520} // namespace pzip
0 commit comments