| | #pragma once |
| |
|
| | #include <c10/macros/Macros.h> |
| | #include <c10/util/C++17.h> |
| |
|
| | #include <atomic> |
| | #include <functional> |
| | #include <mutex> |
| | #include <utility> |
| |
|
| | namespace c10 { |
| |
|
| | |
| | |
| | |
| | template <typename Flag, typename F, typename... Args> |
| | inline void call_once(Flag& flag, F&& f, Args&&... args) { |
| | if (C10_LIKELY(flag.test_once())) { |
| | return; |
| | } |
| | flag.call_once_slow(std::forward<F>(f), std::forward<Args>(args)...); |
| | } |
| |
|
| | class once_flag { |
| | public: |
| | #ifndef _WIN32 |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | constexpr |
| | #endif |
| | once_flag() noexcept = default; |
| | once_flag(const once_flag&) = delete; |
| | once_flag& operator=(const once_flag&) = delete; |
| | once_flag(once_flag&&) = delete; |
| | once_flag& operator=(once_flag&&) = delete; |
| | ~once_flag() = default; |
| | bool test_once() { |
| | return init_.load(std::memory_order_acquire); |
| | } |
| |
|
| | private: |
| | template <typename Flag, typename F, typename... Args> |
| | friend void call_once(Flag& flag, F&& f, Args&&... args); |
| |
|
| | template <typename F, typename... Args> |
| | void call_once_slow(F&& f, Args&&... args) { |
| | std::lock_guard<std::mutex> guard(mutex_); |
| | if (init_.load(std::memory_order_relaxed)) { |
| | return; |
| | } |
| | std::invoke(std::forward<F>(f), std::forward<Args>(args)...); |
| | init_.store(true, std::memory_order_release); |
| | } |
| |
|
| | void reset_once() { |
| | init_.store(false, std::memory_order_release); |
| | } |
| |
|
| | private: |
| | std::mutex mutex_; |
| | std::atomic<bool> init_{false}; |
| | }; |
| |
|
| | } |
| |
|