1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "mozilla/Attributes.h"
11 #include "nsIContent.h"
14 * A generic pre-order tree iterator on top of ChildIterator.
16 * See ChildIterator.h for the kind of iterators you can use as the template
17 * argument for this class.
23 template <typename ChildIterator
>
24 class MOZ_STACK_CLASS TreeIterator
{
25 enum class Direction
{
30 template <Direction aDirection
>
31 nsIContent
* GetNextChild(ChildIterator
& aIter
) {
32 return aDirection
== Direction::Forward
? aIter
.GetNextChild()
33 : aIter
.GetPreviousChild();
37 inline void Advance();
39 inline void AdvanceSkippingChildren();
42 explicit TreeIterator(nsIContent
& aRoot
) : mRoot(aRoot
), mCurrent(&aRoot
) {}
44 nsIContent
* GetCurrent() const { return mCurrent
; }
46 // Note that this keeps the iterator state consistent in case of failure.
47 inline bool Seek(nsIContent
&);
48 inline nsIContent
* GetNext();
49 inline nsIContent
* GetNextSkippingChildren();
50 inline nsIContent
* GetPrev();
51 inline nsIContent
* GetPrevSkippingChildren();
54 using IteratorArray
= AutoTArray
<ChildIterator
, 30>;
58 IteratorArray mParentIterators
;
61 template <typename ChildIterator
>
62 template <typename TreeIterator
<ChildIterator
>::Direction aDirection
>
63 inline void TreeIterator
<ChildIterator
>::AdvanceSkippingChildren() {
65 if (MOZ_UNLIKELY(mParentIterators
.IsEmpty())) {
70 if (nsIContent
* nextSibling
=
71 GetNextChild
<aDirection
>(mParentIterators
.LastElement())) {
72 mCurrent
= nextSibling
;
75 mParentIterators
.RemoveLastElement();
79 template <typename ChildIterator
>
80 inline bool TreeIterator
<ChildIterator
>::Seek(nsIContent
& aContent
) {
81 IteratorArray parentIterators
;
82 nsIContent
* current
= &aContent
;
83 while (current
!= &mRoot
) {
84 nsIContent
* parent
= ChildIterator::GetParent(*current
);
89 ChildIterator
children(parent
);
90 if (!children
.Seek(current
)) {
94 parentIterators
.AppendElement(std::move(children
));
98 parentIterators
.Reverse();
100 mParentIterators
= std::move(parentIterators
);
101 mCurrent
= &aContent
;
105 template <typename ChildIterator
>
106 template <typename TreeIterator
<ChildIterator
>::Direction aDirection
>
107 inline void TreeIterator
<ChildIterator
>::Advance() {
108 MOZ_ASSERT(mCurrent
);
109 const bool startAtBeginning
= aDirection
== Direction::Forward
;
110 ChildIterator
children(mCurrent
, startAtBeginning
);
111 if (nsIContent
* first
= GetNextChild
<aDirection
>(children
)) {
113 mParentIterators
.AppendElement(std::move(children
));
117 AdvanceSkippingChildren
<aDirection
>();
120 template <typename ChildIterator
>
121 inline nsIContent
* TreeIterator
<ChildIterator
>::GetNext() {
122 Advance
<Direction::Forward
>();
126 template <typename ChildIterator
>
127 inline nsIContent
* TreeIterator
<ChildIterator
>::GetPrev() {
128 Advance
<Direction::Backwards
>();
132 template <typename ChildIterator
>
133 inline nsIContent
* TreeIterator
<ChildIterator
>::GetNextSkippingChildren() {
134 AdvanceSkippingChildren
<Direction::Forward
>();
138 template <typename ChildIterator
>
139 inline nsIContent
* TreeIterator
<ChildIterator
>::GetPrevSkippingChildren() {
140 AdvanceSkippingChildren
<Direction::Backwards
>();
145 } // namespace mozilla