Subversion Repositories gelsvn

Rev

Rev 39 | Rev 89 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 39 Rev 56
1
#ifndef __RESOURCE_MANAGER_H
1
#ifndef __RESOURCE_MANAGER_H
2
#define __RESOURCE_MANAGER_H
2
#define __RESOURCE_MANAGER_H
3
 
3
 
-
 
4
#include <cassert>
4
#include <string>
5
#include <string>
5
#include <list>
6
#include <list>
6
#include <typeinfo>
7
#include <typeinfo>
7
 
8
 
8
#define CLEAN_SHUTDOWN 1
9
#define CLEAN_SHUTDOWN 1
9
 
10
 
10
namespace Components
11
namespace Util
11
{
12
{
12
 
13
 
13
	typedef unsigned char FlagByte;
14
	typedef unsigned char FlagByte;
14
	const FlagByte REMOVE_WHEN_UNUSED = 0x01;
15
	const FlagByte REMOVE_WHEN_UNUSED = 0x01;
15
	const FlagByte STATIC_RESOURCE    = 0x02;
16
	const FlagByte STATIC_RESOURCE    = 0x02;
16
 
17
 
17
	/** This class template represents a resource record. There is a pointer to 
18
	/** This class template represents a resource record. There is a pointer to 
18
			the actual resource (of type RES) and a usage counter which should never
19
			the actual resource (of type RES) and a usage counter which should never
19
			be less than 0. */
20
			be less than 0. */
20
	template<class RES>
21
	template<class RES>
21
	class ResourceRecord
22
	class ResourceRecord
22
	{
23
	{
23
		/// Name of the resource (const)
24
		/// Name of the resource (const)
24
    const std::string name;
25
    const std::string name;
25
 
26
 
26
		/// A pointer to the resource (the pointer not the pointee is const)
27
		/// A pointer to the resource (the pointer not the pointee is const)
27
		RES * const res;
28
		RES * const res;
28
		
29
		
29
		/// Usage counter.
30
		/// Usage counter.
30
		int usage;
31
		int usage;
31
 
32
 
32
		/// Flags
33
		/// Flags
33
		FlagByte flags;
34
		FlagByte flags;
34
 
35
 
35
	public:
36
	public:
36
	
37
	
37
		/// Construct a null record.
38
		/// Construct a null record.
38
		ResourceRecord(): res(0), usage(0), flags(0) {}
39
		ResourceRecord(): res(0), usage(0), flags(0) {}
39
 
40
 
40
		/// Construct a resource record with a name and a pointer.
41
		/// Construct a resource record with a name and a pointer.
41
		ResourceRecord(const std::string& _name, RES* _res, bool static_res=false): 
42
		ResourceRecord(const std::string& _name, RES* _res, bool static_res=false): 
42
			name(_name), 
43
			name(_name), 
43
			res(_res), 
44
			res(_res), 
44
			usage(0), 
45
			usage(0), 
45
			flags(static_res ? STATIC_RESOURCE : 0) 
46
			flags(static_res ? STATIC_RESOURCE : 0) 
46
		{
47
		{
47
			assert(res != 0);
48
			assert(res != 0);
48
		}
49
		}
49
 
50
 
50
		~ResourceRecord() 
51
		~ResourceRecord() 
51
		{
52
		{
52
#if CLEAN_SHUTDOWN
53
#if CLEAN_SHUTDOWN
53
			assert(usage==0);		
54
			assert(usage==0);		
54
#endif
55
#endif
55
		}
56
		}
56
	
57
	
57
		void erase_resource()
58
		void erase_resource()
58
		{
59
		{
59
			assert(usage==0);
60
			assert(usage==0);
60
			if(!(flags&STATIC_RESOURCE)) 
61
			if(!(flags&STATIC_RESOURCE)) 
61
				{
62
				{
62
					delete res;
63
					delete res;
63
				}
64
				}
64
		}
65
		}
65
 
66
 
66
		/// Increment the usage counter
67
		/// Increment the usage counter
67
		void increment_usage() 
68
		void increment_usage() 
68
		{
69
		{
69
			assert(usage>=0);
70
			assert(usage>=0);
70
			++usage;
71
			++usage;
71
		}
72
		}
72
 
73
 
73
		/// Decrement the usage counter. Assert that counter is >0
74
		/// Decrement the usage counter. assert that counter is >0
74
		void decrement_usage() 
75
		void decrement_usage() 
75
		{
76
		{
76
			assert(usage>0);
77
			assert(usage>0);
77
			--usage;
78
			--usage;
78
		}
79
		}
79
 
80
 
80
		/// Return the usage count (mostly for debugging)
81
		/// Return the usage count (mostly for debugging)
81
		int get_usage() const { return usage; }
82
		int get_usage() const { return usage; }
82
 
83
 
83
		/// Get the name of a resource
84
		/// Get the name of a resource
84
		const std::string& get_name() const {return name;}
85
		const std::string& get_name() const {return name;}
85
 
86
 
86
		/// Get a pointer to the resource (const pointer)
87
		/// Get a pointer to the resource (const pointer)
87
		RES * const get_ptr() 
88
		RES * const get_ptr() 
88
		{
89
		{
89
			return res;
90
			return res;
90
		}
91
		}
91
 
92
 
92
		/// Get a resource pointer (const pointer and pointee)
93
		/// Get a resource pointer (const pointer and pointee)
93
		const RES * const get_ptr() const 
94
		const RES * const get_ptr() const 
94
		{
95
		{
95
			return res;
96
			return res;
96
		}
97
		}
97
 
98
 
98
		void remove_when_unused() 
99
		void remove_when_unused() 
99
		{
100
		{
100
/* 			assert(!(flags&STATIC_RESOURCE)); */
101
/* 			assert(!(flags&STATIC_RESOURCE)); */
101
/* 			if(!(flags&STATIC_RESOURCE)) */
102
/* 			if(!(flags&STATIC_RESOURCE)) */
102
				flags = flags|REMOVE_WHEN_UNUSED;
103
				flags = flags|REMOVE_WHEN_UNUSED;
103
		}
104
		}
104
 
105
 
105
		FlagByte get_flags() const { return flags;}
106
		FlagByte get_flags() const { return flags;}
106
	
107
	
107
	};
108
	};
108
 
109
 
109
 
110
 
110
	template<class RES> class ResourceManager;
111
	template<class RES> class ResourceManager;
111
 
112
 
112
 
113
 
113
	/** The ResourcePtr class template is a template for a reference
114
	/** The ResourcePtr class template is a template for a reference
114
			counted resource pointer. It is a smart pointer that actually points
115
			counted resource pointer. It is a smart pointer that actually points
115
			to a ResourceRecord and not to the actual resource. Since the record
116
			to a ResourceRecord and not to the actual resource. Since the record
116
			contains a reference count, we can increase the reference count when
117
			contains a reference count, we can increase the reference count when
117
			the pointer is copied and decrease it in the destructor. Only the
118
			the pointer is copied and decrease it in the destructor. Only the
118
			ResourceManager can create ResourcePtr's directly from a raw
119
			ResourceManager can create ResourcePtr's directly from a raw
119
			ResourceRecord. */
120
			ResourceRecord. */
120
	template<class RES>
121
	template<class RES>
121
	class ResourcePtr
122
	class ResourcePtr
122
	{
123
	{
123
		typedef ResourceRecord<RES> RR;
124
		typedef ResourceRecord<RES> RR;
124
		typedef std::list<RR> RRList;
125
		typedef std::list<RR> RRList;
125
		typedef typename RRList::iterator RRListIter;
126
		typedef typename RRList::iterator RRListIter;
126
 
127
 
127
		friend class ResourceManager<RES>;
128
		friend class ResourceManager<RES>;
128
 
129
 
129
	private:
130
	private:
130
		RRListIter rr;
131
		RRListIter rr;
131
		RES* res;
132
		RES* res;
132
	
133
	
133
		/** Explicit constructor with value. The constructor can only be called
134
		/** Explicit constructor with value. The constructor can only be called
134
				by a friend, i.e. the resource manager. */
135
				by a friend, i.e. the resource manager. */
135
		explicit ResourcePtr(const RRListIter& _rr): rr(_rr), res(0)
136
		explicit ResourcePtr(const RRListIter& _rr): rr(_rr), res(0)
136
		{
137
		{
137
			if(rr != 0)
138
			if(rr != 0)
138
				{
139
				{
139
					rr->increment_usage();
140
					rr->increment_usage();
140
					res = rr->get_ptr();
141
					res = rr->get_ptr();
141
				}
142
				}
142
		}
143
		}
143
 
144
 
144
		void decrement_usage();
145
		void decrement_usage();
145
	
146
	
146
	public:
147
	public:
147
	
148
	
148
		ResourcePtr(): rr(0), res(0) {}
149
		ResourcePtr(): rr(0), res(0) {}
149
	
150
	
150
		ResourcePtr(const ResourcePtr& r2): rr(r2.rr), res(0)
151
		ResourcePtr(const ResourcePtr& r2): rr(r2.rr), res(0)
151
		{
152
		{
152
			if(rr != 0)
153
			if(rr != 0)
153
				{
154
				{
154
					rr->increment_usage();
155
					rr->increment_usage();
155
					res = rr->get_ptr();
156
					res = rr->get_ptr();
156
				}
157
				}
157
		}
158
		}
158
 
159
 
159
		const ResourcePtr& operator=(const ResourcePtr& r2) 
160
		const ResourcePtr& operator=(const ResourcePtr& r2) 
160
		{
161
		{
161
			// Guard against self-assignment
162
			// Guard against self-assignment
162
			if (r2.rr != this->rr)
163
			if (r2.rr != this->rr)
163
				{
164
				{
164
					if(rr != 0)	decrement_usage();
165
					if(rr != 0)	decrement_usage();
165
 
166
 
166
					rr  = r2.rr;
167
					rr  = r2.rr;
167
					res = 0;
168
					res = 0;
168
 
169
 
169
					if(rr != 0)
170
					if(rr != 0)
170
						{
171
						{
171
							res = rr->get_ptr();
172
							res = rr->get_ptr();
172
							rr->increment_usage();
173
							rr->increment_usage();
173
						}
174
						}
174
				}
175
				}
175
			return *this;
176
			return *this;
176
		}
177
		}
177
 
178
 
178
		~ResourcePtr() {decrement_usage();}
179
		~ResourcePtr() {decrement_usage();}
179
 
180
 
180
		RES& operator*() const 
181
		RES& operator*() const 
181
		{
182
		{
182
			assert(rr != 0);
183
			assert(rr != 0);
183
			assert(res != 0);
184
			assert(res != 0);
184
			return *res;
185
			return *res;
185
		}
186
		}
186
 
187
 
187
		RES* const operator->() const 
188
		RES* const operator->() const 
188
		{
189
		{
189
			assert(rr != 0);
190
			assert(rr != 0);
190
			assert(res !=0);
191
			assert(res !=0);
191
			return res;
192
			return res;
192
		}
193
		}
193
 
194
 
194
		RES* const get_raw_ptr() const 
195
		RES* const get_raw_ptr() const 
195
		{
196
		{
196
			assert(rr != 0);
197
			assert(rr != 0);
197
			assert(res != 0);
198
			assert(res != 0);
198
			return res;
199
			return res;
199
		}
200
		}
200
 
201
 
201
		int usage() const
202
		int usage() const
202
		{
203
		{
203
			if(rr != 0)
204
			if(rr != 0)
204
				return rr->get_usage();
205
				return rr->get_usage();
205
			return -1;
206
			return -1;
206
		}
207
		}
207
 
208
 
208
		bool is_valid() const {return rr != 0;}
209
		bool is_valid() const {return rr != 0;}
209
 
210
 
210
		void relinquish_resource()
211
		void relinquish_resource()
211
		{
212
		{
212
			ResourcePtr p;
213
			ResourcePtr p;
213
			*this = p;
214
			*this = p;
214
		}
215
		}
215
 
216
 
216
		/** Calling this function sets the REMOVE_WHEN_UNUSED flag. If this 
217
		/** Calling this function sets the REMOVE_WHEN_UNUSED flag. If this 
217
				flag is set, the resource record is removed from the manager */
218
				flag is set, the resource record is removed from the manager */
218
		void remove_when_unused() {	rr->remove_when_unused(); }
219
		void remove_when_unused() {	rr->remove_when_unused(); }
219
	};
220
	};
220
 
221
 
221
 
222
 
222
	/** The ResourceManager is a singleton, and it uses Scott Meyers construct
223
	/** The ResourceManager is a singleton, and it uses Scott Meyers construct
223
			on first use idiom, i.e. the static function get_instance() will
224
			on first use idiom, i.e. the static function get_instance() will
224
			construct it when first called. There may be a problem with this
225
			construct it when first called. There may be a problem with this
225
			idion if resources depend on each other. However, that is only
226
			idion if resources depend on each other. However, that is only
226
			when the program shuts down.  See modern C++ design by
227
			when the program shuts down.  See modern C++ design by
227
			Alexandrescu for more information.
228
			Alexandrescu for more information.
228
 
229
 
229
			I'll try to make everything in this class private and accessed
230
			I'll try to make everything in this class private and accessed
230
			by a simple interface of friend functions.
231
			by a simple interface of friend functions.
231
 
232
 
232
	*/
233
	*/
233
 
234
 
234
	template<class RES>
235
	template<class RES>
235
	class ResourceManager
236
	class ResourceManager
236
	{
237
	{
237
		typedef ResourceRecord<RES> RR;
238
		typedef ResourceRecord<RES> RR;
238
		typedef std::list<RR> RRList;
239
		typedef std::list<RR> RRList;
239
		typedef typename RRList::iterator RRListIter;
240
		typedef typename RRList::iterator RRListIter;
240
		RRList resources;
241
		RRList resources;
241
	
242
	
242
		ResourceManager(): resources(0) {}
243
		ResourceManager(): resources(0) {}
243
		ResourceManager(const ResourceManager&);
244
		ResourceManager(const ResourceManager&);
244
		ResourceManager& operator=(const ResourceManager&);
245
		ResourceManager& operator=(const ResourceManager&);
245
 
246
 
246
	public:
247
	public:
247
 
248
 
248
 
249
 
249
		~ResourceManager()
250
		~ResourceManager()
250
		{
251
		{
251
#if CLEAN_SHUTDOWN
252
#if CLEAN_SHUTDOWN
252
			RRListIter i = resources.begin(); 
253
			RRListIter i = resources.begin(); 
253
			while(i != resources.end())
254
			while(i != resources.end())
254
				{
255
				{
255
					if(i->get_usage()==0)
256
					if(i->get_usage()==0)
256
						{
257
						{
257
							RRListIter tmp = i;
258
							RRListIter tmp = i;
258
							++i;
259
							++i;
259
							erase_resource(tmp);
260
							erase_resource(tmp);
260
						}
261
						}
261
					else
262
					else
262
						{
263
						{
263
							std::cout << "Warning, ResourceManager:\n\n"
264
							std::cout << "Warning, ResourceManager:\n\n"
264
												<< (typeid(this).name())
265
												<< (typeid(this).name())
265
												<< "\n\nis shutting down, and resource \n\n" 
266
												<< "\n\nis shutting down, and resource \n\n" 
266
												<< i->get_name() << "\n\nhas usage: " << i->get_usage()
267
												<< i->get_name() << "\n\nhas usage: " << i->get_usage()
267
												<< std::endl;
268
												<< std::endl;
268
							std::cout <<
269
							std::cout <<
269
 								"In other words, this resource is not unused at this\n"
270
 								"In other words, this resource is not unused at this\n"
270
								"point. That is unfortunate because then it cannot\n"
271
								"point. That is unfortunate because then it cannot\n"
271
								"be deleted (since it might be used by some other\n"
272
								"be deleted (since it might be used by some other\n"
272
								"part of the program during shutdown). Please ensure\n"
273
								"part of the program during shutdown). Please ensure\n"
273
								"that all resources are unused at program\n"
274
								"that all resources are unused at program\n"
274
								"termination. If you use a global ResourcePtr, this is\n"
275
								"termination. If you use a global ResourcePtr, this is\n"
275
								"done by calling relinquish_resource just before\n"
276
								"done by calling relinquish_resource just before\n"
276
								"exiting.\n"
277
								"exiting.\n"
277
												<< std::endl;
278
												<< std::endl;
278
							++i;
279
							++i;
279
						}
280
						}
280
				}
281
				}
281
#endif
282
#endif
282
		}
283
		}
283
 
284
 
284
		int get_no_resources() const
285
		int get_no_resources() const
285
		{
286
		{
286
			return resources.size();
287
			return resources.size();
287
		}
288
		}
288
 
289
 
289
		static ResourceManager& get_instance() 
290
		static ResourceManager& get_instance() 
290
		{
291
		{
291
			static ResourceManager instance;
292
			static ResourceManager instance;
292
			return instance;
293
			return instance;
293
		}
294
		}
294
 
295
 
295
		void erase_resource(RRListIter iter)
296
		void erase_resource(RRListIter iter)
296
		{
297
		{
297
			iter->erase_resource();
298
			iter->erase_resource();
298
			resources.erase(iter);
299
			resources.erase(iter);
299
		}
300
		}
300
 
301
 
301
		/** Find a resource and return a ResourcePtr to it. Returns the 
302
		/** Find a resource and return a ResourcePtr to it. Returns the 
302
				0 ResourcePtr if no string found. */
303
				0 ResourcePtr if no string found. */
303
		ResourcePtr<RES> get_resource_ptr(const std::string& str)
304
		ResourcePtr<RES> get_resource_ptr(const std::string& str)
304
		{
305
		{
305
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
306
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
306
				if((*i).get_name() == str) 
307
				if((*i).get_name() == str) 
307
					return ResourcePtr<RES>(i);
308
					return ResourcePtr<RES>(i);
308
			return ResourcePtr<RES>(0);
309
			return ResourcePtr<RES>(0);
309
		}
310
		}
310
 
311
 
311
		/** Add a resource with name passed as first argument and a pointer
312
		/** Add a resource with name passed as first argument and a pointer
312
				passed as 2nd argument. A ResourcePtr to the just inserted
313
				passed as 2nd argument. A ResourcePtr to the just inserted
313
				element is returned. */
314
				element is returned. */
314
		ResourcePtr<RES> register_resource(const std::string& str, 
315
		ResourcePtr<RES> register_resource(const std::string& str, 
315
																			 RES* res, bool static_resource)
316
																			 RES* res, bool static_resource)
316
		{
317
		{
317
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
318
			for(RRListIter i = resources.begin(); i != resources.end(); ++i)
318
				if(i->get_name() == str)
319
				if(i->get_name() == str)
319
					return (ResourcePtr<RES>(0));
320
					return (ResourcePtr<RES>(0));
320
 
321
 
321
			resources.push_front(RR(str, res, static_resource));
322
			resources.push_front(RR(str, res, static_resource));
322
			ResourcePtr<RES> ptr = ResourcePtr<RES>(resources.begin());
323
			ResourcePtr<RES> ptr = ResourcePtr<RES>(resources.begin());
323
			return ptr;
324
			return ptr;
324
		}
325
		}
325
 
326
 
326
/*		friend class ResourcePtr<RES>;
327
/*		friend class ResourcePtr<RES>;
327
		friend int get_no_resources<RES>();
328
		friend int get_no_resources<RES>();
328
		friend ResourcePtr<RES> get_resource_ptr<RES>(const std::string& str); 
329
		friend ResourcePtr<RES> get_resource_ptr<RES>(const std::string& str); 
329
		friend ResourcePtr<RES> register_static_resource<RES>(const std::string&,
330
		friend ResourcePtr<RES> register_static_resource<RES>(const std::string&,
330
																													RES*); 
331
																													RES*); 
331
		friend ResourcePtr<RES> register_dynamic_resource<RES>(const std::string&,
332
		friend ResourcePtr<RES> register_dynamic_resource<RES>(const std::string&,
332
																													 RES*);*/ 
333
																													 RES*);*/ 
333
	};
334
	};
334
 
335
 
335
	template<class RES>
336
	template<class RES>
336
	inline void ResourcePtr<RES>::decrement_usage()
337
	inline void ResourcePtr<RES>::decrement_usage()
337
	{
338
	{
338
		assert( (rr == 0) || (res != 0));
339
		assert( (rr == 0) || (res != 0));
339
		if(rr != 0)
340
		if(rr != 0)
340
			{
341
			{
341
				rr->decrement_usage();
342
				rr->decrement_usage();
342
				if(rr->get_usage() == 0 && (rr->get_flags()&REMOVE_WHEN_UNUSED))
343
				if(rr->get_usage() == 0 && (rr->get_flags()&REMOVE_WHEN_UNUSED))
343
					{
344
					{
344
						ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
345
						ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
345
						man.erase_resource(rr);
346
						man.erase_resource(rr);
346
					}
347
					}
347
			}
348
			}
348
	}
349
	}
349
 
350
 
350
	template<class RES>
351
	template<class RES>
351
	inline int get_no_resources()
352
	inline int get_no_resources()
352
	{
353
	{
353
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
354
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
354
		return man.get_no_resources();
355
		return man.get_no_resources();
355
	}
356
	}
356
 
357
 
357
	template<class RES>
358
	template<class RES>
358
	inline ResourcePtr<RES> get_resource_ptr(const std::string& str)
359
	inline ResourcePtr<RES> get_resource_ptr(const std::string& str)
359
	{
360
	{
360
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
361
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
361
		return man.get_resource_ptr(str);
362
		return man.get_resource_ptr(str);
362
	}
363
	}
363
 
364
 
364
	template<class RES>
365
	template<class RES>
365
	inline ResourcePtr<RES> register_dynamic_resource(const std::string& str,RES* res)
366
	inline ResourcePtr<RES> register_dynamic_resource(const std::string& str,RES* res)
366
	{
367
	{
367
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
368
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
368
		ResourcePtr<RES> ptr = man.register_resource(str, res, false);
369
		ResourcePtr<RES> ptr = man.register_resource(str, res, false);
369
		return ptr;
370
		return ptr;
370
	}
371
	}
371
 
372
 
372
	template<class RES>
373
	template<class RES>
373
	inline ResourcePtr<RES> register_static_resource(const std::string& str,RES* res)
374
	inline ResourcePtr<RES> register_static_resource(const std::string& str,RES* res)
374
	{
375
	{
375
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
376
		ResourceManager<RES>& man = ResourceManager<RES>::get_instance();
376
		ResourcePtr<RES> ptr = man.register_resource(str, res, true);
377
		ResourcePtr<RES> ptr = man.register_resource(str, res, true);
377
		return ptr;
378
		return ptr;
378
	}
379
	}
379
 
380
 
380
}
381
}
381
namespace CMP = Components;
-
 
382
 
382
 
383
 
383
 
384
#endif
384
#endif
385
 
385