base62-rb 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/benchmarks/comparison.rb +1 -3
- data/benchmarks/decode_bench.rb +161 -0
- data/benchmarks/encode_bench.rb +129 -0
- data/lib/base62-rb.rb +29 -29
- data/lib/base62/version.rb +1 -1
- data/test/base62_test.rb +22 -22
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 299f76e841055f3d30cc34ff3795eac2e212e283
|
4
|
+
data.tar.gz: 80b78e4e05f4c5740050e753cca18e7def48fe7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 214f81b6a1919b075db0924bbd1f80dedab436f14a4b699421f838d2eeae24f0e2b17626b3e10d2706ae9cad3770dc8063e5a487f1fcc1f734aae787cb81ef8d
|
7
|
+
data.tar.gz: d1b0000f0512a29e98b3f5f0556079b3f81e8ccfe39cb30013e4d4532dd083dee4ba85ebc0b5ae7b8eb8b68427a993df30c12122843ed4d780e791b95e2eb229
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Base62 in Ruby
|
2
2
|
|
3
|
-
A simple and fast implementation of base62 in pure Ruby without too much sugar and magic.
|
3
|
+
A simple and fast implementation of base62 in pure Ruby without too much sugar and magic.
|
4
4
|
|
5
5
|
It uses character set: `0-9`, `a-z`, `A-Z` for encoding and decoding.
|
6
6
|
|
@@ -41,4 +41,4 @@ See the comparison [here](benchmarks/comparison.rb)
|
|
41
41
|
|
42
42
|
## License
|
43
43
|
|
44
|
-
MIT License - Copyright (c)
|
44
|
+
MIT License - Copyright (c) 2016 Steven Yue
|
data/benchmarks/comparison.rb
CHANGED
@@ -15,7 +15,6 @@ time = Benchmark.measure do
|
|
15
15
|
end
|
16
16
|
puts time # => 3.280000 0.010000 3.290000 ( 3.311349))
|
17
17
|
|
18
|
-
|
19
18
|
# gem radix62 v1.0.1
|
20
19
|
# https://github.com/matiaskorhonen/radix62
|
21
20
|
require 'radix62'
|
@@ -28,7 +27,6 @@ time = Benchmark.measure do
|
|
28
27
|
end
|
29
28
|
puts time # => 6.790000 0.020000 6.810000 ( 6.842925)
|
30
29
|
|
31
|
-
|
32
30
|
# gem base62 v1.0.0
|
33
31
|
# https://github.com/jtzemp/base62
|
34
32
|
require 'base62'
|
@@ -39,4 +37,4 @@ time = Benchmark.measure do
|
|
39
37
|
raise "Assertion error!" unless i == decode
|
40
38
|
end
|
41
39
|
end
|
42
|
-
puts time # => 10.370000 0.030000 10.400000 ( 10.452976)
|
40
|
+
puts time # => 10.370000 0.030000 10.400000 ( 10.452976)
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
|
3
|
+
KEYS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
4
|
+
KEYS_HASH = KEYS.each_char.with_index.inject({}){|h,(k,v)| h[k]=v;h}
|
5
|
+
BASE = KEYS.length
|
6
|
+
|
7
|
+
### Decode Method Candidates =====
|
8
|
+
|
9
|
+
# The one that is used in base62-rb library
|
10
|
+
# Use 'while' loop, and define a variable i as the counter
|
11
|
+
def decode(str)
|
12
|
+
num = 0
|
13
|
+
i = 0
|
14
|
+
len = str.length - 1
|
15
|
+
while i < str.length
|
16
|
+
pow = BASE ** (len - i)
|
17
|
+
num += KEYS_HASH[str[i]] * pow
|
18
|
+
i += 1
|
19
|
+
end
|
20
|
+
return num
|
21
|
+
end
|
22
|
+
|
23
|
+
# Use KEYS.index to get the index
|
24
|
+
# instead of using a predefined Hash Map(KEYS_HASH)
|
25
|
+
def decode1(str)
|
26
|
+
num = 0
|
27
|
+
i = 0
|
28
|
+
while i < str.length
|
29
|
+
pow = BASE ** (str.length - i -1)
|
30
|
+
num += KEYS.index(str[i]) * pow
|
31
|
+
i += 1
|
32
|
+
end
|
33
|
+
return num
|
34
|
+
end
|
35
|
+
|
36
|
+
# Use 'for...in...' loop
|
37
|
+
def decode2(str)
|
38
|
+
num = 0
|
39
|
+
for i in 0...str.length
|
40
|
+
pow = BASE ** (str.length - i -1)
|
41
|
+
num += KEYS_HASH[str[i]] * pow
|
42
|
+
end
|
43
|
+
return num
|
44
|
+
end
|
45
|
+
|
46
|
+
# Use String#each_char, and #with_index
|
47
|
+
# Use block to do the calcuation
|
48
|
+
def decode3(str)
|
49
|
+
num = 0
|
50
|
+
str.each_char.with_index do |char, i|
|
51
|
+
pow = BASE ** (str.length - i -1)
|
52
|
+
num += KEYS.index(char) * pow
|
53
|
+
end
|
54
|
+
return num
|
55
|
+
end
|
56
|
+
|
57
|
+
# Similar as above, but use KEYS_HASH to get the index
|
58
|
+
def decode4(str)
|
59
|
+
num = 0
|
60
|
+
str.each_char.with_index do |char, i|
|
61
|
+
pow = BASE ** (str.length - i -1)
|
62
|
+
num += KEYS_HASH[char] * pow
|
63
|
+
end
|
64
|
+
return num
|
65
|
+
end
|
66
|
+
|
67
|
+
# Similar as above, but explicitly define the counter
|
68
|
+
# without using #with_index
|
69
|
+
def decode5(str)
|
70
|
+
num = 0
|
71
|
+
i = 0
|
72
|
+
str.each_char do |char|
|
73
|
+
pow = BASE ** (str.length - i -1)
|
74
|
+
num += KEYS_HASH[char] * pow
|
75
|
+
i += 1
|
76
|
+
end
|
77
|
+
return num
|
78
|
+
end
|
79
|
+
|
80
|
+
# same thing but with less variable
|
81
|
+
def decode6(str)
|
82
|
+
num = 0
|
83
|
+
i = 0
|
84
|
+
while i < str.length
|
85
|
+
num += KEYS_HASH[str[i]] * (BASE ** (str.length - 1 - i))
|
86
|
+
i += 1
|
87
|
+
end
|
88
|
+
return num
|
89
|
+
end
|
90
|
+
|
91
|
+
### ==================
|
92
|
+
|
93
|
+
### Testing =====
|
94
|
+
|
95
|
+
tests = ["A", "Jr", "DFL", "2B5S", "8zTZmv", "1AnE6bpNA", "hjNv8tS3K"]
|
96
|
+
|
97
|
+
Benchmark.ips do |x|
|
98
|
+
x.report("decode") do
|
99
|
+
tests.each do |test|
|
100
|
+
decode(test)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
x.report("decode1") do
|
105
|
+
tests.each do |test|
|
106
|
+
decode1(test)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
x.report("decode2") do
|
111
|
+
tests.each do |test|
|
112
|
+
decode2(test)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
x.report("decode3") do
|
117
|
+
tests.each do |test|
|
118
|
+
decode3(test)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
x.report("decode4") do
|
123
|
+
tests.each do |test|
|
124
|
+
decode4(test)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
x.report("decode5") do
|
129
|
+
tests.each do |test|
|
130
|
+
decode5(test)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
x.report("decode6") do
|
135
|
+
tests.each do |test|
|
136
|
+
decode6(test)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
### Results
|
142
|
+
|
143
|
+
# Results tested on Macbook Air 1.4 GHz Intel Core i5, 8 GB 1600 MHz DDR3
|
144
|
+
# Using Ruby 2.1.3p242
|
145
|
+
|
146
|
+
# Calculating -------------------------------------
|
147
|
+
# decode 6677 i/100ms
|
148
|
+
# decode1 5962 i/100ms
|
149
|
+
# decode2 5535 i/100ms
|
150
|
+
# decode3 4378 i/100ms
|
151
|
+
# decode4 4502 i/100ms
|
152
|
+
# decode5 5915 i/100ms
|
153
|
+
# decode6 6443 i/100ms
|
154
|
+
# -------------------------------------------------
|
155
|
+
# decode 67891.4 (±9.7%) i/s - 340527 in 5.069726s
|
156
|
+
# decode1 62385.4 (±7.8%) i/s - 310024 in 5.000584s
|
157
|
+
# decode2 57033.8 (±8.5%) i/s - 287820 in 5.082882s
|
158
|
+
# decode3 45356.5 (±6.5%) i/s - 227656 in 5.041103s
|
159
|
+
# decode4 47708.3 (±6.5%) i/s - 238606 in 5.023164s
|
160
|
+
# decode5 64856.4 (±6.6%) i/s - 325325 in 5.038748s
|
161
|
+
# decode6 67880.8 (±7.4%) i/s - 341479 in 5.059089s
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
|
3
|
+
KEYS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
4
|
+
KEYS_HASH = KEYS.each_char.with_index.inject({}){|h,(k,v)| h[k]=v;h}
|
5
|
+
BASE = KEYS.length
|
6
|
+
|
7
|
+
### Encode Method Candidates =====
|
8
|
+
|
9
|
+
# The one that is used in base62-rb library
|
10
|
+
# Use '+' to prepend string
|
11
|
+
def encode(num)
|
12
|
+
return "0" if num == 0
|
13
|
+
return nil if num < 0
|
14
|
+
|
15
|
+
str = ""
|
16
|
+
while num > 0
|
17
|
+
str = KEYS[num % BASE] + str
|
18
|
+
num = num / BASE
|
19
|
+
end
|
20
|
+
return str
|
21
|
+
end
|
22
|
+
|
23
|
+
# Use String#reverse method at the end
|
24
|
+
def encode1(num)
|
25
|
+
return "0" if num == 0
|
26
|
+
return nil if num < 0
|
27
|
+
|
28
|
+
str = ""
|
29
|
+
while num > 0
|
30
|
+
str = str + KEYS[num % BASE]
|
31
|
+
num = num / (BASE)
|
32
|
+
end
|
33
|
+
return str.reverse
|
34
|
+
end
|
35
|
+
|
36
|
+
# Use String#prepend method
|
37
|
+
def encode2(num)
|
38
|
+
return "0" if num == 0
|
39
|
+
return nil if num < 0
|
40
|
+
|
41
|
+
str = ""
|
42
|
+
while num > 0
|
43
|
+
str.prepend KEYS[num % BASE]
|
44
|
+
num = num / (BASE)
|
45
|
+
end
|
46
|
+
return str
|
47
|
+
end
|
48
|
+
|
49
|
+
# Use the '/=' way
|
50
|
+
def encode3(num)
|
51
|
+
return "0" if num == 0
|
52
|
+
return nil if num < 0
|
53
|
+
|
54
|
+
str = ""
|
55
|
+
while num > 0
|
56
|
+
str = KEYS[num % BASE] + str
|
57
|
+
num /= BASE
|
58
|
+
end
|
59
|
+
return str
|
60
|
+
end
|
61
|
+
|
62
|
+
# Use #<< to append string
|
63
|
+
def encode4(num)
|
64
|
+
return "0" if num == 0
|
65
|
+
return nil if num < 0
|
66
|
+
|
67
|
+
str = ""
|
68
|
+
while num > 0
|
69
|
+
str << KEYS[num % BASE]
|
70
|
+
num /= BASE
|
71
|
+
end
|
72
|
+
return str.reverse
|
73
|
+
end
|
74
|
+
|
75
|
+
### ==================
|
76
|
+
|
77
|
+
### Testing =====
|
78
|
+
|
79
|
+
tests_encode = [630, 1231, 902323, 3781504209452600, 18446744073709551615]
|
80
|
+
|
81
|
+
Benchmark.ips do |x|
|
82
|
+
x.report("encode") do
|
83
|
+
tests_encode.each do |test|
|
84
|
+
encode(test)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
x.report("encode1") do
|
89
|
+
tests_encode.each do |test|
|
90
|
+
encode1(test)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
x.report("encode2") do
|
95
|
+
tests_encode.each do |test|
|
96
|
+
encode2(test)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
x.report("encode3") do
|
101
|
+
tests_encode.each do |test|
|
102
|
+
encode3(test)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
x.report("encode4") do
|
107
|
+
tests_encode.each do |test|
|
108
|
+
encode4(test)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
### Results
|
114
|
+
|
115
|
+
# Results tested on Macbook Air 1.4 GHz Intel Core i5, 8 GB 1600 MHz DDR3
|
116
|
+
# Using Ruby 2.1.3p242
|
117
|
+
|
118
|
+
# Calculating -------------------------------------
|
119
|
+
# encode 9141 i/100ms
|
120
|
+
# encode1 8231 i/100ms
|
121
|
+
# encode2 7222 i/100ms
|
122
|
+
# encode3 9040 i/100ms
|
123
|
+
# encode4 8660 i/100ms
|
124
|
+
# -------------------------------------------------
|
125
|
+
# encode 97414.2 (±8.1%) i/s - 484473 in 5.008219s
|
126
|
+
# encode1 89976.1 (±6.5%) i/s - 452705 in 5.053138s
|
127
|
+
# encode2 76680.4 (±6.8%) i/s - 382766 in 5.015263s
|
128
|
+
# encode3 94348.1 (±8.2%) i/s - 470080 in 5.016213s
|
129
|
+
# encode4 86996.4 (±8.7%) i/s - 433000 in 5.016085s
|
data/lib/base62-rb.rb
CHANGED
@@ -1,35 +1,35 @@
|
|
1
1
|
require "base62/version"
|
2
2
|
|
3
3
|
module Base62
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
KEYS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze
|
5
|
+
KEYS_HASH = KEYS.each_char.with_index.inject({}) { |h, (k, v)| h[k] = v; h }
|
6
|
+
BASE = KEYS.length
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
# Encodes base10 (decimal) number to base62 string.
|
9
|
+
def self.encode(num)
|
10
|
+
return "0" if num == 0
|
11
|
+
return nil if num < 0
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
str = ""
|
14
|
+
while num > 0
|
15
|
+
# prepend base62 charaters
|
16
|
+
str = KEYS[num % BASE] + str
|
17
|
+
num = num / BASE
|
18
|
+
end
|
19
|
+
str
|
20
|
+
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
22
|
+
# Decodes base62 string to a base10 (decimal) number.
|
23
|
+
def self.decode(str)
|
24
|
+
num = 0
|
25
|
+
i = 0
|
26
|
+
len = str.length - 1
|
27
|
+
# while loop is faster than each_char or other 'idiomatic' way
|
28
|
+
while i < str.length
|
29
|
+
pow = BASE**(len - i)
|
30
|
+
num += KEYS_HASH[str[i]] * pow
|
31
|
+
i += 1
|
32
|
+
end
|
33
|
+
num
|
34
|
+
end
|
35
|
+
end
|
data/lib/base62/version.rb
CHANGED
data/test/base62_test.rb
CHANGED
@@ -2,27 +2,27 @@ require "base62-rb"
|
|
2
2
|
require "test/unit"
|
3
3
|
|
4
4
|
class Base62Test < Test::Unit::TestCase
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
5
|
+
def test_encode
|
6
|
+
{
|
7
|
+
0 => "0",
|
8
|
+
3781504209452600 => "hjNv8tS3K",
|
9
|
+
18446744073709551615 => "lYGhA16ahyf"
|
10
|
+
}.each do |int, base62|
|
11
|
+
assert_equal base62, Base62.encode(int)
|
12
|
+
end
|
13
|
+
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
15
|
+
def test_decode
|
16
|
+
{
|
17
|
+
"0" => 0,
|
18
|
+
"hjNv8tS3K" => 3781504209452600,
|
19
|
+
"lYGhA16ahyf" => 18446744073709551615
|
20
|
+
}.each do |base62, int|
|
21
|
+
assert_equal int, Base62.decode(base62)
|
22
|
+
end
|
23
|
+
end
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def test_negative_numbers
|
26
|
+
assert_nil Base62.encode(-123)
|
27
|
+
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: base62-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Yue
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,8 @@ files:
|
|
52
52
|
- Rakefile
|
53
53
|
- base62-rb.gemspec
|
54
54
|
- benchmarks/comparison.rb
|
55
|
+
- benchmarks/decode_bench.rb
|
56
|
+
- benchmarks/encode_bench.rb
|
55
57
|
- lib/base62-rb.rb
|
56
58
|
- lib/base62/version.rb
|
57
59
|
- test/base62_test.rb
|
@@ -75,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
75
77
|
version: '0'
|
76
78
|
requirements: []
|
77
79
|
rubyforge_project:
|
78
|
-
rubygems_version: 2.
|
80
|
+
rubygems_version: 2.5.1
|
79
81
|
signing_key:
|
80
82
|
specification_version: 4
|
81
83
|
summary: Fast Base62 encoding and decoding in Ruby
|