ob64 0.5.0 → 0.6.0

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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/main.yml +77 -16
  4. data/.standard.yml +1 -2
  5. data/CHANGELOG.md +14 -1
  6. data/README.md +57 -19
  7. data/benchmark.rb +60 -95
  8. data/ext/ob64/extconf.rb +0 -42
  9. data/ext/ob64/ob64.h +3 -1
  10. data/ext/ob64/ob64_ext.c +80 -23
  11. data/ext/ob64/ob64_pack.c +228 -0
  12. data/ext/ob64/pack_base64.c +5182 -0
  13. data/ext/ob64/pack_base64.h +33 -0
  14. data/ext/ob64/pack_generic.h +151 -0
  15. data/ext/ob64/pack_simd.h +22 -0
  16. data/ext/ob64/pack_uuencode.c +1741 -0
  17. data/ext/ob64/pack_uuencode.h +18 -0
  18. data/lib/ob64/core_ext.rb +2 -25
  19. data/lib/ob64/version.rb +1 -1
  20. data/lib/ob64.rb +149 -70
  21. data/ob64.gemspec +3 -5
  22. metadata +17 -73
  23. data/.gitmodules +0 -3
  24. data/ext/ob64/libbase64.h +0 -1
  25. data/vendor/libbase64/.gitignore +0 -12
  26. data/vendor/libbase64/.travis.yml +0 -71
  27. data/vendor/libbase64/CMakeLists.txt +0 -264
  28. data/vendor/libbase64/LICENSE +0 -28
  29. data/vendor/libbase64/Makefile +0 -93
  30. data/vendor/libbase64/README.md +0 -474
  31. data/vendor/libbase64/base64-benchmarks.png +0 -0
  32. data/vendor/libbase64/bin/base64.c +0 -132
  33. data/vendor/libbase64/cmake/Modules/TargetArch.cmake +0 -29
  34. data/vendor/libbase64/cmake/Modules/TargetSIMDInstructionSet.cmake +0 -34
  35. data/vendor/libbase64/cmake/base64-config.cmake.in +0 -5
  36. data/vendor/libbase64/cmake/config.h.in +0 -25
  37. data/vendor/libbase64/cmake/test-arch.c +0 -35
  38. data/vendor/libbase64/include/libbase64.h +0 -145
  39. data/vendor/libbase64/lib/arch/avx/codec.c +0 -42
  40. data/vendor/libbase64/lib/arch/avx2/codec.c +0 -42
  41. data/vendor/libbase64/lib/arch/avx2/dec_loop.c +0 -110
  42. data/vendor/libbase64/lib/arch/avx2/dec_reshuffle.c +0 -34
  43. data/vendor/libbase64/lib/arch/avx2/enc_loop.c +0 -89
  44. data/vendor/libbase64/lib/arch/avx2/enc_reshuffle.c +0 -83
  45. data/vendor/libbase64/lib/arch/avx2/enc_translate.c +0 -30
  46. data/vendor/libbase64/lib/arch/generic/32/dec_loop.c +0 -86
  47. data/vendor/libbase64/lib/arch/generic/32/enc_loop.c +0 -73
  48. data/vendor/libbase64/lib/arch/generic/64/enc_loop.c +0 -77
  49. data/vendor/libbase64/lib/arch/generic/codec.c +0 -39
  50. data/vendor/libbase64/lib/arch/generic/dec_head.c +0 -37
  51. data/vendor/libbase64/lib/arch/generic/dec_tail.c +0 -91
  52. data/vendor/libbase64/lib/arch/generic/enc_head.c +0 -24
  53. data/vendor/libbase64/lib/arch/generic/enc_tail.c +0 -34
  54. data/vendor/libbase64/lib/arch/neon32/codec.c +0 -72
  55. data/vendor/libbase64/lib/arch/neon32/dec_loop.c +0 -106
  56. data/vendor/libbase64/lib/arch/neon32/enc_loop.c +0 -58
  57. data/vendor/libbase64/lib/arch/neon32/enc_reshuffle.c +0 -54
  58. data/vendor/libbase64/lib/arch/neon32/enc_translate.c +0 -57
  59. data/vendor/libbase64/lib/arch/neon64/codec.c +0 -70
  60. data/vendor/libbase64/lib/arch/neon64/dec_loop.c +0 -129
  61. data/vendor/libbase64/lib/arch/neon64/enc_loop.c +0 -66
  62. data/vendor/libbase64/lib/arch/neon64/enc_reshuffle.c +0 -54
  63. data/vendor/libbase64/lib/arch/sse41/codec.c +0 -42
  64. data/vendor/libbase64/lib/arch/sse42/codec.c +0 -42
  65. data/vendor/libbase64/lib/arch/ssse3/codec.c +0 -42
  66. data/vendor/libbase64/lib/arch/ssse3/dec_loop.c +0 -173
  67. data/vendor/libbase64/lib/arch/ssse3/dec_reshuffle.c +0 -33
  68. data/vendor/libbase64/lib/arch/ssse3/enc_loop.c +0 -67
  69. data/vendor/libbase64/lib/arch/ssse3/enc_reshuffle.c +0 -48
  70. data/vendor/libbase64/lib/arch/ssse3/enc_translate.c +0 -33
  71. data/vendor/libbase64/lib/codec_choose.c +0 -281
  72. data/vendor/libbase64/lib/codecs.h +0 -65
  73. data/vendor/libbase64/lib/env.h +0 -67
  74. data/vendor/libbase64/lib/exports.txt +0 -7
  75. data/vendor/libbase64/lib/lib.c +0 -164
  76. data/vendor/libbase64/lib/lib_openmp.c +0 -149
  77. data/vendor/libbase64/lib/tables/.gitignore +0 -1
  78. data/vendor/libbase64/lib/tables/Makefile +0 -17
  79. data/vendor/libbase64/lib/tables/table_dec_32bit.h +0 -393
  80. data/vendor/libbase64/lib/tables/table_enc_12bit.h +0 -1031
  81. data/vendor/libbase64/lib/tables/table_enc_12bit.py +0 -45
  82. data/vendor/libbase64/lib/tables/table_generator.c +0 -184
  83. data/vendor/libbase64/lib/tables/tables.c +0 -40
  84. data/vendor/libbase64/lib/tables/tables.h +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf866c04fac9e6cf9d4f8c98741f17e2109e0bd5fd545d2d0482b4c28a6dd61a
4
- data.tar.gz: e6ee12aebbece01e6e1ce8181aafdfe9b32b7fbd2d1307c07d7af02d46b73f4e
3
+ metadata.gz: c8b76a774595914a6124939fe2410fe4ae5bb0687286315ab4ec1f05b8569d70
4
+ data.tar.gz: 662b74f7505f28362436d44771e51720884cf0ea48076b12e59094eacf4e87b6
5
5
  SHA512:
6
- metadata.gz: 280e35ae08985662cc05a26c5f30ef5e9897b8d7a641a83e7a0bc8bf91a1790dbf8c36f5129ff7dface1e5eeb8d286ef43387688202b26a254a6bad860faa65d
7
- data.tar.gz: f246fed35467cce900ffb7664ca62012c6d0e7bda5c2180a99814fba558331f83ab33d21a1868a0d850fa39b59eec223e39445584703f0302f339e159ce9be83
6
+ metadata.gz: b0e357acff49af3e42b36cb41b521393ed4f6604fc4f5943c491a504741b985d5a47e63217acd27e0896cb2b23a8df2412fe133fff1d76d275decc5cf0a39f7f
7
+ data.tar.gz: 560f3439cff65bc442f16a8815afa729422e6286f6305a044f92035bf28666b80c80c8471ffd7ac0b83379ea999643a531ef9a5905449093dafe10cff36490e9
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ groups:
8
+ github-actions:
9
+ patterns: ["*"]
@@ -1,34 +1,95 @@
1
- name: Test
1
+ name: CI
2
2
 
3
3
  on: [push, pull_request]
4
4
 
5
+ permissions:
6
+ contents: read
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ defaults:
13
+ run:
14
+ shell: bash
15
+
5
16
  jobs:
17
+ lint:
18
+ runs-on: ubuntu-24.04
19
+ timeout-minutes: 10
20
+ steps:
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
+ with:
23
+ persist-credentials: false
24
+
25
+ - uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
26
+ with:
27
+ ruby-version: "3.4"
28
+ bundler-cache: true
29
+
30
+ - run: bundle exec standardrb --no-fix
31
+
6
32
  test:
7
33
  strategy:
8
34
  fail-fast: false
9
35
  matrix:
10
- ruby: ['2.5', '2.6', '2.7', '3.0']
11
- runs-on: ubuntu-latest
36
+ ruby: ["3.3", "3.4", "4.0"]
37
+ os: [ubuntu-24.04, ubuntu-24.04-arm]
38
+ cc: [gcc, clang]
39
+ runs-on: ${{ matrix.os }}
40
+ timeout-minutes: 15
12
41
  steps:
13
- - name: repository checkout
14
- uses: actions/checkout@v2
42
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
15
43
  with:
16
- submodules: true
44
+ persist-credentials: false
17
45
 
18
- - name: load ruby
19
- uses: ruby/setup-ruby@v1
46
+ - uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
20
47
  with:
21
48
  ruby-version: ${{ matrix.ruby }}
49
+ bundler-cache: true
22
50
 
23
- - name: RubyGems, Bundler Update
24
- run: gem update --system --no-document --conservative
25
-
26
- - name: bundle install
27
- run: bundle install --path .bundle/gems --without development
51
+ - name: Install Clang
52
+ if: matrix.cc == 'clang'
53
+ run: command -v clang || { sudo apt-get update && sudo apt-get install -y clang; }
28
54
 
29
- - name: compile
55
+ - name: Compile
56
+ env:
57
+ # Same warnings for both compilers; Ruby's defaults are GCC-only.
58
+ MAKEFLAGS: 'CC=${{ matrix.cc }} warnflags=-Wall\ -Wextra\ -Wno-unused-parameter\ -Werror'
30
59
  run: bundle exec rake compile
31
60
 
32
- - name: test
61
+ - name: Show codecs
62
+ run: bundle exec ruby -Ilib -rob64 -e 'p Ob64.codecs, Ob64.codec'
63
+
64
+ - name: Test
33
65
  run: bundle exec rake spec
34
- timeout-minutes: 10
66
+
67
+ package:
68
+ runs-on: ubuntu-24.04
69
+ timeout-minutes: 10
70
+ steps:
71
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
72
+ with:
73
+ persist-credentials: false
74
+
75
+ - uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
76
+ with:
77
+ ruby-version: "3.4"
78
+
79
+ - name: Build gem
80
+ run: gem build ob64.gemspec
81
+
82
+ - name: Install gem
83
+ run: gem install --local ./ob64-*.gem
84
+
85
+ - name: Smoke test
86
+ working-directory: ${{ runner.temp }}
87
+ run: |
88
+ ruby -e '
89
+ require "ob64"
90
+ require "ob64/core_ext"
91
+ s = Random.bytes(4096)
92
+ abort "Base64 round trip failed" unless Ob64::Base64.decode(Ob64::Base64.encode(s)) == s
93
+ abort "UU round trip failed" unless Ob64::UU.decode(Ob64::UU.encode(s)) == s
94
+ abort "pack round trip failed" unless [s].pack("m0").unpack1("m0") == s
95
+ '
data/.standard.yml CHANGED
@@ -5,6 +5,5 @@ format: progress
5
5
  ignore:
6
6
  - 'benchmark.rb'
7
7
  - 'ext/**/*'
8
- - 'vendor/**/*'
9
8
  - 'spec/**/*':
10
- - Layout/AlignHash
9
+ - Layout/HashAlignment
data/CHANGELOG.md CHANGED
@@ -1,4 +1,17 @@
1
- ## [Unreleased]
1
+ ## [0.6.0] - 2026-10-26
2
+
3
+ - **Breaking:** `ob64/core_ext` patches `Array#pack`, `String#unpack` and `String#unpack1` instead of `Base64`.
4
+ - **Breaking:** Require Ruby >= 3.3.
5
+ - **Breaking:** Drop CMake and libbase64. Require GCC or Clang.
6
+ - **Breaking:** Base64 methods move from `Ob64` to `Ob64::Base64` (e.g. `Ob64.encode` is now `Ob64::Base64.encode`).
7
+ - **Breaking:** `decode` and `urlsafe_decode` reject non-zero trailing bits (e.g. `"AB=="`), like `unpack1("m0")`.
8
+ - Port SIMD codecs (AVX2, AVX512, NEON64) into the extension. They also run line-wrapped `m` and `u`.
9
+ - AVX512 requires VBMI2.
10
+ - Add `Ob64.codec`, `Ob64.codec=`, `Ob64.codecs` and `Ob64.best_codec`.
11
+ - Add `Ob64::Base64.decode(string, loose: true)`.
12
+ - Add `Ob64::UU.encode`, `Ob64::UU.decode`, `Ob64::UU.encoded_length_of` and `Ob64::UU.decoded_length_of`.
13
+ - Encode and decode URL-safe in C.
14
+ - Support Linux on AArch64.
2
15
 
3
16
  # [0.5.0] - 2021-09-29
4
17
 
data/README.md CHANGED
@@ -1,20 +1,18 @@
1
1
  # Ob64 gem
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/ob64.svg)](http://rubygems.org/gems/ob64)
4
- [![Build Status](https://github.com/jcmfernandes/ob64/workflows/Test/badge.svg?branch=master&event=push)](https://github.com/jcmfernandes/ob64/actions?query=workflow:Test)
5
- [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/ob64/0.5.0)
4
+ [![CI](https://github.com/jcmfernandes/ob64/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/jcmfernandes/ob64/actions/workflows/main.yml)
5
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/ob64/0.6.0)
6
6
 
7
- A *fast* Base64 encoder and decoder as a Ruby gem.
7
+ A *fast* Base64 and uuencode encoder and decoder as a Ruby gem.
8
8
 
9
9
  How fast? Try it yourself, execute:
10
10
 
11
11
  $ rake benchmark
12
12
 
13
- When compared to Ruby's own `Base64` module, expect a 4x speedup in encoding, and a 2x speedup in decoding. YMMV.
14
-
15
13
  ## Acknowledgements
16
14
 
17
- Ob64 uses `libbase64` under the hood. Originally developed by [aklomp](https://github.com/aklomp), here we started from [BurningEnlightenment](https://github.com/BurningEnlightenment)'s fork. `libbase64` takes advantage of SIMD (AVX2, NEON, AArch64/NEON, SSSE3, SSE4.1, SSE4.2, AVX) acceleration available on x86, x86-64, and ARM systems.
15
+ The SIMD codecs (AVX2, AVX512, NEON64) derive from [aklomp/base64](https://github.com/aklomp/base64).
18
16
 
19
17
  ## Installation
20
18
 
@@ -32,33 +30,75 @@ Or install it yourself as:
32
30
 
33
31
  $ gem install ob64
34
32
 
35
- Requires CMake and a C99 compiler.
36
-
37
- **WARNING:** Only tested on Linux and x86-64.
33
+ Requires Ruby >= 3.3 and GCC or Clang. Linux on x86-64 and AArch64.
38
34
 
39
35
  ## Usage
40
36
 
41
37
  ```ruby
42
38
  require "ob64"
39
+ ```
43
40
 
41
+ ### Base64
42
+
43
+ ```ruby
44
44
  bin1 = "This is data!"
45
- string = Ob64.encode(bin1)
45
+ string = Ob64::Base64.encode(bin1)
46
46
  # string = "VGhpcyBpcyBkYXRhIQ=="
47
47
 
48
- bin2 = Ob64.decode(string)
48
+ bin2 = Ob64::Base64.decode(string)
49
49
  puts "Same? #{bin1 == bin2}"
50
50
  # "Same? true"
51
51
  ```
52
52
 
53
- If you want to replace Ruby's own `Base64` module with Ob64 **(NOT RECOMMENDED!)**:
53
+ Decode input with or without padding:
54
+
55
+ ```ruby
56
+ Ob64::Base64.decode("VGhpcyBpcyBkYXRhIQ", loose: true)
57
+ ```
58
+
59
+ Bad padding, non-zero trailing bits and non-alphabet characters still raise `ArgumentError`.
60
+
61
+ URL-safe alphabet: `Ob64::Base64.urlsafe_encode(bin, padding: false)`, `Ob64::Base64.urlsafe_decode(string)`.
62
+
63
+ ### uuencode
64
+
65
+ Same output as `pack("u")` / `unpack1("u")`:
66
+
67
+ ```ruby
68
+ string = Ob64::UU.encode("This is data!")
69
+ # string = "-5&AI<R!I<R!D871A(0``\n"
70
+
71
+ Ob64::UU.decode(string)
72
+ # "This is data!"
73
+ ```
74
+
75
+ ### Codecs
76
+
77
+ The best codec this CPU runs is picked at load and used for every call. `Ob64.codec=` forces one for the whole process (e.g. `:scalar`, plain C).
78
+
79
+ ```ruby
80
+ Ob64.codecs
81
+ # x86-64 with AVX512 => [:scalar, :avx2, :avx512]
82
+ # x86-64 with AVX2 => [:scalar, :avx2]
83
+ # AArch64 => [:scalar, :neon64]
84
+ # other => [:scalar]
85
+
86
+ Ob64.best_codec # => :avx512
87
+ Ob64.codec # => :avx512
88
+ Ob64.codec = :scalar
89
+ Ob64.codec = Ob64.best_codec
90
+ ```
91
+
92
+ AVX512 needs VL, VBMI and VBMI2.
93
+
94
+ ### `pack` / `unpack`
54
95
 
55
96
  ```ruby
56
97
  require "ob64/core_ext"
57
- # It does NOT replace:
58
- # - Base64.encode64
59
- # - Base64.decode64
60
98
  ```
61
99
 
100
+ Patches `Array#pack`, `String#unpack` and `String#unpack1`. Fast only for single-directive formats `m`, `mN`, `m*`, `u`, `uN`, `u*`. Everything else runs Ruby's own code. Passing `buffer:`, `offset:`, a block, or a non-String first element also runs Ruby's own code. Output is identical to Ruby's.
101
+
62
102
  See [YARD documentation](http://www.rubydoc.info/gems/ob64).
63
103
 
64
104
  ## Releases
@@ -77,10 +117,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/jcmfer
77
117
 
78
118
  ## TODO
79
119
 
80
- * URL-safe encoding/decoding using separate alphabet/tables
81
120
  * Streaming interface
82
121
  * RFC 2045 (MIME) encoding/decoding
83
- * Make the OpenMP threshold configurable (and enable OpenMP acceleration)
84
122
  * Windows support
85
123
 
86
124
  ## License
@@ -107,9 +145,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
107
145
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
108
146
  THE SOFTWARE.
109
147
 
110
- ### libbase64
148
+ ### aklomp/base64
111
149
 
112
- Released under the BSD 2-clause License. See [LICENSE](https://github.com/jcmfernandes/base64-cmake/blob/feature/cmake/LICENSE).
150
+ Released under the BSD 2-clause License. See [LICENSE](https://github.com/aklomp/base64/blob/master/LICENSE).
113
151
 
114
152
  Copyright (c) 2005-2007, Nick Galbreath
115
153
  Copyright (c) 2013-2019, Alfred Klomp
data/benchmark.rb CHANGED
@@ -1,118 +1,83 @@
1
1
  require "benchmark/ips"
2
- require "securerandom"
2
+
3
+ # Ruby's own, captured before ob64/core_ext patches them.
4
+ NATIVE_PACK = Array.instance_method(:pack)
5
+ NATIVE_UNPACK1 = String.instance_method(:unpack1)
3
6
 
4
7
  require "ob64"
5
- require "base64"
8
+ require "ob64/core_ext"
6
9
 
7
- $run_encode_benchmark = true
8
- $run_decode_benchmark = true
9
- $run_urlsafe_encode_benchmark = true
10
- $run_urlsafe_decode_benchmark = true
10
+ $run_base64_benchmark = true
11
+ $run_uu_benchmark = true
11
12
 
12
13
  def to_size(bytes)
13
14
  bytes >= 2**20 ? "#{bytes / 2**20} MB" : "#{bytes / 2**10} kB"
14
15
  end
15
16
 
16
- def each_block
17
- [
18
- [1, :kb],
19
- [4, :kb],
20
- [64, :kb],
21
- [1, :mb],
22
- [10, :mb],
23
- [64, :mb]
24
- ].each do |(n, unit)|
25
- yield(n * 2**({kb: 10, mb: 20}.fetch(unit)))
26
- end
27
- end
28
-
29
- def benchmark(setup_block)
30
- each_block do |size|
31
- setup_block.call(size)
32
- GC.start
17
+ def each_size
18
+ [1 * 2**10, 4 * 2**10, 64 * 2**10, 1 * 2**20, 10 * 2**20, 64 * 2**20].each do |size|
33
19
  puts "\n\n#{"=" * 60}\nbenchmark with block size #{to_size(size)}"
34
- yield
20
+ yield Random.bytes(size)
35
21
  end
36
22
  end
37
23
 
38
- def encode_benchmark(&block)
39
- benchmark(
40
- lambda { |size| $unencoded = File.open("/dev/urandom") { |f| f.read(size) } },
41
- &block
42
- )
43
- end
44
-
45
- def decode_benchmark(&block)
46
- benchmark(
47
- lambda { |size| $encoded = SecureRandom.base64(size) },
48
- &block
49
- )
50
- end
51
-
52
- encode_benchmark do
53
- Benchmark.ips do |x|
54
- x.time = 5
55
- x.warmup = 2
56
-
57
- x.report("base64 .strict_encode64") do
58
- Base64.strict_encode64($unencoded)
59
- end
60
-
61
- x.report("ob64 .encode") do
62
- Ob64.encode($unencoded)
63
- end
64
-
65
- x.compare!
66
- end
67
- end if $run_encode_benchmark
68
-
69
- decode_benchmark do
70
- Benchmark.ips do |x|
71
- x.time = 5
72
- x.warmup = 2
73
-
74
- x.report("base64 .strict_decode64") do
75
- Base64.strict_decode64($encoded)
76
- end
77
-
78
- x.report("ob64 .decode") do
79
- Ob64.decode($encoded)
80
- end
81
-
82
- x.compare!
83
- end
84
- end if $run_decode_benchmark
85
-
86
- encode_benchmark do
24
+ # Compares reports, label => block
25
+ def compare(reports)
26
+ GC.start
87
27
  Benchmark.ips do |x|
88
28
  x.time = 5
89
29
  x.warmup = 2
90
30
 
91
- x.report("base64 .urlsafe_encode64") do
92
- Base64.urlsafe_encode64($unencoded)
93
- end
94
-
95
- x.report("ob64 .urlsafe_encode") do
96
- Ob64.urlsafe_encode($unencoded)
97
- end
31
+ reports.each { |label, block| x.report(label, &block) }
98
32
 
99
- x.compare!
33
+ x.compare!(order: :baseline)
100
34
  end
101
- end if $run_urlsafe_encode_benchmark
35
+ end
102
36
 
103
- decode_benchmark do
104
- Benchmark.ips do |x|
105
- x.time = 5
106
- x.warmup = 2
37
+ each_size do |bin|
38
+ m0 = NATIVE_PACK.bind_call([bin], "m0")
39
+ urlsafe = m0.tr("+/", "-_")
40
+ m = NATIVE_PACK.bind_call([bin], "m")
107
41
 
108
- x.report("base64 .urlsafe_decode64") do
109
- Base64.urlsafe_decode64($encoded)
110
- end
42
+ compare(
43
+ "Ruby pack(\"m0\")" => -> { NATIVE_PACK.bind_call([bin], "m0") },
44
+ "ob64 Base64.encode" => -> { Ob64::Base64.encode(bin) },
45
+ "ob64 pack(\"m0\")" => -> { [bin].pack("m0") }
46
+ )
47
+ compare(
48
+ "Ruby unpack1(\"m0\")" => -> { NATIVE_UNPACK1.bind_call(m0, "m0") },
49
+ "ob64 Base64.decode" => -> { Ob64::Base64.decode(m0) },
50
+ "ob64 unpack1(\"m0\")" => -> { m0.unpack1("m0") }
51
+ )
52
+ compare(
53
+ "Ruby pack(\"m0\").tr" => -> { NATIVE_PACK.bind_call([bin], "m0").tr("+/", "-_") },
54
+ "ob64 Base64.urlsafe_encode" => -> { Ob64::Base64.urlsafe_encode(bin) }
55
+ )
56
+ compare(
57
+ "Ruby tr.unpack1(\"m0\")" => -> { NATIVE_UNPACK1.bind_call(urlsafe.tr("-_", "+/"), "m0") },
58
+ "ob64 Base64.urlsafe_decode" => -> { Ob64::Base64.urlsafe_decode(urlsafe) }
59
+ )
60
+ compare(
61
+ "Ruby pack(\"m\")" => -> { NATIVE_PACK.bind_call([bin], "m") },
62
+ "ob64 pack(\"m\")" => -> { [bin].pack("m") }
63
+ )
64
+ compare(
65
+ "Ruby unpack1(\"m\")" => -> { NATIVE_UNPACK1.bind_call(m, "m") },
66
+ "ob64 unpack1(\"m\")" => -> { m.unpack1("m") }
67
+ )
68
+ end if $run_base64_benchmark
111
69
 
112
- x.report("ob64 .urlsafe_decode") do
113
- Ob64.urlsafe_decode($encoded)
114
- end
70
+ each_size do |bin|
71
+ u = NATIVE_PACK.bind_call([bin], "u")
115
72
 
116
- x.compare!
117
- end
118
- end if $run_urlsafe_decode_benchmark
73
+ compare(
74
+ "Ruby pack(\"u\")" => -> { NATIVE_PACK.bind_call([bin], "u") },
75
+ "ob64 UU.encode" => -> { Ob64::UU.encode(bin) },
76
+ "ob64 pack(\"u\")" => -> { [bin].pack("u") }
77
+ )
78
+ compare(
79
+ "Ruby unpack1(\"u\")" => -> { NATIVE_UNPACK1.bind_call(u, "u") },
80
+ "ob64 UU.decode" => -> { Ob64::UU.decode(u) },
81
+ "ob64 unpack1(\"u\")" => -> { u.unpack1("u") }
82
+ )
83
+ end if $run_uu_benchmark
data/ext/ob64/extconf.rb CHANGED
@@ -2,46 +2,4 @@
2
2
 
3
3
  require "mkmf"
4
4
 
5
- def sys(cmd)
6
- puts " -- #{cmd}"
7
- unless ret = xsystem(cmd)
8
- raise "ERROR: '#{cmd}' failed"
9
- end
10
- ret
11
- end
12
-
13
- def run_cmake(args)
14
- pid = Process.spawn("cmake #{args}")
15
- Process.waitpid(pid)
16
- end
17
-
18
- if !find_executable("cmake")
19
- abort "ERROR: CMake is required to build ob64"
20
- end
21
-
22
- MAKE = find_executable("make") || find_executable("gmake")
23
- if !MAKE
24
- abort "ERROR: make is required to build ob64"
25
- end
26
-
27
- CWD = __dir__
28
- LIBBASE64_DIR = File.join(CWD, "..", "..", "vendor", "libbase64")
29
-
30
- Dir.chdir(LIBBASE64_DIR) do
31
- Dir.mkdir("build") unless Dir.exist?("build")
32
-
33
- Dir.chdir("build") do
34
- run_cmake(".. -DBUILD_SHARED_LIBS=true -DOPENMP=false")
35
- sys(MAKE)
36
- end
37
-
38
- $DEFLIBPATH.unshift("#{LIBBASE64_DIR}/build/bin")
39
- dir_config("base64", "#{LIBBASE64_DIR}/include", "#{LIBBASE64_DIR}/build/bin")
40
- end
41
-
42
- unless have_library("base64") && have_header("libbase64.h")
43
- abort "ERROR: Failed to build libbase64"
44
- end
45
-
46
- dir_config("ob64_ext")
47
5
  create_makefile("ob64_ext")
data/ext/ob64/ob64.h CHANGED
@@ -1,7 +1,9 @@
1
1
  #ifndef OB64_H
2
2
  #define OB64_H 1
3
3
 
4
- #include "libbase64.h"
4
+ #include "pack_base64.h"
5
5
  #include "ruby.h"
6
6
 
7
+ void Init_ob64_pack(VALUE mExt);
8
+
7
9
  #endif /* OB64_H */