ob64 0.7.0 → 0.8.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.
- checksums.yaml +4 -4
- data/.github/scripts/install-sde +21 -0
- data/.github/workflows/main.yml +54 -4
- data/CHANGELOG.md +5 -0
- data/README.md +47 -4
- data/Rakefile +11 -0
- data/ext/ob64/ob64_ext.c +3 -0
- data/ext/ob64/pack_base64.c +1 -1
- data/lib/ob64/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93d2eaeaa970d18c2ab92ff9f5bb4621c22135c16faa0f1ef09ac71babe94b95
|
|
4
|
+
data.tar.gz: 7bad60e17ca1b3189634cb2043d58bf1ffa85c701deff0b99886dde4a34082e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc8c44a79e33c420a13c1d4460a2773ed6d60ff0e4eab47ea5ad0a1db4365d85c4e642e442dfa4a2753ef0153f8bde876dca4867005f28c124f4b7251b06e55d
|
|
7
|
+
data.tar.gz: 61b2550bc2035667a86d6bfd87149fcba0bd3faa33d9e29c6f42f89cef8be2b5e5df6a36a35682e2cb9d193ea1252ee7d37bcb1d787d0c62cfa78d1618218144
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Installs Intel SDE if this CPU can't run the avx512 codec, and exports SDE,
|
|
3
|
+
# a command prefix that emulates a CPU that can.
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
missing=
|
|
7
|
+
for flag in avx512vl avx512vbmi avx512_vbmi2; do
|
|
8
|
+
grep -qw "$flag" /proc/cpuinfo || missing=1
|
|
9
|
+
done
|
|
10
|
+
[ -n "$missing" ] || exit 0
|
|
11
|
+
|
|
12
|
+
url=https://downloadmirror.intel.com/924984/sde-external-10.13.1-2026-07-28-lin.tar.xz
|
|
13
|
+
sha256=94e97d623fec54385686e1e7ba65ebc9941748c05ee451423948334892bf2b50
|
|
14
|
+
dir="$RUNNER_TEMP/sde"
|
|
15
|
+
|
|
16
|
+
curl -fsSL -o "$dir.tar.xz" "$url"
|
|
17
|
+
echo "$sha256 $dir.tar.xz" | sha256sum -c --quiet
|
|
18
|
+
mkdir -p "$dir"
|
|
19
|
+
tar xJf "$dir.tar.xz" -C "$dir" --strip-components=1
|
|
20
|
+
# Ice Lake: AVX512 with VBMI and VBMI2
|
|
21
|
+
echo "SDE=$dir/sde64 -icl --" >>"$GITHUB_ENV"
|
data/.github/workflows/main.yml
CHANGED
|
@@ -36,8 +36,15 @@ jobs:
|
|
|
36
36
|
ruby: ["3.3", "3.4", "4.0"]
|
|
37
37
|
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
|
38
38
|
cc: [gcc, clang]
|
|
39
|
+
include:
|
|
40
|
+
# Ruby built with AddressSanitizer, x86-64 only: memory errors in the
|
|
41
|
+
# C code fail the specs. ubsan adds UndefinedBehaviorSanitizer.
|
|
42
|
+
- ruby: asan-release
|
|
43
|
+
os: ubuntu-24.04
|
|
44
|
+
cc: clang
|
|
45
|
+
ubsan: true
|
|
39
46
|
runs-on: ${{ matrix.os }}
|
|
40
|
-
timeout-minutes:
|
|
47
|
+
timeout-minutes: 30
|
|
41
48
|
steps:
|
|
42
49
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
43
50
|
with:
|
|
@@ -55,14 +62,57 @@ jobs:
|
|
|
55
62
|
- name: Compile
|
|
56
63
|
env:
|
|
57
64
|
# Same warnings for both compilers; Ruby's defaults are GCC-only.
|
|
58
|
-
MAKEFLAGS:
|
|
65
|
+
MAKEFLAGS: >-
|
|
66
|
+
CC=${{ matrix.cc }}${{ matrix.ubsan && '\ -fsanitize=undefined\ -fno-sanitize-recover=all' || '' }}
|
|
67
|
+
warnflags=-Wall\ -Wextra\ -Wno-unused-parameter\ -Werror
|
|
59
68
|
run: bundle exec rake compile
|
|
60
69
|
|
|
70
|
+
- name: Install Intel SDE if the CPU lacks AVX512
|
|
71
|
+
if: runner.arch == 'X64'
|
|
72
|
+
run: .github/scripts/install-sde
|
|
73
|
+
|
|
61
74
|
- name: Show codecs
|
|
62
|
-
run: bundle exec ruby -Ilib -rob64 -e 'p Ob64.codecs, Ob64.codec'
|
|
75
|
+
run: $SDE bundle exec ruby -Ilib -rob64 -e 'p Ob64.codecs, Ob64.codec'
|
|
76
|
+
|
|
77
|
+
- name: Test
|
|
78
|
+
env:
|
|
79
|
+
# Fails the codec spec if one is missing
|
|
80
|
+
OB64_CODECS: ${{ runner.arch == 'X64' && 'scalar,avx2,avx512' || 'scalar,neon64' }}
|
|
81
|
+
run: $SDE bundle exec rake spec
|
|
82
|
+
|
|
83
|
+
codecs:
|
|
84
|
+
# The C codecs alone under ASan and UBSan, on exact-size buffers.
|
|
85
|
+
strategy:
|
|
86
|
+
fail-fast: false
|
|
87
|
+
matrix:
|
|
88
|
+
os: [ubuntu-24.04, ubuntu-24.04-arm]
|
|
89
|
+
cc: [gcc, clang]
|
|
90
|
+
runs-on: ${{ matrix.os }}
|
|
91
|
+
# Long under SDE, which emulates AVX512 slowly
|
|
92
|
+
timeout-minutes: 90
|
|
93
|
+
steps:
|
|
94
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
95
|
+
with:
|
|
96
|
+
persist-credentials: false
|
|
97
|
+
|
|
98
|
+
- uses: ruby/setup-ruby@7f797815d8adceb1c412e7abefdd1ab4abc47a5f # v1.335.0
|
|
99
|
+
with:
|
|
100
|
+
ruby-version: "3.4"
|
|
101
|
+
bundler-cache: true
|
|
102
|
+
|
|
103
|
+
- name: Install Clang
|
|
104
|
+
if: matrix.cc == 'clang'
|
|
105
|
+
run: command -v clang || { sudo apt-get update && sudo apt-get install -y clang; }
|
|
106
|
+
|
|
107
|
+
- name: Install Intel SDE if the CPU lacks AVX512
|
|
108
|
+
if: runner.arch == 'X64'
|
|
109
|
+
run: .github/scripts/install-sde
|
|
63
110
|
|
|
64
111
|
- name: Test
|
|
65
|
-
|
|
112
|
+
env:
|
|
113
|
+
CC: ${{ matrix.cc }}
|
|
114
|
+
OB64_CODECS: ${{ runner.arch == 'X64' && 'scalar,avx2,avx512' || 'scalar,neon64' }}
|
|
115
|
+
run: bundle exec rake spec:c
|
|
66
116
|
|
|
67
117
|
package:
|
|
68
118
|
runs-on: ubuntu-24.04
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [0.8.0] - 2026-10-27
|
|
2
|
+
|
|
3
|
+
- Fix undefined behavior in AVX512 detection.
|
|
4
|
+
- `Ob64::Base64::RFC4648.encode` and `encode_urlsafe` return US-ASCII Strings, like `pack("m0")` (were BINARY).
|
|
5
|
+
|
|
1
6
|
## [0.7.0] - 2026-10-26
|
|
2
7
|
|
|
3
8
|
- **Breaking:** Split `Ob64::Base64` into one module per RFC. `Ob64::Base64::RFC4648` has `encode`, `decode`, `encode_urlsafe`, `decode_urlsafe`, `encoded_length_of` and `decoded_length_of` (were `Ob64::Base64.encode`, `decode`, `urlsafe_encode`, `urlsafe_decode`, `encoded_length_of` and `decoded_length_of`).
|
data/README.md
CHANGED
|
@@ -2,13 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
[](http://rubygems.org/gems/ob64)
|
|
4
4
|
[](https://github.com/jcmfernandes/ob64/actions/workflows/main.yml)
|
|
5
|
-
[](http://www.rubydoc.info/gems/ob64/0.
|
|
5
|
+
[](http://www.rubydoc.info/gems/ob64/0.8.0)
|
|
6
6
|
|
|
7
7
|
A *fast* Base64 and uuencode encoder and decoder as a Ruby gem.
|
|
8
8
|
|
|
9
|
-
How fast?
|
|
9
|
+
How fast? Times faster than Ruby's own `pack` / `unpack1`, per call, measured with `benchmark.rb` on an AMD Ryzen 9 9900X (AVX512) with Ruby 3.4:
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
```mermaid
|
|
12
|
+
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#2a78d6"}}}}%%
|
|
13
|
+
xychart-beta
|
|
14
|
+
title "1 kB input: times faster than Ruby"
|
|
15
|
+
x-axis ["m0 enc", "m0 dec", "url enc", "url dec", "m enc", "m dec", "u enc", "u dec"]
|
|
16
|
+
y-axis "times faster" 0 --> 45
|
|
17
|
+
bar [3.1, 4.8, 11.1, 12.6, 5.2, 3.9, 5.9, 4.2]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#2a78d6"}}}}%%
|
|
22
|
+
xychart-beta
|
|
23
|
+
title "4 kB input: times faster than Ruby"
|
|
24
|
+
x-axis ["m0 enc", "m0 dec", "url enc", "url dec", "m enc", "m dec", "u enc", "u dec"]
|
|
25
|
+
y-axis "times faster" 0 --> 45
|
|
26
|
+
bar [6.3, 8.4, 17.6, 22.9, 8.4, 6.1, 7.5, 5.2]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```mermaid
|
|
30
|
+
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#2a78d6"}}}}%%
|
|
31
|
+
xychart-beta
|
|
32
|
+
title "16 kB input: times faster than Ruby"
|
|
33
|
+
x-axis ["m0 enc", "m0 dec", "url enc", "url dec", "m enc", "m dec", "u enc", "u dec"]
|
|
34
|
+
y-axis "times faster" 0 --> 45
|
|
35
|
+
bar [11.1, 12.6, 24.3, 32.8, 6.0, 7.0, 7.2, 5.3]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
%%{init: {"themeVariables": {"xyChart": {"plotColorPalette": "#2a78d6"}}}}%%
|
|
40
|
+
xychart-beta
|
|
41
|
+
title "512 kB input: times faster than Ruby"
|
|
42
|
+
x-axis ["m0 enc", "m0 dec", "url enc", "url dec", "m enc", "m dec", "u enc", "u dec"]
|
|
43
|
+
y-axis "times faster" 0 --> 45
|
|
44
|
+
bar [14.0, 13.8, 39.2, 42.0, 7.7, 7.6, 7.3, 5.3]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `m0`: RFC 4648 (`Ob64::Base64::RFC4648.encode` / `decode`)
|
|
48
|
+
- `url`: RFC 4648 URL-safe (`encode_urlsafe` / `decode_urlsafe`), against Ruby's `pack("m0")` plus `tr`
|
|
49
|
+
- `m`: RFC 2045 (`Ob64::Base64::RFC2045.encode` / `decode`)
|
|
50
|
+
- `u`: uuencode (`Ob64::UU.encode` / `decode`)
|
|
51
|
+
|
|
52
|
+
Try it yourself:
|
|
53
|
+
|
|
54
|
+
$ bin/rake compile benchmark
|
|
12
55
|
|
|
13
56
|
## Acknowledgements
|
|
14
57
|
|
|
@@ -115,7 +158,7 @@ See [{file:CHANGELOG.md}](CHANGELOG.md).
|
|
|
115
158
|
|
|
116
159
|
## Development
|
|
117
160
|
|
|
118
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
161
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests, and `rake spec:c` to check the C codecs for memory errors. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
119
162
|
|
|
120
163
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
121
164
|
|
data/Rakefile
CHANGED
|
@@ -14,6 +14,17 @@ Rake::ExtensionTask.new("ob64_ext") do |ext|
|
|
|
14
14
|
ext.ext_dir = "ext/ob64"
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
+
desc "Check the SIMD codecs against scalar in C, under ASan and UBSan; SEED=n repeats a run"
|
|
18
|
+
task "spec:c" do
|
|
19
|
+
mkdir_p "tmp"
|
|
20
|
+
sh "#{ENV.fetch("CC", "cc")} -std=gnu99 -O3 -g -fsanitize=address,undefined -fno-sanitize-recover=all " \
|
|
21
|
+
"-fno-omit-frame-pointer -Wall -Wextra -Wno-unused-parameter -Werror -Iext/ob64 -o tmp/codecs_test " \
|
|
22
|
+
"spec/c/codecs_test.c ext/ob64/pack_base64.c ext/ob64/pack_uuencode.c"
|
|
23
|
+
# SDE: an emulator prefix, see .github/scripts/install-sde. It must run the test
|
|
24
|
+
# itself: under SDE, ASan programs started by another one exit 0 unrun.
|
|
25
|
+
sh "#{ENV["SDE"]} tmp/codecs_test #{ENV["SEED"]}"
|
|
26
|
+
end
|
|
27
|
+
|
|
17
28
|
desc "Run benchmark"
|
|
18
29
|
task :benchmark do
|
|
19
30
|
load "#{__dir__}/benchmark.rb"
|
data/ext/ob64/ob64_ext.c
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <stdbool.h>
|
|
2
2
|
#include "ob64.h"
|
|
3
|
+
#include "ruby/encoding.h"
|
|
3
4
|
|
|
4
5
|
VALUE mOb64 = Qnil;
|
|
5
6
|
VALUE mOb64_Ext = Qnil;
|
|
@@ -51,6 +52,8 @@ VALUE Ob64_encode_string(VALUE self, VALUE bin, VALUE urlsafe, VALUE padding)
|
|
|
51
52
|
|
|
52
53
|
pack_base64_encode(RSTRING_PTR(bin), bin_len, RSTRING_PTR(result), flags);
|
|
53
54
|
rb_str_set_len(result, __encoded_length_of(bin_len, RTEST(padding)));
|
|
55
|
+
/* US-ASCII, as pack("m0") */
|
|
56
|
+
ENCODING_CODERANGE_SET(result, rb_usascii_encindex(), ENC_CODERANGE_7BIT);
|
|
54
57
|
RB_GC_GUARD(bin);
|
|
55
58
|
|
|
56
59
|
return result;
|
data/ext/ob64/pack_base64.c
CHANGED
data/lib/ob64/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ob64
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- João Fernandes
|
|
@@ -19,6 +19,7 @@ extensions:
|
|
|
19
19
|
extra_rdoc_files: []
|
|
20
20
|
files:
|
|
21
21
|
- ".github/dependabot.yml"
|
|
22
|
+
- ".github/scripts/install-sde"
|
|
22
23
|
- ".github/workflows/main.yml"
|
|
23
24
|
- ".gitignore"
|
|
24
25
|
- ".rspec"
|
|
@@ -59,8 +60,8 @@ licenses:
|
|
|
59
60
|
metadata:
|
|
60
61
|
homepage_uri: https://github.com/jcmfernandes/ob64
|
|
61
62
|
changelog_uri: https://github.com/jcmfernandes/ob64/blob/master/CHANGELOG.md
|
|
62
|
-
documentation_uri: https://www.rubydoc.info/gems/ob64/0.
|
|
63
|
-
source_code_uri: https://github.com/jcmfernandes/ob64/tree/v0.
|
|
63
|
+
documentation_uri: https://www.rubydoc.info/gems/ob64/0.8.0
|
|
64
|
+
source_code_uri: https://github.com/jcmfernandes/ob64/tree/v0.8.0
|
|
64
65
|
rdoc_options: []
|
|
65
66
|
require_paths:
|
|
66
67
|
- lib
|