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 | #include <folly/detail/StaticSingletonManager.h> |
18 | |
19 | #include <mutex> |
20 | #include <typeindex> |
21 | #include <unordered_map> |
22 | |
23 | namespace folly { |
24 | namespace detail { |
25 | |
26 | namespace { |
27 | |
28 | class StaticSingletonManagerImpl { |
29 | public: |
30 | using Make = void*(); |
31 | using Cache = std::atomic<void*>; |
32 | |
33 | void* create(std::type_info const& key, Make& make, Cache& cache) { |
34 | auto const ptr = entry(key).get(make); |
35 | cache.store(ptr, std::memory_order_release); |
36 | return ptr; |
37 | } |
38 | |
39 | private: |
40 | struct Entry { |
41 | void* ptr{}; |
42 | std::mutex mutex; |
43 | |
44 | void* get(Make& make) { |
45 | std::lock_guard<std::mutex> lock(mutex); |
46 | return ptr ? ptr : (ptr = make()); |
47 | } |
48 | }; |
49 | |
50 | Entry& entry(std::type_info const& key) { |
51 | std::lock_guard<std::mutex> lock(mutex_); |
52 | auto& e = map_[key]; |
53 | return e ? *e : *(e = new Entry()); |
54 | } |
55 | |
56 | std::unordered_map<std::type_index, Entry*> map_; |
57 | std::mutex mutex_; |
58 | }; |
59 | |
60 | } // namespace |
61 | |
62 | void* StaticSingletonManager::create_( |
63 | Key const& key, |
64 | Make& make, |
65 | Cache& cache) { |
66 | // This Leaky Meyers Singleton must always live in the .cpp file. |
67 | static auto& instance = *new StaticSingletonManagerImpl(); |
68 | return instance.create(key, make, cache); |
69 | } |
70 | |
71 | } // namespace detail |
72 | } // namespace folly |
73 | |