commit 898757c3e9bde9698d51e9f34391eaa52d9b6030
parent 06d049b967a75f1d0dc8d96af22cbdbb2325c617
Author: Jared Tobin <jared@jtobin.io>
Date: Sat, 16 May 2026 19:34:44 -0230
lib: drop builder from bech32 final concat
Replaces the 'toStrict $ BSB.byteString hrp <> BSB.word8 49 <>
BSB.byteString dat <> BSB.byteString (as_base32 check)' pattern in
'Data.ByteString.Bech32.encode' and 'Data.ByteString.Bech32m.encode'
with a single 'BS.concat'. No more builder, no more 'safeStrategy'
buffer.
Drops the now-unused 'Data.ByteString.Builder' /
'Data.ByteString.Builder.Extra' imports and the local 'toStrict'
helper in both modules.
Benchmarks (M4 Air, -fllvm):
bech32 encode 120b 456.4 ns -> 235.4 ns (1.94x)
bech32 decode 120b 508.8 ns -> 264.5 ns (1.92x)
Diffstat:
2 files changed, 2 insertions(+), 26 deletions(-)
diff --git a/lib/Data/ByteString/Bech32.hs b/lib/Data/ByteString/Bech32.hs
@@ -25,17 +25,9 @@ import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Base32 as B32
import qualified Data.ByteString.Bech32.Internal as BI
-import qualified Data.ByteString.Builder as BSB
-import qualified Data.ByteString.Builder.Extra as BE
import qualified Data.ByteString.Internal as BSI
import qualified Data.Char as C (toLower, isLower, isAlpha)
--- realization for small builders
-toStrict :: BSB.Builder -> BS.ByteString
-toStrict = BS.toStrict
- . BE.toLazyByteStringWith (BE.safeStrategy 128 BE.smallChunkSize) mempty
-{-# INLINE toStrict #-}
-
create_checksum :: BS.ByteString -> BS.ByteString -> BS.ByteString
create_checksum = BI.create_checksum BI.Bech32
@@ -52,11 +44,7 @@ encode (B8.map C.toLower -> hrp) (B32.encode -> dat) = do
guard (BI.valid_hrp hrp)
ws <- BI.as_word5 dat
let check = create_checksum hrp ws
- res = toStrict $
- BSB.byteString hrp
- <> BSB.word8 49 -- 1
- <> BSB.byteString dat
- <> BSB.byteString (BI.as_base32 check)
+ res = BS.concat [hrp, BS.singleton 49, dat, BI.as_base32 check]
guard (BS.length res < 91)
pure res
diff --git a/lib/Data/ByteString/Bech32m.hs b/lib/Data/ByteString/Bech32m.hs
@@ -26,17 +26,9 @@ import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Base32 as B32
import qualified Data.ByteString.Bech32.Internal as BI
-import qualified Data.ByteString.Builder as BSB
-import qualified Data.ByteString.Builder.Extra as BE
import qualified Data.ByteString.Internal as BSI
import qualified Data.Char as C (toLower)
--- realization for small builders
-toStrict :: BSB.Builder -> BS.ByteString
-toStrict = BS.toStrict
- . BE.toLazyByteStringWith (BE.safeStrategy 128 BE.smallChunkSize) mempty
-{-# INLINE toStrict #-}
-
create_checksum :: BS.ByteString -> BS.ByteString -> BS.ByteString
create_checksum = BI.create_checksum BI.Bech32m
@@ -53,11 +45,7 @@ encode (B8.map C.toLower -> hrp) (B32.encode -> dat) = do
guard (BI.valid_hrp hrp)
ws <- BI.as_word5 dat
let check = create_checksum hrp ws
- res = toStrict $
- BSB.byteString hrp
- <> BSB.word8 49 -- 1
- <> BSB.byteString dat
- <> BSB.byteString (BI.as_base32 check)
+ res = BS.concat [hrp, BS.singleton 49, dat, BI.as_base32 check]
guard (BS.length res < 91)
pure res