class Epithet::Block58
Fixed-length Base58 codec for a fixed-size block.
Constants
- Alphabet
-
= "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
Public Class Methods
Source
# File lib/epithet.rb, line 225 def initialize(block_size, alphabet: Alphabet) @alphabet = alphabet.b.freeze raise ArgumentError, "invalid alphabet length" unless @alphabet.bytesize == 58 @size = ((block_size * 8) / Math.log2(58)).ceil(0) @charsel = @alphabet.gsub(/[\^\-\\]/, '\\\\\&').freeze @blank = @alphabet[0] * @size @lut = @alphabet.each_byte.with_index.with_object("\0" * 256) { |(val, idx), lut| lut.setbyte(val, idx) }.freeze end
Create a codec for a block size in bytes.
Public Instance Methods
Source
# File lib/epithet.rb, line 244 def i2s(int) # Using divmod+setbyte is faster than Integer#digits under YJIT, # and about equal in plain MRI. alphabet = @alphabet out = @blank.dup idx = @size - 1 n = int while idx >= 0 && n > 0 n, rem = n.divmod(58) out.setbyte(idx, alphabet.getbyte(rem)) idx -= 1 end out end
Encode a non-negative Integer to fixed-length Base58.
Source
# File lib/epithet.rb, line 234 def inspect "#<#{self.class}:#{'%#016x' % (object_id << 1)} size=#{@size} alphabet=#{@alphabet}>" end
Source
# File lib/epithet.rb, line 261 def s2i(str) # By unrolling coefficients, this is ~8x faster than Horner's scheme # # str.each_byte.inject(0) { _1 * 58 + @lut[_2] } # # at computing the inner product when using YJIT, by chunking # intermediate results into 64-bit integers. lut = @lut acc0 = lut.getbyte(str.getbyte(0)) * 7427658739644928 + lut.getbyte(str.getbyte(1)) * 128063081718016 + lut.getbyte(str.getbyte(2)) * 2207984167552 + lut.getbyte(str.getbyte(3)) * 38068692544 + lut.getbyte(str.getbyte(4)) * 656356768 + lut.getbyte(str.getbyte(5)) * 11316496 + lut.getbyte(str.getbyte(6)) * 195112 + lut.getbyte(str.getbyte(7)) * 3364 + lut.getbyte(str.getbyte(8)) * 58 + lut.getbyte(str.getbyte(9)) acc1 = lut.getbyte(str.getbyte(10)) * 7427658739644928 + lut.getbyte(str.getbyte(11)) * 128063081718016 + lut.getbyte(str.getbyte(12)) * 2207984167552 + lut.getbyte(str.getbyte(13)) * 38068692544 + lut.getbyte(str.getbyte(14)) * 656356768 + lut.getbyte(str.getbyte(15)) * 11316496 + lut.getbyte(str.getbyte(16)) * 195112 + lut.getbyte(str.getbyte(17)) * 3364 + lut.getbyte(str.getbyte(18)) * 58 + lut.getbyte(str.getbyte(19)) lut.getbyte(str.getbyte(21)) + 58 * lut.getbyte(str.getbyte(20)) + 3364 * acc1 + 1449225352009601191936 * acc0 end
Decode a fixed-length Base58 string to an Integer. Assumes the input passes valid?.
Source
# File lib/epithet.rb, line 239 def valid?(s) String === s && s.bytesize == @size && s.count(@charsel) == @size end
Return true if the string has the right size and alphabet.