sassc 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.gitmodules +3 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +24 -0
- data/Rakefile +21 -0
- data/ext/libsass/.editorconfig +15 -0
- data/ext/libsass/.gitattributes +2 -0
- data/ext/libsass/.gitignore +61 -0
- data/ext/libsass/.travis.yml +38 -0
- data/ext/libsass/COPYING +25 -0
- data/ext/libsass/INSTALL +1 -0
- data/ext/libsass/LICENSE +25 -0
- data/ext/libsass/Makefile +223 -0
- data/ext/libsass/Makefile.am +145 -0
- data/ext/libsass/Readme.md +93 -0
- data/ext/libsass/appveyor.yml +76 -0
- data/ext/libsass/ast.cpp +581 -0
- data/ext/libsass/ast.hpp +1949 -0
- data/ext/libsass/ast_def_macros.hpp +16 -0
- data/ext/libsass/ast_factory.hpp +87 -0
- data/ext/libsass/ast_fwd_decl.hpp +72 -0
- data/ext/libsass/b64/cencode.h +32 -0
- data/ext/libsass/b64/encode.h +77 -0
- data/ext/libsass/backtrace.hpp +81 -0
- data/ext/libsass/base64vlq.cpp +43 -0
- data/ext/libsass/base64vlq.hpp +28 -0
- data/ext/libsass/bind.cpp +187 -0
- data/ext/libsass/bind.hpp +18 -0
- data/ext/libsass/cencode.c +102 -0
- data/ext/libsass/color_names.hpp +324 -0
- data/ext/libsass/configure.ac +130 -0
- data/ext/libsass/constants.cpp +144 -0
- data/ext/libsass/constants.hpp +145 -0
- data/ext/libsass/context.cpp +507 -0
- data/ext/libsass/context.hpp +150 -0
- data/ext/libsass/contextualize.cpp +157 -0
- data/ext/libsass/contextualize.hpp +65 -0
- data/ext/libsass/copy_c_str.cpp +13 -0
- data/ext/libsass/copy_c_str.hpp +5 -0
- data/ext/libsass/debug.hpp +39 -0
- data/ext/libsass/environment.hpp +75 -0
- data/ext/libsass/error_handling.cpp +28 -0
- data/ext/libsass/error_handling.hpp +28 -0
- data/ext/libsass/eval.cpp +1149 -0
- data/ext/libsass/eval.hpp +80 -0
- data/ext/libsass/expand.cpp +430 -0
- data/ext/libsass/expand.hpp +77 -0
- data/ext/libsass/extconf.rb +6 -0
- data/ext/libsass/extend.cpp +1962 -0
- data/ext/libsass/extend.hpp +50 -0
- data/ext/libsass/file.cpp +291 -0
- data/ext/libsass/file.hpp +18 -0
- data/ext/libsass/functions.cpp +1565 -0
- data/ext/libsass/functions.hpp +187 -0
- data/ext/libsass/inspect.cpp +727 -0
- data/ext/libsass/inspect.hpp +108 -0
- data/ext/libsass/json.cpp +1411 -0
- data/ext/libsass/json.hpp +117 -0
- data/ext/libsass/kwd_arg_macros.hpp +23 -0
- data/ext/libsass/m4/.gitkeep +0 -0
- data/ext/libsass/mapping.hpp +17 -0
- data/ext/libsass/memory_manager.hpp +54 -0
- data/ext/libsass/node.cpp +251 -0
- data/ext/libsass/node.hpp +122 -0
- data/ext/libsass/operation.hpp +153 -0
- data/ext/libsass/output_compressed.cpp +401 -0
- data/ext/libsass/output_compressed.hpp +95 -0
- data/ext/libsass/output_nested.cpp +364 -0
- data/ext/libsass/output_nested.hpp +108 -0
- data/ext/libsass/parser.cpp +2016 -0
- data/ext/libsass/parser.hpp +264 -0
- data/ext/libsass/paths.hpp +69 -0
- data/ext/libsass/position.hpp +22 -0
- data/ext/libsass/posix/getopt.c +562 -0
- data/ext/libsass/posix/getopt.h +95 -0
- data/ext/libsass/prelexer.cpp +688 -0
- data/ext/libsass/prelexer.hpp +513 -0
- data/ext/libsass/remove_placeholders.cpp +59 -0
- data/ext/libsass/remove_placeholders.hpp +43 -0
- data/ext/libsass/res/resource.rc +35 -0
- data/ext/libsass/sass.cpp +33 -0
- data/ext/libsass/sass.h +60 -0
- data/ext/libsass/sass2scss.cpp +834 -0
- data/ext/libsass/sass2scss.h +110 -0
- data/ext/libsass/sass_context.cpp +709 -0
- data/ext/libsass/sass_context.h +120 -0
- data/ext/libsass/sass_functions.cpp +137 -0
- data/ext/libsass/sass_functions.h +90 -0
- data/ext/libsass/sass_interface.cpp +277 -0
- data/ext/libsass/sass_interface.h +97 -0
- data/ext/libsass/sass_util.cpp +136 -0
- data/ext/libsass/sass_util.hpp +259 -0
- data/ext/libsass/sass_values.cpp +337 -0
- data/ext/libsass/sass_values.h +124 -0
- data/ext/libsass/script/bootstrap +10 -0
- data/ext/libsass/script/branding +10 -0
- data/ext/libsass/script/ci-build-libsass +72 -0
- data/ext/libsass/script/ci-install-compiler +4 -0
- data/ext/libsass/script/ci-install-deps +19 -0
- data/ext/libsass/script/ci-report-coverage +25 -0
- data/ext/libsass/script/coveralls-debug +32 -0
- data/ext/libsass/script/spec +5 -0
- data/ext/libsass/script/tap-driver +652 -0
- data/ext/libsass/script/tap-runner +1 -0
- data/ext/libsass/source_map.cpp +133 -0
- data/ext/libsass/source_map.hpp +46 -0
- data/ext/libsass/subset_map.hpp +145 -0
- data/ext/libsass/support/libsass.pc.in +11 -0
- data/ext/libsass/test-driver +127 -0
- data/ext/libsass/test/test_node.cpp +98 -0
- data/ext/libsass/test/test_paths.cpp +29 -0
- data/ext/libsass/test/test_selector_difference.cpp +28 -0
- data/ext/libsass/test/test_specificity.cpp +28 -0
- data/ext/libsass/test/test_subset_map.cpp +472 -0
- data/ext/libsass/test/test_superselector.cpp +71 -0
- data/ext/libsass/test/test_unification.cpp +33 -0
- data/ext/libsass/to_c.cpp +61 -0
- data/ext/libsass/to_c.hpp +44 -0
- data/ext/libsass/to_string.cpp +29 -0
- data/ext/libsass/to_string.hpp +32 -0
- data/ext/libsass/token.hpp +32 -0
- data/ext/libsass/units.cpp +54 -0
- data/ext/libsass/units.hpp +10 -0
- data/ext/libsass/utf8.h +34 -0
- data/ext/libsass/utf8/checked.h +327 -0
- data/ext/libsass/utf8/core.h +329 -0
- data/ext/libsass/utf8/unchecked.h +228 -0
- data/ext/libsass/utf8_string.cpp +102 -0
- data/ext/libsass/utf8_string.hpp +36 -0
- data/ext/libsass/util.cpp +189 -0
- data/ext/libsass/util.hpp +26 -0
- data/ext/libsass/win/libsass.filters +291 -0
- data/ext/libsass/win/libsass.sln +28 -0
- data/ext/libsass/win/libsass.vcxproj +255 -0
- data/lib/sassc.rb +6 -0
- data/lib/sassc/engine.rb +13 -0
- data/lib/sassc/native.rb +44 -0
- data/lib/sassc/native/native_context_api.rb +140 -0
- data/lib/sassc/native/native_functions_api.rb +41 -0
- data/lib/sassc/native/sass_input_style.rb +11 -0
- data/lib/sassc/native/sass_output_style.rb +10 -0
- data/lib/sassc/native/sass_value.rb +95 -0
- data/lib/sassc/native/string_list.rb +8 -0
- data/lib/sassc/version.rb +3 -0
- data/sassc.gemspec +43 -0
- data/test/smoke_test.rb +171 -0
- data/test/test_helper.rb +4 -0
- metadata +281 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
#ifndef SASS_C_INTERFACE
|
2
|
+
#define SASS_C_INTERFACE
|
3
|
+
|
4
|
+
#include <stddef.h>
|
5
|
+
#include <stdbool.h>
|
6
|
+
#include "sass.h"
|
7
|
+
|
8
|
+
#ifdef __cplusplus
|
9
|
+
extern "C" {
|
10
|
+
#endif
|
11
|
+
|
12
|
+
|
13
|
+
// Please ensure there are no null values.
|
14
|
+
// Thar be dragons.
|
15
|
+
struct sass_options {
|
16
|
+
// Output style for the generated css code
|
17
|
+
// A value from above SASS_STYLE_* constants
|
18
|
+
int output_style;
|
19
|
+
// If you want inline source comments
|
20
|
+
bool source_comments;
|
21
|
+
// Path to source map file
|
22
|
+
// Enables the source map generating
|
23
|
+
// Used to create sourceMappingUrl
|
24
|
+
const char* source_map_file;
|
25
|
+
// Disable sourceMappingUrl in css output
|
26
|
+
bool omit_source_map_url;
|
27
|
+
// embed sourceMappingUrl as data uri
|
28
|
+
bool source_map_embed;
|
29
|
+
// embed include contents in maps
|
30
|
+
bool source_map_contents;
|
31
|
+
// Treat source_string as sass (as opposed to scss)
|
32
|
+
bool is_indented_syntax_src;
|
33
|
+
// Colon-separated list of paths
|
34
|
+
// Semicolon-separated on Windows
|
35
|
+
const char* include_paths;
|
36
|
+
// For the image-url Sass function
|
37
|
+
const char* image_path;
|
38
|
+
// Precision for outputting fractional numbers
|
39
|
+
int precision;
|
40
|
+
};
|
41
|
+
|
42
|
+
struct sass_context {
|
43
|
+
const char* input_path;
|
44
|
+
const char* output_path;
|
45
|
+
const char* source_string;
|
46
|
+
char* output_string;
|
47
|
+
char* source_map_string;
|
48
|
+
struct sass_options options;
|
49
|
+
int error_status;
|
50
|
+
char* error_message;
|
51
|
+
Sass_C_Function_List c_functions;
|
52
|
+
char** included_files;
|
53
|
+
int num_included_files;
|
54
|
+
};
|
55
|
+
|
56
|
+
struct sass_file_context {
|
57
|
+
const char* input_path;
|
58
|
+
const char* output_path;
|
59
|
+
char* output_string;
|
60
|
+
char* source_map_string;
|
61
|
+
struct sass_options options;
|
62
|
+
int error_status;
|
63
|
+
char* error_message;
|
64
|
+
Sass_C_Function_List c_functions;
|
65
|
+
char** included_files;
|
66
|
+
int num_included_files;
|
67
|
+
};
|
68
|
+
|
69
|
+
struct sass_folder_context {
|
70
|
+
const char* search_path;
|
71
|
+
const char* output_path;
|
72
|
+
struct sass_options options;
|
73
|
+
int error_status;
|
74
|
+
char* error_message;
|
75
|
+
Sass_C_Function_List c_functions;
|
76
|
+
char** included_files;
|
77
|
+
int num_included_files;
|
78
|
+
};
|
79
|
+
|
80
|
+
struct sass_context* sass_new_context (void);
|
81
|
+
struct sass_file_context* sass_new_file_context (void);
|
82
|
+
struct sass_folder_context* sass_new_folder_context (void);
|
83
|
+
|
84
|
+
void sass_free_context (struct sass_context* ctx);
|
85
|
+
void sass_free_file_context (struct sass_file_context* ctx);
|
86
|
+
void sass_free_folder_context(struct sass_folder_context* ctx);
|
87
|
+
|
88
|
+
int sass_compile (struct sass_context* ctx);
|
89
|
+
int sass_compile_file (struct sass_file_context* ctx);
|
90
|
+
int sass_compile_folder (struct sass_folder_context* ctx);
|
91
|
+
|
92
|
+
|
93
|
+
#ifdef __cplusplus
|
94
|
+
}
|
95
|
+
#endif
|
96
|
+
|
97
|
+
#endif
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#ifndef SASS_AST
|
2
|
+
#include "node.hpp"
|
3
|
+
#endif
|
4
|
+
|
5
|
+
#include "to_string.hpp"
|
6
|
+
|
7
|
+
|
8
|
+
namespace Sass {
|
9
|
+
|
10
|
+
|
11
|
+
/*
|
12
|
+
This is the equivalent of ruby's Sass::Util.paths.
|
13
|
+
|
14
|
+
# Return an array of all possible paths through the given arrays.
|
15
|
+
#
|
16
|
+
# @param arrs [NodeCollection<NodeCollection<Node>>]
|
17
|
+
# @return [NodeCollection<NodeCollection<Node>>]
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# paths([[1, 2], [3, 4], [5]]) #=>
|
21
|
+
# # [[1, 3, 5],
|
22
|
+
# # [2, 3, 5],
|
23
|
+
# # [1, 4, 5],
|
24
|
+
# # [2, 4, 5]]
|
25
|
+
|
26
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
27
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
28
|
+
|
29
|
+
def paths(arrs)
|
30
|
+
// I changed the inject and maps to an iterative approach to make it easier to implement in C++
|
31
|
+
loopStart = [[]]
|
32
|
+
|
33
|
+
for arr in arrs do
|
34
|
+
permutations = []
|
35
|
+
for e in arr do
|
36
|
+
for path in loopStart do
|
37
|
+
permutations.push(path + [e])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
loopStart = permutations
|
41
|
+
end
|
42
|
+
end
|
43
|
+
*/
|
44
|
+
Node paths(const Node& arrs, Context& ctx) {
|
45
|
+
To_String to_string;
|
46
|
+
|
47
|
+
Node loopStart = Node::createCollection();
|
48
|
+
loopStart.collection()->push_back(Node::createCollection());
|
49
|
+
|
50
|
+
for (NodeDeque::iterator arrsIter = arrs.collection()->begin(), arrsEndIter = arrs.collection()->end();
|
51
|
+
arrsIter != arrsEndIter; ++arrsIter) {
|
52
|
+
|
53
|
+
Node& arr = *arrsIter;
|
54
|
+
|
55
|
+
Node permutations = Node::createCollection();
|
56
|
+
|
57
|
+
for (NodeDeque::iterator arrIter = arr.collection()->begin(), arrIterEnd = arr.collection()->end();
|
58
|
+
arrIter != arrIterEnd; ++arrIter) {
|
59
|
+
|
60
|
+
Node& e = *arrIter;
|
61
|
+
|
62
|
+
for (NodeDeque::iterator loopStartIter = loopStart.collection()->begin(), loopStartIterEnd = loopStart.collection()->end();
|
63
|
+
loopStartIter != loopStartIterEnd; ++loopStartIter) {
|
64
|
+
|
65
|
+
Node& path = *loopStartIter;
|
66
|
+
|
67
|
+
Node newPermutation = Node::createCollection();
|
68
|
+
newPermutation.plus(path);
|
69
|
+
newPermutation.collection()->push_back(e);
|
70
|
+
|
71
|
+
permutations.collection()->push_back(newPermutation);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
loopStart = permutations;
|
76
|
+
}
|
77
|
+
|
78
|
+
return loopStart;
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
/*
|
83
|
+
This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
|
84
|
+
Sass::Util.flatten requires the number of levels to flatten, while
|
85
|
+
[].flatten doesn't and will flatten the entire array. This function
|
86
|
+
supports both.
|
87
|
+
|
88
|
+
# Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
|
89
|
+
#
|
90
|
+
# @param arr [NodeCollection] The array to flatten
|
91
|
+
# @param n [int] The number of levels to flatten
|
92
|
+
# @return [NodeCollection] The flattened array
|
93
|
+
|
94
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
95
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
96
|
+
|
97
|
+
def flatten(arr, n = -1)
|
98
|
+
if n != -1 and n == 0 then
|
99
|
+
return arr
|
100
|
+
end
|
101
|
+
|
102
|
+
flattened = []
|
103
|
+
|
104
|
+
for e in arr do
|
105
|
+
if e.is_a?(Array) then
|
106
|
+
flattened.concat(flatten(e, n - 1))
|
107
|
+
else
|
108
|
+
flattened << e
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
return flattened
|
113
|
+
end
|
114
|
+
*/
|
115
|
+
Node flatten(const Node& arr, Context& ctx, int n = -1) {
|
116
|
+
if (n != -1 && n == 0) {
|
117
|
+
return arr;
|
118
|
+
}
|
119
|
+
|
120
|
+
Node flattened = Node::createCollection();
|
121
|
+
|
122
|
+
for (NodeDeque::iterator iter = arr.collection()->begin(), iterEnd = arr.collection()->end();
|
123
|
+
iter != iterEnd; iter++) {
|
124
|
+
Node& e = *iter;
|
125
|
+
|
126
|
+
if (e.isCollection()) {
|
127
|
+
Node recurseFlattened = flatten(e, ctx, n - 1);
|
128
|
+
flattened.collection()->insert(flattened.collection()->end(), recurseFlattened.collection()->begin(), recurseFlattened.collection()->end());
|
129
|
+
} else {
|
130
|
+
flattened.collection()->push_back(e);
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
134
|
+
return flattened;
|
135
|
+
}
|
136
|
+
}
|
@@ -0,0 +1,259 @@
|
|
1
|
+
#include <deque>
|
2
|
+
#include <iostream>
|
3
|
+
|
4
|
+
#ifndef SASS_AST
|
5
|
+
#include "ast.hpp"
|
6
|
+
#endif
|
7
|
+
|
8
|
+
#include "node.hpp"
|
9
|
+
#include "debug.hpp"
|
10
|
+
|
11
|
+
|
12
|
+
namespace Sass {
|
13
|
+
|
14
|
+
|
15
|
+
using namespace std;
|
16
|
+
|
17
|
+
|
18
|
+
/*
|
19
|
+
This is for ports of functions in the Sass:Util module.
|
20
|
+
*/
|
21
|
+
|
22
|
+
|
23
|
+
/*
|
24
|
+
# Return a Node collection of all possible paths through the given Node collection of Node collections.
|
25
|
+
#
|
26
|
+
# @param arrs [NodeCollection<NodeCollection<Node>>]
|
27
|
+
# @return [NodeCollection<NodeCollection<Node>>]
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# paths([[1, 2], [3, 4], [5]]) #=>
|
31
|
+
# # [[1, 3, 5],
|
32
|
+
# # [2, 3, 5],
|
33
|
+
# # [1, 4, 5],
|
34
|
+
# # [2, 4, 5]]
|
35
|
+
*/
|
36
|
+
Node paths(const Node& arrs, Context& ctx);
|
37
|
+
|
38
|
+
|
39
|
+
/*
|
40
|
+
This class is a default implementation of a Node comparator that can be passed to the lcs function below.
|
41
|
+
It uses operator== for equality comparision. It then returns one if the Nodes are equal.
|
42
|
+
*/
|
43
|
+
class DefaultLcsComparator {
|
44
|
+
public:
|
45
|
+
bool operator()(const Node& one, const Node& two, Node& out) const {
|
46
|
+
// TODO: Is this the correct C++ interpretation?
|
47
|
+
// block ||= proc {|a, b| a == b && a}
|
48
|
+
if (one == two) {
|
49
|
+
out = one;
|
50
|
+
return true;
|
51
|
+
}
|
52
|
+
|
53
|
+
return false;
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
|
58
|
+
typedef vector<vector<int> > LCSTable;
|
59
|
+
|
60
|
+
|
61
|
+
/*
|
62
|
+
This is the equivalent of ruby's Sass::Util.lcs_backtrace.
|
63
|
+
|
64
|
+
# Computes a single longest common subsequence for arrays x and y.
|
65
|
+
# Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS
|
66
|
+
*/
|
67
|
+
template<typename ComparatorType>
|
68
|
+
Node lcs_backtrace(const LCSTable& c, const Node& x, const Node& y, int i, int j, const ComparatorType& comparator) {
|
69
|
+
DEBUG_PRINTLN(LCS, "LCSBACK: X=" << x << " Y=" << y << " I=" << i << " J=" << j)
|
70
|
+
|
71
|
+
if (i == 0 || j == 0) {
|
72
|
+
DEBUG_PRINTLN(LCS, "RETURNING EMPTY")
|
73
|
+
return Node::createCollection();
|
74
|
+
}
|
75
|
+
|
76
|
+
NodeDeque& xChildren = *(x.collection());
|
77
|
+
NodeDeque& yChildren = *(y.collection());
|
78
|
+
|
79
|
+
Node compareOut = Node::createNil();
|
80
|
+
if (comparator(xChildren[i], yChildren[j], compareOut)) {
|
81
|
+
DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
|
82
|
+
Node result = lcs_backtrace(c, x, y, i - 1, j - 1, comparator);
|
83
|
+
result.collection()->push_back(compareOut);
|
84
|
+
return result;
|
85
|
+
}
|
86
|
+
|
87
|
+
if (c[i][j - 1] > c[i - 1][j]) {
|
88
|
+
DEBUG_PRINTLN(LCS, "RETURNING AFTER TABLE COMPARE")
|
89
|
+
return lcs_backtrace(c, x, y, i, j - 1, comparator);
|
90
|
+
}
|
91
|
+
|
92
|
+
DEBUG_PRINTLN(LCS, "FINAL RETURN")
|
93
|
+
return lcs_backtrace(c, x, y, i - 1, j, comparator);
|
94
|
+
}
|
95
|
+
|
96
|
+
|
97
|
+
/*
|
98
|
+
This is the equivalent of ruby's Sass::Util.lcs_table.
|
99
|
+
|
100
|
+
# Calculates the memoization table for the Least Common Subsequence algorithm.
|
101
|
+
# Algorithm from http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS
|
102
|
+
*/
|
103
|
+
template<typename ComparatorType>
|
104
|
+
void lcs_table(const Node& x, const Node& y, const ComparatorType& comparator, LCSTable& out) {
|
105
|
+
DEBUG_PRINTLN(LCS, "LCSTABLE: X=" << x << " Y=" << y)
|
106
|
+
|
107
|
+
NodeDeque& xChildren = *(x.collection());
|
108
|
+
NodeDeque& yChildren = *(y.collection());
|
109
|
+
|
110
|
+
LCSTable c(xChildren.size(), vector<int>(yChildren.size()));
|
111
|
+
|
112
|
+
// These shouldn't be necessary since the vector will be initialized to 0 already.
|
113
|
+
// x.size.times {|i| c[i][0] = 0}
|
114
|
+
// y.size.times {|j| c[0][j] = 0}
|
115
|
+
|
116
|
+
for (size_t i = 1; i < xChildren.size(); i++) {
|
117
|
+
for (size_t j = 1; j < yChildren.size(); j++) {
|
118
|
+
Node compareOut = Node::createNil();
|
119
|
+
|
120
|
+
if (comparator(xChildren[i], yChildren[j], compareOut)) {
|
121
|
+
c[i][j] = c[i - 1][j - 1] + 1;
|
122
|
+
} else {
|
123
|
+
c[i][j] = max(c[i][j - 1], c[i - 1][j]);
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
out = c;
|
129
|
+
}
|
130
|
+
|
131
|
+
|
132
|
+
/*
|
133
|
+
This is the equivalent of ruby's Sass::Util.lcs.
|
134
|
+
|
135
|
+
# Computes a single longest common subsequence for `x` and `y`.
|
136
|
+
# If there are more than one longest common subsequences,
|
137
|
+
# the one returned is that which starts first in `x`.
|
138
|
+
|
139
|
+
# @param x [NodeCollection]
|
140
|
+
# @param y [NodeCollection]
|
141
|
+
# @comparator An equality check between elements of `x` and `y`.
|
142
|
+
# @return [NodeCollection] The LCS
|
143
|
+
|
144
|
+
http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
|
145
|
+
*/
|
146
|
+
template<typename ComparatorType>
|
147
|
+
Node lcs(Node& x, Node& y, const ComparatorType& comparator, Context& ctx) {
|
148
|
+
DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
|
149
|
+
|
150
|
+
Node newX = Node::createCollection();
|
151
|
+
newX.collection()->push_back(Node::createNil());
|
152
|
+
newX.plus(x);
|
153
|
+
|
154
|
+
Node newY = Node::createCollection();
|
155
|
+
newY.collection()->push_back(Node::createNil());
|
156
|
+
newY.plus(y);
|
157
|
+
|
158
|
+
LCSTable table;
|
159
|
+
lcs_table(newX, newY, comparator, table);
|
160
|
+
|
161
|
+
return lcs_backtrace(table, newX, newY, static_cast<int>(newX.collection()->size()) - 1, static_cast<int>(newY.collection()->size()) - 1, comparator);
|
162
|
+
}
|
163
|
+
|
164
|
+
|
165
|
+
/*
|
166
|
+
This is the equivalent of ruby sass' Sass::Util.flatten and [].flatten.
|
167
|
+
Sass::Util.flatten requires the number of levels to flatten, while
|
168
|
+
[].flatten doesn't and will flatten the entire array. This function
|
169
|
+
supports both.
|
170
|
+
|
171
|
+
# Flattens the first `n` nested arrays. If n == -1, all arrays will be flattened
|
172
|
+
#
|
173
|
+
# @param arr [NodeCollection] The array to flatten
|
174
|
+
# @param n [int] The number of levels to flatten
|
175
|
+
# @return [NodeCollection] The flattened array
|
176
|
+
*/
|
177
|
+
Node flatten(const Node& arr, Context& ctx, int n = -1);
|
178
|
+
|
179
|
+
|
180
|
+
/*
|
181
|
+
This is the equivalent of ruby's Sass::Util.group_by_to_a.
|
182
|
+
|
183
|
+
# Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
|
184
|
+
# order. Unlike [#hash_to_a], the resulting order isn't sorted key order;
|
185
|
+
# instead, it's the same order as `#group_by` has under Ruby 1.9 (key
|
186
|
+
# appearance order).
|
187
|
+
#
|
188
|
+
# @param enum [Enumerable]
|
189
|
+
# @return [Array<[Object, Array]>] An array of pairs.
|
190
|
+
|
191
|
+
TODO: update @param and @return once I know what those are.
|
192
|
+
|
193
|
+
The following is the modified version of the ruby code that was more portable to C++. You
|
194
|
+
should be able to drop it into ruby 3.2.19 and get the same results from ruby sass.
|
195
|
+
|
196
|
+
def group_by_to_a(enum, &block)
|
197
|
+
order = {}
|
198
|
+
|
199
|
+
arr = []
|
200
|
+
|
201
|
+
grouped = {}
|
202
|
+
|
203
|
+
for e in enum do
|
204
|
+
key = block[e]
|
205
|
+
unless order.include?(key)
|
206
|
+
order[key] = order.size
|
207
|
+
end
|
208
|
+
|
209
|
+
if not grouped.has_key?(key) then
|
210
|
+
grouped[key] = [e]
|
211
|
+
else
|
212
|
+
grouped[key].push(e)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
grouped.each do |key, vals|
|
217
|
+
arr[order[key]] = [key, vals]
|
218
|
+
end
|
219
|
+
|
220
|
+
arr
|
221
|
+
end
|
222
|
+
|
223
|
+
*/
|
224
|
+
template<typename EnumType, typename KeyType, typename KeyFunctorType>
|
225
|
+
void group_by_to_a(vector<EnumType>& enumeration, KeyFunctorType& keyFunc, vector<pair<KeyType, vector<EnumType> > >& arr /*out*/) {
|
226
|
+
|
227
|
+
map<unsigned int, KeyType> order;
|
228
|
+
|
229
|
+
map<KeyType, vector<EnumType> > grouped;
|
230
|
+
|
231
|
+
for (typename vector<EnumType>::iterator enumIter = enumeration.begin(), enumIterEnd = enumeration.end(); enumIter != enumIterEnd; enumIter++) {
|
232
|
+
EnumType& e = *enumIter;
|
233
|
+
|
234
|
+
KeyType key = keyFunc(e);
|
235
|
+
|
236
|
+
if (grouped.find(key) == grouped.end()) {
|
237
|
+
order.insert(make_pair(order.size(), key));
|
238
|
+
|
239
|
+
vector<EnumType> newCollection;
|
240
|
+
newCollection.push_back(e);
|
241
|
+
grouped.insert(make_pair(key, newCollection));
|
242
|
+
} else {
|
243
|
+
vector<EnumType>& collection = grouped.at(key);
|
244
|
+
collection.push_back(e);
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
for (unsigned int index = 0; index < order.size(); index++) {
|
249
|
+
KeyType& key = order.at(index);
|
250
|
+
vector<EnumType>& values = grouped.at(key);
|
251
|
+
|
252
|
+
pair<KeyType, vector<EnumType> > grouping = make_pair(key, values);
|
253
|
+
|
254
|
+
arr.push_back(grouping);
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
258
|
+
|
259
|
+
}
|