build-graph 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,133 @@
1
+ //
2
+ // main.cpp
3
+ // DictionarySort
4
+ //
5
+ // Created by Samuel Williams on 31/10/11.
6
+ // Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
7
+ //
8
+
9
+ #include <iostream>
10
+ #include <algorithm>
11
+
12
+ #include "Benchmark.h"
13
+ #include "DictionarySort.h"
14
+
15
+ // Print out vectors using a simple [item0, item1, ... itemn] format.
16
+ template <typename AnyT>
17
+ std::ostream& operator<< (std::ostream &o, const std::vector<AnyT> & v)
18
+ {
19
+ bool first = true;
20
+
21
+ o << "[";
22
+ for (typename std::vector<AnyT>::const_iterator i = v.begin(); i != v.end(); ++i) {
23
+ if (first)
24
+ first = false;
25
+ else
26
+ o << ", ";
27
+
28
+ o << *i;
29
+ }
30
+ o << "]";
31
+
32
+ return o;
33
+ }
34
+
35
+ static void test_parallel_merge ()
36
+ {
37
+ typedef std::vector<long long> ArrayT;
38
+ typedef std::less<long long> ComparatorT;
39
+ ComparatorT comparator;
40
+
41
+ const long long data[] = {
42
+ 2, 4, 6, 8, 12,
43
+ 1, 3, 5, 10, 11
44
+ };
45
+
46
+ ArrayT a(data, data+(sizeof(data)/sizeof(*data)));
47
+ ArrayT b(a.size());
48
+
49
+ ParallelMergeSort::ParallelLeftMerge<ArrayT, ComparatorT> left_merge = {a, b, comparator, 0, a.size() / 2};
50
+ left_merge();
51
+
52
+ std::cout << "After Left: " << b << std::endl;
53
+
54
+ ParallelMergeSort::ParallelRightMerge<ArrayT, ComparatorT> right_merge = {a, b, comparator, 0, a.size() / 2, a.size()};
55
+ right_merge();
56
+
57
+ std::cout << "After Right: " << b << std::endl;
58
+ }
59
+
60
+ static void test_sort ()
61
+ {
62
+ typedef std::vector<long long> ArrayT;
63
+ typedef std::less<long long> ComparatorT;
64
+ ComparatorT comparator;
65
+
66
+ const long long data[] = {
67
+ 11, 2, 4, 6, 8, 10, 12, 1, 3, 5, 7, 9, 13
68
+ };
69
+
70
+ std::vector<long long> v(data, data+(sizeof(data)/sizeof(*data)));
71
+
72
+ std::cerr << "Sorting " << v << std::endl;
73
+
74
+ ParallelMergeSort::sort(v, comparator, 0);
75
+
76
+ std::cerr << "Sorted " << v << std::endl;
77
+ }
78
+
79
+ static void test_dictionary ()
80
+ {
81
+ // This defines a dictionary based on ASCII characters.
82
+ typedef DictionarySort::Dictionary<char, DictionarySort::IndexT[256]> ASCIIDictionaryT;
83
+
84
+ // For unicode characters, you could use something like this:
85
+ // typedef DictionarySort::Dictionary<uint32_t, std::map<uint32_t, DictionarySort::IndexT>> UCS32DictionaryT;
86
+ // Be aware that
87
+
88
+ std::string s = "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz";
89
+ ASCIIDictionaryT::WordT alphabet(s.begin(), s.end());
90
+ ASCIIDictionaryT dictionary(alphabet);
91
+
92
+ ASCIIDictionaryT::WordsT words, sorted_words;
93
+ const std::size_t MAX_LENGTH = 25;
94
+ const std::size_t MAX_COUNT = 2500000;
95
+ for (std::size_t i = 0; i < MAX_COUNT; i += 1) {
96
+ ASCIIDictionaryT::WordT word;
97
+ for (std::size_t j = i; (j-i) <= (i ^ (i * 21)) % MAX_LENGTH; j += 1) {
98
+ word.push_back(alphabet[(j ^ (j << (i % 4))) % alphabet.size()]);
99
+ }
100
+ words.push_back(word);
101
+ }
102
+
103
+ std::cerr << "Sorting " << words.size() << " words..." << std::endl;
104
+ std::cerr << "Sort mode = " << DictionarySort::SORT_MODE << std::endl;
105
+
106
+ if (DictionarySort::SORT_MODE > 0)
107
+ std::cerr << "Parallel merge thread count: " << (1 << (DictionarySort::SORT_MODE+1)) - 2 << std::endl;
108
+
109
+ const int K = 4;
110
+ Benchmark::WallTime t;
111
+ Benchmark::ProcessorTime processor_time;
112
+
113
+ uint64_t checksum;
114
+ for (std::size_t i = 0; i < K; i += 1) {
115
+ checksum = dictionary.sort(words, sorted_words);
116
+ }
117
+ Benchmark::TimeT elapsed_time = t.total() / K;
118
+
119
+ std::cerr << "Checksum: " << checksum << " ? " << (checksum == 479465310674138860) << std::endl;
120
+ std::cerr << "Total Time: " << elapsed_time << std::endl;
121
+
122
+ std::cerr << "Finished." << std::endl;
123
+ }
124
+
125
+ int main (int argc, const char * argv[])
126
+ {
127
+ //test_parallel_merge();
128
+ //test_sort();
129
+ test_dictionary();
130
+
131
+ return 0;
132
+ }
133
+
@@ -0,0 +1 @@
1
+ main.cpp.o: main.cpp Benchmark.h DictionarySort.h ParallelMergeSort.h
Binary file
metadata CHANGED
@@ -1,83 +1,125 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: build-graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-25 00:00:00.000000000 Z
11
+ date: 2014-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: process-group
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: build-files
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
18
32
  - !ruby/object:Gem::Version
19
33
  version: 0.1.0
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
- - - ~>
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: build-makefile
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
25
53
  - !ruby/object:Gem::Version
26
54
  version: 0.1.0
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: system
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
- - - '>='
59
+ - - ">="
32
60
  - !ruby/object:Gem::Version
33
61
  version: '0'
34
62
  type: :runtime
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
- - - '>='
66
+ - - ">="
39
67
  - !ruby/object:Gem::Version
40
68
  version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: rainbow
43
71
  requirement: !ruby/object:Gem::Requirement
44
72
  requirements:
45
- - - '>='
73
+ - - "~>"
46
74
  - !ruby/object:Gem::Version
47
- version: '0'
75
+ version: 2.0.0
48
76
  type: :runtime
49
77
  prerelease: false
50
78
  version_requirements: !ruby/object:Gem::Requirement
51
79
  requirements:
52
- - - '>='
80
+ - - "~>"
53
81
  - !ruby/object:Gem::Version
54
- version: '0'
82
+ version: 2.0.0
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: bundler
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
- - - ~>
87
+ - - "~>"
60
88
  - !ruby/object:Gem::Version
61
89
  version: '1.3'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
- - - ~>
94
+ - - "~>"
67
95
  - !ruby/object:Gem::Version
68
96
  version: '1.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0.rc1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0.rc1
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: rake
71
113
  requirement: !ruby/object:Gem::Requirement
72
114
  requirements:
73
- - - '>='
115
+ - - ">="
74
116
  - !ruby/object:Gem::Version
75
117
  version: '0'
76
118
  type: :development
77
119
  prerelease: false
78
120
  version_requirements: !ruby/object:Gem::Requirement
79
121
  requirements:
80
- - - '>='
122
+ - - ">="
81
123
  - !ruby/object:Gem::Version
82
124
  version: '0'
83
125
  description: "\tBuild::Graph is a framework for managing file-system based build processes.
@@ -89,25 +131,30 @@ executables: []
89
131
  extensions: []
90
132
  extra_rdoc_files: []
91
133
  files:
92
- - .gitignore
93
- - .travis.yml
134
+ - ".gitignore"
135
+ - ".travis.yml"
94
136
  - Gemfile
95
137
  - README.md
96
138
  - Rakefile
97
139
  - build-graph.gemspec
98
- - lib/build.rb
99
- - lib/build/edge.rb
100
- - lib/build/error.rb
101
- - lib/build/files.rb
102
- - lib/build/files/monitor.rb
103
- - lib/build/files/state.rb
104
140
  - lib/build/graph.rb
105
- - lib/build/node.rb
106
- - lib/build/version.rb
107
- - lib/build/walker.rb
108
- - test/program/main.cpp
109
- - test/test_files.rb
110
- - test/test_graph.rb
141
+ - lib/build/graph/controller.rb
142
+ - lib/build/graph/edge.rb
143
+ - lib/build/graph/error.rb
144
+ - lib/build/graph/node.rb
145
+ - lib/build/graph/version.rb
146
+ - lib/build/graph/walker.rb
147
+ - spec/build/graph/graph_spec.rb
148
+ - spec/build/graph/program/Benchmark.cpp
149
+ - spec/build/graph/program/Benchmark.cpp.d
150
+ - spec/build/graph/program/Benchmark.cpp.o
151
+ - spec/build/graph/program/Benchmark.h
152
+ - spec/build/graph/program/DictionarySort.h
153
+ - spec/build/graph/program/ParallelMergeSort.h
154
+ - spec/build/graph/program/dictionary-sort
155
+ - spec/build/graph/program/main.cpp
156
+ - spec/build/graph/program/main.cpp.d
157
+ - spec/build/graph/program/main.cpp.o
111
158
  homepage: ''
112
159
  licenses:
113
160
  - MIT
@@ -118,22 +165,30 @@ require_paths:
118
165
  - lib
119
166
  required_ruby_version: !ruby/object:Gem::Requirement
120
167
  requirements:
121
- - - '>='
168
+ - - ">="
122
169
  - !ruby/object:Gem::Version
123
170
  version: '0'
124
171
  required_rubygems_version: !ruby/object:Gem::Requirement
125
172
  requirements:
126
- - - '>='
173
+ - - ">="
127
174
  - !ruby/object:Gem::Version
128
175
  version: '0'
129
176
  requirements: []
130
177
  rubyforge_project:
131
- rubygems_version: 2.0.3
178
+ rubygems_version: 2.2.2
132
179
  signing_key:
133
180
  specification_version: 4
134
181
  summary: Build::Graph is a framework for build systems, with specific functionality
135
182
  for dealing with file based processes.
136
183
  test_files:
137
- - test/program/main.cpp
138
- - test/test_files.rb
139
- - test/test_graph.rb
184
+ - spec/build/graph/graph_spec.rb
185
+ - spec/build/graph/program/Benchmark.cpp
186
+ - spec/build/graph/program/Benchmark.cpp.d
187
+ - spec/build/graph/program/Benchmark.cpp.o
188
+ - spec/build/graph/program/Benchmark.h
189
+ - spec/build/graph/program/DictionarySort.h
190
+ - spec/build/graph/program/ParallelMergeSort.h
191
+ - spec/build/graph/program/dictionary-sort
192
+ - spec/build/graph/program/main.cpp
193
+ - spec/build/graph/program/main.cpp.d
194
+ - spec/build/graph/program/main.cpp.o
data/lib/build.rb DELETED
@@ -1,5 +0,0 @@
1
- require "build/version"
2
-
3
- module Build
4
-
5
- end
data/lib/build/edge.rb DELETED
@@ -1,49 +0,0 @@
1
-
2
- require 'build/error'
3
-
4
- module Build
5
- # Represents an input to a graph node, with count inputs.
6
- class Edge
7
- def initialize(count = 0)
8
- @fiber = Fiber.current
9
- @count = count
10
-
11
- @failed = []
12
- end
13
-
14
- attr :failed
15
-
16
- attr :fiber
17
- attr :count
18
-
19
- def wait
20
- if @count > 0
21
- Fiber.yield
22
- end
23
-
24
- failed?
25
- end
26
-
27
- attr :failed
28
-
29
- def failed?
30
- @failed.size != 0
31
- end
32
-
33
- def traverse(node)
34
- @count -= 1
35
-
36
- if node.failed?
37
- @failed << node
38
- end
39
-
40
- if @count == 0
41
- @fiber.resume
42
- end
43
- end
44
-
45
- def increment!
46
- @count += 1
47
- end
48
- end
49
- end
data/lib/build/error.rb DELETED
@@ -1,18 +0,0 @@
1
-
2
-
3
- module Build
4
- class TransientError < StandardError
5
- end
6
-
7
- class CommandFailure < TransientError
8
- def initialize(command, status)
9
- super "Command #{command.inspect} failed with exit status #{status}!"
10
-
11
- @command = command
12
- @status = status
13
- end
14
-
15
- attr :command
16
- attr :status
17
- end
18
- end
data/lib/build/files.rb DELETED
@@ -1,286 +0,0 @@
1
- # Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
- #
3
- # Permission is hereby granted, free of charge, to any person obtaining a copy
4
- # of this software and associated documentation files (the "Software"), to deal
5
- # in the Software without restriction, including without limitation the rights
6
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
- # copies of the Software, and to permit persons to whom the Software is
8
- # furnished to do so, subject to the following conditions:
9
- #
10
- # The above copyright notice and this permission notice shall be included in
11
- # all copies or substantial portions of the Software.
12
- #
13
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
- # THE SOFTWARE.
20
-
21
- require 'set'
22
- require 'pathname'
23
-
24
- module Build
25
- module Files
26
- class List
27
- include Enumerable
28
-
29
- def +(list)
30
- Composite.new([self, list])
31
- end
32
-
33
- def intersects? other
34
- other.any?{|path| include?(path)}
35
- end
36
-
37
- def match(pattern)
38
- all? {|path| path.match(pattern)}
39
- end
40
- end
41
-
42
- class RelativePath < String
43
- # Both paths must be full absolute paths, and path must have root as an prefix.
44
- def initialize(path, root)
45
- raise ArgumentError.new("#{root} is not a prefix of #{path}") unless path.start_with?(root)
46
-
47
- super path
48
-
49
- @root = root
50
- end
51
-
52
- attr :root
53
-
54
- def relative_path
55
- self.slice(@root.length..-1)
56
- end
57
- end
58
-
59
- # A list which has a single root directory.
60
- class DirectoryList < List
61
- def initialize(root)
62
- @root = root.to_s
63
- end
64
-
65
- attr :root
66
-
67
- def roots
68
- [@root]
69
- end
70
-
71
- def rebase(root)
72
- raise NotImplementedError
73
- end
74
-
75
- def to_paths(root=@root)
76
- relative_paths = self.each do |path|
77
- path.relative_path
78
- end
79
-
80
- return Paths.new(root, relative_paths)
81
- end
82
-
83
- def process(root=@root)
84
- self.collect do |path|
85
- basename, _, filename = path.relative_path.rpartition(File::SEPARATOR)
86
-
87
- File.join(basename, yield(filename))
88
- end
89
-
90
- Paths.new(root, self.collect)
91
- end
92
- end
93
-
94
- class Directory < DirectoryList
95
- def initialize(root, path = "")
96
- super(root)
97
-
98
- @path = path
99
- end
100
-
101
- attr :path
102
-
103
- def full_path
104
- File.join(@root, @path)
105
- end
106
-
107
- def each(&block)
108
- Dir.glob(full_path + "**/*") do |path|
109
- yield RelativePath.new(path, @root)
110
- end
111
- end
112
-
113
- def eql?(other)
114
- other.kind_of?(self.class) and @root.eql?(other.root) and @path.eql?(other.path)
115
- end
116
-
117
- def hash
118
- [@root, @path].hash
119
- end
120
-
121
- def include?(path)
122
- # Would be true if path is a descendant of full_path.
123
- path.start_with?(full_path)
124
- end
125
-
126
- def rebase(root)
127
- self.class.new(root, @path)
128
- end
129
- end
130
-
131
- class Glob < DirectoryList
132
- def initialize(root, pattern)
133
- super(root)
134
-
135
- @pattern = pattern
136
- end
137
-
138
- attr :root
139
- attr :pattern
140
-
141
- def full_pattern
142
- File.join(@root, @pattern)
143
- end
144
-
145
- # Enumerate all paths matching the pattern.
146
- def each(&block)
147
- Dir.glob(full_pattern) do |path|
148
- yield RelativePath.new(path, @root)
149
- end
150
- end
151
-
152
- def eql?(other)
153
- other.kind_of?(self.class) and @root.eql?(other.root) and @pattern.eql?(other.pattern)
154
- end
155
-
156
- def hash
157
- [@root, @pattern].hash
158
- end
159
-
160
- def include?(path)
161
- File.fnmatch(full_pattern, path)
162
- end
163
-
164
- def rebase(root)
165
- self.class.new(root, @pattern)
166
- end
167
- end
168
-
169
- class Paths < DirectoryList
170
- def initialize(root, paths)
171
- super(root)
172
-
173
- @paths = Array(paths)
174
- end
175
-
176
- attr :paths
177
-
178
- def each(&block)
179
- @paths.each do |path|
180
- full_path = File.join(@root, path)
181
- yield RelativePath.new(full_path, @root)
182
- end
183
- end
184
-
185
- def eql? other
186
- other.kind_of?(self.class) and @paths.eql?(other.paths)
187
- end
188
-
189
- def hash
190
- @paths.hash
191
- end
192
-
193
- def include?(path)
194
- # Compute a full relative path:
195
- full_path = File.absolute_path(path, @root)
196
-
197
- # If the full path starts with @root, test it for inclusion:
198
- if full_path.start_with? @root
199
- # Compute the relative component:
200
- relative_path = full_path[@root.length..-1]
201
-
202
- # Does this list of paths include it?
203
- return @paths.include?(relative_path)
204
- else
205
- return false
206
- end
207
- end
208
-
209
- def rebase(root)
210
- self.class.new(root, @paths)
211
- end
212
-
213
- def to_paths
214
- return self
215
- end
216
- end
217
-
218
- class Composite < List
219
- def initialize(files = Set.new)
220
- @files = files
221
- end
222
-
223
- attr :files
224
-
225
- def each(&block)
226
- @files.each do |files|
227
- files.each &block
228
- end
229
- end
230
-
231
- def roots
232
- @files.collect(&:roots).flatten.uniq
233
- end
234
-
235
- def eql?(other)
236
- other.kind_of?(self.class) and @files.eql?(other.files)
237
- end
238
-
239
- def hash
240
- @files.hash
241
- end
242
-
243
- def merge(list)
244
- if list.kind_of? Composite
245
- @files += list.files
246
- elsif list.kind_of? List
247
- @files << list
248
- else
249
- raise ArgumentError.new("Cannot merge non-list of file paths.")
250
- end
251
- end
252
-
253
- def +(list)
254
- if list.kind_of? Composite
255
- Composite.new(@files + list.files)
256
- else
257
- Composite.new(@files + [list])
258
- end
259
- end
260
-
261
- def include?(path)
262
- @files.any? {|list| list.include?(path)}
263
- end
264
-
265
- def rebase(root)
266
- self.class.new(@files.collect{|list| list.rebase(root)})
267
- end
268
-
269
- def to_paths
270
- Composite.new(@files.collect(&:to_paths))
271
- end
272
-
273
- def self.[](files)
274
- if files.size == 0
275
- return None
276
- elsif files.size == 1
277
- files.first
278
- else
279
- self.class.new(files)
280
- end
281
- end
282
- end
283
-
284
- NONE = Composite.new
285
- end
286
- end