Fix copyright lines
[folly.git] / folly / detail / StaticSingletonManager.h
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <cassert>
20 #include <mutex>
21 #include <typeindex>
22 #include <unordered_map>
23
24 namespace folly {
25 namespace detail {
26
27 // This internal-use-only class is used to create all leaked Meyers singletons.
28 // It guarantees that only one instance of every such singleton will ever be
29 // created, even when requested from different compilation units linked
30 // dynamically.
31 class StaticSingletonManager {
32  public:
33   static StaticSingletonManager& instance();
34
35   template <typename T, typename Tag, typename F>
36   inline T* create(F&& creator) {
37     auto& entry = [&]() mutable -> Entry<T>& {
38       std::lock_guard<std::mutex> lg(mutex_);
39
40       auto& id = typeid(TypePair<T, Tag>);
41       auto& entryPtr = map_[id];
42       if (!entryPtr) {
43         entryPtr = new Entry<T>();
44       }
45       assert(dynamic_cast<Entry<T>*>(entryPtr) != nullptr);
46       return *static_cast<Entry<T>*>(entryPtr);
47     }();
48
49     std::lock_guard<std::mutex> lg(entry.mutex);
50
51     if (!entry.ptr) {
52       entry.ptr = creator();
53     }
54     return entry.ptr;
55   }
56
57  private:
58   template <typename A, typename B>
59   class TypePair {};
60
61   StaticSingletonManager() {}
62
63   struct EntryIf {
64     virtual ~EntryIf() {}
65   };
66
67   template <typename T>
68   struct Entry : public EntryIf {
69     T* ptr{nullptr};
70     std::mutex mutex;
71   };
72
73   std::unordered_map<std::type_index, EntryIf*> map_;
74   std::mutex mutex_;
75 };
76
77 template <typename T, typename Tag, typename F>
78 inline T* createGlobal(F&& creator) {
79   return StaticSingletonManager::instance().create<T, Tag>(
80       std::forward<F>(creator));
81 }
82
83 template <typename T, typename Tag>
84 inline T* createGlobal() {
85   return createGlobal<T, Tag>([]() { return new T(); });
86 }
87 } // namespace detail
88 } // namespace folly