| /* |
| * Copyright (C) 2013-2020 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "ElementIterator.h" |
| |
| namespace WebCore { |
| |
| template<typename> class DoubleElementDescendantIterator; |
| template<typename> class DoubleElementDescendantRange; |
| template<typename> class ElementDescendantRange; |
| template<typename ElementType, bool(const ElementType&)> class FilteredElementDescendantRange; |
| |
| // Range for iterating through descendant elements. |
| template<typename ElementType> ElementDescendantRange<ElementType> descendantsOfType(ContainerNode&); |
| template<typename ElementType> ElementDescendantRange<const ElementType> descendantsOfType(const ContainerNode&); |
| |
| // Range that skips elements where the filter returns false. |
| template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<const ElementType, filter> filteredDescendants(const ContainerNode&); |
| |
| // Range for use when both sets of descendants are known to be the same length. |
| // If they are different lengths, this will stop when the shorter one reaches the end, but also an assertion will fail. |
| template<typename ElementType> DoubleElementDescendantRange<ElementType> descendantsOfType(ContainerNode& firstRoot, ContainerNode& secondRoot); |
| |
| template<typename ElementType> class ElementDescendantIterator : public ElementIterator<ElementType> { |
| public: |
| ElementDescendantIterator() = default; |
| ElementDescendantIterator(const ContainerNode& root, ElementType* current); |
| ElementDescendantIterator& operator++(); |
| ElementDescendantIterator& operator--(); |
| }; |
| |
| template<typename ElementType> class ElementDescendantRange { |
| public: |
| ElementDescendantRange(const ContainerNode& root); |
| ElementDescendantIterator<ElementType> begin() const; |
| static constexpr std::nullptr_t end() { return nullptr; } |
| ElementDescendantIterator<ElementType> beginAt(ElementType&) const; |
| ElementDescendantIterator<ElementType> from(Element&) const; |
| |
| ElementType* first() const; |
| ElementType* last() const; |
| |
| private: |
| const ContainerNode& m_root; |
| }; |
| |
| template<typename ElementType> class InclusiveElementDescendantRange { |
| public: |
| InclusiveElementDescendantRange(const ContainerNode& root); |
| ElementDescendantIterator<ElementType> begin() const; |
| static constexpr std::nullptr_t end() { return nullptr; } |
| ElementDescendantIterator<ElementType> beginAt(ElementType&) const; |
| ElementDescendantIterator<ElementType> from(Element&) const; |
| |
| ElementType* first() const; |
| ElementType* last() const; |
| |
| private: |
| const ContainerNode& m_root; |
| }; |
| |
| template<typename ElementType> class DoubleElementDescendantRange { |
| public: |
| typedef ElementDescendantRange<ElementType> SingleAdapter; |
| typedef DoubleElementDescendantIterator<ElementType> Iterator; |
| |
| DoubleElementDescendantRange(SingleAdapter&&, SingleAdapter&&); |
| Iterator begin() const; |
| static constexpr std::nullptr_t end() { return nullptr; } |
| |
| private: |
| std::pair<SingleAdapter, SingleAdapter> m_pair; |
| }; |
| |
| template<typename ElementType> class DoubleElementDescendantIterator { |
| public: |
| typedef ElementDescendantIterator<ElementType> SingleIterator; |
| typedef std::pair<ElementType&, ElementType&> ReferenceProxy; |
| |
| DoubleElementDescendantIterator(SingleIterator&&, SingleIterator&&); |
| ReferenceProxy operator*() const; |
| constexpr bool operator!=(std::nullptr_t) const; |
| DoubleElementDescendantIterator& operator++(); |
| |
| private: |
| std::pair<SingleIterator, SingleIterator> m_pair; |
| }; |
| |
| template<typename ElementType, bool filter(const ElementType&)> class FilteredElementDescendantIterator : public ElementIterator<ElementType> { |
| public: |
| FilteredElementDescendantIterator(const ContainerNode&, ElementType* = nullptr); |
| FilteredElementDescendantIterator& operator++(); |
| }; |
| |
| template<typename ElementType, bool filter(const ElementType&)> class FilteredElementDescendantRange { |
| public: |
| using Iterator = FilteredElementDescendantIterator<ElementType, filter>; |
| |
| FilteredElementDescendantRange(const ContainerNode&); |
| Iterator begin() const; |
| static constexpr std::nullptr_t end() { return nullptr; } |
| |
| ElementType* first() const; |
| |
| private: |
| const ContainerNode& m_root; |
| }; |
| |
| // ElementDescendantIterator |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType>::ElementDescendantIterator(const ContainerNode& root, ElementType* current) |
| : ElementIterator<ElementType>(&root, current) |
| { |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType>& ElementDescendantIterator<ElementType>::operator++() |
| { |
| ElementIterator<ElementType>::traverseNext(); |
| return *this; |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType>& ElementDescendantIterator<ElementType>::operator--() |
| { |
| ElementIterator<ElementType>::traversePrevious(); |
| return *this; |
| } |
| |
| // ElementDescendantRange |
| |
| template<typename ElementType> ElementDescendantRange<ElementType>::ElementDescendantRange(const ContainerNode& root) |
| : m_root(root) |
| { |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::begin() const |
| { |
| return ElementDescendantIterator<ElementType>(m_root, Traversal<ElementType>::firstWithin(m_root)); |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::beginAt(ElementType& descendant) const |
| { |
| ASSERT(descendant.isDescendantOf(m_root)); |
| return ElementDescendantIterator<ElementType>(m_root, &descendant); |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::from(Element& descendant) const |
| { |
| ASSERT(descendant.isDescendantOf(m_root)); |
| if (auto descendantElement = dynamicDowncast<ElementType>(descendant)) |
| return ElementDescendantIterator<ElementType>(m_root, descendantElement); |
| ElementType* next = Traversal<ElementType>::next(descendant, &m_root); |
| return ElementDescendantIterator<ElementType>(m_root, next); |
| } |
| |
| template<typename ElementType> ElementType* ElementDescendantRange<ElementType>::first() const |
| { |
| return Traversal<ElementType>::firstWithin(m_root); |
| } |
| |
| template<typename ElementType> ElementType* ElementDescendantRange<ElementType>::last() const |
| { |
| return Traversal<ElementType>::lastWithin(m_root); |
| } |
| |
| // InclusiveElementDescendantRange |
| |
| template<typename ElementType> InclusiveElementDescendantRange<ElementType>::InclusiveElementDescendantRange(const ContainerNode& root) |
| : m_root(root) |
| { |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> InclusiveElementDescendantRange<ElementType>::begin() const |
| { |
| return ElementDescendantIterator<ElementType>(m_root, Traversal<ElementType>::inclusiveFirstWithin(const_cast<ContainerNode&>(m_root))); |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> InclusiveElementDescendantRange<ElementType>::beginAt(ElementType& descendant) const |
| { |
| ASSERT(&m_root == &descendant || descendant.isDescendantOf(m_root)); |
| return ElementDescendantIterator<ElementType>(m_root, &descendant); |
| } |
| |
| template<typename ElementType> ElementDescendantIterator<ElementType> InclusiveElementDescendantRange<ElementType>::from(Element& descendant) const |
| { |
| ASSERT(&m_root == &descendant || descendant.isDescendantOf(m_root)); |
| if (auto descendantElement = dynamicDowncast<ElementType>(descendant)) |
| return ElementDescendantIterator<ElementType>(m_root, descendantElement); |
| ElementType* next = Traversal<ElementType>::next(descendant, &m_root); |
| return ElementDescendantIterator<ElementType>(m_root, next); |
| } |
| |
| template<typename ElementType> ElementType* InclusiveElementDescendantRange<ElementType>::first() const |
| { |
| return Traversal<ElementType>::inclusiveFirstWithin(m_root); |
| } |
| |
| template<typename ElementType> ElementType* InclusiveElementDescendantRange<ElementType>::last() const |
| { |
| return Traversal<ElementType>::inclusiveLastWithin(m_root); |
| } |
| |
| // DoubleElementDescendantRange |
| |
| template<typename ElementType> DoubleElementDescendantRange<ElementType>::DoubleElementDescendantRange(SingleAdapter&& first, SingleAdapter&& second) |
| : m_pair(WTFMove(first), WTFMove(second)) |
| { |
| } |
| |
| template<typename ElementType> auto DoubleElementDescendantRange<ElementType>::begin() const -> Iterator |
| { |
| return Iterator(m_pair.first.begin(), m_pair.second.begin()); |
| } |
| |
| // DoubleElementDescendantIterator |
| |
| template<typename ElementType> DoubleElementDescendantIterator<ElementType>::DoubleElementDescendantIterator(SingleIterator&& first, SingleIterator&& second) |
| : m_pair(WTFMove(first), WTFMove(second)) |
| { |
| } |
| |
| template<typename ElementType> auto DoubleElementDescendantIterator<ElementType>::operator*() const -> ReferenceProxy |
| { |
| return { *m_pair.first, *m_pair.second }; |
| } |
| |
| template<typename ElementType> constexpr bool DoubleElementDescendantIterator<ElementType>::operator!=(std::nullptr_t) const |
| { |
| ASSERT(!m_pair.first == !m_pair.second); |
| return m_pair.first; |
| } |
| |
| template<typename ElementType> DoubleElementDescendantIterator<ElementType>& DoubleElementDescendantIterator<ElementType>::operator++() |
| { |
| ++m_pair.first; |
| ++m_pair.second; |
| return *this; |
| } |
| |
| // FilteredElementDescendantIterator |
| |
| template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantIterator<ElementType, filter>::FilteredElementDescendantIterator(const ContainerNode& root, ElementType* element) |
| : ElementIterator<const ElementType> { &root, element } |
| { |
| } |
| |
| template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantIterator<ElementType, filter>& FilteredElementDescendantIterator<ElementType, filter>::operator++() |
| { |
| do { |
| ElementIterator<ElementType>::traverseNext(); |
| } while (*this && !filter(**this)); |
| return *this; |
| } |
| |
| // FilteredElementDescendantRange |
| |
| template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<ElementType, filter>::FilteredElementDescendantRange(const ContainerNode& root) |
| : m_root { root } |
| { |
| } |
| |
| template<typename ElementType, bool filter(const ElementType&)> auto FilteredElementDescendantRange<ElementType, filter>::begin() const -> Iterator |
| { |
| return { m_root, first() }; |
| } |
| |
| template<typename ElementType, bool filter(const ElementType&)> ElementType* FilteredElementDescendantRange<ElementType, filter>::first() const |
| { |
| for (auto* element = Traversal<ElementType>::firstWithin(m_root); element; element = Traversal<ElementType>::next(*element, &m_root)) { |
| if (filter(*element)) |
| return element; |
| } |
| return nullptr; |
| } |
| |
| // Standalone functions |
| |
| template<typename ElementType> ElementDescendantRange<ElementType> descendantsOfType(ContainerNode& root) |
| { |
| return ElementDescendantRange<ElementType>(root); |
| } |
| |
| template<typename ElementType> InclusiveElementDescendantRange<ElementType> inclusiveDescendantsOfType(ContainerNode& root) |
| { |
| return InclusiveElementDescendantRange<ElementType>(root); |
| } |
| |
| template<typename ElementType> ElementDescendantRange<const ElementType> descendantsOfType(const ContainerNode& root) |
| { |
| return ElementDescendantRange<const ElementType>(root); |
| } |
| |
| template<typename ElementType> DoubleElementDescendantRange<ElementType> descendantsOfType(ContainerNode& firstRoot, ContainerNode& secondRoot) |
| { |
| return { descendantsOfType<ElementType>(firstRoot), descendantsOfType<ElementType>(secondRoot) }; |
| } |
| |
| template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<const ElementType, filter> filteredDescendants(const ContainerNode& root) |
| { |
| return { root }; |
| } |
| |
| } // namespace WebCore |