Skip to content
This repository was archived by the owner on May 28, 2024. It is now read-only.

Commit e50ee6a

Browse files
author
bors-servo
authoredOct 27, 2016
Auto merge of #100 - servo:remove-string-cache-and-some-traits-and-split-bloom, r=nox
Remove string cache and some traits <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-selectors/100) <!-- Reviewable:end -->
2 parents cc734b2 + 7346186 commit e50ee6a

File tree

5 files changed

+104
-143
lines changed

5 files changed

+104
-143
lines changed
 

‎.travis.yml

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ rust:
55
- stable
66
script:
77
- cargo test
8-
- ([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --features unstable)
98

109
branches:
1110
except:

‎Cargo.toml

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
22

33
name = "selectors"
4-
version = "0.13.1"
4+
version = "0.14.0"
55
authors = ["Simon Sapin <simon.sapin@exyr.org>", "Alan Jeffrey <ajeffrey@mozilla.com>"]
6-
documentation = "http://doc.servo.org/selectors/"
6+
documentation = "https://docs.rs/selectors/"
77

88
description = "CSS Selectors matching for Rust"
99
repository = "https://github.com/servo/rust-selectors"
@@ -12,14 +12,12 @@ keywords = ["css", "selectors"]
1212
license = "MPL-2.0"
1313

1414
[features]
15-
unstable = ["string_cache/unstable"]
16-
heap_size = ["string_cache/heap_size", "heapsize", "heapsize_plugin"]
15+
heap_size = ["heapsize", "heapsize_plugin"]
1716

1817
[dependencies]
1918
bitflags = "0.7"
2019
matches = "0.1"
2120
cssparser = ">=0.6, <0.8"
2221
fnv = "1.0"
23-
string_cache = "0.2.16"
2422
heapsize = {version = "0.3", features = ["unstable"], optional = true}
2523
heapsize_plugin = {version = "0.1.0", optional = true}

‎src/bloom.rs

+17-61
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
//! Simple counting bloom filters.
66
77
use fnv::FnvHasher;
8-
use std::hash::Hasher;
9-
use string_cache::{Atom, Namespace};
8+
use std::hash::{Hash, Hasher};
109

1110
const KEY_SIZE: usize = 12;
1211
const ARRAY_SIZE: usize = 1 << KEY_SIZE;
@@ -124,8 +123,8 @@ impl BloomFilter {
124123

125124
/// Inserts an item into the bloom filter.
126125
#[inline]
127-
pub fn insert<T:BloomHash>(&mut self, elem: &T) {
128-
self.insert_hash(elem.bloom_hash())
126+
pub fn insert<T: Hash>(&mut self, elem: &T) {
127+
self.insert_hash(hash(elem))
129128

130129
}
131130

@@ -147,8 +146,8 @@ impl BloomFilter {
147146

148147
/// Removes an item from the bloom filter.
149148
#[inline]
150-
pub fn remove<T:BloomHash>(&mut self, elem: &T) {
151-
self.remove_hash(elem.bloom_hash())
149+
pub fn remove<T: Hash>(&mut self, elem: &T) {
150+
self.remove_hash(hash(elem))
152151
}
153152

154153
#[inline]
@@ -161,59 +160,8 @@ impl BloomFilter {
161160
/// but will never return false for items that are actually in the
162161
/// filter.
163162
#[inline]
164-
pub fn might_contain<T:BloomHash>(&self, elem: &T) -> bool {
165-
self.might_contain_hash(elem.bloom_hash())
166-
}
167-
}
168-
169-
pub trait BloomHash {
170-
fn bloom_hash(&self) -> u32;
171-
}
172-
173-
impl BloomHash for u64 {
174-
#[inline]
175-
fn bloom_hash(&self) -> u32 {
176-
((*self >> 32) ^ *self) as u32
177-
}
178-
}
179-
180-
impl BloomHash for isize {
181-
#[allow(exceeding_bitshifts)]
182-
#[inline]
183-
fn bloom_hash(&self) -> u32 {
184-
((*self >> 32) ^ *self) as u32
185-
}
186-
}
187-
188-
impl BloomHash for usize {
189-
#[allow(exceeding_bitshifts)]
190-
#[inline]
191-
fn bloom_hash(&self) -> u32 {
192-
((*self >> 32) ^ *self) as u32
193-
}
194-
}
195-
196-
impl BloomHash for Atom {
197-
#[inline]
198-
fn bloom_hash(&self) -> u32 {
199-
self.get_hash()
200-
}
201-
}
202-
203-
impl BloomHash for Namespace {
204-
#[inline]
205-
fn bloom_hash(&self) -> u32 {
206-
let Namespace(ref atom) = *self;
207-
atom.bloom_hash()
208-
}
209-
}
210-
211-
impl BloomHash for String {
212-
#[inline]
213-
fn bloom_hash(&self) -> u32 {
214-
let mut h = FnvHasher::default();
215-
h.write(self.as_bytes());
216-
h.finish().bloom_hash()
163+
pub fn might_contain<T: Hash>(&self, elem: &T) -> bool {
164+
self.might_contain_hash(hash(elem))
217165
}
218166
}
219167

@@ -222,6 +170,14 @@ fn full(slot: &u8) -> bool {
222170
*slot == 0xff
223171
}
224172

173+
#[inline]
174+
fn hash<T: Hash>(elem: &T) -> u32 {
175+
let mut hasher = FnvHasher::default();
176+
elem.hash(&mut hasher);
177+
let hash: u64 = hasher.finish();
178+
(hash >> 32) as u32 ^ (hash as u32)
179+
}
180+
225181
#[inline]
226182
fn hash1(hash: u32) -> u32 {
227183
hash & KEY_MASK
@@ -247,7 +203,7 @@ fn create_and_insert_some_stuff() {
247203
let false_positives =
248204
(1001_usize .. 2000).filter(|i| bf.might_contain(i)).count();
249205

250-
assert!(false_positives < 10); // 1%.
206+
assert!(false_positives < 150, "{} is not < 150", false_positives); // 15%.
251207

252208
for i in 0_usize .. 100 {
253209
bf.remove(&i);
@@ -259,7 +215,7 @@ fn create_and_insert_some_stuff() {
259215

260216
let false_positives = (0_usize .. 100).filter(|i| bf.might_contain(i)).count();
261217

262-
assert!(false_positives < 2); // 2%.
218+
assert!(false_positives < 20, "{} is not < 20", false_positives); // 20%.
263219

264220
bf.clear();
265221

‎src/lib.rs

-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
#![cfg_attr(all(test, feature = "unstable"), feature(test))]
65
#![cfg_attr(feature = "heap_size", feature(plugin, custom_derive))]
76
#![cfg_attr(feature = "heap_size", plugin(heapsize_plugin))]
87

98
#[cfg(feature = "heap_size")] extern crate heapsize;
109
#[macro_use] extern crate bitflags;
1110
#[macro_use] extern crate cssparser;
1211
#[macro_use] extern crate matches;
13-
#[macro_use] extern crate string_cache;
1412
extern crate fnv;
1513

1614
pub mod bloom;

‎src/parser.rs

+84-74
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use bloom::BloomHash;
65
use cssparser::{Token, Parser, parse_nth, ToCss, serialize_identifier, CssStringWriter};
76
use std::ascii::AsciiExt;
87
use std::borrow::{Borrow, Cow};
@@ -14,81 +13,92 @@ use std::sync::Arc;
1413

1514
use HashMap;
1615

17-
/// An empty trait that requires `HeapSizeOf` if the `heap_size` Cargo feature is enabled.
18-
#[cfg(feature = "heap_size")] pub trait MaybeHeapSizeOf: ::heapsize::HeapSizeOf {}
19-
#[cfg(feature = "heap_size")] impl<T: ::heapsize::HeapSizeOf> MaybeHeapSizeOf for T {}
16+
macro_rules! with_bounds {
17+
( [ $( $CommonBounds: tt )* ] [ $( $FromStr: tt )* ]) => {
18+
fn from_cow_str<T>(cow: Cow<str>) -> T where T: $($FromStr)* {
19+
match cow {
20+
Cow::Borrowed(s) => T::from(s),
21+
Cow::Owned(s) => T::from(s),
22+
}
23+
}
2024

21-
/// An empty trait that requires `HeapSizeOf` if the `heap_size` Cargo feature is enabled.
22-
#[cfg(not(feature = "heap_size"))] pub trait MaybeHeapSizeOf {}
23-
#[cfg(not(feature = "heap_size"))] impl<T> MaybeHeapSizeOf for T {}
25+
fn from_ascii_lowercase<T>(s: &str) -> T where T: $($FromStr)* {
26+
if let Some(first_uppercase) = s.bytes().position(|byte| byte >= b'A' && byte <= b'Z') {
27+
let mut string = s.to_owned();
28+
string[first_uppercase..].make_ascii_lowercase();
29+
T::from(string)
30+
} else {
31+
T::from(s)
32+
}
33+
}
2434

25-
/// Although it could, String does not implement From<Cow<str>>
26-
pub trait FromCowStr {
27-
fn from_cow_str(s: Cow<str>) -> Self;
28-
}
35+
/// This trait allows to define the parser implementation in regards
36+
/// of pseudo-classes/elements
37+
pub trait SelectorImpl: Sized + Debug {
38+
type AttrValue: $($CommonBounds)* + $($FromStr)* + Display;
39+
type Identifier: $($CommonBounds)* + $($FromStr)* + Display;
40+
type ClassName: $($CommonBounds)* + $($FromStr)* + Display;
41+
type LocalName: $($CommonBounds)* + $($FromStr)* + Display
42+
+ Borrow<Self::BorrowedLocalName>;
43+
type NamespaceUrl: $($CommonBounds)* + Display + Default
44+
+ Borrow<Self::BorrowedNamespaceUrl>;
45+
type NamespacePrefix: $($CommonBounds)* + $($FromStr)* + Display + Default;
46+
type BorrowedNamespaceUrl: ?Sized + Eq;
47+
type BorrowedLocalName: ?Sized + Eq + Hash;
48+
49+
/// non tree-structural pseudo-classes
50+
/// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
51+
type NonTSPseudoClass: $($CommonBounds)* + Sized + ToCss;
52+
53+
/// pseudo-elements
54+
type PseudoElement: $($CommonBounds)* + Sized + ToCss;
55+
56+
/// Declares if the following "attribute exists" selector is considered
57+
/// "common" enough to be shareable. If that's not the case, when matching
58+
/// over an element, the relation
59+
/// AFFECTED_BY_NON_COMMON_STYLE_AFFECTING_ATTRIBUTE would be set.
60+
fn attr_exists_selector_is_shareable(_attr_selector: &AttrSelector<Self>) -> bool {
61+
false
62+
}
2963

30-
impl FromCowStr for String {
31-
fn from_cow_str(s: Cow<str>) -> Self {
32-
s.into_owned()
33-
}
34-
}
64+
/// Declares if the following "equals" attribute selector is considered
65+
/// "common" enough to be shareable.
66+
fn attr_equals_selector_is_shareable(_attr_selector: &AttrSelector<Self>,
67+
_value: &Self::AttrValue) -> bool {
68+
false
69+
}
3570

36-
impl FromCowStr for ::string_cache::Atom {
37-
fn from_cow_str(s: Cow<str>) -> Self {
38-
s.into()
71+
/// This function can return an "Err" pseudo-element in order to support CSS2.1
72+
/// pseudo-elements.
73+
fn parse_non_ts_pseudo_class(_context: &ParserContext<Self>,
74+
_name: &str)
75+
-> Result<Self::NonTSPseudoClass, ()> { Err(()) }
76+
77+
fn parse_non_ts_functional_pseudo_class(_context: &ParserContext<Self>,
78+
_name: &str,
79+
_arguments: &mut Parser)
80+
-> Result<Self::NonTSPseudoClass, ()> { Err(()) }
81+
fn parse_pseudo_element(_context: &ParserContext<Self>,
82+
_name: &str)
83+
-> Result<Self::PseudoElement, ()> { Err(()) }
84+
}
3985
}
4086
}
4187

42-
/// This trait allows to define the parser implementation in regards
43-
/// of pseudo-classes/elements
44-
pub trait SelectorImpl: Sized + Debug {
45-
type AttrValue: Clone + Display + MaybeHeapSizeOf + Eq + FromCowStr + Hash;
46-
type Identifier: Clone + Display + MaybeHeapSizeOf + Eq + FromCowStr + Hash + BloomHash;
47-
type ClassName: Clone + Display + MaybeHeapSizeOf + Eq + FromCowStr + Hash + BloomHash;
48-
type LocalName: Clone + Display + MaybeHeapSizeOf + Eq + FromCowStr + Hash + BloomHash
49-
+ Borrow<Self::BorrowedLocalName>;
50-
type NamespaceUrl: Clone + Display + MaybeHeapSizeOf + Eq + Default + Hash + BloomHash
51-
+ Borrow<Self::BorrowedNamespaceUrl>;
52-
type NamespacePrefix: Clone + Display + MaybeHeapSizeOf + Eq + Default + Hash + FromCowStr;
53-
type BorrowedNamespaceUrl: ?Sized + Eq;
54-
type BorrowedLocalName: ?Sized + Eq + Hash;
55-
56-
/// Declares if the following "attribute exists" selector is considered
57-
/// "common" enough to be shareable. If that's not the case, when matching
58-
/// over an element, the relation
59-
/// AFFECTED_BY_NON_COMMON_STYLE_AFFECTING_ATTRIBUTE would be set.
60-
fn attr_exists_selector_is_shareable(_attr_selector: &AttrSelector<Self>) -> bool {
61-
false
88+
macro_rules! with_heap_size_bound {
89+
($( $HeapSizeOf: tt )*) => {
90+
with_bounds! {
91+
[Clone + Eq + Hash $($HeapSizeOf)*]
92+
[From<String> + for<'a> From<&'a str>]
93+
}
6294
}
95+
}
6396

64-
/// Declares if the following "equals" attribute selector is considered
65-
/// "common" enough to be shareable.
66-
fn attr_equals_selector_is_shareable(_attr_selector: &AttrSelector<Self>,
67-
_value: &Self::AttrValue) -> bool {
68-
false
69-
}
97+
#[cfg(feature = "heap_size")]
98+
with_heap_size_bound!(+ ::heapsize::HeapSizeOf);
7099

71-
/// non tree-structural pseudo-classes
72-
/// (see: https://drafts.csswg.org/selectors/#structural-pseudos)
73-
type NonTSPseudoClass: Clone + Eq + Hash + MaybeHeapSizeOf + PartialEq + Sized + ToCss;
74-
75-
/// This function can return an "Err" pseudo-element in order to support CSS2.1
76-
/// pseudo-elements.
77-
fn parse_non_ts_pseudo_class(_context: &ParserContext<Self>,
78-
_name: &str)
79-
-> Result<Self::NonTSPseudoClass, ()> { Err(()) }
80-
81-
fn parse_non_ts_functional_pseudo_class(_context: &ParserContext<Self>,
82-
_name: &str,
83-
_arguments: &mut Parser)
84-
-> Result<Self::NonTSPseudoClass, ()> { Err(()) }
85-
86-
/// pseudo-elements
87-
type PseudoElement: Sized + PartialEq + Eq + Clone + Hash + MaybeHeapSizeOf + ToCss;
88-
fn parse_pseudo_element(_context: &ParserContext<Self>,
89-
_name: &str)
90-
-> Result<Self::PseudoElement, ()> { Err(()) }
91-
}
100+
#[cfg(not(feature = "heap_size"))]
101+
with_heap_size_bound!();
92102

93103
pub struct ParserContext<Impl: SelectorImpl> {
94104
pub in_user_agent_stylesheet: bool,
@@ -714,8 +724,8 @@ fn parse_type_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>, input:
714724
match local_name {
715725
Some(name) => {
716726
compound_selector.push(SimpleSelector::LocalName(LocalName {
717-
lower_name: Impl::LocalName::from_cow_str(name.to_ascii_lowercase().into()),
718-
name: Impl::LocalName::from_cow_str(name),
727+
lower_name: from_ascii_lowercase(&name),
728+
name: from_cow_str(name),
719729
}))
720730
}
721731
None => (),
@@ -769,7 +779,7 @@ fn parse_qualified_name<'i, 't, Impl: SelectorImpl>
769779
let position = input.position();
770780
match input.next_including_whitespace() {
771781
Ok(Token::Delim('|')) => {
772-
let prefix = Impl::NamespacePrefix::from_cow_str(value);
782+
let prefix = from_cow_str(value);
773783
let result = context.namespace_prefixes.get(&prefix);
774784
let url = try!(result.ok_or(()));
775785
explicit_namespace(input, NamespaceConstraint::Specific(Namespace {
@@ -819,13 +829,13 @@ fn parse_attribute_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>, i
819829
Some((_, None)) => unreachable!(),
820830
Some((namespace, Some(local_name))) => AttrSelector {
821831
namespace: namespace,
822-
lower_name: Impl::LocalName::from_cow_str(local_name.to_ascii_lowercase().into()),
823-
name: Impl::LocalName::from_cow_str(local_name),
832+
lower_name: from_ascii_lowercase(&local_name),
833+
name: from_cow_str(local_name),
824834
},
825835
};
826836

827837
fn parse_value<Impl: SelectorImpl>(input: &mut Parser) -> Result<Impl::AttrValue, ()> {
828-
Ok(Impl::AttrValue::from_cow_str(try!(input.expect_ident_or_string())))
838+
Ok(from_cow_str(try!(input.expect_ident_or_string())))
829839
}
830840
// TODO: deal with empty value or value containing whitespace (see spec)
831841
match input.next() {
@@ -983,13 +993,13 @@ fn parse_one_simple_selector<Impl: SelectorImpl>(context: &ParserContext<Impl>,
983993
let start_position = input.position();
984994
match input.next_including_whitespace() {
985995
Ok(Token::IDHash(id)) => {
986-
let id = SimpleSelector::ID(Impl::Identifier::from_cow_str(id));
996+
let id = SimpleSelector::ID(from_cow_str(id));
987997
Ok(Some(SimpleSelectorParseResult::SimpleSelector(id)))
988998
}
989999
Ok(Token::Delim('.')) => {
9901000
match input.next_including_whitespace() {
9911001
Ok(Token::Ident(class)) => {
992-
let class = SimpleSelector::Class(Impl::ClassName::from_cow_str(class));
1002+
let class = SimpleSelector::Class(from_cow_str(class));
9931003
Ok(Some(SimpleSelectorParseResult::SimpleSelector(class)))
9941004
}
9951005
_ => Err(()),

0 commit comments

Comments
 (0)
This repository has been archived.