1
#pragma once
2

            
3
#include <functional>
4
#include <memory>
5
#include <string>
6

            
7
#include "envoy/common/pure.h"
8
#include "envoy/config/typed_config.h"
9
#include "envoy/registry/registry.h"
10
#include "envoy/singleton/instance.h"
11

            
12
namespace Envoy {
13
namespace Singleton {
14

            
15
/**
16
 * An abstract registration for a singleton entry.
17
 */
18
class Registration : public Config::UntypedFactory {
19
public:
20
1
  std::string category() const override { return "envoy.singleton"; }
21
};
22

            
23
/**
24
 * A concrete implementation of a singleton registration. All singletons are referenced by name
25
 * and must be statically registered ahead of time. This can be done like so:
26
 *
27
 * static constexpr char foo_singleton_name[] = "foo_singleton";
28
 * static Registry::RegisterFactory<Singleton::RegistrationImpl<foo_singleton_name>,
29
 *                                  Singleton::Registration>
30
 *     date_provider_singleton_registered_;
31
 *
32
 * Once this is done, the singleton can be get/set via the manager. See the Manager interface
33
 * for more information.
34
 */
35
template <const char* name_param> class RegistrationImpl : public Registration {
36
public:
37
9487
  std::string name() const override { return name_param; }
38
};
39

            
40
/**
41
 * Macro used to statically register singletons managed by the singleton manager
42
 * defined in envoy/singleton/manager.h. After the NAME has been registered use the
43
 * SINGLETON_MANAGER_REGISTERED_NAME macro to access the name registered with the
44
 * singleton manager.
45
 */
46
#define SINGLETON_MANAGER_REGISTRATION(NAME)                                                       \
47
  static constexpr char NAME##_singleton_name[] = #NAME "_singleton";                              \
48
  static Envoy::Registry::RegisterInternalFactory<                                                 \
49
      Envoy::Singleton::RegistrationImpl<NAME##_singleton_name>, Envoy::Singleton::Registration>   \
50
      NAME##_singleton_registered_;
51

            
52
124870
#define SINGLETON_MANAGER_REGISTERED_NAME(NAME) NAME##_singleton_name
53

            
54
/**
55
 * Callback function used to create a singleton.
56
 */
57
using SingletonFactoryCb = std::function<InstanceSharedPtr()>;
58

            
59
/**
60
 * A manager for all server-side singletons.
61
 */
62
class Manager {
63
public:
64
50862
  virtual ~Manager() = default;
65

            
66
  /**
67
   * This is a helper on top of get() that casts the object stored to the specified type. Since the
68
   * manager only stores pointers to the base interface, dynamic_cast provides some level of
69
   * protection via RTTI.
70
   * @param name the unique name of the singleton instance. This should be provided by the macro
71
   * SINGLETON_MANAGER_REGISTERED_NAME.
72
   * @param cb supplies the singleton creation callback. This will only be called if the singleton
73
   * does not already exist.
74
   * @param pin supplies whether the singleton should be pinned. By default, the manager only stores
75
   * a weak pointer. This allows a singleton to be cleaned up if it is not needed any more. All code
76
   * that uses singletons must store the shared_ptr for as long as the singleton is needed. But if
77
   * the pin is set to true, the singleton will be stored as a shared_ptr. This is useful if the
78
   * users want to keep the singleton around for the lifetime of the server even if it is not used
79
   * for a while.
80
   * @return InstancePtr the singleton cast to the specified type. nullptr if the singleton does not
81
   * exist.
82
   */
83
  template <class T>
84
125070
  std::shared_ptr<T> getTyped(const std::string& name, SingletonFactoryCb cb, bool pin = false) {
85
125070
    return std::dynamic_pointer_cast<T>(get(name, cb, pin));
86
125070
  }
87

            
88
  /**
89
   * This is a non-constructing getter. Use when the caller can deal with instances where
90
   * the singleton being accessed may not have been constructed previously.
91
   * @param name the unique name of singleton instance. This should be provided by the macro
92
   * SINGLETON_MANAGER_REGISTERED_NAME.
93
   * @return InstancePtr the singleton cast to the specified type. nullptr if the singleton does not
94
   * exist.
95
   */
96
61
  template <class T> std::shared_ptr<T> getTyped(const std::string& name) {
97
61
    return std::dynamic_pointer_cast<T>(get(name, [] { return nullptr; }, false));
98
61
  }
99

            
100
  /**
101
   * Get a singleton and create it if it does not exist.
102
   * @param name the unique name of the singleton instance. This should be provided by the macro
103
   * SINGLETON_MANAGER_REGISTERED_NAME.
104
   * @param cb supplies the singleton creation callback. This will only be called if the singleton
105
   * does not already exist.
106
   * @param pin supplies whether the singleton should be pinned. By default, the manager only stores
107
   * a weak pointer. This allows a singleton to be cleaned up if it is not needed any more. All code
108
   * that uses singletons must store the shared_ptr for as long as the singleton is needed. But if
109
   * the pin is set to true, the singleton will be stored as a shared_ptr. This is useful if the
110
   * users want to keep the singleton around for the lifetime of the server even if it is not used
111
   * for a while.
112
   * @return InstancePtr the singleton cast to the specified type. nullptr if the singleton does not
113
   * exist.
114
   */
115
  virtual InstanceSharedPtr get(const std::string& name, SingletonFactoryCb cb, bool pin) PURE;
116
};
117

            
118
using ManagerPtr = std::unique_ptr<Manager>;
119

            
120
} // namespace Singleton
121
} // namespace Envoy