gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
coroutine.test.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * Authors: Giacomo Travaglini
38  */
39 
40 #include <gtest/gtest.h>
41 
42 #include "base/coroutine.hh"
43 
44 using namespace m5;
45 
51 TEST(Coroutine, Unstarted)
52 {
53  auto yielding_task =
55  {
56  yield();
57  };
58 
59  const bool start_upon_creation = false;
60  Coroutine<void, void> coro(yielding_task, start_upon_creation);
61 
62  ASSERT_FALSE(coro.started());
63 }
64 
69 TEST(Coroutine, Unfinished)
70 {
71  auto yielding_task =
73  {
74  yield();
75  };
76 
77  Coroutine<void, void> coro(yielding_task);
78  ASSERT_TRUE(coro);
79 }
80 
87 TEST(Coroutine, Passing)
88 {
89  const std::vector<int> input{ 1, 2, 3 };
90  const std::vector<int> expected_values = input;
91 
92  auto passing_task =
93  [&expected_values] (Coroutine<int, void>::CallerType& yield)
94  {
95  int argument;
96 
97  for (const auto expected : expected_values) {
98  argument = yield.get();
99  ASSERT_EQ(argument, expected);
100  }
101  };
102 
103  Coroutine<int, void> coro(passing_task);
104  ASSERT_TRUE(coro);
105 
106  for (const auto val : input) {
107  coro(val);
108  }
109 }
110 
117 TEST(Coroutine, Returning)
118 {
119  const std::vector<int> output{ 1, 2, 3 };
120  const std::vector<int> expected_values = output;
121 
122  auto returning_task =
124  {
125  for (const auto ret : output) {
126  yield(ret);
127  }
128  };
129 
130  Coroutine<void, int> coro(returning_task);
131  ASSERT_TRUE(coro);
132 
133  for (const auto expected : expected_values) {
134  int returned = coro.get();
135  ASSERT_EQ(returned, expected);
136  }
137 }
138 
146 TEST(Coroutine, Fibonacci)
147 {
148  const std::vector<int> expected_values{
149  1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233 };
150 
151  const int steps = expected_values.size();
152 
153  auto fibonacci_task =
154  [steps] (Coroutine<void, int>::CallerType& yield)
155  {
156  int prev = 0;
157  int current = 1;
158 
159  for (auto iter = 0; iter < steps; iter++) {
160  int sum = prev + current;
161  yield(sum);
162 
163  prev = current;
164  current = sum;
165  }
166  };
167 
168  Coroutine<void, int> coro(fibonacci_task);
169  ASSERT_TRUE(coro);
170 
171  for (const auto expected : expected_values) {
172  ASSERT_TRUE(coro);
173  int returned = coro.get();
174  ASSERT_EQ(returned, expected);
175  }
176 }
177 
187 TEST(Coroutine, Cooperative)
188 {
189  const std::string caller_str("HloWrd");
190  const std::string coro_str("el ol!");
191  const std::string expected("Hello World!");
192 
193  auto cooperative_task =
195  {
196  for (auto& appended_c : coro_str) {
197  auto old_str = yield.get();
198  yield(old_str + appended_c);
199  }
200  };
201 
202  Coroutine<std::string, std::string> coro(cooperative_task);
203 
204  std::string result;
205  for (auto& c : caller_str) {
206  ASSERT_TRUE(coro);
207  result += c;
208  result = coro(result).get();
209  }
210 
211  ASSERT_EQ(result, expected);
212 }
213 
220 TEST(Coroutine, Nested)
221 {
222  const std::string wrong("Inner");
223  const std::string expected("Inner + Outer");
224 
225  auto inner_task =
227  {
228  std::string inner_string("Inner");
229  yield(inner_string);
230  };
231 
232  auto outer_task =
233  [&inner_task] (Coroutine<void, std::string>::CallerType& yield)
234  {
235  Coroutine<void, std::string> coro(inner_task);
236  std::string inner_string = coro.get();
237 
238  std::string outer_string("Outer");
239  yield(inner_string + " + " + outer_string);
240  };
241 
242 
243  Coroutine<void, std::string> coro(outer_task);
244  ASSERT_TRUE(coro);
245 
246  std::string result = coro.get();
247 
248  ASSERT_NE(result, wrong);
249  ASSERT_EQ(result, expected);
250 }
251 
261 TEST(Coroutine, TwoCallers)
262 {
263  bool valid_return = false;
264 
265  Coroutine<void, void> callee{[]
267  {
268  yield();
269  yield();
270  }};
271 
272  Coroutine<void, void> other_caller{[&callee, &valid_return]
274  {
275  callee();
276  valid_return = true;
277  yield();
278  }};
279 
280  ASSERT_TRUE(valid_return);
281 }
static void output(const char *filename)
Definition: debug.cc:63
Bitfield< 63 > val
Definition: misc.hh:771
CallerType: A reference to an object of this class will be passed to the coroutine task...
Definition: coroutine.hh:85
TEST(Coroutine, Unstarted)
This test is checking if the Coroutine, once it&#39;s created it doesn&#39;t start since the second argument ...
Bitfield< 18 > sum
Definition: registers.hh:617
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })
This template defines a Coroutine wrapper type with a Boost-like interface.
Definition: coroutine.hh:64
std::enable_if<!std::is_same< T, void >::value, T >::type get()
get() is the way we can extrapolate return values (yielded) from the coroutine.
Definition: coroutine.hh:229
Bitfield< 29 > c
bool started() const
Returns whether the "main" function of this fiber has started.
Definition: fiber.hh:87
Definition: compiler.hh:92

Generated on Fri Feb 28 2020 16:26:58 for gem5 by doxygen 1.8.13