1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // UNSUPPORTED: no-threads |
10 | // UNSUPPORTED: c++03 |
11 | |
12 | // ALLOW_RETRIES: 3 |
13 | |
14 | // <future> |
15 | |
16 | // template <class F, class... Args> |
17 | // future<typename result_of<F(Args...)>::type> |
18 | // async(F&& f, Args&&... args); |
19 | |
20 | // template <class F, class... Args> |
21 | // future<typename result_of<F(Args...)>::type> |
22 | // async(launch policy, F&& f, Args&&... args); |
23 | |
24 | |
25 | #include <atomic> |
26 | #include <cassert> |
27 | #include <chrono> |
28 | #include <future> |
29 | #include <memory> |
30 | |
31 | #include "test_macros.h" |
32 | |
33 | typedef std::chrono::high_resolution_clock Clock; |
34 | typedef std::chrono::milliseconds ms; |
35 | |
36 | std::atomic_bool invoked{false}; |
37 | |
38 | int f0() |
39 | { |
40 | invoked = true; |
41 | std::this_thread::sleep_for(ms(200)); |
42 | return 3; |
43 | } |
44 | |
45 | int i = 0; |
46 | |
47 | int& f1() |
48 | { |
49 | invoked = true; |
50 | std::this_thread::sleep_for(ms(200)); |
51 | return i; |
52 | } |
53 | |
54 | void f2() |
55 | { |
56 | invoked = true; |
57 | std::this_thread::sleep_for(ms(200)); |
58 | } |
59 | |
60 | std::unique_ptr<int> f3(int j) |
61 | { |
62 | invoked = true; |
63 | std::this_thread::sleep_for(ms(200)); |
64 | return std::unique_ptr<int>(new int(j)); |
65 | } |
66 | |
67 | std::unique_ptr<int> f4(std::unique_ptr<int>&& p) |
68 | { |
69 | invoked = true; |
70 | std::this_thread::sleep_for(ms(200)); |
71 | return std::move(p); |
72 | } |
73 | |
74 | void f5(int j) |
75 | { |
76 | std::this_thread::sleep_for(ms(200)); |
77 | ((void)j); |
78 | TEST_THROW(j); |
79 | } |
80 | |
81 | template <class Ret, class CheckLambda, class... Args> |
82 | void test(CheckLambda&& getAndCheckFn, bool IsDeferred, Args&&... args) { |
83 | // Reset global state. |
84 | invoked = false; |
85 | |
86 | // Create the future and wait |
87 | std::future<Ret> f = std::async(std::forward<Args>(args)...); |
88 | std::this_thread::sleep_for(ms(300)); |
89 | |
90 | // Check that deferred async's have not invoked the function. |
91 | assert(invoked == !IsDeferred); |
92 | |
93 | // Time the call to f.get() and check that the returned value matches |
94 | // what is expected. |
95 | Clock::time_point t0 = Clock::now(); |
96 | assert(getAndCheckFn(f)); |
97 | Clock::time_point t1 = Clock::now(); |
98 | |
99 | // If the async is deferred it should take more than 100ms, otherwise |
100 | // it should take less than 100ms. |
101 | if (IsDeferred) { |
102 | assert(t1 - t0 > ms(100)); |
103 | } else { |
104 | assert(t1 - t0 < ms(100)); |
105 | } |
106 | } |
107 | |
108 | int main(int, char**) |
109 | { |
110 | // The default launch policy is implementation defined. libc++ defines |
111 | // it to be std::launch::async. |
112 | bool DefaultPolicyIsDeferred = false; |
113 | bool DPID = DefaultPolicyIsDeferred; |
114 | |
115 | std::launch AnyPolicy = std::launch::async | std::launch::deferred; |
116 | LIBCPP_ASSERT(AnyPolicy == std::launch::any); |
117 | |
118 | { |
119 | auto checkInt = [](std::future<int>& f) { return f.get() == 3; }; |
120 | test<int>(getAndCheckFn&: checkInt, IsDeferred: DPID, args&: f0); |
121 | test<int>(getAndCheckFn&: checkInt, IsDeferred: false, args: std::launch::async, args&: f0); |
122 | test<int>(getAndCheckFn&: checkInt, IsDeferred: true, args: std::launch::deferred, args&: f0); |
123 | test<int>(getAndCheckFn&: checkInt, IsDeferred: DPID, args&: AnyPolicy, args&: f0); |
124 | } |
125 | { |
126 | auto checkIntRef = [&](std::future<int&>& f) { return &f.get() == &i; }; |
127 | test<int&>(getAndCheckFn&: checkIntRef, IsDeferred: DPID, args&: f1); |
128 | test<int&>(getAndCheckFn&: checkIntRef, IsDeferred: false, args: std::launch::async, args&: f1); |
129 | test<int&>(getAndCheckFn&: checkIntRef, IsDeferred: true, args: std::launch::deferred, args&: f1); |
130 | test<int&>(getAndCheckFn&: checkIntRef, IsDeferred: DPID, args&: AnyPolicy, args&: f1); |
131 | } |
132 | { |
133 | auto checkVoid = [](std::future<void>& f) { f.get(); return true; }; |
134 | test<void>(getAndCheckFn&: checkVoid, IsDeferred: DPID, args&: f2); |
135 | test<void>(getAndCheckFn&: checkVoid, IsDeferred: false, args: std::launch::async, args&: f2); |
136 | test<void>(getAndCheckFn&: checkVoid, IsDeferred: true, args: std::launch::deferred, args&: f2); |
137 | test<void>(getAndCheckFn&: checkVoid, IsDeferred: DPID, args&: AnyPolicy, args&: f2); |
138 | } |
139 | { |
140 | using Ret = std::unique_ptr<int>; |
141 | auto checkUPtr = [](std::future<Ret>& f) { return *f.get() == 3; }; |
142 | test<Ret>(getAndCheckFn&: checkUPtr, IsDeferred: DPID, args&: f3, args: 3); |
143 | test<Ret>(getAndCheckFn&: checkUPtr, IsDeferred: DPID, args&: f4, args: std::unique_ptr<int>(new int(3))); |
144 | } |
145 | #ifndef TEST_HAS_NO_EXCEPTIONS |
146 | { |
147 | std::future<void> f = std::async(fn&: f5, args: 3); |
148 | std::this_thread::sleep_for(ms(300)); |
149 | try { f.get(); assert (false); } catch ( int ) {} |
150 | } |
151 | { |
152 | std::future<void> f = std::async(policy: std::launch::deferred, fn&: f5, args: 3); |
153 | std::this_thread::sleep_for(ms(300)); |
154 | try { f.get(); assert (false); } catch ( int ) {} |
155 | } |
156 | #endif |
157 | return 0; |
158 | } |
159 | |