comp_tree 0.7.6 → 1.0.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.
- data/CHANGES.rdoc +6 -0
- data/MANIFEST +14 -15
- data/README.rdoc +13 -14
- data/Rakefile +1 -1
- data/devel/jumpstart.rb +591 -255
- data/install.rb +1 -2
- data/lib/comp_tree/algorithm.rb +44 -44
- data/lib/comp_tree/comp_tree.rb +55 -0
- data/lib/comp_tree/driver.rb +29 -38
- data/lib/comp_tree/error.rb +40 -6
- data/lib/comp_tree/node.rb +32 -27
- data/lib/comp_tree/queue/queue.rb +1 -0
- data/lib/comp_tree/{queue_old.rb → queue/queue_18.rb} +5 -5
- data/lib/comp_tree/{queue_new.rb → queue/queue_19.rb} +3 -1
- data/lib/comp_tree.rb +22 -75
- data/test/{test_basic.rb → basic_test.rb} +5 -3
- data/test/{test_circular.rb → circular_test.rb} +1 -1
- data/test/{common.rb → comp_tree_test_base.rb} +17 -4
- data/test/{test_drain.rb → drain_test.rb} +5 -6
- data/test/exception_test.rb +117 -0
- data/test/{test_flood.rb → flood_test.rb} +1 -1
- data/test/{test_grind.rb → grind_test.rb} +11 -12
- data/test/readme_test.rb +5 -0
- data/test/{test_sequential.rb → sequential_test.rb} +1 -1
- data/test/{test_throw.rb → throw_test.rb} +1 -1
- metadata +42 -43
- data/devel/jumpstart/lazy_attribute.rb +0 -38
- data/devel/jumpstart/ruby.rb +0 -44
- data/devel/jumpstart/simple_installer.rb +0 -85
- data/lib/comp_tree/queue.rb +0 -1
- data/test/test_exception.rb +0 -84
data/install.rb
CHANGED
data/lib/comp_tree/algorithm.rb
CHANGED
@@ -1,60 +1,61 @@
|
|
1
1
|
|
2
|
-
require 'comp_tree/queue'
|
3
|
-
|
4
2
|
module CompTree
|
5
3
|
module Algorithm
|
6
4
|
module_function
|
7
5
|
|
8
6
|
def compute_parallel(root, num_threads)
|
9
|
-
to_workers = Queue.new
|
10
7
|
from_workers = Queue.new
|
11
|
-
|
8
|
+
to_workers = Queue.new
|
12
9
|
|
13
10
|
workers = (1..num_threads).map {
|
14
11
|
Thread.new {
|
15
|
-
|
16
|
-
node.compute
|
17
|
-
from_workers.push node
|
18
|
-
end
|
12
|
+
worker_loop(from_workers, to_workers)
|
19
13
|
}
|
20
14
|
}
|
21
15
|
|
22
|
-
Thread.new {
|
23
|
-
|
24
|
-
|
25
|
-
num_working = 0
|
26
|
-
while true
|
27
|
-
if num_working == num_threads or
|
28
|
-
(not (node_to_worker = find_node(root)))
|
29
|
-
#
|
30
|
-
# maxed out or no nodes available -- wait for results
|
31
|
-
#
|
32
|
-
node_from_worker = from_workers.pop
|
33
|
-
node_from_worker.unlock
|
34
|
-
num_working -= 1
|
35
|
-
if node_from_worker == root or
|
36
|
-
node_from_worker.computed.is_a? Exception
|
37
|
-
final_node = node_from_worker
|
38
|
-
break
|
39
|
-
end
|
40
|
-
elsif node_to_worker
|
41
|
-
#
|
42
|
-
# found a node
|
43
|
-
#
|
44
|
-
to_workers.push node_to_worker
|
45
|
-
num_working += 1
|
46
|
-
node_to_worker = nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
num_threads.times { to_workers.push nil }
|
50
|
-
}.join
|
16
|
+
node = Thread.new {
|
17
|
+
master_loop(root, num_threads, from_workers, to_workers)
|
18
|
+
}.value
|
51
19
|
|
20
|
+
num_threads.times { to_workers.push(nil) }
|
52
21
|
workers.each { |t| t.join }
|
53
22
|
|
54
|
-
if
|
55
|
-
raise
|
23
|
+
if node.computed.is_a? Exception
|
24
|
+
raise node.computed
|
56
25
|
else
|
57
|
-
|
26
|
+
node.result
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def worker_loop(from_workers, to_workers)
|
31
|
+
while node = to_workers.pop
|
32
|
+
node.compute
|
33
|
+
from_workers.push(node)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def master_loop(root, num_threads, from_workers, to_workers)
|
38
|
+
num_working = 0
|
39
|
+
node = nil
|
40
|
+
while true
|
41
|
+
if num_working == num_threads or !(node = find_node(root))
|
42
|
+
#
|
43
|
+
# maxed out or no nodes available -- wait for results
|
44
|
+
#
|
45
|
+
node = from_workers.pop
|
46
|
+
node.unlock
|
47
|
+
num_working -= 1
|
48
|
+
if node == root or node.computed.is_a? Exception
|
49
|
+
break node
|
50
|
+
end
|
51
|
+
else
|
52
|
+
#
|
53
|
+
# found a node
|
54
|
+
#
|
55
|
+
num_working += 1
|
56
|
+
node.lock
|
57
|
+
to_workers.push(node)
|
58
|
+
end
|
58
59
|
end
|
59
60
|
end
|
60
61
|
|
@@ -67,18 +68,17 @@ module CompTree
|
|
67
68
|
elsif not node.locked? and node.children_results
|
68
69
|
#
|
69
70
|
# Node is not computed, not locked, and its children are
|
70
|
-
# computed;
|
71
|
+
# computed; ready to compute.
|
71
72
|
#
|
72
|
-
node.lock
|
73
73
|
node
|
74
74
|
else
|
75
75
|
#
|
76
76
|
# locked or children not computed; recurse to children
|
77
77
|
#
|
78
78
|
node.each_child { |child|
|
79
|
-
found = find_node(child)
|
79
|
+
if found = find_node(child)
|
80
80
|
return found
|
81
|
-
|
81
|
+
end
|
82
82
|
}
|
83
83
|
nil
|
84
84
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# CompTree -- Parallel Computation Tree.
|
4
|
+
#
|
5
|
+
# See README.rdoc.
|
6
|
+
#
|
7
|
+
module CompTree
|
8
|
+
VERSION = "1.0.0"
|
9
|
+
|
10
|
+
class << self
|
11
|
+
#
|
12
|
+
# :call-seq:
|
13
|
+
# build { |driver| ... }
|
14
|
+
#
|
15
|
+
# Build a new computation tree. A Driver instance is passed to the
|
16
|
+
# given block.
|
17
|
+
#
|
18
|
+
# Example:
|
19
|
+
# CompTree.build do |driver|
|
20
|
+
#
|
21
|
+
# # Define a function named 'area' taking these two arguments.
|
22
|
+
# driver.define(:area, :width, :height) { |width, height|
|
23
|
+
# width*height
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# # Define a function 'width' which takes a 'border' argument.
|
27
|
+
# driver.define(:width, :border) { |border|
|
28
|
+
# 7 + border
|
29
|
+
# }
|
30
|
+
#
|
31
|
+
# # Ditto for 'height'.
|
32
|
+
# driver.define(:height, :border) { |border|
|
33
|
+
# 5 + border
|
34
|
+
# }
|
35
|
+
#
|
36
|
+
# #
|
37
|
+
# # Define a constant function 'border'.
|
38
|
+
# driver.define(:border) {
|
39
|
+
# 2
|
40
|
+
# }
|
41
|
+
#
|
42
|
+
# # Compute the area using four parallel threads.
|
43
|
+
# puts driver.compute(:area, 4)
|
44
|
+
# # => 63
|
45
|
+
#
|
46
|
+
# # We've done this computation.
|
47
|
+
# puts((7 + 2)*(5 + 2))
|
48
|
+
# # => 63
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
def build(opts = {})
|
52
|
+
yield Driver.new(opts)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/comp_tree/driver.rb
CHANGED
@@ -1,26 +1,15 @@
|
|
1
1
|
|
2
|
-
require 'comp_tree/algorithm'
|
3
|
-
require 'comp_tree/node'
|
4
|
-
require 'comp_tree/error'
|
5
|
-
|
6
2
|
module CompTree
|
7
3
|
#
|
8
4
|
# Driver is the main interface to the computation tree. It is
|
9
5
|
# responsible for defining nodes and running computations.
|
10
6
|
#
|
11
7
|
class Driver
|
12
|
-
include Algorithm
|
13
|
-
|
14
8
|
#
|
15
9
|
# See CompTree.build
|
16
10
|
#
|
17
|
-
def initialize(opts =
|
18
|
-
@node_class =
|
19
|
-
if opts and opts[:node_class]
|
20
|
-
opts[:node_class]
|
21
|
-
else
|
22
|
-
Node
|
23
|
-
end
|
11
|
+
def initialize(opts = {}) #:nodoc:
|
12
|
+
@node_class = opts[:node_class] || Node
|
24
13
|
@nodes = Hash.new
|
25
14
|
end
|
26
15
|
|
@@ -49,16 +38,16 @@ module CompTree
|
|
49
38
|
#
|
50
39
|
def define(name, *child_names, &block)
|
51
40
|
#
|
52
|
-
# retrieve or create
|
41
|
+
# retrieve or create node and children
|
53
42
|
#
|
54
43
|
|
55
|
-
|
44
|
+
node = @nodes.fetch(name) {
|
56
45
|
@nodes[name] = @node_class.new(name)
|
57
46
|
}
|
58
|
-
if
|
59
|
-
raise RedefinitionError
|
47
|
+
if node.function
|
48
|
+
raise RedefinitionError.new(node.name)
|
60
49
|
end
|
61
|
-
|
50
|
+
node.function = block
|
62
51
|
|
63
52
|
children = child_names.map { |child_name|
|
64
53
|
@nodes.fetch(child_name) {
|
@@ -69,12 +58,12 @@ module CompTree
|
|
69
58
|
#
|
70
59
|
# link
|
71
60
|
#
|
72
|
-
|
61
|
+
node.children = children
|
73
62
|
children.each { |child|
|
74
|
-
child.parents <<
|
63
|
+
child.parents << node
|
75
64
|
}
|
76
65
|
|
77
|
-
|
66
|
+
node
|
78
67
|
end
|
79
68
|
|
80
69
|
#
|
@@ -106,35 +95,37 @@ module CompTree
|
|
106
95
|
nil
|
107
96
|
end
|
108
97
|
|
109
|
-
#
|
110
|
-
# :call-seq:
|
111
|
-
# compute(name, threads)
|
112
|
-
# compute(name, :threads => threads)
|
113
98
|
#
|
114
99
|
# _name_ -- unique node identifier (for example a symbol).
|
115
100
|
#
|
116
|
-
#
|
101
|
+
# _num_threads_ -- number of threads.
|
117
102
|
#
|
118
|
-
# Compute
|
103
|
+
# Compute the tree below _name_ and return the result.
|
119
104
|
#
|
120
|
-
#
|
105
|
+
# If a node's computation raises an exception, the exception will
|
106
|
+
# be transferred to the caller of compute(). The tree will be
|
107
|
+
# left in a dirty state so that individual nodes may be examined.
|
108
|
+
# It is your responsibility to call reset() before attempting the
|
109
|
+
# computation again, otherwise the result will be undefined.
|
121
110
|
#
|
122
|
-
def compute(name,
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
111
|
+
def compute(name, num_threads)
|
112
|
+
begin
|
113
|
+
num_threads = num_threads.to_int
|
114
|
+
rescue NoMethodError
|
115
|
+
raise TypeError, "can't convert #{num_threads.class} into Integer"
|
116
|
+
end
|
117
|
+
unless num_threads > 0
|
118
|
+
raise RangeError, "number of threads must be greater than zero"
|
127
119
|
end
|
128
120
|
root = @nodes.fetch(name) {
|
129
|
-
raise
|
130
|
-
"no such node named `#{name.inspect}'"
|
121
|
+
raise NoNodeError.new(name)
|
131
122
|
}
|
132
123
|
if root.computed
|
133
124
|
root.result
|
134
|
-
elsif
|
135
|
-
root.
|
125
|
+
elsif num_threads == 1
|
126
|
+
root.compute_now
|
136
127
|
else
|
137
|
-
compute_parallel(root,
|
128
|
+
Algorithm.compute_parallel(root, num_threads)
|
138
129
|
end
|
139
130
|
end
|
140
131
|
end
|
data/lib/comp_tree/error.rb
CHANGED
@@ -1,19 +1,53 @@
|
|
1
1
|
|
2
2
|
module CompTree
|
3
|
+
#
|
3
4
|
# Base class for CompTree errors.
|
4
|
-
|
5
|
+
#
|
6
|
+
class Error < StandardError
|
7
|
+
def inspect #:nodoc:
|
8
|
+
"#<#{self.class.name}: #{message}>"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Base class for node errors.
|
14
|
+
#
|
15
|
+
class NodeError < Error
|
16
|
+
attr_reader :node_name
|
17
|
+
|
18
|
+
def initialize(node_name) #:nodoc:
|
19
|
+
super()
|
20
|
+
@node_name = node_name
|
21
|
+
end
|
22
|
+
end
|
5
23
|
|
6
24
|
#
|
7
|
-
#
|
25
|
+
# An attempt was made to redefine a node.
|
8
26
|
#
|
9
27
|
# If you wish to only replace the function, set
|
10
28
|
# driver.nodes[name].function = lambda { ... }
|
11
29
|
#
|
12
|
-
class RedefinitionError <
|
30
|
+
class RedefinitionError < NodeError
|
31
|
+
def message #:nodoc:
|
32
|
+
"attempt to redefine node `#{node_name.inspect}'"
|
33
|
+
end
|
34
|
+
end
|
13
35
|
|
36
|
+
#
|
14
37
|
# Encountered a node without a function during a computation.
|
15
|
-
|
38
|
+
#
|
39
|
+
class NoFunctionError < NodeError
|
40
|
+
def message #:nodoc:
|
41
|
+
"no function was defined for node `#{node_name.inspect}'"
|
42
|
+
end
|
43
|
+
end
|
16
44
|
|
17
|
-
#
|
18
|
-
|
45
|
+
#
|
46
|
+
# Requested node does not exist.
|
47
|
+
#
|
48
|
+
class NoNodeError < NodeError
|
49
|
+
def message #:nodoc:
|
50
|
+
"no node named `#{node_name.inspect}'"
|
51
|
+
end
|
52
|
+
end
|
19
53
|
end
|
data/lib/comp_tree/node.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
|
2
|
-
require 'thread'
|
3
|
-
|
4
2
|
module CompTree
|
5
3
|
#
|
6
4
|
# Base class for nodes in the computation tree.
|
7
5
|
#
|
8
6
|
class Node
|
9
|
-
attr_reader :name
|
7
|
+
attr_reader :name
|
10
8
|
|
11
|
-
attr_accessor
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
9
|
+
attr_accessor(
|
10
|
+
:parents,
|
11
|
+
:children,
|
12
|
+
:function,
|
13
|
+
:result,
|
14
|
+
:computed,
|
15
|
+
:lock_level
|
16
|
+
)
|
17
17
|
|
18
18
|
#
|
19
19
|
# Create a node
|
20
20
|
#
|
21
|
-
def initialize(name)
|
21
|
+
def initialize(name)
|
22
22
|
@name = name
|
23
23
|
@parents = []
|
24
24
|
@children = []
|
@@ -29,7 +29,7 @@ module CompTree
|
|
29
29
|
#
|
30
30
|
# Reset the computation for this node.
|
31
31
|
#
|
32
|
-
def reset_self
|
32
|
+
def reset_self
|
33
33
|
@result = nil
|
34
34
|
@computed = nil
|
35
35
|
@lock_level = 0
|
@@ -39,27 +39,27 @@ module CompTree
|
|
39
39
|
#
|
40
40
|
# Reset the computation for this node and all children.
|
41
41
|
#
|
42
|
-
def reset
|
42
|
+
def reset
|
43
43
|
each_downward { |node|
|
44
44
|
node.reset_self
|
45
45
|
}
|
46
46
|
end
|
47
47
|
|
48
|
-
def each_downward(&block)
|
48
|
+
def each_downward(&block)
|
49
49
|
block.call(self)
|
50
50
|
@children.each { |child|
|
51
51
|
child.each_downward(&block)
|
52
52
|
}
|
53
53
|
end
|
54
54
|
|
55
|
-
def each_upward(&block)
|
55
|
+
def each_upward(&block)
|
56
56
|
block.call(self)
|
57
57
|
@parents.each { |parent|
|
58
58
|
parent.each_upward(&block)
|
59
59
|
}
|
60
60
|
end
|
61
61
|
|
62
|
-
def each_child
|
62
|
+
def each_child
|
63
63
|
@children.each { |child|
|
64
64
|
yield(child)
|
65
65
|
}
|
@@ -69,20 +69,26 @@ module CompTree
|
|
69
69
|
# Force all children and self to be computed; no locking required.
|
70
70
|
# Intended to be used outside of parallel computations.
|
71
71
|
#
|
72
|
-
def compute_now
|
73
|
-
unless @
|
74
|
-
@children_results
|
75
|
-
child
|
76
|
-
|
72
|
+
def compute_now
|
73
|
+
unless @computed
|
74
|
+
unless @children_results
|
75
|
+
@children_results = @children.map { |child|
|
76
|
+
child.compute_now
|
77
|
+
}
|
78
|
+
end
|
79
|
+
compute
|
80
|
+
if @computed.is_a? Exception
|
81
|
+
raise @computed
|
82
|
+
end
|
77
83
|
end
|
78
|
-
|
84
|
+
@result
|
79
85
|
end
|
80
86
|
|
81
87
|
#
|
82
88
|
# If all children have been computed, return their results;
|
83
89
|
# otherwise return nil.
|
84
90
|
#
|
85
|
-
def children_results
|
91
|
+
def children_results
|
86
92
|
@children_results or (
|
87
93
|
@children_results = @children.map { |child|
|
88
94
|
unless child.computed
|
@@ -97,11 +103,10 @@ module CompTree
|
|
97
103
|
# Compute this node; children must be computed and lock must be
|
98
104
|
# already acquired.
|
99
105
|
#
|
100
|
-
def compute
|
106
|
+
def compute
|
101
107
|
begin
|
102
108
|
unless @function
|
103
|
-
raise NoFunctionError
|
104
|
-
"no function was defined for node `#{@name.inspect}'"
|
109
|
+
raise NoFunctionError.new(@name)
|
105
110
|
end
|
106
111
|
@result = @function.call(*@children_results)
|
107
112
|
@computed = true
|
@@ -115,13 +120,13 @@ module CompTree
|
|
115
120
|
@lock_level != 0
|
116
121
|
end
|
117
122
|
|
118
|
-
def lock
|
123
|
+
def lock
|
119
124
|
each_upward { |node|
|
120
125
|
node.lock_level += 1
|
121
126
|
}
|
122
127
|
end
|
123
128
|
|
124
|
-
def unlock
|
129
|
+
def unlock
|
125
130
|
each_upward { |node|
|
126
131
|
node.lock_level -= 1
|
127
132
|
}
|
@@ -0,0 +1 @@
|
|
1
|
+
require("comp_tree/queue/queue_" + (RUBY_VERSION < "1.9" ? "18" : "19"))
|
@@ -14,15 +14,15 @@ module CompTree
|
|
14
14
|
def push(object)
|
15
15
|
Thread.critical = true
|
16
16
|
@queue.push object
|
17
|
-
|
18
|
-
thread
|
19
|
-
ensure
|
20
|
-
Thread.critical = false
|
17
|
+
if thread = @waiting.shift
|
18
|
+
thread.wakeup
|
21
19
|
end
|
20
|
+
ensure
|
21
|
+
Thread.critical = false
|
22
22
|
end
|
23
23
|
|
24
24
|
def pop
|
25
|
-
while (Thread.critical = true; @queue.empty?)
|
25
|
+
while (Thread.critical = true ; @queue.empty?)
|
26
26
|
@waiting.push Thread.current
|
27
27
|
Thread.stop
|
28
28
|
end
|
data/lib/comp_tree.rb
CHANGED
@@ -1,83 +1,30 @@
|
|
1
1
|
#
|
2
2
|
# Copyright (c) 2008, 2009 James M. Lawrence. All rights reserved.
|
3
3
|
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person
|
5
|
-
# of this software and associated documentation files
|
6
|
-
# in the Software without restriction,
|
7
|
-
# to use, copy, modify, merge,
|
8
|
-
#
|
9
|
-
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person
|
5
|
+
# obtaining a copy of this software and associated documentation files
|
6
|
+
# (the "Software"), to deal in the Software without restriction,
|
7
|
+
# including without limitation the rights to use, copy, modify, merge,
|
8
|
+
# publish, distribute, sublicense, and/or sell copies of the Software,
|
9
|
+
# and to permit persons to whom the Software is furnished to do so,
|
10
|
+
# subject to the following conditions:
|
10
11
|
#
|
11
|
-
# The above copyright notice and this permission notice shall be
|
12
|
-
# all copies or substantial portions of the Software.
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
13
14
|
#
|
14
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# THE SOFTWARE
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
19
|
+
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
20
|
+
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
21
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
22
|
+
# SOFTWARE.
|
21
23
|
#
|
22
24
|
|
25
|
+
require 'comp_tree/error'
|
26
|
+
require 'comp_tree/queue/queue'
|
27
|
+
require 'comp_tree/node'
|
28
|
+
require 'comp_tree/algorithm'
|
23
29
|
require 'comp_tree/driver'
|
24
|
-
|
25
|
-
#
|
26
|
-
# CompTree -- Parallel Computation Tree.
|
27
|
-
#
|
28
|
-
# See README.rdoc.
|
29
|
-
#
|
30
|
-
module CompTree
|
31
|
-
COMP_TREE_VERSION = "0.7.6"
|
32
|
-
|
33
|
-
class << self
|
34
|
-
#
|
35
|
-
# :call-seq:
|
36
|
-
# build { |driver| ... }
|
37
|
-
#
|
38
|
-
# Build a new computation tree. A Driver instance is passed to the
|
39
|
-
# given block.
|
40
|
-
#
|
41
|
-
# Options hash:
|
42
|
-
#
|
43
|
-
# <tt>:node_class</tt> -- CompTree::Node subclass from which nodes
|
44
|
-
# are created.
|
45
|
-
#
|
46
|
-
# Example:
|
47
|
-
# CompTree.build do |driver|
|
48
|
-
#
|
49
|
-
# # Define a function named 'area' taking these two arguments.
|
50
|
-
# driver.define(:area, :width, :height) { |width, height|
|
51
|
-
# width*height
|
52
|
-
# }
|
53
|
-
#
|
54
|
-
# # Define a function 'width' which takes a 'border' argument.
|
55
|
-
# driver.define(:width, :border) { |border|
|
56
|
-
# 7 + border
|
57
|
-
# }
|
58
|
-
#
|
59
|
-
# # Ditto for 'height'.
|
60
|
-
# driver.define(:height, :border) { |border|
|
61
|
-
# 5 + border
|
62
|
-
# }
|
63
|
-
#
|
64
|
-
# #
|
65
|
-
# # Define a constant function 'border'.
|
66
|
-
# driver.define(:border) {
|
67
|
-
# 2
|
68
|
-
# }
|
69
|
-
#
|
70
|
-
# # Compute the area using four parallel threads.
|
71
|
-
# puts driver.compute(:area, :threads => 4)
|
72
|
-
# # => 63
|
73
|
-
#
|
74
|
-
# # We've done this computation.
|
75
|
-
# puts((7 + 2)*(5 + 2))
|
76
|
-
# # => 63
|
77
|
-
# end
|
78
|
-
#
|
79
|
-
def build(opts = nil)
|
80
|
-
yield Driver.new(opts)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
30
|
+
require 'comp_tree/comp_tree'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/
|
1
|
+
require File.dirname(__FILE__) + '/comp_tree_test_base'
|
2
2
|
|
3
3
|
class TestBasic < Test::Unit::TestCase
|
4
4
|
def test_define
|
@@ -44,7 +44,7 @@ class TestBasic < Test::Unit::TestCase
|
|
44
44
|
(1..20).each { |threads|
|
45
45
|
CompTree.build do |driver|
|
46
46
|
driver.define(:a) { 33 }
|
47
|
-
assert_equal(33, driver.compute(:a,
|
47
|
+
assert_equal(33, driver.compute(:a, threads))
|
48
48
|
end
|
49
49
|
}
|
50
50
|
end
|
@@ -55,12 +55,14 @@ class TestBasic < Test::Unit::TestCase
|
|
55
55
|
driver.define {
|
56
56
|
}
|
57
57
|
}
|
58
|
-
assert_raise(CompTree::RedefinitionError) {
|
58
|
+
error = assert_raise(CompTree::RedefinitionError) {
|
59
59
|
driver.define(:a) {
|
60
60
|
}
|
61
61
|
driver.define(:a) {
|
62
62
|
}
|
63
63
|
}
|
64
|
+
assert_equal "attempt to redefine node `:a'", error.message
|
65
|
+
assert_equal :a, error.node_name
|
64
66
|
}
|
65
67
|
end
|
66
68
|
|