Changeset 154370 in webkit


Ignore:
Timestamp:
Aug 20, 2013 3:43:57 PM (11 years ago)
Author:
benjamin@webkit.org
Message:

<https://webkit.org/b/120050> Don't bother using a Vector for the ouput of querySelector, just return the first element found

Reviewed by Ryosuke Niwa.

Simplify the case of querySelector. Instead of using the same output type as querySelectorAll,
simply use a trait to define what to do in the loop.

  • dom/SelectorQuery.cpp:

(WebCore::AllElementExtractorSelectorQueryTrait::appendOutputForElement):
(WebCore::SelectorDataList::queryAll):
(WebCore::SingleElementExtractorSelectorQueryTrait::appendOutputForElement):
(WebCore::SelectorDataList::queryFirst):
(WebCore::SelectorDataList::executeFastPathForIdSelector):
(WebCore::elementsForLocalName):
(WebCore::anyElement):
(WebCore::SelectorDataList::executeSingleTagNameSelectorData):
(WebCore::SelectorDataList::executeSingleClassNameSelectorData):
(WebCore::SelectorDataList::executeSingleSelectorData):
(WebCore::SelectorDataList::executeSingleMultiSelectorData):
(WebCore::SelectorDataList::execute):

  • dom/SelectorQuery.h:
Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r154365 r154370  
     12013-08-20  Benjamin Poulain  <benjamin@webkit.org>
     2
     3        <https://webkit.org/b/120050> Don't bother using a Vector for the ouput of querySelector, just return the first element found
     4
     5        Reviewed by Ryosuke Niwa.
     6
     7        Simplify the case of querySelector. Instead of using the same output type as querySelectorAll,
     8        simply use a trait to define what to do in the loop.
     9
     10        * dom/SelectorQuery.cpp:
     11        (WebCore::AllElementExtractorSelectorQueryTrait::appendOutputForElement):
     12        (WebCore::SelectorDataList::queryAll):
     13        (WebCore::SingleElementExtractorSelectorQueryTrait::appendOutputForElement):
     14        (WebCore::SelectorDataList::queryFirst):
     15        (WebCore::SelectorDataList::executeFastPathForIdSelector):
     16        (WebCore::elementsForLocalName):
     17        (WebCore::anyElement):
     18        (WebCore::SelectorDataList::executeSingleTagNameSelectorData):
     19        (WebCore::SelectorDataList::executeSingleClassNameSelectorData):
     20        (WebCore::SelectorDataList::executeSingleSelectorData):
     21        (WebCore::SelectorDataList::executeSingleMultiSelectorData):
     22        (WebCore::SelectorDataList::execute):
     23        * dom/SelectorQuery.h:
     24
    1252013-08-20  Antti Koivisto  <antti@apple.com>
    226
  • trunk/Source/WebCore/dom/SelectorQuery.cpp

    r154037 r154370  
    8181}
    8282
     83struct AllElementExtractorSelectorQueryTrait {
     84    typedef Vector<RefPtr<Node>> OutputType;
     85    static const bool shouldOnlyMatchFirstElement = false;
     86    static void appendOutputForElement(OutputType& output, Element* element) { output.append(element); }
     87};
     88
    8389PassRefPtr<NodeList> SelectorDataList::queryAll(Node* rootNode) const
    8490{
    85     Vector<RefPtr<Node> > result;
    86     execute<false>(rootNode, result);
     91    Vector<RefPtr<Node>> result;
     92    execute<AllElementExtractorSelectorQueryTrait>(rootNode, result);
    8793    return StaticNodeList::adopt(result);
    8894}
    8995
     96struct SingleElementExtractorSelectorQueryTrait {
     97    typedef Element* OutputType;
     98    static const bool shouldOnlyMatchFirstElement = true;
     99    static void appendOutputForElement(OutputType& output, Element* element)
     100    {
     101        ASSERT(element);
     102        ASSERT(!output);
     103        output = element;
     104    }
     105};
     106
    90107PassRefPtr<Element> SelectorDataList::queryFirst(Node* rootNode) const
    91108{
    92     Vector<RefPtr<Node> > result;
    93     execute<true>(rootNode, result);
    94     if (result.isEmpty())
    95         return 0;
    96     ASSERT(result.size() == 1);
    97     ASSERT(result.first()->isElementNode());
    98     return toElement(result.first().get());
     109    Element* result = 0;
     110    execute<SingleElementExtractorSelectorQueryTrait>(rootNode, result);
     111    return result;
    99112}
    100113
     
    123136}
    124137
    125 template <bool firstMatchOnly>
    126 ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const Node* rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, Vector<RefPtr<Node> >& matchedElements) const
     138template <typename SelectorQueryTrait>
     139ALWAYS_INLINE void SelectorDataList::executeFastPathForIdSelector(const Node* rootNode, const SelectorData& selectorData, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType& output) const
    127140{
    128141    ASSERT(m_selectors.size() == 1);
    129142    ASSERT(idSelector);
     143
    130144    const AtomicString& idToMatch = idSelector->value();
    131145    if (UNLIKELY(rootNode->treeScope()->containsMultipleElementsWithId(idToMatch))) {
     
    137151            Element* element = elements->at(i);
    138152            if ((rootNodeIsTreeScopeRoot || element->isDescendantOf(rootNode)) && selectorMatches(selectorData, element, rootNode)) {
    139                 matchedElements.append(element);
    140                 if (firstMatchOnly)
     153                SelectorQueryTrait::appendOutputForElement(output, element);
     154                if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    141155                    return;
    142156            }
     
    144158        return;
    145159    }
     160
    146161    Element* element = rootNode->treeScope()->getElementById(idToMatch);
    147162    if (!element || !(isTreeScopeRoot(rootNode) || element->isDescendantOf(rootNode)))
    148163        return;
    149164    if (selectorMatches(selectorData, element, rootNode))
    150         matchedElements.append(element);
     165        SelectorQueryTrait::appendOutputForElement(output, element);
    151166}
    152167
     
    156171}
    157172
    158 template <bool firstMatchOnly>
    159 static inline void elementsForLocalName(const Node* rootNode, const AtomicString& localName, Vector<RefPtr<Node> >& matchedElements)
    160 {
    161     for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
    162         if (element->localName() == localName) {
    163             matchedElements.append(element);
    164             if (firstMatchOnly)
     173template <typename SelectorQueryTrait>
     174static inline void elementsForLocalName(const Node* rootNode, const AtomicString& localName, typename SelectorQueryTrait::OutputType& output)
     175{
     176    for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
     177        if (element->tagQName().localName() == localName) {
     178            SelectorQueryTrait::appendOutputForElement(output, element);
     179            if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    165180                return;
    166181        }
     
    168183}
    169184
    170 template <bool firstMatchOnly>
    171 static inline void anyElement(const Node* rootNode, Vector<RefPtr<Node> >& matchedElements)
    172 {
    173     for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
    174         matchedElements.append(element);
    175         if (firstMatchOnly)
     185template <typename SelectorQueryTrait>
     186static inline void anyElement(const Node* rootNode, typename SelectorQueryTrait::OutputType& output)
     187{
     188    for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
     189        SelectorQueryTrait::appendOutputForElement(output, element);
     190        if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    176191            return;
    177192    }
     
    179194
    180195
    181 template <bool firstMatchOnly>
    182 ALWAYS_INLINE void SelectorDataList::executeSingleTagNameSelectorData(const Node* rootNode, const SelectorData& selectorData, Vector<RefPtr<Node> >& matchedElements) const
     196template <typename SelectorQueryTrait>
     197ALWAYS_INLINE void SelectorDataList::executeSingleTagNameSelectorData(const Node* rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
    183198{
    184199    ASSERT(m_selectors.size() == 1);
     
    192207        if (selectorLocalName != starAtom) {
    193208            // Common case: name defined, selectorNamespaceURI is a wildcard.
    194             elementsForLocalName<firstMatchOnly>(rootNode, selectorLocalName, matchedElements);
     209            elementsForLocalName<SelectorQueryTrait>(rootNode, selectorLocalName, output);
    195210        } else {
    196211            // Other fairly common case: both are wildcards.
    197             anyElement<firstMatchOnly>(rootNode, matchedElements);
     212            anyElement<SelectorQueryTrait>(rootNode, output);
    198213        }
    199214    } else {
    200215        // Fallback: NamespaceURI is set, selectorLocalName may be starAtom.
    201216        for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
    202             if (element->namespaceURI() == selectorNamespaceURI && (selectorLocalName == starAtom || element->localName() == selectorLocalName)) {
    203                 matchedElements.append(element);
    204                 if (firstMatchOnly)
    205                     break;
     217            if (element->namespaceURI() == selectorNamespaceURI && (selectorLocalName == starAtom || element->tagQName().localName() == selectorLocalName)) {
     218                SelectorQueryTrait::appendOutputForElement(output, element);
     219                if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
     220                    return;
    206221            }
    207222        }
    208223    }
    209 #if !ASSERT_DISABLED
    210     for (size_t i = 0; i < matchedElements.size(); ++i) {
    211         ASSERT(matchedElements[i]->isElementNode());
    212         ASSERT(SelectorChecker::tagMatches(static_cast<const Element*>(matchedElements[i].get()), tagQualifiedName));
    213     }
    214 #endif
    215224}
    216225
     
    220229}
    221230
    222 template <bool firstMatchOnly>
    223 ALWAYS_INLINE void SelectorDataList::executeSingleClassNameSelectorData(const Node* rootNode, const SelectorData& selectorData, Vector<RefPtr<Node> >& matchedElements) const
     231template <typename SelectorQueryTrait>
     232ALWAYS_INLINE void SelectorDataList::executeSingleClassNameSelectorData(const Node* rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
    224233{
    225234    ASSERT(m_selectors.size() == 1);
     
    229238    for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
    230239        if (element->hasClass() && element->classNames().contains(className)) {
    231             matchedElements.append(element);
    232             if (firstMatchOnly)
     240            SelectorQueryTrait::appendOutputForElement(output, element);
     241            if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    233242                return;
    234243        }
     
    236245}
    237246
    238 template <bool firstMatchOnly>
    239 ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const Node* rootNode, const SelectorData& selectorData, Vector<RefPtr<Node> >& matchedElements) const
     247template <typename SelectorQueryTrait>
     248ALWAYS_INLINE void SelectorDataList::executeSingleSelectorData(const Node* rootNode, const SelectorData& selectorData, typename SelectorQueryTrait::OutputType& output) const
    240249{
    241250    ASSERT(m_selectors.size() == 1);
     
    243252    for (Element* element = ElementTraversal::firstWithin(rootNode); element; element = ElementTraversal::next(element, rootNode)) {
    244253        if (selectorMatches(selectorData, element, rootNode)) {
    245             matchedElements.append(element);
    246             if (firstMatchOnly)
     254            SelectorQueryTrait::appendOutputForElement(output, element);
     255            if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    247256                return;
    248257        }
     
    250259}
    251260
    252 template <bool firstMatchOnly>
    253 ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const
     261template <typename SelectorQueryTrait>
     262ALWAYS_INLINE void SelectorDataList::executeSingleMultiSelectorData(const Node* rootNode, typename SelectorQueryTrait::OutputType& output) const
    254263{
    255264    unsigned selectorCount = m_selectors.size();
     
    257266        for (unsigned i = 0; i < selectorCount; ++i) {
    258267            if (selectorMatches(m_selectors[i], element, rootNode)) {
    259                 matchedElements.append(element);
    260                 if (firstMatchOnly)
     268                SelectorQueryTrait::appendOutputForElement(output, element);
     269                if (SelectorQueryTrait::shouldOnlyMatchFirstElement)
    261270                    return;
    262271                break;
     
    266275}
    267276
    268 template <bool firstMatchOnly>
    269 ALWAYS_INLINE void SelectorDataList::execute(Node* rootNode, Vector<RefPtr<Node> >& matchedElements) const
     277template <typename SelectorQueryTrait>
     278ALWAYS_INLINE void SelectorDataList::execute(Node* rootNode, typename SelectorQueryTrait::OutputType& output) const
    270279{
    271280    if (m_selectors.size() == 1) {
    272281        const SelectorData& selectorData = m_selectors[0];
    273282        if (const CSSSelector* idSelector = selectorForIdLookup(rootNode, selectorData.selector))
    274             executeFastPathForIdSelector<firstMatchOnly>(rootNode, selectorData, idSelector, matchedElements);
     283            executeFastPathForIdSelector<SelectorQueryTrait>(rootNode, selectorData, idSelector, output);
    275284        else if (isSingleTagNameSelector(selectorData.selector))
    276             executeSingleTagNameSelectorData<firstMatchOnly>(rootNode, selectorData, matchedElements);
     285            executeSingleTagNameSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
    277286        else if (isSingleClassNameSelector(selectorData.selector))
    278             executeSingleClassNameSelectorData<firstMatchOnly>(rootNode, selectorData, matchedElements);
     287            executeSingleClassNameSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
    279288        else
    280             executeSingleSelectorData<firstMatchOnly>(rootNode, selectorData, matchedElements);
     289            executeSingleSelectorData<SelectorQueryTrait>(rootNode, selectorData, output);
    281290        return;
    282291    }
    283     executeSingleMultiSelectorData<firstMatchOnly>(rootNode, matchedElements);
     292    executeSingleMultiSelectorData<SelectorQueryTrait>(rootNode, output);
    284293}
    285294
  • trunk/Source/WebCore/dom/SelectorQuery.h

    r151365 r154370  
    5959
    6060    bool selectorMatches(const SelectorData&, Element*, const Node*) const;
    61     template <bool firstMatchOnly>
    62     void execute(Node* rootNode, Vector<RefPtr<Node> >&) const;
    6361
    64     template <bool firstMatchOnly> void executeFastPathForIdSelector(const Node* rootNode, const SelectorData&, const CSSSelector* idSelector, Vector<RefPtr<Node> >&) const;
    65     template <bool firstMatchOnly> void executeSingleTagNameSelectorData(const Node* rootNode, const SelectorData&, Vector<RefPtr<Node> >&) const;
    66     template <bool firstMatchOnly> void executeSingleClassNameSelectorData(const Node* rootNode, const SelectorData&, Vector<RefPtr<Node> >&) const;
    67     template <bool firstMatchOnly> void executeSingleSelectorData(const Node* rootNode, const SelectorData&, Vector<RefPtr<Node> >&) const;
    68     template <bool firstMatchOnly> void executeSingleMultiSelectorData(const Node* rootNode, Vector<RefPtr<Node> >&) const;
     62    template <typename SelectorQueryTrait> void execute(Node* rootNode, typename SelectorQueryTrait::OutputType&) const;
     63    template <typename SelectorQueryTrait> void executeFastPathForIdSelector(const Node* rootNode, const SelectorData&, const CSSSelector* idSelector, typename SelectorQueryTrait::OutputType&) const;
     64    template <typename SelectorQueryTrait> void executeSingleTagNameSelectorData(const Node* rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
     65    template <typename SelectorQueryTrait> void executeSingleClassNameSelectorData(const Node* rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
     66    template <typename SelectorQueryTrait> void executeSingleSelectorData(const Node* rootNode, const SelectorData&, typename SelectorQueryTrait::OutputType&) const;
     67    template <typename SelectorQueryTrait> void executeSingleMultiSelectorData(const Node* rootNode, typename SelectorQueryTrait::OutputType&) const;
    6968
    7069    Vector<SelectorData> m_selectors;
Note: See TracChangeset for help on using the changeset viewer.