Skip to content

Commit 5e55444

Browse files
authored
Merge pull request #1163 from bloomberg/micro_opt
some micro optimizations of string
2 parents c902ab3 + 0910abe commit 5e55444

File tree

11 files changed

+2152
-1214
lines changed

11 files changed

+2152
-1214
lines changed

jscomp/bin/all_ounit_tests.i.ml

Lines changed: 1280 additions & 1094 deletions
Large diffs are not rendered by default.

jscomp/bin/all_ounit_tests.ml

Lines changed: 178 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,7 +1737,7 @@ val single_space : string
17371737

17381738
val concat3 : string -> string -> string -> string
17391739
val concat4 : string -> string -> string -> string -> string
1740-
1740+
val concat5 : string -> string -> string -> string -> string -> string
17411741
val inter2 : string -> string -> string
17421742
val inter3 : string -> string -> string -> string
17431743
val inter4 : string -> string -> string -> string -> string
@@ -1957,15 +1957,15 @@ let contain_substring s sub =
19571957
find s ~sub >= 0
19581958

19591959
(** TODO: optimize
1960-
avoid nonterminating when string is empty
1960+
avoid nonterminating when string is empty
19611961
*)
19621962
let non_overlap_count ~sub s =
19631963
let sub_len = String.length sub in
19641964
let rec aux acc off =
19651965
let i = find ~start:off ~sub s in
19661966
if i < 0 then acc
19671967
else aux (acc + 1) (i + sub_len) in
1968-
if String.length sub = 0 then invalid_arg "Ext_string.non_overlap_count"
1968+
if String.length sub = 0 then invalid_arg "Ext_string.non_overlap_count"
19691969
else aux 0 0
19701970

19711971

@@ -2128,19 +2128,95 @@ external compare : string -> string -> int = "caml_string_length_based_compare"
21282128

21292129
let single_space = " "
21302130
let single_colon = ":"
2131-
let concat3 a b c = a ^ b ^ c
2132-
let concat4 a b c d = a ^ b ^ c ^ d
21332131

2134-
let inter2 a b = a ^ single_space ^ b
2132+
let concat_array sep (s : string array) =
2133+
let s_len = Array.length s in
2134+
match s_len with
2135+
| 0 -> empty
2136+
| 1 -> Array.unsafe_get s 0
2137+
| _ ->
2138+
let sep_len = String.length sep in
2139+
let len = ref 0 in
2140+
for i = 0 to s_len - 1 do
2141+
len := !len + String.length (Array.unsafe_get s i)
2142+
done;
2143+
let target =
2144+
Bytes.create
2145+
(!len + (s_len - 1) * sep_len ) in
2146+
let hd = (Array.unsafe_get s 0) in
2147+
let hd_len = String.length hd in
2148+
String.unsafe_blit hd 0 target 0 hd_len;
2149+
let current_offset = ref hd_len in
2150+
for i = 1 to s_len - 1 do
2151+
String.unsafe_blit sep 0 target !current_offset sep_len;
2152+
let cur = Array.unsafe_get s i in
2153+
let cur_len = String.length cur in
2154+
let new_off_set = (!current_offset + sep_len ) in
2155+
String.unsafe_blit cur 0 target new_off_set cur_len;
2156+
current_offset :=
2157+
new_off_set + cur_len ;
2158+
done;
2159+
Bytes.unsafe_to_string target
2160+
2161+
let concat3 a b c =
2162+
let a_len = String.length a in
2163+
let b_len = String.length b in
2164+
let c_len = String.length c in
2165+
let len = a_len + b_len + c_len in
2166+
let target = Bytes.create len in
2167+
String.unsafe_blit a 0 target 0 a_len ;
2168+
String.unsafe_blit b 0 target a_len b_len;
2169+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
2170+
Bytes.unsafe_to_string target
2171+
2172+
let concat4 a b c d =
2173+
let a_len = String.length a in
2174+
let b_len = String.length b in
2175+
let c_len = String.length c in
2176+
let d_len = String.length d in
2177+
let len = a_len + b_len + c_len + d_len in
2178+
2179+
let target = Bytes.create len in
2180+
String.unsafe_blit a 0 target 0 a_len ;
2181+
String.unsafe_blit b 0 target a_len b_len;
2182+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
2183+
String.unsafe_blit d 0 target (a_len + b_len + c_len) d_len;
2184+
Bytes.unsafe_to_string target
2185+
2186+
2187+
let concat5 a b c d e =
2188+
let a_len = String.length a in
2189+
let b_len = String.length b in
2190+
let c_len = String.length c in
2191+
let d_len = String.length d in
2192+
let e_len = String.length e in
2193+
let len = a_len + b_len + c_len + d_len + e_len in
2194+
2195+
let target = Bytes.create len in
2196+
String.unsafe_blit a 0 target 0 a_len ;
2197+
String.unsafe_blit b 0 target a_len b_len;
2198+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
2199+
String.unsafe_blit d 0 target (a_len + b_len + c_len) d_len;
2200+
String.unsafe_blit e 0 target (a_len + b_len + c_len + d_len) e_len;
2201+
Bytes.unsafe_to_string target
2202+
2203+
2204+
2205+
let inter2 a b =
2206+
concat3 a single_space b
2207+
21352208

21362209
let inter3 a b c =
2137-
a ^ single_space ^ b ^ single_space ^ c
2210+
concat5 a single_space b single_space c
2211+
2212+
2213+
2214+
21382215

21392216
let inter4 a b c d =
2140-
a ^ single_space ^ b ^ single_space ^ c ^ single_space ^ d
2141-
(** TODO: improve perf *)
2142-
let concat_array sep (s : string array) =
2143-
String.concat sep (Array.to_list s)
2217+
concat_array single_space [| a; b ; c; d|]
2218+
2219+
21442220
end
21452221
module Ounit_array_tests
21462222
= struct
@@ -11939,7 +12015,7 @@ let suites =
1193912015
OUnit.assert_bool __LOC__ (Ext_string.compare a b < 0);
1194012016
OUnit.assert_bool __LOC__ (Ext_string.compare b a > 0)
1194112017
done ;
11942-
12018+
1194312019
end;
1194412020
__LOC__ >:: begin fun _ ->
1194512021
let slow_compare x y =
@@ -11949,20 +12025,96 @@ let suites =
1194912025
String.compare x y
1195012026
else
1195112027
Pervasives.compare x_len y_len in
11952-
let same_sign x y =
11953-
if x = 0 then y = 0
11954-
else if x < 0 then y < 0
11955-
else y > 0 in
11956-
for i = 0 to 3000 do
11957-
let chars = [|'a';'b';'c';'d'|] in
11958-
let x = Ounit_data_random.random_string chars 129 in
11959-
let y = Ounit_data_random.random_string chars 129 in
11960-
let a = Ext_string.compare x y in
11961-
let b = slow_compare x y in
11962-
if same_sign a b then OUnit.assert_bool __LOC__ true
11963-
else failwith ("incosistent " ^ x ^ " " ^ y ^ " " ^ string_of_int a ^ " " ^ string_of_int b)
11964-
done
11965-
end
12028+
let same_sign x y =
12029+
if x = 0 then y = 0
12030+
else if x < 0 then y < 0
12031+
else y > 0 in
12032+
for i = 0 to 3000 do
12033+
let chars = [|'a';'b';'c';'d'|] in
12034+
let x = Ounit_data_random.random_string chars 129 in
12035+
let y = Ounit_data_random.random_string chars 129 in
12036+
let a = Ext_string.compare x y in
12037+
let b = slow_compare x y in
12038+
if same_sign a b then OUnit.assert_bool __LOC__ true
12039+
else failwith ("incosistent " ^ x ^ " " ^ y ^ " " ^ string_of_int a ^ " " ^ string_of_int b)
12040+
done
12041+
end ;
12042+
__LOC__ >:: begin fun _ ->
12043+
OUnit.assert_bool __LOC__
12044+
(Ext_string.equal
12045+
(Ext_string.concat3 "a0" "a1" "a2") "a0a1a2"
12046+
);
12047+
OUnit.assert_bool __LOC__
12048+
(Ext_string.equal
12049+
(Ext_string.concat3 "a0" "a11" "") "a0a11"
12050+
);
12051+
12052+
OUnit.assert_bool __LOC__
12053+
(Ext_string.equal
12054+
(Ext_string.concat4 "a0" "a1" "a2" "a3") "a0a1a2a3"
12055+
);
12056+
OUnit.assert_bool __LOC__
12057+
(Ext_string.equal
12058+
(Ext_string.concat4 "a0" "a11" "" "a33") "a0a11a33"
12059+
);
12060+
end;
12061+
__LOC__ >:: begin fun _ ->
12062+
OUnit.assert_bool __LOC__
12063+
(Ext_string.equal
12064+
(Ext_string.inter2 "a0" "a1") "a0 a1"
12065+
);
12066+
OUnit.assert_bool __LOC__
12067+
(Ext_string.equal
12068+
(Ext_string.inter3 "a0" "a1" "a2") "a0 a1 a2"
12069+
);
12070+
OUnit.assert_bool __LOC__
12071+
(Ext_string.equal
12072+
(Ext_string.inter4 "a0" "a1" "a2" "a3") "a0 a1 a2 a3"
12073+
);
12074+
end;
12075+
__LOC__ >:: begin fun _ ->
12076+
OUnit.assert_bool __LOC__
12077+
(Ext_string.equal
12078+
(Ext_string.concat_array Ext_string.single_space [||])
12079+
Ext_string.empty
12080+
);
12081+
OUnit.assert_bool __LOC__
12082+
(Ext_string.equal
12083+
(Ext_string.concat_array Ext_string.single_space [|"a0"|])
12084+
"a0"
12085+
);
12086+
OUnit.assert_bool __LOC__
12087+
(Ext_string.equal
12088+
(Ext_string.concat_array Ext_string.single_space [|"a0";"a1"|])
12089+
"a0 a1"
12090+
);
12091+
OUnit.assert_bool __LOC__
12092+
(Ext_string.equal
12093+
(Ext_string.concat_array Ext_string.single_space [|"a0";"a1"; "a2"|])
12094+
"a0 a1 a2"
12095+
);
12096+
OUnit.assert_bool __LOC__
12097+
(Ext_string.equal
12098+
(Ext_string.concat_array Ext_string.single_space [|"a0";"a1"; "a2";"a3"|])
12099+
"a0 a1 a2 a3"
12100+
);
12101+
OUnit.assert_bool __LOC__
12102+
(Ext_string.equal
12103+
(Ext_string.concat_array Ext_string.single_space [|"a0";"a1"; "a2";"a3";""; "a4"|])
12104+
"a0 a1 a2 a3 a4"
12105+
);
12106+
OUnit.assert_bool __LOC__
12107+
(Ext_string.equal
12108+
(Ext_string.concat_array Ext_string.single_space [|"0";"a1"; "2";"a3";""; "a4"|])
12109+
"0 a1 2 a3 a4"
12110+
);
12111+
OUnit.assert_bool __LOC__
12112+
(Ext_string.equal
12113+
(Ext_string.concat_array Ext_string.single_space [|"0";"a1"; "2";"3";"d"; ""; "e"|])
12114+
"0 a1 2 3 d e"
12115+
);
12116+
12117+
end
1196612118
]
1196712119
end
1196812120
module Ext_topsort : sig

jscomp/bin/bsb.ml

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ val single_space : string
823823

824824
val concat3 : string -> string -> string -> string
825825
val concat4 : string -> string -> string -> string -> string
826-
826+
val concat5 : string -> string -> string -> string -> string -> string
827827
val inter2 : string -> string -> string
828828
val inter3 : string -> string -> string -> string
829829
val inter4 : string -> string -> string -> string -> string
@@ -1043,15 +1043,15 @@ let contain_substring s sub =
10431043
find s ~sub >= 0
10441044

10451045
(** TODO: optimize
1046-
avoid nonterminating when string is empty
1046+
avoid nonterminating when string is empty
10471047
*)
10481048
let non_overlap_count ~sub s =
10491049
let sub_len = String.length sub in
10501050
let rec aux acc off =
10511051
let i = find ~start:off ~sub s in
10521052
if i < 0 then acc
10531053
else aux (acc + 1) (i + sub_len) in
1054-
if String.length sub = 0 then invalid_arg "Ext_string.non_overlap_count"
1054+
if String.length sub = 0 then invalid_arg "Ext_string.non_overlap_count"
10551055
else aux 0 0
10561056

10571057

@@ -1214,19 +1214,95 @@ external compare : string -> string -> int = "caml_string_length_based_compare"
12141214

12151215
let single_space = " "
12161216
let single_colon = ":"
1217-
let concat3 a b c = a ^ b ^ c
1218-
let concat4 a b c d = a ^ b ^ c ^ d
12191217

1220-
let inter2 a b = a ^ single_space ^ b
1218+
let concat_array sep (s : string array) =
1219+
let s_len = Array.length s in
1220+
match s_len with
1221+
| 0 -> empty
1222+
| 1 -> Array.unsafe_get s 0
1223+
| _ ->
1224+
let sep_len = String.length sep in
1225+
let len = ref 0 in
1226+
for i = 0 to s_len - 1 do
1227+
len := !len + String.length (Array.unsafe_get s i)
1228+
done;
1229+
let target =
1230+
Bytes.create
1231+
(!len + (s_len - 1) * sep_len ) in
1232+
let hd = (Array.unsafe_get s 0) in
1233+
let hd_len = String.length hd in
1234+
String.unsafe_blit hd 0 target 0 hd_len;
1235+
let current_offset = ref hd_len in
1236+
for i = 1 to s_len - 1 do
1237+
String.unsafe_blit sep 0 target !current_offset sep_len;
1238+
let cur = Array.unsafe_get s i in
1239+
let cur_len = String.length cur in
1240+
let new_off_set = (!current_offset + sep_len ) in
1241+
String.unsafe_blit cur 0 target new_off_set cur_len;
1242+
current_offset :=
1243+
new_off_set + cur_len ;
1244+
done;
1245+
Bytes.unsafe_to_string target
1246+
1247+
let concat3 a b c =
1248+
let a_len = String.length a in
1249+
let b_len = String.length b in
1250+
let c_len = String.length c in
1251+
let len = a_len + b_len + c_len in
1252+
let target = Bytes.create len in
1253+
String.unsafe_blit a 0 target 0 a_len ;
1254+
String.unsafe_blit b 0 target a_len b_len;
1255+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
1256+
Bytes.unsafe_to_string target
1257+
1258+
let concat4 a b c d =
1259+
let a_len = String.length a in
1260+
let b_len = String.length b in
1261+
let c_len = String.length c in
1262+
let d_len = String.length d in
1263+
let len = a_len + b_len + c_len + d_len in
1264+
1265+
let target = Bytes.create len in
1266+
String.unsafe_blit a 0 target 0 a_len ;
1267+
String.unsafe_blit b 0 target a_len b_len;
1268+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
1269+
String.unsafe_blit d 0 target (a_len + b_len + c_len) d_len;
1270+
Bytes.unsafe_to_string target
1271+
1272+
1273+
let concat5 a b c d e =
1274+
let a_len = String.length a in
1275+
let b_len = String.length b in
1276+
let c_len = String.length c in
1277+
let d_len = String.length d in
1278+
let e_len = String.length e in
1279+
let len = a_len + b_len + c_len + d_len + e_len in
1280+
1281+
let target = Bytes.create len in
1282+
String.unsafe_blit a 0 target 0 a_len ;
1283+
String.unsafe_blit b 0 target a_len b_len;
1284+
String.unsafe_blit c 0 target (a_len + b_len) c_len;
1285+
String.unsafe_blit d 0 target (a_len + b_len + c_len) d_len;
1286+
String.unsafe_blit e 0 target (a_len + b_len + c_len + d_len) e_len;
1287+
Bytes.unsafe_to_string target
1288+
1289+
1290+
1291+
let inter2 a b =
1292+
concat3 a single_space b
1293+
12211294

12221295
let inter3 a b c =
1223-
a ^ single_space ^ b ^ single_space ^ c
1296+
concat5 a single_space b single_space c
1297+
1298+
1299+
1300+
12241301

12251302
let inter4 a b c d =
1226-
a ^ single_space ^ b ^ single_space ^ c ^ single_space ^ d
1227-
(** TODO: improve perf *)
1228-
let concat_array sep (s : string array) =
1229-
String.concat sep (Array.to_list s)
1303+
concat_array single_space [| a; b ; c; d|]
1304+
1305+
12301306
end
12311307
module Ext_filename : sig
12321308
#1 "ext_filename.mli"

0 commit comments

Comments
 (0)