summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libcxx/include/mutex45
-rw-r--r--libcxx/test/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp20
2 files changed, 61 insertions, 4 deletions
diff --git a/libcxx/include/mutex b/libcxx/include/mutex
index 21d38342dd1..fcfe4b71d89 100644
--- a/libcxx/include/mutex
+++ b/libcxx/include/mutex
@@ -175,6 +175,9 @@ template<class Callable, class ...Args>
#include <__config>
#include <__mutex_base>
#include <functional>
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+#include <tuple>
+#endif
#pragma GCC system_header
@@ -455,6 +458,39 @@ private:
#endif // _LIBCPP_HAS_NO_VARIADICS
};
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+
+template <class _F>
+class __call_once_param
+{
+ _F __f_;
+public:
+#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES
+ _LIBCPP_INLINE_VISIBILITY
+ explicit __call_once_param(_F&& __f) : __f_(_STD::move(__f)) {}
+#else
+ _LIBCPP_INLINE_VISIBILITY
+ explicit __call_once_param(const _F& __f) : __f_(__f) {}
+#endif
+
+ _LIBCPP_INLINE_VISIBILITY
+ void operator()()
+ {
+ typedef typename __make_tuple_indices<tuple_size<_F>::value, 1>::type _Index;
+ __execute(_Index());
+ }
+
+private:
+ template <size_t ..._Indices>
+ _LIBCPP_INLINE_VISIBILITY
+ void __execute(__tuple_indices<_Indices...>)
+ {
+ _STD::move(_STD::get<0>(__f_))(_STD::move(_STD::get<_Indices>(__f_))...);
+ }
+};
+
+#else
+
template <class _F>
class __call_once_param
{
@@ -475,6 +511,8 @@ public:
}
};
+#endif
+
template <class _F>
void
__call_once_proxy(void* __vp)
@@ -494,10 +532,9 @@ call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args)
{
if (__builtin_expect(__flag.__state_ , ~0ul) != ~0ul)
{
- typedef decltype(std::bind(std::forward<_Callable>(__func),
- std::forward<_Args>(__args)...)) _G;
- __call_once_param<_G> __p(std::bind(std::forward<_Callable>(__func),
- std::forward<_Args>(__args)...));
+ typedef tuple<typename decay<_Callable>::type, typename decay<_Args>::type...> _G;
+ __call_once_param<_G> __p(_G(__decay_copy(_STD::forward<_Callable>(__func)),
+ __decay_copy(_STD::forward<_Args>(__args))...));
__call_once(__flag.__state_, &__p, &__call_once_proxy<_G>);
}
}
diff --git a/libcxx/test/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp b/libcxx/test/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp
index 68ee43946b4..b4f76b45c5b 100644
--- a/libcxx/test/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp
+++ b/libcxx/test/thread/thread.mutex/thread.once/thread.once.callonce/call_once.pass.cpp
@@ -129,6 +129,22 @@ void f42()
std::call_once(flg41, init41);
}
+#ifndef _LIBCPP_HAS_NO_VARIADICS
+
+class MoveOnly
+{
+ MoveOnly(const MoveOnly&);
+public:
+ MoveOnly() {}
+ MoveOnly(MoveOnly&&) {}
+
+ void operator()(MoveOnly&&)
+ {
+ }
+};
+
+#endif
+
int main()
{
// check basic functionality
@@ -174,5 +190,9 @@ int main()
t1.join();
assert(init2::called == 5);
}
+ {
+ std::once_flag f;
+ std::call_once(f, MoveOnly(), MoveOnly());
+ }
#endif // _LIBCPP_HAS_NO_VARIADICS
}
OpenPOWER on IntegriCloud