/* * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include namespace folly { namespace detail { // This internal-use-only class is used to create all leaked Meyers singletons. // It guarantees that only one instance of every such singleton will ever be // created, even when requested from different compilation units linked // dynamically. class StaticSingletonManager { public: static StaticSingletonManager& instance(); template inline T* create(F&& creator) { auto& entry = [&]() mutable -> Entry& { std::lock_guard lg(mutex_); auto& id = typeid(TypePair); auto& entryPtr = map_[id]; if (!entryPtr) { entryPtr = new Entry(); } assert(dynamic_cast*>(entryPtr) != nullptr); return *static_cast*>(entryPtr); }(); std::lock_guard lg(entry.mutex); if (!entry.ptr) { entry.ptr = creator(); } return entry.ptr; } private: template class TypePair {}; StaticSingletonManager() {} struct EntryIf { virtual ~EntryIf() {} }; template struct Entry : public EntryIf { T* ptr{nullptr}; std::mutex mutex; }; std::unordered_map map_; std::mutex mutex_; }; template inline T* createGlobal(F&& creator) { return StaticSingletonManager::instance().create( std::forward(creator)); } template inline T* createGlobal() { return createGlobal([]() { return new T(); }); } } }