1 // Copyright (C) 2013 Vicente J. Botet Escriba
2 //
3 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 // <boost/thread/future.hpp>
7 
8 // class future<R>
9 
10 // R future::get_or(R&&);
11 // R& future<R&>::get_or(R&);
12 
13 #define BOOST_THREAD_VERSION 4
14 //#define BOOST_THREAD_USES_LOG
15 #define BOOST_THREAD_USES_LOG_THREAD_ID
16 #include <boost/thread/detail/log.hpp>
17 
18 #include <boost/thread/future.hpp>
19 #include <boost/thread/thread.hpp>
20 #include <boost/core/ref.hpp>
21 #include <boost/detail/lightweight_test.hpp>
22 
23 #if defined BOOST_THREAD_USES_CHRONO
24 
25 #ifdef BOOST_MSVC
26 #pragma warning(disable: 4127) // conditional expression is constant
27 #endif
28 
29 template <typename T>
30 struct wrap
31 {
wrapwrap32   wrap(T const& v) : value(v){}
33   T value;
34 
35 };
36 
37 template <typename T>
make_exception_ptr(T v)38 boost::exception_ptr make_exception_ptr(T v) {
39   return boost::copy_exception(wrap<T>(v));
40 }
41 
func1(boost::promise<int> p)42 void func1(boost::promise<int> p)
43 {
44     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
45     p.set_value(3);
46 }
47 
func2(boost::promise<int> p)48 void func2(boost::promise<int> p)
49 {
50     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
51     p.set_exception(::make_exception_ptr(3));
52 }
53 
54 int j = 0;
55 
func3(boost::promise<int &> p)56 void func3(boost::promise<int&> p)
57 {
58     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
59     j = 5;
60     p.set_value(j);
61 }
62 
func4(boost::promise<int &> p)63 void func4(boost::promise<int&> p)
64 {
65     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
66     p.set_exception(::make_exception_ptr(3.5));
67 }
68 
func5(boost::promise<void> p)69 void func5(boost::promise<void> p)
70 {
71     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
72     p.set_value();
73 }
74 
func6(boost::promise<void> p)75 void func6(boost::promise<void> p)
76 {
77     boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
78     p.set_exception(::make_exception_ptr(4));
79 }
80 
81 
main()82 int main()
83 {
84   BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
85   {
86       typedef int T;
87       {
88           boost::promise<T> p;
89           boost::future<T> f = p.get_future();
90 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
91            boost::thread(func1, boost::move(p)).detach();
92 #else
93            p.set_value(3);
94 #endif
95           BOOST_TEST(f.valid());
96           BOOST_TEST(f.get_or(4) == 3);
97 #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
98           BOOST_TEST(!f.valid());
99 #endif
100       }
101       BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
102       {
103           boost::promise<T> p;
104           BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
105           boost::future<T> f = p.get_future();
106           BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
107 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
108           boost::thread(func2, boost::move(p)).detach();
109 #else
110           p.set_exception(::make_exception_ptr(3));
111 #endif
112           BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
113           try
114           {
115             BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
116               BOOST_TEST(f.valid());
117               BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
118               BOOST_TEST(f.get_or(4) == 4);
119               BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
120           }
121           catch (...)
122           {
123             BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
124             BOOST_TEST(false);
125           }
126 #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
127           BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
128           BOOST_TEST(!f.valid());
129 #endif
130           BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
131       }
132   }
133   BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
134   {
135       typedef int& T;
136       {
137           boost::promise<T> p;
138           boost::future<T> f = p.get_future();
139 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
140           boost::thread(func3, boost::move(p)).detach();
141 #else
142           int j=5;
143           p.set_value(j);
144 #endif
145           BOOST_TEST(f.valid());
146           int k=4;
147           BOOST_TEST(f.get_or(boost::ref(k)) == 5);
148 #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
149           BOOST_TEST(!f.valid());
150 #endif
151       }
152       BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
153       {
154           boost::promise<T> p;
155           boost::future<T> f = p.get_future();
156 #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
157           boost::thread(func4, boost::move(p)).detach();
158 #else
159           p.set_exception(::make_exception_ptr(3.5));
160 #endif
161           try
162           {
163               BOOST_TEST(f.valid());
164               int j=4;
165               BOOST_TEST(f.get_or(boost::ref(j)) == 4);
166           }
167           catch (...)
168           {
169             BOOST_TEST(false);
170           }
171 #ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
172           BOOST_TEST(!f.valid());
173 #endif
174       }
175   }
176   BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
177 
178 
179   return boost::report_errors();
180 }
181 
182 #else
183 #error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported"
184 #endif
185