Subversion Repositories gelsvn

Rev

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

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