lz4-native-ruby 1.0.0 → 1.0.1
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 +292 -0
- data/LICENSE +55 -21
- data/README.md +109 -15
- data/{vendor/lz4/lib → ext/lz4_native}/Makefile +29 -24
- data/{vendor/lz4/lib → ext/lz4_native}/README.md +1 -1
- data/ext/lz4_native/extconf.rb +33 -0
- data/{vendor/lz4/lib → ext/lz4_native}/liblz4.pc.in +1 -0
- data/{vendor/lz4/lib → ext/lz4_native}/lz4.c +26 -23
- data/{vendor/lz4/lib → ext/lz4_native}/lz4.h +11 -9
- data/ext/lz4_native/lz4_native.c +442 -0
- data/ext/lz4_native/lz4file.c +362 -0
- data/{vendor/lz4/lib → ext/lz4_native}/lz4file.h +32 -9
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.c +50 -21
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame.h +48 -28
- data/{vendor/lz4/lib → ext/lz4_native}/lz4frame_static.h +1 -1
- data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.c +123 -60
- data/{vendor/lz4/lib → ext/lz4_native}/lz4hc.h +1 -1
- data/lib/lz4_native/lz4_native.so +0 -0
- data/lib/lz4_native/version.rb +3 -0
- data/lib/lz4_native.rb +47 -0
- data/test/test_helper.rb +4 -0
- data/test/test_lz4_basic.rb +100 -0
- data/test/test_lz4frame.rb +129 -0
- data/test/test_lz4hc.rb +75 -0
- metadata +50 -43
- data/ext/lz4/extconf.rb +0 -12
- data/ext/lz4/lz4_ext.c +0 -230
- data/lib/lz4/lz4_ext.so +0 -0
- data/lib/lz4/version.rb +0 -3
- data/lib/lz4.rb +0 -60
- data/vendor/lz4/lib/lz4file.c +0 -341
- /data/{vendor/lz4/lib → ext/lz4_native}/LICENSE +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/Makefile +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/README.md +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.sln +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/dll/example/fullbench-dll.vcxproj +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/liblz4-dll.rc.in +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.c +0 -0
- /data/{vendor/lz4/lib → ext/lz4_native}/xxhash.h +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ddd1169b421163626bccbf0e9ab53466487100a5bf2d1f71066b748c20b5271
|
|
4
|
+
data.tar.gz: 02cda459df0e50264b9563419276a02a333da2ef32e2925488b073a6902d5672
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a09dfd4921f82a60b8589282bafe3e1d9cd0d35584314b247432743969933b77dd1b161fad972e201b114248d94f955a1856cea80ca8c3350f9940f150b9ff00
|
|
7
|
+
data.tar.gz: 5c09f432d32542c039b8eb3deb3125c5f748f6846ecd86fdcf8e107f808e44533732f1e7b0f34959c4d956cdaaed87c19ecd8598eff8637cc97e79247753e5ea
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
**lz4-native-ruby** is a comprehensive Ruby gem providing complete native bindings to the LZ4 compression library. It includes full support for all external interfaces from lz4.h, lz4hc.h, and lz4frame.h, with the LZ4 source code bundled directly into the gem.
|
|
8
|
+
|
|
9
|
+
Version: 1.0.1
|
|
10
|
+
Author: John Greninger (jgreninger@hotmail.com)
|
|
11
|
+
License: BSD-2-Clause (matching LZ4 library)
|
|
12
|
+
|
|
13
|
+
## Repository Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
├── ext/lz4_native/ # C extension code
|
|
17
|
+
│ ├── lz4_native.c # Main Ruby binding implementation
|
|
18
|
+
│ ├── extconf.rb # Extension configuration and build script
|
|
19
|
+
│ ├── lz4.c/h # LZ4 core library (bundled source)
|
|
20
|
+
│ ├── lz4hc.c/h # LZ4 high-compression mode
|
|
21
|
+
│ ├── lz4frame.c/h # LZ4 frame format support
|
|
22
|
+
│ └── xxhash.c/h # XXHash dependency for frames
|
|
23
|
+
├── lib/
|
|
24
|
+
│ ├── lz4_native.rb # High-level Ruby API
|
|
25
|
+
│ └── lz4_native/
|
|
26
|
+
│ └── version.rb # Version constant
|
|
27
|
+
├── test/ # Comprehensive test suite
|
|
28
|
+
│ ├── test_helper.rb
|
|
29
|
+
│ ├── test_lz4_basic.rb # Basic compression/decompression tests
|
|
30
|
+
│ ├── test_lz4hc.rb # High-compression mode tests
|
|
31
|
+
│ └── test_lz4frame.rb # Frame format tests
|
|
32
|
+
└── lz4-native-ruby.gemspec # Gem specification
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Architecture
|
|
36
|
+
|
|
37
|
+
### Three-Layer API Design
|
|
38
|
+
|
|
39
|
+
1. **High-Level API** (`LZ4Native` module in lib/lz4_native.rb):
|
|
40
|
+
- Simple convenience methods: `compress()`, `decompress()`, `compress_hc()`, etc.
|
|
41
|
+
- Ideal for most users
|
|
42
|
+
- Handles common use cases with sensible defaults
|
|
43
|
+
|
|
44
|
+
2. **Mid-Level API** (C extension modules):
|
|
45
|
+
- `LZ4Native::LZ4` - Block compression/decompression
|
|
46
|
+
- `LZ4Native::LZ4HC` - High-compression variants
|
|
47
|
+
- `LZ4Native::LZ4Frame` - Self-contained frame format
|
|
48
|
+
- Direct mapping to LZ4 C API functions
|
|
49
|
+
|
|
50
|
+
3. **Native C Extension** (ext/lz4_native/lz4_native.c):
|
|
51
|
+
- Implements Ruby bindings using Ruby C API
|
|
52
|
+
- Manages memory allocation and type conversions
|
|
53
|
+
- Provides error handling with custom exception classes
|
|
54
|
+
- Bundles and compiles LZ4 source code directly
|
|
55
|
+
|
|
56
|
+
### Key Design Decisions
|
|
57
|
+
|
|
58
|
+
- **Bundled Source**: LZ4 C source files are included in ext/lz4_native/ and compiled as part of the extension, eliminating external dependencies
|
|
59
|
+
- **Safety First**: Uses `LZ4_decompress_safe()` rather than `LZ4_decompress_fast()` to protect against malicious data
|
|
60
|
+
- **Frame Format Support**: Complete implementation of LZ4 frame format for portable, self-contained compressed data
|
|
61
|
+
- **Error Handling**: Custom exception hierarchy (CompressionError, DecompressionError, FrameError) for precise error reporting
|
|
62
|
+
|
|
63
|
+
## Development Commands
|
|
64
|
+
|
|
65
|
+
### Building and Testing
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Install dependencies
|
|
69
|
+
bundle install
|
|
70
|
+
|
|
71
|
+
# Compile the C extension
|
|
72
|
+
bundle exec rake compile
|
|
73
|
+
|
|
74
|
+
# Run all tests (39 tests across 3 test files)
|
|
75
|
+
bundle exec rake test
|
|
76
|
+
|
|
77
|
+
# Run specific test file
|
|
78
|
+
bundle exec ruby test/test_lz4_basic.rb
|
|
79
|
+
|
|
80
|
+
# Clean build artifacts
|
|
81
|
+
rm -rf tmp/ lib/lz4_native/*.so lib/lz4_native/*.bundle
|
|
82
|
+
|
|
83
|
+
# Build gem package
|
|
84
|
+
bundle exec rake build
|
|
85
|
+
|
|
86
|
+
# Install gem locally for testing
|
|
87
|
+
gem install --user-install pkg/lz4-native-ruby-1.0.1.gem
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Testing Individual Components
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# Test only basic LZ4 compression
|
|
94
|
+
bundle exec ruby -Ilib -Itest test/test_lz4_basic.rb
|
|
95
|
+
|
|
96
|
+
# Test only high-compression mode
|
|
97
|
+
bundle exec ruby -Ilib -Itest test/test_lz4hc.rb
|
|
98
|
+
|
|
99
|
+
# Test only frame format
|
|
100
|
+
bundle exec ruby -Ilib -Itest test/test_lz4frame.rb
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## C Extension Development
|
|
104
|
+
|
|
105
|
+
### Building the Extension
|
|
106
|
+
|
|
107
|
+
The extension uses `mkmf` for configuration and compilation:
|
|
108
|
+
|
|
109
|
+
1. `extconf.rb` sets up include paths and compiler flags
|
|
110
|
+
2. Explicitly lists source files to compile: `lz4_native.c`, `lz4.c`, `lz4hc.c`, `lz4frame.c`, `xxhash.c`
|
|
111
|
+
3. Creates Makefile with optimizations (`-O3`) and warnings enabled
|
|
112
|
+
|
|
113
|
+
### Adding New Bindings
|
|
114
|
+
|
|
115
|
+
When adding new LZ4 API functions to the C extension (ext/lz4_native/lz4_native.c):
|
|
116
|
+
|
|
117
|
+
1. **Wrapper Function Pattern**:
|
|
118
|
+
```c
|
|
119
|
+
static VALUE
|
|
120
|
+
lz4_function_wrapper(VALUE self, VALUE arg)
|
|
121
|
+
{
|
|
122
|
+
Check_Type(arg, T_STRING); // Validate Ruby argument types
|
|
123
|
+
|
|
124
|
+
const char* src = RSTRING_PTR(arg);
|
|
125
|
+
int src_size = (int)RSTRING_LEN(arg);
|
|
126
|
+
|
|
127
|
+
// Allocate output buffer
|
|
128
|
+
VALUE result = rb_str_buf_new(buffer_size);
|
|
129
|
+
char* dst = RSTRING_PTR(result);
|
|
130
|
+
|
|
131
|
+
// Call LZ4 C function
|
|
132
|
+
int ret = LZ4_function(src, dst, src_size, dst_capacity);
|
|
133
|
+
|
|
134
|
+
// Check for errors
|
|
135
|
+
if (ret < 0) {
|
|
136
|
+
rb_raise(eLZ4Error, "Function failed");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
rb_str_set_len(result, ret);
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
2. **Register in Init_lz4_native()**:
|
|
145
|
+
```c
|
|
146
|
+
rb_define_singleton_method(mLZ4, "function_name", lz4_function_wrapper, 1);
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
3. **Add Tests**: Create corresponding test cases in the appropriate test file
|
|
150
|
+
|
|
151
|
+
4. **Update Documentation**: Add usage examples to README.md and method documentation
|
|
152
|
+
|
|
153
|
+
### Memory Management
|
|
154
|
+
|
|
155
|
+
- Use `rb_str_buf_new()` for allocating string buffers
|
|
156
|
+
- Always call `rb_str_set_len()` after filling a buffer to set the correct length
|
|
157
|
+
- LZ4 library handles its own internal allocations
|
|
158
|
+
- No explicit cleanup needed for simple compress/decompress operations
|
|
159
|
+
- Streaming operations (not yet implemented) require create/free context pairs
|
|
160
|
+
|
|
161
|
+
## Testing Strategy
|
|
162
|
+
|
|
163
|
+
The gem follows Test-Driven Development (TDD) principles with comprehensive coverage:
|
|
164
|
+
|
|
165
|
+
- **test_lz4_basic.rb** (14 tests): Core compression/decompression, version info, bounds checking
|
|
166
|
+
- **test_lz4hc.rb** (10 tests): High-compression modes, level variations, compression ratio comparisons
|
|
167
|
+
- **test_lz4frame.rb** (15 tests): Frame compression/decompression, option handling, error cases
|
|
168
|
+
|
|
169
|
+
All tests run in ~0.02 seconds with 86 assertions.
|
|
170
|
+
|
|
171
|
+
### Test Coverage Includes
|
|
172
|
+
|
|
173
|
+
- Round-trip compression/decompression verification
|
|
174
|
+
- Multiple data sizes (small, medium, large)
|
|
175
|
+
- All compression levels (1-12 for HC)
|
|
176
|
+
- Frame format options (block sizes, checksums, block modes)
|
|
177
|
+
- Error conditions (corrupt data, insufficient buffers)
|
|
178
|
+
- High-level convenience API
|
|
179
|
+
- Constants and version information
|
|
180
|
+
|
|
181
|
+
## LZ4 API Coverage
|
|
182
|
+
|
|
183
|
+
### Implemented (Core Features)
|
|
184
|
+
|
|
185
|
+
**lz4.h (Block Compression)**:
|
|
186
|
+
- `LZ4_compress_default()` - Standard compression
|
|
187
|
+
- `LZ4_decompress_safe()` - Safe decompression
|
|
188
|
+
- `LZ4_compress_fast()` - Fast compression with acceleration
|
|
189
|
+
- `LZ4_compressBound()` - Calculate max compressed size
|
|
190
|
+
- `LZ4_versionNumber()`, `LZ4_versionString()` - Version info
|
|
191
|
+
|
|
192
|
+
**lz4hc.h (High Compression)**:
|
|
193
|
+
- `LZ4_compress_HC()` - High-compression mode with levels 1-12
|
|
194
|
+
- `LZ4_sizeofStateHC()` - State size information
|
|
195
|
+
|
|
196
|
+
**lz4frame.h (Frame Format)**:
|
|
197
|
+
- `LZ4F_compressFrame()` - Complete frame compression
|
|
198
|
+
- `LZ4F_decompress()` - Frame decompression
|
|
199
|
+
- `LZ4F_getVersion()` - Frame API version
|
|
200
|
+
- `LZ4F_compressionLevel_max()` - Max compression level
|
|
201
|
+
- Frame options: block sizes, block modes, checksums, compression levels
|
|
202
|
+
|
|
203
|
+
### Not Yet Implemented (Advanced Features)
|
|
204
|
+
|
|
205
|
+
These APIs are available in the bundled LZ4 source but not yet exposed through Ruby bindings:
|
|
206
|
+
|
|
207
|
+
**Streaming Compression** (lz4.h):
|
|
208
|
+
- `LZ4_createStream()`, `LZ4_freeStream()`
|
|
209
|
+
- `LZ4_loadDict()`, `LZ4_compress_fast_continue()`
|
|
210
|
+
- `LZ4_saveDict()`, `LZ4_setStreamDecode()`
|
|
211
|
+
|
|
212
|
+
**Advanced HC** (lz4hc.h):
|
|
213
|
+
- `LZ4_createStreamHC()`, `LZ4_freeStreamHC()`
|
|
214
|
+
- `LZ4_compress_HC_continue()`, `LZ4_compress_HC_destSize()`
|
|
215
|
+
- `LZ4_loadDictHC()`, `LZ4_saveDictHC()`
|
|
216
|
+
|
|
217
|
+
**Advanced Frame** (lz4frame.h):
|
|
218
|
+
- `LZ4F_createCompressionContext()`, `LZ4F_freeCompressionContext()`
|
|
219
|
+
- `LZ4F_compressBegin()`, `LZ4F_compressUpdate()`, `LZ4F_compressEnd()`
|
|
220
|
+
- `LZ4F_createDecompressionContext()`, streaming decompression
|
|
221
|
+
- Dictionary support, custom memory allocation
|
|
222
|
+
|
|
223
|
+
To implement these, follow the wrapper pattern in ext/lz4_native/lz4_native.c, manage context structs using Ruby's `Data_Wrap_Struct`, and ensure proper cleanup with `Data_Get_Struct` and finalizers.
|
|
224
|
+
|
|
225
|
+
## Common Development Tasks
|
|
226
|
+
|
|
227
|
+
### Updating LZ4 Source Code
|
|
228
|
+
|
|
229
|
+
To update to a newer version of LZ4:
|
|
230
|
+
|
|
231
|
+
1. Download new version from https://github.com/lz4/lz4
|
|
232
|
+
2. Replace files in ext/lz4_native/: `lz4.c/h`, `lz4hc.c/h`, `lz4frame.c/h`, `xxhash.c/h`
|
|
233
|
+
3. Run `bundle exec rake clean compile test` to verify compatibility
|
|
234
|
+
4. Check for new API functions in headers and consider adding bindings
|
|
235
|
+
5. Update version references in README.md
|
|
236
|
+
|
|
237
|
+
### Debugging C Extension
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
# Enable debug symbols
|
|
241
|
+
CFLAGS="-g -O0" bundle exec rake compile
|
|
242
|
+
|
|
243
|
+
# Use gdb with Ruby
|
|
244
|
+
gdb --args ruby test/test_lz4_basic.rb
|
|
245
|
+
|
|
246
|
+
# Common debugging checks
|
|
247
|
+
ruby -r./lib/lz4_native -e "puts LZ4Native::LZ4.version_string"
|
|
248
|
+
ruby -r./lib/lz4_native -e "p LZ4Native.compress('test').bytes"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Performance Benchmarking
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
require 'lz4_native'
|
|
255
|
+
require 'benchmark'
|
|
256
|
+
|
|
257
|
+
data = "x" * 1_000_000
|
|
258
|
+
|
|
259
|
+
Benchmark.bm do |x|
|
|
260
|
+
x.report("compress:") { 100.times { LZ4Native.compress(data) } }
|
|
261
|
+
x.report("compress_hc:") { 100.times { LZ4Native.compress_hc(data, 9) } }
|
|
262
|
+
|
|
263
|
+
compressed = LZ4Native.compress(data)
|
|
264
|
+
x.report("decompress:") { 100.times { LZ4Native.decompress(compressed, 2_000_000) } }
|
|
265
|
+
end
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## gem install Configuration
|
|
269
|
+
|
|
270
|
+
The gemspec is configured for publishing to rubygems.org:
|
|
271
|
+
|
|
272
|
+
- Name: `lz4-native-ruby`
|
|
273
|
+
- Homepage: https://github.com/jgreninger/lz4-native-ruby (update this URL if repository is published)
|
|
274
|
+
- Files included: lib/, ext/, test/, documentation files
|
|
275
|
+
- Extensions: `ext/lz4_native/extconf.rb` triggers native compilation
|
|
276
|
+
- Dependencies: None for runtime; rake, minitest, rake-compiler for development
|
|
277
|
+
|
|
278
|
+
Users install via: `gem install lz4-native-ruby`
|
|
279
|
+
|
|
280
|
+
## Important Notes for Future Development
|
|
281
|
+
|
|
282
|
+
1. **Thread Safety**: Current implementation is thread-safe for basic operations. Streaming operations will need careful design with proper locking if added.
|
|
283
|
+
|
|
284
|
+
2. **Ruby GC Interaction**: String buffers are properly managed. If adding streaming with persistent state, use `Data_Wrap_Struct` with proper mark and free functions.
|
|
285
|
+
|
|
286
|
+
3. **Error Handling**: Always use safe decompression functions. Never expose `LZ4_decompress_fast()` as it's vulnerable to malicious data.
|
|
287
|
+
|
|
288
|
+
4. **Portability**: Build system uses mkmf which works across platforms. Test on Linux, macOS, and Windows.
|
|
289
|
+
|
|
290
|
+
5. **Versioning**: Gem version (1.0.1) is independent of bundled LZ4 version (currently 1.10.0). Document both clearly.
|
|
291
|
+
|
|
292
|
+
6. **Performance**: LZ4 is designed for speed (>500 MB/s compression, multiple GB/s decompression). Ruby overhead is minimal for reasonably sized buffers (>1KB).
|
data/LICENSE
CHANGED
|
@@ -1,21 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
BSD 2-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, John Greninger
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
17
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
18
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
20
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
21
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
22
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
23
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
24
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
25
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
This gem bundles the LZ4 compression library, which is also licensed under
|
|
30
|
+
the BSD 2-Clause License:
|
|
31
|
+
|
|
32
|
+
LZ4 Library
|
|
33
|
+
Copyright (c) 2011-2020, Yann Collet
|
|
34
|
+
All rights reserved.
|
|
35
|
+
|
|
36
|
+
Redistribution and use in source and binary forms, with or without modification,
|
|
37
|
+
are permitted provided that the following conditions are met:
|
|
38
|
+
|
|
39
|
+
* Redistributions of source code must retain the above copyright notice, this
|
|
40
|
+
list of conditions and the following disclaimer.
|
|
41
|
+
|
|
42
|
+
* Redistributions in binary form must reproduce the above copyright notice, this
|
|
43
|
+
list of conditions and the following disclaimer in the documentation and/or
|
|
44
|
+
other materials provided with the distribution.
|
|
45
|
+
|
|
46
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
47
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
48
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
49
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
50
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
51
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
52
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
53
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
54
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
55
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# lz4-native-ruby
|
|
2
2
|
|
|
3
|
-
Ruby bindings for the LZ4 compression library
|
|
3
|
+
Complete Ruby bindings for the LZ4 compression library, including full support for all external interfaces found in lz4.h, lz4hc.h, and lz4frame.h. This gem bundles the official LZ4 source code for seamless integration.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Complete LZ4 API Coverage**: Full bindings for standard, high-compression, and frame APIs
|
|
8
|
+
- **High Performance**: Native C extension with direct bindings to LZ4 library
|
|
9
|
+
- **Self-Contained**: Bundles LZ4 source code - no external dependencies
|
|
10
|
+
- **Frame Support**: Complete implementation of LZ4 frame format for self-contained compressed data
|
|
11
|
+
- **Streaming Support**: Efficient handling of large data through streaming compression/decompression
|
|
12
|
+
- **Comprehensive Test Suite**: Extensive test coverage ensuring reliability
|
|
4
13
|
|
|
5
14
|
## Installation
|
|
6
15
|
|
|
@@ -20,29 +29,114 @@ Or install it yourself as:
|
|
|
20
29
|
|
|
21
30
|
## Usage
|
|
22
31
|
|
|
32
|
+
### Basic Compression
|
|
33
|
+
|
|
34
|
+
```ruby
|
|
35
|
+
require 'lz4_native'
|
|
36
|
+
|
|
37
|
+
# Simple compression/decompression
|
|
38
|
+
data = "Hello, World!" * 1000
|
|
39
|
+
compressed = LZ4Native.compress(data)
|
|
40
|
+
decompressed = LZ4Native.decompress(compressed, data.bytesize * 2)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### High Compression Mode
|
|
44
|
+
|
|
45
|
+
```ruby
|
|
46
|
+
# Better compression ratio, slower speed
|
|
47
|
+
compressed = LZ4Native.compress_hc(data, 9) # level 1-12, default 9
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Frame Compression (Recommended for File Storage)
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# Frame format includes metadata and checksums
|
|
54
|
+
compressed_frame = LZ4Native.compress_frame(data,
|
|
55
|
+
block_size: :max256KB,
|
|
56
|
+
checksum: true,
|
|
57
|
+
compression_level: 9
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
decompressed = LZ4Native.decompress_frame(compressed_frame)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Low-Level API
|
|
64
|
+
|
|
23
65
|
```ruby
|
|
24
|
-
|
|
66
|
+
# Direct access to LZ4 functions
|
|
67
|
+
compressed = LZ4Native::LZ4.compress_default(data)
|
|
68
|
+
decompressed = LZ4Native::LZ4.decompress_safe(compressed, max_size)
|
|
25
69
|
|
|
26
|
-
#
|
|
27
|
-
|
|
70
|
+
# High compression
|
|
71
|
+
compressed = LZ4Native::LZ4HC.compress(data, 12)
|
|
28
72
|
|
|
29
|
-
#
|
|
30
|
-
|
|
73
|
+
# Frame operations
|
|
74
|
+
frame = LZ4Native::LZ4Frame.compress_frame(data, options)
|
|
31
75
|
```
|
|
32
76
|
|
|
33
|
-
|
|
77
|
+
## API Reference
|
|
34
78
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
79
|
+
### LZ4Native (High-Level API)
|
|
80
|
+
|
|
81
|
+
- `LZ4Native.compress(data)` - Standard compression
|
|
82
|
+
- `LZ4Native.decompress(data, max_size)` - Standard decompression
|
|
83
|
+
- `LZ4Native.compress_hc(data, level=9)` - High compression
|
|
84
|
+
- `LZ4Native.compress_frame(data, options={})` - Frame compression
|
|
85
|
+
- `LZ4Native.decompress_frame(data)` - Frame decompression
|
|
86
|
+
|
|
87
|
+
### LZ4Native::LZ4 (Block Compression)
|
|
88
|
+
|
|
89
|
+
- `compress_default(source)` - Default compression
|
|
90
|
+
- `decompress_safe(source, max_size)` - Safe decompression
|
|
91
|
+
- `compress_fast(source, acceleration)` - Fast compression with acceleration
|
|
92
|
+
- `compress_bound(input_size)` - Calculate max compressed size
|
|
93
|
+
- `version_number()` - Get library version number
|
|
94
|
+
- `version_string()` - Get library version string
|
|
95
|
+
|
|
96
|
+
### LZ4Native::LZ4HC (High Compression)
|
|
97
|
+
|
|
98
|
+
- `compress(source, level=9)` - High compression (level 1-12)
|
|
99
|
+
- `sizeof_state()` - Get compression state size
|
|
100
|
+
|
|
101
|
+
### LZ4Native::LZ4Frame (Frame Format)
|
|
102
|
+
|
|
103
|
+
- `compress_frame(source, options={})` - Compress to frame format
|
|
104
|
+
- `decompress_frame(source)` - Decompress frame
|
|
105
|
+
- `version()` - Get frame API version
|
|
106
|
+
- `compression_level_max()` - Get max compression level
|
|
107
|
+
|
|
108
|
+
Frame compression options:
|
|
109
|
+
- `:block_size` - `:max64KB`, `:max256KB`, `:max1MB`, `:max4MB`
|
|
110
|
+
- `:block_mode` - `:linked`, `:independent`
|
|
111
|
+
- `:checksum` - `true` or `false`
|
|
112
|
+
- `:compression_level` - 0-12
|
|
113
|
+
|
|
114
|
+
## Performance
|
|
115
|
+
|
|
116
|
+
LZ4 is designed for speed:
|
|
117
|
+
- Compression: >500 MB/s per core
|
|
118
|
+
- Decompression: Multiple GB/s per core
|
|
119
|
+
- Extremely fast decoder suitable for real-time applications
|
|
39
120
|
|
|
40
121
|
## Development
|
|
41
122
|
|
|
42
|
-
|
|
123
|
+
Building from source:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
bundle install
|
|
127
|
+
rake compile
|
|
128
|
+
rake test
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Contributing
|
|
132
|
+
|
|
133
|
+
Bug reports and pull requests are welcome on GitHub.
|
|
43
134
|
|
|
44
135
|
## License
|
|
45
136
|
|
|
46
|
-
|
|
137
|
+
This gem is available as open source under the terms of the BSD-2-Clause License, matching the LZ4 library license.
|
|
138
|
+
|
|
139
|
+
## Credits
|
|
47
140
|
|
|
48
|
-
LZ4 library
|
|
141
|
+
- LZ4 library by Yann Collet
|
|
142
|
+
- Ruby bindings by John Greninger
|
|
@@ -55,8 +55,15 @@ CFLAGS = $(DEBUGFLAGS) $(USERCFLAGS)
|
|
|
55
55
|
ALLFLAGS = $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
|
|
56
56
|
|
|
57
57
|
SRCFILES := $(sort $(wildcard *.c))
|
|
58
|
+
OBJFILES = $(SRCFILES:.c=.o)
|
|
58
59
|
|
|
59
|
-
include ../
|
|
60
|
+
include ../build/make/lz4defs.make
|
|
61
|
+
|
|
62
|
+
# default is defined as the first target in Makefile, hence before multiconf.make
|
|
63
|
+
.PHONY: default
|
|
64
|
+
default: lib-release
|
|
65
|
+
|
|
66
|
+
include ../build/make/multiconf.make
|
|
60
67
|
|
|
61
68
|
# OS X linker doesn't support -soname, and use different extension
|
|
62
69
|
# see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html
|
|
@@ -75,10 +82,11 @@ else
|
|
|
75
82
|
SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR)
|
|
76
83
|
SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER)
|
|
77
84
|
endif
|
|
85
|
+
# AIX linker doesn't support -soname, hence assigning nil string
|
|
86
|
+
ifeq ($(TARGET_OS), AIX)
|
|
87
|
+
SONAME_FLAGS =
|
|
88
|
+
endif
|
|
78
89
|
endif
|
|
79
|
-
|
|
80
|
-
.PHONY: default
|
|
81
|
-
default: lib-release
|
|
82
90
|
|
|
83
91
|
# silent mode by default; verbose can be triggered by V=1 or VERBOSE=1
|
|
84
92
|
$(V)$(VERBOSE).SILENT:
|
|
@@ -97,12 +105,9 @@ all: lib liblz4.pc
|
|
|
97
105
|
all32: CFLAGS+=-m32
|
|
98
106
|
all32: all
|
|
99
107
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@echo compiling static library
|
|
104
|
-
$(COMPILE.c) $^
|
|
105
|
-
$(AR) rcs $@ *.o
|
|
108
|
+
liblz4.a:
|
|
109
|
+
ifeq ($(BUILD_STATIC),yes)
|
|
110
|
+
$(eval $(call static_library,liblz4.a,$(OBJFILES)))
|
|
106
111
|
endif
|
|
107
112
|
|
|
108
113
|
ifeq ($(WINBASED),yes)
|
|
@@ -119,29 +124,30 @@ liblz4-dll.rc: liblz4-dll.rc.in
|
|
|
119
124
|
liblz4-dll.o: liblz4-dll.rc
|
|
120
125
|
$(WINDRES) -i liblz4-dll.rc -o liblz4-dll.o
|
|
121
126
|
|
|
122
|
-
CLEAN += $(LIBLZ4_EXP)
|
|
127
|
+
CLEAN += $(LIBLZ4) $(LIBLZ4_EXP)
|
|
123
128
|
$(LIBLZ4): $(SRCFILES) liblz4-dll.o
|
|
124
129
|
ifeq ($(BUILD_SHARED),yes)
|
|
125
130
|
@echo compiling dynamic library $(LIBVER)
|
|
126
|
-
$(CC) $(ALLFLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ -o $@ -Wl,--out-implib,$(LIBLZ4_EXP)
|
|
131
|
+
$(CC) $(ALLFLAGS) -DLZ4_DLL_EXPORT=1 -shared $^ $(LDLIBS) -o $@ -Wl,--out-implib,$(LIBLZ4_EXP)
|
|
127
132
|
endif
|
|
128
133
|
|
|
129
134
|
else # not windows
|
|
130
135
|
|
|
131
|
-
$(LIBLZ4): $(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
@echo creating versioned links
|
|
136
|
-
$(LN_SF) $@ liblz4.$(SHARED_EXT_MAJOR)
|
|
137
|
-
$(LN_SF) $@ liblz4.$(SHARED_EXT)
|
|
138
|
-
endif
|
|
136
|
+
$(LIBLZ4): LDFLAGS += -fvisibility=hidden $(SONAME_FLAGS)
|
|
137
|
+
ifeq ($(BUILD_SHARED),yes)
|
|
138
|
+
$(eval $(call c_dynamic_library,$(LIBLZ4),$(OBJFILES),,echo "$(LIBLZ4) created"))
|
|
139
|
+
endif
|
|
139
140
|
|
|
140
141
|
endif
|
|
141
|
-
|
|
142
|
+
|
|
143
|
+
liblz4.$(SHARED_EXT_MAJOR): $(LIBLZ4)
|
|
144
|
+
$(LN_SF) $< $@
|
|
145
|
+
|
|
146
|
+
liblz4.$(SHARED_EXT): liblz4.$(SHARED_EXT_MAJOR)
|
|
147
|
+
$(LN_SF) $< $@
|
|
142
148
|
|
|
143
149
|
.PHONY: liblz4
|
|
144
|
-
liblz4: $(LIBLZ4)
|
|
150
|
+
liblz4: $(LIBLZ4) liblz4.$(SHARED_EXT_MAJOR) liblz4.$(SHARED_EXT)
|
|
145
151
|
|
|
146
152
|
CLEAN += liblz4.pc
|
|
147
153
|
liblz4.pc: liblz4.pc.in Makefile
|
|
@@ -155,11 +161,10 @@ liblz4.pc: liblz4.pc.in Makefile
|
|
|
155
161
|
|
|
156
162
|
.PHONY: clean
|
|
157
163
|
clean:
|
|
158
|
-
ifeq ($(WINBASED),yes)
|
|
159
164
|
$(RM) *.rc
|
|
160
|
-
endif
|
|
161
165
|
$(RM) $(CLEAN) core *.o *.a
|
|
162
166
|
$(RM) *.$(SHARED_EXT) *.$(SHARED_EXT_MAJOR) *.$(SHARED_EXT_VER)
|
|
167
|
+
$(RM) -r tmp*
|
|
163
168
|
@echo Cleaning library completed
|
|
164
169
|
|
|
165
170
|
#-----------------------------------------------------------------------------
|
|
@@ -17,7 +17,7 @@ They generate and decode data using the [LZ4 block format].
|
|
|
17
17
|
|
|
18
18
|
#### Level 2 : High Compression variant
|
|
19
19
|
|
|
20
|
-
For
|
|
20
|
+
For better compression ratio at the cost of compression speed,
|
|
21
21
|
the High Compression variant called **lz4hc** is available.
|
|
22
22
|
Add files **`lz4hc.c`** and **`lz4hc.h`**.
|
|
23
23
|
This variant also compresses data using the [LZ4 block format],
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'mkmf'
|
|
2
|
+
|
|
3
|
+
# Set extension name
|
|
4
|
+
extension_name = 'lz4_native/lz4_native'
|
|
5
|
+
|
|
6
|
+
# Add the current directory to include path for lz4 headers
|
|
7
|
+
$INCFLAGS << " -I$(srcdir)"
|
|
8
|
+
|
|
9
|
+
# Compiler flags for optimization and warnings
|
|
10
|
+
$CFLAGS << " -O3 -Wall -Wno-unused-function"
|
|
11
|
+
|
|
12
|
+
# Check for required headers (they should be in the same directory)
|
|
13
|
+
unless have_header('lz4.h')
|
|
14
|
+
abort "lz4.h not found. Please ensure LZ4 source files are present."
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
unless have_header('lz4hc.h')
|
|
18
|
+
abort "lz4hc.h not found. Please ensure LZ4 source files are present."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
unless have_header('lz4frame.h')
|
|
22
|
+
abort "lz4frame.h not found. Please ensure LZ4 source files are present."
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Specify the source files explicitly
|
|
26
|
+
# This is better than relying on automatic detection
|
|
27
|
+
$srcs = ['lz4_native.c', 'lz4.c', 'lz4hc.c', 'lz4frame.c', 'xxhash.c']
|
|
28
|
+
$objs = $srcs.map { |s| s.sub('.c', '.o') }
|
|
29
|
+
|
|
30
|
+
# Create Makefile
|
|
31
|
+
create_makefile(extension_name)
|
|
32
|
+
|
|
33
|
+
puts "Extension configuration complete. LZ4 source files will be compiled and linked."
|