QualifiedName.cpp 2.6 KB

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