1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "Module.h"
23#include "Exception.h"
24#include "deprecation.h"
25
26// std
27#include <map>
28#include <utility>
29#include <string>
30
31namespace
32{
33 typedef std::map<std::string, love::Module*> ModuleRegistry;
34
35 // The registry must be dynamically managed, because some modules
36 // (the math module) are static globals that are not guaranteed to
37 // be destroyed before other static globals.
38 ModuleRegistry *registry = nullptr;
39
40 ModuleRegistry &registryInstance()
41 {
42 if (!registry)
43 registry = new ModuleRegistry;
44
45 return *registry;
46 }
47
48 void freeEmptyRegistry()
49 {
50 if (registry && registry->empty())
51 {
52 delete registry;
53 registry = nullptr;
54 }
55 }
56
57} // anonymous namespace
58
59namespace love
60{
61
62love::Type Module::type("Module", &Object::type);
63Module *Module::instances[] = {};
64
65Module::Module()
66{
67 initDeprecation();
68}
69
70Module::~Module()
71{
72 ModuleRegistry &registry = registryInstance();
73
74 // We can't use the overridden Module::getName() in this destructor.
75 for (auto it = registry.begin(); it != registry.end(); ++it)
76 {
77 if (it->second == this)
78 {
79 registry.erase(it);
80 break;
81 }
82 }
83
84 // Same deal with Module::getModuleType().
85 for (int i = 0; i < (int) M_MAX_ENUM; i++)
86 {
87 if (instances[i] == this)
88 instances[i] = nullptr;
89 }
90
91 freeEmptyRegistry();
92
93 deinitDeprecation();
94}
95
96void Module::registerInstance(Module *instance)
97{
98 if (instance == nullptr)
99 throw Exception("Module instance is null");
100
101 std::string name(instance->getName());
102
103 ModuleRegistry &registry = registryInstance();
104
105 auto it = registry.find(name);
106
107 if (it != registry.end())
108 {
109 if (it->second == instance)
110 return;
111 throw Exception("Module %s already registered!", instance->getName());
112 }
113
114 registry.insert(make_pair(name, instance));
115
116 ModuleType moduletype = instance->getModuleType();
117
118 if (instances[moduletype] != nullptr)
119 {
120 printf("Warning: overwriting module instance %s with new instance %s\n",
121 instances[moduletype]->getName(), instance->getName());
122 }
123
124 instances[moduletype] = instance;
125}
126
127Module *Module::getInstance(const std::string &name)
128{
129 ModuleRegistry &registry = registryInstance();
130
131 auto it = registry.find(name);
132
133 if (registry.end() == it)
134 return nullptr;
135
136 return it->second;
137}
138
139} // love
140