From 302b9f9dd7751030a41e1e444c099b98dbbae3f8 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Thu, 20 Nov 2025 22:01:14 +0800 Subject: [PATCH] micro-optimize pseudoclass parsing, add :modal --- src/browser/webapi/selector/List.zig | 1 + src/browser/webapi/selector/Parser.zig | 49 +++++++++++++----------- src/browser/webapi/selector/Selector.zig | 1 + 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/src/browser/webapi/selector/List.zig b/src/browser/webapi/selector/List.zig index 8f91d8ec..7174ecc2 100644 --- a/src/browser/webapi/selector/List.zig +++ b/src/browser/webapi/selector/List.zig @@ -499,6 +499,7 @@ fn attributeContainsWord(value: []const u8, word: []const u8) bool { fn matchesPseudoClass(el: *Node.Element, pseudo: Selector.PseudoClass) bool { switch (pseudo) { + .modal => return false, .first_child => return isFirstChild(el), .last_child => return isLastChild(el), .only_child => return isFirstChild(el) and isLastChild(el), diff --git a/src/browser/webapi/selector/Parser.zig b/src/browser/webapi/selector/Parser.zig index 7d2a058f..0b465e1d 100644 --- a/src/browser/webapi/selector/Parser.zig +++ b/src/browser/webapi/selector/Parser.zig @@ -398,29 +398,25 @@ fn pseudoClass(self: *Parser, arena: Allocator, page: *Page) !Selector.PseudoCla return error.UnknownPseudoClass; } - // Simple pseudo-classes without arguments - if (std.mem.eql(u8, name, "first-child")) { - return .first_child; - } - - if (std.mem.eql(u8, name, "last-child")) { - return .last_child; - } - - if (std.mem.eql(u8, name, "only-child")) { - return .only_child; - } - - if (std.mem.eql(u8, name, "first-of-type")) { - return .first_of_type; - } - - if (std.mem.eql(u8, name, "last-of-type")) { - return .last_of_type; - } - - if (std.mem.eql(u8, name, "only-of-type")) { - return .only_of_type; + switch (name.len) { + 5 => { + if (fastEql(name, "modal")) return .modal; + }, + 10 => { + if (fastEql(name, "only-child")) return .only_child; + if (fastEql(name, "last-child")) return .last_child; + }, + 11 => { + if (fastEql(name, "first-child")) return .first_child; + }, + 12 => { + if (fastEql(name, "only-of-type")) return .only_of_type; + if (fastEql(name, "last-of-type")) return .last_of_type; + }, + 13 => { + if (fastEql(name, "first-of-type")) return .first_of_type; + }, + else => {}, } return error.UnknownPseudoClass; @@ -801,6 +797,13 @@ fn asUint(comptime string: anytype) std.meta.Int( return @bitCast(@as(*const [byteLength]u8, string).*); } +fn fastEql(a: []const u8, comptime b: []const u8) bool { + for (a, b) |a_byte, b_byte| { + if (a_byte != b_byte) return false; + } + return true; +} + const testing = @import("../../../testing.zig"); test "Selector: Parser.ID" { { diff --git a/src/browser/webapi/selector/Selector.zig b/src/browser/webapi/selector/Selector.zig index bed15801..defc3014 100644 --- a/src/browser/webapi/selector/Selector.zig +++ b/src/browser/webapi/selector/Selector.zig @@ -131,6 +131,7 @@ pub const AttributeMatcher = union(enum) { }; pub const PseudoClass = union(enum) { + modal, first_child, last_child, only_child,