Handle.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Badge.h>
  8. #include <AK/IntrusiveList.h>
  9. #include <AK/Noncopyable.h>
  10. #include <AK/RefCounted.h>
  11. #include <AK/RefPtr.h>
  12. #include <AK/SourceLocation.h>
  13. #include <LibJS/Forward.h>
  14. #include <LibJS/Runtime/Value.h>
  15. namespace JS {
  16. class HandleImpl : public RefCounted<HandleImpl> {
  17. AK_MAKE_NONCOPYABLE(HandleImpl);
  18. AK_MAKE_NONMOVABLE(HandleImpl);
  19. public:
  20. ~HandleImpl();
  21. Cell* cell() { return m_cell; }
  22. Cell const* cell() const { return m_cell; }
  23. SourceLocation const& source_location() const { return m_location; }
  24. private:
  25. template<class T>
  26. friend class Handle;
  27. explicit HandleImpl(Cell*, SourceLocation location);
  28. GCPtr<Cell> m_cell;
  29. SourceLocation m_location;
  30. IntrusiveListNode<HandleImpl> m_list_node;
  31. public:
  32. using List = IntrusiveList<&HandleImpl::m_list_node>;
  33. };
  34. template<class T>
  35. class Handle {
  36. public:
  37. Handle() = default;
  38. static Handle create(T* cell, SourceLocation location = SourceLocation::current())
  39. {
  40. return Handle(adopt_ref(*new HandleImpl(const_cast<RemoveConst<T>*>(cell), location)));
  41. }
  42. Handle(T* cell, SourceLocation location = SourceLocation::current())
  43. {
  44. if (cell)
  45. m_impl = adopt_ref(*new HandleImpl(cell, location));
  46. }
  47. Handle(T& cell, SourceLocation location = SourceLocation::current())
  48. : m_impl(adopt_ref(*new HandleImpl(&cell, location)))
  49. {
  50. }
  51. Handle(GCPtr<T> cell, SourceLocation location = SourceLocation::current())
  52. : Handle(cell.ptr(), location)
  53. {
  54. }
  55. Handle(NonnullGCPtr<T> cell, SourceLocation location = SourceLocation::current())
  56. : Handle(*cell, location)
  57. {
  58. }
  59. T* cell() const
  60. {
  61. if (!m_impl)
  62. return nullptr;
  63. return static_cast<T*>(m_impl->cell());
  64. }
  65. T* ptr() const
  66. {
  67. return cell();
  68. }
  69. bool is_null() const
  70. {
  71. return m_impl.is_null();
  72. }
  73. T* operator->() const
  74. {
  75. return cell();
  76. }
  77. T& operator*() const
  78. {
  79. return *cell();
  80. }
  81. bool operator!() const
  82. {
  83. return !cell();
  84. }
  85. operator bool() const
  86. {
  87. return cell();
  88. }
  89. operator T*() const { return cell(); }
  90. private:
  91. explicit Handle(NonnullRefPtr<HandleImpl> impl)
  92. : m_impl(move(impl))
  93. {
  94. }
  95. RefPtr<HandleImpl> m_impl;
  96. };
  97. template<class T>
  98. inline Handle<T> make_handle(T* cell, SourceLocation location = SourceLocation::current())
  99. {
  100. if (!cell)
  101. return Handle<T> {};
  102. return Handle<T>::create(cell, location);
  103. }
  104. template<class T>
  105. inline Handle<T> make_handle(T& cell, SourceLocation location = SourceLocation::current())
  106. {
  107. return Handle<T>::create(&cell, location);
  108. }
  109. template<class T>
  110. inline Handle<T> make_handle(GCPtr<T> cell, SourceLocation location = SourceLocation::current())
  111. {
  112. if (!cell)
  113. return Handle<T> {};
  114. return Handle<T>::create(cell.ptr(), location);
  115. }
  116. template<class T>
  117. inline Handle<T> make_handle(NonnullGCPtr<T> cell, SourceLocation location = SourceLocation::current())
  118. {
  119. return Handle<T>::create(cell.ptr(), location);
  120. }
  121. template<>
  122. class Handle<Value> {
  123. public:
  124. Handle() = default;
  125. static Handle create(Value value, SourceLocation location)
  126. {
  127. if (value.is_cell())
  128. return Handle(value, &value.as_cell(), location);
  129. return Handle(value);
  130. }
  131. auto cell() { return m_handle.cell(); }
  132. auto cell() const { return m_handle.cell(); }
  133. auto value() const { return *m_value; }
  134. bool is_null() const { return m_handle.is_null() && !m_value.has_value(); }
  135. bool operator==(Value const& value) const { return value == m_value; }
  136. bool operator==(Handle<Value> const& other) const { return other.m_value == this->m_value; }
  137. private:
  138. explicit Handle(Value value)
  139. : m_value(value)
  140. {
  141. }
  142. explicit Handle(Value value, Cell* cell, SourceLocation location)
  143. : m_value(value)
  144. , m_handle(Handle<Cell>::create(cell, location))
  145. {
  146. }
  147. Optional<Value> m_value;
  148. Handle<Cell> m_handle;
  149. };
  150. inline Handle<Value> make_handle(Value value, SourceLocation location = SourceLocation::current())
  151. {
  152. return Handle<Value>::create(value, location);
  153. }
  154. }
  155. namespace AK {
  156. template<typename T>
  157. struct Traits<JS::Handle<T>> : public DefaultTraits<JS::Handle<T>> {
  158. static unsigned hash(JS::Handle<T> const& handle) { return Traits<T>::hash(handle); }
  159. };
  160. template<>
  161. struct Traits<JS::Handle<JS::Value>> : public DefaultTraits<JS::Handle<JS::Value>> {
  162. static unsigned hash(JS::Handle<JS::Value> const& handle) { return Traits<JS::Value>::hash(handle.value()); }
  163. };
  164. namespace Detail {
  165. template<typename T>
  166. inline constexpr bool IsHashCompatible<JS::Handle<T>, T> = true;
  167. template<typename T>
  168. inline constexpr bool IsHashCompatible<T, JS::Handle<T>> = true;
  169. }
  170. }