summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/store.h
blob: 046b451aea704b2ee42a772baf2592de01dcf26d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
/**
 * @file
 * @brief Saveable hash-table and vector capable of storing
 *             multiple types of data.
**/

#ifndef STORE_H
#define STORE_H

#include <limits.h>
#include <map>
#include <string>
#include <vector>

class  reader;
class  writer;
class  CrawlHashTable;
class  CrawlVector;
struct item_def;
struct coord_def;
struct level_pos;
class  level_id;
class  dlua_chunk;
class monster;

#include "tags.h"

typedef uint16_t vec_size;
typedef uint8_t store_flags;

#define VEC_MAX_SIZE  0xFFFF

// NOTE: Changing the ordering of these enums will break savefile
// compatibility.
enum store_val_type
{
    SV_NONE = 0,
    SV_BOOL,
    SV_BYTE,
    SV_SHORT,
    SV_INT,
    SV_FLOAT,
    SV_STR,
    SV_COORD,
    SV_ITEM,
    SV_HASH,
    SV_VEC,
    SV_LEV_ID,
    SV_LEV_POS,
    SV_MONST,
    SV_LUA,
    SV_INT64,
    NUM_STORE_VAL_TYPES
};

enum store_flag_type
{
    SFLAG_UNSET      = (1 << 0),
    SFLAG_CONST_VAL  = (1 << 1),
    SFLAG_CONST_TYPE = (1 << 2),
    SFLAG_NO_ERASE   = (1 << 3),
};

typedef union StoreUnion StoreUnion;
union StoreUnion
{
    bool  boolean;
    char  byte;
    short _short;
    int   _int;
    float _float;
    int64_t _int64;
    void* ptr;
};

class CrawlStoreValue
{
public:
    CrawlStoreValue();
    CrawlStoreValue(const CrawlStoreValue &other);

    ~CrawlStoreValue();

    // Conversion constructors
    CrawlStoreValue(const bool val);
    CrawlStoreValue(const char &val);
    CrawlStoreValue(const short &val);
    CrawlStoreValue(const int &val);
    CrawlStoreValue(const int64_t &val);
    CrawlStoreValue(const float &val);
    CrawlStoreValue(const string &val);
    CrawlStoreValue(const char* val);
    CrawlStoreValue(const coord_def &val);
    CrawlStoreValue(const item_def &val);
    CrawlStoreValue(const CrawlHashTable &val);
    CrawlStoreValue(const CrawlVector &val);
    CrawlStoreValue(const level_id &val);
    CrawlStoreValue(const level_pos &val);
    CrawlStoreValue(const monster& val);
    CrawlStoreValue(const dlua_chunk &val);

    CrawlStoreValue &operator = (const CrawlStoreValue &other);

protected:
    // These first two fields need to match those in CrawlVector
    store_val_type type:8;
    store_flags    flags;

    StoreUnion     val;

public:
    store_flags    get_flags() const;
    store_flags    set_flags(store_flags flags);
    store_flags    unset_flags(store_flags flags);
    store_val_type get_type() const;

    CrawlHashTable &new_table();

    CrawlVector &new_vector(store_flags flags,
                            vec_size max_size = VEC_MAX_SIZE);
    CrawlVector &new_vector(store_val_type type, store_flags flags = 0,
                            vec_size max_size = VEC_MAX_SIZE);

    bool           &get_bool();
    char           &get_byte();
    short          &get_short();
    int            &get_int();
    int64_t        &get_int64();
    float          &get_float();
    string         &get_string();
    coord_def      &get_coord();
    CrawlHashTable &get_table();
    CrawlVector    &get_vector();
    item_def       &get_item();
    level_id       &get_level_id();
    level_pos      &get_level_pos();
    monster        &get_monster();
    dlua_chunk     &get_lua();

    bool           get_bool()      const;
    char           get_byte()      const;
    short          get_short()     const;
    int            get_int()       const;
    int64_t        get_int64()     const;
    float          get_float()     const;
    string         get_string()    const;
    coord_def      get_coord()     const;
    level_id       get_level_id()  const;
    level_pos      get_level_pos() const;

    const CrawlHashTable& get_table()  const;
    const CrawlVector&    get_vector() const;
    const item_def&       get_item()   const;
    const monster&        get_monster() const;
    const dlua_chunk&     get_lua() const;

public:
    // NOTE: All operators will assert if the value is of the wrong
    // type for the operation.  If the value has no type yet, the
    // operation will set it to the appropriate type.  If the value
    // has no type yet and the operation modifies the existing value
    // rather than replacing it (e.g., ++) the value will be set to a
    // default before the operation is done.

    // If the value is a hash table or vector, the container's values
    // can be accessed with the [] operator with the approriate key
    // type (strings for hashes, longs for vectors).
    CrawlStoreValue &operator [] (const string &key);
    CrawlStoreValue &operator [] (const char *key);
    CrawlStoreValue &operator [] (const vec_size &index);

    const CrawlStoreValue &operator [] (const string &key) const;
    const CrawlStoreValue &operator [] (const char *key) const;
    const CrawlStoreValue &operator [] (const vec_size &index) const;

    // Typecast operators
    operator bool&();
    operator char&();
    operator short&();
    operator int&();
    operator int64_t&();
    operator float&();
    operator string&();
    operator coord_def&();
    operator CrawlHashTable&();
    operator CrawlVector&();
    operator item_def&();
    operator level_id&();
    operator level_pos&();
    operator monster& ();
    operator dlua_chunk&();

    operator bool()        const;
    operator char()        const;
    operator short()       const;
    operator int()         const;
    operator int64_t()     const;
    operator float()       const;
    operator string()      const;
    operator coord_def()   const;
    operator level_id()    const;
    operator level_pos()   const;

    // Assignment operators
    CrawlStoreValue &operator = (const bool &val);
    CrawlStoreValue &operator = (const char &val);
    CrawlStoreValue &operator = (const short &val);
    CrawlStoreValue &operator = (const int &val);
    CrawlStoreValue &operator = (const int64_t &val);
    CrawlStoreValue &operator = (const float &val);
    CrawlStoreValue &operator = (const string &val);
    CrawlStoreValue &operator = (const char* val);
    CrawlStoreValue &operator = (const coord_def &val);
    CrawlStoreValue &operator = (const CrawlHashTable &val);
    CrawlStoreValue &operator = (const CrawlVector &val);
    CrawlStoreValue &operator = (const item_def &val);
    CrawlStoreValue &operator = (const level_id &val);
    CrawlStoreValue &operator = (const level_pos &val);
    CrawlStoreValue &operator = (const monster& val);
    CrawlStoreValue &operator = (const dlua_chunk &val);

    // Misc operators
    string &operator += (const string &val);

    // Prefix
    int operator ++ ();
    int operator -- ();

    // Postfix
    int operator ++ (int);
    int operator -- (int);

protected:
    CrawlStoreValue(const store_flags flags,
                    const store_val_type type = SV_NONE);

    void write(writer &) const;
    void read(reader &);

    void unset(bool force = false);

    friend class CrawlHashTable;
    friend class CrawlVector;
};

// By default a hash table's value data types are heterogeneous.  To
// make it homogeneous (which causes dynamic type checking) you have
// to give a type to the hash table constructor; once it's been
// created its type (or lack of type) is immutable.
class CrawlHashTable
{
public:
    CrawlHashTable();
    CrawlHashTable(const CrawlHashTable& other);

    ~CrawlHashTable();

    typedef map<string, CrawlStoreValue>  hash_map_type;
    typedef hash_map_type::iterator       iterator;
    typedef hash_map_type::const_iterator const_iterator;

protected:
    // NOTE: Not using auto_ptr because making hash_map an auto_ptr
    // causes compile weirdness in externs.h
    hash_map_type *hash_map;

    void init_hash_map();

    friend class CrawlStoreValue;

public:
    CrawlHashTable &operator = (const CrawlHashTable &other);

    void write(writer &) const;
    void read(reader &);

    bool exists(const string &key) const;
    void assert_validity() const;

    // NOTE: If the const versions of get_value() or [] are given a
    // key which doesn't exist, they will assert.
    const CrawlStoreValue& get_value(const string &key) const;
    const CrawlStoreValue& get_value(const char *key) const
    { return get_value(string(key)); }
    const CrawlStoreValue& operator[] (const string &key) const
    { return get_value(key); }
    const CrawlStoreValue& operator[] (const char *key) const
    { return get_value(string(key)); }

    // NOTE: If get_value() or [] is given a key which doesn't exist
    // in the table, an unset/empty CrawlStoreValue will be created
    // with that key and returned.  If it is not then given a value
    // then the next call to assert_validity() will fail.  If the
    // hash table has a type (rather than being heterogeneous)
    // then trying to assign a different type to the CrawlStoreValue
    // will assert.
    CrawlStoreValue& get_value(const string &key);
    CrawlStoreValue& get_value(const char *key)
    { return get_value(string(key)); }
    CrawlStoreValue& operator[] (const string &key)
    { return get_value(key); }
    CrawlStoreValue& operator[] (const char *key)
    { return get_value(string(key)); }

    // std::map style interface
    unsigned int size() const;
    bool      empty() const;

    void      erase(const string key);
    void      erase(const char *key) { erase(string(key)); }
    void      clear();

    const_iterator begin() const;
    const_iterator end() const;

    iterator  begin();
    iterator  end();
};

// A CrawlVector is the vector version of CrawlHashTable, except that
// a non-empty CrawlVector has one more byte of savefile overhead that
// a hash table, and that can specify a maximum size to make it act
// similarly to a FixedVec.
class CrawlVector
{
public:
    CrawlVector();
    CrawlVector(store_flags flags, vec_size max_size = VEC_MAX_SIZE);
    CrawlVector(store_val_type type, store_flags flags = 0,
                vec_size max_size = VEC_MAX_SIZE);

    ~CrawlVector();

    typedef vector<CrawlStoreValue>     vector_type;
    typedef vector_type::iterator       iterator;
    typedef vector_type::const_iterator const_iterator;

protected:
    // These first two fields need to match those in CrawlStoreValue
    store_val_type type:8;
    store_flags    default_flags;

    vec_size       max_size;
    vector_type    vec;

    friend class CrawlStoreValue;

public:
    void write(writer &) const;
    void read(reader &);

    store_flags    get_default_flags() const;
    store_flags    set_default_flags(store_flags flags);
    store_flags    unset_default_flags(store_flags flags);
    store_val_type get_type() const;
    void           assert_validity() const;
    void           set_max_size(vec_size size);
    vec_size       get_max_size() const;

    // NOTE: If the const versions of get_value() or [] are given an
    // index which doesn't exist, they will assert.
    const CrawlStoreValue& get_value(const vec_size &index) const;
    const CrawlStoreValue& operator[] (const vec_size &index) const
    { return get_value(index); }

    CrawlStoreValue& get_value(const vec_size &index);
    CrawlStoreValue& operator[] (const vec_size &index)
    { return get_value(index); }

    // std::vector style interface
    vec_size size() const;
    bool     empty() const;

    // NOTE: push_back() and insert() have val passed by value rather
    // than by reference so that conversion constructors will work.
    CrawlStoreValue& pop_back();
    void             push_back(CrawlStoreValue val);
    void insert(const vec_size index, CrawlStoreValue val);

    // resize() will assert if the maximum size has been set.
    void resize(const vec_size size);
    void erase(const vec_size index);
    void clear();

    const_iterator begin() const;
    const_iterator end() const;

    iterator begin();
    iterator end();
};

#ifdef DEBUG_PROPS
void dump_prop_accesses();
#endif

// inlines... it sucks so badly to have to pander to ancient compilers with
// no -flto
inline CrawlStoreValue &CrawlStoreValue::operator [] (const string &key)
{
    return get_table().get_value(key);
}

inline CrawlStoreValue &CrawlStoreValue::operator [] (const char* key)
{
    return get_table().get_value(key);
}

inline CrawlStoreValue &CrawlStoreValue::operator [] (const vec_size &index)
{
    return get_vector()[index];
}

inline const CrawlStoreValue &CrawlStoreValue::operator [] (const string &key) const
{
    return get_table().get_value(key);
}

inline const CrawlStoreValue &CrawlStoreValue::operator [] (const char* key) const
{
    return get_table().get_value(key);
}

inline const CrawlStoreValue &CrawlStoreValue::operator [](const vec_size &index) const
{
    return get_vector().get_value(index);
}

#endif