/src/serenity/Userland/Libraries/LibWeb/DOM/QualifiedName.cpp
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2022, Andreas Kling <kling@serenityos.org> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #include <AK/HashTable.h> |
8 | | #include <LibWeb/DOM/QualifiedName.h> |
9 | | |
10 | | namespace Web::DOM { |
11 | | |
12 | | static unsigned hash_impl(FlyString const& local_name, Optional<FlyString> const& prefix, Optional<FlyString> const& namespace_) |
13 | 0 | { |
14 | 0 | unsigned hash = local_name.hash(); |
15 | 0 | if (prefix.has_value()) |
16 | 0 | hash = pair_int_hash(hash, prefix->hash()); |
17 | 0 | if (namespace_.has_value()) |
18 | 0 | hash = pair_int_hash(hash, namespace_->hash()); |
19 | 0 | return hash; |
20 | 0 | } |
21 | | |
22 | | struct ImplTraits : public Traits<QualifiedName::Impl*> { |
23 | | static unsigned hash(QualifiedName::Impl* impl) |
24 | 0 | { |
25 | 0 | return hash_impl(impl->local_name, impl->prefix, impl->namespace_); |
26 | 0 | } |
27 | | |
28 | | static bool equals(QualifiedName::Impl* a, QualifiedName::Impl* b) |
29 | 0 | { |
30 | 0 | return a->local_name == b->local_name |
31 | 0 | && a->prefix == b->prefix |
32 | 0 | && a->namespace_ == b->namespace_; |
33 | 0 | } |
34 | | }; |
35 | | |
36 | | static HashTable<QualifiedName::Impl*, ImplTraits> impls; |
37 | | |
38 | | static NonnullRefPtr<QualifiedName::Impl> ensure_impl(FlyString const& local_name, Optional<FlyString> const& prefix, Optional<FlyString> const& namespace_) |
39 | 0 | { |
40 | 0 | unsigned hash = hash_impl(local_name, prefix, namespace_); |
41 | |
|
42 | 0 | auto it = impls.find(hash, [&](QualifiedName::Impl* entry) { |
43 | 0 | return entry->local_name == local_name |
44 | 0 | && entry->prefix == prefix |
45 | 0 | && entry->namespace_ == namespace_; |
46 | 0 | }); |
47 | 0 | if (it != impls.end()) |
48 | 0 | return *(*it); |
49 | 0 | return adopt_ref(*new QualifiedName::Impl(local_name, prefix, namespace_)); |
50 | 0 | } |
51 | | |
52 | | QualifiedName::QualifiedName(FlyString const& local_name, Optional<FlyString> const& prefix, Optional<FlyString> const& namespace_) |
53 | 0 | : m_impl(ensure_impl(local_name, prefix, namespace_)) |
54 | 0 | { |
55 | 0 | } |
56 | | |
57 | | QualifiedName::Impl::Impl(FlyString const& a_local_name, Optional<FlyString> const& a_prefix, Optional<FlyString> const& a_namespace) |
58 | 0 | : local_name(a_local_name) |
59 | 0 | , prefix(a_prefix) |
60 | 0 | , namespace_(a_namespace) |
61 | 0 | { |
62 | 0 | impls.set(this); |
63 | 0 | make_internal_string(); |
64 | 0 | } |
65 | | |
66 | | QualifiedName::Impl::~Impl() |
67 | 0 | { |
68 | 0 | impls.remove(this); |
69 | 0 | } |
70 | | |
71 | | // https://dom.spec.whatwg.org/#concept-attribute-qualified-name |
72 | | // https://dom.spec.whatwg.org/#concept-element-qualified-name |
73 | | void QualifiedName::Impl::make_internal_string() |
74 | 0 | { |
75 | | // This is possible to do according to the spec: "User agents could have this as an internal slot as an optimization." |
76 | 0 | if (!prefix.has_value()) { |
77 | 0 | as_string = local_name; |
78 | 0 | return; |
79 | 0 | } |
80 | | |
81 | 0 | as_string = MUST(String::formatted("{}:{}", prefix.value(), local_name)); |
82 | 0 | } |
83 | | |
84 | | void QualifiedName::set_prefix(Optional<FlyString> value) |
85 | 0 | { |
86 | 0 | m_impl->prefix = move(value); |
87 | 0 | } |
88 | | |
89 | | } |