Commit 4f2ea592 authored by vegorov@chromium.org's avatar vegorov@chromium.org

Introduce TerminatedArray<T> type to make data-structure used by RuleSet visible at the type level.

Before this change it was not possible to easily distinguish when RuleData represented a single item and when it represented an array.

This change is prerequisite for moving RuleSet/RuleData into the GC managed heap because tracing routines are largely type driven.

BUG=
NOTRY=true

Review URL: https://codereview.chromium.org/181403005

git-svn-id: svn://svn.chromium.org/blink/trunk@168508 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 39c3beec
......@@ -67,26 +67,4 @@ void CSSTestHelper::addCSSRules(const char* cssText)
ASSERT_TRUE(m_styleSheet->length() > sheetLength);
}
int CSSTestHelper::numRules(const RuleData* ruleData)
{
if (!ruleData)
return 0;
int count = 1;
while (!ruleData->isLastInArray()) {
ruleData++;
count++;
}
return count;
}
const RuleData& CSSTestHelper::getRule(const RuleData* ruleData, int index)
{
int count = 0;
while (!ruleData->isLastInArray() && count < index) {
ruleData++;
count++;
}
return *ruleData;
}
} // namespace WebCore
......@@ -53,10 +53,6 @@ public:
void addCSSRules(const char* ruleText);
RuleSet& ruleSet();
// Returns the number of rules in the given RuleData array.
static int numRules(const RuleData*);
// Returns the data at index i (must be less than numNules())
static const RuleData& getRule(const RuleData*, int index);
private:
RefPtr<Document> m_document;
RefPtr<CSSStyleSheet> m_styleSheet;
......
......@@ -336,24 +336,6 @@ void ElementRuleCollector::collectRuleIfMatches(const RuleData& ruleData, Select
}
}
void ElementRuleCollector::collectMatchingRulesForList(const RuleData* rules, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
{
if (!rules)
return;
while (!rules->isLastInArray())
collectRuleIfMatches(*rules++, behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
collectRuleIfMatches(*rules, behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
}
void ElementRuleCollector::collectMatchingRulesForList(const Vector<RuleData>* rules, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
{
if (!rules)
return;
unsigned size = rules->size();
for (unsigned i = 0; i < size; ++i)
collectRuleIfMatches(rules->at(i), behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
}
static inline bool compareRules(const MatchedRule& matchedRule1, const MatchedRule& matchedRule2)
{
if (matchedRule1.cascadeScope() != matchedRule2.cascadeScope())
......
......@@ -115,8 +115,17 @@ public:
private:
void collectRuleIfMatches(const RuleData&, SelectorChecker::BehaviorAtBoundary, CascadeScope, CascadeOrder, const MatchRequest&, RuleRange&);
void collectMatchingRulesForList(const Vector<RuleData>*, SelectorChecker::BehaviorAtBoundary, CascadeScope, CascadeOrder, const MatchRequest&, RuleRange&);
void collectMatchingRulesForList(const RuleData*, SelectorChecker::BehaviorAtBoundary, CascadeScope, CascadeOrder, const MatchRequest&, RuleRange&);
template<typename RuleDataListType>
void collectMatchingRulesForList(const RuleDataListType* rules, SelectorChecker::BehaviorAtBoundary behaviorAtBoundary, CascadeScope cascadeScope, CascadeOrder cascadeOrder, const MatchRequest& matchRequest, RuleRange& ruleRange)
{
if (!rules)
return;
for (typename RuleDataListType::const_iterator it = rules->begin(), end = rules->end(); it != end; ++it)
collectRuleIfMatches(*it, behaviorAtBoundary, cascadeScope, cascadeOrder, matchRequest, ruleRange);
}
bool ruleMatches(const RuleData&, const ContainerNode* scope, SelectorChecker::BehaviorAtBoundary, SelectorChecker::MatchResult*);
CSSRuleList* nestedRuleList(CSSRule*);
......
......@@ -43,6 +43,8 @@
#include "platform/TraceEvent.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "wtf/TerminatedArrayBuilder.h"
namespace WebCore {
using namespace HTMLNames;
......@@ -119,76 +121,6 @@ static inline PropertyWhitelistType determinePropertyWhitelistType(const AddRule
return PropertyWhitelistNone;
}
namespace {
// FIXME: Should we move this class to WTF?
template<typename T>
class TerminatedArrayBuilder {
public:
explicit TerminatedArrayBuilder(PassOwnPtr<T> array)
: m_array(array)
, m_count(0)
, m_capacity(0)
{
if (!m_array)
return;
for (T* item = m_array.get(); !item->isLastInArray(); ++item)
++m_count;
++m_count; // To count the last item itself.
m_capacity = m_count;
}
void grow(size_t count)
{
ASSERT(count);
if (!m_array) {
ASSERT(!m_count);
ASSERT(!m_capacity);
m_capacity = count;
m_array = adoptPtr(static_cast<T*>(fastMalloc(m_capacity * sizeof(T))));
return;
}
m_capacity += count;
m_array = adoptPtr(static_cast<T*>(fastRealloc(m_array.leakPtr(), m_capacity * sizeof(T))));
m_array.get()[m_count - 1].setLastInArray(false);
}
void append(const T& item)
{
RELEASE_ASSERT(m_count < m_capacity);
ASSERT(!item.isLastInArray());
m_array.get()[m_count++] = item;
}
PassOwnPtr<T> release()
{
RELEASE_ASSERT(m_count == m_capacity);
if (m_array)
m_array.get()[m_count - 1].setLastInArray(true);
assertValid();
return m_array.release();
}
private:
#ifndef NDEBUG
void assertValid()
{
for (size_t i = 0; i < m_count; ++i) {
bool isLastInArray = (i + 1 == m_count);
ASSERT(m_array.get()[i].isLastInArray() == isLastInArray);
}
}
#else
void assertValid() { }
#endif
OwnPtr<T> m_array;
size_t m_count;
size_t m_capacity;
};
}
RuleData::RuleData(StyleRule* rule, unsigned selectorIndex, unsigned position, AddRuleFlags addRuleFlags)
: m_rule(rule)
, m_selectorIndex(selectorIndex)
......
......@@ -30,6 +30,7 @@
#include "wtf/Forward.h"
#include "wtf/HashMap.h"
#include "wtf/LinkedStack.h"
#include "wtf/TerminatedArray.h"
namespace WebCore {
......@@ -125,10 +126,10 @@ public:
const RuleFeatureSet& features() const { return m_features; }
const RuleData* idRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_idRules.get(key); }
const RuleData* classRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_classRules.get(key); }
const RuleData* tagRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_tagRules.get(key); }
const RuleData* shadowPseudoElementRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_shadowPseudoElementRules.get(key); }
const TerminatedArray<RuleData>* idRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_idRules.get(key); }
const TerminatedArray<RuleData>* classRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_classRules.get(key); }
const TerminatedArray<RuleData>* tagRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_tagRules.get(key); }
const TerminatedArray<RuleData>* shadowPseudoElementRules(const AtomicString& key) const { ASSERT(!m_pendingRules); return m_shadowPseudoElementRules.get(key); }
const Vector<RuleData>* linkPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_linkPseudoClassRules; }
const Vector<RuleData>* cuePseudoRules() const { ASSERT(!m_pendingRules); return &m_cuePseudoRules; }
const Vector<RuleData>* focusPseudoClassRules() const { ASSERT(!m_pendingRules); return &m_focusPseudoClassRules; }
......@@ -164,7 +165,7 @@ public:
private:
typedef HashMap<AtomicString, OwnPtr<LinkedStack<RuleData> > > PendingRuleMap;
typedef HashMap<AtomicString, OwnPtr<RuleData> > CompactRuleMap;
typedef HashMap<AtomicString, OwnPtr<TerminatedArray<RuleData> > > CompactRuleMap;
RuleSet()
: m_ruleCount(0)
......
......@@ -42,9 +42,9 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_CustomPseudoElements)
helper.addCSSRules("summary::-webkit-details-marker { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("-webkit-details-marker");
const RuleData* ruleData = ruleSet.shadowPseudoElementRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
ASSERT_EQ(str, CSSTestHelper::getRule(ruleData, 0).selector().value());
const TerminatedArray<RuleData>* rules = ruleSet.shadowPseudoElementRules(str);
ASSERT_EQ(1u, rules->size());
ASSERT_EQ(str, rules->at(0).selector().value());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_Id)
......@@ -54,9 +54,9 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_Id)
helper.addCSSRules("#id { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("id");
const RuleData* ruleData = ruleSet.idRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
ASSERT_EQ(str, CSSTestHelper::getRule(ruleData, 0).selector().value());
const TerminatedArray<RuleData>* rules = ruleSet.idRules(str);
ASSERT_EQ(1u, rules->size());
ASSERT_EQ(str, rules->at(0).selector().value());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_NthChild)
......@@ -66,9 +66,9 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_NthChild)
helper.addCSSRules("div:nth-child(2) { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("div");
const RuleData* ruleData = ruleSet.tagRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
ASSERT_EQ(str, CSSTestHelper::getRule(ruleData, 0).selector().tagQName().localName());
const TerminatedArray<RuleData>* rules = ruleSet.tagRules(str);
ASSERT_EQ(1u, rules->size());
ASSERT_EQ(str, rules->at(0).selector().tagQName().localName());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_ClassThenId)
......@@ -79,10 +79,10 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_ClassThenId)
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("id");
// id is prefered over class even if class preceeds it in the selector.
const RuleData* ruleData = ruleSet.idRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
const TerminatedArray<RuleData>* rules = ruleSet.idRules(str);
ASSERT_EQ(1u, rules->size());
AtomicString classStr("class");
ASSERT_EQ(classStr, CSSTestHelper::getRule(ruleData, 0).selector().value());
ASSERT_EQ(classStr, rules->at(0).selector().value());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_IdThenClass)
......@@ -92,9 +92,9 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_IdThenClass)
helper.addCSSRules("#id.class { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("id");
const RuleData* ruleData = ruleSet.idRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
ASSERT_EQ(str, CSSTestHelper::getRule(ruleData, 0).selector().value());
const TerminatedArray<RuleData>* rules = ruleSet.idRules(str);
ASSERT_EQ(1u, rules->size());
ASSERT_EQ(str, rules->at(0).selector().value());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_AttrThenId)
......@@ -104,10 +104,10 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_AttrThenId)
helper.addCSSRules("[attr]#id { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("id");
const RuleData* ruleData = ruleSet.idRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
const TerminatedArray<RuleData>* rules = ruleSet.idRules(str);
ASSERT_EQ(1u, rules->size());
AtomicString attrStr("attr");
ASSERT_EQ(attrStr, CSSTestHelper::getRule(ruleData, 0).selector().attribute().localName());
ASSERT_EQ(attrStr, rules->at(0).selector().attribute().localName());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_TagThenAttrThenId)
......@@ -117,10 +117,10 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_TagThenAttrThenId)
helper.addCSSRules("div[attr]#id { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("id");
const RuleData* ruleData = ruleSet.idRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
const TerminatedArray<RuleData>* rules = ruleSet.idRules(str);
ASSERT_EQ(1u, rules->size());
AtomicString tagStr("div");
ASSERT_EQ(tagStr, CSSTestHelper::getRule(ruleData, 0).selector().tagQName().localName());
ASSERT_EQ(tagStr, rules->at(0).selector().tagQName().localName());
}
TEST(RuleSetTest, findBestRuleSetAndAdd_DivWithContent)
......@@ -130,10 +130,10 @@ TEST(RuleSetTest, findBestRuleSetAndAdd_DivWithContent)
helper.addCSSRules("div::content { }");
RuleSet& ruleSet = helper.ruleSet();
AtomicString str("div");
const RuleData* ruleData = ruleSet.tagRules(str);
ASSERT_EQ(1, CSSTestHelper::numRules(ruleData));
const TerminatedArray<RuleData>* rules = ruleSet.tagRules(str);
ASSERT_EQ(1u, rules->size());
AtomicString valueStr("content");
ASSERT_EQ(valueStr, CSSTestHelper::getRule(ruleData, 0).selector().value());
ASSERT_EQ(valueStr, rules->at(0).selector().value());
}
} // namespace WebCore
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TerminatedArray_h
#define TerminatedArray_h
#include "wtf/FastAllocBase.h"
#include "wtf/OwnPtr.h"
namespace WTF {
// TerminatedArray<T> represents a sequence of elements of type T in which each
// element knows whether it is the last element in the sequence or not. For this
// check type T must provide isLastInArray method.
// TerminatedArray<T> can only be constructed by TerminatedArrayBuilder<T>.
template<typename T>
class TerminatedArray {
WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(TerminatedArray);
public:
T& at(size_t index) { return reinterpret_cast<T*>(this)[index]; }
const T& at(size_t index) const { return reinterpret_cast<const T*>(this)[index]; }
template<typename U>
class iterator_base {
public:
iterator_base& operator++()
{
if (m_val->isLastInArray()) {
m_val = 0;
} else {
++m_val;
}
return *this;
}
U& operator*() const { return *m_val; }
bool operator==(const iterator_base& other) const { return m_val == other.m_val; }
bool operator!=(const iterator_base& other) const { return !(*this == other); }
private:
iterator_base(U* val) : m_val(val) { }
U* m_val;
friend class TerminatedArray;
};
typedef iterator_base<T> iterator;
typedef iterator_base<const T> const_iterator;
iterator begin() { return iterator(reinterpret_cast<T*>(this)); }
const_iterator begin() const { return const_iterator(reinterpret_cast<const T*>(this)); }
iterator end() { return iterator(0); }
const_iterator end() const { return const_iterator(0); }
size_t size() const
{
size_t count = 0;
for (const_iterator it = begin(); it != end(); ++it)
count++;
return count;
}
private:
static PassOwnPtr<TerminatedArray> create(size_t capacity)
{
return adoptPtr(static_cast<TerminatedArray*>(fastMalloc(capacity * sizeof(T))));
}
static PassOwnPtr<TerminatedArray> resize(PassOwnPtr<TerminatedArray> array, size_t capacity)
{
return adoptPtr(static_cast<TerminatedArray*>(fastRealloc(array.leakPtr(), capacity * sizeof(T))));
}
template<typename> friend class TerminatedArrayBuilder;
};
} // namespace WTF
using WTF::TerminatedArray;
#endif // TerminatedArray_h
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TerminatedArrayBuilder_h
#define TerminatedArrayBuilder_h
#include "wtf/OwnPtr.h"
namespace WTF {
template<typename T>
class TerminatedArrayBuilder {
DISALLOW_ALLOCATION();
WTF_MAKE_NONCOPYABLE(TerminatedArrayBuilder);
public:
explicit TerminatedArrayBuilder(PassOwnPtr<TerminatedArray<T> > array)
: m_array(array)
, m_count(0)
, m_capacity(0)
{
if (!m_array)
return;
m_capacity = m_count = m_array->size();
}
void grow(size_t count)
{
ASSERT(count);
if (!m_array) {
ASSERT(!m_count);
ASSERT(!m_capacity);
m_capacity = count;
m_array = TerminatedArray<T>::create(m_capacity);
return;
}
m_capacity += count;
m_array = TerminatedArray<T>::resize(m_array.release(), m_capacity);
m_array->at(m_count - 1).setLastInArray(false);
}
void append(const T& item)
{
RELEASE_ASSERT(m_count < m_capacity);
ASSERT(!item.isLastInArray());
m_array->at(m_count++) = item;
}
PassOwnPtr<TerminatedArray<T> > release()
{
RELEASE_ASSERT(m_count == m_capacity);
if (m_array)
m_array->at(m_count - 1).setLastInArray(true);
assertValid();
return m_array.release();
}
private:
#ifndef NDEBUG
void assertValid()
{
for (size_t i = 0; i < m_count; ++i) {
bool isLastInArray = (i + 1 == m_count);
ASSERT(m_array->at(i).isLastInArray() == isLastInArray);
}
}
#else
void assertValid() { }
#endif
OwnPtr<TerminatedArray<T> > m_array;
size_t m_count;
size_t m_capacity;
};
} // namespace WTF
using WTF::TerminatedArrayBuilder;
#endif // TerminatedArrayBuilder_h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment