Use more references instead of pointers in DocumentOrderedMap
[WebKit-https.git] / Source / WebCore / dom / DocumentOrderedMap.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "DocumentOrderedMap.h"
33
34 #include "Element.h"
35 #include "ElementTraversal.h"
36 #include "HTMLImageElement.h"
37 #include "HTMLLabelElement.h"
38 #include "HTMLMapElement.h"
39 #include "HTMLNameCollection.h"
40 #include "HTMLNames.h"
41 #include "TreeScope.h"
42
43 namespace WebCore {
44
45 using namespace HTMLNames;
46
47 inline bool keyMatchesId(const AtomicStringImpl& key, Element* element)
48 {
49     return element->getIdAttribute().impl() == &key;
50 }
51
52 inline bool keyMatchesName(const AtomicStringImpl& key, Element* element)
53 {
54     return element->getNameAttribute().impl() == &key;
55 }
56
57 inline bool keyMatchesMapName(const AtomicStringImpl& key, Element* element)
58 {
59     return isHTMLMapElement(element) && toHTMLMapElement(element)->getName().impl() == &key;
60 }
61
62 inline bool keyMatchesLowercasedMapName(const AtomicStringImpl& key, Element* element)
63 {
64     return isHTMLMapElement(element) && toHTMLMapElement(element)->getName().lower().impl() == &key;
65 }
66
67 inline bool keyMatchesLowercasedUsemap(const AtomicStringImpl& key, Element* element)
68 {
69     // FIXME: HTML5 specification says we should match both image and object elements.
70     return isHTMLImageElement(element) && toHTMLImageElement(element)->matchesLowercasedUsemap(key);
71 }
72
73 inline bool keyMatchesLabelForAttribute(const AtomicStringImpl& key, Element* element)
74 {
75     return isHTMLLabelElement(element) && element->getAttribute(forAttr).impl() == &key;
76 }
77
78 inline bool keyMatchesWindowNamedItem(const AtomicStringImpl& key, Element* element)
79 {
80     return WindowNameCollection::nodeMatches(element, &key);
81 }
82
83 inline bool keyMatchesDocumentNamedItem(const AtomicStringImpl& key, Element* element)
84 {
85     return DocumentNameCollection::nodeMatches(element, &key);
86 }
87
88 void DocumentOrderedMap::clear()
89 {
90     m_map.clear();
91 }
92
93 void DocumentOrderedMap::add(const AtomicStringImpl& key, Element& element)
94 {
95     Map::AddResult addResult = m_map.add(&key, MapEntry(&element));
96     if (addResult.isNewEntry)
97         return;
98
99     MapEntry& entry = addResult.iterator->value;
100     ASSERT(entry.count);
101     entry.element = 0;
102     entry.count++;
103     entry.orderedList.clear();
104 }
105
106 void DocumentOrderedMap::remove(const AtomicStringImpl& key, Element& element)
107 {
108     m_map.checkConsistency();
109     auto it = m_map.find(&key);
110     ASSERT(it != m_map.end());
111     MapEntry& entry = it->value;
112
113     ASSERT(entry.count);
114     if (entry.count == 1) {
115         ASSERT(!entry.element || entry.element == &element);
116         m_map.remove(it);
117     } else {
118         if (entry.element == &element)
119             entry.element = 0;
120         entry.count--;
121         entry.orderedList.clear(); // FIXME: Remove the element instead if there are only few items left.
122     }
123 }
124
125 template<bool keyMatches(const AtomicStringImpl&, Element*)>
126 inline Element* DocumentOrderedMap::get(const AtomicStringImpl& key, const TreeScope& scope) const
127 {
128     m_map.checkConsistency();
129
130     auto it = m_map.find(&key);
131     if (it == m_map.end())
132         return 0;
133
134     MapEntry& entry = it->value;
135     ASSERT(entry.count);
136     if (entry.element)
137         return entry.element;
138
139     // We know there's at least one node that matches; iterate to find the first one.
140     for (Element* element = ElementTraversal::firstWithin(scope.rootNode()); element; element = ElementTraversal::next(element)) {
141         if (!keyMatches(key, element))
142             continue;
143         entry.element = element;
144         return element;
145     }
146     ASSERT_NOT_REACHED();
147     return 0;
148 }
149
150 Element* DocumentOrderedMap::getElementById(const AtomicStringImpl& key, const TreeScope& scope) const
151 {
152     return get<keyMatchesId>(key, scope);
153 }
154
155 Element* DocumentOrderedMap::getElementByName(const AtomicStringImpl& key, const TreeScope& scope) const
156 {
157     return get<keyMatchesName>(key, scope);
158 }
159
160 HTMLMapElement* DocumentOrderedMap::getElementByMapName(const AtomicStringImpl& key, const TreeScope& scope) const
161 {
162     return toHTMLMapElement(get<keyMatchesMapName>(key, scope));
163 }
164
165 HTMLMapElement* DocumentOrderedMap::getElementByLowercasedMapName(const AtomicStringImpl& key, const TreeScope& scope) const
166 {
167     return toHTMLMapElement(get<keyMatchesLowercasedMapName>(key, scope));
168 }
169
170 HTMLImageElement* DocumentOrderedMap::getElementByLowercasedUsemap(const AtomicStringImpl& key, const TreeScope& scope) const
171 {
172     return toHTMLImageElement(get<keyMatchesLowercasedUsemap>(key, scope));
173 }
174
175 HTMLLabelElement* DocumentOrderedMap::getElementByLabelForAttribute(const AtomicStringImpl& key, const TreeScope& scope) const
176 {
177     return toHTMLLabelElement(get<keyMatchesLabelForAttribute>(key, scope));
178 }
179
180 Element* DocumentOrderedMap::getElementByWindowNamedItem(const AtomicStringImpl& key, const TreeScope& scope) const
181 {
182     return get<keyMatchesWindowNamedItem>(key, scope);
183 }
184
185 Element* DocumentOrderedMap::getElementByDocumentNamedItem(const AtomicStringImpl& key, const TreeScope& scope) const
186 {
187     return get<keyMatchesDocumentNamedItem>(key, scope);
188 }
189
190 const Vector<Element*>* DocumentOrderedMap::getAllElementsById(const AtomicStringImpl& key, const TreeScope& scope) const
191 {
192     m_map.checkConsistency();
193
194     auto it = m_map.find(&key);
195     if (it == m_map.end())
196         return 0;
197
198     MapEntry& entry = it->value;
199     ASSERT(entry.count);
200     if (!entry.count)
201         return 0;
202
203     if (entry.orderedList.isEmpty()) {
204         entry.orderedList.reserveCapacity(entry.count);
205         for (Element* element = entry.element ? entry.element : ElementTraversal::firstWithin(scope.rootNode()); element; element = ElementTraversal::next(element)) {
206             if (!keyMatchesId(key, element))
207                 continue;
208             entry.orderedList.append(element);
209         }
210         ASSERT(entry.orderedList.size() == entry.count);
211     }
212
213     return &entry.orderedList;
214 }
215
216 } // namespace WebCore