Merge remote-tracking branch 'illwieckz/pakpath'
[xonotic/netradiant.git] / include / modulesystem.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_MODULESYSTEM_H )
23 #define INCLUDED_MODULESYSTEM_H
24
25 #include "generic/static.h"
26 #include "debugging/debugging.h"
27
28 #if defined( WIN32 )
29 #ifdef MINGW32
30 #define RADIANT_DLLEXPORT __declspec( dllexport )
31 #define RADIANT_DLLIMPORT __declspec( dllimport )
32 #else
33 #define RADIANT_DLLEXPORT __stdcall
34 #define RADIANT_DLLIMPORT __stdcall
35 #endif
36 #else
37 #define RADIANT_DLLEXPORT
38 #define RADIANT_DLLIMPORT
39 #endif
40
41
42 class Module
43 {
44 public:
45 virtual void capture() = 0;
46 virtual void release() = 0;
47 virtual void* getTable() = 0;
48 };
49
50 inline void* Module_getTable( Module& module ){
51         return module.getTable();
52 }
53
54 class TextOutputStream;
55 class DebugMessageHandler;
56
57 class ModuleServer
58 {
59 public:
60 class Visitor
61 {
62 public:
63 virtual void visit( const char* name, Module& module ) const = 0;
64 };
65
66 virtual void setError( bool error ) = 0;
67 virtual bool getError() const = 0;
68
69 virtual TextOutputStream& getOutputStream() = 0;
70 virtual TextOutputStream& getErrorStream() = 0;
71 virtual DebugMessageHandler& getDebugMessageHandler() = 0;
72
73 virtual void registerModule( const char* type, int version, const char* name, Module& module ) = 0;
74 virtual Module* findModule( const char* type, int version, const char* name ) const = 0;
75 virtual void foreachModule( const char* type, int version, const Visitor& visitor ) = 0;
76 };
77
78 class ModuleServerHolder
79 {
80 ModuleServer* m_server;
81 public:
82 ModuleServerHolder()
83         : m_server( 0 ){
84 }
85 void set( ModuleServer& server ){
86         m_server = &server;
87 }
88 ModuleServer& get(){
89         return *m_server;
90 }
91 };
92
93 typedef Static<ModuleServerHolder> GlobalModuleServer;
94
95 inline ModuleServer& globalModuleServer(){
96         return GlobalModuleServer::instance().get();
97 }
98
99
100 inline void initialiseModule( ModuleServer& server ){
101         GlobalErrorStream::instance().setOutputStream( server.getErrorStream() );
102         GlobalOutputStream::instance().setOutputStream( server.getOutputStream() );
103         GlobalDebugMessageHandler::instance().setHandler( server.getDebugMessageHandler() );
104         GlobalModuleServer::instance().set( server );
105 }
106
107
108
109 template<typename Type>
110 class Modules
111 {
112 public:
113 class Visitor
114 {
115 public:
116 virtual void visit( const char* name, const Type& table ) const = 0;
117 };
118
119 virtual Type* findModule( const char* name ) = 0;
120 virtual void foreachModule( const Visitor& visitor ) = 0;
121 };
122
123 #include "debugging/debugging.h"
124
125 template<typename Type>
126 class ModuleRef
127 {
128 Module* m_module;
129 Type* m_table;
130 public:
131 ModuleRef( const char* name ) : m_table( 0 ){
132         if ( !globalModuleServer().getError() ) {
133                 m_module = globalModuleServer().findModule( typename Type::Name(), typename Type::Version(), name );
134                 if ( m_module == 0 ) {
135                         globalModuleServer().setError( true );
136                         globalErrorStream() << "ModuleRef::initialise: type=" << makeQuoted( typename Type::Name() ) << " version=" << makeQuoted( typename Type::Version() ) << " name=" << makeQuoted( name ) << " - not found\n";
137                 }
138                 else
139                 {
140                         m_module->capture();
141                         if ( !globalModuleServer().getError() ) {
142                                 m_table = static_cast<Type*>( m_module->getTable() );
143                         }
144                 }
145         }
146 }
147 ~ModuleRef(){
148         if ( m_module != 0 ) {
149                 m_module->release();
150         }
151 }
152 Type* getTable(){
153 #if defined( _DEBUG )
154         ASSERT_MESSAGE( m_table != 0, "ModuleRef::getTable: type=" << makeQuoted( typename Type::Name() ) << " version=" << makeQuoted( typename Type::Version() ) << " - module-reference used without being initialised" );
155 #endif
156         return m_table;
157 }
158 };
159
160 template<typename Type>
161 class SingletonModuleRef
162 {
163 Module* m_module;
164 Type* m_table;
165 public:
166
167 SingletonModuleRef()
168         : m_module( 0 ), m_table( 0 ){
169 }
170
171 bool initialised() const {
172         return m_module != 0;
173 }
174
175 void initialise( const char* name ){
176         m_module = globalModuleServer().findModule( typename Type::Name(), typename Type::Version(), name );
177         if ( m_module == 0 ) {
178                 globalModuleServer().setError( true );
179                 globalErrorStream() << "SingletonModuleRef::initialise: type=" << makeQuoted( typename Type::Name() ) << " version=" << makeQuoted( typename Type::Version() ) << " name=" << makeQuoted( name ) << " - not found\n";
180         }
181 }
182
183 Type* getTable(){
184 #if defined( _DEBUG )
185         ASSERT_MESSAGE( m_table != 0, "SingletonModuleRef::getTable: type=" << makeQuoted( typename Type::Name() ) << " version=" << makeQuoted( typename Type::Version() ) << " - module-reference used without being initialised" );
186 #endif
187         return m_table;
188 }
189 void capture(){
190         if ( initialised() ) {
191                 m_module->capture();
192                 m_table = static_cast<Type*>( m_module->getTable() );
193         }
194 }
195 void release(){
196         if ( initialised() ) {
197                 m_module->release();
198         }
199 }
200 };
201
202 template<typename Type>
203 class GlobalModule
204 {
205 static SingletonModuleRef<Type> m_instance;
206 public:
207 static SingletonModuleRef<Type>& instance(){
208         return m_instance;
209 }
210 static Type& getTable(){
211         return *m_instance.getTable();
212 }
213 };
214
215 template<class Type>
216 SingletonModuleRef<Type> GlobalModule<Type>::m_instance;
217
218
219 template<typename Type>
220 class GlobalModuleRef
221 {
222 public:
223 GlobalModuleRef( const char* name = "*" ){
224         if ( !globalModuleServer().getError() ) {
225                 GlobalModule<Type>::instance().initialise( name );
226         }
227         GlobalModule<Type>::instance().capture();
228 }
229 ~GlobalModuleRef(){
230         GlobalModule<Type>::instance().release();
231 }
232 Type& getTable(){
233         return GlobalModule<Type>::getTable();
234 }
235 };
236
237 #endif