Skip to content

Commit ebb2053

Browse files
committed
Implement optimized environment accessors
Use result from find whenever possible. Avoids the need to fetch key bucket twice.
1 parent 6be3eb0 commit ebb2053

File tree

3 files changed

+85
-23
lines changed

3 files changed

+85
-23
lines changed

src/environment.cpp

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,25 @@ namespace Sass {
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)

src/environment.hpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@
77

88
namespace Sass {
99

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+
1021
template <typename T>
1122
class Environment {
1223
// TODO: test with map
@@ -39,10 +50,13 @@ namespace Sass {
3950

4051
bool has_local(const std::string& key) const;
4152

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

4457
// set variable on the current frame
45-
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);
4660

4761
void del_local(const std::string& key);
4862

@@ -58,7 +72,8 @@ namespace Sass {
5872
T& get_global(const std::string& key);
5973

6074
// set a variable on the global frame
61-
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);
6277

6378
void del_global(const std::string& key);
6479

@@ -70,12 +85,17 @@ namespace Sass {
7085
// see if we have a lexical we could update
7186
// either update already existing lexical value
7287
// or we create a new one on the current frame
73-
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);
7490

7591
// look on the full stack for key
7692
// include all scopes available
7793
bool has(const std::string& key) const;
7894

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

src/eval.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -989,27 +989,19 @@ namespace Sass {
989989

990990
Expression_Ptr Eval::operator()(Variable_Ptr v)
991991
{
992-
std::string name(v->name());
993992
Expression_Obj value = 0;
994993
Env* env = environment();
995-
if (env->has(name)) {
996-
value = Cast<Expression>((*env)[name]);
997-
}
994+
const std::string& name(v->name());
995+
EnvResult rv(env->find(name));
996+
if (rv.found) value = static_cast<Expression*>(rv.it->second.ptr());
998997
else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
999-
if (Argument* arg = Cast<Argument>(value)) {
1000-
value = arg->value();
1001-
}
1002-
1003-
// behave according to as ruby sass (add leading zero)
1004-
if (Number_Ptr nr = Cast<Number>(value)) {
1005-
nr->zero(true);
1006-
}
1007-
998+
if (Argument_Ptr arg = Cast<Argument>(value)) value = arg->value();
999+
if (Number_Ptr nr = Cast<Number>(value)) nr->zero(true); // force flag
10081000
value->is_interpolant(v->is_interpolant());
10091001
if (force) value->is_expanded(false);
10101002
value->set_delayed(false); // verified
10111003
value = value->perform(this);
1012-
if(!force) (*env)[name] = value;
1004+
if(!force) rv.it->second = value;
10131005
return value.detach();
10141006
}
10151007

0 commit comments

Comments
 (0)