sassc 1.11.4 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.md +4 -1
- data/ext/libsass/.editorconfig +1 -1
- data/ext/libsass/.github/CONTRIBUTING.md +7 -7
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
- data/ext/libsass/.gitignore +3 -0
- data/ext/libsass/.travis.yml +37 -18
- data/ext/libsass/GNUmakefile.am +23 -37
- data/ext/libsass/Makefile +10 -6
- data/ext/libsass/Makefile.conf +3 -0
- data/ext/libsass/Readme.md +68 -63
- data/ext/libsass/appveyor.yml +7 -3
- data/ext/libsass/configure.ac +10 -14
- data/ext/libsass/docs/api-context-internal.md +29 -21
- data/ext/libsass/docs/api-context.md +26 -6
- data/ext/libsass/docs/api-doc.md +49 -16
- data/ext/libsass/docs/api-function-example.md +1 -1
- data/ext/libsass/docs/api-function.md +31 -7
- data/ext/libsass/docs/api-importer.md +19 -19
- data/ext/libsass/docs/api-value.md +4 -2
- data/ext/libsass/docs/build-on-windows.md +4 -4
- data/ext/libsass/docs/build-with-mingw.md +3 -3
- data/ext/libsass/docs/build.md +9 -9
- data/ext/libsass/docs/custom-functions-internal.md +10 -8
- data/ext/libsass/docs/implementations.md +20 -8
- data/ext/libsass/docs/unicode.md +16 -10
- data/ext/libsass/include/sass/base.h +0 -3
- data/ext/libsass/include/sass/context.h +20 -2
- data/ext/libsass/include/sass/functions.h +31 -0
- data/ext/libsass/include/sass/values.h +3 -1
- data/ext/libsass/include/sass/version.h +1 -1
- data/ext/libsass/include/sass/version.h.in +1 -1
- data/ext/libsass/include/sass2scss.h +1 -1
- data/ext/libsass/res/resource.rc +6 -6
- data/ext/libsass/script/ci-build-libsass +10 -5
- data/ext/libsass/script/ci-build-plugin +62 -0
- data/ext/libsass/script/ci-install-compiler +1 -1
- data/ext/libsass/script/ci-install-deps +4 -7
- data/ext/libsass/script/ci-report-coverage +13 -3
- data/ext/libsass/script/tap-driver +1 -1
- data/ext/libsass/script/tap-runner +1 -1
- data/ext/libsass/src/GNUmakefile.am +1 -1
- data/ext/libsass/src/ast.cpp +537 -762
- data/ext/libsass/src/ast.hpp +377 -419
- data/ext/libsass/src/ast_def_macros.hpp +26 -1
- data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
- data/ext/libsass/src/b64/encode.h +3 -1
- data/ext/libsass/src/backtrace.cpp +46 -0
- data/ext/libsass/src/backtrace.hpp +7 -54
- data/ext/libsass/src/bind.cpp +72 -50
- data/ext/libsass/src/bind.hpp +0 -1
- data/ext/libsass/src/cencode.c +6 -0
- data/ext/libsass/src/check_nesting.cpp +157 -135
- data/ext/libsass/src/check_nesting.hpp +11 -10
- data/ext/libsass/src/color_maps.cpp +10 -6
- data/ext/libsass/src/color_maps.hpp +6 -8
- data/ext/libsass/src/constants.cpp +4 -3
- data/ext/libsass/src/constants.hpp +4 -3
- data/ext/libsass/src/context.cpp +110 -47
- data/ext/libsass/src/context.hpp +11 -1
- data/ext/libsass/src/cssize.cpp +105 -94
- data/ext/libsass/src/cssize.hpp +4 -5
- data/ext/libsass/src/debugger.hpp +247 -244
- data/ext/libsass/src/emitter.cpp +30 -6
- data/ext/libsass/src/emitter.hpp +7 -0
- data/ext/libsass/src/environment.cpp +67 -16
- data/ext/libsass/src/environment.hpp +28 -7
- data/ext/libsass/src/error_handling.cpp +92 -64
- data/ext/libsass/src/error_handling.hpp +64 -43
- data/ext/libsass/src/eval.cpp +494 -544
- data/ext/libsass/src/eval.hpp +17 -23
- data/ext/libsass/src/expand.cpp +182 -154
- data/ext/libsass/src/expand.hpp +4 -5
- data/ext/libsass/src/extend.cpp +299 -291
- data/ext/libsass/src/extend.hpp +46 -11
- data/ext/libsass/src/file.cpp +103 -36
- data/ext/libsass/src/file.hpp +21 -4
- data/ext/libsass/src/functions.cpp +561 -312
- data/ext/libsass/src/functions.hpp +8 -5
- data/ext/libsass/src/inspect.cpp +108 -53
- data/ext/libsass/src/inspect.hpp +5 -2
- data/ext/libsass/src/lexer.cpp +15 -7
- data/ext/libsass/src/lexer.hpp +13 -4
- data/ext/libsass/src/listize.cpp +3 -2
- data/ext/libsass/src/listize.hpp +0 -1
- data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
- data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
- data/ext/libsass/src/node.cpp +34 -38
- data/ext/libsass/src/node.hpp +6 -8
- data/ext/libsass/src/operation.hpp +2 -2
- data/ext/libsass/src/operators.cpp +240 -0
- data/ext/libsass/src/operators.hpp +30 -0
- data/ext/libsass/src/output.cpp +22 -20
- data/ext/libsass/src/parser.cpp +719 -358
- data/ext/libsass/src/parser.hpp +57 -22
- data/ext/libsass/src/plugins.cpp +28 -10
- data/ext/libsass/src/position.cpp +21 -3
- data/ext/libsass/src/position.hpp +2 -1
- data/ext/libsass/src/prelexer.cpp +104 -19
- data/ext/libsass/src/prelexer.hpp +10 -3
- data/ext/libsass/src/remove_placeholders.cpp +9 -10
- data/ext/libsass/src/remove_placeholders.hpp +1 -5
- data/ext/libsass/src/sass.cpp +62 -4
- data/ext/libsass/src/sass.hpp +5 -2
- data/ext/libsass/src/sass_context.cpp +96 -58
- data/ext/libsass/src/sass_context.hpp +7 -5
- data/ext/libsass/src/sass_functions.cpp +63 -1
- data/ext/libsass/src/sass_functions.hpp +19 -1
- data/ext/libsass/src/sass_util.cpp +3 -3
- data/ext/libsass/src/sass_util.hpp +4 -4
- data/ext/libsass/src/sass_values.cpp +42 -39
- data/ext/libsass/src/sass_values.hpp +2 -1
- data/ext/libsass/src/source_map.cpp +16 -18
- data/ext/libsass/src/subset_map.cpp +6 -8
- data/ext/libsass/src/subset_map.hpp +6 -6
- data/ext/libsass/src/to_c.cpp +2 -2
- data/ext/libsass/src/to_value.cpp +8 -3
- data/ext/libsass/src/to_value.hpp +1 -0
- data/ext/libsass/src/units.cpp +349 -45
- data/ext/libsass/src/units.hpp +39 -22
- data/ext/libsass/src/utf8/checked.h +7 -0
- data/ext/libsass/src/utf8/unchecked.h +7 -0
- data/ext/libsass/src/utf8_string.cpp +1 -1
- data/ext/libsass/src/util.cpp +139 -45
- data/ext/libsass/src/util.hpp +4 -7
- data/ext/libsass/src/values.cpp +15 -23
- data/ext/libsass/win/libsass.sln +13 -2
- data/ext/libsass/win/libsass.sln.DotSettings +9 -0
- data/ext/libsass/win/libsass.targets +3 -0
- data/ext/libsass/win/libsass.vcxproj.filters +9 -0
- data/lib/sassc/version.rb +1 -1
- data/sassc.gemspec +1 -1
- data/test/native_test.rb +1 -1
- metadata +11 -4
|
@@ -4,22 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
namespace Sass {
|
|
6
6
|
|
|
7
|
-
void Subset_Map::put(const Compound_Selector_Obj& sel, const
|
|
7
|
+
void Subset_Map::put(const Compound_Selector_Obj& sel, const SubSetMapPair& value)
|
|
8
8
|
{
|
|
9
9
|
if (sel->empty()) throw std::runtime_error("internal error: subset map keys may not be empty");
|
|
10
10
|
size_t index = values_.size();
|
|
11
11
|
values_.push_back(value);
|
|
12
12
|
for (size_t i = 0, S = sel->length(); i < S; ++i)
|
|
13
13
|
{
|
|
14
|
-
hash_[(*sel)[i]].push_back(std::make_pair(
|
|
14
|
+
hash_[(*sel)[i]].push_back(std::make_pair(sel, index));
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
std::vector<
|
|
18
|
+
std::vector<SubSetMapPair> Subset_Map::get_kv(const Compound_Selector_Obj& sel)
|
|
19
19
|
{
|
|
20
|
-
|
|
21
|
-
// std::set<std::string> dict(s.begin(), s.end());
|
|
22
|
-
std::unordered_set<Simple_Selector_Obj, HashSimpleSelector, CompareSimpleSelector> dict(sel->begin(), sel->end());
|
|
20
|
+
SimpleSelectorDict dict(sel->begin(), sel->end()); // XXX Set
|
|
23
21
|
std::vector<size_t> indices;
|
|
24
22
|
for (size_t i = 0, S = sel->length(); i < S; ++i) {
|
|
25
23
|
if (!hash_.count((*sel)[i])) {
|
|
@@ -42,14 +40,14 @@ namespace Sass {
|
|
|
42
40
|
std::vector<size_t>::iterator indices_end = unique(indices.begin(), indices.end());
|
|
43
41
|
indices.resize(distance(indices.begin(), indices_end));
|
|
44
42
|
|
|
45
|
-
std::vector<
|
|
43
|
+
std::vector<SubSetMapPair> results;
|
|
46
44
|
for (size_t i = 0, S = indices.size(); i < S; ++i) {
|
|
47
45
|
results.push_back(values_[indices[i]]);
|
|
48
46
|
}
|
|
49
47
|
return results;
|
|
50
48
|
}
|
|
51
49
|
|
|
52
|
-
std::vector<
|
|
50
|
+
std::vector<SubSetMapPair> Subset_Map::get_v(const Compound_Selector_Obj& sel)
|
|
53
51
|
{
|
|
54
52
|
return get_kv(sel);
|
|
55
53
|
}
|
|
@@ -60,15 +60,15 @@ namespace Sass {
|
|
|
60
60
|
|
|
61
61
|
class Subset_Map {
|
|
62
62
|
private:
|
|
63
|
-
std::vector<
|
|
64
|
-
std::map<Simple_Selector_Obj, std::vector<std::pair<Compound_Selector_Obj, size_t>
|
|
63
|
+
std::vector<SubSetMapPair> values_;
|
|
64
|
+
std::map<Simple_Selector_Obj, std::vector<std::pair<Compound_Selector_Obj, size_t> >, OrderNodes > hash_;
|
|
65
65
|
public:
|
|
66
|
-
void put(const Compound_Selector_Obj& sel, const
|
|
67
|
-
std::vector<
|
|
68
|
-
std::vector<
|
|
66
|
+
void put(const Compound_Selector_Obj& sel, const SubSetMapPair& value);
|
|
67
|
+
std::vector<SubSetMapPair> get_kv(const Compound_Selector_Obj& s);
|
|
68
|
+
std::vector<SubSetMapPair> get_v(const Compound_Selector_Obj& s);
|
|
69
69
|
bool empty() { return values_.empty(); }
|
|
70
70
|
void clear() { values_.clear(); hash_.clear(); }
|
|
71
|
-
const std::vector<
|
|
71
|
+
const std::vector<SubSetMapPair> values(void) { return values_; }
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
}
|
data/ext/libsass/src/to_c.cpp
CHANGED
|
@@ -36,7 +36,7 @@ namespace Sass {
|
|
|
36
36
|
|
|
37
37
|
union Sass_Value* To_C::operator()(List_Ptr l)
|
|
38
38
|
{
|
|
39
|
-
union Sass_Value* v = sass_make_list(l->length(), l->separator());
|
|
39
|
+
union Sass_Value* v = sass_make_list(l->length(), l->separator(), l->is_bracketed());
|
|
40
40
|
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
|
41
41
|
sass_list_set_value(v, i, (*l)[i]->perform(this));
|
|
42
42
|
}
|
|
@@ -57,7 +57,7 @@ namespace Sass {
|
|
|
57
57
|
|
|
58
58
|
union Sass_Value* To_C::operator()(Arguments_Ptr a)
|
|
59
59
|
{
|
|
60
|
-
union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA);
|
|
60
|
+
union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA, false);
|
|
61
61
|
for (size_t i = 0, L = a->length(); i < L; ++i) {
|
|
62
62
|
sass_list_set_value(v, i, (*a)[i]->perform(this));
|
|
63
63
|
}
|
|
@@ -9,8 +9,6 @@ namespace Sass {
|
|
|
9
9
|
// throw a runtime error if this happens
|
|
10
10
|
// we want a well defined set of possible nodes
|
|
11
11
|
throw std::runtime_error("invalid node for to_value");
|
|
12
|
-
// mute warning
|
|
13
|
-
return 0;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
// Custom_Error is a valid value
|
|
@@ -62,7 +60,8 @@ namespace Sass {
|
|
|
62
60
|
l->pstate(),
|
|
63
61
|
l->length(),
|
|
64
62
|
l->separator(),
|
|
65
|
-
l->is_arglist()
|
|
63
|
+
l->is_arglist(),
|
|
64
|
+
l->is_bracketed());
|
|
66
65
|
for (size_t i = 0, L = l->length(); i < L; ++i) {
|
|
67
66
|
ll->append((*l)[i]->perform(this));
|
|
68
67
|
}
|
|
@@ -81,6 +80,12 @@ namespace Sass {
|
|
|
81
80
|
return n;
|
|
82
81
|
}
|
|
83
82
|
|
|
83
|
+
// Function is a valid value
|
|
84
|
+
Value_Ptr To_Value::operator()(Function_Ptr n)
|
|
85
|
+
{
|
|
86
|
+
return n;
|
|
87
|
+
}
|
|
88
|
+
|
|
84
89
|
// Argument returns its value
|
|
85
90
|
Value_Ptr To_Value::operator()(Argument_Ptr arg)
|
|
86
91
|
{
|
data/ext/libsass/src/units.cpp
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "sass.hpp"
|
|
2
2
|
#include <stdexcept>
|
|
3
3
|
#include "units.hpp"
|
|
4
|
+
#include "error_handling.hpp"
|
|
4
5
|
|
|
5
6
|
namespace Sass {
|
|
6
7
|
|
|
@@ -53,12 +54,12 @@ namespace Sass {
|
|
|
53
54
|
{
|
|
54
55
|
switch (unit & 0xFF00)
|
|
55
56
|
{
|
|
56
|
-
case UnitClass::LENGTH: return UnitClass::LENGTH;
|
|
57
|
-
case UnitClass::ANGLE: return UnitClass::ANGLE;
|
|
58
|
-
case UnitClass::TIME: return UnitClass::TIME;
|
|
59
|
-
case UnitClass::FREQUENCY: return UnitClass::FREQUENCY;
|
|
60
|
-
case UnitClass::RESOLUTION: return UnitClass::RESOLUTION;
|
|
61
|
-
default: return UnitClass::INCOMMENSURABLE;
|
|
57
|
+
case UnitClass::LENGTH: return UnitClass::LENGTH;
|
|
58
|
+
case UnitClass::ANGLE: return UnitClass::ANGLE;
|
|
59
|
+
case UnitClass::TIME: return UnitClass::TIME;
|
|
60
|
+
case UnitClass::FREQUENCY: return UnitClass::FREQUENCY;
|
|
61
|
+
case UnitClass::RESOLUTION: return UnitClass::RESOLUTION;
|
|
62
|
+
default: return UnitClass::INCOMMENSURABLE;
|
|
62
63
|
}
|
|
63
64
|
};
|
|
64
65
|
|
|
@@ -66,12 +67,25 @@ namespace Sass {
|
|
|
66
67
|
{
|
|
67
68
|
switch (unit & 0xFF00)
|
|
68
69
|
{
|
|
69
|
-
case UnitClass::LENGTH: return "LENGTH";
|
|
70
|
-
case UnitClass::ANGLE: return "ANGLE";
|
|
71
|
-
case UnitClass::TIME: return "TIME";
|
|
72
|
-
case UnitClass::FREQUENCY: return "FREQUENCY";
|
|
73
|
-
case UnitClass::RESOLUTION: return "RESOLUTION";
|
|
74
|
-
default: return "INCOMMENSURABLE";
|
|
70
|
+
case UnitClass::LENGTH: return "LENGTH";
|
|
71
|
+
case UnitClass::ANGLE: return "ANGLE";
|
|
72
|
+
case UnitClass::TIME: return "TIME";
|
|
73
|
+
case UnitClass::FREQUENCY: return "FREQUENCY";
|
|
74
|
+
case UnitClass::RESOLUTION: return "RESOLUTION";
|
|
75
|
+
default: return "INCOMMENSURABLE";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
UnitType get_main_unit(const UnitClass unit)
|
|
80
|
+
{
|
|
81
|
+
switch (unit)
|
|
82
|
+
{
|
|
83
|
+
case UnitClass::LENGTH: return UnitType::PX;
|
|
84
|
+
case UnitClass::ANGLE: return UnitType::DEG;
|
|
85
|
+
case UnitClass::TIME: return UnitType::SEC;
|
|
86
|
+
case UnitClass::FREQUENCY: return UnitType::HERTZ;
|
|
87
|
+
case UnitClass::RESOLUTION: return UnitType::DPI;
|
|
88
|
+
default: return UnitType::UNKNOWN;
|
|
75
89
|
}
|
|
76
90
|
};
|
|
77
91
|
|
|
@@ -107,29 +121,29 @@ namespace Sass {
|
|
|
107
121
|
{
|
|
108
122
|
switch (unit) {
|
|
109
123
|
// size units
|
|
110
|
-
case UnitType::PX: return "px";
|
|
111
|
-
case UnitType::PT: return "pt";
|
|
112
|
-
case UnitType::PC: return "pc";
|
|
113
|
-
case UnitType::MM: return "mm";
|
|
114
|
-
case UnitType::CM: return "cm";
|
|
115
|
-
case UnitType::IN: return "in";
|
|
124
|
+
case UnitType::PX: return "px";
|
|
125
|
+
case UnitType::PT: return "pt";
|
|
126
|
+
case UnitType::PC: return "pc";
|
|
127
|
+
case UnitType::MM: return "mm";
|
|
128
|
+
case UnitType::CM: return "cm";
|
|
129
|
+
case UnitType::IN: return "in";
|
|
116
130
|
// angle units
|
|
117
|
-
case UnitType::DEG: return "deg";
|
|
118
|
-
case UnitType::GRAD: return "grad";
|
|
119
|
-
case UnitType::RAD: return "rad";
|
|
120
|
-
case UnitType::TURN: return "turn";
|
|
131
|
+
case UnitType::DEG: return "deg";
|
|
132
|
+
case UnitType::GRAD: return "grad";
|
|
133
|
+
case UnitType::RAD: return "rad";
|
|
134
|
+
case UnitType::TURN: return "turn";
|
|
121
135
|
// time units
|
|
122
|
-
case UnitType::SEC: return "s";
|
|
123
|
-
case UnitType::MSEC: return "ms";
|
|
136
|
+
case UnitType::SEC: return "s";
|
|
137
|
+
case UnitType::MSEC: return "ms";
|
|
124
138
|
// frequency units
|
|
125
|
-
case UnitType::HERTZ: return "Hz";
|
|
126
|
-
case UnitType::KHERTZ: return "kHz";
|
|
139
|
+
case UnitType::HERTZ: return "Hz";
|
|
140
|
+
case UnitType::KHERTZ: return "kHz";
|
|
127
141
|
// resolutions units
|
|
128
|
-
case UnitType::DPI: return "dpi";
|
|
129
|
-
case UnitType::DPCM: return "dpcm";
|
|
130
|
-
case UnitType::DPPX: return "dppx";
|
|
142
|
+
case UnitType::DPI: return "dpi";
|
|
143
|
+
case UnitType::DPCM: return "dpcm";
|
|
144
|
+
case UnitType::DPPX: return "dppx";
|
|
131
145
|
// for unknown units
|
|
132
|
-
default: return "";
|
|
146
|
+
default: return "";
|
|
133
147
|
}
|
|
134
148
|
}
|
|
135
149
|
|
|
@@ -161,7 +175,7 @@ namespace Sass {
|
|
|
161
175
|
}
|
|
162
176
|
|
|
163
177
|
// throws incompatibleUnits exceptions
|
|
164
|
-
double conversion_factor(const std::string& s1, const std::string& s2
|
|
178
|
+
double conversion_factor(const std::string& s1, const std::string& s2)
|
|
165
179
|
{
|
|
166
180
|
// assert for same units
|
|
167
181
|
if (s1 == s2) return 1;
|
|
@@ -171,27 +185,317 @@ namespace Sass {
|
|
|
171
185
|
// query unit group types
|
|
172
186
|
UnitClass t1 = get_unit_type(u1);
|
|
173
187
|
UnitClass t2 = get_unit_type(u2);
|
|
188
|
+
// return the conversion factor
|
|
189
|
+
return conversion_factor(u1, u2, t1, t2);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// throws incompatibleUnits exceptions
|
|
193
|
+
double conversion_factor(UnitType u1, UnitType u2, UnitClass t1, UnitClass t2)
|
|
194
|
+
{
|
|
195
|
+
// can't convert between groups
|
|
196
|
+
if (t1 != t2) return 0;
|
|
174
197
|
// get absolute offset
|
|
175
198
|
// used for array acces
|
|
176
199
|
size_t i1 = u1 - t1;
|
|
177
200
|
size_t i2 = u2 - t2;
|
|
178
|
-
//
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
201
|
+
// process known units
|
|
202
|
+
switch (t1) {
|
|
203
|
+
case LENGTH:
|
|
204
|
+
return size_conversion_factors[i1][i2];
|
|
205
|
+
case ANGLE:
|
|
206
|
+
return angle_conversion_factors[i1][i2];
|
|
207
|
+
case TIME:
|
|
208
|
+
return time_conversion_factors[i1][i2];
|
|
209
|
+
case FREQUENCY:
|
|
210
|
+
return frequency_conversion_factors[i1][i2];
|
|
211
|
+
case RESOLUTION:
|
|
212
|
+
return resolution_conversion_factors[i1][i2];
|
|
213
|
+
case INCOMMENSURABLE:
|
|
214
|
+
return 0;
|
|
192
215
|
}
|
|
193
216
|
// fallback
|
|
194
217
|
return 0;
|
|
195
218
|
}
|
|
196
219
|
|
|
220
|
+
double convert_units(const std::string& lhs, const std::string& rhs, int& lhsexp, int& rhsexp)
|
|
221
|
+
{
|
|
222
|
+
double f = 0;
|
|
223
|
+
// do not convert same ones
|
|
224
|
+
if (lhs == rhs) return 0;
|
|
225
|
+
// skip already canceled out unit
|
|
226
|
+
if (lhsexp == 0) return 0;
|
|
227
|
+
if (rhsexp == 0) return 0;
|
|
228
|
+
// check if it can be converted
|
|
229
|
+
UnitType ulhs = string_to_unit(lhs);
|
|
230
|
+
UnitType urhs = string_to_unit(rhs);
|
|
231
|
+
// skip units we cannot convert
|
|
232
|
+
if (ulhs == UNKNOWN) return 0;
|
|
233
|
+
if (urhs == UNKNOWN) return 0;
|
|
234
|
+
// query unit group types
|
|
235
|
+
UnitClass clhs = get_unit_type(ulhs);
|
|
236
|
+
UnitClass crhs = get_unit_type(urhs);
|
|
237
|
+
// skip units we cannot convert
|
|
238
|
+
if (clhs != crhs) return 0;
|
|
239
|
+
// if right denominator is bigger than lhs, we want to keep it in rhs unit
|
|
240
|
+
if (rhsexp < 0 && lhsexp > 0 && - rhsexp > lhsexp) {
|
|
241
|
+
// get the conversion factor for units
|
|
242
|
+
f = conversion_factor(urhs, ulhs, clhs, crhs);
|
|
243
|
+
// left hand side has been consumned
|
|
244
|
+
f = std::pow(f, lhsexp);
|
|
245
|
+
rhsexp += lhsexp;
|
|
246
|
+
lhsexp = 0;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// get the conversion factor for units
|
|
250
|
+
f = conversion_factor(ulhs, urhs, clhs, crhs);
|
|
251
|
+
// right hand side has been consumned
|
|
252
|
+
f = std::pow(f, rhsexp);
|
|
253
|
+
lhsexp += rhsexp;
|
|
254
|
+
rhsexp = 0;
|
|
255
|
+
}
|
|
256
|
+
return f;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
bool Units::operator< (const Units& rhs) const
|
|
260
|
+
{
|
|
261
|
+
return (numerators < rhs.numerators) &&
|
|
262
|
+
(denominators < rhs.denominators);
|
|
263
|
+
}
|
|
264
|
+
bool Units::operator== (const Units& rhs) const
|
|
265
|
+
{
|
|
266
|
+
return (numerators == rhs.numerators) &&
|
|
267
|
+
(denominators == rhs.denominators);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
double Units::normalize()
|
|
271
|
+
{
|
|
272
|
+
|
|
273
|
+
size_t iL = numerators.size();
|
|
274
|
+
size_t nL = denominators.size();
|
|
275
|
+
|
|
276
|
+
// the final conversion factor
|
|
277
|
+
double factor = 1;
|
|
278
|
+
|
|
279
|
+
for (size_t i = 0; i < iL; i++) {
|
|
280
|
+
std::string &lhs = numerators[i];
|
|
281
|
+
UnitType ulhs = string_to_unit(lhs);
|
|
282
|
+
if (ulhs == UNKNOWN) continue;
|
|
283
|
+
UnitClass clhs = get_unit_type(ulhs);
|
|
284
|
+
UnitType umain = get_main_unit(clhs);
|
|
285
|
+
if (ulhs == umain) continue;
|
|
286
|
+
double f(conversion_factor(umain, ulhs, clhs, clhs));
|
|
287
|
+
if (f == 0) throw std::runtime_error("INVALID");
|
|
288
|
+
numerators[i] = unit_to_string(umain);
|
|
289
|
+
factor /= f;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
for (size_t n = 0; n < nL; n++) {
|
|
293
|
+
std::string &rhs = denominators[n];
|
|
294
|
+
UnitType urhs = string_to_unit(rhs);
|
|
295
|
+
if (urhs == UNKNOWN) continue;
|
|
296
|
+
UnitClass crhs = get_unit_type(urhs);
|
|
297
|
+
UnitType umain = get_main_unit(crhs);
|
|
298
|
+
if (urhs == umain) continue;
|
|
299
|
+
double f(conversion_factor(umain, urhs, crhs, crhs));
|
|
300
|
+
if (f == 0) throw std::runtime_error("INVALID");
|
|
301
|
+
denominators[n] = unit_to_string(umain);
|
|
302
|
+
factor /= f;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
std::sort (numerators.begin(), numerators.end());
|
|
306
|
+
std::sort (denominators.begin(), denominators.end());
|
|
307
|
+
|
|
308
|
+
// return for conversion
|
|
309
|
+
return factor;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
double Units::reduce()
|
|
313
|
+
{
|
|
314
|
+
|
|
315
|
+
size_t iL = numerators.size();
|
|
316
|
+
size_t nL = denominators.size();
|
|
317
|
+
|
|
318
|
+
// have less than two units?
|
|
319
|
+
if (iL + nL < 2) return 1;
|
|
320
|
+
|
|
321
|
+
// first make sure same units cancel each other out
|
|
322
|
+
// it seems that a map table will fit nicely to do this
|
|
323
|
+
// we basically construct exponents for each unit
|
|
324
|
+
// has the advantage that they will be pre-sorted
|
|
325
|
+
std::map<std::string, int> exponents;
|
|
326
|
+
|
|
327
|
+
// initialize by summing up occurences in unit vectors
|
|
328
|
+
// this will already cancel out equivalent units (e.q. px/px)
|
|
329
|
+
for (size_t i = 0; i < iL; i ++) exponents[numerators[i]] += 1;
|
|
330
|
+
for (size_t n = 0; n < nL; n ++) exponents[denominators[n]] -= 1;
|
|
331
|
+
|
|
332
|
+
// the final conversion factor
|
|
333
|
+
double factor = 1;
|
|
334
|
+
|
|
335
|
+
// convert between compatible units
|
|
336
|
+
for (size_t i = 0; i < iL; i++) {
|
|
337
|
+
for (size_t n = 0; n < nL; n++) {
|
|
338
|
+
std::string &lhs = numerators[i], &rhs = denominators[n];
|
|
339
|
+
int &lhsexp = exponents[lhs], &rhsexp = exponents[rhs];
|
|
340
|
+
double f(convert_units(lhs, rhs, lhsexp, rhsexp));
|
|
341
|
+
if (f == 0) continue;
|
|
342
|
+
factor /= f;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// now we can build up the new unit arrays
|
|
347
|
+
numerators.clear();
|
|
348
|
+
denominators.clear();
|
|
349
|
+
|
|
350
|
+
// recreate sorted units vectors
|
|
351
|
+
for (auto exp : exponents) {
|
|
352
|
+
int &exponent = exp.second;
|
|
353
|
+
while (exponent > 0 && exponent --)
|
|
354
|
+
numerators.push_back(exp.first);
|
|
355
|
+
while (exponent < 0 && exponent ++)
|
|
356
|
+
denominators.push_back(exp.first);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// return for conversion
|
|
360
|
+
return factor;
|
|
361
|
+
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
std::string Units::unit() const
|
|
365
|
+
{
|
|
366
|
+
std::string u;
|
|
367
|
+
size_t iL = numerators.size();
|
|
368
|
+
size_t nL = denominators.size();
|
|
369
|
+
for (size_t i = 0; i < iL; i += 1) {
|
|
370
|
+
if (i) u += '*';
|
|
371
|
+
u += numerators[i];
|
|
372
|
+
}
|
|
373
|
+
if (nL != 0) u += '/';
|
|
374
|
+
for (size_t n = 0; n < nL; n += 1) {
|
|
375
|
+
if (n) u += '*';
|
|
376
|
+
u += denominators[n];
|
|
377
|
+
}
|
|
378
|
+
return u;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
bool Units::is_unitless() const
|
|
382
|
+
{
|
|
383
|
+
return numerators.empty() &&
|
|
384
|
+
denominators.empty();
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
bool Units::is_valid_css_unit() const
|
|
388
|
+
{
|
|
389
|
+
return numerators.size() <= 1 &&
|
|
390
|
+
denominators.size() == 0;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// this does not cover all cases (multiple prefered units)
|
|
394
|
+
double Units::convert_factor(const Units& r) const
|
|
395
|
+
{
|
|
396
|
+
|
|
397
|
+
std::vector<std::string> miss_nums(0);
|
|
398
|
+
std::vector<std::string> miss_dens(0);
|
|
399
|
+
// create copy since we need these for state keeping
|
|
400
|
+
std::vector<std::string> r_nums(r.numerators);
|
|
401
|
+
std::vector<std::string> r_dens(r.denominators);
|
|
402
|
+
|
|
403
|
+
auto l_num_it = numerators.begin();
|
|
404
|
+
auto l_num_end = numerators.end();
|
|
405
|
+
|
|
406
|
+
bool l_unitless = is_unitless();
|
|
407
|
+
auto r_unitless = r.is_unitless();
|
|
408
|
+
|
|
409
|
+
// overall conversion
|
|
410
|
+
double factor = 1;
|
|
411
|
+
|
|
412
|
+
// process all left numerators
|
|
413
|
+
while (l_num_it != l_num_end)
|
|
414
|
+
{
|
|
415
|
+
// get and increment afterwards
|
|
416
|
+
const std::string l_num = *(l_num_it ++);
|
|
417
|
+
|
|
418
|
+
auto r_num_it = r_nums.begin(), r_num_end = r_nums.end();
|
|
419
|
+
|
|
420
|
+
bool found = false;
|
|
421
|
+
// search for compatible numerator
|
|
422
|
+
while (r_num_it != r_num_end)
|
|
423
|
+
{
|
|
424
|
+
// get and increment afterwards
|
|
425
|
+
const std::string r_num = *(r_num_it);
|
|
426
|
+
// get possible conversion factor for units
|
|
427
|
+
double conversion = conversion_factor(l_num, r_num);
|
|
428
|
+
// skip incompatible numerator
|
|
429
|
+
if (conversion == 0) {
|
|
430
|
+
++ r_num_it;
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
// apply to global factor
|
|
434
|
+
factor *= conversion;
|
|
435
|
+
// remove item from vector
|
|
436
|
+
r_nums.erase(r_num_it);
|
|
437
|
+
// found numerator
|
|
438
|
+
found = true;
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
441
|
+
// maybe we did not find any
|
|
442
|
+
// left numerator is leftover
|
|
443
|
+
if (!found) miss_nums.push_back(l_num);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
auto l_den_it = denominators.begin();
|
|
447
|
+
auto l_den_end = denominators.end();
|
|
448
|
+
|
|
449
|
+
// process all left denominators
|
|
450
|
+
while (l_den_it != l_den_end)
|
|
451
|
+
{
|
|
452
|
+
// get and increment afterwards
|
|
453
|
+
const std::string l_den = *(l_den_it ++);
|
|
454
|
+
|
|
455
|
+
auto r_den_it = r_dens.begin();
|
|
456
|
+
auto r_den_end = r_dens.end();
|
|
457
|
+
|
|
458
|
+
bool found = false;
|
|
459
|
+
// search for compatible denominator
|
|
460
|
+
while (r_den_it != r_den_end)
|
|
461
|
+
{
|
|
462
|
+
// get and increment afterwards
|
|
463
|
+
const std::string r_den = *(r_den_it);
|
|
464
|
+
// get possible converstion factor for units
|
|
465
|
+
double conversion = conversion_factor(l_den, r_den);
|
|
466
|
+
// skip incompatible denominator
|
|
467
|
+
if (conversion == 0) {
|
|
468
|
+
++ r_den_it;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
// apply to global factor
|
|
472
|
+
factor /= conversion;
|
|
473
|
+
// remove item from vector
|
|
474
|
+
r_dens.erase(r_den_it);
|
|
475
|
+
// found denominator
|
|
476
|
+
found = true;
|
|
477
|
+
break;
|
|
478
|
+
}
|
|
479
|
+
// maybe we did not find any
|
|
480
|
+
// left denominator is leftover
|
|
481
|
+
if (!found) miss_dens.push_back(l_den);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// check left-overs (ToDo: might cancel out?)
|
|
485
|
+
if (miss_nums.size() > 0 && !r_unitless) {
|
|
486
|
+
throw Exception::IncompatibleUnits(r, *this);
|
|
487
|
+
}
|
|
488
|
+
else if (miss_dens.size() > 0 && !r_unitless) {
|
|
489
|
+
throw Exception::IncompatibleUnits(r, *this);
|
|
490
|
+
}
|
|
491
|
+
else if (r_nums.size() > 0 && !l_unitless) {
|
|
492
|
+
throw Exception::IncompatibleUnits(r, *this);
|
|
493
|
+
}
|
|
494
|
+
else if (r_dens.size() > 0 && !l_unitless) {
|
|
495
|
+
throw Exception::IncompatibleUnits(r, *this);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
return factor;
|
|
499
|
+
}
|
|
500
|
+
|
|
197
501
|
}
|