1 #ifndef HEADER_RESOURCEPACK_H
2 #define HEADER_RESOURCEPACK_H
3 
4 #include "Log.h"
5 #include "Random.h"
6 #include "INamed.h"
7 #include "ResourceException.h"
8 
9 #include <string>
10 #include <vector>
11 #include <map>
12 
13 /**
14  * Share resources.
15  */
16 template <class T>
17 class ResourcePack : public INamed {
18     public:
19     typedef std::vector<T> t_range;
20     protected:
21     typedef std::multimap<std::string,T> t_reses;
22     typedef typename t_reses::iterator t_resIterator;
23     typedef typename t_reses::const_iterator t_constIterator;
24     t_reses m_reses;
25 
26     public:
27     /**
28      * Frees the given resource.
29      */
30     virtual void unloadRes(T res) = 0;
31 
32     //NOTE: we cannot call virtual functions from desctructor,
33     // call removeAll before delete
~ResourcePack()34     virtual ~ResourcePack()
35     {
36         if (!m_reses.empty()) {
37             LOG_WARNING(ExInfo("resources are not released")
38                 .addInfo("pack", toString()));
39         }
40     }
41     //-----------------------------------------------------------------
42     /**
43      * Free all resources.
44      * NOTE: we cannot call virtual functions from desctructor
45      */
removeAll()46     void removeAll()
47         {
48             t_resIterator end = m_reses.end();
49             for (t_resIterator item = m_reses.begin(); item != end; ++item) {
50                 unloadRes(item->second);
51             }
52             m_reses.clear();
53         }
54     //-----------------------------------------------------------------
55     /**
56      * Unload all resources with this name.
57      */
removeRes(const std::string & name)58     void removeRes(const std::string &name)
59         {
60             std::pair<t_resIterator, t_resIterator> range =
61                 m_reses.equal_range(name);
62             while (range.first != range.second) {
63                 unloadRes(range.first->second);
64                 ++(range.first);
65             }
66             m_reses.erase(name);
67             LOG_DEBUG(ExInfo("removed resources")
68                     .addInfo("name", name));
69         }
70 
71     //-----------------------------------------------------------------
72     /**
73      * Store resource under this name.
74      */
addRes(const std::string & name,T res)75     void addRes(const std::string &name, T res)
76     {
77         m_reses.insert(
78                 std::pair<std::string,T>(name, res));
79     }
80     //-----------------------------------------------------------------
81     /**
82      * Get resource with this name.
83      */
84     T getRes(const std::string &name, int rank=0)
85     {
86         std::pair<t_resIterator, t_resIterator> range =
87             m_reses.equal_range(name);
88         for (int i = 0; i < rank && range.first != range.second; ++i) {
89             ++(range.first);
90         }
91         if (range.second == range.first) {
92             throw ResourceException(ExInfo("no such resource at index")
93                     .addInfo("name", name)
94                     .addInfo("index", rank)
95                     .addInfo("pack", toString()));
96         }
97         return range.first->second;
98     }
99     //-----------------------------------------------------------------
100     /**
101      * Get all resources with this name.
102      * NOTE: range can be empty.
103      */
getRange(const std::string & name)104     t_range getRange(const std::string &name)
105     {
106         t_range result;
107         std::pair<t_resIterator, t_resIterator> range =
108             m_reses.equal_range(name);
109         while (range.first != range.second) {
110             result.push_back(range.first->second);
111             range.first++;
112         }
113 
114         return result;
115     }
116     //-----------------------------------------------------------------
117     /**
118      * Get resource at random index or return NULL.
119      */
getRandomRes(const std::string & name)120     T getRandomRes(const std::string &name)
121     {
122         T result = NULL;
123         typename t_reses::size_type count = m_reses.count(name);
124         if (count > 0) {
125             result = getRes(name, Random::randomInt(count));
126         }
127         else {
128             LOG_WARNING(ExInfo("no such resource")
129                     .addInfo("name", name)
130                     .addInfo("pack", toString()));
131         }
132         return result;
133     }
134     //-----------------------------------------------------------------
135     /**
136      * Count resources with this name.
137      */
countRes(const std::string & name)138     int countRes(const std::string &name)
139     {
140         return m_reses.count(name);
141     }
142     //-----------------------------------------------------------------
toString()143     std::string toString() const
144     {
145             ExInfo available_res = ExInfo("resources")
146                 .addInfo("name", getName());
147 
148             t_constIterator end = m_reses.end();
149             for (t_constIterator item = m_reses.begin(); item != end; ++item) {
150                 available_res.addInfo("key", item->first);
151             }
152             return available_res.info();
153     }
154 
155 };
156 
157 #endif
158 
159