Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: Source/core/dom/ElementData.h

Issue 298253009: Add iterator object to iterate efficiently over an Element's attributes (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * Copyright (C) 2014 Apple Inc. All rights reserved.
esprehn 2014/05/28 20:03:54 Do we really need to add Apple copyrights?
Inactive 2014/05/29 15:14:01 I don't know what the exact rules are but it seems
Inactive 2014/05/29 15:17:59 Also, this CL seems to hint that I am not the only
3 * 4 *
4 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
6 * met: 7 * met:
7 * 8 *
8 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 11 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer 12 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the 13 * in the documentation and/or other materials provided with the
(...skipping 22 matching lines...) Expand all
35 #include "core/dom/SpaceSplitString.h" 36 #include "core/dom/SpaceSplitString.h"
36 #include "wtf/text/AtomicString.h" 37 #include "wtf/text/AtomicString.h"
37 38
38 namespace WebCore { 39 namespace WebCore {
39 40
40 class Attr; 41 class Attr;
41 class ShareableElementData; 42 class ShareableElementData;
42 class StylePropertySet; 43 class StylePropertySet;
43 class UniqueElementData; 44 class UniqueElementData;
44 45
46 class AttributeConstIterator {
47 public:
48 AttributeConstIterator(const Attribute* array, unsigned index)
49 : m_array(array)
50 , m_index(index)
51 { }
52
53 const Attribute* operator*() const { return &m_array[m_index]; }
54 const Attribute* operator->() const { return &m_array[m_index]; }
55 AttributeConstIterator& operator++() { ++m_index; return *this; }
56
57 bool operator==(const AttributeConstIterator& other) const { return m_index == other.m_index; }
58 bool operator!=(const AttributeConstIterator& other) const { return !(*this == other); }
59
60 unsigned index() const { return m_index; }
61
62 private:
63 const Attribute* m_array;
64 unsigned m_index;
65 };
66
67 class AttributeIteratorAccessor {
esprehn 2014/05/28 20:03:54 This class seems unnecessary.
Inactive 2014/05/29 15:14:01 The main reason for this class (besides avoiding m
68 public:
69 AttributeIteratorAccessor(const Attribute* array, unsigned size)
70 : m_array(array)
71 , m_size(size)
72 { }
73
74 AttributeConstIterator begin() const { return AttributeConstIterator(m_array , 0); }
75 AttributeConstIterator end() const { return AttributeConstIterator(m_array, m_size); }
76
77 unsigned size() const { return m_size; }
78
79 private:
80 const Attribute* m_array;
81 unsigned m_size;
82 };
83
45 // ElementData represents very common, but not necessarily unique to an element, 84 // ElementData represents very common, but not necessarily unique to an element,
46 // data such as attributes, inline style, and parsed class names and ids. 85 // data such as attributes, inline style, and parsed class names and ids.
47 class ElementData : public RefCounted<ElementData> { 86 class ElementData : public RefCounted<ElementData> {
48 WTF_MAKE_FAST_ALLOCATED; 87 WTF_MAKE_FAST_ALLOCATED;
49 public: 88 public:
50 // Override RefCounted's deref() to ensure operator delete is called on 89 // Override RefCounted's deref() to ensure operator delete is called on
51 // the appropriate subclass type. 90 // the appropriate subclass type.
52 void deref(); 91 void deref();
53 92
54 void clearClass() const { m_classNames.clear(); } 93 void clearClass() const { m_classNames.clear(); }
55 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_ classNames.set(className, shouldFoldCase); } 94 void setClass(const AtomicString& className, bool shouldFoldCase) const { m_ classNames.set(className, shouldFoldCase); }
56 const SpaceSplitString& classNames() const { return m_classNames; } 95 const SpaceSplitString& classNames() const { return m_classNames; }
57 96
58 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu tion; } 97 const AtomicString& idForStyleResolution() const { return m_idForStyleResolu tion; }
59 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle Resolution = newId; } 98 void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyle Resolution = newId; }
60 99
61 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); } 100 const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
62 101
63 const StylePropertySet* presentationAttributeStyle() const; 102 const StylePropertySet* presentationAttributeStyle() const;
64 103
65 // This is not a trivial getter and its return value should be cached for pe rformance. 104 // This is not a trivial getter and its return value should be cached for pe rformance.
66 size_t length() const; 105 size_t length() const;
67 bool isEmpty() const { return !length(); } 106 bool isEmpty() const { return !length(); }
68 107
108 AttributeIteratorAccessor attributesIterator() const;
esprehn 2014/05/28 20:03:54 Can we just add attributesBegin() and attributesEn
Inactive 2014/05/29 15:14:01 If we do this then we will call ElementData::isUni
Inactive 2014/05/30 13:16:03 Note that we had issues before with callers not ca
109
69 const Attribute& attributeItem(unsigned index) const; 110 const Attribute& attributeItem(unsigned index) const;
70 const Attribute* getAttributeItem(const QualifiedName&) const; 111 const Attribute* getAttributeItem(const QualifiedName&) const;
71 size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = f alse) const; 112 size_t getAttributeItemIndex(const QualifiedName&, bool shouldIgnoreCase = f alse) const;
72 size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttr ibuteCase) const; 113 size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttr ibuteCase) const;
73 size_t getAttrIndex(Attr*) const; 114 size_t getAttrIndex(Attr*) const;
74 115
75 bool hasID() const { return !m_idForStyleResolution.isNull(); } 116 bool hasID() const { return !m_idForStyleResolution.isNull(); }
76 bool hasClass() const { return !m_classNames.isNull(); } 117 bool hasClass() const { return !m_classNames.isNull(); }
77 118
78 bool isEquivalent(const ElementData* other) const; 119 bool isEquivalent(const ElementData* other) const;
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 236
196 inline const Attribute* ElementData::attributeBase() const 237 inline const Attribute* ElementData::attributeBase() const
197 { 238 {
198 if (m_isUnique) 239 if (m_isUnique)
199 return static_cast<const UniqueElementData*>(this)->m_attributeVector.be gin(); 240 return static_cast<const UniqueElementData*>(this)->m_attributeVector.be gin();
200 return static_cast<const ShareableElementData*>(this)->m_attributeArray; 241 return static_cast<const ShareableElementData*>(this)->m_attributeArray;
201 } 242 }
202 243
203 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const 244 inline size_t ElementData::getAttributeItemIndex(const QualifiedName& name, bool shouldIgnoreCase) const
204 { 245 {
205 const Attribute* begin = attributeBase(); 246 AttributeIteratorAccessor attributes = attributesIterator();
206 // Cache length for performance as ElementData::length() contains a conditio nal branch. 247 AttributeConstIterator end = attributes.end();
207 unsigned length = this->length(); 248 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) {
208 for (unsigned i = 0; i < length; ++i) { 249 if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
209 const Attribute& attribute = begin[i]; 250 return it.index();
210 if (attribute.name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase) )
211 return i;
212 } 251 }
213 return kNotFound; 252 return kNotFound;
214 } 253 }
215 254
216 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th at the caller 255 // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so th at the caller
217 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not). 256 // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
218 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const 257 inline size_t ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const
219 { 258 {
220 // Cache length for performance as ElementData::length() contains a conditio nal branch.
221 unsigned length = this->length();
222 bool doSlowCheck = shouldIgnoreAttributeCase; 259 bool doSlowCheck = shouldIgnoreAttributeCase;
223 260
224 // Optimize for the case where the attribute exists and its name exactly mat ches. 261 // Optimize for the case where the attribute exists and its name exactly mat ches.
225 const Attribute* begin = attributeBase(); 262 AttributeIteratorAccessor attributes = attributesIterator();
226 for (unsigned i = 0; i < length; ++i) { 263 AttributeConstIterator end = attributes.end();
227 const Attribute& attribute = begin[i]; 264 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) {
228 // FIXME: Why check the prefix? Namespaces should be all that matter. 265 // FIXME: Why check the prefix? Namespaces should be all that matter.
229 // Most attributes (all of HTML and CSS) have no namespace. 266 // Most attributes (all of HTML and CSS) have no namespace.
230 if (!attribute.name().hasPrefix()) { 267 if (!it->name().hasPrefix()) {
231 if (name == attribute.localName()) 268 if (name == it->localName())
232 return i; 269 return it.index();
233 } else { 270 } else {
234 doSlowCheck = true; 271 doSlowCheck = true;
235 } 272 }
236 } 273 }
237 274
238 if (doSlowCheck) 275 if (doSlowCheck)
239 return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase); 276 return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
240 return kNotFound; 277 return kNotFound;
241 } 278 }
242 279
280 inline AttributeIteratorAccessor ElementData::attributesIterator() const
281 {
282 if (isUnique()) {
283 const Vector<Attribute, 4>& attributeVector = static_cast<const UniqueEl ementData*>(this)->m_attributeVector;
284 return AttributeIteratorAccessor(attributeVector.data(), attributeVector .size());
285 }
286 return AttributeIteratorAccessor(static_cast<const ShareableElementData*>(th is)->m_attributeArray, m_arraySize);
287 }
288
243 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const 289 inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const
244 { 290 {
245 const Attribute* begin = attributeBase(); 291 AttributeIteratorAccessor attributes = attributesIterator();
246 unsigned length = this->length(); 292 AttributeConstIterator end = attributes.end();
247 for (unsigned i = 0; i < length; ++i) { 293 for (AttributeConstIterator it = attributes.begin(); it != end; ++it) {
248 const Attribute& attribute = begin[i]; 294 if (it->name().matches(name))
249 if (attribute.name().matches(name)) 295 return *it;
250 return &attribute;
251 } 296 }
252 return 0; 297 return 0;
253 } 298 }
254 299
255 inline const Attribute& ElementData::attributeItem(unsigned index) const 300 inline const Attribute& ElementData::attributeItem(unsigned index) const
256 { 301 {
257 RELEASE_ASSERT(index < length()); 302 RELEASE_ASSERT(index < length());
258 ASSERT(attributeBase() + index); 303 ASSERT(attributeBase() + index);
259 return *(attributeBase() + index); 304 return *(attributeBase() + index);
260 } 305 }
261 306
262 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value) 307 inline void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
263 { 308 {
264 m_attributeVector.append(Attribute(attributeName, value)); 309 m_attributeVector.append(Attribute(attributeName, value));
265 } 310 }
266 311
267 inline void UniqueElementData::removeAttribute(size_t index) 312 inline void UniqueElementData::removeAttribute(size_t index)
268 { 313 {
269 m_attributeVector.remove(index); 314 m_attributeVector.remove(index);
270 } 315 }
271 316
272 inline Attribute& UniqueElementData::attributeItem(unsigned index) 317 inline Attribute& UniqueElementData::attributeItem(unsigned index)
273 { 318 {
274 return m_attributeVector.at(index); 319 return m_attributeVector.at(index);
275 } 320 }
276 321
277 } // namespace WebCore 322 } // namespace WebCore
278 323
279 #endif // ElementData_h 324 #endif // ElementData_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698