deflate-ruby 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CLAUDE.md +95 -92
- data/LICENSE.txt +6 -6
- data/README.md +87 -65
- data/Rakefile +23 -0
- data/ext/deflate_ruby/{libdeflate/lib/x86/adler32_impl.h → adler32_impl.h} +8 -7
- data/ext/deflate_ruby/common_defs.h +748 -0
- data/ext/deflate_ruby/{libdeflate/lib/x86/cpu_features.c → cpu_features.c} +46 -16
- data/ext/deflate_ruby/{libdeflate/lib/x86/cpu_features.h → cpu_features.h} +2 -1
- data/ext/deflate_ruby/{libdeflate/lib/x86/crc32_impl.h → crc32_impl.h} +22 -23
- data/ext/deflate_ruby/{libdeflate/lib/crc32_multipliers.h → crc32_multipliers.h} +2 -4
- data/ext/deflate_ruby/{libdeflate/lib/x86/crc32_pclmul_template.h → crc32_pclmul_template.h} +23 -94
- data/ext/deflate_ruby/{libdeflate/lib/crc32_tables.h → crc32_tables.h} +1 -1
- data/ext/deflate_ruby/{libdeflate/lib/deflate_compress.c → deflate_compress.c} +59 -60
- data/ext/deflate_ruby/deflate_ruby.c +392 -218
- data/ext/deflate_ruby/deflate_ruby.h +6 -0
- data/ext/deflate_ruby/extconf.rb +35 -25
- data/ext/deflate_ruby/libdeflate/adler32.c +162 -0
- data/ext/deflate_ruby/libdeflate/{lib/arm → arm}/adler32_impl.h +14 -7
- data/ext/deflate_ruby/libdeflate/{lib/arm → arm}/crc32_impl.h +25 -31
- data/ext/deflate_ruby/libdeflate/arm/crc32_pmull_helpers.h +156 -0
- data/ext/deflate_ruby/libdeflate/arm/crc32_pmull_wide.h +226 -0
- data/ext/deflate_ruby/libdeflate/bt_matchfinder.h +342 -0
- data/ext/deflate_ruby/libdeflate/common_defs.h +2 -1
- data/ext/deflate_ruby/libdeflate/cpu_features_common.h +93 -0
- data/ext/deflate_ruby/libdeflate/crc32.c +262 -0
- data/ext/deflate_ruby/libdeflate/crc32_multipliers.h +375 -0
- data/ext/deflate_ruby/libdeflate/crc32_tables.h +587 -0
- data/ext/deflate_ruby/libdeflate/decompress_template.h +777 -0
- data/ext/deflate_ruby/libdeflate/deflate_compress.c +4128 -0
- data/ext/deflate_ruby/libdeflate/deflate_compress.h +15 -0
- data/ext/deflate_ruby/libdeflate/deflate_constants.h +56 -0
- data/ext/deflate_ruby/libdeflate/deflate_decompress.c +1208 -0
- data/ext/deflate_ruby/libdeflate/gzip_compress.c +90 -0
- data/ext/deflate_ruby/libdeflate/gzip_constants.h +45 -0
- data/ext/deflate_ruby/libdeflate/gzip_decompress.c +144 -0
- data/ext/deflate_ruby/libdeflate/hc_matchfinder.h +401 -0
- data/ext/deflate_ruby/libdeflate/ht_matchfinder.h +234 -0
- data/ext/deflate_ruby/libdeflate/lib_common.h +106 -0
- data/ext/deflate_ruby/libdeflate/libdeflate.h +2 -2
- data/ext/deflate_ruby/libdeflate/{lib/matchfinder_common.h → matchfinder_common.h} +3 -3
- data/ext/deflate_ruby/libdeflate/x86/adler32_impl.h +135 -0
- data/ext/deflate_ruby/libdeflate/x86/adler32_template.h +518 -0
- data/ext/deflate_ruby/libdeflate/x86/cpu_features.c +213 -0
- data/ext/deflate_ruby/libdeflate/x86/cpu_features.h +170 -0
- data/ext/deflate_ruby/libdeflate/x86/crc32_impl.h +159 -0
- data/ext/deflate_ruby/libdeflate/x86/crc32_pclmul_template.h +424 -0
- data/ext/deflate_ruby/libdeflate/x86/decompress_impl.h +57 -0
- data/ext/deflate_ruby/libdeflate.h +411 -0
- data/ext/deflate_ruby/matchfinder_common.h +224 -0
- data/ext/deflate_ruby/matchfinder_impl.h +122 -0
- data/ext/deflate_ruby/utils.c +141 -0
- data/ext/deflate_ruby/zlib_compress.c +82 -0
- data/ext/deflate_ruby/zlib_constants.h +21 -0
- data/ext/deflate_ruby/zlib_decompress.c +104 -0
- data/lib/deflate_ruby/version.rb +1 -1
- data/lib/deflate_ruby.rb +1 -63
- data/sig/deflate_ruby.rbs +4 -0
- data/test/test_deflate_ruby.rb +220 -0
- data/test/test_helper.rb +6 -0
- metadata +89 -144
- data/ext/deflate_ruby/libdeflate/CMakeLists.txt +0 -270
- data/ext/deflate_ruby/libdeflate/NEWS.md +0 -494
- data/ext/deflate_ruby/libdeflate/README.md +0 -228
- data/ext/deflate_ruby/libdeflate/libdeflate-config.cmake.in +0 -3
- data/ext/deflate_ruby/libdeflate/libdeflate.pc.in +0 -18
- data/ext/deflate_ruby/libdeflate/programs/CMakeLists.txt +0 -105
- data/ext/deflate_ruby/libdeflate/programs/benchmark.c +0 -696
- data/ext/deflate_ruby/libdeflate/programs/checksum.c +0 -218
- data/ext/deflate_ruby/libdeflate/programs/config.h.in +0 -19
- data/ext/deflate_ruby/libdeflate/programs/gzip.c +0 -688
- data/ext/deflate_ruby/libdeflate/programs/prog_util.c +0 -521
- data/ext/deflate_ruby/libdeflate/programs/prog_util.h +0 -225
- data/ext/deflate_ruby/libdeflate/programs/test_checksums.c +0 -200
- data/ext/deflate_ruby/libdeflate/programs/test_custom_malloc.c +0 -155
- data/ext/deflate_ruby/libdeflate/programs/test_incomplete_codes.c +0 -385
- data/ext/deflate_ruby/libdeflate/programs/test_invalid_streams.c +0 -130
- data/ext/deflate_ruby/libdeflate/programs/test_litrunlen_overflow.c +0 -72
- data/ext/deflate_ruby/libdeflate/programs/test_overread.c +0 -95
- data/ext/deflate_ruby/libdeflate/programs/test_slow_decompression.c +0 -472
- data/ext/deflate_ruby/libdeflate/programs/test_trailing_bytes.c +0 -151
- data/ext/deflate_ruby/libdeflate/programs/test_util.c +0 -237
- data/ext/deflate_ruby/libdeflate/programs/test_util.h +0 -61
- data/ext/deflate_ruby/libdeflate/programs/tgetopt.c +0 -118
- data/ext/deflate_ruby/libdeflate/scripts/android_build.sh +0 -118
- data/ext/deflate_ruby/libdeflate/scripts/android_tests.sh +0 -69
- data/ext/deflate_ruby/libdeflate/scripts/benchmark.sh +0 -10
- data/ext/deflate_ruby/libdeflate/scripts/checksum.sh +0 -10
- data/ext/deflate_ruby/libdeflate/scripts/checksum_benchmarks.sh +0 -253
- data/ext/deflate_ruby/libdeflate/scripts/cmake-helper.sh +0 -17
- data/ext/deflate_ruby/libdeflate/scripts/deflate_benchmarks.sh +0 -119
- data/ext/deflate_ruby/libdeflate/scripts/exec_tests.sh +0 -38
- data/ext/deflate_ruby/libdeflate/scripts/gen-release-archives.sh +0 -37
- data/ext/deflate_ruby/libdeflate/scripts/gen_bitreverse_tab.py +0 -19
- data/ext/deflate_ruby/libdeflate/scripts/gen_crc32_multipliers.c +0 -199
- data/ext/deflate_ruby/libdeflate/scripts/gen_crc32_tables.c +0 -105
- data/ext/deflate_ruby/libdeflate/scripts/gen_default_litlen_costs.py +0 -44
- data/ext/deflate_ruby/libdeflate/scripts/gen_offset_slot_map.py +0 -29
- data/ext/deflate_ruby/libdeflate/scripts/gzip_tests.sh +0 -523
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/deflate_compress/corpus/0 +0 -0
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/deflate_compress/fuzz.c +0 -95
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/deflate_decompress/corpus/0 +0 -3
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/deflate_decompress/fuzz.c +0 -62
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/fuzz.sh +0 -108
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/gzip_decompress/corpus/0 +0 -0
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/gzip_decompress/fuzz.c +0 -19
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/zlib_decompress/corpus/0 +0 -3
- data/ext/deflate_ruby/libdeflate/scripts/libFuzzer/zlib_decompress/fuzz.c +0 -19
- data/ext/deflate_ruby/libdeflate/scripts/run_tests.sh +0 -416
- data/ext/deflate_ruby/libdeflate/scripts/toolchain-i686-w64-mingw32.cmake +0 -8
- data/ext/deflate_ruby/libdeflate/scripts/toolchain-x86_64-w64-mingw32.cmake +0 -8
- /data/ext/deflate_ruby/{libdeflate/lib/adler32.c → adler32.c} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/x86/adler32_template.h → adler32_template.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/bt_matchfinder.h → bt_matchfinder.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/cpu_features_common.h → cpu_features_common.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/crc32.c → crc32.c} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/arm/crc32_pmull_helpers.h → crc32_pmull_helpers.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/arm/crc32_pmull_wide.h → crc32_pmull_wide.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/x86/decompress_impl.h → decompress_impl.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/decompress_template.h → decompress_template.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/deflate_compress.h → deflate_compress.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/deflate_constants.h → deflate_constants.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/deflate_decompress.c → deflate_decompress.c} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/gzip_compress.c → gzip_compress.c} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/gzip_constants.h → gzip_constants.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/gzip_decompress.c → gzip_decompress.c} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/hc_matchfinder.h → hc_matchfinder.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/ht_matchfinder.h → ht_matchfinder.h} +0 -0
- /data/ext/deflate_ruby/{libdeflate/lib/lib_common.h → lib_common.h} +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/arm → arm}/cpu_features.c +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/arm → arm}/cpu_features.h +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/arm → arm}/matchfinder_impl.h +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/riscv → riscv}/matchfinder_impl.h +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/utils.c → utils.c} +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/x86 → x86}/matchfinder_impl.h +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/zlib_compress.c → zlib_compress.c} +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/zlib_constants.h → zlib_constants.h} +0 -0
- /data/ext/deflate_ruby/libdeflate/{lib/zlib_decompress.c → zlib_decompress.c} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 88a97c7ccd0d0ef7d03fcaa9d214bd30ef1fa73b4326972b85c7bb95ecf063eb
|
|
4
|
+
data.tar.gz: aa4e11e8c5adcc97dd727ec5bdf32428f3d66b1af6378c39c61e6fe1e6170caf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6b475adcceaf1ebbe98a1af627a709aa1a5cfcff8a4080489718d618e4f1a541ffb36506800881a6304115eb6d8e8860613019d9364106118613450941081b6b
|
|
7
|
+
data.tar.gz: 88e08c9c81b82d445e5e944c6b0d8ab86cf7b030d579e5c5a87e214e3315216c98a779a3c2ec3417a80206582b89c91280e74a203c7e14aabe488f948639009d
|
data/CLAUDE.md
CHANGED
|
@@ -4,53 +4,65 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
DeflateRuby is a Ruby gem that
|
|
7
|
+
DeflateRuby is a Ruby gem that provides bindings to libdeflate, a heavily optimized library for DEFLATE, gzip, and zlib compression/decompression. The gem bundles the complete libdeflate source code and compiles it as a native C extension.
|
|
8
8
|
|
|
9
9
|
## Architecture
|
|
10
10
|
|
|
11
11
|
### Core Components
|
|
12
12
|
|
|
13
|
-
1. **C Extension** (`ext/deflate_ruby
|
|
14
|
-
-
|
|
15
|
-
- `
|
|
16
|
-
-
|
|
13
|
+
1. **C Extension** (`ext/deflate_ruby/deflate_ruby.c`)
|
|
14
|
+
- Wraps all libdeflate APIs using Ruby's C API
|
|
15
|
+
- Implements `DeflateRuby::Compressor` and `DeflateRuby::Decompressor` classes
|
|
16
|
+
- Provides module-level `crc32` and `adler32` functions
|
|
17
|
+
- Uses Ruby's TypedData API for memory-safe object wrapping
|
|
17
18
|
|
|
18
|
-
2. **
|
|
19
|
-
-
|
|
20
|
-
- `
|
|
21
|
-
-
|
|
19
|
+
2. **Bundled libdeflate Source** (`ext/deflate_ruby/libdeflate/`)
|
|
20
|
+
- Complete libdeflate source code (from https://github.com/ebiggers/libdeflate)
|
|
21
|
+
- Architecture-specific optimizations in subdirectories: `arm/`, `x86/`, `riscv/`
|
|
22
|
+
- Build system selects appropriate CPU-specific code at compile time
|
|
22
23
|
|
|
23
|
-
3. **
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- `
|
|
24
|
+
3. **Build Configuration** (`ext/deflate_ruby/extconf.rb`)
|
|
25
|
+
- Detects CPU architecture via `RbConfig::CONFIG['host_cpu']`
|
|
26
|
+
- Includes only relevant architecture-specific C files to avoid symbol conflicts
|
|
27
|
+
- Each architecture subdirectory has its own `cpu_features.c` - only one is compiled
|
|
28
|
+
- Adds optimization flags (-O3) and sets up include paths
|
|
27
29
|
|
|
28
|
-
###
|
|
30
|
+
### API Design
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
The gem provides a Ruby-friendly API that mirrors libdeflate's functionality:
|
|
31
33
|
|
|
32
|
-
- **
|
|
34
|
+
- **Compressor**: Stateful object for compression operations
|
|
35
|
+
- `deflate_compress(data)` - Raw DEFLATE compression
|
|
36
|
+
- `zlib_compress(data)` - Zlib format (with header/trailer)
|
|
37
|
+
- `gzip_compress(data)` - Gzip format (with header/trailer)
|
|
38
|
+
- `*_compress_bound(size)` - Calculates worst-case output size
|
|
33
39
|
|
|
34
|
-
- **
|
|
40
|
+
- **Decompressor**: Stateful object for decompression operations
|
|
41
|
+
- `deflate_decompress(data, output_size)` - Raw DEFLATE decompression
|
|
42
|
+
- `zlib_decompress(data, output_size)` - Zlib format
|
|
43
|
+
- `gzip_decompress(data, output_size)` - Gzip format
|
|
44
|
+
- Requires output size parameter (libdeflate design constraint)
|
|
35
45
|
|
|
36
|
-
|
|
46
|
+
- **Module Functions**: Stateless checksum operations
|
|
47
|
+
- `DeflateRuby.crc32(data, initial=0)` - CRC32 checksum
|
|
48
|
+
- `DeflateRuby.adler32(data, initial=1)` - Adler32 checksum
|
|
49
|
+
|
|
50
|
+
## Development Workflow
|
|
37
51
|
|
|
38
52
|
### Building the Extension
|
|
39
53
|
|
|
40
54
|
```bash
|
|
41
|
-
#
|
|
55
|
+
# Generate Makefile and compile
|
|
42
56
|
cd ext/deflate_ruby
|
|
43
57
|
ruby extconf.rb
|
|
44
58
|
make
|
|
45
59
|
|
|
46
|
-
#
|
|
47
|
-
cp deflate_ruby.so ../../lib/deflate_ruby/
|
|
48
|
-
|
|
49
|
-
# Or use rake
|
|
50
|
-
cd ../..
|
|
60
|
+
# Or use rake from root
|
|
51
61
|
rake compile
|
|
52
62
|
```
|
|
53
63
|
|
|
64
|
+
The compiled `.so` file is placed in `ext/deflate_ruby/` and should be copied to `lib/deflate_ruby/` for testing.
|
|
65
|
+
|
|
54
66
|
### Running Tests
|
|
55
67
|
|
|
56
68
|
```bash
|
|
@@ -58,81 +70,72 @@ rake compile
|
|
|
58
70
|
rake test
|
|
59
71
|
|
|
60
72
|
# Run specific test file
|
|
61
|
-
ruby -
|
|
62
|
-
ruby -Ilib:test test/zlib_test.rb
|
|
63
|
-
ruby -Ilib:test test/gzip_test.rb
|
|
64
|
-
|
|
65
|
-
# Run single test method
|
|
66
|
-
ruby -Ilib:test test/deflate_test.rb -n test_deflate_compress_decompress_roundtrip
|
|
73
|
+
ruby -I./lib:./test test/test_deflate_ruby.rb
|
|
67
74
|
```
|
|
68
75
|
|
|
69
|
-
|
|
76
|
+
Tests use Minitest and cover:
|
|
77
|
+
- Compression/decompression round-trips for all formats
|
|
78
|
+
- Different compression levels (0-12)
|
|
79
|
+
- Edge cases (empty data, large data, binary data)
|
|
80
|
+
- Checksum functions with incremental updates
|
|
81
|
+
- Error handling for invalid compressed data
|
|
82
|
+
|
|
83
|
+
### Building the Gem
|
|
70
84
|
|
|
71
85
|
```bash
|
|
72
|
-
|
|
73
|
-
|
|
86
|
+
# Build gem package
|
|
87
|
+
rake build
|
|
74
88
|
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
rake clean
|
|
89
|
+
# Install locally for testing
|
|
90
|
+
rake install
|
|
78
91
|
```
|
|
79
92
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
### C Extension (ext/deflate_ruby/deflate_ruby.c)
|
|
83
|
-
|
|
84
|
-
- **Error Handling**: Uses custom `DeflateRuby::Error` exception class for all compression/decompression errors
|
|
85
|
-
- **Memory Management**: All libdeflate compressor/decompressor objects are properly freed after use
|
|
86
|
-
- **Compression Levels**: Supports levels 1-12 (libdeflate extends beyond standard 1-9)
|
|
87
|
-
- **Buffer Allocation**: Uses Ruby's string buffer API (`rb_str_buf_new`, `rb_str_resize`) for efficient memory handling
|
|
88
|
-
|
|
89
|
-
### Extension Configuration (ext/deflate_ruby/extconf.rb)
|
|
90
|
-
|
|
91
|
-
- Compiles all libdeflate source files from `lib/*.c` and architecture-specific subdirectories (`lib/x86/*.c`, `lib/arm/*.c`)
|
|
92
|
-
- Uses `-O2` optimization and `-std=c99` for C99 compatibility
|
|
93
|
-
- Sets up include paths to find `libdeflate.h`
|
|
94
|
-
|
|
95
|
-
### Test Data Characteristics
|
|
96
|
-
|
|
97
|
-
- Tests use moderately large data (1000x repetitions) to see meaningful compression level differences
|
|
98
|
-
- For gzip tests, binary data is prepended to text to make compression level differences more apparent
|
|
99
|
-
- Compression level tests compare level 1 vs level 6 (not higher levels) as very high levels can sometimes produce larger output on small, highly compressible data
|
|
93
|
+
### Clean Build
|
|
100
94
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
- Provides faster compression/decompression than zlib for whole-buffer operations
|
|
106
|
-
- Includes CPU-specific optimizations (x86 SSE/AVX, ARM NEON)
|
|
107
|
-
- Supports DEFLATE, zlib, and gzip formats
|
|
108
|
-
- Is designed for non-streaming (whole-buffer) use cases
|
|
109
|
-
|
|
110
|
-
**Version**: Currently using libdeflate v1.21
|
|
111
|
-
|
|
112
|
-
**Updating libdeflate**: To update to a new version:
|
|
113
|
-
1. Download new release from https://github.com/ebiggers/libdeflate/releases
|
|
114
|
-
2. Extract to `ext/deflate_ruby/libdeflate/`
|
|
115
|
-
3. Test thoroughly as API may have changed
|
|
116
|
-
4. Update version reference in this file
|
|
117
|
-
|
|
118
|
-
## Testing Philosophy
|
|
119
|
-
|
|
120
|
-
This gem follows test-driven development (TDD):
|
|
121
|
-
|
|
122
|
-
1. Tests were written first, defining expected behavior
|
|
123
|
-
2. Implementation follows the test specifications
|
|
124
|
-
3. All three formats (deflate, zlib, gzip) have comprehensive test coverage including:
|
|
125
|
-
- Round-trip compression/decompression
|
|
126
|
-
- Multiple compression levels
|
|
127
|
-
- Empty data handling
|
|
128
|
-
- Invalid data error handling
|
|
129
|
-
- Binary data support
|
|
130
|
-
- Interoperability with Ruby's stdlib Zlib
|
|
131
|
-
|
|
132
|
-
## Compression Format Notes
|
|
95
|
+
```bash
|
|
96
|
+
# Clean compiled files
|
|
97
|
+
rake clobber
|
|
98
|
+
```
|
|
133
99
|
|
|
134
|
-
|
|
135
|
-
- **zlib**: DEFLATE stream with zlib header and Adler-32 checksum trailer
|
|
136
|
-
- **gzip**: DEFLATE stream with gzip header (includes magic bytes 0x1f 0x8b) and CRC32 checksum trailer
|
|
100
|
+
## Important Implementation Details
|
|
137
101
|
|
|
138
|
-
|
|
102
|
+
### Memory Management
|
|
103
|
+
- Compressor and decompressor objects use Ruby's TypedData with custom free functions
|
|
104
|
+
- `libdeflate_free_compressor/decompressor` called automatically during GC
|
|
105
|
+
- Explicit `close()` methods provided for manual resource management
|
|
106
|
+
- NULL checks prevent double-free issues
|
|
107
|
+
|
|
108
|
+
### Architecture-Specific Compilation
|
|
109
|
+
The `extconf.rb` script selects CPU-specific source files to avoid duplicate symbol errors:
|
|
110
|
+
- x86/x86_64: Includes `x86/cpu_features.c` and SSE optimizations
|
|
111
|
+
- ARM/AArch64: Includes `arm/cpu_features.c` and NEON optimizations
|
|
112
|
+
- RISC-V: Includes only base implementation
|
|
113
|
+
- Only ONE architecture's files are compiled per build
|
|
114
|
+
|
|
115
|
+
### Error Handling
|
|
116
|
+
- All libdeflate result codes are mapped to Ruby exceptions
|
|
117
|
+
- `DeflateRuby::CompressionError` - Compression failures
|
|
118
|
+
- `DeflateRuby::DecompressionError` - Decompression failures (bad data, size mismatch)
|
|
119
|
+
- Detailed error messages based on libdeflate result codes
|
|
120
|
+
|
|
121
|
+
## Testing Notes
|
|
122
|
+
|
|
123
|
+
- Tests verify compatibility with standard formats (can compress with DeflateRuby, decompress with Ruby Zlib and vice versa)
|
|
124
|
+
- Decompression requires knowing the original uncompressed size (libdeflate design)
|
|
125
|
+
- Compression level 0 = no compression (store only)
|
|
126
|
+
- Compression level 12 = maximum compression (slower)
|
|
127
|
+
- Default level 6 balances speed and compression ratio
|
|
128
|
+
|
|
129
|
+
## Publishing to RubyGems
|
|
130
|
+
|
|
131
|
+
The gemspec is already configured for publication:
|
|
132
|
+
- Homepage: https://github.com/jgreninger/deflate_ruby
|
|
133
|
+
- License: MIT (covers both gem and bundled libdeflate)
|
|
134
|
+
- Includes all libdeflate source in the gem package
|
|
135
|
+
- Extension builds automatically during `gem install`
|
|
136
|
+
|
|
137
|
+
To publish:
|
|
138
|
+
```bash
|
|
139
|
+
gem build deflate_ruby.gemspec
|
|
140
|
+
gem push deflate_ruby-0.1.0.gem
|
|
141
|
+
```
|
data/LICENSE.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
MIT License
|
|
1
|
+
The MIT License (MIT)
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2025
|
|
3
|
+
Copyright (c) 2025 John Greninger
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
9
9
|
copies of the Software, and to permit persons to whom the Software is
|
|
10
10
|
furnished to do so, subject to the following conditions:
|
|
11
11
|
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
copies or substantial portions of the Software.
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
14
|
|
|
15
15
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
16
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
17
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
18
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
19
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
SOFTWARE.
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
|
@@ -1,117 +1,139 @@
|
|
|
1
1
|
# DeflateRuby
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ruby bindings for [libdeflate](https://github.com/ebiggers/libdeflate), a heavily optimized library for DEFLATE, gzip, and zlib compression and decompression.
|
|
4
4
|
|
|
5
|
-
DeflateRuby provides
|
|
5
|
+
DeflateRuby provides significantly faster compression and decompression compared to Ruby's built-in Zlib module, while maintaining full compatibility with standard DEFLATE, gzip, and zlib formats.
|
|
6
6
|
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
### From RubyGems.org
|
|
10
|
-
|
|
11
|
-
Install the gem directly:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
gem install deflate-ruby
|
|
15
|
-
```
|
|
7
|
+
## Features
|
|
16
8
|
|
|
17
|
-
|
|
9
|
+
- **Fast compression and decompression** - Leverages libdeflate's heavily optimized implementation
|
|
10
|
+
- **Multiple compression formats** - Support for raw DEFLATE, zlib, and gzip formats
|
|
11
|
+
- **Configurable compression levels** - Levels 0-12 (higher = better compression, slower)
|
|
12
|
+
- **Checksum functions** - CRC32 and Adler32 implementations
|
|
13
|
+
- **Cross-platform** - Works on x86, ARM, and RISC-V architectures
|
|
14
|
+
- **Clean API** - Simple, Ruby-friendly interface
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
gem 'deflate-ruby'
|
|
21
|
-
```
|
|
16
|
+
## Installation
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
Install the gem by executing:
|
|
24
19
|
|
|
25
20
|
```bash
|
|
26
|
-
|
|
21
|
+
gem install deflate_ruby
|
|
27
22
|
```
|
|
28
23
|
|
|
29
|
-
|
|
24
|
+
Or add to your Gemfile:
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
git clone https://github.com/deflate-ruby/deflate-ruby.git
|
|
35
|
-
cd deflate-ruby
|
|
36
|
-
gem build deflate-ruby.gemspec
|
|
37
|
-
gem install deflate-ruby-0.1.0.gem
|
|
26
|
+
```ruby
|
|
27
|
+
gem 'deflate_ruby'
|
|
38
28
|
```
|
|
39
29
|
|
|
40
30
|
## Usage
|
|
41
31
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
### String Compression/Decompression
|
|
32
|
+
### Compression
|
|
45
33
|
|
|
46
34
|
```ruby
|
|
47
35
|
require 'deflate_ruby'
|
|
48
36
|
|
|
37
|
+
# Create a compressor
|
|
38
|
+
compressor = DeflateRuby::Compressor.new(level: 6) # level 0-12, default 6
|
|
39
|
+
|
|
40
|
+
# Compress data in different formats
|
|
49
41
|
data = "Hello, World!" * 100
|
|
50
42
|
|
|
51
|
-
# DEFLATE
|
|
52
|
-
|
|
53
|
-
decompressed = DeflateRuby.deflate_decompress(compressed)
|
|
43
|
+
# Raw DEFLATE
|
|
44
|
+
deflated = compressor.deflate_compress(data)
|
|
54
45
|
|
|
55
|
-
# Zlib
|
|
56
|
-
|
|
57
|
-
decompressed = DeflateRuby.zlib_decompress(compressed)
|
|
46
|
+
# Zlib format (with header and checksum)
|
|
47
|
+
zlib_compressed = compressor.zlib_compress(data)
|
|
58
48
|
|
|
59
|
-
# Gzip
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
# Gzip format (with header and checksum)
|
|
50
|
+
gzip_compressed = compressor.gzip_compress(data)
|
|
51
|
+
|
|
52
|
+
# Always close the compressor when done
|
|
53
|
+
compressor.close
|
|
62
54
|
```
|
|
63
55
|
|
|
64
|
-
###
|
|
56
|
+
### Decompression
|
|
65
57
|
|
|
66
58
|
```ruby
|
|
67
|
-
#
|
|
68
|
-
DeflateRuby.
|
|
69
|
-
DeflateRuby.deflate_decompress_file("output.deflate", "decompressed.txt")
|
|
59
|
+
# Create a decompressor
|
|
60
|
+
decompressor = DeflateRuby::Decompressor.new
|
|
70
61
|
|
|
71
|
-
#
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
# Decompress data (must know original size)
|
|
63
|
+
original_data = decompressor.deflate_decompress(deflated, data.bytesize)
|
|
64
|
+
original_data = decompressor.zlib_decompress(zlib_compressed, data.bytesize)
|
|
65
|
+
original_data = decompressor.gzip_decompress(gzip_compressed, data.bytesize)
|
|
74
66
|
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
DeflateRuby.gzip_decompress_file("output.gz", "decompressed.txt")
|
|
67
|
+
# Always close the decompressor when done
|
|
68
|
+
decompressor.close
|
|
78
69
|
```
|
|
79
70
|
|
|
80
|
-
###
|
|
71
|
+
### Checksums
|
|
81
72
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
```ruby
|
|
74
|
+
# CRC32
|
|
75
|
+
crc = DeflateRuby.crc32("Hello, World!")
|
|
85
76
|
|
|
86
|
-
|
|
77
|
+
# CRC32 with initial value (for incremental calculation)
|
|
78
|
+
crc1 = DeflateRuby.crc32("Hello, ")
|
|
79
|
+
crc2 = DeflateRuby.crc32("World!", crc1)
|
|
87
80
|
|
|
88
|
-
|
|
81
|
+
# Adler32
|
|
82
|
+
adler = DeflateRuby.adler32("Hello, World!")
|
|
89
83
|
|
|
90
|
-
|
|
84
|
+
# Adler32 with initial value
|
|
85
|
+
adler1 = DeflateRuby.adler32("Hello, ")
|
|
86
|
+
adler2 = DeflateRuby.adler32("World!", adler1)
|
|
87
|
+
```
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
### Compression Bounds
|
|
93
90
|
|
|
94
|
-
|
|
91
|
+
```ruby
|
|
92
|
+
# Get worst-case compressed size for a given input size
|
|
93
|
+
compressor = DeflateRuby::Compressor.new
|
|
94
|
+
bound = compressor.deflate_compress_bound(1000)
|
|
95
|
+
zlib_bound = compressor.zlib_compress_bound(1000)
|
|
96
|
+
gzip_bound = compressor.gzip_compress_bound(1000)
|
|
97
|
+
compressor.close
|
|
98
|
+
```
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
-
|
|
99
|
-
- High-throughput scenarios
|
|
100
|
+
## Performance
|
|
101
|
+
|
|
102
|
+
DeflateRuby is significantly faster than Ruby's built-in Zlib for both compression and decompression, especially at higher compression levels. Benchmarks show 2-5x performance improvements depending on the data and compression level.
|
|
100
103
|
|
|
101
104
|
## Development
|
|
102
105
|
|
|
103
|
-
After checking out the repo
|
|
106
|
+
After checking out the repo:
|
|
104
107
|
|
|
105
108
|
```bash
|
|
109
|
+
cd deflate_ruby
|
|
106
110
|
bundle install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
To compile the extension:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
107
116
|
rake compile
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
To run tests:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
108
122
|
rake test
|
|
109
123
|
```
|
|
110
124
|
|
|
111
|
-
|
|
125
|
+
To build the gem:
|
|
112
126
|
|
|
113
|
-
|
|
127
|
+
```bash
|
|
128
|
+
rake build
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Contributing
|
|
132
|
+
|
|
133
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jgreninger/deflate_ruby.
|
|
134
|
+
|
|
135
|
+
## License
|
|
114
136
|
|
|
115
|
-
|
|
137
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
116
138
|
|
|
117
|
-
This gem
|
|
139
|
+
This gem bundles [libdeflate](https://github.com/ebiggers/libdeflate), which is also licensed under the MIT License.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/extensiontask"
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
|
|
7
|
+
task build: :compile
|
|
8
|
+
|
|
9
|
+
GEMSPEC = Gem::Specification.load("deflate_ruby.gemspec")
|
|
10
|
+
|
|
11
|
+
Rake::ExtensionTask.new("deflate_ruby", GEMSPEC) do |ext|
|
|
12
|
+
ext.lib_dir = "lib/deflate_ruby"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Rake::TestTask.new(:test) do |t|
|
|
16
|
+
t.libs << "test"
|
|
17
|
+
t.libs << "lib"
|
|
18
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
task test: :compile
|
|
22
|
+
|
|
23
|
+
task default: %i[clobber compile test]
|
|
@@ -60,7 +60,8 @@
|
|
|
60
60
|
* instead of gcc 11. (libdeflate supports direct compilation without a
|
|
61
61
|
* configure step, so checking the binutils version is not always an option.)
|
|
62
62
|
*/
|
|
63
|
-
#if GCC_PREREQ(12, 1) || CLANG_PREREQ(12, 0, 13000000) || MSVC_PREREQ(1930)
|
|
63
|
+
#if (GCC_PREREQ(12, 1) || CLANG_PREREQ(12, 0, 13000000) || MSVC_PREREQ(1930)) && \
|
|
64
|
+
!defined(LIBDEFLATE_ASSEMBLER_DOES_NOT_SUPPORT_AVX_VNNI)
|
|
64
65
|
# define adler32_x86_avx2_vnni adler32_x86_avx2_vnni
|
|
65
66
|
# define SUFFIX _avx2_vnni
|
|
66
67
|
# define ATTRIBUTES _target_attribute("avx2,avxvnni")
|
|
@@ -70,13 +71,14 @@
|
|
|
70
71
|
# include "adler32_template.h"
|
|
71
72
|
#endif
|
|
72
73
|
|
|
73
|
-
#if GCC_PREREQ(8, 1) || CLANG_PREREQ(6, 0, 10000000) || MSVC_PREREQ(1920)
|
|
74
|
+
#if (GCC_PREREQ(8, 1) || CLANG_PREREQ(6, 0, 10000000) || MSVC_PREREQ(1920)) && \
|
|
75
|
+
!defined(LIBDEFLATE_ASSEMBLER_DOES_NOT_SUPPORT_AVX512VNNI)
|
|
74
76
|
/*
|
|
75
77
|
* AVX512VNNI implementation using 256-bit vectors. This is very similar to the
|
|
76
78
|
* AVX-VNNI implementation but takes advantage of masking and more registers.
|
|
77
|
-
* This is used on
|
|
78
|
-
*
|
|
79
|
-
*
|
|
79
|
+
* This is used on certain older Intel CPUs, specifically Ice Lake and Tiger
|
|
80
|
+
* Lake, which support AVX512VNNI but downclock a bit too eagerly when ZMM
|
|
81
|
+
* registers are used.
|
|
80
82
|
*/
|
|
81
83
|
# define adler32_x86_avx512_vl256_vnni adler32_x86_avx512_vl256_vnni
|
|
82
84
|
# define SUFFIX _avx512_vl256_vnni
|
|
@@ -88,8 +90,7 @@
|
|
|
88
90
|
|
|
89
91
|
/*
|
|
90
92
|
* AVX512VNNI implementation using 512-bit vectors. This is used on CPUs that
|
|
91
|
-
* have a good AVX-512 implementation including AVX512VNNI.
|
|
92
|
-
* the optimal implementation on CPUs that support AVX10/512.
|
|
93
|
+
* have a good AVX-512 implementation including AVX512VNNI.
|
|
93
94
|
*/
|
|
94
95
|
# define adler32_x86_avx512_vl512_vnni adler32_x86_avx512_vl512_vnni
|
|
95
96
|
# define SUFFIX _avx512_vl512_vnni
|