Refine the DOM element iterator implementation
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 23 Feb 2020 07:16:50 +0000 (07:16 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 23 Feb 2020 07:16:50 +0000 (07:16 +0000)
https://bugs.webkit.org/show_bug.cgi?id=208100

Reviewed by Antti Koivisto.

- Removed the duplicate descendant iterator, keeping the one that matches
  the style of the ancestor and child iterators.
- Removed the non-template elementAncestors, elementChildren, elementDescendants,
  and elementLineage functions and changed callers to use xxxOfType<Element> instead.
- Renamed "IteratorAdapter" templates to "Range", choosing that term to match the
  upcoming C++20 Ranges library and range-based for loops.
- Changed the iterators to use an actual "nullptr" for end, following the "sentinel"
  design pattern from the Ranges library. Still kept a tiny bit of using an iterator
  for end around, only so we can use iterator library functions like std::distance
  while waiting for std::ranges::distance, which is compatible with sentinels.
- Implemented const correctness by using const types instead of separate "Const"
  class templates. This cut down on source code size a lot. These element iterators
  don't need whole separate templates to implement the const correctness the way
  collection classes like HashMap do.
- Improved some other details, like using more const and constexpr on members.
  All the functions on a range are const, because the range itself doesn't ever
  get modified, and all functions on an iterator are also const, because only
  operations like ++ and -- actually modify the iterator.
- For now at least, removed extra code we don't need in practice. We never need to
  compare iterators to each other except when iterating a range, for example, so
  kept the != used for range iteration but not ==.
- Simplified the HTMLCollection implementations by taking advantage of the null-
  based and sentinel designs. There are various places where we can write
  simpler code and pass around fewer arguments.
- Added a new descendantsOfType template that takes a predicate and filters to only
  the elements that match that predicate. Similar concept to how we implement HTML
  collections, and possibly could be used even more eventually.
- Use std::iterator in ElementIterator so we don't need to do that in derived
  classes. Also made more of ElementIterator protected to make it more explicit
  that it's an abstract class template and not something to be used directly.

The most unusual clients of the elmeent ranges and iterators are HTMLCollection and
the related caches, and this patch includes changes to those to adopt the new model.

* Headers.cmake: Removed ElementDescendantIterator.h.
* WebCore.xcodeproj/project.pbxproj: Ditto.

* dom/ChildNodeList.cpp:
(WebCore::ChildNodeList::ChildNodeList): Removed initialization of m_indexCache
since the constructor no longer requires arguments.
(WebCore::ChildNodeList::invalidateCache): Removed argument to
CollectionIndexCache::invalidate.
* dom/ChildNodeList.h: Removed collectionEnd, since it's no longer needed.

* dom/CollectionIndexCache.h: Removed the collection argument to the
constructor, hasValidCache, and invalidate functions. Updated algorithms to use
null style termination instead of actually relying on comparing with an end
iterator, since that works for our element iterators.

* dom/ContainerNode.cpp:
(WebCore::ContainerNode::childElementCount const):: Use an empty initializer
list instead of the result of the end function since std::distance requires
both begin and end iterators have the same type.

* dom/ElementAncestorIterator.h: Made the changes mentioned above, plus moved the
declarations of functions to the top of the file, since the classes are
implementation details, used downcast instead of static_cast.

* dom/ElementAndTextDescendantIterator.h: Renamed IteratorAdapter to Range,
mostly didn't make other changes since this is not one of the element iterators.

* dom/ElementChildIterator.h: Made the changes mentioned above, plus moved the
declarations of functions to the top of the file, since the classes are
implementation details.

* dom/ElementDescendantIterator.h: Removed.

* dom/ElementIterator.h: Made the changes mentioned above.

* dom/LiveNodeList.cpp: Removed some unneeded includes, including HTMLCollection.h.
(WebCore::LiveNodeList::LiveNodeList): Simplified a little bit.
(WebCore::LiveNodeList::rootNode): Moved to the header.

* dom/LiveNodeList.h: Updated since CollectionTraversal now uses the
more modern ElementDescendantIterator, not the older one that used a vector of
ancestors to do the iteration. Also use WTF_MAKE_ISO_NONALLOCATABLE since
LiveNodeList is an abstract class, and made some members protected. Removed
CachedLiveNodeList::rootNode since it was identical to LiveNodeList::rootNode,
and made LiveNodeList::rootNode protected so it can be called in
CachedLiveNodeList, and moved it to the header so it will still be inlined.
Simplified CachedListNodeList to use more final, to name long types less by
using "auto" and "using", and to not pass arguments to functions that don't
need them any more.

* dom/NameNodeList.cpp:
(WebCore::NameNodeList::create): Moved here from the header.
* dom/NameNodeList.h: Removed unneeded includes and comment, moved create
function out of the header.

* dom/TypedElementDescendantIterator.h: Made all the change mentioned above.
Also added a new filteredDescendants function, range, and iterator that uses
a filter function. Not used yet in this patch; use comes in a future one.

* html/CachedHTMLCollection.h: Updated includes, shortened type names,
and used auto to simplify the code a bit. Removed unneeded collection arguments
from various CollectionIndexCache functions.

* html/CollectionTraversal.h: Updated to use the new/typed version of
ElementDescendantIterator. Removed end functions. Use shorter type names.
Tweaked algorithms to use null termination for loops instead of end iterators.

* html/HTMLFormControlsCollection.h:
(WebCore::HTMLFormControlsCollection::item const): Removed unneeded class
template arguments.

* html/HTMLFormElement.cpp:
(WebCore::HTMLFormElement::formElementIndex): Changed to use the null check
instead of comparing iterator with end.
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::selectNextSourceChild): Ditto.

* html/HTMLTableSectionElement.cpp:
(WebCore::HTMLTableSectionElement::numRows const): Pass a default-constructed
iterator for end to std::distance. When we get C++20 we can clean this up by
using std::ranges::distances instead.

* html/LabelsNodeList.cpp:
(WebCore::LabelsNodeList::create): Moved here from the header.
* html/LabelsNodeList.h: Removed unneeded include, tweaked coding style a bit,
moved create function into the .cpp file.

* html/RadioNodeList.cpp: Removed unneeded include.
(WebCore::RadioNodeList::create): Moved this here from the header.
(WebCore::nonEmptyRadioButton): Renamed from toRadioButtonInputElement to make
a little clearer what the function does.
(WebCore::RadioNodeList::value const): Updated to use nonEmptyRadioButton and
straighten out the loop a tiny bit.
(WebCore::RadioNodeList::setValue): Ditto.
(WebCore::RadioNodeList::checkElementMatchesRadioNodeListFilter const): Deleted.
(WebCore::RadioNodeList::elementMatches const): Merged in the logic from
checkElementMatchesRadioNodeListFilter, since the separate function wasn't helpful.

* html/RadioNodeList.h: Removed unneeded includes. Moved the create function out
of the header. Removed unneeded override of the item function to tighten the
return type; not used in WebCore and not helpful for bindings. Made more private.

* style/StyleInvalidator.cpp:
(WebCore::Style::Invalidator::invalidateStyleForDescendants): Use null checking
style for the loop rather than comparing with end.
(WebCore::Style::Invalidator::invalidateStyleWithMatchElement): Remove an unneeded
local variable and braces.

* svg/SVGUseElement.cpp:
(WebCore::removeDisallowedElementsFromSubtree): Use null checking style rather than
comparing with end.
(WebCore::SVGUseElement::expandUseElementsInShadowTree const): Ditto. Also use
dropAssertions rather than assigning to end with a comment saying it drops assertions.
(WebCore::SVGUseElement::expandSymbolElementsInShadowTree const): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@257192 268f45cc-cd09-0410-ab3c-d52691b4dbfc

29 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Headers.cmake
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/dom/ChildNodeList.cpp
Source/WebCore/dom/ChildNodeList.h
Source/WebCore/dom/CollectionIndexCache.h
Source/WebCore/dom/ContainerNode.cpp
Source/WebCore/dom/ElementAncestorIterator.h
Source/WebCore/dom/ElementAndTextDescendantIterator.h
Source/WebCore/dom/ElementChildIterator.h
Source/WebCore/dom/ElementDescendantIterator.h [deleted file]
Source/WebCore/dom/ElementIterator.h
Source/WebCore/dom/LiveNodeList.cpp
Source/WebCore/dom/LiveNodeList.h
Source/WebCore/dom/NameNodeList.cpp
Source/WebCore/dom/NameNodeList.h
Source/WebCore/dom/TypedElementDescendantIterator.h
Source/WebCore/html/CachedHTMLCollection.h
Source/WebCore/html/CollectionTraversal.h
Source/WebCore/html/HTMLFormControlsCollection.h
Source/WebCore/html/HTMLFormElement.cpp
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLTableSectionElement.cpp
Source/WebCore/html/LabelsNodeList.cpp
Source/WebCore/html/LabelsNodeList.h
Source/WebCore/html/RadioNodeList.cpp
Source/WebCore/html/RadioNodeList.h
Source/WebCore/style/StyleInvalidator.cpp
Source/WebCore/svg/SVGUseElement.cpp

index 8c011fd..a114e49 100644 (file)
@@ -1,5 +1,161 @@
 2020-02-22  Darin Adler  <darin@apple.com>
 
+        Refine the DOM element iterator implementation
+        https://bugs.webkit.org/show_bug.cgi?id=208100
+
+        Reviewed by Antti Koivisto.
+
+        - Removed the duplicate descendant iterator, keeping the one that matches
+          the style of the ancestor and child iterators.
+        - Removed the non-template elementAncestors, elementChildren, elementDescendants,
+          and elementLineage functions and changed callers to use xxxOfType<Element> instead.
+        - Renamed "IteratorAdapter" templates to "Range", choosing that term to match the
+          upcoming C++20 Ranges library and range-based for loops.
+        - Changed the iterators to use an actual "nullptr" for end, following the "sentinel"
+          design pattern from the Ranges library. Still kept a tiny bit of using an iterator
+          for end around, only so we can use iterator library functions like std::distance
+          while waiting for std::ranges::distance, which is compatible with sentinels.
+        - Implemented const correctness by using const types instead of separate "Const"
+          class templates. This cut down on source code size a lot. These element iterators
+          don't need whole separate templates to implement the const correctness the way
+          collection classes like HashMap do.
+        - Improved some other details, like using more const and constexpr on members.
+          All the functions on a range are const, because the range itself doesn't ever
+          get modified, and all functions on an iterator are also const, because only
+          operations like ++ and -- actually modify the iterator.
+        - For now at least, removed extra code we don't need in practice. We never need to
+          compare iterators to each other except when iterating a range, for example, so
+          kept the != used for range iteration but not ==.
+        - Simplified the HTMLCollection implementations by taking advantage of the null-
+          based and sentinel designs. There are various places where we can write
+          simpler code and pass around fewer arguments.
+        - Added a new descendantsOfType template that takes a predicate and filters to only
+          the elements that match that predicate. Similar concept to how we implement HTML
+          collections, and possibly could be used even more eventually.
+        - Use std::iterator in ElementIterator so we don't need to do that in derived
+          classes. Also made more of ElementIterator protected to make it more explicit
+          that it's an abstract class template and not something to be used directly.
+
+        The most unusual clients of the elmeent ranges and iterators are HTMLCollection and
+        the related caches, and this patch includes changes to those to adopt the new model.
+
+        * Headers.cmake: Removed ElementDescendantIterator.h.
+        * WebCore.xcodeproj/project.pbxproj: Ditto.
+
+        * dom/ChildNodeList.cpp:
+        (WebCore::ChildNodeList::ChildNodeList): Removed initialization of m_indexCache
+        since the constructor no longer requires arguments.
+        (WebCore::ChildNodeList::invalidateCache): Removed argument to
+        CollectionIndexCache::invalidate.
+        * dom/ChildNodeList.h: Removed collectionEnd, since it's no longer needed.
+
+        * dom/CollectionIndexCache.h: Removed the collection argument to the
+        constructor, hasValidCache, and invalidate functions. Updated algorithms to use
+        null style termination instead of actually relying on comparing with an end
+        iterator, since that works for our element iterators.
+
+        * dom/ContainerNode.cpp:
+        (WebCore::ContainerNode::childElementCount const):: Use an empty initializer
+        list instead of the result of the end function since std::distance requires
+        both begin and end iterators have the same type.
+
+        * dom/ElementAncestorIterator.h: Made the changes mentioned above, plus moved the
+        declarations of functions to the top of the file, since the classes are
+        implementation details, used downcast instead of static_cast.
+
+        * dom/ElementAndTextDescendantIterator.h: Renamed IteratorAdapter to Range,
+        mostly didn't make other changes since this is not one of the element iterators.
+
+        * dom/ElementChildIterator.h: Made the changes mentioned above, plus moved the
+        declarations of functions to the top of the file, since the classes are
+        implementation details.
+
+        * dom/ElementDescendantIterator.h: Removed.
+
+        * dom/ElementIterator.h: Made the changes mentioned above.
+
+        * dom/LiveNodeList.cpp: Removed some unneeded includes, including HTMLCollection.h.
+        (WebCore::LiveNodeList::LiveNodeList): Simplified a little bit.
+        (WebCore::LiveNodeList::rootNode): Moved to the header.
+
+        * dom/LiveNodeList.h: Updated since CollectionTraversal now uses the
+        more modern ElementDescendantIterator, not the older one that used a vector of
+        ancestors to do the iteration. Also use WTF_MAKE_ISO_NONALLOCATABLE since
+        LiveNodeList is an abstract class, and made some members protected. Removed
+        CachedLiveNodeList::rootNode since it was identical to LiveNodeList::rootNode,
+        and made LiveNodeList::rootNode protected so it can be called in
+        CachedLiveNodeList, and moved it to the header so it will still be inlined.
+        Simplified CachedListNodeList to use more final, to name long types less by
+        using "auto" and "using", and to not pass arguments to functions that don't
+        need them any more.
+
+        * dom/NameNodeList.cpp:
+        (WebCore::NameNodeList::create): Moved here from the header.
+        * dom/NameNodeList.h: Removed unneeded includes and comment, moved create
+        function out of the header.
+
+        * dom/TypedElementDescendantIterator.h: Made all the change mentioned above.
+        Also added a new filteredDescendants function, range, and iterator that uses
+        a filter function. Not used yet in this patch; use comes in a future one.
+
+        * html/CachedHTMLCollection.h: Updated includes, shortened type names,
+        and used auto to simplify the code a bit. Removed unneeded collection arguments
+        from various CollectionIndexCache functions.
+
+        * html/CollectionTraversal.h: Updated to use the new/typed version of
+        ElementDescendantIterator. Removed end functions. Use shorter type names.
+        Tweaked algorithms to use null termination for loops instead of end iterators.
+
+        * html/HTMLFormControlsCollection.h:
+        (WebCore::HTMLFormControlsCollection::item const): Removed unneeded class
+        template arguments.
+
+        * html/HTMLFormElement.cpp:
+        (WebCore::HTMLFormElement::formElementIndex): Changed to use the null check
+        instead of comparing iterator with end.
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::selectNextSourceChild): Ditto.
+
+        * html/HTMLTableSectionElement.cpp:
+        (WebCore::HTMLTableSectionElement::numRows const): Pass a default-constructed
+        iterator for end to std::distance. When we get C++20 we can clean this up by
+        using std::ranges::distances instead.
+
+        * html/LabelsNodeList.cpp:
+        (WebCore::LabelsNodeList::create): Moved here from the header.
+        * html/LabelsNodeList.h: Removed unneeded include, tweaked coding style a bit,
+        moved create function into the .cpp file.
+
+        * html/RadioNodeList.cpp: Removed unneeded include.
+        (WebCore::RadioNodeList::create): Moved this here from the header.
+        (WebCore::nonEmptyRadioButton): Renamed from toRadioButtonInputElement to make
+        a little clearer what the function does.
+        (WebCore::RadioNodeList::value const): Updated to use nonEmptyRadioButton and
+        straighten out the loop a tiny bit.
+        (WebCore::RadioNodeList::setValue): Ditto.
+        (WebCore::RadioNodeList::checkElementMatchesRadioNodeListFilter const): Deleted.
+        (WebCore::RadioNodeList::elementMatches const): Merged in the logic from
+        checkElementMatchesRadioNodeListFilter, since the separate function wasn't helpful.
+
+        * html/RadioNodeList.h: Removed unneeded includes. Moved the create function out
+        of the header. Removed unneeded override of the item function to tighten the
+        return type; not used in WebCore and not helpful for bindings. Made more private.
+
+        * style/StyleInvalidator.cpp:
+        (WebCore::Style::Invalidator::invalidateStyleForDescendants): Use null checking
+        style for the loop rather than comparing with end.
+        (WebCore::Style::Invalidator::invalidateStyleWithMatchElement): Remove an unneeded
+        local variable and braces.
+
+        * svg/SVGUseElement.cpp:
+        (WebCore::removeDisallowedElementsFromSubtree): Use null checking style rather than
+        comparing with end.
+        (WebCore::SVGUseElement::expandUseElementsInShadowTree const): Ditto. Also use
+        dropAssertions rather than assigning to end with a comment saying it drops assertions.
+        (WebCore::SVGUseElement::expandSymbolElementsInShadowTree const): Ditto.
+
+2020-02-22  Darin Adler  <darin@apple.com>
+
         Put more of the datalist element implementation inside ENABLE(DATALIST_ELEMENT)
         https://bugs.webkit.org/show_bug.cgi?id=208098
 
index ad4f71d..533748c 100644 (file)
@@ -390,7 +390,6 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
     dom/ElementChildIterator.h
     dom/ElementContext.h
     dom/ElementData.h
-    dom/ElementDescendantIterator.h
     dom/ElementIdentifier.h
     dom/ElementIterator.h
     dom/ElementIteratorAssertions.h
index 8112f83..ddba948 100644 (file)
                93D196331D6CAB8200FC7E47 /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D196321D6CAB8200FC7E47 /* Exception.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93D4379F1D57B15300AB85EA /* JSExecState.h in Headers */ = {isa = PBXBuildFile; fileRef = 8F934D831189F1EE00508D5D /* JSExecState.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93D437A01D57B19A00AB85EA /* CustomElementReactionQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B56C9A81C89312800C456DF /* CustomElementReactionQueue.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               93D437A11D57B3F400AB85EA /* ElementDescendantIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = ADE11F4A18D8311B0078983B /* ElementDescendantIterator.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93D437A21D57B3FE00AB85EA /* URLUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 656B9DCA189DE10000BB842C /* URLUtils.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93D437A31D57B7E200AB85EA /* JSMediaListCustom.h in Headers */ = {isa = PBXBuildFile; fileRef = AD726FE716D9F204003A4E6D /* JSMediaListCustom.h */; settings = {ATTRIBUTES = (Private, ); }; };
                93D9D53C0DA27E180077216C /* RangeBoundaryPoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 93D9D53B0DA27E180077216C /* RangeBoundaryPoint.h */; settings = {ATTRIBUTES = (Private, ); }; };
                ADDA94BF19686F8000453029 /* JSDocumentCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDocumentCustom.h; sourceTree = "<group>"; };
                ADDF1AD41257CD9A0003A759 /* RenderSVGPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGPath.cpp; sourceTree = "<group>"; };
                ADDF1AD51257CD9A0003A759 /* RenderSVGPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGPath.h; sourceTree = "<group>"; };
-               ADE11F4A18D8311B0078983B /* ElementDescendantIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementDescendantIterator.h; sourceTree = "<group>"; };
                ADE16736181050C300463A2E /* RenderPtr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderPtr.h; sourceTree = "<group>"; };
                ADEC78F718EE5308001315C2 /* JSElementCustom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSElementCustom.h; sourceTree = "<group>"; };
                ADFE2B541BD5F41200DAB457 /* ResourceUsageOverlayCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ResourceUsageOverlayCocoa.mm; sourceTree = "<group>"; };
                                313BCE1B235E3BDB00FC39E5 /* ElementContext.h */,
                                B5B7A16F17C1080600E4AA0A /* ElementData.cpp */,
                                B5B7A16E17C1048000E4AA0A /* ElementData.h */,
-                               ADE11F4A18D8311B0078983B /* ElementDescendantIterator.h */,
                                2D2BEB2F2234A334005544CA /* ElementIdentifier.h */,
                                E4AE7C1517D1BB950009FB31 /* ElementIterator.h */,
                                E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */,
                                E46A2B1E17CA76B1000DBCD8 /* ElementChildIterator.h in Headers */,
                                313BCE1C235E3BE500FC39E5 /* ElementContext.h in Headers */,
                                B5B7A17117C10AC000E4AA0A /* ElementData.h in Headers */,
-                               93D437A11D57B3F400AB85EA /* ElementDescendantIterator.h in Headers */,
                                2D2BEB312234A335005544CA /* ElementIdentifier.h in Headers */,
                                E4AE7C1617D1BB950009FB31 /* ElementIterator.h in Headers */,
                                E401C27517CE53EC00C41A35 /* ElementIteratorAssertions.h in Headers */,
index cbf6f1e..47e46dc 100644 (file)
@@ -39,7 +39,6 @@ EmptyNodeList::~EmptyNodeList()
 
 ChildNodeList::ChildNodeList(ContainerNode& parent)
     : m_parent(parent)
-    , m_indexCache(*this)
 {
 }
 
@@ -87,7 +86,7 @@ void ChildNodeList::collectionTraverseBackward(Node*& current, unsigned count) c
 
 void ChildNodeList::invalidateCache()
 {
-    m_indexCache.invalidate(*this);
+    m_indexCache.invalidate();
 }
 
 } // namespace WebCore
index 113282e..10b9a28 100644 (file)
@@ -72,7 +72,6 @@ public:
     // For CollectionIndexCache
     Node* collectionBegin() const;
     Node* collectionLast() const;
-    Node* collectionEnd() const { return nullptr; }
     void collectionTraverseForward(Node*&, unsigned count, unsigned& traversedCount) const;
     void collectionTraverseBackward(Node*&, unsigned count) const;
     bool collectionCanTraverseBackward() const { return true; }
index 2801942..3f81b23 100644 (file)
@@ -34,15 +34,15 @@ WEBCORE_EXPORT void reportExtraMemoryAllocatedForCollectionIndexCache(size_t);
 template <class Collection, class Iterator>
 class CollectionIndexCache {
 public:
-    explicit CollectionIndexCache(const Collection&);
+    CollectionIndexCache();
 
     typedef typename std::iterator_traits<Iterator>::value_type NodeType;
 
     unsigned nodeCount(const Collection&);
     NodeType* nodeAt(const Collection&, unsigned index);
 
-    bool hasValidCache(const Collection& collection) const { return m_current != collection.collectionEnd() || m_nodeCountValid || m_listValid; }
-    void invalidate(const Collection&);
+    bool hasValidCache() const { return m_current || m_nodeCountValid || m_listValid; }
+    void invalidate();
     size_t memoryCost()
     {
         // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful
@@ -56,20 +56,16 @@ private:
     NodeType* traverseBackwardTo(const Collection&, unsigned);
     NodeType* traverseForwardTo(const Collection&, unsigned);
 
-    Iterator m_current;
-    unsigned m_currentIndex;
-    unsigned m_nodeCount;
+    Iterator m_current { };
+    unsigned m_currentIndex { 0 };
+    unsigned m_nodeCount { 0 };
     Vector<NodeType*> m_cachedList;
     bool m_nodeCountValid : 1;
     bool m_listValid : 1;
 };
 
-template <class Collection, class Iterator>
-inline CollectionIndexCache<Collection, Iterator>::CollectionIndexCache(const Collection& collection)
-    : m_current(collection.collectionEnd())
-    , m_currentIndex(0)
-    , m_nodeCount(0)
-    , m_nodeCountValid(false)
+template<class Collection, class Iterator> CollectionIndexCache<Collection, Iterator>::CollectionIndexCache()
+    : m_nodeCountValid(false)
     , m_listValid(false)
 {
 }
@@ -78,7 +74,7 @@ template <class Collection, class Iterator>
 inline unsigned CollectionIndexCache<Collection, Iterator>::nodeCount(const Collection& collection)
 {
     if (!m_nodeCountValid) {
-        if (!hasValidCache(collection))
+        if (!hasValidCache())
             collection.willValidateIndexCache();
         m_nodeCount = computeNodeCountUpdatingListCache(collection);
         m_nodeCountValid = true;
@@ -91,16 +87,15 @@ template <class Collection, class Iterator>
 unsigned CollectionIndexCache<Collection, Iterator>::computeNodeCountUpdatingListCache(const Collection& collection)
 {
     auto current = collection.collectionBegin();
-    auto end = collection.collectionEnd();
-    if (current == end)
+    if (!current)
         return 0;
 
     unsigned oldCapacity = m_cachedList.capacity();
-    while (current != end) {
+    while (current) {
         m_cachedList.append(&*current);
         unsigned traversed;
         collection.collectionTraverseForward(current, 1, traversed);
-        ASSERT(traversed == (current != end ? 1 : 0));
+        ASSERT(traversed == (current ? 1 : 0));
     }
     m_listValid = true;
 
@@ -113,7 +108,7 @@ unsigned CollectionIndexCache<Collection, Iterator>::computeNodeCountUpdatingLis
 template <class Collection, class Iterator>
 inline typename CollectionIndexCache<Collection, Iterator>::NodeType* CollectionIndexCache<Collection, Iterator>::traverseBackwardTo(const Collection& collection, unsigned index)
 {
-    ASSERT(m_current != collection.collectionEnd());
+    ASSERT(m_current);
     ASSERT(index < m_currentIndex);
 
     bool firstIsCloser = index < m_currentIndex - index;
@@ -122,50 +117,50 @@ inline typename CollectionIndexCache<Collection, Iterator>::NodeType* Collection
         m_currentIndex = 0;
         if (index)
             collection.collectionTraverseForward(m_current, index, m_currentIndex);
-        ASSERT(m_current != collection.collectionEnd());
+        ASSERT(m_current);
         return &*m_current;
     }
 
     collection.collectionTraverseBackward(m_current, m_currentIndex - index);
     m_currentIndex = index;
 
-    ASSERT(m_current != collection.collectionEnd());
+    ASSERT(m_current);
     return &*m_current;
 }
 
 template <class Collection, class Iterator>
 inline typename CollectionIndexCache<Collection, Iterator>::NodeType* CollectionIndexCache<Collection, Iterator>::traverseForwardTo(const Collection& collection, unsigned index)
 {
-    ASSERT(m_current != collection.collectionEnd());
+    ASSERT(m_current);
     ASSERT(index > m_currentIndex);
     ASSERT(!m_nodeCountValid || index < m_nodeCount);
 
     bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index - m_currentIndex;
     if (lastIsCloser && collection.collectionCanTraverseBackward()) {
-        ASSERT(hasValidCache(collection));
+        ASSERT(hasValidCache());
         m_current = collection.collectionLast();
         if (index < m_nodeCount - 1)
             collection.collectionTraverseBackward(m_current, m_nodeCount - index - 1);
         m_currentIndex = index;
-        ASSERT(m_current != collection.collectionEnd());
+        ASSERT(m_current);
         return &*m_current;
     }
 
-    if (!hasValidCache(collection))
+    if (!hasValidCache())
         collection.willValidateIndexCache();
 
     unsigned traversedCount;
     collection.collectionTraverseForward(m_current, index - m_currentIndex, traversedCount);
     m_currentIndex = m_currentIndex + traversedCount;
 
-    if (m_current == collection.collectionEnd()) {
+    if (!m_current) {
         ASSERT(m_currentIndex < index);
         // Failed to find the index but at least we now know the size.
         m_nodeCount = m_currentIndex + 1;
         m_nodeCountValid = true;
         return nullptr;
     }
-    ASSERT(hasValidCache(collection));
+    ASSERT(hasValidCache());
     return &*m_current;
 }
 
@@ -178,8 +173,7 @@ inline typename CollectionIndexCache<Collection, Iterator>::NodeType* Collection
     if (m_listValid)
         return m_cachedList[index];
 
-    auto end = collection.collectionEnd();
-    if (m_current != end) {
+    if (m_current) {
         if (index > m_currentIndex)
             return traverseForwardTo(collection, index);
         if (index < m_currentIndex)
@@ -189,39 +183,39 @@ inline typename CollectionIndexCache<Collection, Iterator>::NodeType* Collection
 
     bool lastIsCloser = m_nodeCountValid && m_nodeCount - index < index;
     if (lastIsCloser && collection.collectionCanTraverseBackward()) {
-        ASSERT(hasValidCache(collection));
+        ASSERT(hasValidCache());
         m_current = collection.collectionLast();
         if (index < m_nodeCount - 1)
             collection.collectionTraverseBackward(m_current, m_nodeCount - index - 1);
         m_currentIndex = index;
-        ASSERT(m_current != end);
+        ASSERT(m_current);
         return &*m_current;
     }
 
-    if (!hasValidCache(collection))
+    if (!hasValidCache())
         collection.willValidateIndexCache();
 
     m_current = collection.collectionBegin();
     m_currentIndex = 0;
-    bool startIsEnd = m_current == end;
-    if (index && !startIsEnd) {
+    bool startIsEnd = !m_current;
+    if (index && m_current) {
         collection.collectionTraverseForward(m_current, index, m_currentIndex);
-        ASSERT(m_current != end || m_currentIndex < index);
+        ASSERT(m_current || m_currentIndex < index);
     }
-    if (m_current == end) {
+    if (!m_current) {
         // Failed to find the index but at least we now know the size.
         m_nodeCount = startIsEnd ? 0 : m_currentIndex + 1;
         m_nodeCountValid = true;
         return nullptr;
     }
-    ASSERT(hasValidCache(collection));
+    ASSERT(hasValidCache());
     return &*m_current;
 }
 
 template <class Collection, class Iterator>
-void CollectionIndexCache<Collection, Iterator>::invalidate(const Collection& collection)
+void CollectionIndexCache<Collection, Iterator>::invalidate()
 {
-    m_current = collection.collectionEnd();
+    m_current = { };
     m_nodeCountValid = false;
     m_listValid = false;
     m_cachedList.shrink(0);
index 7ae1382..8d4ef96 100644 (file)
@@ -923,7 +923,7 @@ Element* ContainerNode::lastElementChild() const
 unsigned ContainerNode::childElementCount() const
 {
     auto children = childrenOfType<Element>(*this);
-    return std::distance(children.begin(), children.end());
+    return std::distance(children.begin(), { });
 }
 
 ExceptionOr<void> ContainerNode::append(Vector<NodeOrString>&& vector)
index 4b62d38..c99c766 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
 
 namespace WebCore {
 
-template <typename ElementType>
-class ElementAncestorIterator : public ElementIterator<ElementType> {
-public:
-    ElementAncestorIterator();
-    explicit ElementAncestorIterator(ElementType* current);
-    ElementAncestorIterator& operator++();
-};
+template<typename> class ElementAncestorRange;
 
-template <typename ElementType>
-class ElementAncestorConstIterator : public ElementConstIterator<ElementType> {
-public:
-    ElementAncestorConstIterator();
-    explicit ElementAncestorConstIterator(const ElementType* current);
-    ElementAncestorConstIterator& operator++();
-};
+// Range for iterating an element and its ancestors.
+template<typename ElementType> ElementAncestorRange<ElementType> lineageOfType(Element& first);
+template<typename ElementType> ElementAncestorRange<const ElementType> lineageOfType(const Element& first);
+
+// Range for iterating a node's element ancestors.
+template<typename ElementType> ElementAncestorRange<ElementType> ancestorsOfType(Node& descendant);
+template<typename ElementType> ElementAncestorRange<const ElementType> ancestorsOfType(const Node& descendant);
 
 template <typename ElementType>
-class ElementAncestorIteratorAdapter {
+class ElementAncestorIterator : public ElementIterator<ElementType> {
 public:
-    explicit ElementAncestorIteratorAdapter(ElementType* first);
-    ElementAncestorIterator<ElementType> begin();
-    ElementAncestorIterator<ElementType> end();
-    ElementType* first() { return m_first; }
-
-private:
-    ElementType* m_first;
+    explicit ElementAncestorIterator(ElementType* = nullptr);
+    ElementAncestorIterator& operator++();
 };
 
 template <typename ElementType>
-class ElementAncestorConstIteratorAdapter {
+class ElementAncestorRange {
 public:
-    explicit ElementAncestorConstIteratorAdapter(const ElementType* first);
-    ElementAncestorConstIterator<ElementType> begin() const;
-    ElementAncestorConstIterator<ElementType> end() const;
-    const ElementType* first() const { return m_first; }
+    explicit ElementAncestorRange(ElementType* first);
+    ElementAncestorIterator<ElementType> begin() const;
+    static constexpr std::nullptr_t end() { return nullptr; }
+    ElementType* first() const { return m_first; }
 
 private:
-    const ElementType* m_first;
+    ElementType* const m_first;
 };
 
-ElementAncestorIteratorAdapter<Element> elementLineage(Element* first);
-ElementAncestorConstIteratorAdapter<Element> elementLineage(const Element* first);
-ElementAncestorIteratorAdapter<Element> elementAncestors(Element* descendant);
-ElementAncestorConstIteratorAdapter<Element> elementAncestors(const Element* descendant);
-template <typename ElementType> ElementAncestorIteratorAdapter<ElementType> lineageOfType(Element& first);
-template <typename ElementType> ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const Element& first);
-template <typename ElementType> ElementAncestorIteratorAdapter<ElementType> ancestorsOfType(Node& descendant);
-template <typename ElementType> ElementAncestorConstIteratorAdapter<ElementType> ancestorsOfType(const Node& descendant);
-
 // ElementAncestorIterator
 
 template <typename ElementType>
-inline ElementAncestorIterator<ElementType>::ElementAncestorIterator()
-    : ElementIterator<ElementType>(nullptr)
-{
-}
-
-template <typename ElementType>
 inline ElementAncestorIterator<ElementType>::ElementAncestorIterator(ElementType* current)
     : ElementIterator<ElementType>(nullptr, current)
 {
@@ -95,119 +69,62 @@ inline ElementAncestorIterator<ElementType>::ElementAncestorIterator(ElementType
 template <typename ElementType>
 inline ElementAncestorIterator<ElementType>& ElementAncestorIterator<ElementType>::operator++()
 {
-    return static_cast<ElementAncestorIterator<ElementType>&>(ElementIterator<ElementType>::traverseAncestor());
-}
-
-// ElementAncestorConstIterator
-
-template <typename ElementType>
-inline ElementAncestorConstIterator<ElementType>::ElementAncestorConstIterator()
-    : ElementConstIterator<ElementType>(nullptr)
-{
-}
-
-template <typename ElementType>
-inline ElementAncestorConstIterator<ElementType>::ElementAncestorConstIterator(const ElementType* current)
-    : ElementConstIterator<ElementType>(nullptr, current)
-{
-}
-
-template <typename ElementType>
-inline ElementAncestorConstIterator<ElementType>& ElementAncestorConstIterator<ElementType>::operator++()
-{
-    return static_cast<ElementAncestorConstIterator<ElementType>&>(ElementConstIterator<ElementType>::traverseAncestor());
+    ElementIterator<ElementType>::traverseAncestor();
+    return *this;
 }
 
-// ElementAncestorIteratorAdapter
+// ElementAncestorRange
 
 template <typename ElementType>
-inline ElementAncestorIteratorAdapter<ElementType>::ElementAncestorIteratorAdapter(ElementType* first)
+inline ElementAncestorRange<ElementType>::ElementAncestorRange(ElementType* first)
     : m_first(first)
 {
 }
 
 template <typename ElementType>
-inline ElementAncestorIterator<ElementType> ElementAncestorIteratorAdapter<ElementType>::begin()
+inline ElementAncestorIterator<ElementType> ElementAncestorRange<ElementType>::begin() const
 {
     return ElementAncestorIterator<ElementType>(m_first);
 }
 
-template <typename ElementType>
-inline ElementAncestorIterator<ElementType> ElementAncestorIteratorAdapter<ElementType>::end()
-{
-    return ElementAncestorIterator<ElementType>();
-}
-
-// ElementAncestorConstIteratorAdapter
-
-template <typename ElementType>
-inline ElementAncestorConstIteratorAdapter<ElementType>::ElementAncestorConstIteratorAdapter(const ElementType* first)
-    : m_first(first)
-{
-}
-
-template <typename ElementType>
-inline ElementAncestorConstIterator<ElementType> ElementAncestorConstIteratorAdapter<ElementType>::begin() const
-{
-    return ElementAncestorConstIterator<ElementType>(m_first);
-}
-
-template <typename ElementType>
-inline ElementAncestorConstIterator<ElementType> ElementAncestorConstIteratorAdapter<ElementType>::end() const
-{
-    return ElementAncestorConstIterator<ElementType>();
-}
-
 // Standalone functions
 
-inline ElementAncestorIteratorAdapter<Element> elementLineage(Element* first)
-{
-    return ElementAncestorIteratorAdapter<Element>(first);
-}
-
-inline ElementAncestorConstIteratorAdapter<Element> elementLineage(const Element* first)
+template<> inline ElementAncestorRange<Element> lineageOfType<Element>(Element& first)
 {
-    return ElementAncestorConstIteratorAdapter<Element>(first);
-}
-
-inline ElementAncestorIteratorAdapter<Element> elementAncestors(Element* descendant)
-{
-    return ElementAncestorIteratorAdapter<Element>(descendant->parentElement());
-}
-
-inline ElementAncestorConstIteratorAdapter<Element> elementAncestors(const Element* descendant)
-{
-    return ElementAncestorConstIteratorAdapter<Element>(descendant->parentElement());
+    return ElementAncestorRange<Element>(&first);
 }
 
 template <typename ElementType>
-inline ElementAncestorIteratorAdapter<ElementType> lineageOfType(Element& first)
+inline ElementAncestorRange<ElementType> lineageOfType(Element& first)
 {
     if (is<ElementType>(first))
-        return ElementAncestorIteratorAdapter<ElementType>(static_cast<ElementType*>(&first));
+        return ElementAncestorRange<ElementType>(&downcast<ElementType>(first));
     return ancestorsOfType<ElementType>(first);
 }
 
+template<> inline ElementAncestorRange<const Element> lineageOfType<Element>(const Element& first)
+{
+    return ElementAncestorRange<const Element>(&first);
+}
+
 template <typename ElementType>
-inline ElementAncestorConstIteratorAdapter<ElementType> lineageOfType(const Element& first)
+inline ElementAncestorRange<const ElementType> lineageOfType(const Element& first)
 {
     if (is<ElementType>(first))
-        return ElementAncestorConstIteratorAdapter<ElementType>(static_cast<const ElementType*>(&first));
+        return ElementAncestorRange<const ElementType>(&downcast<ElementType>(first));
     return ancestorsOfType<ElementType>(first);
 }
 
 template <typename ElementType>
-inline ElementAncestorIteratorAdapter<ElementType> ancestorsOfType(Node& descendant)
+inline ElementAncestorRange<ElementType> ancestorsOfType(Node& descendant)
 {
-    ElementType* first = findElementAncestorOfType<ElementType>(descendant);
-    return ElementAncestorIteratorAdapter<ElementType>(first);
+    return ElementAncestorRange<ElementType>(findElementAncestorOfType<ElementType>(descendant));
 }
 
 template <typename ElementType>
-inline ElementAncestorConstIteratorAdapter<ElementType> ancestorsOfType(const Node& descendant)
+inline ElementAncestorRange<const ElementType> ancestorsOfType(const Node& descendant)
 {
-    const ElementType* first = findElementAncestorOfType<const ElementType>(descendant);
-    return ElementAncestorConstIteratorAdapter<ElementType>(first);
+    return ElementAncestorRange<const ElementType>(findElementAncestorOfType<const ElementType>(descendant));
 }
 
 } // namespace WebCore
index 48e3b1a..d1ddb0f 100644 (file)
@@ -36,8 +36,8 @@ class ElementAndTextDescendantIterator {
 public:
     ElementAndTextDescendantIterator();
     enum FirstChildTag { FirstChild };
-    ElementAndTextDescendantIterator(ContainerNode& root, FirstChildTag);
-    ElementAndTextDescendantIterator(ContainerNode& root, Node* current);
+    ElementAndTextDescendantIterator(const ContainerNode& root, FirstChildTag);
+    ElementAndTextDescendantIterator(const ContainerNode& root, Node* current);
 
     ElementAndTextDescendantIterator& operator++() { return traverseNext(); }
 
@@ -63,9 +63,9 @@ public:
 
 private:
     static bool isElementOrText(const Node& node) { return is<Element>(node) || is<Text>(node); }
-    static Node* firstChild(Node&);
-    static Node* nextSibling(Node&);
-    static Node* previousSibling(Node&);
+    static Node* firstChild(const Node&);
+    static Node* nextSibling(const Node&);
+    static Node* previousSibling(const Node&);
 
     void popAncestorSiblingStack();
 
@@ -82,17 +82,17 @@ private:
 #endif
 };
 
-class ElementAndTextDescendantIteratorAdapter {
+class ElementAndTextDescendantRange {
 public:
-    explicit ElementAndTextDescendantIteratorAdapter(ContainerNode& root);
-    ElementAndTextDescendantIterator begin();
-    ElementAndTextDescendantIterator end();
+    explicit ElementAndTextDescendantRange(const ContainerNode& root);
+    ElementAndTextDescendantIterator begin() const;
+    ElementAndTextDescendantIterator end() const;
 
 private:
-    ContainerNode& m_root;
+    const ContainerNode& m_root;
 };
 
-ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode&);
+ElementAndTextDescendantRange elementAndTextDescendants(ContainerNode&);
 
 // ElementAndTextDescendantIterator
 
@@ -101,7 +101,7 @@ inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator()
 {
 }
 
-inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(ContainerNode& root, FirstChildTag)
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(const ContainerNode& root, FirstChildTag)
     : m_current(firstChild(root))
 #if ASSERT_ENABLED
     , m_assertions(m_current)
@@ -113,7 +113,7 @@ inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(Contai
     m_depth = 1;
 }
 
-inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(ContainerNode& root, Node* current)
+inline ElementAndTextDescendantIterator::ElementAndTextDescendantIterator(const ContainerNode& root, Node* current)
     : m_current(current)
 #if ASSERT_ENABLED
     , m_assertions(m_current)
@@ -148,7 +148,7 @@ inline void ElementAndTextDescendantIterator::dropAssertions()
 #endif
 }
 
-inline Node* ElementAndTextDescendantIterator::firstChild(Node& current)
+inline Node* ElementAndTextDescendantIterator::firstChild(const Node& current)
 {
     auto* node = current.firstChild();
     while (node && !isElementOrText(*node))
@@ -156,7 +156,7 @@ inline Node* ElementAndTextDescendantIterator::firstChild(Node& current)
     return node;
 }
 
-inline Node* ElementAndTextDescendantIterator::nextSibling(Node& current)
+inline Node* ElementAndTextDescendantIterator::nextSibling(const Node& current)
 {
     auto* node = current.nextSibling();
     while (node && !isElementOrText(*node))
@@ -164,7 +164,7 @@ inline Node* ElementAndTextDescendantIterator::nextSibling(Node& current)
     return node;
 }
 
-inline Node* ElementAndTextDescendantIterator::previousSibling(Node& current)
+inline Node* ElementAndTextDescendantIterator::previousSibling(const Node& current)
 {
     auto* node = current.previousSibling();
     while (node && !isElementOrText(*node))
@@ -294,28 +294,28 @@ inline bool ElementAndTextDescendantIterator::operator!=(const ElementAndTextDes
     return !(*this == other);
 }
 
-// ElementAndTextDescendantIteratorAdapter
+// ElementAndTextDescendantRange
 
-inline ElementAndTextDescendantIteratorAdapter::ElementAndTextDescendantIteratorAdapter(ContainerNode& root)
+inline ElementAndTextDescendantRange::ElementAndTextDescendantRange(const ContainerNode& root)
     : m_root(root)
 {
 }
 
-inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::begin()
+inline ElementAndTextDescendantIterator ElementAndTextDescendantRange::begin() const
 {
     return ElementAndTextDescendantIterator(m_root, ElementAndTextDescendantIterator::FirstChild);
 }
 
-inline ElementAndTextDescendantIterator ElementAndTextDescendantIteratorAdapter::end()
+inline ElementAndTextDescendantIterator ElementAndTextDescendantRange::end() const
 {
     return { };
 }
 
 // Standalone functions
 
-inline ElementAndTextDescendantIteratorAdapter elementAndTextDescendants(ContainerNode& root)
+inline ElementAndTextDescendantRange elementAndTextDescendants(ContainerNode& root)
 {
-    return ElementAndTextDescendantIteratorAdapter(root);
+    return ElementAndTextDescendantRange(root);
 }
 
 } // namespace WebCore
index 8e38fb5..e66b249 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
 
 namespace WebCore {
 
+template<typename> class ElementChildRange;
+
+// Range for iterating through child elements.
+template <typename ElementType> ElementChildRange<ElementType> childrenOfType(ContainerNode&);
+template <typename ElementType> ElementChildRange<const ElementType> childrenOfType(const ContainerNode&);
+
 template <typename ElementType>
 class ElementChildIterator : public ElementIterator<ElementType> {
 public:
-    typedef ElementType value_type;
-    typedef ptrdiff_t difference_type;
-    typedef ElementType* pointer;
-    typedef ElementType& reference;
-    typedef std::forward_iterator_tag iterator_category;
-
-    ElementChildIterator(const ContainerNode& parent);
+    ElementChildIterator() = default;
     ElementChildIterator(const ContainerNode& parent, ElementType* current);
     ElementChildIterator& operator--();
     ElementChildIterator& operator++();
 };
 
 template <typename ElementType>
-class ElementChildConstIterator : public ElementConstIterator<ElementType> {
-public:
-    typedef const ElementType value_type;
-    typedef ptrdiff_t difference_type;
-    typedef const ElementType* pointer;
-    typedef const ElementType& reference;
-    typedef std::forward_iterator_tag iterator_category;
-
-    ElementChildConstIterator(const ContainerNode& parent);
-    ElementChildConstIterator(const ContainerNode& parent, const ElementType* current);
-    ElementChildConstIterator& operator--();
-    ElementChildConstIterator& operator++();
-};
-
-template <typename ElementType>
-class ElementChildIteratorAdapter {
-public:
-    ElementChildIteratorAdapter(ContainerNode& parent);
-
-    ElementChildIterator<ElementType> begin();
-    ElementChildIterator<ElementType> end();
-    ElementChildIterator<ElementType> beginAt(ElementType&);
-
-    ElementType* first();
-    ElementType* last();
-
-private:
-    ContainerNode& m_parent;
-};
-
-template <typename ElementType>
-class ElementChildConstIteratorAdapter {
+class ElementChildRange {
 public:
-    ElementChildConstIteratorAdapter(const ContainerNode& parent);
+    ElementChildRange(const ContainerNode& parent);
 
-    ElementChildConstIterator<ElementType> begin() const;
-    ElementChildConstIterator<ElementType> end() const;
-    ElementChildConstIterator<ElementType> beginAt(const ElementType&) const;
+    ElementChildIterator<ElementType> begin() const;
+    static constexpr std::nullptr_t end() { return nullptr; }
+    ElementChildIterator<ElementType> beginAt(ElementType&) const;
 
-    const ElementType* first() const;
-    const ElementType* last() const;
+    ElementType* first() const;
+    ElementType* last() const;
 
 private:
     const ContainerNode& m_parent;
 };
 
-template <typename ElementType> ElementChildIteratorAdapter<ElementType> childrenOfType(ContainerNode&);
-template <typename ElementType> ElementChildConstIteratorAdapter<ElementType> childrenOfType(const ContainerNode&);
-
 // ElementChildIterator
 
 template <typename ElementType>
-inline ElementChildIterator<ElementType>::ElementChildIterator(const ContainerNode& parent)
-    : ElementIterator<ElementType>(&parent)
-{
-}
-
-template <typename ElementType>
 inline ElementChildIterator<ElementType>::ElementChildIterator(const ContainerNode& parent, ElementType* current)
     : ElementIterator<ElementType>(&parent, current)
 {
@@ -111,132 +71,62 @@ inline ElementChildIterator<ElementType>::ElementChildIterator(const ContainerNo
 template <typename ElementType>
 inline ElementChildIterator<ElementType>& ElementChildIterator<ElementType>::operator--()
 {
-    return static_cast<ElementChildIterator<ElementType>&>(ElementIterator<ElementType>::traversePreviousSibling());
+    ElementIterator<ElementType>::traversePreviousSibling();
+    return *this;
 }
 
 template <typename ElementType>
 inline ElementChildIterator<ElementType>& ElementChildIterator<ElementType>::operator++()
 {
-    return static_cast<ElementChildIterator<ElementType>&>(ElementIterator<ElementType>::traverseNextSibling());
-}
-
-// ElementChildConstIterator
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType>::ElementChildConstIterator(const ContainerNode& parent)
-    : ElementConstIterator<ElementType>(&parent)
-{
-}
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType>::ElementChildConstIterator(const ContainerNode& parent, const ElementType* current)
-    : ElementConstIterator<ElementType>(&parent, current)
-{
-}
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType>& ElementChildConstIterator<ElementType>::operator--()
-{
-    return static_cast<ElementChildConstIterator<ElementType>&>(ElementConstIterator<ElementType>::traversePreviousSibling());
+    ElementIterator<ElementType>::traverseNextSibling();
+    return *this;
 }
 
+// ElementChildRange
 
 template <typename ElementType>
-inline ElementChildConstIterator<ElementType>& ElementChildConstIterator<ElementType>::operator++()
-{
-    return static_cast<ElementChildConstIterator<ElementType>&>(ElementConstIterator<ElementType>::traverseNextSibling());
-}
-
-// ElementChildIteratorAdapter
-
-template <typename ElementType>
-inline ElementChildIteratorAdapter<ElementType>::ElementChildIteratorAdapter(ContainerNode& parent)
+inline ElementChildRange<ElementType>::ElementChildRange(const ContainerNode& parent)
     : m_parent(parent)
 {
 }
 
 template <typename ElementType>
-inline ElementChildIterator<ElementType> ElementChildIteratorAdapter<ElementType>::begin()
+inline ElementChildIterator<ElementType> ElementChildRange<ElementType>::begin() const
 {
     return ElementChildIterator<ElementType>(m_parent, Traversal<ElementType>::firstChild(m_parent));
 }
 
 template <typename ElementType>
-inline ElementChildIterator<ElementType> ElementChildIteratorAdapter<ElementType>::end()
-{
-    return ElementChildIterator<ElementType>(m_parent);
-}
-
-template <typename ElementType>
-inline ElementType* ElementChildIteratorAdapter<ElementType>::first()
+inline ElementType* ElementChildRange<ElementType>::first() const
 {
     return Traversal<ElementType>::firstChild(m_parent);
 }
 
 template <typename ElementType>
-inline ElementType* ElementChildIteratorAdapter<ElementType>::last()
+inline ElementType* ElementChildRange<ElementType>::last() const
 {
     return Traversal<ElementType>::lastChild(m_parent);
 }
 
 template <typename ElementType>
-inline ElementChildIterator<ElementType> ElementChildIteratorAdapter<ElementType>::beginAt(ElementType& child)
+inline ElementChildIterator<ElementType> ElementChildRange<ElementType>::beginAt(ElementType& child) const
 {
     ASSERT(child.parentNode() == &m_parent);
     return ElementChildIterator<ElementType>(m_parent, &child);
 }
 
-// ElementChildConstIteratorAdapter
-
-template <typename ElementType>
-inline ElementChildConstIteratorAdapter<ElementType>::ElementChildConstIteratorAdapter(const ContainerNode& parent)
-    : m_parent(parent)
-{
-}
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType> ElementChildConstIteratorAdapter<ElementType>::begin() const
-{
-    return ElementChildConstIterator<ElementType>(m_parent, Traversal<ElementType>::firstChild(m_parent));
-}
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType> ElementChildConstIteratorAdapter<ElementType>::end() const
-{
-    return ElementChildConstIterator<ElementType>(m_parent);
-}
-
-template <typename ElementType>
-inline const ElementType* ElementChildConstIteratorAdapter<ElementType>::first() const
-{
-    return Traversal<ElementType>::firstChild(m_parent);
-}
-
-template <typename ElementType>
-inline const ElementType* ElementChildConstIteratorAdapter<ElementType>::last() const
-{
-    return Traversal<ElementType>::lastChild(m_parent);
-}
-
-template <typename ElementType>
-inline ElementChildConstIterator<ElementType> ElementChildConstIteratorAdapter<ElementType>::beginAt(const ElementType& child) const
-{
-    ASSERT(child.parentNode() == &m_parent);
-    return ElementChildConstIterator<ElementType>(m_parent, &child);
-}
-
 // Standalone functions
 
 template <typename ElementType>
-inline ElementChildIteratorAdapter<ElementType> childrenOfType(ContainerNode& parent)
+inline ElementChildRange<ElementType> childrenOfType(ContainerNode& parent)
 {
-    return ElementChildIteratorAdapter<ElementType>(parent);
+    return ElementChildRange<ElementType>(parent);
 }
 
 template <typename ElementType>
-inline ElementChildConstIteratorAdapter<ElementType> childrenOfType(const ContainerNode& parent)
+inline ElementChildRange<const ElementType> childrenOfType(const ContainerNode& parent)
 {
-    return ElementChildConstIteratorAdapter<ElementType>(parent);
+    return ElementChildRange<const ElementType>(parent);
 }
 
 } // namespace WebCore
diff --git a/Source/WebCore/dom/ElementDescendantIterator.h b/Source/WebCore/dom/ElementDescendantIterator.h
deleted file mode 100644 (file)
index 8dbdb99..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (C) 2014 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 "Element.h"
-#include "ElementIteratorAssertions.h"
-#include "ElementTraversal.h"
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-class ElementDescendantIterator {
-public:
-    ElementDescendantIterator();
-    explicit ElementDescendantIterator(Element* current);
-
-    ElementDescendantIterator& operator++();
-    ElementDescendantIterator& operator--();
-
-    Element& operator*();
-    Element* operator->();
-
-    bool operator==(const ElementDescendantIterator& other) const;
-    bool operator!=(const ElementDescendantIterator& other) const;
-
-    void dropAssertions();
-
-private:
-    Element* m_current;
-    Vector<Element*, 16> m_ancestorSiblingStack;
-
-#if ASSERT_ENABLED
-    ElementIteratorAssertions m_assertions;
-#endif
-};
-
-class ElementDescendantConstIterator {
-public:
-    ElementDescendantConstIterator();
-    explicit ElementDescendantConstIterator(const Element*);
-
-    ElementDescendantConstIterator& operator++();
-
-    const Element& operator*() const;
-    const Element* operator->() const;
-
-    bool operator==(const ElementDescendantConstIterator& other) const;
-    bool operator!=(const ElementDescendantConstIterator& other) const;
-
-    void dropAssertions();
-
-private:
-    const Element* m_current;
-    Vector<Element*, 16> m_ancestorSiblingStack;
-
-#if ASSERT_ENABLED
-    ElementIteratorAssertions m_assertions;
-#endif
-};
-
-class ElementDescendantIteratorAdapter {
-public:
-    ElementDescendantIteratorAdapter(ContainerNode& root);
-    ElementDescendantIterator begin();
-    ElementDescendantIterator end();
-    ElementDescendantIterator last();
-
-private:
-    ContainerNode& m_root;
-};
-
-class ElementDescendantConstIteratorAdapter {
-public:
-    ElementDescendantConstIteratorAdapter(const ContainerNode& root);
-    ElementDescendantConstIterator begin() const;
-    ElementDescendantConstIterator end() const;
-    ElementDescendantConstIterator last() const;
-
-private:
-    const ContainerNode& m_root;
-};
-
-ElementDescendantIteratorAdapter elementDescendants(ContainerNode&);
-ElementDescendantConstIteratorAdapter elementDescendants(const ContainerNode&);
-
-// ElementDescendantIterator
-
-inline ElementDescendantIterator::ElementDescendantIterator()
-    : m_current(nullptr)
-{
-}
-
-inline ElementDescendantIterator::ElementDescendantIterator(Element* current)
-    : m_current(current)
-#if ASSERT_ENABLED
-    , m_assertions(current)
-#endif
-{
-    m_ancestorSiblingStack.uncheckedAppend(nullptr);
-}
-
-inline void ElementDescendantIterator::dropAssertions()
-{
-#if ASSERT_ENABLED
-    m_assertions.clear();
-#endif
-}
-
-ALWAYS_INLINE ElementDescendantIterator& ElementDescendantIterator::operator++()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-
-    Element* firstChild = ElementTraversal::firstChild(*m_current);
-    Element* nextSibling = ElementTraversal::nextSibling(*m_current);
-
-    if (firstChild) {
-        if (nextSibling)
-            m_ancestorSiblingStack.append(nextSibling);
-        m_current = firstChild;
-        return *this;
-    }
-
-    if (nextSibling) {
-        m_current = nextSibling;
-        return *this;
-    }
-
-    m_current = m_ancestorSiblingStack.takeLast();
-
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-
-    return *this;
-}
-
-ALWAYS_INLINE ElementDescendantIterator& ElementDescendantIterator::operator--()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-
-    Element* previousSibling = ElementTraversal::previousSibling(*m_current);
-
-    if (!previousSibling) {
-        m_current = m_current->parentElement();
-        // The stack optimizes for forward traversal only, this just maintains consistency.
-        if (m_current->nextSibling() && m_current->nextSibling() == m_ancestorSiblingStack.last())
-            m_ancestorSiblingStack.removeLast();
-        return *this;
-    }
-
-    Element* deepestSibling = previousSibling;
-    while (Element* lastChild = ElementTraversal::lastChild(*deepestSibling))
-        deepestSibling = lastChild;
-    ASSERT(deepestSibling);
-
-    if (deepestSibling != previousSibling)
-        m_ancestorSiblingStack.append(m_current);
-
-    m_current = deepestSibling;
-
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-
-    return *this;
-}
-
-inline Element& ElementDescendantIterator::operator*()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return *m_current;
-}
-
-inline Element* ElementDescendantIterator::operator->()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current;
-}
-
-inline bool ElementDescendantIterator::operator==(const ElementDescendantIterator& other) const
-{
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current == other.m_current;
-}
-
-inline bool ElementDescendantIterator::operator!=(const ElementDescendantIterator& other) const
-{
-    return !(*this == other);
-}
-
-// ElementDescendantConstIterator
-
-inline ElementDescendantConstIterator::ElementDescendantConstIterator()
-    : m_current(nullptr)
-{
-}
-
-inline ElementDescendantConstIterator::ElementDescendantConstIterator(const Element* current)
-    : m_current(current)
-#if ASSERT_ENABLED
-    , m_assertions(current)
-#endif
-{
-    m_ancestorSiblingStack.uncheckedAppend(nullptr);
-}
-
-inline void ElementDescendantConstIterator::dropAssertions()
-{
-#if ASSERT_ENABLED
-    m_assertions.clear();
-#endif
-}
-
-ALWAYS_INLINE ElementDescendantConstIterator& ElementDescendantConstIterator::operator++()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-
-    Element* firstChild = ElementTraversal::firstChild(*m_current);
-    Element* nextSibling = ElementTraversal::nextSibling(*m_current);
-
-    if (firstChild) {
-        if (nextSibling)
-            m_ancestorSiblingStack.append(nextSibling);
-        m_current = firstChild;
-        return *this;
-    }
-
-    if (nextSibling) {
-        m_current = nextSibling;
-        return *this;
-    }
-
-    m_current = m_ancestorSiblingStack.takeLast();
-
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-
-    return *this;
-}
-
-inline const Element& ElementDescendantConstIterator::operator*() const
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return *m_current;
-}
-
-inline const Element* ElementDescendantConstIterator::operator->() const
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current;
-}
-
-inline bool ElementDescendantConstIterator::operator==(const ElementDescendantConstIterator& other) const
-{
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current == other.m_current;
-}
-
-inline bool ElementDescendantConstIterator::operator!=(const ElementDescendantConstIterator& other) const
-{
-    return !(*this == other);
-}
-
-// ElementDescendantIteratorAdapter
-
-inline ElementDescendantIteratorAdapter::ElementDescendantIteratorAdapter(ContainerNode& root)
-    : m_root(root)
-{
-}
-
-inline ElementDescendantIterator ElementDescendantIteratorAdapter::begin()
-{
-    return ElementDescendantIterator(ElementTraversal::firstChild(m_root));
-}
-
-inline ElementDescendantIterator ElementDescendantIteratorAdapter::end()
-{
-    return ElementDescendantIterator();
-}
-
-inline ElementDescendantIterator ElementDescendantIteratorAdapter::last()
-{
-    return ElementDescendantIterator(ElementTraversal::lastWithin(m_root));
-}
-
-// ElementDescendantConstIteratorAdapter
-
-inline ElementDescendantConstIteratorAdapter::ElementDescendantConstIteratorAdapter(const ContainerNode& root)
-    : m_root(root)
-{
-}
-
-inline ElementDescendantConstIterator ElementDescendantConstIteratorAdapter::begin() const
-{
-    return ElementDescendantConstIterator(ElementTraversal::firstChild(m_root));
-}
-
-inline ElementDescendantConstIterator ElementDescendantConstIteratorAdapter::end() const
-{
-    return ElementDescendantConstIterator();
-}
-
-inline ElementDescendantConstIterator ElementDescendantConstIteratorAdapter::last() const
-{
-    return ElementDescendantConstIterator(ElementTraversal::lastWithin(m_root));
-}
-
-// Standalone functions
-
-inline ElementDescendantIteratorAdapter elementDescendants(ContainerNode& root)
-{
-    return ElementDescendantIteratorAdapter(root);
-}
-
-inline ElementDescendantConstIteratorAdapter elementDescendants(const ContainerNode& root)
-{
-    return ElementDescendantConstIteratorAdapter(root);
-}
-
-} // namespace WebCore
-
-namespace std {
-template <> struct iterator_traits<WebCore::ElementDescendantIterator> {
-    typedef WebCore::Element value_type;
-};
-template <> struct iterator_traits<WebCore::ElementDescendantConstIterator> {
-    typedef const WebCore::Element value_type;
-};
-}
index 374dba7..6012bb6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * 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
 namespace WebCore {
 
 template <typename ElementType>
-class ElementIterator {
+class ElementIterator : public std::iterator<std::forward_iterator_tag, ElementType> {
 public:
-    ElementIterator(const ContainerNode* root);
-    ElementIterator(const ContainerNode* root, ElementType* current);
+    ElementIterator() = default;
 
     ElementType& operator*() const;
     ElementType* operator->() const;
 
-    bool operator==(const ElementIterator& other) const;
-    bool operator!=(const ElementIterator& other) 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();
@@ -54,39 +55,12 @@ public:
 
     void dropAssertions();
 
-private:
-    const ContainerNode* m_root;
-    ElementType* m_current;
-
-#if ASSERT_ENABLED
-    ElementIteratorAssertions m_assertions;
-#endif
-};
-
-template <typename ElementType>
-class ElementConstIterator {
-public:
-    ElementConstIterator(const ContainerNode* root);
-    ElementConstIterator(const ContainerNode* root, const ElementType* current);
-
-    const ElementType& operator*() const;
-    const ElementType* operator->() const;
-
-    bool operator==(const ElementConstIterator& other) const;
-    bool operator!=(const ElementConstIterator& other) const;
-
-    ElementConstIterator& traverseNext();
-    ElementConstIterator& traversePrevious();
-    ElementConstIterator& traverseNextSibling();
-    ElementConstIterator& traversePreviousSibling();
-    ElementConstIterator& traverseNextSkippingChildren();
-    ElementConstIterator& traverseAncestor();
-
-    void dropAssertions();
+protected:
+    ElementIterator(const ContainerNode* root, ElementType* current);
 
 private:
-    const ContainerNode* m_root;
-    const ElementType* m_current;
+    const ContainerNode* m_root { nullptr };
+    ElementType* m_current { nullptr };
 
 #if ASSERT_ENABLED
     ElementIteratorAssertions m_assertions;
@@ -96,13 +70,6 @@ private:
 // ElementIterator
 
 template <typename ElementType>
-inline ElementIterator<ElementType>::ElementIterator(const ContainerNode* root)
-    : m_root(root)
-    , m_current(nullptr)
-{
-}
-
-template <typename ElementType>
 inline ElementIterator<ElementType>::ElementIterator(const ContainerNode* root, ElementType* current)
     : m_root(root)
     , m_current(current)
@@ -237,160 +204,25 @@ inline ElementType* ElementIterator<ElementType>::operator->() const
     return m_current;
 }
 
-template <typename ElementType>
-inline bool ElementIterator<ElementType>::operator==(const ElementIterator& other) const
-{
-    ASSERT(m_root == other.m_root);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current == other.m_current;
-}
-
-template <typename ElementType>
-inline bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
-{
-    return !(*this == other);
-}
-
-// ElementConstIterator
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>::ElementConstIterator(const ContainerNode* root)
-    : m_root(root)
-    , m_current(nullptr)
+template<typename ElementType> constexpr ElementIterator<ElementType>::operator bool() const
 {
+    return m_current;
 }
 
-template <typename ElementType>
-inline ElementConstIterator<ElementType>::ElementConstIterator(const ContainerNode* root, const ElementType* current)
-    : m_root(root)
-    , m_current(current)
-#if ASSERT_ENABLED
-    , m_assertions(current)
-#endif
-{
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseNext()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = Traversal<ElementType>::next(*m_current, m_root);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traversePrevious()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = Traversal<ElementType>::previous(*m_current, m_root);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseNextSibling()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = Traversal<ElementType>::nextSibling(*m_current);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traversePreviousSibling()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = Traversal<ElementType>::previousSibling(*m_current);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseNextSkippingChildren()
-{
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = Traversal<ElementType>::nextSkippingChildren(*m_current, m_root);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline ElementConstIterator<ElementType>& ElementConstIterator<ElementType>::traverseAncestor()
-{
-    ASSERT(m_current);
-    ASSERT(m_current != m_root);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    m_current = findElementAncestorOfType<const ElementType>(*m_current);
-#if ASSERT_ENABLED
-    // Drop the assertion when the iterator reaches the end.
-    if (!m_current)
-        m_assertions.dropEventDispatchAssertion();
-#endif
-    return *this;
-}
-
-template <typename ElementType>
-inline void ElementConstIterator<ElementType>::dropAssertions()
-{
-#if ASSERT_ENABLED
-    m_assertions.clear();
-#endif
-}
-
-template <typename ElementType>
-inline const ElementType& ElementConstIterator<ElementType>::operator*() const
+template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!() const
 {
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return *m_current;
+    return !m_current;
 }
 
-template <typename ElementType>
-inline const ElementType* ElementConstIterator<ElementType>::operator->() const
+template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!=(std::nullptr_t) const
 {
-    ASSERT(m_current);
-    ASSERT(!m_assertions.domTreeHasMutated());
     return m_current;
 }
 
-template <typename ElementType>
-inline bool ElementConstIterator<ElementType>::operator==(const ElementConstIterator& other) const
-{
-    ASSERT(m_root == other.m_root);
-    ASSERT(!m_assertions.domTreeHasMutated());
-    return m_current == other.m_current;
-}
-
-template <typename ElementType>
-inline bool ElementConstIterator<ElementType>::operator!=(const ElementConstIterator& other) const
+template<typename ElementType> constexpr bool ElementIterator<ElementType>::operator!=(const ElementIterator& other) const
 {
-    return !(*this == other);
+    ASSERT(m_root == other.m_root || !m_current || !other.m_current);
+    return m_current != other.m_current;
 }
 
 } // namespace WebCore
index dd0c999..4789230 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2006-2008, 2010, 2013-2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "config.h"
 #include "LiveNodeList.h"
 
-#include "ClassCollection.h"
-#include "Element.h"
-#include "ElementTraversal.h"
-#include "HTMLCollection.h"
-#include <wtf/IsoMallocInlines.h>
-
 namespace WebCore {
 
-WTF_MAKE_ISO_ALLOCATED_IMPL(LiveNodeList);
-
 LiveNodeList::LiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType invalidationType)
     : m_ownerNode(ownerNode)
     , m_invalidationType(invalidationType)
-    , m_isRegisteredForInvalidationAtDocument(false)
 {
-    ASSERT(m_invalidationType == static_cast<unsigned>(invalidationType));
 }
 
 LiveNodeList::~LiveNodeList() = default;
 
-ContainerNode& LiveNodeList::rootNode() const
-{
-    if (isRootedAtDocument() && ownerNode().isConnected())
-        return ownerNode().document();
-
-    return ownerNode();
-}
-
 } // namespace WebCore
index f27f0ef..4891636 100644 (file)
@@ -26,7 +26,6 @@
 #include "CollectionIndexCache.h"
 #include "CollectionTraversal.h"
 #include "Document.h"
-#include "ElementDescendantIterator.h"
 #include "HTMLNames.h"
 #include "NodeList.h"
 #include <wtf/Forward.h>
@@ -39,39 +38,35 @@ class Element;
 static bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType, const QualifiedName&);
 
 class LiveNodeList : public NodeList {
-    WTF_MAKE_ISO_ALLOCATED(LiveNodeList);
+    WTF_MAKE_ISO_NONALLOCATABLE(LiveNodeList);
 public:
-    LiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType);
     virtual ~LiveNodeList();
 
     virtual bool elementMatches(Element&) const = 0;
     virtual bool isRootedAtDocument() const = 0;
 
-    ALWAYS_INLINE NodeListInvalidationType invalidationType() const { return static_cast<NodeListInvalidationType>(m_invalidationType); }
+    NodeListInvalidationType invalidationType() const { return m_invalidationType; }
     ContainerNode& ownerNode() const { return m_ownerNode; }
-    ALWAYS_INLINE void invalidateCacheForAttribute(const QualifiedName& attrName) const
-    {
-        if (shouldInvalidateTypeOnAttributeChange(invalidationType(), attrName))
-            invalidateCache();
-    }
+    void invalidateCacheForAttribute(const QualifiedName& attributeName) const;
     virtual void invalidateCacheForDocument(Document&) const = 0;
     void invalidateCache() const { invalidateCacheForDocument(document()); }
 
     bool isRegisteredForInvalidationAtDocument() const { return m_isRegisteredForInvalidationAtDocument; }
-    void setRegisteredForInvalidationAtDocument(bool f) { m_isRegisteredForInvalidationAtDocument = f; }
+    void setRegisteredForInvalidationAtDocument(bool isRegistered) { m_isRegisteredForInvalidationAtDocument = isRegistered; }
 
 protected:
+    LiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType);
+
     Document& document() const { return m_ownerNode->document(); }
+    ContainerNode& rootNode() const;
 
 private:
     bool isLiveNodeList() const final { return true; }
 
-    ContainerNode& rootNode() const;
-
     Ref<ContainerNode> m_ownerNode;
 
-    const unsigned m_invalidationType;
-    bool m_isRegisteredForInvalidationAtDocument;
+    const NodeListInvalidationType m_invalidationType;
+    bool m_isRegisteredForInvalidationAtDocument { false };
 };
 
 template <class NodeListType>
@@ -81,16 +76,17 @@ public:
     virtual ~CachedLiveNodeList();
 
     unsigned length() const final { return m_indexCache.nodeCount(nodeList()); }
-    Element* item(unsigned offset) const override { return m_indexCache.nodeAt(nodeList(), offset); }
+    Element* item(unsigned offset) const final { return m_indexCache.nodeAt(nodeList(), offset); }
 
     // For CollectionIndexCache
-    ElementDescendantIterator collectionBegin() const { return CollectionTraversal<CollectionTraversalType::Descendants>::begin(nodeList(), rootNode()); }
-    ElementDescendantIterator collectionLast() const { return CollectionTraversal<CollectionTraversalType::Descendants>::last(nodeList(), rootNode()); }
-    ElementDescendantIterator collectionEnd() const { return ElementDescendantIterator(); }
-    void collectionTraverseForward(ElementDescendantIterator& current, unsigned count, unsigned& traversedCount) const { CollectionTraversal<CollectionTraversalType::Descendants>::traverseForward(nodeList(), current, count, traversedCount); }
-    void collectionTraverseBackward(ElementDescendantIterator& current, unsigned count) const { CollectionTraversal<CollectionTraversalType::Descendants>::traverseBackward(nodeList(), current, count); }
+    using Traversal = CollectionTraversal<CollectionTraversalType::Descendants>;
+    using Iterator = Traversal::Iterator;
+    auto collectionBegin() const { return Traversal::begin(nodeList(), rootNode()); }
+    auto collectionLast() const { return Traversal::last(nodeList(), rootNode()); }
+    void collectionTraverseForward(Iterator& current, unsigned count, unsigned& traversedCount) const { Traversal::traverseForward(nodeList(), current, count, traversedCount); }
+    void collectionTraverseBackward(Iterator& current, unsigned count) const { Traversal::traverseBackward(nodeList(), current, count); }
     bool collectionCanTraverseBackward() const { return true; }
-    void willValidateIndexCache() const { document().registerNodeListForInvalidation(const_cast<CachedLiveNodeList<NodeListType>&>(*this)); }
+    void willValidateIndexCache() const { document().registerNodeListForInvalidation(const_cast<CachedLiveNodeList&>(*this)); }
 
     void invalidateCacheForDocument(Document&) const final;
     size_t memoryCost() const final
@@ -108,9 +104,7 @@ private:
     NodeListType& nodeList() { return static_cast<NodeListType&>(*this); }
     const NodeListType& nodeList() const { return static_cast<const NodeListType&>(*this); }
 
-    ContainerNode& rootNode() const;
-
-    mutable CollectionIndexCache<NodeListType, ElementDescendantIterator> m_indexCache;
+    mutable CollectionIndexCache<NodeListType, Iterator> m_indexCache;
 };
 
 ALWAYS_INLINE bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationType type, const QualifiedName& attrName)
@@ -137,36 +131,40 @@ ALWAYS_INLINE bool shouldInvalidateTypeOnAttributeChange(NodeListInvalidationTyp
     return false;
 }
 
+ALWAYS_INLINE void LiveNodeList::invalidateCacheForAttribute(const QualifiedName& attributeName) const
+{
+    if (shouldInvalidateTypeOnAttributeChange(m_invalidationType, attributeName))
+        invalidateCache();
+}
+
+inline ContainerNode& LiveNodeList::rootNode() const
+{
+    if (isRootedAtDocument() && m_ownerNode->isConnected())
+        return document();
+
+    return m_ownerNode;
+}
+
 template <class NodeListType>
 CachedLiveNodeList<NodeListType>::CachedLiveNodeList(ContainerNode& ownerNode, NodeListInvalidationType invalidationType)
     : LiveNodeList(ownerNode, invalidationType)
-    , m_indexCache(nodeList())
 {
 }
 
 template <class NodeListType>
 CachedLiveNodeList<NodeListType>::~CachedLiveNodeList()
 {
-    if (m_indexCache.hasValidCache(nodeList()))
+    if (m_indexCache.hasValidCache())
         document().unregisterNodeListForInvalidation(*this);
 }
 
 template <class NodeListType>
-inline ContainerNode& CachedLiveNodeList<NodeListType>::rootNode() const
-{
-    if (nodeList().isRootedAtDocument() && ownerNode().isConnected())
-        return ownerNode().document();
-
-    return ownerNode();
-}
-
-template <class NodeListType>
 void CachedLiveNodeList<NodeListType>::invalidateCacheForDocument(Document& document) const
 {
-    if (!m_indexCache.hasValidCache(nodeList()))
-        return;
-    document.unregisterNodeListForInvalidation(const_cast<NodeListType&>(nodeList()));
-    m_indexCache.invalidate(nodeList());
+    if (m_indexCache.hasValidCache()) {
+        document.unregisterNodeListForInvalidation(const_cast<NodeListType&>(nodeList()));
+        m_indexCache.invalidate();
+    }
 }
 
 } // namespace WebCore
index f0add2a..f4fa26f 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2007, 2014-2019 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -38,6 +38,11 @@ NameNodeList::NameNodeList(ContainerNode& rootNode, const AtomString& name)
 {
 }
 
+Ref<NameNodeList> NameNodeList::create(ContainerNode& rootNode, const AtomString& name)
+{
+    return adoptRef(*new NameNodeList(rootNode, name));
+}
+
 NameNodeList::~NameNodeList()
 {
     ownerNode().nodeLists()->removeCacheWithAtomName(*this, m_name);
index 70c5c70..9475def 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2007-2008, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #pragma once
 
 #include "LiveNodeList.h"
-#include <wtf/Forward.h>
-#include <wtf/text/AtomString.h>
 
 namespace WebCore {
 
-// NodeList which lists all Nodes in a Element with a given "name" attribute
 class NameNodeList final : public CachedLiveNodeList<NameNodeList> {
     WTF_MAKE_ISO_ALLOCATED(NameNodeList);
 public:
-    static Ref<NameNodeList> create(ContainerNode& rootNode, const AtomString& name)
-    {
-        return adoptRef(*new NameNodeList(rootNode, name));
-    }
-
+    static Ref<NameNodeList> create(ContainerNode& rootNode, const AtomString& name);
     virtual ~NameNodeList();
 
-    bool elementMatches(Element&) const override;
-    bool isRootedAtDocument() const override { return false; }
+    bool elementMatches(Element&) const final;
+    bool isRootedAtDocument() const final { return false; }
 
 private:
     NameNodeList(ContainerNode& rootNode, const AtomString& name);
index 9f35935..7895797 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * 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
 
 namespace WebCore {
 
-template<typename ElementType> class DoubleTypedElementDescendantIterator;
+template<typename> class DoubleElementDescendantIterator;
+template<typename> class DoubleElementDescendantRange;
+template<typename> class ElementDescendantRange;
+template<typename ElementType, bool(const ElementType&)> class FilteredElementDescendantRange;
 
-template <typename ElementType>
-class TypedElementDescendantIterator : public ElementIterator<ElementType> {
-public:
-    TypedElementDescendantIterator(const ContainerNode& root);
-    TypedElementDescendantIterator(const ContainerNode& root, ElementType* current);
-    TypedElementDescendantIterator& operator++();
-};
-
-template <typename ElementType>
-class TypedElementDescendantConstIterator : public ElementConstIterator<ElementType>  {
-public:
-    TypedElementDescendantConstIterator(const ContainerNode& root);
-    TypedElementDescendantConstIterator(const ContainerNode& root, const ElementType* current);
-    TypedElementDescendantConstIterator& operator++();
-};
+// Range for iterating through descendant elements.
+template<typename ElementType> ElementDescendantRange<ElementType> descendantsOfType(ContainerNode&);
+template<typename ElementType> ElementDescendantRange<const ElementType> descendantsOfType(const ContainerNode&);
 
-template <typename ElementType>
-class TypedElementDescendantIteratorAdapter {
-public:
-    TypedElementDescendantIteratorAdapter(ContainerNode& root);
-    TypedElementDescendantIterator<ElementType> begin();
-    TypedElementDescendantIterator<ElementType> end();
-    TypedElementDescendantIterator<ElementType> beginAt(ElementType&);
-    TypedElementDescendantIterator<ElementType> from(Element&);
+// Range that skips elements where the filter returns false.
+template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<const ElementType, filter> filteredDescendants(const ContainerNode&);
 
-    ElementType* first();
-    ElementType* last();
+// 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);
 
-private:
-    ContainerNode& m_root;
+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 TypedElementDescendantConstIteratorAdapter {
+template<typename ElementType> class ElementDescendantRange {
 public:
-    TypedElementDescendantConstIteratorAdapter(const ContainerNode& root);
-    TypedElementDescendantConstIterator<ElementType> begin() const;
-    TypedElementDescendantConstIterator<ElementType> end() const;
-    TypedElementDescendantConstIterator<ElementType> beginAt(const ElementType&) const;
-    TypedElementDescendantConstIterator<ElementType> from(const Element&) const;
+    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;
 
-    const ElementType* first() const;
-    const ElementType* last() const;
+    ElementType* first() const;
+    ElementType* last() const;
 
 private:
     const ContainerNode& m_root;
 };
 
-template<typename ElementType> class DoubleTypedElementDescendantIteratorAdapter {
+template<typename ElementType> class DoubleElementDescendantRange {
 public:
-    typedef TypedElementDescendantIteratorAdapter<ElementType> SingleAdapter;
-    typedef DoubleTypedElementDescendantIterator<ElementType> Iterator;
+    typedef ElementDescendantRange<ElementType> SingleAdapter;
+    typedef DoubleElementDescendantIterator<ElementType> Iterator;
 
-    DoubleTypedElementDescendantIteratorAdapter(SingleAdapter&&, SingleAdapter&&);
-    Iterator begin();
-    Iterator end();
+    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 DoubleTypedElementDescendantIterator {
+template<typename ElementType> class DoubleElementDescendantIterator {
 public:
-    typedef TypedElementDescendantIterator<ElementType> SingleIterator;
+    typedef ElementDescendantIterator<ElementType> SingleIterator;
     typedef std::pair<ElementType&, ElementType&> ReferenceProxy;
 
-    DoubleTypedElementDescendantIterator(SingleIterator&&, SingleIterator&&);
+    DoubleElementDescendantIterator(SingleIterator&&, SingleIterator&&);
     ReferenceProxy operator*() const;
-    bool operator==(const DoubleTypedElementDescendantIterator&) const;
-    bool operator!=(const DoubleTypedElementDescendantIterator&) const;
-    DoubleTypedElementDescendantIterator& operator++();
+    constexpr bool operator!=(std::nullptr_t) const;
+    DoubleElementDescendantIterator& operator++();
 
 private:
     std::pair<SingleIterator, SingleIterator> m_pair;
 };
 
-template <typename ElementType> TypedElementDescendantIteratorAdapter<ElementType> descendantsOfType(ContainerNode&);
-template <typename ElementType> TypedElementDescendantConstIteratorAdapter<ElementType> descendantsOfType(const ContainerNode&);
-
-// This must only be used 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> DoubleTypedElementDescendantIteratorAdapter<ElementType> descendantsOfType(ContainerNode& firstRoot, ContainerNode& secondRoot);
-
-// TypedElementDescendantIterator
+template<typename ElementType, bool filter(const ElementType&)> class FilteredElementDescendantIterator : public ElementIterator<ElementType> {
+public:
+    FilteredElementDescendantIterator(const ContainerNode&, ElementType* = nullptr);
+    FilteredElementDescendantIterator& operator++();
+};
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType>::TypedElementDescendantIterator(const ContainerNode& root)
-    : ElementIterator<ElementType>(&root)
-{
-}
+template<typename ElementType, bool filter(const ElementType&)> class FilteredElementDescendantRange {
+public:
+    using Iterator = FilteredElementDescendantIterator<ElementType, filter>;
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType>::TypedElementDescendantIterator(const ContainerNode& root, ElementType* current)
-    : ElementIterator<ElementType>(&root, current)
-{
-}
+    FilteredElementDescendantRange(const ContainerNode&);
+    Iterator begin() const;
+    static constexpr std::nullptr_t end() { return nullptr; }
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType>& TypedElementDescendantIterator<ElementType>::operator++()
-{
-    return static_cast<TypedElementDescendantIterator<ElementType>&>(ElementIterator<ElementType>::traverseNext());
-}
+    ElementType* first() const;
 
-// TypedElementDescendantConstIterator
+private:
+    const ContainerNode& m_root;
+};
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType>::TypedElementDescendantConstIterator(const ContainerNode& root)
-    : ElementConstIterator<ElementType>(&root)
+// ElementDescendantIterator
 
+template<typename ElementType> ElementDescendantIterator<ElementType>::ElementDescendantIterator(const ContainerNode& root, ElementType* current)
+    : ElementIterator<ElementType>(&root, current)
 {
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType>::TypedElementDescendantConstIterator(const ContainerNode& root, const ElementType* current)
-    : ElementConstIterator<ElementType>(&root, current)
+template<typename ElementType> ElementDescendantIterator<ElementType>& ElementDescendantIterator<ElementType>::operator++()
 {
+    ElementIterator<ElementType>::traverseNext();
+    return *this;
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType>& TypedElementDescendantConstIterator<ElementType>::operator++()
+template<typename ElementType> ElementDescendantIterator<ElementType>& ElementDescendantIterator<ElementType>::operator--()
 {
-    return static_cast<TypedElementDescendantConstIterator<ElementType>&>(ElementConstIterator<ElementType>::traverseNext());
+    ElementIterator<ElementType>::traversePrevious();
+    return *this;
 }
 
-// TypedElementDescendantIteratorAdapter
+// ElementDescendantRange
 
-template <typename ElementType>
-inline TypedElementDescendantIteratorAdapter<ElementType>::TypedElementDescendantIteratorAdapter(ContainerNode& root)
+template<typename ElementType> ElementDescendantRange<ElementType>::ElementDescendantRange(const ContainerNode& root)
     : m_root(root)
 {
 }
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType> TypedElementDescendantIteratorAdapter<ElementType>::begin()
+template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::begin() const
 {
-    return TypedElementDescendantIterator<ElementType>(m_root, Traversal<ElementType>::firstWithin(m_root));
+    return ElementDescendantIterator<ElementType>(m_root, Traversal<ElementType>::firstWithin(m_root));
 }
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType> TypedElementDescendantIteratorAdapter<ElementType>::end()
-{
-    return TypedElementDescendantIterator<ElementType>(m_root);
-}
-    
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType> TypedElementDescendantIteratorAdapter<ElementType>::beginAt(ElementType& descendant)
+template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::beginAt(ElementType& descendant) const
 {
     ASSERT(descendant.isDescendantOf(m_root));
-    return TypedElementDescendantIterator<ElementType>(m_root, &descendant);
+    return ElementDescendantIterator<ElementType>(m_root, &descendant);
 }
 
-template <typename ElementType>
-inline TypedElementDescendantIterator<ElementType> TypedElementDescendantIteratorAdapter<ElementType>::from(Element& descendant)
+template<typename ElementType> ElementDescendantIterator<ElementType> ElementDescendantRange<ElementType>::from(Element& descendant) const
 {
     ASSERT(descendant.isDescendantOf(m_root));
     if (is<ElementType>(descendant))
-        return TypedElementDescendantIterator<ElementType>(m_root, downcast<ElementType>(&descendant));
+        return ElementDescendantIterator<ElementType>(m_root, downcast<ElementType>(&descendant));
     ElementType* next = Traversal<ElementType>::next(descendant, &m_root);
-    return TypedElementDescendantIterator<ElementType>(m_root, next);
+    return ElementDescendantIterator<ElementType>(m_root, next);
 }
 
-template <typename ElementType>
-inline ElementType* TypedElementDescendantIteratorAdapter<ElementType>::first()
+template<typename ElementType> ElementType* ElementDescendantRange<ElementType>::first() const
 {
     return Traversal<ElementType>::firstWithin(m_root);
 }
 
-template <typename ElementType>
-inline ElementType* TypedElementDescendantIteratorAdapter<ElementType>::last()
+template<typename ElementType> ElementType* ElementDescendantRange<ElementType>::last() const
 {
     return Traversal<ElementType>::lastWithin(m_root);
 }
 
-// TypedElementDescendantConstIteratorAdapter
+// DoubleElementDescendantRange
 
-template <typename ElementType>
-inline TypedElementDescendantConstIteratorAdapter<ElementType>::TypedElementDescendantConstIteratorAdapter(const ContainerNode& root)
-    : m_root(root)
+template<typename ElementType> DoubleElementDescendantRange<ElementType>::DoubleElementDescendantRange(SingleAdapter&& first, SingleAdapter&& second)
+    : m_pair(WTFMove(first), WTFMove(second))
 {
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType> TypedElementDescendantConstIteratorAdapter<ElementType>::begin() const
+template<typename ElementType> auto DoubleElementDescendantRange<ElementType>::begin() const -> Iterator
 {
-    return TypedElementDescendantConstIterator<ElementType>(m_root, Traversal<ElementType>::firstWithin(m_root));
+    return Iterator(m_pair.first.begin(), m_pair.second.begin());
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType> TypedElementDescendantConstIteratorAdapter<ElementType>::end() const
-{
-    return TypedElementDescendantConstIterator<ElementType>(m_root);
-}
+// DoubleElementDescendantIterator
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType> TypedElementDescendantConstIteratorAdapter<ElementType>::beginAt(const ElementType& descendant) const
+template<typename ElementType> DoubleElementDescendantIterator<ElementType>::DoubleElementDescendantIterator(SingleIterator&& first, SingleIterator&& second)
+    : m_pair(WTFMove(first), WTFMove(second))
 {
-    ASSERT(descendant.isDescendantOf(m_root));
-    return TypedElementDescendantConstIterator<ElementType>(m_root, &descendant);
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIterator<ElementType> TypedElementDescendantConstIteratorAdapter<ElementType>::from(const Element& descendant) const
+template<typename ElementType> auto DoubleElementDescendantIterator<ElementType>::operator*() const -> ReferenceProxy
 {
-    ASSERT(descendant.isDescendantOf(m_root));
-    if (is<ElementType>(descendant))
-        return TypedElementDescendantConstIterator<ElementType>(m_root, downcast<ElementType>(&descendant));
-    const ElementType* next = Traversal<ElementType>::next(descendant, &m_root);
-    return TypedElementDescendantConstIterator<ElementType>(m_root, next);
+    return { *m_pair.first, *m_pair.second };
 }
 
-template <typename ElementType>
-inline const ElementType* TypedElementDescendantConstIteratorAdapter<ElementType>::first() const
+template<typename ElementType> constexpr bool DoubleElementDescendantIterator<ElementType>::operator!=(std::nullptr_t) const
 {
-    return Traversal<ElementType>::firstWithin(m_root);
+    ASSERT(!m_pair.first == !m_pair.second);
+    return m_pair.first;
 }
 
-template <typename ElementType>
-inline const ElementType* TypedElementDescendantConstIteratorAdapter<ElementType>::last() const
+template<typename ElementType> DoubleElementDescendantIterator<ElementType>& DoubleElementDescendantIterator<ElementType>::operator++()
 {
-    return Traversal<ElementType>::lastWithin(m_root);
+    ++m_pair.first;
+    ++m_pair.second;
+    return *this;
 }
 
-// DoubleTypedElementDescendantIteratorAdapter
+// FilteredElementDescendantIterator
 
-template<typename ElementType> inline DoubleTypedElementDescendantIteratorAdapter<ElementType>::DoubleTypedElementDescendantIteratorAdapter(SingleAdapter&& first, SingleAdapter&& second)
-    : m_pair(WTFMove(first), WTFMove(second))
+template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantIterator<ElementType, filter>::FilteredElementDescendantIterator(const ContainerNode& root, ElementType* element)
+    : ElementIterator<const ElementType> { &root, element }
 {
 }
 
-template<typename ElementType> inline auto DoubleTypedElementDescendantIteratorAdapter<ElementType>::begin() -> Iterator
+template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantIterator<ElementType, filter>& FilteredElementDescendantIterator<ElementType, filter>::operator++()
 {
-    return Iterator(m_pair.first.begin(), m_pair.second.begin());
-}
-
-template<typename ElementType> inline auto DoubleTypedElementDescendantIteratorAdapter<ElementType>::end() -> Iterator
-{
-    return Iterator(m_pair.first.end(), m_pair.second.end());
+    do {
+        ElementIterator<ElementType>::traverseNext();
+    } while (*this && !filter(**this));
+    return *this;
 }
 
-// DoubleTypedElementDescendantIterator
+// FilteredElementDescendantRange
 
-template<typename ElementType> inline DoubleTypedElementDescendantIterator<ElementType>::DoubleTypedElementDescendantIterator(SingleIterator&& first, SingleIterator&& second)
-    : m_pair(WTFMove(first), WTFMove(second))
+template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<ElementType, filter>::FilteredElementDescendantRange(const ContainerNode& root)
+    : m_root { root }
 {
 }
 
-template<typename ElementType> inline auto DoubleTypedElementDescendantIterator<ElementType>::operator*() const -> ReferenceProxy
+template<typename ElementType, bool filter(const ElementType&)> auto FilteredElementDescendantRange<ElementType, filter>::begin() const -> Iterator
 {
-    return { *m_pair.first, *m_pair.second };
+    return { m_root, first() };
 }
 
-template<typename ElementType> inline bool DoubleTypedElementDescendantIterator<ElementType>::operator==(const DoubleTypedElementDescendantIterator& other) const
+template<typename ElementType, bool filter(const ElementType&)> ElementType* FilteredElementDescendantRange<ElementType, filter>::first() const
 {
-    ASSERT((m_pair.first == other.m_pair.first) == (m_pair.second == other.m_pair.second));
-    return m_pair.first == other.m_pair.first || m_pair.second == other.m_pair.second;
+    for (auto* element = Traversal<ElementType>::firstWithin(m_root); element; element = Traversal<ElementType>::next(*element, &m_root)) {
+        if (filter(*element))
+            return element;
+    }
+    return nullptr;
 }
 
-template<typename ElementType> inline bool DoubleTypedElementDescendantIterator<ElementType>::operator!=(const DoubleTypedElementDescendantIterator& other) const
-{
-    return !(*this == other);
-}
+// Standalone functions
 
-template<typename ElementType> inline DoubleTypedElementDescendantIterator<ElementType>& DoubleTypedElementDescendantIterator<ElementType>::operator++()
+template<typename ElementType> ElementDescendantRange<ElementType> descendantsOfType(ContainerNode& root)
 {
-    ++m_pair.first;
-    ++m_pair.second;
-    return *this;
+    return ElementDescendantRange<ElementType>(root);
 }
 
-// Standalone functions
-
-template <typename ElementType>
-inline TypedElementDescendantIteratorAdapter<ElementType> descendantsOfType(ContainerNode& root)
+template<typename ElementType> ElementDescendantRange<const ElementType> descendantsOfType(const ContainerNode& root)
 {
-    return TypedElementDescendantIteratorAdapter<ElementType>(root);
+    return ElementDescendantRange<const ElementType>(root);
 }
 
-template <typename ElementType>
-inline TypedElementDescendantConstIteratorAdapter<ElementType> descendantsOfType(const ContainerNode& root)
+template<typename ElementType> DoubleElementDescendantRange<ElementType> descendantsOfType(ContainerNode& firstRoot, ContainerNode& secondRoot)
 {
-    return TypedElementDescendantConstIteratorAdapter<ElementType>(root);
+    return { descendantsOfType<ElementType>(firstRoot), descendantsOfType<ElementType>(secondRoot) };
 }
 
-template<typename ElementType> inline DoubleTypedElementDescendantIteratorAdapter<ElementType> descendantsOfType(ContainerNode& firstRoot, ContainerNode& secondRoot)
+template<typename ElementType, bool filter(const ElementType&)> FilteredElementDescendantRange<const ElementType, filter> filteredDescendants(const ContainerNode& root)
 {
-    return { descendantsOfType<ElementType>(firstRoot), descendantsOfType<ElementType>(secondRoot) };
+    return { root };
 }
 
 } // namespace WebCore
index 79f477d..0f06c0b 100644 (file)
@@ -25,7 +25,6 @@
 
 #pragma once
 
-#include "CollectionTraversal.h"
 #include "HTMLCollection.h"
 #include "HTMLElement.h"
 #include <wtf/IsoMalloc.h>
@@ -52,14 +51,14 @@ public:
     }
 
     // For CollectionIndexCache; do not use elsewhere.
-    using CollectionTraversalIterator = typename CollectionTraversal<traversalType>::Iterator;
-    CollectionTraversalIterator collectionBegin() const { return CollectionTraversal<traversalType>::begin(collection(), rootNode()); }
-    CollectionTraversalIterator collectionLast() const { return CollectionTraversal<traversalType>::last(collection(), rootNode()); }
-    CollectionTraversalIterator collectionEnd() const { return CollectionTraversal<traversalType>::end(rootNode()); }
-    void collectionTraverseForward(CollectionTraversalIterator& current, unsigned count, unsigned& traversedCount) const { CollectionTraversal<traversalType>::traverseForward(collection(), current, count, traversedCount); }
-    void collectionTraverseBackward(CollectionTraversalIterator& current, unsigned count) const { CollectionTraversal<traversalType>::traverseBackward(collection(), current, count); }
+    using Traversal = CollectionTraversal<traversalType>;
+    using Iterator = typename Traversal::Iterator;
+    auto collectionBegin() const { return Traversal::begin(collection(), rootNode()); }
+    auto collectionLast() const { return Traversal::last(collection(), rootNode()); }
+    void collectionTraverseForward(Iterator& current, unsigned count, unsigned& traversedCount) const { Traversal::traverseForward(collection(), current, count, traversedCount); }
+    void collectionTraverseBackward(Iterator& current, unsigned count) const { Traversal::traverseBackward(collection(), current, count); }
     bool collectionCanTraverseBackward() const { return traversalType != CollectionTraversalType::CustomForwardOnly; }
-    void willValidateIndexCache() const { document().registerCollection(const_cast<CachedHTMLCollection<HTMLCollectionClass, traversalType>&>(*this)); }
+    void willValidateIndexCache() const { document().registerCollection(const_cast<CachedHTMLCollection&>(*this)); }
 
     void invalidateCacheForDocument(Document&) override;
 
@@ -69,19 +68,19 @@ private:
     HTMLCollectionClass& collection() { return static_cast<HTMLCollectionClass&>(*this); }
     const HTMLCollectionClass& collection() const { return static_cast<const HTMLCollectionClass&>(*this); }
 
-    mutable CollectionIndexCache<HTMLCollectionClass, CollectionTraversalIterator> m_indexCache;
+    mutable CollectionIndexCache<HTMLCollectionClass, Iterator> m_indexCache;
 };
 
 template <typename HTMLCollectionClass, CollectionTraversalType traversalType>
 CachedHTMLCollection<HTMLCollectionClass, traversalType>::CachedHTMLCollection(ContainerNode& base, CollectionType collectionType)
     : HTMLCollection(base, collectionType)
-    , m_indexCache(collection())
-}
+{
+}
 
 template <typename HTMLCollectionClass, CollectionTraversalType traversalType>
 CachedHTMLCollection<HTMLCollectionClass, traversalType>::~CachedHTMLCollection()
 {
-    if (m_indexCache.hasValidCache(collection()))
+    if (m_indexCache.hasValidCache())
         document().unregisterCollection(*this);
 }
 
@@ -89,9 +88,9 @@ template <typename HTMLCollectionClass, CollectionTraversalType traversalType>
 void CachedHTMLCollection<HTMLCollectionClass, traversalType>::invalidateCacheForDocument(Document& document)
 {
     HTMLCollection::invalidateCacheForDocument(document);
-    if (m_indexCache.hasValidCache(collection())) {
+    if (m_indexCache.hasValidCache()) {
         document.unregisterCollection(*this);
-        m_indexCache.invalidate(collection());
+        m_indexCache.invalidate();
     }
 }
 
index 6682933..2a88f57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-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
@@ -26,8 +26,7 @@
 #pragma once
 
 #include "CollectionType.h"
-#include "ElementChildIterator.h"
-#include "ElementDescendantIterator.h"
+#include "ElementIterator.h"
 
 namespace WebCore {
 
@@ -36,76 +35,64 @@ struct CollectionTraversal { };
 
 template <>
 struct CollectionTraversal<CollectionTraversalType::Descendants> {
-    using Iterator = ElementDescendantIterator;
-
-    static ElementDescendantIterator end(ContainerNode&) { return ElementDescendantIterator(); }
+    using Iterator = ElementDescendantIterator<Element>;
 
     template <typename CollectionClass>
-    static ElementDescendantIterator begin(const CollectionClass&, ContainerNode& rootNode);
+    static Iterator begin(const CollectionClass&, ContainerNode& rootNode);
 
     template <typename CollectionClass>
-    static ElementDescendantIterator last(const CollectionClass&, ContainerNode& rootNode);
+    static Iterator last(const CollectionClass&, ContainerNode& rootNode);
 
     template <typename CollectionClass>
-    static void traverseForward(const CollectionClass&, ElementDescendantIterator& current, unsigned count, unsigned& traversedCount);
+    static void traverseForward(const CollectionClass&, Iterator& current, unsigned count, unsigned& traversedCount);
 
     template <typename CollectionClass>
-    static void traverseBackward(const CollectionClass&, ElementDescendantIterator& current, unsigned count);
+    static void traverseBackward(const CollectionClass&, Iterator& current, unsigned count);
 };
 
 template <typename CollectionClass>
-inline ElementDescendantIterator CollectionTraversal<CollectionTraversalType::Descendants>::begin(const CollectionClass& collection, ContainerNode& rootNode)
+inline auto CollectionTraversal<CollectionTraversalType::Descendants>::begin(const CollectionClass& collection, ContainerNode& rootNode) -> Iterator
 {
-    auto descendants = elementDescendants(rootNode);
-    auto end = descendants.end();
-    for (auto it = descendants.begin(); it != end; ++it) {
-        if (collection.elementMatches(*it)) {
-            // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
-            it.dropAssertions();
-            return it;
-        }
-    }
-    return end;
+    auto it = descendantsOfType<Element>(rootNode).begin();
+    while (it && !collection.elementMatches(*it))
+        ++it;
+    // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
+    it.dropAssertions();
+    return it;
 }
 
 template <typename CollectionClass>
-inline ElementDescendantIterator CollectionTraversal<CollectionTraversalType::Descendants>::last(const CollectionClass& collection, ContainerNode& rootNode)
+inline auto CollectionTraversal<CollectionTraversalType::Descendants>::last(const CollectionClass& collection, ContainerNode& rootNode) -> Iterator
 {
-    auto descendants = elementDescendants(rootNode);
-    ElementDescendantIterator invalid;
-    for (auto it = descendants.last(); it != invalid; --it) {
-        if (collection.elementMatches(*it)) {
-            // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
-            it.dropAssertions();
-            return it;
-        }
-    }
-    return invalid;
+    Iterator it { rootNode, ElementTraversal::lastWithin(rootNode) };
+    while (it && !collection.elementMatches(*it))
+        --it;
+    // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
+    it.dropAssertions();
+    return it;
 }
 
 template <typename CollectionClass>
-inline void CollectionTraversal<CollectionTraversalType::Descendants>::traverseForward(const CollectionClass& collection, ElementDescendantIterator& current, unsigned count, unsigned& traversedCount)
+inline void CollectionTraversal<CollectionTraversalType::Descendants>::traverseForward(const CollectionClass& collection, Iterator& current, unsigned count, unsigned& traversedCount)
 {
     ASSERT(collection.elementMatches(*current));
-    ElementDescendantIterator invalid;
     for (traversedCount = 0; traversedCount < count; ++traversedCount) {
         do {
             ++current;
-            if (current == invalid)
+            if (!current)
                 return;
         } while (!collection.elementMatches(*current));
     }
 }
 
 template <typename CollectionClass>
-inline void CollectionTraversal<CollectionTraversalType::Descendants>::traverseBackward(const CollectionClass& collection, ElementDescendantIterator& current, unsigned count)
+inline void CollectionTraversal<CollectionTraversalType::Descendants>::traverseBackward(const CollectionClass& collection, Iterator& current, unsigned count)
 {
     ASSERT(collection.elementMatches(*current));
-    ElementDescendantIterator invalid;
     for (; count; --count) {
         do {
             --current;
-            if (current == invalid)
+            if (!current)
                 return;
         } while (!collection.elementMatches(*current));
     }
@@ -115,75 +102,62 @@ template <>
 struct CollectionTraversal<CollectionTraversalType::ChildrenOnly> {
     using Iterator = ElementChildIterator<Element>;
 
-    static ElementChildIterator<Element> end(ContainerNode& rootNode) { return ElementChildIterator<Element>(rootNode); }
-
     template <typename CollectionClass>
-    static ElementChildIterator<Element> begin(const CollectionClass&, ContainerNode& rootNode);
+    static Iterator begin(const CollectionClass&, ContainerNode& rootNode);
 
     template <typename CollectionClass>
-    static ElementChildIterator<Element> last(const CollectionClass&, ContainerNode& rootNode);
+    static Iterator last(const CollectionClass&, ContainerNode& rootNode);
 
     template <typename CollectionClass>
-    static void traverseForward(const CollectionClass&, ElementChildIterator<Element>& current, unsigned count, unsigned& traversedCount);
+    static void traverseForward(const CollectionClass&, Iterator& current, unsigned count, unsigned& traversedCount);
 
     template <typename CollectionClass>
-    static void traverseBackward(const CollectionClass&, ElementChildIterator<Element>& current, unsigned count);
+    static void traverseBackward(const CollectionClass&, Iterator& current, unsigned count);
 };
 
 template <typename CollectionClass>
-inline ElementChildIterator<Element> CollectionTraversal<CollectionTraversalType::ChildrenOnly>::begin(const CollectionClass& collection, ContainerNode& rootNode)
+inline auto CollectionTraversal<CollectionTraversalType::ChildrenOnly>::begin(const CollectionClass& collection, ContainerNode& rootNode) -> Iterator
 {
-    auto children = childrenOfType<Element>(rootNode);
-    auto end = children.end();
-    for (auto it = children.begin(); it != end; ++it) {
-        if (collection.elementMatches(*it)) {
-            // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
-            it.dropAssertions();
-            return it;
-        }
-    }
-    return end;
+    auto it = childrenOfType<Element>(rootNode).begin();
+    while (it && !collection.elementMatches(*it))
+        ++it;
+    // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
+    it.dropAssertions();
+    return it;
 }
 
 template <typename CollectionClass>
-inline ElementChildIterator<Element> CollectionTraversal<CollectionTraversalType::ChildrenOnly>::last(const CollectionClass& collection, ContainerNode& rootNode)
+inline auto CollectionTraversal<CollectionTraversalType::ChildrenOnly>::last(const CollectionClass& collection, ContainerNode& rootNode) -> Iterator
 {
-    auto children = childrenOfType<Element>(rootNode);
-    ElementChildIterator<Element> invalid(collection.rootNode());
-    ElementChildIterator<Element> last(rootNode, children.last());
-    for (auto it = last; it != invalid; --it) {
-        if (collection.elementMatches(*it)) {
-            // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
-            it.dropAssertions();
-            return it;
-        }
-    }
-    return invalid;
+    auto it = childrenOfType<Element>(rootNode).begin();
+    while (it && !collection.elementMatches(*it))
+        --it;
+    // Drop iterator assertions because HTMLCollections / NodeList use a fine-grained invalidation scheme.
+    it.dropAssertions();
+    return it;
 }
 
 template <typename CollectionClass>
-inline void CollectionTraversal<CollectionTraversalType::ChildrenOnly>::traverseForward(const CollectionClass& collection, ElementChildIterator<Element>& current, unsigned count, unsigned& traversedCount)
+inline void CollectionTraversal<CollectionTraversalType::ChildrenOnly>::traverseForward(const CollectionClass& collection, Iterator& current, unsigned count, unsigned& traversedCount)
 {
     ASSERT(collection.elementMatches(*current));
-    ElementChildIterator<Element> invalid(collection.rootNode());
     for (traversedCount = 0; traversedCount < count; ++traversedCount) {
         do {
             ++current;
-            if (current == invalid)
+            if (!current)
                 return;
         } while (!collection.elementMatches(*current));
     }
 }
 
 template <typename CollectionClass>
-inline void CollectionTraversal<CollectionTraversalType::ChildrenOnly>::traverseBackward(const CollectionClass& collection, ElementChildIterator<Element>& current, unsigned count)
+inline void CollectionTraversal<CollectionTraversalType::ChildrenOnly>::traverseBackward(const CollectionClass& collection, Iterator& current, unsigned count)
 {
     ASSERT(collection.elementMatches(*current));
-    ElementChildIterator<Element> invalid(collection.rootNode());
     for (; count; --count) {
         do {
             --current;
-            if (current == invalid)
+            if (!current)
                 return;
         } while (!collection.elementMatches(*current));
     }
@@ -193,7 +167,7 @@ template <>
 struct CollectionTraversal<CollectionTraversalType::CustomForwardOnly> {
     using Iterator = Element*;
 
-    static Element* end(ContainerNode&) { return nullptr; }
+    static constexpr Element* end(ContainerNode&) { return nullptr; }
 
     template <typename CollectionClass>
     static Element* begin(const CollectionClass&, ContainerNode&);
index 774e54f..902730e 100644 (file)
@@ -63,7 +63,7 @@ private:
 
 inline HTMLElement* HTMLFormControlsCollection::item(unsigned offset) const
 {
-    return downcast<HTMLElement>(CachedHTMLCollection<HTMLFormControlsCollection, CollectionTypeTraits<FormControls>::traversalType>::item(offset));
+    return downcast<HTMLElement>(CachedHTMLCollection::item(offset));
 }
 
 } // namespace WebCore
index e7e414c..2d093ef 100644 (file)
@@ -509,14 +509,13 @@ unsigned HTMLFormElement::formElementIndex(FormAssociatedElement* associatedElem
     if (!associatedHTMLElement.isDescendantOf(*this))
         return currentAssociatedElementsAfterIndex;
 
+    auto descendants = descendantsOfType<HTMLElement>(*this);
+
     // Check for the special case where this element is the very last thing in
     // the form's tree of children; we don't want to walk the entire tree in that
     // common case that occurs during parsing; instead we'll just return a value
     // that says "add this form element to the end of the array".
-    auto descendants = descendantsOfType<HTMLElement>(*this);
-    auto it = descendants.beginAt(associatedHTMLElement);
-    auto end = descendants.end();
-    if (++it == end)
+    if (!++descendants.beginAt(associatedHTMLElement))
         return currentAssociatedElementsAfterIndex;
 
     unsigned i = m_associatedElementsBeforeIndex;
index 9e7a964..3f75784 100644 (file)
@@ -4653,7 +4653,7 @@ URL HTMLMediaElement::selectNextSourceChild(ContentType* contentType, String* ke
     // each still is a child of this media element before using.
     Vector<Ref<HTMLSourceElement>> potentialSourceNodes;
     auto sources = childrenOfType<HTMLSourceElement>(*this);
-    for (auto next = m_nextChildNodeToConsider ? sources.beginAt(*m_nextChildNodeToConsider) : sources.begin(), end = sources.end(); next != end; ++next)
+    for (auto next = m_nextChildNodeToConsider ? sources.beginAt(*m_nextChildNodeToConsider) : sources.begin(); next; ++next)
         potentialSourceNodes.append(*next);
 
     for (auto& source : potentialSourceNodes) {
index e516a81..4999c15 100644 (file)
@@ -26,7 +26,6 @@
 #include "HTMLTableSectionElement.h"
 
 #include "GenericCachedHTMLCollection.h"
-#include "HTMLCollection.h"
 #include "HTMLNames.h"
 #include "HTMLTableRowElement.h"
 #include "HTMLTableElement.h"
@@ -95,7 +94,7 @@ ExceptionOr<void> HTMLTableSectionElement::deleteRow(int index)
 int HTMLTableSectionElement::numRows() const
 {
     auto rows = childrenOfType<HTMLTableRowElement>(*this);
-    return std::distance(rows.begin(), rows.end());
+    return std::distance(rows.begin(), { });
 }
 
 Ref<HTMLCollection> HTMLTableSectionElement::rows()
index d410178..919a28e 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2007, 2008, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Nokia Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
@@ -24,9 +24,9 @@
 #include "config.h"
 #include "LabelsNodeList.h"
 
-#include "Element.h"
 #include "HTMLLabelElement.h"
 #include "HTMLNames.h"
+#include "LabelableElement.h"
 #include "NodeRareData.h"
 #include <wtf/IsoMallocInlines.h>
 
@@ -36,11 +36,16 @@ using namespace HTMLNames;
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(LabelsNodeList);
 
-LabelsNodeList::LabelsNodeList(LabelableElement& forNode)
-    : CachedLiveNodeList(forNode, InvalidateOnForTypeAttrChange)
+LabelsNodeList::LabelsNodeList(LabelableElement& element)
+    : CachedLiveNodeList(element, InvalidateOnForTypeAttrChange)
 {
 }
 
+Ref<LabelsNodeList> LabelsNodeList::create(LabelableElement& element, const AtomString&)
+{
+    return adoptRef(*new LabelsNodeList(element));
+}
+
 LabelsNodeList::~LabelsNodeList()
 {
     ownerNode().nodeLists()->removeCacheWithAtomName(*this, starAtom());
index f539d79..80d977f 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
- * Copyright (C) 2004, 2007, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2004-2020 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Nokia Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
 
 #pragma once
 
-#include "LabelableElement.h"
 #include "LiveNodeList.h"
 
 namespace WebCore {
 
+class LabelableElement;
+
 class LabelsNodeList final : public CachedLiveNodeList<LabelsNodeList> {
     WTF_MAKE_ISO_ALLOCATED(LabelsNodeList);
 public:
-    static Ref<LabelsNodeList> create(LabelableElement& forNode, const AtomString&)
-    {
-        return adoptRef(*new LabelsNodeList(forNode));
-    }
-    ~LabelsNodeList();
+    static Ref<LabelsNodeList> create(LabelableElement&, const AtomString&);
+    virtual ~LabelsNodeList();
 
-    bool elementMatches(Element&) const override;
-    bool isRootedAtDocument() const override { return true; }
+    bool elementMatches(Element&) const final;
+    bool isRootedAtDocument() const final { return true; }
 
 private:
-    explicit LabelsNodeList(LabelableElement& forNode);
+    explicit LabelsNodeList(LabelableElement&);
 };
 
 } // namespace WebCore
index 9470ea2..dd2c81e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012 Motorola Mobility, Inc. All rights reserved.
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-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
@@ -29,7 +29,6 @@
 
 #include "HTMLFormElement.h"
 #include "HTMLInputElement.h"
-#include "HTMLNames.h"
 #include "HTMLObjectElement.h"
 #include "NodeRareData.h"
 #include <wtf/IsoMallocInlines.h>
@@ -43,16 +42,21 @@ WTF_MAKE_ISO_ALLOCATED_IMPL(RadioNodeList);
 RadioNodeList::RadioNodeList(ContainerNode& rootNode, const AtomString& name)
     : CachedLiveNodeList(rootNode, InvalidateForFormControls)
     , m_name(name)
-    , m_isRootedAtDocument(is<HTMLFormElement>(ownerNode()))
+    , m_isRootedAtDocument(is<HTMLFormElement>(rootNode))
 {
 }
 
+Ref<RadioNodeList> RadioNodeList::create(ContainerNode& rootNode, const AtomString& name)
+{
+    return adoptRef(*new RadioNodeList(rootNode, name));
+}
+
 RadioNodeList::~RadioNodeList()
 {
     ownerNode().nodeLists()->removeCacheWithAtomName(*this, m_name);
 }
 
-static inline RefPtr<HTMLInputElement> toRadioButtonInputElement(HTMLElement& element)
+static RefPtr<HTMLInputElement> nonEmptyRadioButton(Element& element)
 {
     if (!is<HTMLInputElement>(element))
         return nullptr;
@@ -67,10 +71,10 @@ String RadioNodeList::value() const
 {
     auto length = this->length();
     for (unsigned i = 0; i < length; ++i) {
-        auto inputElement = toRadioButtonInputElement(*item(i));
-        if (!inputElement || !inputElement->checked())
-            continue;
-        return inputElement->value();
+        if (auto button = nonEmptyRadioButton(*item(i))) {
+            if (button->checked())
+                return button->value();
+        }
     }
     return String();
 }
@@ -79,40 +83,34 @@ void RadioNodeList::setValue(const String& value)
 {
     auto length = this->length();
     for (unsigned i = 0; i < length; ++i) {
-        auto inputElement = toRadioButtonInputElement(*item(i));
-        if (!inputElement || inputElement->value() != value)
-            continue;
-        inputElement->setChecked(true);
-        return;
+        if (auto button = nonEmptyRadioButton(*item(i))) {
+            if (button->value() == value) {
+                button->setChecked(true);
+                return;
+            }
+        }
     }
 }
 
-bool RadioNodeList::checkElementMatchesRadioNodeListFilter(const Element& testElement) const
+bool RadioNodeList::elementMatches(Element& element) const
 {
-    ASSERT(is<HTMLObjectElement>(testElement) || is<HTMLFormControlElement>(testElement));
+    if (!is<HTMLObjectElement>(element) && !is<HTMLFormControlElement>(element))
+        return false;
+
+    if (is<HTMLInputElement>(element) && downcast<HTMLInputElement>(element).isImageButton())
+        return false;
+
     if (is<HTMLFormElement>(ownerNode())) {
-        RefPtr<HTMLFormElement> formElement;
-        if (testElement.hasTagName(objectTag))
-            formElement = downcast<HTMLObjectElement>(testElement).form();
+        RefPtr<HTMLFormElement> form;
+        if (is<HTMLObjectElement>(element))
+            form = downcast<HTMLObjectElement>(element).form();
         else
-            formElement = downcast<HTMLFormControlElement>(testElement).form();
-        if (!formElement || formElement != &ownerNode())
+            form = downcast<HTMLFormControlElement>(element).form();
+        if (!form || form != &ownerNode())
             return false;
     }
 
-    return testElement.getIdAttribute() == m_name || testElement.getNameAttribute() == m_name;
+    return element.getIdAttribute() == m_name || element.getNameAttribute() == m_name;
 }
 
-bool RadioNodeList::elementMatches(Element& testElement) const
-{
-    if (!is<HTMLObjectElement>(testElement) && !is<HTMLFormControlElement>(testElement))
-        return false;
-
-    if (is<HTMLInputElement>(testElement) && downcast<HTMLInputElement>(testElement).isImageButton())
-        return false;
-
-    return checkElementMatchesRadioNodeListFilter(testElement);
-}
-
-} // namspace
-
+} // namespace WebCore
index a302763..64477c8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 2012 Motorola Mobility, Inc. All rights reserved.
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-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
 
 #pragma once
 
-#include "HTMLElement.h"
 #include "LiveNodeList.h"
-#include <wtf/text/AtomString.h>
 
 namespace WebCore {
 
 class RadioNodeList final : public CachedLiveNodeList<RadioNodeList> {
     WTF_MAKE_ISO_ALLOCATED(RadioNodeList);
 public:
-    static Ref<RadioNodeList> create(ContainerNode& rootNode, const AtomString& name)
-    {
-        return adoptRef(*new RadioNodeList(rootNode, name));
-    }
-
+    static Ref<RadioNodeList> create(ContainerNode& rootNode, const AtomString& name);
     virtual ~RadioNodeList();
 
-    HTMLElement* item(unsigned offset) const override;
-
     String value() const;
     void setValue(const String&);
-
-    bool elementMatches(Element&) const override;
-    bool isRootedAtDocument() const override { return m_isRootedAtDocument; }
+    bool elementMatches(Element&) const final;
 
 private:
     RadioNodeList(ContainerNode&, const AtomString& name);
-    bool checkElementMatchesRadioNodeListFilter(const Element&) const;
+    bool isRootedAtDocument() const final { return m_isRootedAtDocument; }
 
     AtomString m_name;
     bool m_isRootedAtDocument;
 };
 
-inline HTMLElement* RadioNodeList::item(unsigned offset) const
-{
-    return downcast<HTMLElement>(CachedLiveNodeList<RadioNodeList>::item(offset));
-}
-
-} // namepsace WebCore
+} // namespace WebCore
index 5e99fbb..6bef448 100644 (file)
@@ -175,8 +175,7 @@ void Invalidator::invalidateStyleForDescendants(Element& root, SelectorFilter* f
 {
     Vector<Element*, 20> parentStack;
     Element* previousElement = &root;
-    auto descendants = descendantsOfType<Element>(root);
-    for (auto it = descendants.begin(), end = descendants.end(); it != end;) {
+    for (auto it = descendantsOfType<Element>(root).begin(); it; ) {
         auto& descendant = *it;
         auto* parent = descendant.parentElement();
         if (parentStack.isEmpty() || parentStack.last() != parent) {
@@ -275,12 +274,10 @@ void Invalidator::invalidateStyleWithMatchElement(Element& element, MatchElement
         for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling())
             invalidateIfNeeded(*sibling, nullptr);
         break;
-    case MatchElement::AnySibling: {
-        auto parentChildren = childrenOfType<Element>(*element.parentNode());
-        for (auto& parentChild : parentChildren)
+    case MatchElement::AnySibling:
+        for (auto& parentChild : childrenOfType<Element>(*element.parentNode()))
             invalidateIfNeeded(parentChild, nullptr);
         break;
-    }
     case MatchElement::ParentSibling:
         for (auto* sibling = element.nextElementSibling(); sibling; sibling = sibling->nextElementSibling()) {
             auto siblingChildren = childrenOfType<Element>(*sibling);
index 1e75533..c69745d 100644 (file)
@@ -331,8 +331,7 @@ static void removeDisallowedElementsFromSubtree(SVGElement& subtree)
     ASSERT(!subtree.isConnected());
 
     Vector<Element*> disallowedElements;
-    auto descendants = descendantsOfType<Element>(subtree);
-    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
+    for (auto it = descendantsOfType<Element>(subtree).begin(); it; ) {
         if (isDisallowedElement(*it)) {
             disallowedElements.append(&*it);
             it.traverseNextSkippingChildren();
@@ -452,9 +451,9 @@ static void cloneDataAndChildren(SVGElement& replacementClone, SVGElement& origi
 void SVGUseElement::expandUseElementsInShadowTree() const
 {
     auto descendants = descendantsOfType<SVGUseElement>(*userAgentShadowRoot());
-    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
+    for (auto it = descendants.begin(); it; ) {
         SVGUseElement& originalClone = *it;
-        it = end; // Efficiently quiets assertions due to the outstanding iterator.
+        it.dropAssertions();
 
         auto* target = originalClone.findTarget();
 
@@ -485,9 +484,9 @@ void SVGUseElement::expandUseElementsInShadowTree() const
 void SVGUseElement::expandSymbolElementsInShadowTree() const
 {
     auto descendants = descendantsOfType<SVGSymbolElement>(*userAgentShadowRoot());
-    for (auto it = descendants.begin(), end = descendants.end(); it != end; ) {
+    for (auto it = descendants.begin(); it; ) {
         SVGSymbolElement& originalClone = *it;
-        it = end; // Efficiently quiets assertions due to the outstanding iterator.
+        it.dropAssertions();
 
         // Spec: The referenced 'symbol' and its contents are deep-cloned into the generated tree,
         // with the exception that the 'symbol' is replaced by an 'svg'. This generated 'svg' will