ContextContainer.h 3.8 KB

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