#pragma once
#include "ElementTraversal.h"
#if ASSERT_ENABLED
#include "ElementIteratorAssertions.h"
#endif
namespace WebCore {
template <typename ElementType>
class ElementIterator : public std::iterator<std::forward_iterator_tag, ElementType> {
public:
ElementIterator() = default;
ElementType& operator*() const;
ElementType* operator->() const;
constexpr operator bool() const;
constexpr bool operator!() const;
constexpr bool operator!=(std::nullptr_t) const;
constexpr bool operator!=(const ElementIterator&) const;
ElementIterator& traverseNext();
ElementIterator& traversePrevious();
ElementIterator& traverseNextSibling();
ElementIterator& traversePreviousSibling();
ElementIterator& traverseNextSkippingChildren();
ElementIterator& traverseAncestor();
void dropAssertions();
protected:
ElementIterator(const ContainerNode* root, ElementType* current);
private:
const ContainerNode* m_root { nullptr };
ElementType* m_current { nullptr };
#if ASSERT_ENABLED
ElementIteratorAssertions m_assertions;
#endif
};
template <typename ElementType>
inline ElementIterator<ElementType>::ElementIterator(const ContainerNode* root, ElementType* current)
: m_root(root)
, m_current(current)
#if ASSERT_ENABLED
, m_assertions(current)
#endif
{
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseNext()
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = Traversal<ElementType>::next(*m_current, m_root);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traversePrevious()
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = Traversal<ElementType>::previous(*m_current, m_root);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseNextSibling()
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = Traversal<ElementType>::nextSibling(*m_current);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traversePreviousSibling()
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = Traversal<ElementType>::previousSibling(*m_current);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseNextSkippingChildren()
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = Traversal<ElementType>::nextSkippingChildren(*m_current, m_root);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline void ElementIterator<ElementType>::dropAssertions()
{
#if ASSERT_ENABLED
m_assertions.clear();
#endif
}
template <typename ElementType>
inline ElementType* findElementAncestorOfType(const Node& current)
{
for (Element* ancestor = current.parentElement(); ancestor; ancestor = ancestor->parentElement()) {
if (is<ElementType>(*ancestor))
return downcast<ElementType>(ancestor);
}
return nullptr;
}
template <>
inline Element* findElementAncestorOfType<Element>(const Node& current)
{
return current.parentElement();
}
template <typename ElementType>
inline ElementIterator<ElementType>& ElementIterator<ElementType>::traverseAncestor()
{
ASSERT(m_current);
ASSERT(m_current != m_root);
ASSERT(!m_assertions.domTreeHasMutated());
m_current = findElementAncestorOfType<ElementType>(*m_current);
#if ASSERT_ENABLED
if (!m_current)
m_assertions.dropEventDispatchAssertion();
#endif
return *this;
}
template <typename ElementType>
inline ElementType& ElementIterator<ElementType>::operator*() const
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
return *m_current;
}
template <typename ElementType>
inline ElementType* ElementIterator<ElementType>::operator->() const
{
ASSERT(m_current);
ASSERT(!m_assertions.domTreeHasMutated());
return m_current;
}
template<typename ElementType> constexpr ElementIterator<ElementType>::operator bool() const
{
return m_current;
}
template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!() const
{
return !m_current;
}
template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!=(std::nullptr_t) const
{
return m_current;
}
template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
{
ASSERT(m_root == other.m_root || !m_current || !other.m_current);
return m_current != other.m_current;
}
}
#include "ElementAncestorIterator.h"
#include "ElementChildIterator.h"
#include "TypedElementDescendantIterator.h"