Skip to content

Commit e33894e

Browse files
authored
Merge pull request #2339 from mgreter/perf-refactor/loops-and-env
Performance improvements
2 parents 4c4af04 + ca70b9a commit e33894e

File tree

9 files changed

+293
-102
lines changed

9 files changed

+293
-102
lines changed

src/ast.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ namespace Sass {
169169
C_WARNING,
170170
C_ERROR,
171171
FUNCTION,
172+
VARIABLE,
172173
NUM_TYPES
173174
};
174175
enum Simple_Type {
@@ -1512,10 +1513,10 @@ namespace Sass {
15121513
public:
15131514
Variable(ParserState pstate, std::string n)
15141515
: PreValue(pstate), name_(n)
1515-
{ }
1516+
{ concrete_type(VARIABLE); }
15161517
Variable(const Variable* ptr)
15171518
: PreValue(ptr), name_(ptr->name_)
1518-
{ }
1519+
{ concrete_type(VARIABLE); }
15191520

15201521
virtual bool operator==(const Expression& rhs) const
15211522
{

src/ast_fwd_decl.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ namespace Sass {
414414
typedef std::set<Compound_Selector_Obj, OrderNodes> CompoundSelectorSet;
415415
typedef std::unordered_set<Simple_Selector_Obj, HashNodes, CompareNodes> SimpleSelectorDict;
416416

417+
// only to switch implementations for testing
418+
#define environment_map std::map
419+
417420
// ###########################################################################
418421
// explicit type conversion functions
419422
// ###########################################################################

src/environment.cpp

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

77
template <typename T>
88
Environment<T>::Environment(bool is_shadow)
9-
: local_frame_(std::map<std::string, T>()),
9+
: local_frame_(environment_map<std::string, T>()),
1010
parent_(0), is_shadow_(false)
1111
{ }
1212
template <typename T>
1313
Environment<T>::Environment(Environment<T>* env, bool is_shadow)
14-
: local_frame_(std::map<std::string, T>()),
14+
: local_frame_(environment_map<std::string, T>()),
1515
parent_(env), is_shadow_(is_shadow)
1616
{ }
1717
template <typename T>
1818
Environment<T>::Environment(Environment<T>& env, bool is_shadow)
19-
: local_frame_(std::map<std::string, T>()),
19+
: local_frame_(environment_map<std::string, T>()),
2020
parent_(&env), is_shadow_(is_shadow)
2121
{ }
2222

@@ -45,20 +45,33 @@ namespace Sass {
4545
}
4646

4747
template <typename T>
48-
std::map<std::string, T>& Environment<T>::local_frame() {
48+
environment_map<std::string, T>& Environment<T>::local_frame() {
4949
return local_frame_;
5050
}
5151

5252
template <typename T>
5353
bool Environment<T>::has_local(const std::string& key) const
5454
{ return local_frame_.find(key) != local_frame_.end(); }
5555

56+
template <typename T> EnvResult
57+
Environment<T>::find_local(const std::string& key)
58+
{
59+
auto end = local_frame_.end();
60+
auto it = local_frame_.find(key);
61+
return EnvResult(it, it != end);
62+
}
63+
5664
template <typename T>
5765
T& Environment<T>::get_local(const std::string& key)
5866
{ return local_frame_[key]; }
5967

6068
template <typename T>
61-
void Environment<T>::set_local(const std::string& key, T val)
69+
void Environment<T>::set_local(const std::string& key, const T& val)
70+
{
71+
local_frame_[key] = val;
72+
}
73+
template <typename T>
74+
void Environment<T>::set_local(const std::string& key, T&& val)
6275
{
6376
local_frame_[key] = val;
6477
}
@@ -86,7 +99,12 @@ namespace Sass {
8699
{ return (*global_env())[key]; }
87100

88101
template <typename T>
89-
void Environment<T>::set_global(const std::string& key, T val)
102+
void Environment<T>::set_global(const std::string& key, const T& val)
103+
{
104+
global_env()->local_frame_[key] = val;
105+
}
106+
template <typename T>
107+
void Environment<T>::set_global(const std::string& key, T&& val)
90108
{
91109
global_env()->local_frame_[key] = val;
92110
}
@@ -126,13 +144,31 @@ namespace Sass {
126144
// either update already existing lexical value
127145
// or if flag is set, we create one if no lexical found
128146
template <typename T>
129-
void Environment<T>::set_lexical(const std::string& key, T val)
147+
void Environment<T>::set_lexical(const std::string& key, const T& val)
130148
{
131-
auto cur = this;
149+
Environment<T>* cur = this;
132150
bool shadow = false;
133151
while ((cur && cur->is_lexical()) || shadow) {
134-
if (cur->has_local(key)) {
135-
cur->set_local(key, val);
152+
EnvResult rv(cur->find_local(key));
153+
if (rv.found) {
154+
rv.it->second = val;
155+
return;
156+
}
157+
shadow = cur->is_shadow();
158+
cur = cur->parent_;
159+
}
160+
set_local(key, val);
161+
}
162+
// this one moves the value
163+
template <typename T>
164+
void Environment<T>::set_lexical(const std::string& key, T&& val)
165+
{
166+
Environment<T>* cur = this;
167+
bool shadow = false;
168+
while ((cur && cur->is_lexical()) || shadow) {
169+
EnvResult rv(cur->find_local(key));
170+
if (rv.found) {
171+
rv.it->second = val;
136172
return;
137173
}
138174
shadow = cur->is_shadow();
@@ -156,6 +192,20 @@ namespace Sass {
156192
return false;
157193
}
158194

195+
// look on the full stack for key
196+
// include all scopes available
197+
template <typename T> EnvResult
198+
Environment<T>::find(const std::string& key)
199+
{
200+
auto cur = this;
201+
while (true) {
202+
EnvResult rv(cur->find_local(key));
203+
if (rv.found) return rv;
204+
cur = cur->parent_;
205+
if (!cur) return rv;
206+
}
207+
};
208+
159209
// use array access for getter and setter functions
160210
template <typename T>
161211
T& Environment<T>::operator[](const std::string& key)
@@ -177,7 +227,7 @@ namespace Sass {
177227
size_t indent = 0;
178228
if (parent_) indent = parent_->print(prefix) + 1;
179229
std::cerr << prefix << std::string(indent, ' ') << "== " << this << std::endl;
180-
for (typename std::map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
230+
for (typename environment_map<std::string, T>::iterator i = local_frame_.begin(); i != local_frame_.end(); ++i) {
181231
if (!ends_with(i->first, "[f]") && !ends_with(i->first, "[f]4") && !ends_with(i->first, "[f]2")) {
182232
std::cerr << prefix << std::string(indent, ' ') << i->first << " " << i->second;
183233
if (Value_Ptr val = Cast<Value>(i->second))

src/environment.hpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22
#define SASS_ENVIRONMENT_H
33

44
#include <string>
5-
#include <map>
6-
75
#include "ast_fwd_decl.hpp"
86
#include "ast_def_macros.hpp"
97

108
namespace Sass {
119

10+
typedef environment_map<std::string, AST_Node_Obj>::iterator EnvIter;
11+
12+
class EnvResult {
13+
public:
14+
EnvIter it;
15+
bool found;
16+
public:
17+
EnvResult(EnvIter it, bool found)
18+
: it(it), found(found) {}
19+
};
20+
1221
template <typename T>
1322
class Environment {
1423
// TODO: test with map
15-
std::map<std::string, T> local_frame_;
24+
environment_map<std::string, T> local_frame_;
1625
ADD_PROPERTY(Environment*, parent)
1726
ADD_PROPERTY(bool, is_shadow)
1827

@@ -37,14 +46,17 @@ namespace Sass {
3746

3847
// scope operates on the current frame
3948

40-
std::map<std::string, T>& local_frame();
49+
environment_map<std::string, T>& local_frame();
4150

4251
bool has_local(const std::string& key) const;
4352

53+
EnvResult find_local(const std::string& key);
54+
4455
T& get_local(const std::string& key);
4556

4657
// set variable on the current frame
47-
void set_local(const std::string& key, T val);
58+
void set_local(const std::string& key, const T& val);
59+
void set_local(const std::string& key, T&& val);
4860

4961
void del_local(const std::string& key);
5062

@@ -60,7 +72,8 @@ namespace Sass {
6072
T& get_global(const std::string& key);
6173

6274
// set a variable on the global frame
63-
void set_global(const std::string& key, T val);
75+
void set_global(const std::string& key, const T& val);
76+
void set_global(const std::string& key, T&& val);
6477

6578
void del_global(const std::string& key);
6679

@@ -72,12 +85,17 @@ namespace Sass {
7285
// see if we have a lexical we could update
7386
// either update already existing lexical value
7487
// or we create a new one on the current frame
75-
void set_lexical(const std::string& key, T val);
88+
void set_lexical(const std::string& key, T&& val);
89+
void set_lexical(const std::string& key, const T& val);
7690

7791
// look on the full stack for key
7892
// include all scopes available
7993
bool has(const std::string& key) const;
8094

95+
// look on the full stack for key
96+
// include all scopes available
97+
EnvResult find(const std::string& key);
98+
8199
// use array access for getter and setter functions
82100
T& operator[](const std::string& key);
83101

0 commit comments

Comments
 (0)