| Index: Source/core/dom/AttributeCollection.h
|
| diff --git a/Source/core/dom/AttributeCollection.h b/Source/core/dom/AttributeCollection.h
|
| index a46ea8fb99b6d41afbb09c84f8b2e1c5ce13c24c..8890e70bbe48e0627bf0b722076d749d73496d3d 100644
|
| --- a/Source/core/dom/AttributeCollection.h
|
| +++ b/Source/core/dom/AttributeCollection.h
|
| @@ -33,58 +33,108 @@
|
| #ifndef AttributeCollection_h
|
| #define AttributeCollection_h
|
|
|
| +#include "core/dom/Attr.h"
|
| #include "core/dom/Attribute.h"
|
| +#include "wtf/Vector.h"
|
|
|
| namespace blink {
|
|
|
| -class Attr;
|
| -
|
| -class AttributeCollection {
|
| +template <typename Container, typename ContainerMemberType = Container>
|
| +class AttributeCollectionGeneric {
|
| public:
|
| - typedef const Attribute* const_iterator;
|
| + typedef typename Container::ValueType ValueType;
|
| + typedef ValueType* iterator;
|
|
|
| - AttributeCollection(const Attribute* array, unsigned size)
|
| - : m_array(array)
|
| - , m_size(size)
|
| + AttributeCollectionGeneric(Container& attributes)
|
| + : m_attributes(attributes)
|
| { }
|
|
|
| - const Attribute& operator[](unsigned index) const { return at(index); }
|
| - const Attribute& at(unsigned index) const
|
| + ValueType& operator[](unsigned index) const { return at(index); }
|
| + ValueType& at(unsigned index) const
|
| {
|
| - RELEASE_ASSERT(index < m_size);
|
| - return m_array[index];
|
| + RELEASE_ASSERT(index < size());
|
| + return begin()[index];
|
| }
|
|
|
| - const Attribute* find(const QualifiedName&) const;
|
| - const Attribute* find(const AtomicString& name, bool shouldIgnoreCase) const;
|
| + iterator begin() const { return m_attributes.data(); }
|
| + iterator end() const { return begin() + size(); }
|
| +
|
| + unsigned size() const { return m_attributes.size(); }
|
| + bool isEmpty() const { return !size(); }
|
| +
|
| + iterator find(const QualifiedName&) const;
|
| + iterator find(const AtomicString& name, bool shouldIgnoreCase) const;
|
| size_t findIndex(const QualifiedName&, bool shouldIgnoreCase = false) const;
|
| size_t findIndex(const AtomicString& name, bool shouldIgnoreCase) const;
|
| size_t findIndex(Attr*) const;
|
|
|
| - const_iterator begin() const { return m_array; }
|
| - const_iterator end() const { return m_array + m_size; }
|
| +protected:
|
| + size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
|
| +
|
| + ContainerMemberType m_attributes;
|
| +};
|
| +
|
| +class AttributeArray {
|
| +public:
|
| + typedef const Attribute ValueType;
|
| +
|
| + AttributeArray(const Attribute* array, unsigned size)
|
| + : m_array(array)
|
| + , m_size(size)
|
| + { }
|
|
|
| + const Attribute* data() const { return m_array; }
|
| unsigned size() const { return m_size; }
|
| - bool isEmpty() const { return !m_size; }
|
|
|
| private:
|
| - size_t findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
|
| -
|
| const Attribute* m_array;
|
| unsigned m_size;
|
| };
|
|
|
| -inline const Attribute* AttributeCollection::find(const AtomicString& name, bool shouldIgnoreCase) const
|
| +class AttributeCollection : public AttributeCollectionGeneric<const AttributeArray> {
|
| +public:
|
| + typedef iterator const_iterator;
|
| +
|
| + AttributeCollection(const Attribute* array, unsigned size)
|
| + : AttributeCollectionGeneric<const AttributeArray>(AttributeArray(array, size))
|
| + { }
|
| +};
|
| +
|
| +typedef Vector<Attribute, 4> AttributeVector;
|
| +class MutableAttributeCollection : public AttributeCollectionGeneric<AttributeVector, AttributeVector&> {
|
| +public:
|
| + explicit MutableAttributeCollection(AttributeVector& attributes)
|
| + : AttributeCollectionGeneric<AttributeVector, AttributeVector&>(attributes)
|
| + { }
|
| +
|
| + // These functions do no error/duplicate checking.
|
| + void append(const QualifiedName&, const AtomicString& value);
|
| + void remove(unsigned index);
|
| +};
|
| +
|
| +inline void MutableAttributeCollection::append(const QualifiedName& name, const AtomicString& value)
|
| +{
|
| + m_attributes.append(Attribute(name, value));
|
| +}
|
| +
|
| +inline void MutableAttributeCollection::remove(unsigned index)
|
| +{
|
| + m_attributes.remove(index);
|
| +}
|
| +
|
| +template <typename Container, typename ContainerMemberType>
|
| +inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iterator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const AtomicString& name, bool shouldIgnoreCase) const
|
| {
|
| size_t index = findIndex(name, shouldIgnoreCase);
|
| return index != kNotFound ? &at(index) : 0;
|
| }
|
|
|
| -inline size_t AttributeCollection::findIndex(const QualifiedName& name, bool shouldIgnoreCase) const
|
| +template <typename Container, typename ContainerMemberType>
|
| +inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(const QualifiedName& name, bool shouldIgnoreCase) const
|
| {
|
| - const_iterator end = this->end();
|
| + iterator end = this->end();
|
| unsigned index = 0;
|
| - for (const_iterator it = begin(); it != end; ++it, ++index) {
|
| + for (iterator it = begin(); it != end; ++it, ++index) {
|
| if (it->name().matchesPossiblyIgnoringCase(name, shouldIgnoreCase))
|
| return index;
|
| }
|
| @@ -93,14 +143,15 @@ inline size_t AttributeCollection::findIndex(const QualifiedName& name, bool sho
|
|
|
| // We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
|
| // can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
|
| -inline size_t AttributeCollection::findIndex(const AtomicString& name, bool shouldIgnoreCase) const
|
| +template <typename Container, typename ContainerMemberType>
|
| +inline size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(const AtomicString& name, bool shouldIgnoreCase) const
|
| {
|
| bool doSlowCheck = shouldIgnoreCase;
|
|
|
| // Optimize for the case where the attribute exists and its name exactly matches.
|
| - const_iterator end = this->end();
|
| + iterator end = this->end();
|
| unsigned index = 0;
|
| - for (const_iterator it = begin(); it != end; ++it, ++index) {
|
| + for (iterator it = begin(); it != end; ++it, ++index) {
|
| // FIXME: Why check the prefix? Namespaces should be all that matter.
|
| // Most attributes (all of HTML and CSS) have no namespace.
|
| if (!it->name().hasPrefix()) {
|
| @@ -116,16 +167,53 @@ inline size_t AttributeCollection::findIndex(const AtomicString& name, bool shou
|
| return kNotFound;
|
| }
|
|
|
| -inline const Attribute* AttributeCollection::find(const QualifiedName& name) const
|
| +template <typename Container, typename ContainerMemberType>
|
| +inline typename AttributeCollectionGeneric<Container, ContainerMemberType>::iterator AttributeCollectionGeneric<Container, ContainerMemberType>::find(const QualifiedName& name) const
|
| {
|
| - const_iterator end = this->end();
|
| - for (const_iterator it = begin(); it != end; ++it) {
|
| + iterator end = this->end();
|
| + for (iterator it = begin(); it != end; ++it) {
|
| if (it->name().matches(name))
|
| return it;
|
| }
|
| return 0;
|
| }
|
|
|
| +template <typename Container, typename ContainerMemberType>
|
| +size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findIndex(Attr* attr) const
|
| +{
|
| + // This relies on the fact that Attr's QualifiedName == the Attribute's name.
|
| + iterator end = this->end();
|
| + unsigned index = 0;
|
| + for (iterator it = begin(); it != end; ++it, ++index) {
|
| + if (it->name() == attr->qualifiedName())
|
| + return index;
|
| + }
|
| + return kNotFound;
|
| +}
|
| +
|
| +template <typename Container, typename ContainerMemberType>
|
| +size_t AttributeCollectionGeneric<Container, ContainerMemberType>::findSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
|
| +{
|
| + // Continue to checking case-insensitively and/or full namespaced names if necessary:
|
| + iterator end = this->end();
|
| + unsigned index = 0;
|
| + for (iterator it = begin(); it != end; ++it, ++index) {
|
| + // FIXME: Why check the prefix? Namespace is all that should matter
|
| + // and all HTML/SVG attributes have a null namespace!
|
| + if (!it->name().hasPrefix()) {
|
| + if (shouldIgnoreAttributeCase && equalIgnoringCase(name, it->localName()))
|
| + return index;
|
| + } else {
|
| + // FIXME: Would be faster to do this comparison without calling toString, which
|
| + // generates a temporary string by concatenation. But this branch is only reached
|
| + // if the attribute name has a prefix, which is rare in HTML.
|
| + if (equalPossiblyIgnoringCase(name, it->name().toString(), shouldIgnoreAttributeCase))
|
| + return index;
|
| + }
|
| + }
|
| + return kNotFound;
|
| +}
|
| +
|
| } // namespace blink
|
|
|
| #endif // AttributeCollection_h
|
|
|