diff --git a/deno/lib/benchmarks/index.ts b/deno/lib/benchmarks/index.ts index 773572db0..ca3b55359 100644 --- a/deno/lib/benchmarks/index.ts +++ b/deno/lib/benchmarks/index.ts @@ -2,6 +2,7 @@ import Benchmark from "benchmark"; import datetimeBenchmarks from "./datetime.ts"; import discriminatedUnionBenchmarks from "./discriminatedUnion.ts"; +import ipv4Benchmarks from "./ipv4.ts"; import objectBenchmarks from "./object.ts"; import primitiveBenchmarks from "./primitives.ts"; import realworld from "./realworld.ts"; @@ -42,6 +43,9 @@ if (!argv.length) { if (argv.includes("--datetime")) { suites.push(...datetimeBenchmarks.suites); } + if (argv.includes("--ipv4")) { + suites.push(...ipv4Benchmarks.suites); + } } for (const suite of suites) { diff --git a/deno/lib/benchmarks/ipv4.ts b/deno/lib/benchmarks/ipv4.ts new file mode 100644 index 000000000..84f1e6eb6 --- /dev/null +++ b/deno/lib/benchmarks/ipv4.ts @@ -0,0 +1,60 @@ +import Benchmark from "benchmark"; + +const suite = new Benchmark.Suite("ipv4"); + +const DATA = "127.0.0.1"; +const ipv4RegexA = + /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; +const ipv4RegexB = + /^(?:(?:(?=(25[0-5]))\1|(?=(2[0-4][0-9]))\2|(?=(1[0-9]{2}))\3|(?=([0-9]{1,2}))\4)\.){3}(?:(?=(25[0-5]))\5|(?=(2[0-4][0-9]))\6|(?=(1[0-9]{2}))\7|(?=([0-9]{1,2}))\8)$/; +const ipv4RegexC = + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/; +const ipv4RegexD = + /^(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/; +const ipv4RegexE = + /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d)$/; +const ipv4RegexF = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; +const ipv4RegexG = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; +const ipv4RegexH = /^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$/; +const ipv4RegexI = + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + +suite + .add("A", () => { + return ipv4RegexA.test(DATA); + }) + .add("B", () => { + return ipv4RegexB.test(DATA); + }) + .add("C", () => { + return ipv4RegexC.test(DATA); + }) + .add("D", () => { + return ipv4RegexD.test(DATA); + }) + .add("E", () => { + return ipv4RegexE.test(DATA); + }) + .add("F", () => { + return ipv4RegexF.test(DATA); + }) + .add("G", () => { + return ipv4RegexG.test(DATA); + }) + .add("H", () => { + return ipv4RegexH.test(DATA); + }) + .add("I", () => { + return ipv4RegexI.test(DATA); + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${suite.name!}: ${e.target}`); + }); + +export default { + suites: [suite], +}; + +if (require.main === module) { + suite.run(); +} diff --git a/deno/lib/types.ts b/deno/lib/types.ts index 1895e435d..0714f2004 100644 --- a/deno/lib/types.ts +++ b/deno/lib/types.ts @@ -605,8 +605,9 @@ const emailRegex = const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; let emojiRegex: RegExp; +// faster, simpler, safer const ipv4Regex = - /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; const ipv6Regex = /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/; diff --git a/src/benchmarks/index.ts b/src/benchmarks/index.ts index 56049ee44..8a29a3b07 100644 --- a/src/benchmarks/index.ts +++ b/src/benchmarks/index.ts @@ -2,6 +2,7 @@ import Benchmark from "benchmark"; import datetimeBenchmarks from "./datetime"; import discriminatedUnionBenchmarks from "./discriminatedUnion"; +import ipv4Benchmarks from "./ipv4"; import objectBenchmarks from "./object"; import primitiveBenchmarks from "./primitives"; import realworld from "./realworld"; @@ -42,6 +43,9 @@ if (!argv.length) { if (argv.includes("--datetime")) { suites.push(...datetimeBenchmarks.suites); } + if (argv.includes("--ipv4")) { + suites.push(...ipv4Benchmarks.suites); + } } for (const suite of suites) { diff --git a/src/benchmarks/ipv4.ts b/src/benchmarks/ipv4.ts new file mode 100644 index 000000000..84f1e6eb6 --- /dev/null +++ b/src/benchmarks/ipv4.ts @@ -0,0 +1,60 @@ +import Benchmark from "benchmark"; + +const suite = new Benchmark.Suite("ipv4"); + +const DATA = "127.0.0.1"; +const ipv4RegexA = + /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; +const ipv4RegexB = + /^(?:(?:(?=(25[0-5]))\1|(?=(2[0-4][0-9]))\2|(?=(1[0-9]{2}))\3|(?=([0-9]{1,2}))\4)\.){3}(?:(?=(25[0-5]))\5|(?=(2[0-4][0-9]))\6|(?=(1[0-9]{2}))\7|(?=([0-9]{1,2}))\8)$/; +const ipv4RegexC = + /^(?:(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$/; +const ipv4RegexD = + /^(\b25[0-5]|\b2[0-4][0-9]|\b[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/; +const ipv4RegexE = + /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.){3}(25[0-5]|(2[0-4]|1\d|[1-9]|)\d)$/; +const ipv4RegexF = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$/; +const ipv4RegexG = /^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$/; +const ipv4RegexH = /^((25[0-5]|(2[0-4]|1[0-9]|[1-9]|)[0-9])(\.(?!$)|$)){4}$/; +const ipv4RegexI = + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; + +suite + .add("A", () => { + return ipv4RegexA.test(DATA); + }) + .add("B", () => { + return ipv4RegexB.test(DATA); + }) + .add("C", () => { + return ipv4RegexC.test(DATA); + }) + .add("D", () => { + return ipv4RegexD.test(DATA); + }) + .add("E", () => { + return ipv4RegexE.test(DATA); + }) + .add("F", () => { + return ipv4RegexF.test(DATA); + }) + .add("G", () => { + return ipv4RegexG.test(DATA); + }) + .add("H", () => { + return ipv4RegexH.test(DATA); + }) + .add("I", () => { + return ipv4RegexI.test(DATA); + }) + .on("cycle", (e: Benchmark.Event) => { + console.log(`${suite.name!}: ${e.target}`); + }); + +export default { + suites: [suite], +}; + +if (require.main === module) { + suite.run(); +} diff --git a/src/types.ts b/src/types.ts index 1205276b5..aee5869b7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -605,8 +605,9 @@ const emailRegex = const _emojiRegex = `^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$`; let emojiRegex: RegExp; +// faster, simpler, safer const ipv4Regex = - /^(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))$/; + /^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/; const ipv6Regex = /^(([a-f0-9]{1,4}:){7}|::([a-f0-9]{1,4}:){0,6}|([a-f0-9]{1,4}:){1}:([a-f0-9]{1,4}:){0,5}|([a-f0-9]{1,4}:){2}:([a-f0-9]{1,4}:){0,4}|([a-f0-9]{1,4}:){3}:([a-f0-9]{1,4}:){0,3}|([a-f0-9]{1,4}:){4}:([a-f0-9]{1,4}:){0,2}|([a-f0-9]{1,4}:){5}:([a-f0-9]{1,4}:){0,1})([a-f0-9]{1,4}|(((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2}))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9]{2})|([0-9]{1,2})))$/;