Nebula
Loading...
Searching...
No Matches
resourceserver.h
Go to the documentation of this file.
1#pragma once
2//------------------------------------------------------------------------------
11//------------------------------------------------------------------------------
12#include <functional>
13#include "core/refcounted.h"
14#include "ids/id.h"
15#include "core/singleton.h"
16#include "resourceid.h"
17#include "resourceloader.h"
19#include "io/urn.h"
20#include "io/assignregistry.h"
21#include "db/dbfactory.h"
22#include "db/database.h"
23
24namespace Resources
25{
27{
30public:
34 virtual ~ResourceServer();
35
37 void Open();
39 void Close();
40
42 void Update(IndexT frameIndex);
43
45 Resources::ResourceId CreateResource(const ResourceName& res, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
47 Resources::ResourceId CreateResource(const ResourceName& res, const Util::StringAtom& tag, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
49 template<class METADATA> Resources::ResourceId CreateResource(const ResourceName& res, const METADATA& metaData, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
51 template<class METADATA> Resources::ResourceId CreateResource(const ResourceName& res, const METADATA& metaData, const Util::StringAtom& tag, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
52
54 Resources::ResourceId CreateResource(const IO::URN& res, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
56 Resources::ResourceId CreateResource(const IO::URN& res, const Util::StringAtom& tag, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
58 template<class METADATA> Resources::ResourceId CreateResource(const IO::URN& res, const METADATA& metaData, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
60 template<class METADATA> Resources::ResourceId CreateResource(const IO::URN& res, const METADATA& metaData, const Util::StringAtom& tag, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr, bool immediate = false, bool stream = true);
61
63 void DiscardResource(const Resources::ResourceId res);
65 void DiscardResources(const Util::StringAtom& tag);
69 void ReloadResource(const ResourceName& res, std::function<void(const Resources::ResourceId)> success = nullptr, std::function<void(const Resources::ResourceId)> failed = nullptr);
71 void SetMinLod(const ResourceId& id, float lod, bool immediate);
73 void CreateResourceListener(const ResourceId& id, std::function<void(const Resources::ResourceId)> success, std::function<void(const Resources::ResourceId)> failed = nullptr);
74
76 Core::Rtti* GetType(const Resources::ResourceId id);
77
79 const Resources::ResourceName GetName(const Resources::ResourceId id) const;
81 const Util::StringAtom GetTag(const Resources::ResourceId id) const;
83 const Resource::State GetState(const Resources::ResourceId id) const;
85 const SizeT GetUsage(const Resources::ResourceId id) const;
87 bool HasResource(const Resources::ResourceId id) const;
89 const Resources::ResourceId GetId(const Resources::ResourceName& name) const;
90
92 void RegisterStreamLoader(const Util::StringAtom& ext, const Core::Rtti& loaderClass);
94 void DeregisterStreamLoader(const Util::StringAtom& ext, const Core::Rtti& loaderClass);
96 template <class POOL_TYPE> POOL_TYPE* GetStreamLoader() const;
98 bool HasStreamLoader(const Util::StringAtom& ext) const;
100 bool HasStreamLoader(const IO::URN& urn) const;
101
103 void WaitForLoaderThread();
104
107private:
108 friend class ResourceLoader;
109
110 bool open;
115
116 static int32_t UniquePoolCounter;
117};
118
119//------------------------------------------------------------------------------
124inline Resources::ResourceId
126 const ResourceName& id
127 , std::function<void(const Resources::ResourceId)> success
128 , std::function<void(const Resources::ResourceId)> failed
129 , bool immediate
130 , bool stream
131)
132{
133 return this->CreateResource(id, "", success, failed, immediate, stream);
134}
135
136//------------------------------------------------------------------------------
141inline Resources::ResourceId
143 const ResourceName& res
144 , const Util::StringAtom& tag
145 , std::function<void(const Resources::ResourceId)> success
146 , std::function<void(const Resources::ResourceId)> failed
147 , bool immediate
148 , bool stream
149)
150{
151 // get resource loader by extension
153 IndexT i = this->extensionMap.FindIndex(ext);
154 n_warn_fmt(i != InvalidIndex, "No resource loader is associated with file extension '%s'", ext.AsCharPtr());
155 if (i == InvalidIndex)
156 return Resources::InvalidResourceId;
157 const Ptr<ResourceLoader>& loader = this->loaders[this->extensionMap.ValueAtIndex(i)].downcast<ResourceLoader>();
158
159 // create container and cast to actual resource type
160 Resources::ResourceId id = loader->CreateResource(IO::URI(res.AsString()), nullptr, 0, tag, success, failed, immediate, stream);
161 return id;
162}
163
164//------------------------------------------------------------------------------
167inline Resources::ResourceId
169 const IO::URN& res
170 , std::function<void(const Resources::ResourceId)> success
171 , std::function<void(const Resources::ResourceId)> failed
172 , bool immediate
173 , bool stream
174)
175{
176 return CreateResource(res, "", success, failed, immediate, stream);
177}
178
179//------------------------------------------------------------------------------
182inline Resources::ResourceId
184 const IO::URN& res
185 , const Util::StringAtom& tag
186 , std::function<void(const Resources::ResourceId)> success
187 , std::function<void(const Resources::ResourceId)> failed
188 , bool immediate
189 , bool stream
190)
191{
192 // get resource loader by extension
193 IndexT i = this->extensionMap.FindIndex(res.GetNamespace());
194 n_assert_fmt(i != InvalidIndex, "No resource loader is associated with URN namespace '%s'", res.GetNamespace().AsCharPtr());
195 const Ptr<ResourceLoader>& loader = this->loaders[this->extensionMap.ValueAtIndex(i)].downcast<ResourceLoader>();
196
197 // create container and cast to actual resource type
198 Resources::ResourceId id = loader->CreateResource(res, nullptr, 0, tag, success, failed, immediate, stream);
199 return id;
200}
201
202//------------------------------------------------------------------------------
205template<class METADATA>
206inline Resources::ResourceId
208 const ResourceName& res
209 , const METADATA& metaData
210 , std::function<void(const Resources::ResourceId)> success
211 , std::function<void(const Resources::ResourceId)> failed
212 , bool immediate
213 , bool stream
214)
215{
216 return this->CreateResource(res, metaData, "", success, failed, immediate, stream);
217}
218
219//------------------------------------------------------------------------------
222template<class METADATA>
223inline Resources::ResourceId
225 const ResourceName& res
226 , const METADATA& metaData
227 , const Util::StringAtom& tag
228 , std::function<void(const Resources::ResourceId)> success
229 , std::function<void(const Resources::ResourceId)> failed
230 , bool immediate
231 , bool stream
232)
233{
234 // get resource loader by extension
236 IndexT i = this->extensionMap.FindIndex(ext);
237 n_warn_fmt(i != InvalidIndex, "No resource loader is associated with file extension '%s'", ext.AsCharPtr());
238 if (i == InvalidIndex)
239 return Resources::InvalidResourceId;
240 const Ptr<ResourceLoader>& loader = this->loaders[this->extensionMap.ValueAtIndex(i)].downcast<ResourceLoader>();
241
242 // create container and cast to actual resource type
243 Resources::ResourceId id = loader->CreateResource(IO::URI(res.Value()), &metaData, sizeof(METADATA), tag, success, failed, immediate, stream);
244 return id;
245}
246
247//------------------------------------------------------------------------------
250template<class METADATA>
251inline Resources::ResourceId ResourceServer::CreateResource(
252 const IO::URN& res
253 , const METADATA& metaData
254 , std::function<void(const Resources::ResourceId)> success
255 , std::function<void(const Resources::ResourceId)> failed
256 , bool immediate
257 , bool stream
258)
259{
260 return CreateResource(res, metaData, "", success, failed, immediate, stream);
261}
262
263//------------------------------------------------------------------------------
266template<class METADATA>
267inline Resources::ResourceId ResourceServer::CreateResource(
268 const IO::URN& res
269 , const METADATA& metaData
270 , const Util::StringAtom& tag
271 , std::function<void(const Resources::ResourceId)> success
272 , std::function<void(const Resources::ResourceId)> failed
273 , bool immediate
274 , bool stream
275)
276{
277 // get resource loader by extension
278 IndexT i = this->extensionMap.FindIndex(res.GetNamespace());
279 n_assert_fmt(i != InvalidIndex, "No resource loader is associated with URN namespace '%s'", res.GetNamespace().AsCharPtr());
280 const Ptr<ResourceLoader>& loader = this->loaders[this->extensionMap.ValueAtIndex(i)].downcast<ResourceLoader>();
281
282 // create container and cast to actual resource type
283 Resources::ResourceId id = loader->CreateResource(res, &metaData, sizeof(METADATA), tag, success, failed, immediate, stream);
284 return id;
285}
286
287//------------------------------------------------------------------------------
290inline void
291ResourceServer::ReloadResource(const ResourceName& res, std::function<void(const Resources::ResourceId)> success, std::function<void(const Resources::ResourceId)> failed)
292{
293 // get resource loader by extension
295 IndexT i = this->extensionMap.FindIndex(ext);
296 n_warn_fmt(i != InvalidIndex, "No resource loader is associated with file extension '%s'", ext.AsCharPtr());
297 if (i == InvalidIndex)
298 return;
299 const Ptr<ResourceLoader>& loader = this->loaders[this->extensionMap.ValueAtIndex(i)].downcast<ResourceLoader>();
300
301 // create container and cast to actual resource type
302 loader->ReloadResource(res, success, failed);
303}
304
305//------------------------------------------------------------------------------
308inline bool
310{
311 IndexT i = this->extensionMap.FindIndex(ext);
312 return i != InvalidIndex;
313}
314
315//------------------------------------------------------------------------------
318inline bool
320{
321 IndexT i = this->extensionMap.FindIndex(urn.GetNamespace());
322 return i != InvalidIndex;
323}
324
325//------------------------------------------------------------------------------
328inline void
329ResourceServer::SetMinLod(const ResourceId& id, float lod, bool immediate)
330{
331 // get id of loader
332 const Ids::Id8 loaderid = id.loaderIndex;
333
334 // get resource loader by extension
335 n_assert(this->loaders.Size() > loaderid);
336 const Ptr<ResourceLoader>& loader = this->loaders[loaderid].downcast<ResourceLoader>();
337
338 // update LOD
339 loader->SetMinLod(id, lod, immediate);
340}
341
342//------------------------------------------------------------------------------
345inline void
347 const ResourceId& id,
348 std::function<void(const Resources::ResourceId)> success,
349 std::function<void(const Resources::ResourceId)> failed
350)
351{
352 // get id of loader
353 const Ids::Id8 loaderid = id.loaderIndex;
354
355 // get resource loader by extension
356 n_assert(this->loaders.Size() > loaderid);
357 const Ptr<ResourceLoader>& loader = this->loaders[loaderid].downcast<ResourceLoader>();
358
359 loader->CreateListener(id, success, failed);
360}
361
362//------------------------------------------------------------------------------
366inline void
367ResourceServer::DiscardResource(const Resources::ResourceId id)
368{
369 // get id of loader
370 const Ids::Id8 loaderid = id.loaderIndex;
371
372 // get resource loader by extension
373 n_assert(this->loaders.Size() > loaderid);
374 const Ptr<ResourceLoader>& loader = this->loaders[loaderid].downcast<ResourceLoader>();
375
376 // discard container
377 loader->DiscardResource(id);
378}
379
380//------------------------------------------------------------------------------
383inline const Resources::ResourceName
384ResourceServer::GetName(const Resources::ResourceId id) const
385{
386 // get resource loader by extension
387 n_assert(this->loaders.Size() > id.loaderIndex);
388 const Ptr<ResourceLoader>& loader = this->loaders[id.loaderIndex];
389 return loader->GetName(id.resourceId);
390}
391
392//------------------------------------------------------------------------------
395inline const Util::StringAtom
396ResourceServer::GetTag(const Resources::ResourceId id) const
397{
398 // get resource loader by extension
399 n_assert(this->loaders.Size() > id.loaderIndex);
400 const Ptr<ResourceLoader>& loader = this->loaders[id.loaderIndex];
401 return loader->GetTag(id.resourceId);
402}
403
404//------------------------------------------------------------------------------
408ResourceServer::GetState(const Resources::ResourceId id) const
409{
410 // get resource loader by extension
411 n_assert(this->loaders.Size() > id.loaderIndex);
412 const Ptr<ResourceLoader>& loader = this->loaders[id.loaderIndex];
413 return loader->GetState(id.resourceId);
414}
415
416//------------------------------------------------------------------------------
419inline const SizeT
420ResourceServer::GetUsage(const Resources::ResourceId id) const
421{
422 // get resource loader by extension
423 n_assert(this->loaders.Size() > id.loaderIndex);
424 const Ptr<ResourceLoader>& loader = this->loaders[id.loaderIndex];
425 return loader->GetUsage(id.resourceId);
426}
427
428//------------------------------------------------------------------------------
431inline bool
432ResourceServer::HasResource(const Resources::ResourceId id) const
433{
434 if (this->loaders.Size() <= id.loaderIndex) return false;
435 {
436 const Ptr<ResourceLoader>& loader = this->loaders[id.loaderIndex];
437 if (loader->HasResource(id)) return true;
438 return false;
439 }
440}
441
442//------------------------------------------------------------------------------
445inline const Resources::ResourceId
447{
448 IndexT i;
449 for (i = 0; i < this->loaders.Size(); i++)
450 {
451 Resources::ResourceId id = this->loaders[i]->GetId(name);
452 if (id != Resources::ResourceId::Invalid()) return id;
453 }
454 return Resources::ResourceId::Invalid();
455}
456
457//------------------------------------------------------------------------------
460template <class POOL_TYPE>
461inline POOL_TYPE*
463{
464 static_assert(std::is_base_of<ResourceLoader, POOL_TYPE>::value, "Type requested is not a stream pool");
465 IndexT i = this->typeMap.FindIndex(&POOL_TYPE::RTTI);
466 if (i != InvalidIndex)
467 {
468 return static_cast<POOL_TYPE*>(this->loaders[this->typeMap.ValueAtIndex(i)].get());
469 }
470
471 n_error("No loader registered for this type");
472 return nullptr;
473}
474
475//------------------------------------------------------------------------------
479inline Resources::ResourceId
481 const ResourceName& res
482 , const Util::StringAtom& tag
483 , std::function<void(const Resources::ResourceId)> success = nullptr
484 , std::function<void(const Resources::ResourceId)> failed = nullptr
485 , bool immediate = false
486 , bool stream = true
487)
488{
489 return ResourceServer::Instance()->CreateResource(res, tag, success, failed, immediate, stream);
490}
491
492//------------------------------------------------------------------------------
496template <class METADATA>
497inline Resources::ResourceId
499 const ResourceName& res
500 , const METADATA& metaData
501 , const Util::StringAtom& tag
502 , std::function<void(const Resources::ResourceId)> success = nullptr
503 , std::function<void(const Resources::ResourceId)> failed = nullptr
504 , bool immediate = false
505 , bool stream = true
506)
507{
508 return ResourceServer::Instance()->CreateResource(res, metaData, tag, success, failed, immediate, stream);
509}
510
511//------------------------------------------------------------------------------
515inline Resources::ResourceId
517 const IO::URN& res
518 , const Util::StringAtom& tag
519 , std::function<void(const Resources::ResourceId)> success = nullptr
520 , std::function<void(const Resources::ResourceId)> failed = nullptr
521 , bool immediate = false
522 , bool stream = true
523)
524{
525 return ResourceServer::Instance()->CreateResource(res, tag, success, failed, immediate, stream);
526}
527
528//------------------------------------------------------------------------------
532template <class METADATA>
533inline Resources::ResourceId
535 const IO::URN& res
536 , const METADATA& metaData
537 , const Util::StringAtom& tag
538 , std::function<void(const Resources::ResourceId)> success = nullptr
539 , std::function<void(const Resources::ResourceId)> failed = nullptr
540 , bool immediate = false
541 , bool stream = true
542)
543{
544 return ResourceServer::Instance()->CreateResource(res, metaData, tag, success, failed, immediate, stream);
545}
546
547//------------------------------------------------------------------------------
551inline void
553 const ResourceId& id
554 , std::function<void(const Resources::ResourceId)> success
555 , std::function<void(const Resources::ResourceId)> failed = nullptr
556)
557{
558 return ResourceServer::Instance()->CreateResourceListener(id, success, failed);
559}
560
561//------------------------------------------------------------------------------
564inline void
565SetMinLod(const ResourceId& id, float lod, bool immediate)
566{
567 return ResourceServer::Instance()->SetMinLod(id, lod, immediate);
568}
569
570//------------------------------------------------------------------------------
573inline void
574DiscardResource(const Resources::ResourceId id)
575{
576 ResourceServer::Instance()->DiscardResource(id);
577}
578
579//------------------------------------------------------------------------------
582inline void
584{
585 return ResourceServer::Instance()->ReloadResource(res);
586}
587
588//------------------------------------------------------------------------------
591inline void
593{
594 ResourceServer::Instance()->WaitForLoaderThread();
595}
596
597//------------------------------------------------------------------------------
600template <class POOL_TYPE>
601inline POOL_TYPE*
603{
604 static_assert(std::is_base_of<ResourceLoader, POOL_TYPE>::value, "Template argument is not a ResourceCache type!");
605 return ResourceServer::Instance()->GetStreamLoader<POOL_TYPE>();
606}
607
608} // namespace Resources
The common base class of Nebula.
Definition refcounted.h:38
Nebula's runtime type information for one class.
Definition rtti.h:27
An URI object can split a Uniform Resource Identifier string into its components or build a string fr...
Definition uri.h:67
A URN (Uniform Resource Name) is a URI (Uniform Resource Identifier) that uses the "urn" scheme.
Definition urn.h:24
const Util::String & GetNamespace() const
get Namespace component
Definition urn.h:288
Nebula's smart pointer class which manages the life time of RefCounted objects.
Definition ptr.h:38
State
Definition resource.h:26
void SetMinLod(const ResourceId &id, float lod, bool immediate)
stream in a new LOD
Definition resourceserver.h:329
__DeclareClass(ResourceServer)
void Close()
close manager
Definition resourceserver.cc:57
__DeclareInterfaceSingleton(ResourceServer)
bool HasStreamLoader(const Util::StringAtom &ext) const
query if a stream loader is registered for a given extension
Definition resourceserver.h:309
void CreateResourceListener(const ResourceId &id, std::function< void(const Resources::ResourceId)> success, std::function< void(const Resources::ResourceId)> failed=nullptr)
Create single-fire listener for resource. When resource is loaded, the callbacks will be invoked and ...
Definition resourceserver.h:346
void Open()
open manager
Definition resourceserver.cc:45
Resources::ResourceId CreateResource(const ResourceName &res, std::function< void(const Resources::ResourceId)> success=nullptr, std::function< void(const Resources::ResourceId)> failed=nullptr, bool immediate=false, bool stream=true)
create a new resource (stream-managed), which will be loaded at some later point, if not already load...
Definition resourceserver.h:125
ResourceServer()
constructor
Definition resourceserver.cc:26
Util::Dictionary< Util::StringAtom, IndexT > extensionMap
Definition resourceserver.h:111
Util::Dictionary< const Core::Rtti *, IndexT > typeMap
Definition resourceserver.h:113
const Resources::ResourceId GetId(const Resources::ResourceName &name) const
get id from name
Definition resourceserver.h:446
friend class ResourceLoader
Definition resourceserver.h:108
void DiscardResources(const Util::StringAtom &tag)
discard all resources by tag (stream-managed)
Definition resourceserver.cc:184
bool HasResource(const Resources::ResourceId id) const
check if resource id is valid
Definition resourceserver.h:432
void RegisterStreamLoader(const Util::StringAtom &ext, const Core::Rtti &loaderClass)
register a stream pool, which takes an extension and the RTTI of the resource type to create
Definition resourceserver.cc:101
void DiscardResource(const Resources::ResourceId res)
discard resource (stream-managed)
Definition resourceserver.h:367
void DeregisterStreamLoader(const Util::StringAtom &ext, const Core::Rtti &loaderClass)
deregisters a stream pool
Definition resourceserver.cc:118
virtual ~ResourceServer()
destructor
Definition resourceserver.cc:35
Core::Rtti * GetType(const Resources::ResourceId id)
get type of resource pool this resource was allocated with
Definition resourceserver.cc:218
Util::Dictionary< Util::StringAtom, IndexT > loaderMap
Definition resourceserver.h:112
void ReloadResource(const ResourceName &res, std::function< void(const Resources::ResourceId)> success=nullptr, std::function< void(const Resources::ResourceId)> failed=nullptr)
reload resource
Definition resourceserver.h:291
const Resources::ResourceName GetName(const Resources::ResourceId id) const
get resource name
Definition resourceserver.h:384
Util::Array< Ptr< ResourceLoader > > loaders
Definition resourceserver.h:114
const Resource::State GetState(const Resources::ResourceId id) const
get resource state
Definition resourceserver.h:408
static int32_t UniquePoolCounter
Definition resourceserver.h:116
const SizeT GetUsage(const Resources::ResourceId id) const
get usage
Definition resourceserver.h:420
bool HasPendingResources()
returns true if there are pending resources in-flight
Definition resourceserver.cc:198
const Util::StringAtom GetTag(const Resources::ResourceId id) const
get tag resource was first registered with
Definition resourceserver.h:396
void LoadDefaultResources()
goes through all pools and sets up their default resources
Definition resourceserver.cc:155
POOL_TYPE * GetStreamLoader() const
get stream pool for later use
Definition resourceserver.h:462
bool open
Definition resourceserver.h:110
void WaitForLoaderThread()
Wait for all loader threads.
Definition resourceserver.cc:233
Nebula's dynamic array class.
Definition array.h:61
A collection of key/value pairs with quick value retrieval by key at roughly O(log n).
Definition dictionary.h:35
A StringAtom.
Definition stringatom.h:22
const char * Value() const
get contained string as char ptr (fast)
Definition stringatom.h:362
String AsString() const
get containted string as string object (SLOW!!!)
Definition stringatom.h:372
Nebula's universal string class.
Definition string.h:50
const char * AsCharPtr() const
return contents as character pointer
Definition string.h:577
String GetFileExtension() const
get filename extension without dot
Definition string.cc:1003
void __cdecl n_error(const char *msg,...)
This function is called when a serious situation is encountered which requires abortion of the applic...
Definition debug.cc:138
#define n_assert_fmt(exp, msg,...)
Definition debug.h:61
#define n_warn_fmt(exp, msg,...)
Definition debug.h:64
#define n_assert(exp)
Definition debug.h:58
uint8_t Id8
Definition id.h:141
A resource is a container for some type of file which is loaded.
Definition resource.cc:9
Resources::ResourceId CreateResource(const ResourceName &res, const Util::StringAtom &tag, std::function< void(const Resources::ResourceId)> success=nullptr, std::function< void(const Resources::ResourceId)> failed=nullptr, bool immediate=false, bool stream=true)
TODO: Make templated with success and failed and use a custom allocator to capture the closure.
Definition resourceserver.h:480
POOL_TYPE * GetStreamLoader()
Definition resourceserver.h:602
void DiscardResource(const Resources::ResourceId id)
Definition resourceserver.h:574
@ Update
Definition resourceloader.h:54
void WaitForLoaderThread()
Definition resourceserver.h:592
void ReloadResource(const ResourceName &res)
Definition resourceserver.h:583
Util::StringAtom ResourceName
Definition resourceid.h:33
void SetMinLod(const ResourceId &id, float lod, bool immediate)
Definition resourceserver.h:565
void CreateResourceListener(const ResourceId &id, std::function< void(const Resources::ResourceId)> success, std::function< void(const Resources::ResourceId)> failed=nullptr)
TODO: Make templated with success and failed and use a custom allocator to capture the closure.
Definition resourceserver.h:552
id
Definition resourceid.h:37
static const int InvalidIndex
Definition types.h:47
int SizeT
Definition types.h:42
int IndexT
Definition types.h:41