Inexor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Subsystem.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <unordered_map>
5 #include <functional>
6 #include <queue>
7 
10 #include "inexor/util/util.hpp"
11 
12 namespace inexor {
13 namespace util {
14 
15 IEXCEPTION(SubsystemException, "Some problem with the "
16  "subsystems occurred.");
17 EXCEPTION(NoSuchSubsystem, SubsystemException,
18  "The subsystem you're trying to start does not exist.");
19 EXCEPTION(SubsystemAlreadyRunning, SubsystemException,
20  "The subsystem you're trying to start is already running.");
21 EXCEPTION(SubsystemNotRunning, SubsystemException,
22  "The subsystem you're trying to stop is not running.");
23 
34 class Subsystem {
35 public:
36 
39  Subsystem() {};
40 
43  virtual ~Subsystem() {};
44 
46  virtual void initialize(int argc, char **argv) {};
47 
50  virtual void tick() {};
51 
52  bool is_initialized = false;
53 
60  typedef std::function<std::unique_ptr<Subsystem>()> Starter;
61 
62  // A map of all registered Starters and their names.
63  //
64  // This is a singleton hash map, with static aliases Get
65  // and Set for convenience.
66  //
67  // Since we register Subsystems during global variable
68  // initialization, we need to make sure, that the hash map
69  // is always available at that point.
70  // Just using another global variable would not guarantee
71  // that.
72  // Hence we use the singleton pattern, which initializes
73  // the unordered map as soon as the first subsystem is
74  // registered.
75  class Register :
76  public std::unordered_map<std::string, Starter> {
77  private:
78  Register() {};
79  Register(Register const&) = delete;
80  void operator=(Register const&) = delete;
81  public:
82  static Register& GetInstance() {
83  static Register instance;
84  return instance;
85  }
86 
88  static bool Exist(const std::string &k) {
89  auto &m = GetInstance();
90  return m.find(k) != m.end();
91  }
92 
93 
96  static void EnsureExist(const std::string &k) {
97  if (!Exist(k)) throw NoSuchSubsystem();
98  }
99 
100  static Starter& Get(const std::string &k) {
101  return GetInstance()[k];
102  }
103 
108  static void Set(const std::string &k, Starter v) {
109  GetInstance()[k] = v;
110  }
111  };
112 };
113 
118 class Metasystem : public Subsystem {
119 public:
120  typedef std::function<void()> tick_cb;
121 
122 private:
124  struct : std::queue<tick_cb> {
126  void tick() {
127  while (!empty()) {
128  front()();
129  pop();
130  }
131  }
132  } next_tick_queue;
133 
134 
135 public:
136  std::unordered_map<
137  std::string, std::unique_ptr<Subsystem>> subsystems;
138 
141 
142  ~Metasystem() override {
143  next_tick_queue.tick();
144  }
145 
147  bool is_running(const std::string &sub) noexcept {
148  return subsystems.count(sub) > 0;
149  }
150 
160  void start(const std::string &sub) {
162  if (!is_running(sub))
163  subsystems[sub] = Subsystem::Register::Get(sub)();
164  }
165 
175  void stop(const std::string &sub) {
177 
178  if (is_running(sub))
179  subsystems.erase(sub);
180  }
181 
183  void tick() override {
184  next_tick_queue.tick();
185  for (auto &e : this->subsystems) e.second->tick();
186  }
187 
189  void initialize(int argc, char **argv) override
190  {
191  for (auto &e : this->subsystems) {
192  if (!e.second->is_initialized) {
193  e.second->initialize(argc, argv);
194  e.second->is_initialized = true;
195  }
196  }
197  }
198 
200  void initialize(const std::string &sub, int argc, char **argv)
201  {
202  for (auto &e : this->subsystems) {
203  if (e.first == sub && !e.second->is_initialized) {
204  e.second->initialize(argc, argv);
205  e.second->is_initialized = true;
206  }
207  }
208  }
209 
220  next_tick_queue.push(f);
221  }
222 };
223 
224 #define __SUBSYSTEM_DUMMY(name) \
225  subsystem_register_stub_for_ ## name
226 
248 #define SUBSYSTEM_REGISTER(name, ...) \
249  int __SUBSYSTEM_DUMMY(name) INEXOR_ATTR_UNUSED = ( \
250  ::inexor::util::Subsystem::Register::Set( #name, \
251  [](){ return ::inexor::util::dynamic_pointer_cast<::inexor::util::Subsystem>( \
252  ::inexor::compat::make_unique<__VA_ARGS__>()); }) \
253  , 0);
254 
260 #define SUBSYSTEM_REQUIRE(name) \
261  { \
262  extern int __SUBSYSTEM_DUMMY(name); \
263  __SUBSYSTEM_DUMMY(name) = 0; \
264  }
265 
266 }
267 }
268 
virtual void initialize(int argc, char **argv)
Called once.
Definition: Subsystem.hpp:46
std::function< void()> tick_cb
Definition: Subsystem.hpp:120
void start(const std::string &sub)
Start a subsystem by name.
Definition: Subsystem.hpp:160
void stop(const std::string &sub)
Stop a subsystem by name.
Definition: Subsystem.hpp:175
static void Set(const std::string &k, Starter v)
Thats an alias for setting a k/v pair in the map.
Definition: Subsystem.hpp:108
void initialize(int argc, char **argv) override
Forwarded to all subsystems.
Definition: Subsystem.hpp:189
Metasystem()
Start this Metasystem with no subsystems.
Definition: Subsystem.hpp:140
Register()
Definition: Subsystem.hpp:78
Definition: Subsystem.hpp:75
static Starter & Get(const std::string &k)
Definition: Subsystem.hpp:100
static bool Exist(const std::string &k)
Check if the given subsystem exists.
Definition: Subsystem.hpp:88
void next_tick(tick_cb f)
Execute code on the next tick.
Definition: Subsystem.hpp:219
A metasystem is a collection of multiple subsystems.
Definition: Subsystem.hpp:118
ICOMMAND * f(float *a, float *b), floatret(*a **b)
void operator=(Register const &)=delete
std::function< std::unique_ptr< Subsystem >)> Starter
A function that starts a subsystem and returns a pointer to the instance this exists for the register...
Definition: Subsystem.hpp:60
virtual void tick()
Called once per frame, or what ever our event loop is.
Definition: Subsystem.hpp:50
EXCEPTION(NoSuchSubsystem, SubsystemException,"The subsystem you're trying to start does not exist.")
IEXCEPTION(SubsystemException,"Some problem with the ""subsystems occurred.")
bool is_initialized
Definition: Subsystem.hpp:52
void tick() override
Forwarded to all subsystems.
Definition: Subsystem.hpp:183
virtual ~Subsystem()
Called to stop the subsystem; usually called when inexor is quit.
Definition: Subsystem.hpp:43
char string[MAXSTRLEN]
cube-strings (char arrays of fixed size).
Definition: cube_types.hpp:18
~Metasystem() override
Definition: Subsystem.hpp:142
static Register & GetInstance()
Definition: Subsystem.hpp:82
Subsystems are loosely coupled parts of inexor.
Definition: Subsystem.hpp:34
std::unordered_map< std::string, std::unique_ptr< Subsystem > > subsystems
Definition: Subsystem.hpp:137
bool is_running(const std::string &sub) noexcept
Check whether the given subsystem is running or not.
Definition: Subsystem.hpp:147
Subsystem()
Called to startup of the subsystem; usually when inexor is started.
Definition: Subsystem.hpp:39
static void EnsureExist(const std::string &k)
Ensure that the given subsystem exists.
Definition: Subsystem.hpp:96
void initialize(const std::string &sub, int argc, char **argv)
Initialize a specific subsystem.
Definition: Subsystem.hpp:200