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* nodeBeforeCachedNode(const Collection&, unsigned index, const Cont
ainerNode& root); | 67 NodeType* nodeBeforeCachedNode(const Collection&, unsigned index); |
68 NodeType* nodeAfterCachedNode(const Collection&, unsigned index, const Conta
inerNode& root); | 68 NodeType* nodeAfterCachedNode(const Collection&, unsigned index); |
69 | 69 |
70 ALWAYS_INLINE NodeType* cachedNode() const { return m_currentNode; } | 70 ALWAYS_INLINE NodeType* cachedNode() const { return m_currentNode; } |
71 ALWAYS_INLINE unsigned cachedNodeIndex() const { ASSERT(cachedNode()); retur
n m_cachedNodeIndex; } | 71 ALWAYS_INLINE unsigned cachedNodeIndex() const { ASSERT(cachedNode()); retur
n m_cachedNodeIndex; } |
72 ALWAYS_INLINE void setCachedNode(NodeType* node, unsigned index) | 72 ALWAYS_INLINE void setCachedNode(NodeType* node, unsigned index) |
73 { | 73 { |
74 ASSERT(node); | 74 ASSERT(node); |
75 m_currentNode = node; | 75 m_currentNode = node; |
76 m_cachedNodeIndex = index; | 76 m_cachedNodeIndex = index; |
77 } | 77 } |
78 | 78 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 | 117 |
118 return cachedNodeCount(); | 118 return cachedNodeCount(); |
119 } | 119 } |
120 | 120 |
121 template <typename Collection, typename NodeType> | 121 template <typename Collection, typename NodeType> |
122 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) |
123 { | 123 { |
124 if (isCachedNodeCountValid() && index >= cachedNodeCount()) | 124 if (isCachedNodeCountValid() && index >= cachedNodeCount()) |
125 return 0; | 125 return 0; |
126 | 126 |
127 ContainerNode& root = collection.rootNode(); | |
128 if (cachedNode()) { | 127 if (cachedNode()) { |
129 if (index > cachedNodeIndex()) | 128 if (index > cachedNodeIndex()) |
130 return nodeAfterCachedNode(collection, index, root); | 129 return nodeAfterCachedNode(collection, index); |
131 if (index < cachedNodeIndex()) | 130 if (index < cachedNodeIndex()) |
132 return nodeBeforeCachedNode(collection, index, root); | 131 return nodeBeforeCachedNode(collection, index); |
133 return cachedNode(); | 132 return cachedNode(); |
134 } | 133 } |
135 | 134 |
136 // No valid cache yet, let's find the first matching element. | 135 // No valid cache yet, let's find the first matching element. |
137 ASSERT(!isCachedNodeCountValid()); | 136 ASSERT(!isCachedNodeCountValid()); |
138 NodeType* firstNode = collection.traverseToFirstElement(root); | 137 NodeType* firstNode = collection.traverseToFirstElement(); |
139 if (!firstNode) { | 138 if (!firstNode) { |
140 // The collection is empty. | 139 // The collection is empty. |
141 setCachedNodeCount(0); | 140 setCachedNodeCount(0); |
142 return 0; | 141 return 0; |
143 } | 142 } |
144 setCachedNode(firstNode, 0); | 143 setCachedNode(firstNode, 0); |
145 return index ? nodeAfterCachedNode(collection, index, root) : firstNode; | 144 return index ? nodeAfterCachedNode(collection, index) : firstNode; |
146 } | 145 } |
147 | 146 |
148 template <typename Collection, typename NodeType> | 147 template <typename Collection, typename NodeType> |
149 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeBeforeCachedNod
e(const Collection& collection, unsigned index, const ContainerNode& root) | 148 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeBeforeCachedNod
e(const Collection& collection, unsigned index) |
150 { | 149 { |
151 ASSERT(cachedNode()); // Cache should be valid. | 150 ASSERT(cachedNode()); // Cache should be valid. |
152 unsigned currentIndex = cachedNodeIndex(); | 151 unsigned currentIndex = cachedNodeIndex(); |
153 ASSERT(currentIndex > index); | 152 ASSERT(currentIndex > index); |
154 | 153 |
155 // Determine if we should traverse from the beginning of the collection inst
ead of the cached node. | 154 // Determine if we should traverse from the beginning of the collection inst
ead of the cached node. |
156 bool firstIsCloser = index < currentIndex - index; | 155 bool firstIsCloser = index < currentIndex - index; |
157 if (firstIsCloser || !collection.canTraverseBackward()) { | 156 if (firstIsCloser || !collection.canTraverseBackward()) { |
158 NodeType* firstNode = collection.traverseToFirstElement(root); | 157 NodeType* firstNode = collection.traverseToFirstElement(); |
159 ASSERT(firstNode); | 158 ASSERT(firstNode); |
160 setCachedNode(firstNode, 0); | 159 setCachedNode(firstNode, 0); |
161 return index ? nodeAfterCachedNode(collection, index, root) : firstNode; | 160 return index ? nodeAfterCachedNode(collection, index) : firstNode; |
162 } | 161 } |
163 | 162 |
164 // Backward traversal from the cached node to the requested index. | 163 // Backward traversal from the cached node to the requested index. |
165 NodeType* currentNode = cachedNode(); | 164 NodeType* currentNode = cachedNode(); |
166 ASSERT(collection.canTraverseBackward()); | 165 ASSERT(collection.canTraverseBackward()); |
167 while ((currentNode = collection.itemBefore(currentNode))) { | 166 while ((currentNode = collection.itemBefore(currentNode))) { |
168 ASSERT(currentIndex); | 167 ASSERT(currentIndex); |
169 --currentIndex; | 168 --currentIndex; |
170 if (currentIndex == index) { | 169 if (currentIndex == index) { |
171 setCachedNode(currentNode, currentIndex); | 170 setCachedNode(currentNode, currentIndex); |
172 return currentNode; | 171 return currentNode; |
173 } | 172 } |
174 } | 173 } |
175 ASSERT_NOT_REACHED(); | 174 ASSERT_NOT_REACHED(); |
176 return 0; | 175 return 0; |
177 } | 176 } |
178 | 177 |
179 template <typename Collection, typename NodeType> | 178 template <typename Collection, typename NodeType> |
180 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeAfterCachedNode
(const Collection& collection, unsigned index, const ContainerNode& root) | 179 inline NodeType* CollectionIndexCache<Collection, NodeType>::nodeAfterCachedNode
(const Collection& collection, unsigned index) |
181 { | 180 { |
182 ASSERT(cachedNode()); // Cache should be valid. | 181 ASSERT(cachedNode()); // Cache should be valid. |
183 unsigned currentIndex = cachedNodeIndex(); | 182 unsigned currentIndex = cachedNodeIndex(); |
184 ASSERT(currentIndex < index); | 183 ASSERT(currentIndex < index); |
185 | 184 |
186 // Determine if we should traverse from the end of the collection instead of
the cached node. | 185 // Determine if we should traverse from the end of the collection instead of
the cached node. |
187 bool lastIsCloser = isCachedNodeCountValid() && cachedNodeCount() - index <
index - currentIndex; | 186 bool lastIsCloser = isCachedNodeCountValid() && cachedNodeCount() - index <
index - currentIndex; |
188 if (lastIsCloser && collection.canTraverseBackward()) { | 187 if (lastIsCloser && collection.canTraverseBackward()) { |
189 NodeType* lastItem = collection.itemBefore(0); | 188 NodeType* lastItem = collection.itemBefore(0); |
190 ASSERT(lastItem); | 189 ASSERT(lastItem); |
191 setCachedNode(lastItem, cachedNodeCount() - 1); | 190 setCachedNode(lastItem, cachedNodeCount() - 1); |
192 if (index < cachedNodeCount() - 1) | 191 if (index < cachedNodeCount() - 1) |
193 return nodeBeforeCachedNode(collection, index, root); | 192 return nodeBeforeCachedNode(collection, index); |
194 return lastItem; | 193 return lastItem; |
195 } | 194 } |
196 | 195 |
197 // Forward traversal from the cached node to the requested index. | 196 // Forward traversal from the cached node to the requested index. |
198 NodeType* currentNode = collection.traverseForwardToOffset(index, *cachedNod
e(), currentIndex, root); | 197 NodeType* currentNode = collection.traverseForwardToOffset(index, *cachedNod
e(), currentIndex); |
199 if (!currentNode) { | 198 if (!currentNode) { |
200 // Did not find the node. On plus side, we now know the length. | 199 // Did not find the node. On plus side, we now know the length. |
201 setCachedNodeCount(currentIndex + 1); | 200 setCachedNodeCount(currentIndex + 1); |
202 return 0; | 201 return 0; |
203 } | 202 } |
204 setCachedNode(currentNode, currentIndex); | 203 setCachedNode(currentNode, currentIndex); |
205 return currentNode; | 204 return currentNode; |
206 } | 205 } |
207 | 206 |
208 } // namespace WebCore | 207 } // namespace WebCore |
209 | 208 |
210 #endif // CollectionIndexCache_h | 209 #endif // CollectionIndexCache_h |
OLD | NEW |