forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContextContainer.h
More file actions
133 lines (112 loc) · 3.77 KB
/
ContextContainer.h
File metadata and controls
133 lines (112 loc) · 3.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <memory>
#include <mutex>
#include <string>
#include <better/map.h>
#include <better/mutex.h>
#include <better/optional.h>
namespace facebook {
namespace react {
/*
* General purpose dependency injection container.
* Instance types must be copyable.
*/
class ContextContainer final {
public:
using Shared = std::shared_ptr<ContextContainer const>;
/*
* Registers an instance of the particular type `T` in the container
* using the provided `key`. Only one instance can be registered per key.
* The method does nothing if given `key` already exists in the container.
*
* Convention is to use the plain base class name for the key, so for
* example if the type `T` is `std::shared_ptr<const ReactNativeConfig>`,
* then one would use `"ReactNativeConfig"` for the `key`, even if the
* instance is actually a `shared_ptr` of derived class
*`EmptyReactNativeConfig`.
*/
template <typename T>
void insert(std::string const &key, T const &instance) const {
std::unique_lock<better::shared_mutex> lock(mutex_);
instances_.insert({key, std::make_shared<T>(instance)});
#ifndef NDEBUG
typeNames_.insert({key, typeid(T).name()});
#endif
}
/*
* Removes an instance stored for a given `key`.
* Does nothing if the instance was not found.
*/
void erase(std::string const &key) const {
std::unique_lock<better::shared_mutex> lock(mutex_);
instances_.erase(key);
#ifndef NDEBUG
typeNames_.erase(key);
#endif
}
/*
* Updates the container with values from a given container.
* Values with keys that already exist in the container will be replaced with
* values from the given container.
*/
void update(ContextContainer const &contextContainer) const {
std::unique_lock<better::shared_mutex> lock(mutex_);
for (auto const &pair : contextContainer.instances_) {
instances_.erase(pair.first);
instances_.insert(pair);
#ifndef NDEBUG
typeNames_.erase(pair.first);
typeNames_.insert(
{pair.first, contextContainer.typeNames_.at(pair.first)});
#endif
}
}
/*
* Returns a previously registered instance of the particular type `T`
* for `key`.
* Throws an exception if the instance could not be found.
*/
template <typename T>
T at(std::string const &key) const {
std::shared_lock<better::shared_mutex> lock(mutex_);
assert(
instances_.find(key) != instances_.end() &&
"ContextContainer doesn't have an instance for given key.");
assert(
typeNames_.at(key) == typeid(T).name() &&
"ContextContainer stores an instance of different type for given key.");
return *std::static_pointer_cast<T>(instances_.at(key));
}
/*
* Returns a (wrapped in an optional) previously registered instance of
* the particular type `T` for given `key`.
* Returns an empty optional if the instance could not be found.
*/
template <typename T>
better::optional<T> find(std::string const &key) const {
std::shared_lock<better::shared_mutex> lock(mutex_);
auto iterator = instances_.find(key);
if (iterator == instances_.end()) {
return {};
}
assert(
typeNames_.at(key) == typeid(T).name() &&
"ContextContainer stores an instance of different type for given key.");
return *std::static_pointer_cast<T>(iterator->second);
}
private:
mutable better::shared_mutex mutex_;
// Protected by mutex_`.
mutable better::map<std::string, std::shared_ptr<void>> instances_;
#ifndef NDEBUG
mutable better::map<std::string, std::string> typeNames_;
#endif
};
} // namespace react
} // namespace facebook