multi_compress 0.3.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 404264c1ba462057374ad7a6a2a72565a16e1da607e47b1d3d91b727b4e74351
4
- data.tar.gz: d23f9c3af016742a7aef3880209a2e68ba5ed2107c6c3eb3943a30802606c6ac
3
+ metadata.gz: 23ab6bacd75b21b5cfbf5b7b3121428c18060bd9e097f815438af6c8bafd8883
4
+ data.tar.gz: 90321202358a43bb732077aa1f28b8a9e5d756e27067df851671883a21eb1470
5
5
  SHA512:
6
- metadata.gz: 91091ad2e184758916b7c79aa0ec82a3216f5d87798a7c597b43afe25b8eaa091fd7094c5de71e4eac5e01804f7b9928734514224cd0312edd1f60187d04c91b
7
- data.tar.gz: 275044013ecacca6ee300ce8b980c252048f021acc2cf51e169722830add7301dbc4e9f6942c07845ea672c5e1dd9fe8074c7840b155096c3b40b2b1e3d5ebdc
6
+ metadata.gz: 431921d63b8757216df9179dfd5d792103777dbf597d52cfafeb2e593ee8ab52ce12f374499826b0eba45a164bfde0f4adaa3aa3ba9ee811c6d9f44ed2ccdb7d
7
+ data.tar.gz: 2e1d3bf4455fd627696c7ff7a500e6424497df012939487d39896b8e50dad421c8acd8b427f10fc3de6a51b799ca5b1532cda5508485440e4f633a5ac5677a1d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.2]
4
+
5
+ ### Changed
6
+ - Micro-optimization
7
+
3
8
  ## [0.3.1]
4
9
 
5
10
  ### Fixed
data/README.md CHANGED
@@ -106,9 +106,9 @@ Performance comparison against Ruby's built-in zlib compression (200 iterations
106
106
  │ Medium JSON (~370KB, no GC) │ 8.5% │ 15.7% │ 6.7% │ 5.5% │
107
107
  │ Medium logs (~168KB, no GC) │ 8.6% │ 17.2% │ 5.4% │ 3.2% │
108
108
  │ Large JSON (~1.6MB, GC) │ 8.1% │ 15.1% │ 6.1% │ 5.6% │
109
- │ Large logs (~600KB, GC) │ 7.6% │ 16.0% │ 2.8% │ 2.1% │
109
+ │ Large logs (~600KB, GC) │ 7.6% │ 16.0% │ 2.9% │ 2.0% │
110
110
  │ Large JSON (~1.6MB, no GC) │ 8.1% │ 15.1% │ 6.1% │ 5.6% │
111
- │ Large logs (~600KB, no GC) │ 7.6% │ 16.0% │ 2.8% │ 2.1% │
111
+ │ Large logs (~600KB, no GC) │ 7.6% │ 16.0% │ 2.9% │ 2.0% │
112
112
  └─────────────────────────────┴─────────┴─────────┴─────────┴─────────┘
113
113
  ```
114
114
 
@@ -117,18 +117,18 @@ Performance comparison against Ruby's built-in zlib compression (200 iterations
117
117
  ┌─────────────────────────────┬─────────┬─────────┬─────────┬─────────┐
118
118
  │ Configuration │ zlib │ lz4 │ zstd │ brotli │
119
119
  ├─────────────────────────────┼─────────┼─────────┼─────────┼─────────┤
120
- │ Small JSON (~10KB, GC) │ 0.05 │ 0.01 │ 0.02 │ 0.14
121
- │ Small text (~10KB, GC) │ 0.04 │ 0.00 │ 0.01 │ 0.11
120
+ │ Small JSON (~10KB, GC) │ 0.05 │ 0.01 │ 0.02 │ 0.12
121
+ │ Small text (~10KB, GC) │ 0.03 │ 0.00 │ 0.01 │ 0.09
122
122
  │ Small JSON (~10KB, no GC) │ 0.06 │ 0.01 │ 0.02 │ 0.13 │
123
- │ Small text (~10KB, no GC) │ 0.04 │ 0.00 │ 0.01 │ 0.11 │
124
- │ Medium JSON (~370KB, GC) │ 2.73 │ 0.29 │ 0.42 │ 2.36
125
- │ Medium logs (~168KB, GC) │ 1.23 │ 0.14 │ 0.18 │ 0.92
126
- │ Medium JSON (~370KB, no GC) │ 2.72 │ 0.28 │ 0.41 │ 2.41
127
- │ Medium logs (~168KB, no GC) │ 1.26 │ 0.13 │ 0.18 │ 0.96
128
- │ Large JSON (~1.6MB, GC) │ 12.44 │ 1.38 │ 1.9612.44
129
- │ Large logs (~600KB, GC) │ 4.29 │ 0.46 │ 0.49 │ 2.85
130
- │ Large JSON (~1.6MB, no GC) │ 12.22 │ 1.28 │ 1.86 │ 11.83
131
- │ Large logs (~600KB, no GC) │ 4.39 │ 0.42 │ 0.44 │ 2.86
123
+ │ Small text (~10KB, no GC) │ 0.03 │ 0.00 │ 0.01 │ 0.11 │
124
+ │ Medium JSON (~370KB, GC) │ 2.62 │ 0.28 │ 0.39 │ 2.31
125
+ │ Medium logs (~168KB, GC) │ 1.23 │ 0.13 │ 0.18 │ 0.88
126
+ │ Medium JSON (~370KB, no GC) │ 2.65 │ 0.27 │ 0.40 │ 2.31
127
+ │ Medium logs (~168KB, no GC) │ 1.27 │ 0.13 │ 0.18 │ 0.95
128
+ │ Large JSON (~1.6MB, GC) │ 11.70 │ 1.36 │ 1.9311.95
129
+ │ Large logs (~600KB, GC) │ 4.10 │ 0.45 │ 0.45 │ 2.62
130
+ │ Large JSON (~1.6MB, no GC) │ 11.47 │ 1.27 │ 1.88 │ 11.47
131
+ │ Large logs (~600KB, no GC) │ 4.06 │ 0.41 │ 0.45 │ 2.79
132
132
  └─────────────────────────────┴─────────┴─────────┴─────────┴─────────┘
133
133
  ```
134
134
 
@@ -137,18 +137,18 @@ Performance comparison against Ruby's built-in zlib compression (200 iterations
137
137
  ┌─────────────────────────────┬─────────┬─────────┬─────────┬─────────┐
138
138
  │ Configuration │ zlib │ lz4 │ zstd │ brotli │
139
139
  ├─────────────────────────────┼─────────┼─────────┼─────────┼─────────┤
140
- │ Small JSON (~10KB, GC) │ 1.00x │ 5.00x │ 2.50x │ 0.36x
141
- │ Small text (~10KB, GC) │ 1.00x │ N/A │ 4.00x │ 0.36x
140
+ │ Small JSON (~10KB, GC) │ 1.00x │ 5.00x │ 2.50x │ 0.42x
141
+ │ Small text (~10KB, GC) │ 1.00x │ N/A │ 3.00x │ 0.33x
142
142
  │ Small JSON (~10KB, no GC) │ 1.00x │ 6.00x │ 3.00x │ 0.46x │
143
- │ Small text (~10KB, no GC) │ 1.00x │ N/A │ 4.00x │ 0.36x
144
- │ Medium JSON (~370KB, GC) │ 1.00x │ 9.41x │ 6.50x │ 1.16x
145
- │ Medium logs (~168KB, GC) │ 1.00x │ 8.79x │ 6.83x │ 1.34x
146
- │ Medium JSON (~370KB, no GC) │ 1.00x │ 9.71x │ 6.63x │ 1.13x
147
- │ Medium logs (~168KB, no GC) │ 1.00x │ 9.69x │ 7.00x │ 1.31x
148
- │ Large JSON (~1.6MB, GC) │ 1.00x │ 9.01x │ 6.35x1.00x
149
- │ Large logs (~600KB, GC) │ 1.00x │ 9.33x8.76x │ 1.51x
150
- │ Large JSON (~1.6MB, no GC) │ 1.00x │ 9.55x │ 6.57x │ 1.03x
151
- │ Large logs (~600KB, no GC) │ 1.00x │ 10.45x │ 9.98x │ 1.53x
143
+ │ Small text (~10KB, no GC) │ 1.00x │ N/A │ 3.00x │ 0.27x
144
+ │ Medium JSON (~370KB, GC) │ 1.00x │ 9.36x │ 6.72x │ 1.13x
145
+ │ Medium logs (~168KB, GC) │ 1.00x │ 9.46x │ 6.83x │ 1.40x
146
+ │ Medium JSON (~370KB, no GC) │ 1.00x │ 9.81x │ 6.62x │ 1.15x
147
+ │ Medium logs (~168KB, no GC) │ 1.00x │ 9.77x │ 7.06x │ 1.34x
148
+ │ Large JSON (~1.6MB, GC) │ 1.00x │ 8.60x │ 6.06x0.98x
149
+ │ Large logs (~600KB, GC) │ 1.00x │ 9.11x9.11x │ 1.56x
150
+ │ Large JSON (~1.6MB, no GC) │ 1.00x │ 9.03x │ 6.10x │ 1.00x
151
+ │ Large logs (~600KB, no GC) │ 1.00x │ 9.90x │ 9.02x │ 1.46x
152
152
  └─────────────────────────────┴─────────┴─────────┴─────────┴─────────┘
153
153
  ```
154
154
 
@@ -137,12 +137,94 @@ static void init_id_cache(void) {
137
137
  sym_cache.max_ratio = ID2SYM(id_cache.max_ratio);
138
138
  }
139
139
 
140
- static inline VALUE opt_get(VALUE opts, VALUE sym) {
141
- return NIL_P(opts) ? Qnil : rb_hash_aref(opts, sym);
140
+ typedef struct {
141
+ VALUE algo;
142
+ VALUE level;
143
+ VALUE dictionary;
144
+ VALUE size;
145
+ VALUE format;
146
+ VALUE max_output_size;
147
+ VALUE max_ratio;
148
+ int saw_algorithm_keyword;
149
+ } mc_opts_t;
150
+
151
+ static inline void mc_opts_init(mc_opts_t *opts) {
152
+ opts->algo = Qnil;
153
+ opts->level = Qnil;
154
+ opts->dictionary = Qnil;
155
+ opts->size = Qnil;
156
+ opts->format = Qnil;
157
+ opts->max_output_size = Qundef;
158
+ opts->max_ratio = Qundef;
159
+ opts->saw_algorithm_keyword = 0;
160
+ }
161
+
162
+ static int mc_opts_parse_i(VALUE key, VALUE value, VALUE arg) {
163
+ mc_opts_t *opts = (mc_opts_t *)arg;
164
+
165
+ if (!SYMBOL_P(key))
166
+ return ST_CONTINUE;
167
+
168
+ ID id = SYM2ID(key);
169
+ if (id == id_cache.algo) {
170
+ opts->algo = value;
171
+ } else if (id == id_cache.level) {
172
+ opts->level = value;
173
+ } else if (id == id_cache.dictionary) {
174
+ opts->dictionary = value;
175
+ } else if (id == id_cache.size) {
176
+ opts->size = value;
177
+ } else if (id == id_cache.format) {
178
+ opts->format = value;
179
+ } else if (id == id_cache.max_output_size) {
180
+ opts->max_output_size = value;
181
+ } else if (id == id_cache.max_ratio) {
182
+ opts->max_ratio = value;
183
+ } else if (id == id_cache.algorithm) {
184
+ opts->saw_algorithm_keyword = 1;
185
+ }
186
+
187
+ return ST_CONTINUE;
188
+ }
189
+
190
+ static inline void mc_parse_opts(VALUE opts_hash, mc_opts_t *opts) {
191
+ mc_opts_init(opts);
192
+ if (NIL_P(opts_hash))
193
+ return;
194
+ Check_Type(opts_hash, T_HASH);
195
+ rb_hash_foreach(opts_hash, mc_opts_parse_i, (VALUE)opts);
196
+ }
197
+
198
+ static inline void scan_one_required_keywords(int argc, VALUE *argv, VALUE *arg, VALUE *opts) {
199
+ if (argc == 1) {
200
+ *arg = argv[0];
201
+ *opts = Qnil;
202
+ return;
203
+ }
204
+
205
+ if (argc == 2 && rb_keyword_given_p()) {
206
+ *arg = argv[0];
207
+ *opts = argv[1];
208
+ Check_Type(*opts, T_HASH);
209
+ return;
210
+ }
211
+
212
+ rb_error_arity(argc, 1, 1);
142
213
  }
143
214
 
144
- static inline VALUE opt_lookup2(VALUE opts, VALUE sym, VALUE default_value) {
145
- return NIL_P(opts) ? default_value : rb_hash_lookup2(opts, sym, default_value);
215
+ static inline void scan_zero_required_keywords(int argc, VALUE *argv, VALUE *opts) {
216
+ if (argc == 0) {
217
+ *opts = Qnil;
218
+ return;
219
+ }
220
+
221
+ if (argc == 1 && rb_keyword_given_p()) {
222
+ *opts = argv[0];
223
+ Check_Type(*opts, T_HASH);
224
+ return;
225
+ }
226
+
227
+ rb_error_arity(argc, 0, 0);
146
228
  }
147
229
 
148
230
  enum { LZ4_FRAME_MAGIC_LEN = 4 };
@@ -152,8 +234,9 @@ static inline int is_lz4_frame_magic(const uint8_t *data, size_t len) {
152
234
  return len >= LZ4_FRAME_MAGIC_LEN && memcmp(data, LZ4_FRAME_MAGIC, LZ4_FRAME_MAGIC_LEN) == 0;
153
235
  }
154
236
 
155
- static lz4_format_t parse_lz4_format(VALUE opts, compress_algo_t algo, int explicit_algo) {
156
- VALUE format_val = opt_lookup2(opts, sym_cache.format, Qundef);
237
+ static lz4_format_t parse_lz4_format(const mc_opts_t *opts, compress_algo_t algo,
238
+ int explicit_algo) {
239
+ VALUE format_val = opts->format;
157
240
  if (format_val == Qundef || NIL_P(format_val))
158
241
  return LZ4_FORMAT_BLOCK;
159
242
  if (explicit_algo && algo != ALGO_LZ4)
@@ -169,10 +252,8 @@ static lz4_format_t parse_lz4_format(VALUE opts, compress_algo_t algo, int expli
169
252
  return LZ4_FORMAT_BLOCK;
170
253
  }
171
254
 
172
- static inline void reject_algorithm_keyword(VALUE opts) {
173
- if (NIL_P(opts))
174
- return;
175
- if (rb_hash_lookup2(opts, sym_cache.algorithm, Qundef) != Qundef) {
255
+ static inline void reject_algorithm_keyword(const mc_opts_t *opts) {
256
+ if (opts->saw_algorithm_keyword) {
176
257
  rb_raise(rb_eArgError, "unknown keyword: :algorithm (use :algo)");
177
258
  }
178
259
  }
@@ -383,11 +464,8 @@ static void limits_config_init(limits_config_t *limits) {
383
464
  limits->max_ratio = DEFAULT_MAX_RATIO;
384
465
  }
385
466
 
386
- static void limits_config_apply_opts(VALUE opts, limits_config_t *limits) {
387
- if (NIL_P(opts))
388
- return;
389
-
390
- VALUE val = opt_lookup2(opts, sym_cache.max_output_size, Qundef);
467
+ static void limits_config_apply_parsed(const mc_opts_t *opts, limits_config_t *limits) {
468
+ VALUE val = opts->max_output_size;
391
469
  if (val != Qundef && !NIL_P(val)) {
392
470
  size_t max_output_size = NUM2SIZET(val);
393
471
  if (max_output_size == 0)
@@ -395,7 +473,7 @@ static void limits_config_apply_opts(VALUE opts, limits_config_t *limits) {
395
473
  limits->max_output_size = max_output_size;
396
474
  }
397
475
 
398
- val = opt_lookup2(opts, sym_cache.max_ratio, Qundef);
476
+ val = opts->max_ratio;
399
477
  if (val == Qundef)
400
478
  return;
401
479
  if (NIL_P(val)) {
@@ -411,9 +489,9 @@ static void limits_config_apply_opts(VALUE opts, limits_config_t *limits) {
411
489
  limits->max_ratio = max_ratio;
412
490
  }
413
491
 
414
- static void parse_limits_from_opts(VALUE opts, limits_config_t *limits) {
492
+ static void parse_limits_from_parsed_opts(const mc_opts_t *opts, limits_config_t *limits) {
415
493
  limits_config_init(limits);
416
- limits_config_apply_opts(opts, limits);
494
+ limits_config_apply_parsed(opts, limits);
417
495
  }
418
496
 
419
497
  static inline size_t checked_add_size(size_t left, size_t right, const char *message) {
@@ -1107,20 +1185,20 @@ static void *zstd_fiber_compress_nogvl(void *arg) {
1107
1185
 
1108
1186
  static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
1109
1187
  VALUE data, opts;
1110
- rb_scan_args(argc, argv, "1:", &data, &opts);
1188
+ scan_one_required_keywords(argc, argv, &data, &opts);
1111
1189
  StringValue(data);
1112
- reject_algorithm_keyword(opts);
1113
1190
 
1114
- VALUE algo_sym = Qnil, level_val = Qnil, dict_val = Qnil;
1115
- if (!NIL_P(opts)) {
1116
- algo_sym = opt_get(opts, sym_cache.algo);
1117
- level_val = opt_get(opts, sym_cache.level);
1118
- dict_val = opt_get(opts, sym_cache.dictionary);
1119
- }
1191
+ mc_opts_t parsed_opts;
1192
+ mc_parse_opts(opts, &parsed_opts);
1193
+ reject_algorithm_keyword(&parsed_opts);
1194
+
1195
+ VALUE algo_sym = parsed_opts.algo;
1196
+ VALUE level_val = parsed_opts.level;
1197
+ VALUE dict_val = parsed_opts.dictionary;
1120
1198
 
1121
1199
  int explicit_algo = !NIL_P(algo_sym);
1122
1200
  compress_algo_t algo = explicit_algo ? sym_to_algo(algo_sym) : ALGO_ZSTD;
1123
- lz4_format_t lz4_format = parse_lz4_format(opts, algo, explicit_algo);
1201
+ lz4_format_t lz4_format = parse_lz4_format(&parsed_opts, algo, explicit_algo);
1124
1202
  int level = resolve_level(algo, level_val);
1125
1203
 
1126
1204
  dictionary_t *dict = NULL;
@@ -1406,17 +1484,17 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
1406
1484
 
1407
1485
  static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
1408
1486
  VALUE data, opts;
1409
- rb_scan_args(argc, argv, "1:", &data, &opts);
1487
+ scan_one_required_keywords(argc, argv, &data, &opts);
1410
1488
  StringValue(data);
1411
- reject_algorithm_keyword(opts);
1412
1489
 
1413
- VALUE algo_sym = Qnil, dict_val = Qnil;
1490
+ mc_opts_t parsed_opts;
1491
+ mc_parse_opts(opts, &parsed_opts);
1492
+ reject_algorithm_keyword(&parsed_opts);
1493
+
1494
+ VALUE algo_sym = parsed_opts.algo;
1495
+ VALUE dict_val = parsed_opts.dictionary;
1414
1496
  limits_config_t limits;
1415
- parse_limits_from_opts(opts, &limits);
1416
- if (!NIL_P(opts)) {
1417
- algo_sym = opt_get(opts, sym_cache.algo);
1418
- dict_val = opt_get(opts, sym_cache.dictionary);
1419
- }
1497
+ parse_limits_from_parsed_opts(&parsed_opts, &limits);
1420
1498
 
1421
1499
  const uint8_t *src = (const uint8_t *)RSTRING_PTR(data);
1422
1500
  size_t slen = RSTRING_LEN(data);
@@ -1428,7 +1506,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
1428
1506
  } else {
1429
1507
  algo = sym_to_algo(algo_sym);
1430
1508
  }
1431
- lz4_format_t lz4_format = parse_lz4_format(opts, algo, explicit_algo);
1509
+ lz4_format_t lz4_format = parse_lz4_format(&parsed_opts, algo, explicit_algo);
1432
1510
 
1433
1511
  const algo_policy_t *policy = algo_policy(algo);
1434
1512
 
@@ -2009,18 +2087,18 @@ static VALUE deflater_alloc(VALUE klass) {
2009
2087
 
2010
2088
  static VALUE deflater_initialize(int argc, VALUE *argv, VALUE self) {
2011
2089
  VALUE opts;
2012
- rb_scan_args(argc, argv, "0:", &opts);
2013
- reject_algorithm_keyword(opts);
2090
+ scan_zero_required_keywords(argc, argv, &opts);
2091
+
2092
+ mc_opts_t parsed_opts;
2093
+ mc_parse_opts(opts, &parsed_opts);
2094
+ reject_algorithm_keyword(&parsed_opts);
2014
2095
 
2015
2096
  deflater_t *d;
2016
2097
  TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
2017
2098
 
2018
- VALUE algo_sym = Qnil, level_val = Qnil, dict_val = Qnil;
2019
- if (!NIL_P(opts)) {
2020
- algo_sym = opt_get(opts, sym_cache.algo);
2021
- level_val = opt_get(opts, sym_cache.level);
2022
- dict_val = opt_get(opts, sym_cache.dictionary);
2023
- }
2099
+ VALUE algo_sym = parsed_opts.algo;
2100
+ VALUE level_val = parsed_opts.level;
2101
+ VALUE dict_val = parsed_opts.dictionary;
2024
2102
 
2025
2103
  d->algo = NIL_P(algo_sym) ? ALGO_ZSTD : sym_to_algo(algo_sym);
2026
2104
  d->level = resolve_level(d->algo, level_val);
@@ -2663,19 +2741,19 @@ static VALUE inflater_alloc(VALUE klass) {
2663
2741
 
2664
2742
  static VALUE inflater_initialize(int argc, VALUE *argv, VALUE self) {
2665
2743
  VALUE opts;
2666
- rb_scan_args(argc, argv, "0:", &opts);
2667
- reject_algorithm_keyword(opts);
2744
+ scan_zero_required_keywords(argc, argv, &opts);
2745
+
2746
+ mc_opts_t parsed_opts;
2747
+ mc_parse_opts(opts, &parsed_opts);
2748
+ reject_algorithm_keyword(&parsed_opts);
2668
2749
 
2669
2750
  inflater_t *inf;
2670
2751
  TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
2671
2752
 
2672
- VALUE algo_sym = Qnil, dict_val = Qnil;
2753
+ VALUE algo_sym = parsed_opts.algo;
2754
+ VALUE dict_val = parsed_opts.dictionary;
2673
2755
  limits_config_t limits;
2674
- parse_limits_from_opts(opts, &limits);
2675
- if (!NIL_P(opts)) {
2676
- algo_sym = opt_get(opts, sym_cache.algo);
2677
- dict_val = opt_get(opts, sym_cache.dictionary);
2678
- }
2756
+ parse_limits_from_parsed_opts(&parsed_opts, &limits);
2679
2757
 
2680
2758
  inf->algo = NIL_P(algo_sym) ? ALGO_ZSTD : sym_to_algo(algo_sym);
2681
2759
  inf->closed = 0;
@@ -3088,17 +3166,17 @@ static VALUE inflater_closed_p(VALUE self) {
3088
3166
 
3089
3167
  static VALUE dict_initialize(int argc, VALUE *argv, VALUE self) {
3090
3168
  VALUE raw, opts;
3091
- rb_scan_args(argc, argv, "1:", &raw, &opts);
3169
+ scan_one_required_keywords(argc, argv, &raw, &opts);
3092
3170
  StringValue(raw);
3093
- reject_algorithm_keyword(opts);
3171
+
3172
+ mc_opts_t parsed_opts;
3173
+ mc_parse_opts(opts, &parsed_opts);
3174
+ reject_algorithm_keyword(&parsed_opts);
3094
3175
 
3095
3176
  dictionary_t *d;
3096
3177
  TypedData_Get_Struct(self, dictionary_t, &dictionary_type, d);
3097
3178
 
3098
- VALUE algo_sym = Qnil;
3099
- if (!NIL_P(opts)) {
3100
- algo_sym = opt_get(opts, sym_cache.algo);
3101
- }
3179
+ VALUE algo_sym = parsed_opts.algo;
3102
3180
  d->algo = NIL_P(algo_sym) ? ALGO_ZSTD : sym_to_algo(algo_sym);
3103
3181
 
3104
3182
  if (d->algo == ALGO_LZ4)
@@ -3183,32 +3261,34 @@ static VALUE train_dictionary_internal(VALUE samples, VALUE size_val, compress_a
3183
3261
 
3184
3262
  static VALUE zstd_train_dictionary(int argc, VALUE *argv, VALUE self) {
3185
3263
  VALUE samples, opts;
3186
- rb_scan_args(argc, argv, "1:", &samples, &opts);
3187
- reject_algorithm_keyword(opts);
3188
- VALUE size_val = opt_get(opts, sym_cache.size);
3189
- return train_dictionary_internal(samples, size_val, ALGO_ZSTD);
3264
+ scan_one_required_keywords(argc, argv, &samples, &opts);
3265
+ mc_opts_t parsed_opts;
3266
+ mc_parse_opts(opts, &parsed_opts);
3267
+ reject_algorithm_keyword(&parsed_opts);
3268
+ return train_dictionary_internal(samples, parsed_opts.size, ALGO_ZSTD);
3190
3269
  }
3191
3270
 
3192
3271
  static VALUE brotli_train_dictionary(int argc, VALUE *argv, VALUE self) {
3193
3272
  VALUE samples, opts;
3194
- rb_scan_args(argc, argv, "1:", &samples, &opts);
3195
- reject_algorithm_keyword(opts);
3196
- VALUE size_val = opt_get(opts, sym_cache.size);
3273
+ scan_one_required_keywords(argc, argv, &samples, &opts);
3274
+ mc_opts_t parsed_opts;
3275
+ mc_parse_opts(opts, &parsed_opts);
3276
+ reject_algorithm_keyword(&parsed_opts);
3197
3277
 
3198
- return train_dictionary_internal(samples, size_val, ALGO_BROTLI);
3278
+ return train_dictionary_internal(samples, parsed_opts.size, ALGO_BROTLI);
3199
3279
  }
3200
3280
 
3201
3281
  static VALUE dict_load(int argc, VALUE *argv, VALUE self) {
3202
3282
  VALUE path, opts;
3203
- rb_scan_args(argc, argv, "1:", &path, &opts);
3283
+ scan_one_required_keywords(argc, argv, &path, &opts);
3204
3284
  StringValue(path);
3205
- reject_algorithm_keyword(opts);
3206
3285
  raise_if_path_has_null_byte(path);
3207
3286
 
3208
- VALUE algo_sym = Qnil;
3209
- if (!NIL_P(opts)) {
3210
- algo_sym = opt_get(opts, sym_cache.algo);
3211
- }
3287
+ mc_opts_t parsed_opts;
3288
+ mc_parse_opts(opts, &parsed_opts);
3289
+ reject_algorithm_keyword(&parsed_opts);
3290
+
3291
+ VALUE algo_sym = parsed_opts.algo;
3212
3292
  compress_algo_t algo = NIL_P(algo_sym) ? ALGO_ZSTD : sym_to_algo(algo_sym);
3213
3293
 
3214
3294
  if (algo == ALGO_LZ4)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MultiCompress
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_compress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Haydarov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-18 00:00:00.000000000 Z
11
+ date: 2026-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler