Skip to content

Commit 5f93d91

Browse files
committed
Merge pull request #1320 from xzyfer/perf/misc-improvements
Adds various performance improvements
2 parents d114e61 + 9c4d4e0 commit 5f93d91

File tree

9 files changed

+102
-47
lines changed

9 files changed

+102
-47
lines changed

ast.cpp

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -681,17 +681,17 @@ namespace Sass {
681681

682682
string Number::unit() const
683683
{
684-
stringstream u;
684+
string u;
685685
for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) {
686-
if (i) u << '*';
687-
u << numerator_units_[i];
686+
if (i) u += '*';
687+
u += numerator_units_[i];
688688
}
689-
if (!denominator_units_.empty()) u << '/';
689+
if (!denominator_units_.empty()) u += '/';
690690
for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) {
691-
if (i) u << '*';
692-
u << denominator_units_[i];
691+
if (i) u += '*';
692+
u += denominator_units_[i];
693693
}
694-
return u.str();
694+
return u;
695695
}
696696

697697
bool Number::is_unitless()
@@ -882,17 +882,11 @@ namespace Sass {
882882

883883
bool Number::operator== (Expression* rhs) const
884884
{
885-
try
886-
{
887-
Number l(pstate_, value_, unit());
888-
Number& r = dynamic_cast<Number&>(*rhs);
889-
l.normalize(find_convertible_unit());
890-
r.normalize(find_convertible_unit());
891-
return l.unit() == r.unit() &&
892-
l.value() == r.value();
885+
if (Number* r = static_cast<Number*>(rhs)) {
886+
return (value() == r->value()) &&
887+
(numerator_units_ == r->numerator_units_) &&
888+
(denominator_units_ == r->denominator_units_);
893889
}
894-
catch (std::bad_cast&) {}
895-
catch (...) { throw; }
896890
return false;
897891
}
898892

ast.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,7 @@ namespace Sass {
16981698
/////////////////////////////////////////
16991699
// Abstract base class for CSS selectors.
17001700
/////////////////////////////////////////
1701-
class Selector : public AST_Node {
1701+
class Selector : public Expression {
17021702
ADD_PROPERTY(bool, has_reference)
17031703
ADD_PROPERTY(bool, has_placeholder)
17041704
// line break before list separator
@@ -1712,14 +1712,14 @@ namespace Sass {
17121712
ADD_PROPERTY(Media_Block*, media_block)
17131713
public:
17141714
Selector(ParserState pstate, bool r = false, bool h = false)
1715-
: AST_Node(pstate),
1715+
: Expression(pstate),
17161716
has_reference_(r),
17171717
has_placeholder_(h),
17181718
has_line_feed_(false),
17191719
has_line_break_(false),
17201720
is_optional_(false),
17211721
media_block_(0)
1722-
{ }
1722+
{ concrete_type(SELECTOR); }
17231723
virtual ~Selector() = 0;
17241724
// virtual Selector_Placeholder* find_placeholder();
17251725
virtual unsigned long specificity() {

cssize.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ namespace Sass {
136136
return rules;
137137
}
138138

139+
Statement* Cssize::operator()(Null* m)
140+
{
141+
return 0;
142+
}
143+
139144
Statement* Cssize::operator()(Media_Block* m)
140145
{
141146
if (parent()->statement_type() == Statement::RULESET)
@@ -243,7 +248,6 @@ namespace Sass {
243248
At_Root_Block* mm = new (ctx.mem) At_Root_Block(m->pstate(),
244249
wrapper_block,
245250
m->expression());
246-
247251
Bubble* bubble = new (ctx.mem) Bubble(mm->pstate(), mm);
248252
return bubble;
249253
}

cssize.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ namespace Sass {
5656
// Statement* operator()(Definition*);
5757
// Statement* operator()(Mixin_Call*);
5858
// Statement* operator()(Content*);
59+
Statement* operator()(Null*);
5960

6061
Statement* parent();
6162
vector<pair<bool, Block*>> slice_by_bubble(Statement*);

environment.hpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,31 @@
11
#ifndef SASS_ENVIRONMENT_H
22
#define SASS_ENVIRONMENT_H
33

4-
#include <map>
54
#include <string>
65
#include <iostream>
6+
#include <unordered_map>
77

88
#include "ast_fwd_decl.hpp"
99
#include "ast_def_macros.hpp"
1010
#include "memory_manager.hpp"
1111

1212
namespace Sass {
1313
using std::string;
14-
using std::map;
14+
using std::unordered_map;
1515
using std::cerr;
1616
using std::endl;
1717

1818
template <typename T>
1919
class Environment {
2020
// TODO: test with unordered_map
21-
map<string, T> local_frame_;
21+
unordered_map<string, T> local_frame_;
2222
ADD_PROPERTY(Environment*, parent)
2323

2424
public:
2525
Memory_Manager<AST_Node> mem;
26-
Environment() : local_frame_(map<string, T>()), parent_(0) { }
26+
Environment() : local_frame_(unordered_map<string, T>()), parent_(0) { }
27+
Environment(Environment* env) : local_frame_(unordered_map<string, T>()), parent_(env) { }
28+
Environment(Environment& env) : local_frame_(unordered_map<string, T>()), parent_(&env) { }
2729

2830
// link parent to create a stack
2931
void link(Environment& env) { parent_ = &env; }
@@ -47,12 +49,12 @@ namespace Sass {
4749

4850
// scope operates on the current frame
4951

50-
map<string, T>& local_frame() {
52+
unordered_map<string, T>& local_frame() {
5153
return local_frame_;
5254
}
5355

5456
bool has_local(const string& key) const
55-
{ return local_frame_.count(key); }
57+
{ return local_frame_.find(key) != local_frame_.end(); }
5658

5759
T& get_local(const string& key)
5860
{ return local_frame_[key]; }
@@ -147,7 +149,7 @@ namespace Sass {
147149
#ifdef DEBUG
148150
void print()
149151
{
150-
for (typename map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
152+
for (typename unordered_map<string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
151153
cerr << i->first << endl;
152154
}
153155
if (parent_) {

eval.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -829,12 +829,7 @@ namespace Sass {
829829

830830
Expression* Eval::operator()(Number* n)
831831
{
832-
n->normalize();
833-
// behave according to as ruby sass (add leading zero)
834-
return new (ctx.mem) Number(n->pstate(),
835-
n->value(),
836-
n->unit(),
837-
true);
832+
return n;
838833
}
839834

840835
Expression* Eval::operator()(Boolean* b)
@@ -1109,8 +1104,11 @@ namespace Sass {
11091104
} break;
11101105

11111106
case Expression::NUMBER: {
1112-
return *static_cast<Number*>(lhs) ==
1113-
*static_cast<Number*>(rhs);
1107+
Number* l = static_cast<Number*>(lhs);
1108+
Number* r = static_cast<Number*>(rhs);
1109+
return (l->value() == r->value()) &&
1110+
(l->numerator_units() == r->numerator_units()) &&
1111+
(l->denominator_units() == r->denominator_units());
11141112
} break;
11151113

11161114
case Expression::COLOR: {

lexer.hpp

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,26 +142,69 @@ namespace Sass {
142142
// Tries supplied matchers in order.
143143
// Succeeds if one of them succeeds.
144144
// Regex equivalent: /(?:FOO|BAR)/
145-
template <prelexer... mxs>
145+
template <const prelexer mx>
146146
const char* alternatives(const char* src) {
147147
const char* rslt;
148-
for (prelexer mx : { mxs... }) {
149-
if ((rslt = mx(src))) return rslt;
150-
}
148+
if ((rslt = mx(src))) return rslt;
151149
return 0;
152150
}
151+
template <const prelexer mx1, const prelexer mx2>
152+
const char* alternatives(const char* src) {
153+
const char* rslt;
154+
if ((rslt = mx1(src))) return rslt;
155+
if ((rslt = mx2(src))) return rslt;
156+
return 0;
157+
}
158+
template <const prelexer mx1, const prelexer mx2, const prelexer mx3>
159+
const char* alternatives(const char* src) {
160+
const char* rslt;
161+
if ((rslt = mx1(src))) return rslt;
162+
if ((rslt = mx2(src))) return rslt;
163+
if ((rslt = mx3(src))) return rslt;
164+
return 0;
165+
}
166+
template <const prelexer mx1, const prelexer mx2, const prelexer mx3, const prelexer mx4, const prelexer... mxs>
167+
const char* alternatives(const char* src) {
168+
const char* rslt;
169+
if ((rslt = mx1(src))) return rslt;
170+
if ((rslt = mx2(src))) return rslt;
171+
if ((rslt = mx3(src))) return rslt;
172+
return alternatives<mx4, mxs...>(src);
173+
}
153174

154175
// Tries supplied matchers in order.
155176
// Succeeds if all of them succeeds.
156177
// Regex equivalent: /(?:FOO)(?:BAR)/
157-
template <prelexer... mxs>
178+
template <const prelexer mx1>
158179
const char* sequence(const char* src) {
159180
const char* rslt = src;
160-
for (prelexer mx : { mxs... }) {
161-
if (!(rslt = mx(rslt))) return 0;
162-
}
181+
if (!(rslt = mx1(rslt))) return 0;
163182
return rslt;
164183
}
184+
template <const prelexer mx1, const prelexer mx2>
185+
const char* sequence(const char* src) {
186+
const char* rslt = src;
187+
if (!(rslt = mx1(rslt))) return 0;
188+
if (!(rslt = mx2(rslt))) return 0;
189+
return rslt;
190+
}
191+
template <const prelexer mx1, const prelexer mx2, const prelexer mx3>
192+
const char* sequence(const char* src) {
193+
const char* rslt = src;
194+
if (!(rslt = mx1(rslt))) return 0;
195+
if (!(rslt = mx2(rslt))) return 0;
196+
if (!(rslt = mx3(rslt))) return 0;
197+
return rslt;
198+
}
199+
template <const prelexer mx1, const prelexer mx2, const prelexer mx3, const prelexer mx4, const prelexer... mxs>
200+
const char* sequence(const char* src) {
201+
const char* rslt = src;
202+
if (!(rslt = mx1(rslt))) return 0;
203+
if (!(rslt = mx2(rslt))) return 0;
204+
if (!(rslt = mx3(rslt))) return 0;
205+
return sequence<mx4, mxs...>(rslt);
206+
}
207+
165208

166209
// Match a pattern or not. Always succeeds.
167210
// Regex equivalent: /(?:literal)?/

output.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,10 +221,8 @@ namespace Sass {
221221
q->perform(this);
222222
append_scope_opener();
223223

224-
Selector* e = f->selector();
225-
if (e && b->has_non_hoistable()) {
224+
if (b->has_non_hoistable()) {
226225
// JMA - hoisted, output the non-hoistable in a nested block, followed by the hoistable
227-
e->perform(this);
228226
append_scope_opener();
229227

230228
for (size_t i = 0, L = b->length(); i < L; ++i) {

parser.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,11 +511,17 @@ namespace Sass {
511511
return ruleset;
512512
}
513513

514+
// parse a selector schema that will be evaluated in the eval stage
515+
// uses a string schema internally to do the actual schema handling
516+
// in the eval stage we will be re-parse it into an actual selector
514517
Selector_Schema* Parser::parse_selector_schema(const char* end_of_selector)
515518
{
519+
// move up to the start
516520
lex< optional_spaces >();
517521
const char* i = position;
522+
// selector schema re-uses string schema implementation
518523
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
524+
// process until end
519525
while (i < end_of_selector) {
520526
// try to parse mutliple interpolants
521527
if (const char* p = find_first_in_interval< exactly<hash_lbrace> >(i, end_of_selector)) {
@@ -525,25 +531,34 @@ namespace Sass {
525531
if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
526532
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
527533
}
534+
// skip over all nested inner interpolations up to our own delimiter
528535
const char* j = skip_over_scopes< exactly<hash_lbrace>, exactly<rbrace> >(p + 2, end_of_selector);
536+
// pass inner expression to the parser to resolve nested interpolations
529537
Expression* interpolant = Parser::from_c_str(p+2, j, ctx, pstate).parse_list();
538+
// set status on the list expression
530539
interpolant->is_interpolant(true);
540+
// add to the string schema
531541
(*schema) << interpolant;
542+
// advance position
532543
i = j;
533544
}
534545
// no more interpolants have been found
535546
// add the last segment if there is one
536547
else {
548+
// make sure to add the last bits of the string up to the end (if any)
537549
if (i < end_of_selector) (*schema) << new (ctx.mem) String_Quoted(pstate, string(i, end_of_selector));
538550
break;
539551
}
540552
}
553+
// EO until eos
541554
position = end_of_selector;
542555
Selector_Schema* selector_schema = new (ctx.mem) Selector_Schema(pstate, schema);
543556
selector_schema->media_block(last_media_block);
544557
selector_schema->last_block(block_stack.back());
558+
// return parsed result
545559
return selector_schema;
546560
}
561+
// EO parse_selector_schema
547562

548563
Selector_List* Parser::parse_selector_group()
549564
{

0 commit comments

Comments
 (0)