Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:Ledest:erlang:24
erlang
5171-binary-Polish-the-hex-encoding-and-decodin...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 5171-binary-Polish-the-hex-encoding-and-decoding-function.patch of Package erlang
From bfb3c873bd1287149687b66f5c3098ddb7b1a11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= <bjorn@erlang.org> Date: Wed, 15 Feb 2023 04:32:14 +0100 Subject: [PATCH] binary: Polish the hex encoding and decoding functions The code for the `binary:encode_hex/1` and `binary:encode_hex/2` functions has been simplified. The simplified implementation has a more consistent runtime compared to the old implementation. To test the performance, I made a new `hex_bench` benchmark based on the `base64` benchmark: https://gist.github.com/bjorng/522470f313ac01d16156a597657f97bb For the old implementation, on my M1 Mac the results for the best case and worst case are as follows: Size: 1024*1024 (divisible by 8) fun binary:encode_hex/1: 1000 iterations in 1899 ms: 526 it/sec Size: 1024*1024 + 1 (not divisible by 2 through 7) fun binary:encode_hex/1: 1000 iterations in 5984 ms: 167 it/sec That is, the worst case is about three times slower than the best case. The simplifed encode function shows much less variation: Size: 1024*1024 (divisible by 8) fun binary:encode_hex/1: 1000 iterations in 1899 ms: 526 it/sec Size: 1024*1024 + 1 (not divisible by 8) fun binary:encode_hex/1: 1000 iterations in 2100 ms: 476 it/sec For the old implementation of `decode_hex/1`, the benchmark results are: fun binary:decode_hex/1: 1000 iterations in 28823 ms: 34 it/sec The results for the simplified implementation are: Size: 1024*1024 (divisible by 8) fun binary:decode_hex/1: 1000 iterations in 3041 ms: 328 it/sec Size: 1024*1024+1 (not divisible by 8) fun binary:decode_hex/1: 1000 iterations in 3144 ms: 318 it/sec That is, the simplified implementation is almost 10 times faster. All hex functions now raise exceptions with correct stack traces (with the function being called at the top of the stack trace) and error information. --- lib/stdlib/src/binary.erl | 141 ++++++++---------------- lib/stdlib/src/erl_stdlib_errors.erl | 11 +- lib/stdlib/test/binary_module_SUITE.erl | 33 +++++- 3 files changed, 84 insertions(+), 101 deletions(-) diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index 4c27b1d3e6..e587cfe98d 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -365,13 +365,14 @@ get_opts_replace(_,_) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Hex encoding functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --define(HEX(X, Off), (hex(X, OffSet)):16). -compile({inline, [hex/2]}). -spec encode_hex(Bin) -> Bin2 when Bin :: binary(), Bin2 :: <<_:_*16>>. +encode_hex(Bin) when is_binary(Bin) -> + encode_hex(Bin, uppercase); encode_hex(Bin) -> - encode_hex(Bin, uppercase). + error_with_info(badarg, [Bin]). -spec encode_hex(Bin, Case) -> Bin2 when Bin :: binary(), @@ -384,23 +385,17 @@ encode_hex(Bin, lowercase) when is_binary(Bin) -> encode_hex(Bin, Case) -> error_with_info(badarg, [Bin, Case]). --spec encode_hex1(binary(), 1 | 257) -> <<_:_*16>>. -encode_hex1(Data, OffSet) when byte_size(Data) rem 8 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet),?HEX(G, OffSet),?HEX(H, OffSet)>> || <<A,B,C,D,E,F,G,H>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 7 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet),?HEX(G, OffSet)>> || <<A,B,C,D,E,F,G>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 6 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet),?HEX(F, OffSet)>> || <<A,B,C,D,E,F>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 5 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet),?HEX(E, OffSet)>> || <<A,B,C,D,E>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 4 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet),?HEX(D, OffSet)>> || <<A,B,C,D>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 3 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet),?HEX(C, OffSet)>> || <<A,B,C>> <= Data >>; -encode_hex1(Data, OffSet) when byte_size(Data) rem 2 =:= 0 -> - << <<?HEX(A, OffSet),?HEX(B, OffSet)>> || <<A,B>> <= Data >>; -encode_hex1(Data, OffSet) when is_binary(Data) -> - << <<?HEX(N, OffSet)>> || <<N>> <= Data >>. +encode_hex1(Data, Offset) -> + <<First:(bit_size(Data) div 64)/binary-unit:64, Rest/binary>> = Data, + Hex = << <<(hex(A, Offset)):16, (hex(B, Offset)):16, (hex(C, Offset)):16, (hex(D, Offset)):16, + (hex(E, Offset)):16, (hex(F, Offset)):16, (hex(G, Offset)):16, (hex(H, Offset)):16>> || + <<A,B,C,D,E,F,G,H>> <= First >>, + encode_hex2(Rest, Offset, Hex). + +encode_hex2(<<A,Data/binary>>, Offset, Acc) -> + encode_hex2(Data, Offset, <<Acc/binary, (hex(A, Offset)):16>>); +encode_hex2(<<>>, _Offset, Acc) -> + Acc. hex(X, Offset) -> element( @@ -440,84 +435,42 @@ hex(X, Offset) -> 16#6530, 16#6531, 16#6532, 16#6533, 16#6534, 16#6535, 16#6536, 16#6537, 16#6538, 16#6539, 16#6561, 16#6562, 16#6563, 16#6564, 16#6565, 16#6566, 16#6630, 16#6631, 16#6632, 16#6633, 16#6634, 16#6635, 16#6636, 16#6637, 16#6638, 16#6639, 16#6661, 16#6662, 16#6663, 16#6664, 16#6665, 16#6666}). +-compile({inline, [unhex/1]}). -spec decode_hex(Bin) -> Bin2 when Bin :: <<_:_*16>>, Bin2 :: binary(). -decode_hex(Bin) when byte_size(Bin) rem 2 =:= 0 -> - << <<(unhex(Int))>> || <<Int:16>> <= Bin >>; -decode_hex(Bin) -> - badarg_with_info([Bin]). - -%% This function pattern-matches on the hexadecimal representation of a pair of characters -%% for example, 16#3030 is matching on the integers <<48, 48>>, which is ascii for <<"00">> -unhex(16#3030) -> 0; unhex(16#3031) -> 1; unhex(16#3032) -> 2; unhex(16#3033) -> 3; unhex(16#3034) -> 4; unhex(16#3035) -> 5; unhex(16#3036) -> 6; unhex(16#3037) -> 7; unhex(16#3038) -> 8; unhex(16#3039) -> 9; -unhex(16#3041) -> 10; unhex(16#3042) -> 11; unhex(16#3043) -> 12; unhex(16#3044) -> 13; unhex(16#3045) -> 14; unhex(16#3046) -> 15; -unhex(16#3061) -> 10; unhex(16#3062) -> 11; unhex(16#3063) -> 12; unhex(16#3064) -> 13; unhex(16#3065) -> 14; unhex(16#3066) -> 15; -unhex(16#3130) -> 16; unhex(16#3131) -> 17; unhex(16#3132) -> 18; unhex(16#3133) -> 19; unhex(16#3134) -> 20; unhex(16#3135) -> 21; unhex(16#3136) -> 22; unhex(16#3137) -> 23; unhex(16#3138) -> 24; unhex(16#3139) -> 25; -unhex(16#3141) -> 26; unhex(16#3142) -> 27; unhex(16#3143) -> 28; unhex(16#3144) -> 29; unhex(16#3145) -> 30; unhex(16#3146) -> 31; -unhex(16#3161) -> 26; unhex(16#3162) -> 27; unhex(16#3163) -> 28; unhex(16#3164) -> 29; unhex(16#3165) -> 30; unhex(16#3166) -> 31; -unhex(16#3230) -> 32; unhex(16#3231) -> 33; unhex(16#3232) -> 34; unhex(16#3233) -> 35; unhex(16#3234) -> 36; unhex(16#3235) -> 37; unhex(16#3236) -> 38; unhex(16#3237) -> 39; unhex(16#3238) -> 40; unhex(16#3239) -> 41; -unhex(16#3241) -> 42; unhex(16#3242) -> 43; unhex(16#3243) -> 44; unhex(16#3244) -> 45; unhex(16#3245) -> 46; unhex(16#3246) -> 47; -unhex(16#3261) -> 42; unhex(16#3262) -> 43; unhex(16#3263) -> 44; unhex(16#3264) -> 45; unhex(16#3265) -> 46; unhex(16#3266) -> 47; -unhex(16#3330) -> 48; unhex(16#3331) -> 49; unhex(16#3332) -> 50; unhex(16#3333) -> 51; unhex(16#3334) -> 52; unhex(16#3335) -> 53; unhex(16#3336) -> 54; unhex(16#3337) -> 55; unhex(16#3338) -> 56; unhex(16#3339) -> 57; -unhex(16#3341) -> 58; unhex(16#3342) -> 59; unhex(16#3343) -> 60; unhex(16#3344) -> 61; unhex(16#3345) -> 62; unhex(16#3346) -> 63; -unhex(16#3361) -> 58; unhex(16#3362) -> 59; unhex(16#3363) -> 60; unhex(16#3364) -> 61; unhex(16#3365) -> 62; unhex(16#3366) -> 63; -unhex(16#3430) -> 64; unhex(16#3431) -> 65; unhex(16#3432) -> 66; unhex(16#3433) -> 67; unhex(16#3434) -> 68; unhex(16#3435) -> 69; unhex(16#3436) -> 70; unhex(16#3437) -> 71; unhex(16#3438) -> 72; unhex(16#3439) -> 73; -unhex(16#3441) -> 74; unhex(16#3442) -> 75; unhex(16#3443) -> 76; unhex(16#3444) -> 77; unhex(16#3445) -> 78; unhex(16#3446) -> 79; -unhex(16#3461) -> 74; unhex(16#3462) -> 75; unhex(16#3463) -> 76; unhex(16#3464) -> 77; unhex(16#3465) -> 78; unhex(16#3466) -> 79; -unhex(16#3530) -> 80; unhex(16#3531) -> 81; unhex(16#3532) -> 82; unhex(16#3533) -> 83; unhex(16#3534) -> 84; unhex(16#3535) -> 85; unhex(16#3536) -> 86; unhex(16#3537) -> 87; unhex(16#3538) -> 88; unhex(16#3539) -> 89; -unhex(16#3541) -> 90; unhex(16#3542) -> 91; unhex(16#3543) -> 92; unhex(16#3544) -> 93; unhex(16#3545) -> 94; unhex(16#3546) -> 95; -unhex(16#3561) -> 90; unhex(16#3562) -> 91; unhex(16#3563) -> 92; unhex(16#3564) -> 93; unhex(16#3565) -> 94; unhex(16#3566) -> 95; -unhex(16#3630) -> 96; unhex(16#3631) -> 97; unhex(16#3632) -> 98; unhex(16#3633) -> 99; unhex(16#3634) -> 100; unhex(16#3635) -> 101; unhex(16#3636) -> 102; unhex(16#3637) -> 103; unhex(16#3638) -> 104; unhex(16#3639) -> 105; -unhex(16#3641) -> 106; unhex(16#3642) -> 107; unhex(16#3643) -> 108; unhex(16#3644) -> 109; unhex(16#3645) -> 110; unhex(16#3646) -> 111; -unhex(16#3661) -> 106; unhex(16#3662) -> 107; unhex(16#3663) -> 108; unhex(16#3664) -> 109; unhex(16#3665) -> 110; unhex(16#3666) -> 111; -unhex(16#3730) -> 112; unhex(16#3731) -> 113; unhex(16#3732) -> 114; unhex(16#3733) -> 115; unhex(16#3734) -> 116; unhex(16#3735) -> 117; unhex(16#3736) -> 118; unhex(16#3737) -> 119; unhex(16#3738) -> 120; unhex(16#3739) -> 121; -unhex(16#3741) -> 122; unhex(16#3742) -> 123; unhex(16#3743) -> 124; unhex(16#3744) -> 125; unhex(16#3745) -> 126; unhex(16#3746) -> 127; -unhex(16#3761) -> 122; unhex(16#3762) -> 123; unhex(16#3763) -> 124; unhex(16#3764) -> 125; unhex(16#3765) -> 126; unhex(16#3766) -> 127; -unhex(16#3830) -> 128; unhex(16#3831) -> 129; unhex(16#3832) -> 130; unhex(16#3833) -> 131; unhex(16#3834) -> 132; unhex(16#3835) -> 133; unhex(16#3836) -> 134; unhex(16#3837) -> 135; unhex(16#3838) -> 136; unhex(16#3839) -> 137; -unhex(16#3841) -> 138; unhex(16#3842) -> 139; unhex(16#3843) -> 140; unhex(16#3844) -> 141; unhex(16#3845) -> 142; unhex(16#3846) -> 143; -unhex(16#3861) -> 138; unhex(16#3862) -> 139; unhex(16#3863) -> 140; unhex(16#3864) -> 141; unhex(16#3865) -> 142; unhex(16#3866) -> 143; -unhex(16#3930) -> 144; unhex(16#3931) -> 145; unhex(16#3932) -> 146; unhex(16#3933) -> 147; unhex(16#3934) -> 148; unhex(16#3935) -> 149; unhex(16#3936) -> 150; unhex(16#3937) -> 151; unhex(16#3938) -> 152; unhex(16#3939) -> 153; -unhex(16#3941) -> 154; unhex(16#3942) -> 155; unhex(16#3943) -> 156; unhex(16#3944) -> 157; unhex(16#3945) -> 158; unhex(16#3946) -> 159; -unhex(16#3961) -> 154; unhex(16#3962) -> 155; unhex(16#3963) -> 156; unhex(16#3964) -> 157; unhex(16#3965) -> 158; unhex(16#3966) -> 159; -unhex(16#4130) -> 160; unhex(16#4131) -> 161; unhex(16#4132) -> 162; unhex(16#4133) -> 163; unhex(16#4134) -> 164; unhex(16#4135) -> 165; unhex(16#4136) -> 166; unhex(16#4137) -> 167; unhex(16#4138) -> 168; unhex(16#4139) -> 169; -unhex(16#4141) -> 170; unhex(16#4142) -> 171; unhex(16#4143) -> 172; unhex(16#4144) -> 173; unhex(16#4145) -> 174; unhex(16#4146) -> 175; -unhex(16#4161) -> 170; unhex(16#4162) -> 171; unhex(16#4163) -> 172; unhex(16#4164) -> 173; unhex(16#4165) -> 174; unhex(16#4166) -> 175; -unhex(16#4230) -> 176; unhex(16#4231) -> 177; unhex(16#4232) -> 178; unhex(16#4233) -> 179; unhex(16#4234) -> 180; unhex(16#4235) -> 181; unhex(16#4236) -> 182; unhex(16#4237) -> 183; unhex(16#4238) -> 184; unhex(16#4239) -> 185; -unhex(16#4241) -> 186; unhex(16#4242) -> 187; unhex(16#4243) -> 188; unhex(16#4244) -> 189; unhex(16#4245) -> 190; unhex(16#4246) -> 191; -unhex(16#4261) -> 186; unhex(16#4262) -> 187; unhex(16#4263) -> 188; unhex(16#4264) -> 189; unhex(16#4265) -> 190; unhex(16#4266) -> 191; -unhex(16#4330) -> 192; unhex(16#4331) -> 193; unhex(16#4332) -> 194; unhex(16#4333) -> 195; unhex(16#4334) -> 196; unhex(16#4335) -> 197; unhex(16#4336) -> 198; unhex(16#4337) -> 199; unhex(16#4338) -> 200; unhex(16#4339) -> 201; -unhex(16#4341) -> 202; unhex(16#4342) -> 203; unhex(16#4343) -> 204; unhex(16#4344) -> 205; unhex(16#4345) -> 206; unhex(16#4346) -> 207; -unhex(16#4361) -> 202; unhex(16#4362) -> 203; unhex(16#4363) -> 204; unhex(16#4364) -> 205; unhex(16#4365) -> 206; unhex(16#4366) -> 207; -unhex(16#4430) -> 208; unhex(16#4431) -> 209; unhex(16#4432) -> 210; unhex(16#4433) -> 211; unhex(16#4434) -> 212; unhex(16#4435) -> 213; unhex(16#4436) -> 214; unhex(16#4437) -> 215; unhex(16#4438) -> 216; unhex(16#4439) -> 217; -unhex(16#4441) -> 218; unhex(16#4442) -> 219; unhex(16#4443) -> 220; unhex(16#4444) -> 221; unhex(16#4445) -> 222; unhex(16#4446) -> 223; -unhex(16#4461) -> 218; unhex(16#4462) -> 219; unhex(16#4463) -> 220; unhex(16#4464) -> 221; unhex(16#4465) -> 222; unhex(16#4466) -> 223; -unhex(16#4530) -> 224; unhex(16#4531) -> 225; unhex(16#4532) -> 226; unhex(16#4533) -> 227; unhex(16#4534) -> 228; unhex(16#4535) -> 229; unhex(16#4536) -> 230; unhex(16#4537) -> 231; unhex(16#4538) -> 232; unhex(16#4539) -> 233; -unhex(16#4541) -> 234; unhex(16#4542) -> 235; unhex(16#4543) -> 236; unhex(16#4544) -> 237; unhex(16#4545) -> 238; unhex(16#4546) -> 239; -unhex(16#4561) -> 234; unhex(16#4562) -> 235; unhex(16#4563) -> 236; unhex(16#4564) -> 237; unhex(16#4565) -> 238; unhex(16#4566) -> 239; -unhex(16#4630) -> 240; unhex(16#4631) -> 241; unhex(16#4632) -> 242; unhex(16#4633) -> 243; unhex(16#4634) -> 244; unhex(16#4635) -> 245; unhex(16#4636) -> 246; unhex(16#4637) -> 247; unhex(16#4638) -> 248; unhex(16#4639) -> 249; -unhex(16#4641) -> 250; unhex(16#4642) -> 251; unhex(16#4643) -> 252; unhex(16#4644) -> 253; unhex(16#4645) -> 254; unhex(16#4646) -> 255; -unhex(16#4661) -> 250; unhex(16#4662) -> 251; unhex(16#4663) -> 252; unhex(16#4664) -> 253; unhex(16#4665) -> 254; unhex(16#4666) -> 255; -unhex(16#6130) -> 160; unhex(16#6131) -> 161; unhex(16#6132) -> 162; unhex(16#6133) -> 163; unhex(16#6134) -> 164; unhex(16#6135) -> 165; unhex(16#6136) -> 166; unhex(16#6137) -> 167; unhex(16#6138) -> 168; unhex(16#6139) -> 169; -unhex(16#6141) -> 170; unhex(16#6142) -> 171; unhex(16#6143) -> 172; unhex(16#6144) -> 173; unhex(16#6145) -> 174; unhex(16#6146) -> 175; -unhex(16#6161) -> 170; unhex(16#6162) -> 171; unhex(16#6163) -> 172; unhex(16#6164) -> 173; unhex(16#6165) -> 174; unhex(16#6166) -> 175; -unhex(16#6230) -> 176; unhex(16#6231) -> 177; unhex(16#6232) -> 178; unhex(16#6233) -> 179; unhex(16#6234) -> 180; unhex(16#6235) -> 181; unhex(16#6236) -> 182; unhex(16#6237) -> 183; unhex(16#6238) -> 184; unhex(16#6239) -> 185; -unhex(16#6241) -> 186; unhex(16#6242) -> 187; unhex(16#6243) -> 188; unhex(16#6244) -> 189; unhex(16#6245) -> 190; unhex(16#6246) -> 191; -unhex(16#6261) -> 186; unhex(16#6262) -> 187; unhex(16#6263) -> 188; unhex(16#6264) -> 189; unhex(16#6265) -> 190; unhex(16#6266) -> 191; -unhex(16#6330) -> 192; unhex(16#6331) -> 193; unhex(16#6332) -> 194; unhex(16#6333) -> 195; unhex(16#6334) -> 196; unhex(16#6335) -> 197; unhex(16#6336) -> 198; unhex(16#6337) -> 199; unhex(16#6338) -> 200; unhex(16#6339) -> 201; -unhex(16#6341) -> 202; unhex(16#6342) -> 203; unhex(16#6343) -> 204; unhex(16#6344) -> 205; unhex(16#6345) -> 206; unhex(16#6346) -> 207; -unhex(16#6361) -> 202; unhex(16#6362) -> 203; unhex(16#6363) -> 204; unhex(16#6364) -> 205; unhex(16#6365) -> 206; unhex(16#6366) -> 207; -unhex(16#6430) -> 208; unhex(16#6431) -> 209; unhex(16#6432) -> 210; unhex(16#6433) -> 211; unhex(16#6434) -> 212; unhex(16#6435) -> 213; unhex(16#6436) -> 214; unhex(16#6437) -> 215; unhex(16#6438) -> 216; unhex(16#6439) -> 217; -unhex(16#6441) -> 218; unhex(16#6442) -> 219; unhex(16#6443) -> 220; unhex(16#6444) -> 221; unhex(16#6445) -> 222; unhex(16#6446) -> 223; -unhex(16#6461) -> 218; unhex(16#6462) -> 219; unhex(16#6463) -> 220; unhex(16#6464) -> 221; unhex(16#6465) -> 222; unhex(16#6466) -> 223; -unhex(16#6530) -> 224; unhex(16#6531) -> 225; unhex(16#6532) -> 226; unhex(16#6533) -> 227; unhex(16#6534) -> 228; unhex(16#6535) -> 229; unhex(16#6536) -> 230; unhex(16#6537) -> 231; unhex(16#6538) -> 232; unhex(16#6539) -> 233; -unhex(16#6541) -> 234; unhex(16#6542) -> 235; unhex(16#6543) -> 236; unhex(16#6544) -> 237; unhex(16#6545) -> 238; unhex(16#6546) -> 239; -unhex(16#6561) -> 234; unhex(16#6562) -> 235; unhex(16#6563) -> 236; unhex(16#6564) -> 237; unhex(16#6565) -> 238; unhex(16#6566) -> 239; -unhex(16#6630) -> 240; unhex(16#6631) -> 241; unhex(16#6632) -> 242; unhex(16#6633) -> 243; unhex(16#6634) -> 244; unhex(16#6635) -> 245; unhex(16#6636) -> 246; unhex(16#6637) -> 247; unhex(16#6638) -> 248; unhex(16#6639) -> 249; -unhex(16#6641) -> 250; unhex(16#6642) -> 251; unhex(16#6643) -> 252; unhex(16#6644) -> 253; unhex(16#6645) -> 254; unhex(16#6646) -> 255; -unhex(16#6661) -> 250; unhex(16#6662) -> 251; unhex(16#6663) -> 252; unhex(16#6664) -> 253; unhex(16#6665) -> 254; unhex(16#6666) -> 255; -unhex(Char) -> - badarg_with_info([<<Char:16>>]). +decode_hex(Data) when byte_size(Data) rem 2 =:= 0 -> + try + decode_hex1(Data) + catch + error:badarg -> + badarg_with_info([Data]) + end; +decode_hex(Data) -> + badarg_with_info([Data]). + +decode_hex1(Data) -> + <<First:(byte_size(Data) div 8)/binary-unit:64, Rest/binary>> = Data, + Bin = << <<(unhex(A)):4, (unhex(B)):4, (unhex(C)):4, (unhex(D)):4, + (unhex(E)):4, (unhex(F)):4, (unhex(G)):4, (unhex(H)):4>> || + <<A,B,C,D,E,F,G,H>> <= First >>, + decode_hex2(Rest, Bin). + +decode_hex2(<<A,Data/binary>>, Acc) -> + decode_hex2(Data, <<Acc/binary-unit:4, (unhex(A)):4>>); +decode_hex2(<<>>, Acc) -> + Acc. + +unhex(X) -> + element(X, + {nonono, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %1 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %16 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %32 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, no, no, no, no, no, no, %48 + no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no, %64 + no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, no, %80 + no, 10, 11, 12, 13, 14, 15, no, no, no, no, no, no, no, no, no %96 + }). badarg_with_cause(Args, Cause) -> erlang:error(badarg, Args, [{error_info, #{module => erl_stdlib_errors, diff --git a/lib/stdlib/src/erl_stdlib_errors.erl b/lib/stdlib/src/erl_stdlib_errors.erl index 540c195a2a..a90d6477a7 100644 --- a/lib/stdlib/src/erl_stdlib_errors.erl +++ b/lib/stdlib/src/erl_stdlib_errors.erl @@ -77,8 +77,13 @@ format_binary_error(encode_hex, [Subject, Case], _) -> [must_be_binary(Subject), must_be_hex_case(Case)]; format_binary_error(decode_hex, [Subject], _) -> if - is_binary(Subject), byte_size(Subject) rem 2 == 1 -> - ["must contain an even number of bytes"]; + is_binary(Subject) -> + if + byte_size(Subject) rem 2 =:= 1 -> + [<<"must contain an even number of bytes">>]; + true -> + [<<"must only contain hex digits 0-9, A-F, and a-f">>] + end; true -> [must_be_binary(Subject)] end; @@ -1088,7 +1093,7 @@ expand_error(not_atom) -> expand_error(not_binary) -> <<"not a binary">>; expand_error(bad_hex_case) -> - <<"not uppercase or lowercase">>; + <<"not 'uppercase' or 'lowercase'">>; expand_error(not_compiled_regexp) -> <<"not a compiled regular expression">>; expand_error(not_iodata) -> diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl index 5ed05bfc55..954efae9b7 100644 --- a/lib/stdlib/test/binary_module_SUITE.erl +++ b/lib/stdlib/test/binary_module_SUITE.erl @@ -1462,11 +1462,15 @@ error_info(_Config) -> {split, [<<1,2,3>>, {bm,make_ref()}, []]}, {split, [<<1,2,3>>, <<"2">>, [bad_option]]}, - {encode_hex, [{no,a,binary}], [allow_rename]}, + {encode_hex, [{no,binary}]}, + {encode_hex, [{no,binary}, lowercase]}, {encode_hex, [<<"foobar">>, othercase]}, - {decode_hex, [{no,a,binary}]}, - {decode_hex, [<<"000">>],[allow_rename]}, - {decode_hex, [<<"GG">>],[allow_rename]} + {encode_hex, [no_binary, othercase], [{1,".*"}, {2,".*"}]}, + + {decode_hex, [{no,binary}]}, + {decode_hex, [<<"000">>]}, + {decode_hex, [<<"GG">>]}, + {decode_hex, [<<255>>]} ], error_info_lib:test_error_info(binary, L). @@ -1512,8 +1516,29 @@ hex_encoding(Config) when is_list(Config) -> <<"foobar">> = binary:decode_hex(<<"666f6f626172">>), <<"foobar">> = binary:decode_hex(<<"666f6F626172">>), + + rand:seed(default), + io:format("*** SEED: ~p ***\n", [rand:export_seed()]), + Bytes = iolist_to_binary([rand:bytes(256), lists:seq(0, 255)]), + do_hex_roundtrip(Bytes), + ok. +do_hex_roundtrip(Bytes) -> + UpperHex = binary:encode_hex(Bytes), + UpperHex = binary:encode_hex(Bytes, uppercase), + LowerHex = binary:encode_hex(Bytes, lowercase), + + Bytes = binary:decode_hex(UpperHex), + Bytes = binary:decode_hex(LowerHex), + + case Bytes of + <<_, Rest/binary>> -> + do_hex_roundtrip(Rest); + <<>> -> + ok + end. + %%% %%% Utilities. %%% -- 2.35.3
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor