1 /**
2  * @file
3  * @brief Saveable hash-table and vector capable of storing
4  *             multiple types of data.
5 **/
6 
7 #pragma once
8 
9 #include <climits>
10 #include <map>
11 #include <string>
12 #include <vector>
13 
14 class  reader;
15 class  writer;
16 class  CrawlHashTable;
17 class  CrawlVector;
18 struct item_def;
19 struct coord_def;
20 struct level_pos;
21 class  level_id;
22 class  dlua_chunk;
23 class monster;
24 
25 #include "tags.h"
26 
27 typedef uint16_t vec_size;
28 typedef uint8_t store_flags;
29 
30 #define VEC_MAX_SIZE  0xFFFF
31 
32 // NOTE: Changing the ordering of these enums will break savefile
33 // compatibility.
34 enum store_val_type
35 {
36     SV_NONE = 0,
37     SV_BOOL,
38     SV_BYTE,
39     SV_SHORT,
40     SV_INT,
41     SV_FLOAT,
42     SV_STR,
43     SV_COORD,
44     SV_ITEM,
45     SV_HASH,
46     SV_VEC,
47     SV_LEV_ID,
48     SV_LEV_POS,
49     SV_MONST,
50     SV_LUA,
51     SV_INT64,
52     NUM_STORE_VAL_TYPES,
53     SV_STR_LONG, // this is a save-only type
54 };
55 
56 enum store_flag_type
57 {
58     SFLAG_UNSET      = (1 << 0),
59     SFLAG_CONST_VAL  = (1 << 1),
60     SFLAG_CONST_TYPE = (1 << 2),
61     SFLAG_NO_ERASE   = (1 << 3),
62 };
63 
64 typedef union StoreUnion StoreUnion;
65 union StoreUnion
66 {
67     bool  boolean;
68     char  byte;
69     short _short;
70     int   _int;
71     float _float;
72     int64_t _int64;
73     void* ptr;
74 };
75 
76 class CrawlStoreValue
77 {
78 public:
79     CrawlStoreValue();
80     CrawlStoreValue(const CrawlStoreValue &other);
81 
82     ~CrawlStoreValue();
83 
84     // Conversion constructors
85     CrawlStoreValue(const bool val);
86     CrawlStoreValue(const char &val);
87     CrawlStoreValue(const short &val);
88     CrawlStoreValue(const int &val);
89     CrawlStoreValue(const int64_t &val);
90     CrawlStoreValue(const float &val);
91     CrawlStoreValue(const string &val);
92     CrawlStoreValue(const char* val);
93     CrawlStoreValue(const coord_def &val);
94     CrawlStoreValue(const item_def &val);
95     CrawlStoreValue(const CrawlHashTable &val);
96     CrawlStoreValue(const CrawlVector &val);
97     CrawlStoreValue(const level_id &val);
98     CrawlStoreValue(const level_pos &val);
99     CrawlStoreValue(const monster& val);
100     CrawlStoreValue(const dlua_chunk &val);
101 
102     CrawlStoreValue &operator = (const CrawlStoreValue &other);
103 
104 protected:
105     // These first two fields need to match those in CrawlVector
106     store_val_type type:8;
107     store_flags    flags;
108 
109     StoreUnion     val;
110 
111 public:
112     store_flags    get_flags() const;
113     store_flags    set_flags(store_flags flags);
114     store_flags    unset_flags(store_flags flags);
115     store_val_type get_type() const;
116 
117     CrawlHashTable &new_table();
118 
119     CrawlVector &new_vector(store_flags flags);
120     CrawlVector &new_vector(store_val_type type, store_flags flags = 0);
121 
122     bool           &get_bool();
123     char           &get_byte();
124     short          &get_short();
125     int            &get_int();
126     int64_t        &get_int64();
127     float          &get_float();
128     string         &get_string();
129     coord_def      &get_coord();
130     CrawlHashTable &get_table();
131     CrawlVector    &get_vector();
132     item_def       &get_item();
133     level_id       &get_level_id();
134     level_pos      &get_level_pos();
135     monster        &get_monster();
136     dlua_chunk     &get_lua();
137 
138     bool           get_bool()      const;
139     char           get_byte()      const;
140     short          get_short()     const;
141     int            get_int()       const;
142     int64_t        get_int64()     const;
143     float          get_float()     const;
144     string         get_string()    const;
145     coord_def      get_coord()     const;
146     level_id       get_level_id()  const;
147     level_pos      get_level_pos() const;
148 
149     const CrawlHashTable& get_table()  const;
150     const CrawlVector&    get_vector() const;
151     const item_def&       get_item()   const;
152     const monster&        get_monster() const;
153     const dlua_chunk&     get_lua() const;
154 
155 public:
156     // NOTE: All operators will assert if the value is of the wrong
157     // type for the operation. If the value has no type yet, the
158     // operation will set it to the appropriate type. If the value
159     // has no type yet and the operation modifies the existing value
160     // rather than replacing it (e.g., ++) the value will be set to a
161     // default before the operation is done.
162 
163     // If the value is a hash table or vector, the container's values
164     // can be accessed with the [] operator with the approriate key
165     // type (strings for hashes, longs for vectors).
166     CrawlStoreValue &operator [] (const string &key);
167     CrawlStoreValue &operator [] (const char *key);
168     CrawlStoreValue &operator [] (const vec_size &index);
169 
170     const CrawlStoreValue &operator [] (const string &key) const;
171     const CrawlStoreValue &operator [] (const char *key) const;
172     const CrawlStoreValue &operator [] (const vec_size &index) const;
173 
174     // Typecast operators
175     operator bool&();
176     operator char&();
177     operator short&();
178     operator int&();
179     operator int64_t&();
180     operator float&();
181     operator string&();
182     operator coord_def&();
183     operator CrawlHashTable&();
184     operator CrawlVector&();
185     operator item_def&();
186     operator level_id&();
187     operator level_pos&();
188     operator monster& ();
189     operator dlua_chunk&();
190 
191     operator bool()        const;
192     operator char()        const;
193     operator short()       const;
194     operator int()         const;
195     operator int64_t()     const;
196     operator float()       const;
197     operator string()      const;
198     operator coord_def()   const;
199     operator level_id()    const;
200     operator level_pos()   const;
201 
202     // Assignment operators
203     CrawlStoreValue &operator = (const bool &val);
204     CrawlStoreValue &operator = (const char &val);
205     CrawlStoreValue &operator = (const short &val);
206     CrawlStoreValue &operator = (const int &val);
207     CrawlStoreValue &operator = (const int64_t &val);
208     CrawlStoreValue &operator = (const float &val);
209     CrawlStoreValue &operator = (const string &val);
210     CrawlStoreValue &operator = (const char* val);
211     CrawlStoreValue &operator = (const coord_def &val);
212     CrawlStoreValue &operator = (const CrawlHashTable &val);
213     CrawlStoreValue &operator = (const CrawlVector &val);
214     CrawlStoreValue &operator = (const item_def &val);
215     CrawlStoreValue &operator = (const level_id &val);
216     CrawlStoreValue &operator = (const level_pos &val);
217     CrawlStoreValue &operator = (const monster& val);
218     CrawlStoreValue &operator = (const dlua_chunk &val);
219 
220     // Misc operators
221     string &operator += (const string &val);
222 
223     // Prefix
224     int operator ++ ();
225     int operator -- ();
226 
227     // Postfix
228     int operator ++ (int);
229     int operator -- (int);
230 
231 protected:
232     CrawlStoreValue(const store_flags flags,
233                     const store_val_type type = SV_NONE);
234 
235     void write(writer &) const;
236     void read(reader &);
237 
238     void unset(bool force = false);
239 
240     friend class CrawlHashTable;
241     friend class CrawlVector;
242 };
243 
244 class CrawlHashTable : public map<string, CrawlStoreValue>
245 {
246 public:
247     friend class CrawlStoreValue;
248 
249     void write(writer &) const;
250     void read(reader &);
251 
252     bool exists(const string &key) const;
253 
254     void assert_validity() const;
255 
256     // NOTE: If the const versions of get_value() or [] are given a
257     // key which doesn't exist, they will assert.
258     const CrawlStoreValue& get_value(const string &key) const;
get_value(const char * key)259     const CrawlStoreValue& get_value(const char *key) const
260     { return get_value(string(key)); }
261     const CrawlStoreValue& operator[] (const string &key) const
262     { return get_value(key); }
263     const CrawlStoreValue& operator[] (const char *key) const
264     { return get_value(string(key)); }
265 
266     // NOTE: If get_value() or [] is given a key which doesn't exist
267     // in the table, an unset/empty CrawlStoreValue will be created
268     // with that key and returned. If it is not then given a value
269     // then the next call to assert_validity() will fail. If the
270     // hash table has a type (rather than being heterogeneous)
271     // then trying to assign a different type to the CrawlStoreValue
272     // will assert.
273     CrawlStoreValue& get_value(const string &key);
get_value(const char * key)274     CrawlStoreValue& get_value(const char *key)
275     { return get_value(string(key)); }
276     using map::operator[];
277     CrawlStoreValue& operator[] (const char *key)
278     { return get_value(string(key)); }
279 };
280 
281 // A CrawlVector is the vector version of CrawlHashTable, except that
282 // a non-empty CrawlVector has one more byte of savefile overhead that
283 // a hash table, and that can specify a maximum size to make it act
284 // similarly to a FixedVec.
285 class CrawlVector
286 {
287 public:
288     CrawlVector();
289     CrawlVector(store_flags flags, vec_size max_size = VEC_MAX_SIZE);
290     CrawlVector(store_val_type type, store_flags flags = 0,
291                 vec_size max_size = VEC_MAX_SIZE);
292 
293     ~CrawlVector();
294 
295     typedef vector<CrawlStoreValue>     vector_type;
296     typedef vector_type::iterator       iterator;
297     typedef vector_type::const_iterator const_iterator;
298 
299 protected:
300     // These first two fields need to match those in CrawlStoreValue
301     store_val_type type:8;
302     store_flags    default_flags;
303 
304     vec_size       max_size;
305     vector_type    vec;
306 
307     friend class CrawlStoreValue;
308 
309 public:
310     void write(writer &) const;
311     void read(reader &);
312 
313     store_flags    get_default_flags() const;
314     store_flags    set_default_flags(store_flags flags);
315     store_flags    unset_default_flags(store_flags flags);
316     store_val_type get_type() const;
317     void           assert_validity() const;
318     void           set_max_size(vec_size size);
319     vec_size       get_max_size() const;
320 
321     // NOTE: If the const versions of get_value() or [] are given an
322     // index which doesn't exist, they will assert.
323     const CrawlStoreValue& get_value(const vec_size &index) const;
324     const CrawlStoreValue& operator[] (const vec_size &index) const
325     { return get_value(index); }
326 
327     CrawlStoreValue& get_value(const vec_size &index);
328     CrawlStoreValue& operator[] (const vec_size &index)
329     { return get_value(index); }
330 
331     // std::vector style interface
332     vec_size size() const;
333     bool     empty() const;
334 
335     // NOTE: push_back() and insert() have val passed by value rather
336     // than by reference so that conversion constructors will work.
337     void             pop_back();
338     void             push_back(CrawlStoreValue val);
339     void insert(const vec_size index, CrawlStoreValue val);
340 
341     // resize() will assert if the maximum size has been set.
342     void resize(const vec_size size);
343     void erase(const vec_size index);
344     void clear();
345 
346     const_iterator begin() const;
347     const_iterator end() const;
348 
349     iterator begin();
350     iterator end();
351 };
352 
353 #ifdef DEBUG_PROPS
354 void dump_prop_accesses();
355 #endif
356 
357 // inlines... it sucks so badly to have to pander to ancient compilers with
358 // no -flto
359 inline CrawlStoreValue &CrawlStoreValue::operator [] (const string &key)
360 {
361     return get_table().get_value(key);
362 }
363 
364 inline CrawlStoreValue &CrawlStoreValue::operator [] (const char* key)
365 {
366     return get_table().get_value(key);
367 }
368 
369 inline CrawlStoreValue &CrawlStoreValue::operator [] (const vec_size &index)
370 {
371     return get_vector()[index];
372 }
373 
374 inline const CrawlStoreValue &CrawlStoreValue::operator [] (const string &key) const
375 {
376     return get_table().get_value(key);
377 }
378 
379 inline const CrawlStoreValue &CrawlStoreValue::operator [] (const char* key) const
380 {
381     return get_table().get_value(key);
382 }
383 
384 inline const CrawlStoreValue &CrawlStoreValue::operator [](const vec_size &index) const
385 {
386     return get_vector().get_value(index);
387 }
388