trackler 2.2.1.135 → 2.2.1.136
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trackler/version.rb +1 -1
- data/problem-specifications/exercises/pov/canonical-data.json +33 -1
- data/tracks/c/exercises/acronym/test/test_acronym.c +25 -17
- data/tracks/csharp/exercises/binary-search-tree/BinarySearchTreeTest.cs +37 -28
- data/tracks/csharp/generators/Exercises/BinarySearchTree.cs +69 -0
- data/tracks/haskell/config.json +1 -0
- data/tracks/haskell/exercises/accumulate/package.yaml +1 -1
- data/tracks/haskell/exercises/acronym/package.yaml +1 -1
- data/tracks/haskell/exercises/all-your-base/package.yaml +1 -1
- data/tracks/haskell/exercises/allergies/package.yaml +1 -1
- data/tracks/haskell/exercises/alphametics/package.yaml +1 -1
- data/tracks/haskell/exercises/anagram/package.yaml +1 -1
- data/tracks/haskell/exercises/atbash-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/bank-account/package.yaml +1 -1
- data/tracks/haskell/exercises/beer-song/package.yaml +1 -1
- data/tracks/haskell/exercises/binary-search-tree/package.yaml +1 -1
- data/tracks/haskell/exercises/binary/package.yaml +1 -1
- data/tracks/haskell/exercises/bob/package.yaml +1 -1
- data/tracks/haskell/exercises/bowling/package.yaml +1 -1
- data/tracks/haskell/exercises/bracket-push/package.yaml +1 -1
- data/tracks/haskell/exercises/change/package.yaml +1 -1
- data/tracks/haskell/exercises/clock/package.yaml +1 -1
- data/tracks/haskell/exercises/collatz-conjecture/package.yaml +1 -1
- data/tracks/haskell/exercises/complex-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/connect/package.yaml +1 -1
- data/tracks/haskell/exercises/crypto-square/package.yaml +1 -1
- data/tracks/haskell/exercises/custom-set/package.yaml +1 -1
- data/tracks/haskell/exercises/diamond/package.yaml +1 -1
- data/tracks/haskell/exercises/difference-of-squares/package.yaml +1 -1
- data/tracks/haskell/exercises/dominoes/package.yaml +1 -1
- data/tracks/haskell/exercises/etl/package.yaml +1 -1
- data/tracks/haskell/exercises/food-chain/package.yaml +1 -1
- data/tracks/haskell/exercises/forth/package.yaml +1 -1
- data/tracks/haskell/exercises/gigasecond/package.yaml +1 -1
- data/tracks/haskell/exercises/go-counting/package.yaml +1 -1
- data/tracks/haskell/exercises/grade-school/package.yaml +1 -1
- data/tracks/haskell/exercises/grains/package.yaml +1 -1
- data/tracks/haskell/exercises/hamming/package.yaml +1 -1
- data/tracks/haskell/exercises/hello-world/package.yaml +1 -1
- data/tracks/haskell/exercises/hexadecimal/package.yaml +1 -1
- data/tracks/haskell/exercises/house/package.yaml +1 -1
- data/tracks/haskell/exercises/isbn-verifier/package.yaml +1 -1
- data/tracks/haskell/exercises/isogram/package.yaml +1 -1
- data/tracks/haskell/exercises/kindergarten-garden/examples/success-standard/src/Garden.hs +1 -10
- data/tracks/haskell/exercises/kindergarten-garden/package.yaml +2 -3
- data/tracks/haskell/exercises/kindergarten-garden/src/Garden.hs +3 -7
- data/tracks/haskell/exercises/kindergarten-garden/test/Tests.hs +10 -16
- data/tracks/haskell/exercises/largest-series-product/package.yaml +1 -1
- data/tracks/haskell/exercises/leap/package.yaml +1 -1
- data/tracks/haskell/exercises/lens-person/examples/success-standard/package.yaml +0 -1
- data/tracks/haskell/exercises/lens-person/package.yaml +1 -1
- data/tracks/haskell/exercises/linked-list/package.yaml +1 -1
- data/tracks/haskell/exercises/list-ops/package.yaml +1 -1
- data/tracks/haskell/exercises/luhn/package.yaml +1 -1
- data/tracks/haskell/exercises/matrix/package.yaml +1 -1
- data/tracks/haskell/exercises/meetup/package.yaml +1 -1
- data/tracks/haskell/exercises/minesweeper/package.yaml +1 -1
- data/tracks/haskell/exercises/nth-prime/package.yaml +1 -1
- data/tracks/haskell/exercises/nucleotide-count/package.yaml +1 -1
- data/tracks/haskell/exercises/ocr-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/octal/package.yaml +1 -1
- data/tracks/haskell/exercises/palindrome-products/package.yaml +1 -1
- data/tracks/haskell/exercises/pangram/package.yaml +1 -1
- data/tracks/haskell/exercises/parallel-letter-frequency/package.yaml +1 -1
- data/tracks/haskell/exercises/pascals-triangle/package.yaml +1 -1
- data/tracks/haskell/exercises/perfect-numbers/package.yaml +1 -1
- data/tracks/haskell/exercises/phone-number/package.yaml +1 -1
- data/tracks/haskell/exercises/pig-latin/package.yaml +1 -1
- data/tracks/haskell/exercises/poker/package.yaml +1 -1
- data/tracks/haskell/exercises/pov/package.yaml +2 -2
- data/tracks/haskell/exercises/pov/test/Tests.hs +15 -0
- data/tracks/haskell/exercises/prime-factors/package.yaml +1 -1
- data/tracks/haskell/exercises/protein-translation/package.yaml +1 -1
- data/tracks/haskell/exercises/pythagorean-triplet/package.yaml +1 -1
- data/tracks/haskell/exercises/queen-attack/package.yaml +1 -1
- data/tracks/haskell/exercises/rail-fence-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/raindrops/package.yaml +1 -1
- data/tracks/haskell/exercises/rna-transcription/package.yaml +1 -1
- data/tracks/haskell/exercises/robot-name/package.yaml +1 -1
- data/tracks/haskell/exercises/robot-simulator/package.yaml +1 -1
- data/tracks/haskell/exercises/roman-numerals/package.yaml +1 -1
- data/tracks/haskell/exercises/rotational-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/run-length-encoding/package.yaml +1 -1
- data/tracks/haskell/exercises/saddle-points/package.yaml +1 -1
- data/tracks/haskell/exercises/say/package.yaml +1 -1
- data/tracks/haskell/exercises/scrabble-score/package.yaml +1 -1
- data/tracks/haskell/exercises/secret-handshake/package.yaml +1 -1
- data/tracks/haskell/exercises/series/package.yaml +1 -1
- data/tracks/haskell/exercises/sgf-parsing/package.yaml +1 -1
- data/tracks/haskell/exercises/sieve/package.yaml +1 -1
- data/tracks/haskell/exercises/simple-cipher/package.yaml +1 -1
- data/tracks/haskell/exercises/simple-linked-list/package.yaml +1 -1
- data/tracks/haskell/exercises/space-age/package.yaml +1 -1
- data/tracks/haskell/exercises/spiral-matrix/package.yaml +1 -1
- data/tracks/haskell/exercises/strain/package.yaml +1 -1
- data/tracks/haskell/exercises/sublist/package.yaml +1 -1
- data/tracks/haskell/exercises/sum-of-multiples/package.yaml +1 -1
- data/tracks/haskell/exercises/transpose/package.yaml +1 -1
- data/tracks/haskell/exercises/triangle/package.yaml +1 -1
- data/tracks/haskell/exercises/trinary/package.yaml +1 -1
- data/tracks/haskell/exercises/twelve-days/package.yaml +1 -1
- data/tracks/haskell/exercises/word-count/package.yaml +1 -1
- data/tracks/haskell/exercises/wordy/package.yaml +1 -1
- data/tracks/haskell/exercises/zebra-puzzle/package.yaml +1 -1
- data/tracks/haskell/exercises/zipper/package.yaml +1 -1
- data/tracks/java/CONTRIBUTING.md +39 -3
- data/tracks/java/POLICIES.md +68 -3
- data/tracks/java/exercises/crypto-square/README.md +4 -5
- data/tracks/java/exercises/error-handling/README.md +38 -0
- data/tracks/java/exercises/series/README.md +6 -6
- data/tracks/java/exercises/sieve/README.md +5 -3
- data/tracks/java/scripts/canonical_data_check.sh +1 -1
- data/tracks/python/exercises/react/example.py +54 -63
- data/tracks/python/exercises/react/react.py +10 -10
- data/tracks/python/exercises/react/react_test.py +197 -131
- data/tracks/python/exercises/sieve/README.md +5 -3
- data/tracks/rust/exercises/react/example.rs +103 -64
- data/tracks/rust/exercises/react/src/lib.rs +31 -17
- data/tracks/rust/exercises/react/tests/react.rs +52 -61
- data/tracks/swift/config.json +11 -0
- data/tracks/swift/exercises/circular-buffer/Sources/CircularBufferExample.swift +12 -12
- data/tracks/swift/exercises/circular-buffer/Tests/CircularBufferTests/CircularBufferTests.swift +1 -1
- data/tracks/swift/exercises/proverb/Package.swift +5 -0
- data/tracks/swift/exercises/proverb/README.md +25 -0
- data/tracks/swift/exercises/proverb/Sources/Proverb.swift +1 -0
- data/tracks/swift/exercises/proverb/Sources/ProverbExample.swift +28 -0
- data/tracks/swift/exercises/proverb/Tests/LinuxMain.swift +6 -0
- data/tracks/swift/exercises/proverb/Tests/ProverbTests/ProverbTests.swift +61 -0
- data/tracks/typescript/config.json +14 -0
- data/tracks/typescript/exercises/palindrome-products/README.md +65 -0
- data/tracks/typescript/exercises/palindrome-products/package.json +36 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.example.ts +38 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.test.ts +69 -0
- data/tracks/typescript/exercises/palindrome-products/palindrome-products.ts +0 -0
- data/tracks/typescript/exercises/palindrome-products/tsconfig.json +22 -0
- data/tracks/typescript/exercises/palindrome-products/tslint.json +127 -0
- data/tracks/typescript/exercises/palindrome-products/yarn.lock +2624 -0
- metadata +17 -2
@@ -1,17 +1,17 @@
|
|
1
|
-
class
|
2
|
-
def
|
3
|
-
|
1
|
+
class InputCell(object):
|
2
|
+
def __init__(self, initial_value):
|
3
|
+
self.value = None
|
4
4
|
|
5
|
-
def add_watcher(self, watcher_callback):
|
6
|
-
pass
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
class ComputeCell(object):
|
7
|
+
def __init__(self, inputs, compute_function):
|
8
|
+
self.value = None
|
10
9
|
|
10
|
+
def add_callback(self, callback):
|
11
|
+
pass
|
11
12
|
|
12
|
-
|
13
|
-
def create_input_cell(self, value):
|
13
|
+
def remove_callback(self, callback):
|
14
14
|
pass
|
15
15
|
|
16
|
-
def
|
16
|
+
def expect_callback_values(self, callback):
|
17
17
|
pass
|
@@ -1,135 +1,201 @@
|
|
1
1
|
import unittest
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
self.assertEqual(
|
51
|
-
|
52
|
-
self.assertEqual(
|
53
|
-
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
self.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
self.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
self.
|
116
|
-
self.
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
self.assertEqual(
|
2
|
+
from functools import partial
|
3
|
+
|
4
|
+
from react import InputCell, ComputeCell
|
5
|
+
|
6
|
+
|
7
|
+
# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0
|
8
|
+
|
9
|
+
class ReactTests(unittest.TestCase):
|
10
|
+
|
11
|
+
def test_input_cells_have_a_value(self):
|
12
|
+
input_ = InputCell(10)
|
13
|
+
self.assertEqual(input_.value, 10)
|
14
|
+
|
15
|
+
def test_can_set_input_cell_value(self):
|
16
|
+
input_ = InputCell(4)
|
17
|
+
input_.value = 20
|
18
|
+
self.assertEqual(input_.value, 20)
|
19
|
+
|
20
|
+
def test_compute_cells_calculate_initial_value(self):
|
21
|
+
input_ = InputCell(1)
|
22
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
23
|
+
self.assertEqual(output.value, 2)
|
24
|
+
|
25
|
+
def test_compute_cells_take_inputs_in_right_order(self):
|
26
|
+
one = InputCell(1)
|
27
|
+
two = InputCell(2)
|
28
|
+
output = ComputeCell(
|
29
|
+
[one, two],
|
30
|
+
lambda inputs: inputs[0] + inputs[1]*10
|
31
|
+
)
|
32
|
+
self.assertEqual(output.value, 21)
|
33
|
+
|
34
|
+
def test_compute_cells_update_value_when_dependencies_are_changed(self):
|
35
|
+
input_ = InputCell(1)
|
36
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
37
|
+
|
38
|
+
input_.value = 3
|
39
|
+
self.assertEqual(output.value, 4)
|
40
|
+
|
41
|
+
def test_compute_cells_can_depend_on_other_compute_cells(self):
|
42
|
+
input_ = InputCell(1)
|
43
|
+
times_two = ComputeCell([input_], lambda inputs: inputs[0] * 2)
|
44
|
+
times_thirty = ComputeCell([input_], lambda inputs: inputs[0] * 30)
|
45
|
+
output = ComputeCell(
|
46
|
+
[times_two, times_thirty],
|
47
|
+
lambda inputs: inputs[0] + inputs[1]
|
48
|
+
)
|
49
|
+
|
50
|
+
self.assertEqual(output.value, 32)
|
51
|
+
input_.value = 3
|
52
|
+
self.assertEqual(output.value, 96)
|
53
|
+
|
54
|
+
def test_compute_cells_fire_callbacks(self):
|
55
|
+
input_ = InputCell(1)
|
56
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
57
|
+
|
58
|
+
observer = []
|
59
|
+
callback1 = self.callback_factory(observer)
|
60
|
+
|
61
|
+
output.add_callback(callback1)
|
62
|
+
input_.value = 3
|
63
|
+
self.assertEqual(observer[-1], 4)
|
64
|
+
|
65
|
+
def test_callbacks_only_fire_on_change(self):
|
66
|
+
input_ = InputCell(1)
|
67
|
+
output = ComputeCell(
|
68
|
+
[input_],
|
69
|
+
lambda inputs: 111 if inputs[0] < 3 else 222
|
70
|
+
)
|
71
|
+
|
72
|
+
observer = []
|
73
|
+
callback1 = self.callback_factory(observer)
|
74
|
+
|
75
|
+
output.add_callback(callback1)
|
76
|
+
input_.value = 2
|
77
|
+
self.assertEqual(observer, [])
|
78
|
+
input_.value = 4
|
79
|
+
self.assertEqual(observer[-1], 222)
|
80
|
+
|
81
|
+
def test_callbacks_do_not_report_already_reported_values(self):
|
82
|
+
input_ = InputCell(1)
|
83
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
84
|
+
|
85
|
+
observer = []
|
86
|
+
callback1 = self.callback_factory(observer)
|
87
|
+
|
88
|
+
output.add_callback(callback1)
|
89
|
+
input_.value = 2
|
90
|
+
self.assertEqual(observer[-1], 3)
|
91
|
+
input_.value = 3
|
92
|
+
self.assertEqual(observer[-1], 4)
|
93
|
+
|
94
|
+
def test_callbacks_can_fire_from_multiple_cells(self):
|
95
|
+
input_ = InputCell(1)
|
96
|
+
plus_one = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
97
|
+
minus_one = ComputeCell([input_], lambda inputs: inputs[0] - 1)
|
98
|
+
|
99
|
+
cb1_observer, cb2_observer = [], []
|
100
|
+
callback1 = self.callback_factory(cb1_observer)
|
101
|
+
callback2 = self.callback_factory(cb2_observer)
|
102
|
+
|
103
|
+
plus_one.add_callback(callback1)
|
104
|
+
minus_one.add_callback(callback2)
|
105
|
+
input_.value = 10
|
106
|
+
|
107
|
+
self.assertEqual(cb1_observer[-1], 11)
|
108
|
+
self.assertEqual(cb2_observer[-1], 9)
|
109
|
+
|
110
|
+
def test_callbacks_can_be_added_and_removed(self):
|
111
|
+
input_ = InputCell(11)
|
112
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
113
|
+
|
114
|
+
cb1_observer, cb2_observer, cb3_observer = [], [], []
|
115
|
+
callback1 = self.callback_factory(cb1_observer)
|
116
|
+
callback2 = self.callback_factory(cb2_observer)
|
117
|
+
callback3 = self.callback_factory(cb3_observer)
|
118
|
+
|
119
|
+
output.add_callback(callback1)
|
120
|
+
output.add_callback(callback2)
|
121
|
+
input_.value = 31
|
122
|
+
self.assertEqual(cb1_observer[-1], 32)
|
123
|
+
self.assertEqual(cb2_observer[-1], 32)
|
124
|
+
|
125
|
+
output.remove_callback(callback1)
|
126
|
+
output.add_callback(callback3)
|
127
|
+
input_.value = 41
|
128
|
+
self.assertEqual(cb2_observer[-1], 42)
|
129
|
+
self.assertEqual(cb3_observer[-1], 42)
|
130
|
+
|
131
|
+
# Expect callback1 not to be called.
|
132
|
+
self.assertEqual(len(cb1_observer), 1)
|
133
|
+
|
134
|
+
def test_removing_a_callback_multiple_times(self):
|
135
|
+
"""Guard against incorrect implementations which store their
|
136
|
+
callbacks in an array."""
|
137
|
+
input_ = InputCell(1)
|
138
|
+
output = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
139
|
+
|
140
|
+
cb1_observer, cb2_observer = [], []
|
141
|
+
callback1 = self.callback_factory(cb1_observer)
|
142
|
+
callback2 = self.callback_factory(cb2_observer)
|
143
|
+
|
144
|
+
output.add_callback(callback1)
|
145
|
+
output.add_callback(callback2)
|
146
|
+
output.remove_callback(callback1)
|
147
|
+
output.remove_callback(callback1)
|
148
|
+
output.remove_callback(callback1)
|
149
|
+
input_.value = 2
|
150
|
+
|
151
|
+
self.assertEqual(cb1_observer, [])
|
152
|
+
self.assertEqual(cb2_observer[-1], 3)
|
153
|
+
|
154
|
+
def test_callbacks_should_only_be_called_once(self):
|
155
|
+
"""Guard against incorrect implementations which call a callback
|
156
|
+
function multiple times when multiple dependencies change."""
|
157
|
+
input_ = InputCell(1)
|
158
|
+
plus_one = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
159
|
+
minus_one1 = ComputeCell([input_], lambda inputs: inputs[0] - 1)
|
160
|
+
minus_one2 = ComputeCell([minus_one1], lambda inputs: inputs[0] - 1)
|
161
|
+
output = ComputeCell(
|
162
|
+
[plus_one, minus_one2],
|
163
|
+
lambda inputs: inputs[0] * inputs[1]
|
164
|
+
)
|
165
|
+
|
166
|
+
observer = []
|
167
|
+
callback1 = self.callback_factory(observer)
|
168
|
+
|
169
|
+
output.add_callback(callback1)
|
170
|
+
input_.value = 4
|
171
|
+
self.assertEqual(observer[-1], 10)
|
172
|
+
|
173
|
+
def test_callbacks_not_called_so_long_as_output_not_changed(self):
|
174
|
+
"""Guard against incorrect implementations which call callbacks
|
175
|
+
if dependencies change but output value doesn't change."""
|
176
|
+
input_ = InputCell(1)
|
177
|
+
plus_one = ComputeCell([input_], lambda inputs: inputs[0] + 1)
|
178
|
+
minus_one = ComputeCell([input_], lambda inputs: inputs[0] - 1)
|
179
|
+
always_two = ComputeCell(
|
180
|
+
[plus_one, minus_one],
|
181
|
+
lambda inputs: inputs[0] - inputs[1]
|
182
|
+
)
|
183
|
+
|
184
|
+
observer = []
|
185
|
+
callback1 = self.callback_factory(observer)
|
186
|
+
|
187
|
+
always_two.add_callback(callback1)
|
188
|
+
input_.value = 2
|
189
|
+
input_.value = 3
|
190
|
+
input_.value = 4
|
191
|
+
input_.value = 5
|
192
|
+
self.assertEqual(observer, [])
|
193
|
+
|
194
|
+
# Utility functions.
|
195
|
+
def callback_factory(self, observer):
|
196
|
+
def callback(observer, value):
|
197
|
+
observer.append(value)
|
198
|
+
return partial(callback, observer)
|
133
199
|
|
134
200
|
|
135
201
|
if __name__ == '__main__':
|
@@ -5,8 +5,8 @@ number.
|
|
5
5
|
|
6
6
|
The Sieve of Eratosthenes is a simple, ancient algorithm for finding all
|
7
7
|
prime numbers up to any given limit. It does so by iteratively marking as
|
8
|
-
composite (i.e. not prime) the multiples of each prime,
|
9
|
-
|
8
|
+
composite (i.e. not prime) the multiples of each prime, starting with the
|
9
|
+
multiples of 2. It does not use any division or remainder operation.
|
10
10
|
|
11
11
|
Create your range, starting at two and continuing up to and including the given limit. (i.e. [2, limit])
|
12
12
|
|
@@ -25,7 +25,9 @@ https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
|
|
25
25
|
|
26
26
|
Notice that this is a very specific algorithm, and the tests don't check
|
27
27
|
that you've implemented the algorithm, only that you've come up with the
|
28
|
-
correct list of primes.
|
28
|
+
correct list of primes. A good first test is to check that you do not use
|
29
|
+
division or remainder operations (div, /, mod or % depending on the
|
30
|
+
language).
|
29
31
|
|
30
32
|
## Exception messages
|
31
33
|
|
@@ -1,12 +1,31 @@
|
|
1
1
|
use std::collections::HashMap;
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
/// `InputCellID` is a unique identifier for an input cell.
|
4
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
5
|
+
pub struct InputCellID(usize);
|
6
|
+
/// `ComputeCellID` is a unique identifier for a compute cell.
|
7
|
+
/// Values of type `InputCellID` and `ComputeCellID` should not be mutually assignable,
|
8
|
+
/// demonstrated by the following tests:
|
9
|
+
///
|
10
|
+
/// ```compile_fail
|
11
|
+
/// let mut r = react::Reactor::new();
|
12
|
+
/// let input: react::ComputeCellID = r.create_input(111);
|
13
|
+
/// ```
|
14
|
+
///
|
15
|
+
/// ```compile_fail
|
16
|
+
/// let mut r = react::Reactor::new();
|
17
|
+
/// let input = r.create_input(111);
|
18
|
+
/// let compute: react::InputCellID = r.create_compute(&[react::CellID::Input(input)], |_| 222).unwrap();
|
19
|
+
/// ```
|
20
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
21
|
+
pub struct ComputeCellID(usize);
|
22
|
+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
23
|
+
pub struct CallbackID(usize);
|
24
|
+
|
25
|
+
#[derive(Clone, Copy, Debug, PartialEq)]
|
26
|
+
pub enum CellID {
|
27
|
+
Input(InputCellID),
|
28
|
+
Compute(ComputeCellID),
|
10
29
|
}
|
11
30
|
|
12
31
|
#[derive(Debug, PartialEq)]
|
@@ -15,27 +34,38 @@ pub enum RemoveCallbackError {
|
|
15
34
|
NonexistentCallback,
|
16
35
|
}
|
17
36
|
|
18
|
-
struct Cell<
|
37
|
+
struct Cell<T: Copy> {
|
19
38
|
value: T,
|
20
39
|
last_value: T,
|
21
|
-
dependents: Vec<
|
22
|
-
cell_type: CellType<'a, T>,
|
23
|
-
callbacks_issued: usize,
|
24
|
-
callbacks: HashMap<CallbackID, Box<FnMut(T) -> () + 'a>>,
|
40
|
+
dependents: Vec<ComputeCellID>,
|
25
41
|
}
|
26
42
|
|
27
|
-
|
28
|
-
|
29
|
-
|
43
|
+
struct ComputeCell<'a, T: Copy> {
|
44
|
+
cell: Cell<T>,
|
45
|
+
|
46
|
+
dependencies: Vec<CellID>,
|
47
|
+
f: Box<Fn(&[T]) -> T + 'a>,
|
48
|
+
callbacks_issued: usize,
|
49
|
+
callbacks: HashMap<CallbackID, Box<FnMut(T) -> () + 'a>>,
|
30
50
|
}
|
31
51
|
|
32
|
-
impl <
|
33
|
-
fn new(initial: T
|
52
|
+
impl <T: Copy> Cell<T> {
|
53
|
+
fn new(initial: T) -> Self {
|
34
54
|
Cell {
|
35
55
|
value: initial,
|
36
56
|
last_value: initial,
|
37
57
|
dependents: Vec::new(),
|
38
|
-
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
impl <'a, T: Copy> ComputeCell<'a, T> {
|
63
|
+
fn new<F: Fn(&[T]) -> T + 'a>(initial: T, dependencies: Vec<CellID>, f: F) -> Self {
|
64
|
+
ComputeCell {
|
65
|
+
cell: Cell::new(initial),
|
66
|
+
|
67
|
+
dependencies,
|
68
|
+
f: Box::new(f),
|
39
69
|
callbacks_issued: 0,
|
40
70
|
callbacks: HashMap::new(),
|
41
71
|
}
|
@@ -43,52 +73,58 @@ impl <'a, T: Copy> Cell<'a, T> {
|
|
43
73
|
}
|
44
74
|
|
45
75
|
pub struct Reactor<'a, T: Copy> {
|
46
|
-
|
76
|
+
inputs: Vec<Cell<T>>,
|
77
|
+
computes: Vec<ComputeCell<'a, T>>,
|
47
78
|
}
|
48
79
|
|
49
80
|
impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
|
50
81
|
pub fn new() -> Self {
|
51
82
|
Reactor{
|
52
|
-
|
83
|
+
inputs: Vec::new(),
|
84
|
+
computes: Vec::new(),
|
53
85
|
}
|
54
86
|
}
|
55
87
|
|
56
|
-
pub fn create_input(&mut self, initial: T) ->
|
57
|
-
self.
|
58
|
-
self.
|
88
|
+
pub fn create_input(&mut self, initial: T) -> InputCellID {
|
89
|
+
self.inputs.push(Cell::new(initial));
|
90
|
+
InputCellID(self.inputs.len() - 1)
|
59
91
|
}
|
60
92
|
|
61
|
-
pub fn create_compute<F: Fn(&[T]) -> T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result<
|
93
|
+
pub fn create_compute<F: Fn(&[T]) -> T + 'a>(&mut self, dependencies: &[CellID], compute_func: F) -> Result<ComputeCellID, CellID> {
|
62
94
|
// Check all dependencies' validity before modifying any of them,
|
63
95
|
// so that we don't perform an incorrect partial write.
|
64
|
-
|
65
|
-
|
96
|
+
for &dep in dependencies {
|
97
|
+
match dep {
|
98
|
+
CellID::Input(InputCellID(id)) => if id >= self.inputs.len() { return Err(dep) },
|
99
|
+
CellID::Compute(ComputeCellID(id)) => if id >= self.computes.len() { return Err(dep) },
|
100
|
+
}
|
66
101
|
}
|
67
|
-
let new_id = self.
|
68
|
-
for &
|
69
|
-
|
102
|
+
let new_id = ComputeCellID(self.computes.len());
|
103
|
+
for &dep in dependencies {
|
104
|
+
match dep {
|
105
|
+
CellID::Input(InputCellID(id)) => self.inputs[id].dependents.push(new_id),
|
106
|
+
CellID::Compute(ComputeCellID(id)) => self.computes[id].cell.dependents.push(new_id),
|
107
|
+
}
|
70
108
|
}
|
71
109
|
let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
|
72
110
|
let initial = compute_func(&inputs);
|
73
|
-
self.
|
111
|
+
self.computes.push(ComputeCell::new(initial, dependencies.to_vec(), compute_func));
|
74
112
|
Ok(new_id)
|
75
113
|
}
|
76
114
|
|
77
115
|
pub fn value(&self, id: CellID) -> Option<T> {
|
78
|
-
|
116
|
+
match id {
|
117
|
+
CellID::Input(InputCellID(id)) => self.inputs.get(id).map(|c| c.value),
|
118
|
+
CellID::Compute(ComputeCellID(id)) => self.computes.get(id).map(|c| c.cell.value),
|
119
|
+
}
|
79
120
|
}
|
80
121
|
|
81
|
-
pub fn set_value(&mut self, id:
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
},
|
88
|
-
CellType::Compute(_, _) => Err(SetValueError::ComputeCell),
|
89
|
-
},
|
90
|
-
None => Err(SetValueError::NonexistentCell),
|
91
|
-
}.map(|deps| {
|
122
|
+
pub fn set_value(&mut self, id: InputCellID, new_value: T) -> bool {
|
123
|
+
let InputCellID(id) = id;
|
124
|
+
self.inputs.get_mut(id).map(|c| {
|
125
|
+
c.value = new_value;
|
126
|
+
c.dependents.clone()
|
127
|
+
}).map(|deps| {
|
92
128
|
for &d in deps.iter() {
|
93
129
|
self.update_dependent(d);
|
94
130
|
}
|
@@ -97,19 +133,22 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
|
|
97
133
|
for d in deps {
|
98
134
|
self.fire_callbacks(d);
|
99
135
|
}
|
100
|
-
})
|
136
|
+
}).is_some()
|
101
137
|
}
|
102
138
|
|
103
|
-
pub fn add_callback<F: FnMut(T) -> () + 'a>(&mut self, id:
|
104
|
-
|
139
|
+
pub fn add_callback<F: FnMut(T) -> () + 'a>(&mut self, id: ComputeCellID, callback: F) -> Option<CallbackID> {
|
140
|
+
let ComputeCellID(id) = id;
|
141
|
+
self.computes.get_mut(id).map(|c| {
|
105
142
|
c.callbacks_issued += 1;
|
106
|
-
|
107
|
-
c.
|
143
|
+
let cbid = CallbackID(c.callbacks_issued);
|
144
|
+
c.callbacks.insert(cbid, Box::new(callback));
|
145
|
+
cbid
|
108
146
|
})
|
109
147
|
}
|
110
148
|
|
111
|
-
pub fn remove_callback(&mut self, cell:
|
112
|
-
|
149
|
+
pub fn remove_callback(&mut self, cell: ComputeCellID, callback: CallbackID) -> Result<(), RemoveCallbackError> {
|
150
|
+
let ComputeCellID(cell) = cell;
|
151
|
+
match self.computes.get_mut(cell) {
|
113
152
|
Some(c) => match c.callbacks.remove(&callback) {
|
114
153
|
Some(_) => Ok(()),
|
115
154
|
None => Err(RemoveCallbackError::NonexistentCallback),
|
@@ -118,29 +157,28 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
|
|
118
157
|
}
|
119
158
|
}
|
120
159
|
|
121
|
-
fn update_dependent(&mut self, id:
|
160
|
+
fn update_dependent(&mut self, id: ComputeCellID) {
|
161
|
+
let ComputeCellID(id) = id;
|
162
|
+
|
122
163
|
let (new_value, dependents) = {
|
123
164
|
// This block limits the scope of the self.cells borrow.
|
124
165
|
// This is necessary becaue we borrow it mutably below.
|
125
|
-
let (dependencies, f, dependents) = match self.
|
126
|
-
Some(c) =>
|
127
|
-
CellType::Input => panic!("Input cell can't be a dependent"),
|
128
|
-
CellType::Compute(ref dependencies, ref f) => (dependencies, f, c.dependents.clone()),
|
129
|
-
},
|
166
|
+
let (dependencies, f, dependents) = match self.computes.get(id) {
|
167
|
+
Some(c) => (&c.dependencies, &c.f, c.cell.dependents.clone()),
|
130
168
|
None => panic!("Cell to update disappeared while querying"),
|
131
169
|
};
|
132
170
|
let inputs: Vec<_> = dependencies.iter().map(|&id| self.value(id).unwrap()).collect();
|
133
171
|
(f(&inputs), dependents)
|
134
172
|
};
|
135
173
|
|
136
|
-
match self.
|
174
|
+
match self.computes.get_mut(id) {
|
137
175
|
Some(c) => {
|
138
|
-
if c.value == new_value {
|
176
|
+
if c.cell.value == new_value {
|
139
177
|
// No change here, we don't need to update our dependents.
|
140
178
|
// (It wouldn't hurt to, but it would be unnecessary work)
|
141
179
|
return;
|
142
180
|
}
|
143
|
-
c.value = new_value;
|
181
|
+
c.cell.value = new_value;
|
144
182
|
},
|
145
183
|
None => panic!("Cell to update disappeared while updating"),
|
146
184
|
}
|
@@ -150,19 +188,20 @@ impl <'a, T: Copy + PartialEq> Reactor<'a, T> {
|
|
150
188
|
}
|
151
189
|
}
|
152
190
|
|
153
|
-
fn fire_callbacks(&mut self, id:
|
154
|
-
let
|
191
|
+
fn fire_callbacks(&mut self, id: ComputeCellID) {
|
192
|
+
let ComputeCellID(id) = id;
|
193
|
+
let dependents = match self.computes.get_mut(id) {
|
155
194
|
Some(c) => {
|
156
|
-
if c.value == c.last_value {
|
195
|
+
if c.cell.value == c.cell.last_value {
|
157
196
|
// Value hasn't changed since last callback fire.
|
158
197
|
// We thus shouldn't fire the callbacks.
|
159
198
|
return
|
160
199
|
}
|
161
200
|
for cb in c.callbacks.values_mut() {
|
162
|
-
cb(c.value);
|
201
|
+
cb(c.cell.value);
|
163
202
|
}
|
164
|
-
c.last_value = c.value;
|
165
|
-
c.dependents.clone()
|
203
|
+
c.cell.last_value = c.cell.value;
|
204
|
+
c.cell.dependents.clone()
|
166
205
|
},
|
167
206
|
None => panic!("Callback cell disappeared"),
|
168
207
|
};
|