15f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #ifndef _LIBCPP___MUTEX_ONCE_FLAG_H 105f757f3fSDimitry Andric #define _LIBCPP___MUTEX_ONCE_FLAG_H 115f757f3fSDimitry Andric 125f757f3fSDimitry Andric #include <__config> 135f757f3fSDimitry Andric #include <__functional/invoke.h> 145f757f3fSDimitry Andric #include <__memory/shared_ptr.h> // __libcpp_acquire_load 155f757f3fSDimitry Andric #include <__tuple/tuple_indices.h> 165f757f3fSDimitry Andric #include <__tuple/tuple_size.h> 175f757f3fSDimitry Andric #include <__utility/forward.h> 185f757f3fSDimitry Andric #include <__utility/move.h> 195f757f3fSDimitry Andric #include <cstdint> 205f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 215f757f3fSDimitry Andric # include <tuple> 225f757f3fSDimitry Andric #endif 235f757f3fSDimitry Andric 245f757f3fSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 255f757f3fSDimitry Andric # pragma GCC system_header 265f757f3fSDimitry Andric #endif 275f757f3fSDimitry Andric 28*b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 29*b3edf446SDimitry Andric #include <__undef_macros> 30*b3edf446SDimitry Andric 315f757f3fSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric struct _LIBCPP_TEMPLATE_VIS once_flag; 345f757f3fSDimitry Andric 355f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 365f757f3fSDimitry Andric 375f757f3fSDimitry Andric template <class _Callable, class... _Args> 385f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&&, _Args&&...); 395f757f3fSDimitry Andric 405f757f3fSDimitry Andric #else // _LIBCPP_CXX03_LANG 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric template <class _Callable> 435f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, _Callable&); 445f757f3fSDimitry Andric 455f757f3fSDimitry Andric template <class _Callable> 465f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void call_once(once_flag&, const _Callable&); 475f757f3fSDimitry Andric 485f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG 495f757f3fSDimitry Andric 505f757f3fSDimitry Andric struct _LIBCPP_TEMPLATE_VIS once_flag { 515f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR once_flag() _NOEXCEPT : __state_(_Unset) {} 525f757f3fSDimitry Andric once_flag(const once_flag&) = delete; 535f757f3fSDimitry Andric once_flag& operator=(const once_flag&) = delete; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric #if defined(_LIBCPP_ABI_MICROSOFT) 565f757f3fSDimitry Andric typedef uintptr_t _State_type; 575f757f3fSDimitry Andric #else 585f757f3fSDimitry Andric typedef unsigned long _State_type; 595f757f3fSDimitry Andric #endif 605f757f3fSDimitry Andric 615f757f3fSDimitry Andric static const _State_type _Unset = 0; 625f757f3fSDimitry Andric static const _State_type _Pending = 1; 635f757f3fSDimitry Andric static const _State_type _Complete = ~_State_type(0); 645f757f3fSDimitry Andric 655f757f3fSDimitry Andric private: 665f757f3fSDimitry Andric _State_type __state_; 675f757f3fSDimitry Andric 685f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 695f757f3fSDimitry Andric template <class _Callable, class... _Args> 705f757f3fSDimitry Andric friend void call_once(once_flag&, _Callable&&, _Args&&...); 715f757f3fSDimitry Andric #else // _LIBCPP_CXX03_LANG 725f757f3fSDimitry Andric template <class _Callable> 735f757f3fSDimitry Andric friend void call_once(once_flag&, _Callable&); 745f757f3fSDimitry Andric 755f757f3fSDimitry Andric template <class _Callable> 765f757f3fSDimitry Andric friend void call_once(once_flag&, const _Callable&); 775f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG 785f757f3fSDimitry Andric }; 795f757f3fSDimitry Andric 805f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 815f757f3fSDimitry Andric 825f757f3fSDimitry Andric template <class _Fp> 835f757f3fSDimitry Andric class __call_once_param { 845f757f3fSDimitry Andric _Fp& __f_; 855f757f3fSDimitry Andric 865f757f3fSDimitry Andric public: 875f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {} 885f757f3fSDimitry Andric 895f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void operator()() { 905f757f3fSDimitry Andric typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 1>::type _Index; 915f757f3fSDimitry Andric __execute(_Index()); 925f757f3fSDimitry Andric } 935f757f3fSDimitry Andric 945f757f3fSDimitry Andric private: 955f757f3fSDimitry Andric template <size_t... _Indices> 965f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void __execute(__tuple_indices<_Indices...>) { 975f757f3fSDimitry Andric std::__invoke(std::get<0>(std::move(__f_)), std::get<_Indices>(std::move(__f_))...); 985f757f3fSDimitry Andric } 995f757f3fSDimitry Andric }; 1005f757f3fSDimitry Andric 1015f757f3fSDimitry Andric #else 1025f757f3fSDimitry Andric 1035f757f3fSDimitry Andric template <class _Fp> 1045f757f3fSDimitry Andric class __call_once_param { 1055f757f3fSDimitry Andric _Fp& __f_; 1065f757f3fSDimitry Andric 1075f757f3fSDimitry Andric public: 1085f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI explicit __call_once_param(_Fp& __f) : __f_(__f) {} 1095f757f3fSDimitry Andric 1105f757f3fSDimitry Andric _LIBCPP_HIDE_FROM_ABI void operator()() { __f_(); } 1115f757f3fSDimitry Andric }; 1125f757f3fSDimitry Andric 1135f757f3fSDimitry Andric #endif 1145f757f3fSDimitry Andric 1155f757f3fSDimitry Andric template <class _Fp> 1165f757f3fSDimitry Andric void _LIBCPP_HIDE_FROM_ABI __call_once_proxy(void* __vp) { 1175f757f3fSDimitry Andric __call_once_param<_Fp>* __p = static_cast<__call_once_param<_Fp>*>(__vp); 1185f757f3fSDimitry Andric (*__p)(); 1195f757f3fSDimitry Andric } 1205f757f3fSDimitry Andric 1215f757f3fSDimitry Andric _LIBCPP_EXPORTED_FROM_ABI void __call_once(volatile once_flag::_State_type&, void*, void (*)(void*)); 1225f757f3fSDimitry Andric 1235f757f3fSDimitry Andric #ifndef _LIBCPP_CXX03_LANG 1245f757f3fSDimitry Andric 1255f757f3fSDimitry Andric template <class _Callable, class... _Args> 1265f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable&& __func, _Args&&... __args) { 1275f757f3fSDimitry Andric if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) { 1285f757f3fSDimitry Andric typedef tuple<_Callable&&, _Args&&...> _Gp; 1295f757f3fSDimitry Andric _Gp __f(std::forward<_Callable>(__func), std::forward<_Args>(__args)...); 1305f757f3fSDimitry Andric __call_once_param<_Gp> __p(__f); 1315f757f3fSDimitry Andric std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Gp>); 1325f757f3fSDimitry Andric } 1335f757f3fSDimitry Andric } 1345f757f3fSDimitry Andric 1355f757f3fSDimitry Andric #else // _LIBCPP_CXX03_LANG 1365f757f3fSDimitry Andric 1375f757f3fSDimitry Andric template <class _Callable> 1385f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, _Callable& __func) { 1395f757f3fSDimitry Andric if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) { 1405f757f3fSDimitry Andric __call_once_param<_Callable> __p(__func); 1415f757f3fSDimitry Andric std::__call_once(__flag.__state_, &__p, &__call_once_proxy<_Callable>); 1425f757f3fSDimitry Andric } 1435f757f3fSDimitry Andric } 1445f757f3fSDimitry Andric 1455f757f3fSDimitry Andric template <class _Callable> 1465f757f3fSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI void call_once(once_flag& __flag, const _Callable& __func) { 1475f757f3fSDimitry Andric if (__libcpp_acquire_load(&__flag.__state_) != once_flag::_Complete) { 1485f757f3fSDimitry Andric __call_once_param<const _Callable> __p(__func); 1495f757f3fSDimitry Andric std::__call_once(__flag.__state_, &__p, &__call_once_proxy<const _Callable>); 1505f757f3fSDimitry Andric } 1515f757f3fSDimitry Andric } 1525f757f3fSDimitry Andric 1535f757f3fSDimitry Andric #endif // _LIBCPP_CXX03_LANG 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric _LIBCPP_END_NAMESPACE_STD 1565f757f3fSDimitry Andric 157*b3edf446SDimitry Andric _LIBCPP_POP_MACROS 158*b3edf446SDimitry Andric 1595f757f3fSDimitry Andric #endif // _LIBCPP___MUTEX_ONCE_FLAG_H 160