OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Apple Inc. All rights reserved. | 2 * Copyright (C) 2013 Apple Inc. All rights reserved. |
3 * Copyright (C) 2014 Samsung Electronics. All rights reserved. | 3 * Copyright (C) 2014 Samsung Electronics. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
57 return !cachedNodeIndex() && !nodeAt(collection, 1); | 57 return !cachedNodeIndex() && !nodeAt(collection, 1); |
58 return nodeAt(collection, 0) && !nodeAt(collection, 1); | 58 return nodeAt(collection, 0) && !nodeAt(collection, 1); |
59 } | 59 } |
60 | 60 |
61 unsigned nodeCount(const Collection&); | 61 unsigned nodeCount(const Collection&); |
62 NodeType* nodeAt(const Collection&, unsigned index); | 62 NodeType* nodeAt(const Collection&, unsigned index); |
63 | 63 |
64 void invalidate(); | 64 void invalidate(); |
65 | 65 |
66 private: | 66 private: |
67 NodeType* nodeBeforeOrAfterCachedNode(const Collection&, unsigned index, con
st ContainerNode& root); | 67 NodeType* nodeBeforeCachedNode(const Collection&, unsigned index, const Cont
ainerNode& root); |
68 bool isLastNodeCloserThanLastOrCachedNode(unsigned index) const; | 68 NodeType* nodeAfterCachedNode(const Collection&, unsigned index, const Conta
inerNode& root); |
69 bool isFirstNodeCloserThanCachedNode(unsigned index) const; | |
70 | 69 |
71 ALWAYS_INLINE NodeType* cachedNode() const { return m_currentNode; } | 70 ALWAYS_INLINE NodeType* cachedNode() const { return m_currentNode; } |
72 ALWAYS_INLINE unsigned cachedNodeIndex() const { ASSERT(cachedNode()); retur
n m_cachedNodeIndex; } | 71 ALWAYS_INLINE unsigned cachedNodeIndex() const { ASSERT(cachedNode()); retur
n m_cachedNodeIndex; } |
73 ALWAYS_INLINE void setCachedNode(NodeType* node, unsigned index) | 72 ALWAYS_INLINE void setCachedNode(NodeType* node, unsigned index) |
74 { | 73 { |
75 ASSERT(node); | 74 ASSERT(node); |
76 m_currentNode = node; | 75 m_currentNode = node; |
77 m_cachedNodeIndex = index; | 76 m_cachedNodeIndex = index; |
78 } | 77 } |
79 | 78 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
115 | 114 |
116 nodeAt(collection, UINT_MAX); | 115 nodeAt(collection, UINT_MAX); |
117 ASSERT(isCachedNodeCountValid()); | 116 ASSERT(isCachedNodeCountValid()); |
118 | 117 |
119 return cachedNodeCount(); | 118 return cachedNodeCount(); |
120 } | 119 } |
121 | 120 |
122 template <typename Collection, typename NodeType> | 121 template <typename Collection, typename NodeType> |
123 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeAt(const Collec
tion& collection, unsigned index) | 122 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeAt(const Collec
tion& collection, unsigned index) |
124 { | 123 { |
125 if (cachedNode() && cachedNodeIndex() == index) | 124 if (isCachedNodeCountValid() && index >= cachedNodeCount()) |
126 return cachedNode(); | |
127 | |
128 if (isCachedNodeCountValid() && cachedNodeCount() <= index) | |
129 return 0; | 125 return 0; |
130 | 126 |
131 ContainerNode& root = collection.rootNode(); | 127 ContainerNode& root = collection.rootNode(); |
132 if (isCachedNodeCountValid() && collection.canTraverseBackward() && isLastNo
deCloserThanLastOrCachedNode(index)) { | 128 if (cachedNode()) { |
133 NodeType* lastNode = collection.itemBefore(0); | 129 if (index > cachedNodeIndex()) |
134 ASSERT(lastNode); | 130 return nodeAfterCachedNode(collection, index, root); |
135 setCachedNode(lastNode, cachedNodeCount() - 1); | 131 if (index < cachedNodeIndex()) |
136 } else if (!cachedNode() || isFirstNodeCloserThanCachedNode(index) || (!coll
ection.canTraverseBackward() && index < cachedNodeIndex())) { | 132 return nodeBeforeCachedNode(collection, index, root); |
137 NodeType* firstNode = collection.traverseToFirstElement(root); | 133 return cachedNode(); |
138 if (!firstNode) { | |
139 setCachedNodeCount(0); | |
140 return 0; | |
141 } | |
142 setCachedNode(firstNode, 0); | |
143 ASSERT(!cachedNodeIndex()); | |
144 } | 134 } |
145 | 135 |
146 if (cachedNodeIndex() == index) | 136 // No valid cache yet, let's find the first matching element. |
147 return cachedNode(); | 137 ASSERT(!isCachedNodeCountValid()); |
148 | 138 NodeType* firstNode = collection.traverseToFirstElement(root); |
149 return nodeBeforeOrAfterCachedNode(collection, index, root); | 139 if (!firstNode) { |
| 140 // The collection is empty. |
| 141 setCachedNodeCount(0); |
| 142 return 0; |
| 143 } |
| 144 setCachedNode(firstNode, 0); |
| 145 return index ? nodeAfterCachedNode(collection, index, root) : firstNode; |
150 } | 146 } |
151 | 147 |
152 template <typename Collection, typename NodeType> | 148 template <typename Collection, typename NodeType> |
153 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeBeforeOrAfterCa
chedNode(const Collection& collection, unsigned index, const ContainerNode &root
) | 149 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeBeforeCachedNod
e(const Collection& collection, unsigned index, const ContainerNode& root) |
154 { | 150 { |
| 151 ASSERT(cachedNode()); // Cache should be valid. |
155 unsigned currentIndex = cachedNodeIndex(); | 152 unsigned currentIndex = cachedNodeIndex(); |
156 NodeType* currentNode = cachedNode(); | 153 ASSERT(currentIndex > index); |
157 ASSERT(currentNode); | |
158 ASSERT(currentIndex != index); | |
159 | 154 |
160 if (index < cachedNodeIndex()) { | 155 // Determine if we should traverse from the beginning of the collection inst
ead of the cached node. |
161 ASSERT(collection.canTraverseBackward()); | 156 bool firstIsCloser = index < currentIndex - index; |
162 while ((currentNode = collection.itemBefore(currentNode))) { | 157 if (firstIsCloser || !collection.canTraverseBackward()) { |
163 ASSERT(currentIndex); | 158 NodeType* firstNode = collection.traverseToFirstElement(root); |
164 currentIndex--; | 159 ASSERT(firstNode); |
165 if (currentIndex == index) { | 160 setCachedNode(firstNode, 0); |
166 setCachedNode(currentNode, currentIndex); | 161 return index ? nodeAfterCachedNode(collection, index, root) : firstNode; |
167 return currentNode; | |
168 } | |
169 } | |
170 ASSERT_NOT_REACHED(); | |
171 return 0; | |
172 } | 162 } |
173 | 163 |
174 currentNode = collection.traverseForwardToOffset(index, *currentNode, curren
tIndex, root); | 164 // Backward traversal from the cached node to the requested index. |
| 165 NodeType* currentNode = cachedNode(); |
| 166 ASSERT(collection.canTraverseBackward()); |
| 167 while ((currentNode = collection.itemBefore(currentNode))) { |
| 168 ASSERT(currentIndex); |
| 169 --currentIndex; |
| 170 if (currentIndex == index) { |
| 171 setCachedNode(currentNode, currentIndex); |
| 172 return currentNode; |
| 173 } |
| 174 } |
| 175 ASSERT_NOT_REACHED(); |
| 176 return 0; |
| 177 } |
| 178 |
| 179 template <typename Collection, typename NodeType> |
| 180 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeAfterCachedNode
(const Collection& collection, unsigned index, const ContainerNode& root) |
| 181 { |
| 182 ASSERT(cachedNode()); // Cache should be valid. |
| 183 unsigned currentIndex = cachedNodeIndex(); |
| 184 ASSERT(currentIndex < index); |
| 185 |
| 186 // Determine if we should traverse from the end of the collection instead of
the cached node. |
| 187 bool lastIsCloser = isCachedNodeCountValid() && cachedNodeCount() - index <
index - currentIndex; |
| 188 if (lastIsCloser && collection.canTraverseBackward()) { |
| 189 NodeType* lastItem = collection.itemBefore(0); |
| 190 ASSERT(lastItem); |
| 191 setCachedNode(lastItem, cachedNodeCount() - 1); |
| 192 if (index < cachedNodeCount() - 1) |
| 193 return nodeBeforeCachedNode(collection, index, root); |
| 194 return lastItem; |
| 195 } |
| 196 |
| 197 // Forward traversal from the cached node to the requested index. |
| 198 NodeType* currentNode = collection.traverseForwardToOffset(index, *cachedNod
e(), currentIndex, root); |
175 if (!currentNode) { | 199 if (!currentNode) { |
176 // Did not find the node. On plus side, we now know the length. | 200 // Did not find the node. On plus side, we now know the length. |
177 setCachedNodeCount(currentIndex + 1); | 201 setCachedNodeCount(currentIndex + 1); |
178 return 0; | 202 return 0; |
179 } | 203 } |
180 setCachedNode(currentNode, currentIndex); | 204 setCachedNode(currentNode, currentIndex); |
181 return currentNode; | 205 return currentNode; |
182 } | 206 } |
183 | 207 |
184 template <typename Collection, typename NodeType> | |
185 ALWAYS_INLINE bool CollectionIndexCache<Collection, NodeType>::isLastNodeCloserT
hanLastOrCachedNode(unsigned index) const | |
186 { | |
187 ASSERT(isCachedNodeCountValid()); | |
188 unsigned distanceFromLastNode = cachedNodeCount() - index; | |
189 if (!cachedNode()) | |
190 return distanceFromLastNode < index; | |
191 | |
192 return cachedNodeIndex() < index && distanceFromLastNode < index - cachedNod
eIndex(); | |
193 } | |
194 | |
195 template <typename Collection, typename NodeType> | |
196 ALWAYS_INLINE bool CollectionIndexCache<Collection, NodeType>::isFirstNodeCloser
ThanCachedNode(unsigned index) const | |
197 { | |
198 if (cachedNodeIndex() < index) | |
199 return false; | |
200 | |
201 unsigned distanceFromCachedNode = cachedNodeIndex() - index; | |
202 return index < distanceFromCachedNode; | |
203 } | |
204 | |
205 } // namespace WebCore | 208 } // namespace WebCore |
206 | 209 |
207 #endif // CollectionIndexCache_h | 210 #endif // CollectionIndexCache_h |
OLD | NEW |