for making a hash table imitate a vector. Since there's now more than just one type of savable/restorable container, hash.cc and hash.h have been renamed to store.cc and store.h ("store" for storage).
Destroying/unlinking/deleting an item now clears out the item's props field.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2389 c06c8d41-db1a-0410-9941-cceddc491573
K2GMFKXUWN5R3KCW6OYVXHN47MIQZKEEIOSAU6LFFKBNKF6JBVWAC
EFWEYIB2R3DPD3JWIPU6LS6SFLPMYN7J7X4GBZR7DJWKHJ3UELSAC
EGV2HM7SD7UQSWJGLR65NQJTUBAJ7WHLM67FMH4UFP7JRSFKREPAC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
7AMQN7MITMXBNVDAK5VOXTQ4TZIAOD6ZLOFJG7GQMBTY23Y2BKSAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
5BJPWUPLJFS34FUTFJVKA4A52YMIGV6EWDXLNSDCWBJWBGVSQFGQC
JPYDWBRN75GC6UZ26MXJTCXGORTJOWGRDEU4JFPU52LYHGK6UI2QC
HZ6SBPPUHJUYFVXA6KOELY455RTBXICRJGVHTUYLHWAPV2DEOMSQC
/*
* File: hash.h
* Summary: Saveable hash-table capable of storing multiple types
* of data.
* Written by: Matthew Cline
*
* Modified for Crawl Reference by $Author$ on $Date$
*
* Change History (most recent first):
*
* <1> 10/5/07 MPC Created
*/
#ifndef HASH_H
#define HASH_H
#include <string>
#include <map>
struct tagHeader;
class CrawlHashTable;
class item_def;
class coord_def;
// NOTE: Changing the ordering of these enums will break savefile
// compatibility.
enum hash_val_type
{
HV_NONE = 0,
HV_BOOL,
HV_BYTE,
HV_SHORT,
HV_LONG,
HV_FLOAT,
HV_STR,
HV_COORD,
HV_HASH,
HV_ITEM,
NUM_HASH_VAL_TYPES
};
enum hash_flag_type
{
HFLAG_UNSET = (1 << 0),
HFLAG_CONST_VAL = (1 << 1),
HFLAG_CONST_TYPE = (1 << 2),
HFLAG_NO_ERASE = (1 << 3)
};
// Can't just cast everything into a void pointer, since a float might
// not fit into a pointer on all systems.
typedef union HashUnion HashUnion;
union HashUnion
{
bool boolean;
char byte;
short _short;
long _long;
float _float;
void* ptr;
};
class CrawlHashValue
{
public:
CrawlHashValue();
CrawlHashValue(const CrawlHashValue &other);
~CrawlHashValue();
// Only needed for doing some assertion checking.
CrawlHashValue &operator = (const CrawlHashValue &other);
protected:
hash_val_type type;
unsigned char flags;
HashUnion val;
public:
unsigned char get_flags() const;
unsigned char set_flags(unsigned char flags);
unsigned char unset_flags(unsigned char flags);
hash_val_type get_type() const;
CrawlHashTable &new_table(unsigned char flags);
CrawlHashTable &new_table(hash_val_type type, unsigned char flags = 0);
bool &get_bool();
char &get_byte();
short &get_short();
long &get_long();
float &get_float();
std::string &get_string();
coord_def &get_coord();
CrawlHashTable &get_table();
item_def &get_item();
bool get_bool() const;
char get_byte() const;
short get_short() const;
long get_long() const;
float get_float() const;
std::string get_string() const;
coord_def get_coord() const;
const CrawlHashTable& get_table() const;
const item_def& get_item() const;
void set_bool(const bool val);
void set_byte(const char val);
void set_short(const short val);
void set_long(const long val);
void set_float(const float val);
void set_string(const std::string &val);
void set_coord(const coord_def &val);
void set_table(const CrawlHashTable &val);
void set_item(const item_def &val);
public:
// NOTE: All operators will assert if the hash 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 (i.e., ++) the value will be set
// to a default before the operation is done.
// If the hash value is a hash table, the table's values can be
// accessed with the [] operator.
CrawlHashValue &operator [] (const std::string &key);
CrawlHashValue &operator [] (const long &key);
const CrawlHashValue &operator [] (const std::string &key) const;
const CrawlHashValue &operator [] (const long &key) const;
// Typecast operators
&operator bool();
&operator char();
&operator short();
&operator long();
&operator float();
&operator std::string();
&operator coord_def();
&operator CrawlHashTable();
&operator item_def();
operator bool() const;
operator char() const;
operator short() const;
operator long() const;
operator float() const;
operator std::string() const;
operator coord_def() const;
// Assignment operators
bool &operator = (const bool &val);
char &operator = (const char &val);
short &operator = (const short &val);
long &operator = (const long &val);
float &operator = (const float &val);
std::string &operator = (const std::string &val);
const char* operator = (const char* val);
coord_def &operator = (const coord_def &val);
CrawlHashTable &operator = (const CrawlHashTable &val);
item_def &operator = (const item_def &val);
// Misc operators
std::string &operator += (const std::string &val);
// Prefix
long operator ++ ();
long operator -- ();
// Postfix
long operator ++ (int);
long operator -- (int);
protected:
CrawlHashValue(const unsigned char flags,
const hash_val_type type = HV_NONE);
void write(tagHeader &th) const;
void read(tagHeader &th);
void unset(bool force = false);
friend class CrawlHashTable;
};
// A hash table can have a maximum of 255 key/value pairs. If you
// want more than that you can use nested hash tables.
//
// 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 it's type (or lack of type) is immutable.
//
// An empty hash table will take up only 1 byte in the savefile. A
// non-empty hash table will have an overhead of 3 bytes for the hash
// table overall and 2 bytes per key/value pair, over and above the
// number of bytes needed to store the keys and values themselves.
class CrawlHashTable
{
public:
CrawlHashTable();
CrawlHashTable(unsigned char flags);
CrawlHashTable(hash_val_type type, unsigned char flags = 0);
~CrawlHashTable();
typedef std::map<std::string, CrawlHashValue> hash_map_type;
protected:
hash_val_type type;
unsigned char default_flags;
hash_map_type hash_map;
friend class CrawlHashValue;
public:
void write(tagHeader &th) const;
void read(tagHeader &th);
unsigned char get_default_flags() const;
unsigned char set_default_flags(unsigned char flags);
unsigned char unset_default_flags(unsigned char flags);
hash_val_type get_type() const;
bool exists(const std::string key) const;
bool exists(const long key) const;
void assert_validity() const;
int compact_indicies(long min_index, long max_index,
bool compact_down = true);
bool fixup_indexed_array(std::string name = "");
// NOTE: If get_value() or [] is given a key which doesn't exist
// in the table, an unset/empty CrawlHashValue 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 CrawlHashValue
// will assert.
CrawlHashValue& get_value(const std::string &key);
CrawlHashValue& get_value(const long &index);
CrawlHashValue& operator[] (const std::string &key);
CrawlHashValue& operator[] (const long &index);
// NOTE: If the const versions of get_value() or [] are given a
// key which doesn't exist, they will assert.
const CrawlHashValue& get_value(const std::string &key) const;
const CrawlHashValue& get_value(const long &index) const;
const CrawlHashValue& operator[] (const std::string &key) const;
const CrawlHashValue& operator[] (const long &index) const;
// std::map style interface
size_t size() const;
bool empty() const;
void erase(const std::string key);
void erase(const long index);
void clear();
hash_map_type::iterator begin();
hash_map_type::iterator end();
hash_map_type::const_iterator begin() const;
hash_map_type::const_iterator end() const;
};
// A wrapper for non-heterogeneous hash tables, so that the values can
// be accessed without using get_foo(). T needs to have both normal
// and const type-cast operators defined by CrawlHashValue for this
// template to work.
template <typename T, hash_val_type TYPE>
class CrawlTableWrapper
{
public:
CrawlTableWrapper();
CrawlTableWrapper(CrawlHashTable& table);
CrawlTableWrapper(CrawlHashTable* table);
protected:
CrawlHashTable* table;
public:
void wrap(CrawlHashTable& table);
void wrap(CrawlHashTable* table);
CrawlHashTable* get_table();
T& operator[] (const std::string &key);
T& operator[] (const long &index);
const CrawlHashTable* get_table() const;
const T operator[] (const std::string &key) const;
const T operator[] (const long &index) const;
};
typedef CrawlTableWrapper<bool, HV_BOOL> CrawlBoolTable;
typedef CrawlTableWrapper<char, HV_BYTE> CrawlByteTable;
typedef CrawlTableWrapper<short, HV_SHORT> CrawlShortTable;
typedef CrawlTableWrapper<long, HV_LONG> CrawlLongTable;
typedef CrawlTableWrapper<float, HV_FLOAT> CrawlFloatTable;
typedef CrawlTableWrapper<std::string, HV_STR> CrawlStringTable;
typedef CrawlTableWrapper<coord_def, HV_COORD> CrawlCoordTable;
#endif
/*
* File: hash.cc
* Summary: Saveable hash-table capable of storing multiple types
* of data.
* Written by: Matthew Cline
*
* Modified for Crawl Reference by $Author$ on $Date$
*
* Change History (most recent first):
* <1> 10/5/07 MPC Created
*/
#include "AppHdr.h"
#include "hash.h"
#include "externs.h"
#include "tags.h"
CrawlHashValue::CrawlHashValue()
: type(HV_NONE), flags(HFLAG_UNSET)
{
val.ptr = NULL;
}
CrawlHashValue::CrawlHashValue(const CrawlHashValue &other)
{
ASSERT(other.type >= HV_NONE && other.type < NUM_HASH_VAL_TYPES);
type = other.type;
flags = other.flags;
if (flags & HFLAG_UNSET)
{
val = other.val;
return;
}
switch (type)
{
case HV_NONE:
case HV_BOOL:
case HV_BYTE:
case HV_SHORT:
case HV_LONG:
case HV_FLOAT:
val = other.val;
break;
case HV_STR:
{
std::string* str;
str = new std::string(*static_cast<std::string*>(other.val.ptr));
val.ptr = static_cast<void*>(str);
break;
}
case HV_COORD:
{
coord_def* coord;
coord = new coord_def(*static_cast<coord_def*>(other.val.ptr));
val.ptr = static_cast<void*>(coord);
break;
}
case HV_HASH:
{
CrawlHashTable* hash;
CrawlHashTable* tmp = static_cast<CrawlHashTable*>(other.val.ptr);
hash = new CrawlHashTable(*tmp);
val.ptr = static_cast<void*>(hash);
break;
}
case HV_ITEM:
{
item_def* item;
item = new item_def(*static_cast<item_def*>(other.val.ptr));
val.ptr = static_cast<void*>(item);
break;
}
case NUM_HASH_VAL_TYPES:
ASSERT(false);
}
}
CrawlHashValue::CrawlHashValue(const unsigned char _flags,
const hash_val_type _type)
: type(_type), flags(_flags)
{
ASSERT(type >= HV_NONE && type < NUM_HASH_VAL_TYPES);
ASSERT(!(flags & HFLAG_UNSET));
flags |= HFLAG_UNSET;
val.ptr = NULL;
}
CrawlHashValue::~CrawlHashValue()
{
unset(true);
}
void CrawlHashValue::unset(bool force)
{
if (flags & HFLAG_UNSET)
return;
if (force)
flags &= ~HFLAG_NO_ERASE;
ASSERT(!(flags & HFLAG_NO_ERASE));
switch (type)
{
case HV_BOOL:
val.boolean = false;
break;
case HV_BYTE:
val.byte = 0;
break;
case HV_SHORT:
val._short = 0;
break;
case HV_LONG:
val._long = 0;
break;
case HV_FLOAT:
val._float = 0.0;
break;
case HV_STR:
{
std::string* str = static_cast<std::string*>(val.ptr);
delete str;
val.ptr = NULL;
break;
}
case HV_COORD:
{
coord_def* coord = static_cast<coord_def*>(val.ptr);
delete coord;
val.ptr = NULL;
break;
}
case HV_HASH:
{
CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
delete hash;
val.ptr = NULL;
break;
}
case HV_ITEM:
{
item_def* item = static_cast<item_def*>(val.ptr);
delete item;
val.ptr = NULL;
break;
}
case HV_NONE:
ASSERT(false);
case NUM_HASH_VAL_TYPES:
ASSERT(false);
}
flags |= HFLAG_UNSET;
}
// Only needed to do some assertion checking.
CrawlHashValue &CrawlHashValue::operator = (const CrawlHashValue &other)
{
ASSERT(other.type >= HV_NONE && other.type < NUM_HASH_VAL_TYPES);
ASSERT(other.type != HV_NONE || type == HV_NONE);
// NOTE: We don't bother checking HFLAG_CONST_VAL, since the
// asignment operator is used when swapping two elements.
if (!(flags & HFLAG_UNSET))
{
if (flags & HFLAG_CONST_TYPE)
ASSERT(type == HV_NONE || type == other.type);
}
type = other.type;
flags = other.flags;
val = other.val;
return (*this);
}
///////////////////////////////////
// Meta-data accessors and changers
unsigned char CrawlHashValue::get_flags() const
{
return flags;
}
unsigned char CrawlHashValue::set_flags(unsigned char _flags)
{
flags |= _flags;
return flags;
}
unsigned char CrawlHashValue::unset_flags(unsigned char _flags)
{
flags &= ~_flags;
return flags;
}
hash_val_type CrawlHashValue::get_type() const
{
return type;
}
//////////////////////////////
// Read/write from/to savefile
void CrawlHashValue::write(tagHeader &th) const
{
ASSERT(!(flags & HFLAG_UNSET));
marshallByte(th, (char) type);
marshallByte(th, (char) flags);
switch (type)
{
case HV_BOOL:
marshallBoolean(th, val.boolean);
break;
case HV_BYTE:
marshallByte(th, val.byte);
break;
case HV_SHORT:
marshallShort(th, val._short);
break;
case HV_LONG:
marshallLong(th, val._long);
break;
case HV_FLOAT:
marshallFloat(th, val._float);
break;
case HV_STR:
{
std::string* str = static_cast<std::string*>(val.ptr);
marshallString(th, *str);
break;
}
case HV_COORD:
{
coord_def* coord = static_cast<coord_def*>(val.ptr);
marshallCoord(th, *coord);
break;
}
case HV_HASH:
{
CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
hash->write(th);
break;
}
case HV_ITEM:
{
item_def* item = static_cast<item_def*>(val.ptr);
marshallItem(th, *item);
break;
}
case HV_NONE:
ASSERT(false);
case NUM_HASH_VAL_TYPES:
ASSERT(false);
}
}
void CrawlHashValue::read(tagHeader &th)
{
type = static_cast<hash_val_type>(unmarshallByte(th));
flags = (unsigned char) unmarshallByte(th);
ASSERT(!(flags & HFLAG_UNSET));
switch (type)
{
case HV_BOOL:
val.boolean = unmarshallBoolean(th);
break;
case HV_BYTE:
val.byte = unmarshallByte(th);
break;
case HV_SHORT:
val._short = unmarshallShort(th);
break;
case HV_LONG:
val._long = unmarshallLong(th);
break;
case HV_FLOAT:
val._float = unmarshallFloat(th);
break;
case HV_STR:
{
std::string str = unmarshallString(th);
val.ptr = (void*) new std::string(str);
break;
}
case HV_COORD:
{
coord_def coord;
unmarshallCoord(th, coord);
val.ptr = (void*) new coord_def(coord);
break;
}
case HV_HASH:
{
CrawlHashTable* hash = new CrawlHashTable();
hash->read(th);
val.ptr = (void*) hash;
break;
}
case HV_ITEM:
{
item_def item;
unmarshallItem(th, item);
val.ptr = (void*) new item_def(item);
break;
}
case HV_NONE:
ASSERT(false);
case NUM_HASH_VAL_TYPES:
ASSERT(false);
}
}
////////////////////////////////////////////////////////////////
// Setup a new table with the given flags and/or type; assert if
// a table already exists.
CrawlHashTable &CrawlHashValue::new_table(unsigned char _flags)
{
return new_table(HV_NONE, flags);
}
CrawlHashTable &CrawlHashValue::new_table(hash_val_type _type,
unsigned char _flags)
{
CrawlHashTable* old_table = static_cast<CrawlHashTable*>(val.ptr);
ASSERT(flags & HFLAG_UNSET);
ASSERT(type == HV_NONE
|| (type == HV_HASH
&& old_table->size() == 0
&& old_table->get_type() == HV_NONE
&& old_table->get_default_flags() == 0));
CrawlHashTable &table = get_table();
table.default_flags = _flags;
table.type = _type;
type = HV_HASH;
flags &= ~HFLAG_UNSET;
return table;
}
///////////////////////////////////////////
// Dynamic type-checking accessor functions
#define GET_VAL(x, _type, field, value) \
ASSERT((flags & HFLAG_UNSET) || !(flags & HFLAG_CONST_VAL)); \
if (type != (x)) \
{ \
if (type == HV_NONE) \
{ \
type = (x); \
field = (value); \
} \
else \
{ \
ASSERT(!(flags & HFLAG_CONST_TYPE)); \
switch(type) \
{ \
case HV_BOOL: \
field = (_type) val.boolean; \
break; \
case HV_BYTE: \
field = (_type) val.byte; \
break; \
case HV_SHORT: \
field = (_type) val._short; \
break; \
case HV_LONG: \
field = (_type) val._long; \
break; \
case HV_FLOAT: \
field = (_type) val._float; \
break; \
default: \
ASSERT(false); \
} \
type = (x); \
} \
} \
flags &= ~HFLAG_UNSET; \
return field;
#define GET_VAL_PTR(x, _type, value) \
ASSERT((flags & HFLAG_UNSET) || !(flags & HFLAG_CONST_VAL)); \
if (type != (x)) \
{ \
if (type == HV_NONE) \
{ \
type = (x); \
val.ptr = (value); \
} \
else \
{ \
unset(); \
val.ptr = (value); \
type = (x); \
} \
} \
flags &= ~HFLAG_UNSET; \
return *((_type) val.ptr);
bool &CrawlHashValue::get_bool()
{
GET_VAL(HV_BOOL, bool, val.boolean, false);
}
char &CrawlHashValue::get_byte()
{
GET_VAL(HV_BYTE, char, val.byte, 0);
}
short &CrawlHashValue::get_short()
{
GET_VAL(HV_SHORT, short, val._short, 0);
}
long &CrawlHashValue::get_long()
{
GET_VAL(HV_LONG, long, val._long, 0);
}
float &CrawlHashValue::get_float()
{
GET_VAL(HV_FLOAT, float, val._float, 0.0);
}
std::string &CrawlHashValue::get_string()
{
GET_VAL_PTR(HV_STR, std::string*, new std::string(""));
}
coord_def &CrawlHashValue::get_coord()
{
GET_VAL_PTR(HV_COORD, coord_def*, new coord_def());
}
CrawlHashTable &CrawlHashValue::get_table()
{
GET_VAL_PTR(HV_HASH, CrawlHashTable*, new CrawlHashTable());
}
item_def &CrawlHashValue::get_item()
{
GET_VAL_PTR(HV_ITEM, item_def*, new item_def());
}
///////////////////////////
// Const accessor functions
#define GET_CONST_SETUP(x) \
ASSERT(!(flags & HFLAG_UNSET)); \
ASSERT(type == (x));
bool CrawlHashValue::get_bool() const
{
GET_CONST_SETUP(HV_BOOL);
return val.boolean;
}
char CrawlHashValue::get_byte() const
{
GET_CONST_SETUP(HV_BYTE);
return val.byte;
}
short CrawlHashValue::get_short() const
{
GET_CONST_SETUP(HV_SHORT);
return val._short;
}
long CrawlHashValue::get_long() const
{
GET_CONST_SETUP(HV_LONG);
return val._long;
}
float CrawlHashValue::get_float() const
{
GET_CONST_SETUP(HV_FLOAT);
return val._float;
}
std::string CrawlHashValue::get_string() const
{
GET_CONST_SETUP(HV_STR);
return *((std::string*)val.ptr);
}
coord_def CrawlHashValue::get_coord() const
{
GET_CONST_SETUP(HV_COORD);
return *((coord_def*)val.ptr);
}
const CrawlHashTable& CrawlHashValue::get_table() const
{
GET_CONST_SETUP(HV_HASH);
return *((CrawlHashTable*)val.ptr);
}
const item_def& CrawlHashValue::get_item() const
{
GET_CONST_SETUP(HV_ITEM);
return *((item_def*)val.ptr);
}
/////////////////////
// Typecast operators
&CrawlHashValue::operator bool()
{
return get_bool();
}
&CrawlHashValue::operator char()
{
return get_byte();
}
&CrawlHashValue::operator short()
{
return get_short();
}
&CrawlHashValue::operator float()
{
return get_float();
}
&CrawlHashValue::operator long()
{
return get_long();
}
&CrawlHashValue::operator std::string()
{
return get_string();
}
&CrawlHashValue::operator coord_def()
{
return get_coord();
}
&CrawlHashValue::operator CrawlHashTable()
{
return get_table();
}
&CrawlHashValue::operator item_def()
{
return get_item();
}
///////////////////////////
// Const typecast operators
CrawlHashValue::operator bool() const
{
return get_bool();
}
#define CONST_INT_CAST() \
switch(type) \
{ \
case HV_BYTE: \
return get_byte(); \
case HV_SHORT: \
return get_short(); \
case HV_LONG: \
return get_long(); \
default: \
ASSERT(false); \
return 0; \
}
CrawlHashValue::operator char() const
{
CONST_INT_CAST();
}
CrawlHashValue::operator short() const
{
CONST_INT_CAST();
}
CrawlHashValue::operator long() const
{
CONST_INT_CAST();
}
CrawlHashValue::operator float() const
{
return get_float();
}
CrawlHashValue::operator std::string() const
{
return get_string();
}
CrawlHashValue::operator coord_def() const
{
return get_coord();
}
///////////////////////
// Assignment operators
bool &CrawlHashValue::operator = (const bool &_val)
{
return (get_bool() = _val);
}
char &CrawlHashValue::operator = (const char &_val)
{
return (get_byte() = _val);
}
short &CrawlHashValue::operator = (const short &_val)
{
return (get_short() = _val);
}
long &CrawlHashValue::operator = (const long &_val)
{
return (get_long() = _val);
}
float &CrawlHashValue::operator = (const float &_val)
{
return (get_float() = _val);
}
std::string &CrawlHashValue::operator = (const std::string &_val)
{
return (get_string() = _val);
}
const char* CrawlHashValue::operator = (const char* _val)
{
get_string() = _val;
return get_string().c_str();
}
coord_def &CrawlHashValue::operator = (const coord_def &_val)
{
return (get_coord() = _val);
}
CrawlHashTable &CrawlHashValue::operator = (const CrawlHashTable &_val)
{
return (get_table() = _val);
}
item_def &CrawlHashValue::operator = (const item_def &_val)
{
return (get_item() = _val);
}
///////////////////////////////////////////////////
// Non-assignment operators which affect the lvalue
#define INT_OPERATOR_UNARY(op) \
switch(type) \
{ \
case HV_BYTE: \
{ \
char &temp = get_byte(); \
temp op; \
return temp; \
} \
\
case HV_SHORT: \
{ \
short &temp = get_short(); \
temp op; \
return temp; \
} \
case HV_LONG: \
{ \
long &temp = get_long(); \
temp op; \
return temp; \
} \
\
default: \
ASSERT(false); \
return 0; \
}
// Prefix
long CrawlHashValue::operator ++ ()
{
INT_OPERATOR_UNARY(++);
}
long CrawlHashValue::operator -- ()
{
INT_OPERATOR_UNARY(--);
}
// Postfix
long CrawlHashValue::operator ++ (int)
{
INT_OPERATOR_UNARY(++);
}
long CrawlHashValue::operator -- (int)
{
INT_OPERATOR_UNARY(--);
}
std::string &CrawlHashValue::operator += (const std::string &_val)
{
return (get_string() += _val);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
CrawlHashTable::CrawlHashTable()
: type(HV_NONE), default_flags(0)
{
}
CrawlHashTable::CrawlHashTable(unsigned char flags)
: type(HV_NONE), default_flags(flags)
{
ASSERT(!(default_flags & HFLAG_UNSET));
}
CrawlHashTable::CrawlHashTable(hash_val_type _type, unsigned char flags)
: type(_type), default_flags(flags)
{
ASSERT(type >= HV_NONE && type < NUM_HASH_VAL_TYPES);
ASSERT(!(default_flags & HFLAG_UNSET));
}
CrawlHashTable::~CrawlHashTable()
{
assert_validity();
}
//////////////////////////////
// Read/write from/to savefile
void CrawlHashTable::write(tagHeader &th) const
{
assert_validity();
if (empty())
{
marshallByte(th, 0);
return;
}
marshallByte(th, size());
marshallByte(th, static_cast<char>(type));
marshallByte(th, (char) default_flags);
CrawlHashTable::hash_map_type::const_iterator i = hash_map.begin();
for (; i != hash_map.end(); i++)
{
marshallString(th, i->first);
i->second.write(th);
}
assert_validity();
}
void CrawlHashTable::read(tagHeader &th)
{
assert_validity();
ASSERT(empty());
ASSERT(type == HV_NONE);
ASSERT(default_flags == 0);
unsigned char _size = (unsigned char) unmarshallByte(th);
if (_size == 0)
return;
type = static_cast<hash_val_type>(unmarshallByte(th));
default_flags = (unsigned char) unmarshallByte(th);
for (unsigned char i = 0; i < _size; i++)
{
std::string key = unmarshallString(th);
CrawlHashValue &val = (*this)[key];
val.read(th);
}
assert_validity();
}
//////////////////
// Misc functions
unsigned char CrawlHashTable::get_default_flags() const
{
assert_validity();
return default_flags;
}
unsigned char CrawlHashTable::set_default_flags(unsigned char flags)
{
assert_validity();
ASSERT(!(flags & HFLAG_UNSET));
default_flags |= flags;
return default_flags;
}
unsigned char CrawlHashTable::unset_default_flags(unsigned char flags)
{
assert_validity();
ASSERT(!(flags & HFLAG_UNSET));
default_flags &= ~flags;
return default_flags;
}
hash_val_type CrawlHashTable::get_type() const
{
assert_validity();
return type;
}
bool CrawlHashTable::exists(const std::string key) const
{
assert_validity();
hash_map_type::const_iterator i = hash_map.find(key);
return (i != hash_map.end());
}
bool CrawlHashTable::exists(const long index) const
{
char buf[12];
sprintf(buf, "%ld", index);
return exists(buf);
}
void CrawlHashTable::assert_validity() const
{
#if DEBUG
ASSERT(!(default_flags & HFLAG_UNSET));
hash_map_type::const_iterator i = hash_map.begin();
unsigned long actual_size = 0;
for (; i != hash_map.end(); i++)
{
actual_size++;
const std::string &key = i->first;
const CrawlHashValue &val = i->second;
ASSERT(key != "");
std::string trimmed = trimmed_string(key);
ASSERT(key == trimmed);
ASSERT(val.type != HV_NONE);
ASSERT(!(val.flags & HFLAG_UNSET));
switch(val.type)
{
case HV_STR:
case HV_COORD:
case HV_ITEM:
ASSERT(val.val.ptr != NULL);
break;
case HV_HASH:
{
ASSERT(val.val.ptr != NULL);
CrawlHashTable* nested;
nested = static_cast<CrawlHashTable*>(val.val.ptr);
nested->assert_validity();
break;
}
default:
break;
}
}
ASSERT(size() == actual_size);
ASSERT(size() <= 255);
#endif
}
int CrawlHashTable::compact_indicies(long min_index, long max_index,
bool compact_down)
{
ASSERT(min_index <= max_index);
if (min_index == max_index)
return 0;
long min_exists, max_exists;
for (min_exists = min_index; min_exists <= max_index; min_exists++)
if (exists(min_exists))
break;
if (min_exists > max_index)
return 0;
for (max_exists = max_index; max_exists >= min_exists; max_exists--)
if (exists(max_exists))
break;
if (max_exists <= min_exists)
return 0;
bool hole_found = false;
for (long i = min_exists; i < max_exists; i++)
if (!exists(i))
{
hole_found = true;
break;
}
if (!hole_found)
return 0;
long start, stop, dir;
if (compact_down)
{
start = min_exists;
stop = max_exists;
dir = +1;
}
else
{
start = max_exists;
stop = min_exists;
dir = -1;
}
stop += dir;
long move = 0;
for (long i = start; i != stop; i += dir)
{
if (!exists(i))
{
move++;
continue;
}
if (move == 0)
continue;
char buf1[12], buf2[12];
sprintf(buf1, "%ld", i - (move * dir));
sprintf(buf2, "%ld", i);
CrawlHashValue &val = hash_map[buf2];
hash_map[buf1] = val;
// Ensure a new()'d object isn't freed, since the other
// CrawlHashValue now owns it.
val.type = HV_BOOL;
erase(buf2);
}
return move;
}
bool CrawlHashTable::fixup_indexed_array(std::string name)
{
bool problems = false;
long max_index = 0;
std::vector<std::string> bad_keys;
for (hash_map_type::iterator i = begin(); i != end(); i++)
{
int index = strtol(i->first.c_str(), NULL, 10);
if (index < 0)
{
if (name != "")
mprf("Negative index %ld found in %s.",
index, name.c_str());
problems = true;
bad_keys.push_back(i->first);
}
else if (index == 0 && i->first != "0")
{
if (name != "")
mprf("Non-numerical index '%s' found in %s.",
i->first.c_str(), name.c_str());
problems = true;
bad_keys.push_back(i->first);
}
else if (index > max_index)
max_index = index;
}
for (unsigned long i = 0, _size = bad_keys.size(); i < _size; i++)
erase(bad_keys[i]);
int holes = compact_indicies(0, max_index);
if (holes > 0 && name != "")
mprf("%d holes found in %s.", holes, name.c_str());
return problems;
}
////////////
// Accessors
CrawlHashValue& CrawlHashTable::get_value(const std::string &key)
{
assert_validity();
hash_map_type::iterator i = hash_map.find(key);
if (i == hash_map.end())
{
hash_map[key] = CrawlHashValue(default_flags);
CrawlHashValue &val = hash_map[key];
if (type != HV_NONE)
{
val.type = type;
val.flags |= HFLAG_CONST_TYPE;
}
return (val);
}
return (i->second);
}
CrawlHashValue& CrawlHashTable::get_value(const long &index)
{
char buf[12];
sprintf(buf, "%ld", index);
return get_value(buf);
}
const CrawlHashValue& CrawlHashTable::get_value(const std::string &key) const
{
assert_validity();
hash_map_type::const_iterator i = hash_map.find(key);
ASSERT(i != hash_map.end());
ASSERT(i->second.type != HV_NONE);
ASSERT(!(i->second.flags & HFLAG_UNSET));
return (i->second);
}
const CrawlHashValue& CrawlHashTable::get_value(const long &index) const
{
char buf[12];
sprintf(buf, "%ld", index);
return get_value(buf);
}
CrawlHashValue& CrawlHashTable::operator[] (const std::string &key)
{
return get_value(key);
}
CrawlHashValue& CrawlHashTable::operator[] (const long &index)
{
return get_value(index);
}
const CrawlHashValue& CrawlHashTable::operator[] (const std::string &key) const
{
return get_value(key);
}
const CrawlHashValue& CrawlHashTable::operator[] (const long &index) const
{
return get_value(index);
}
///////////////////////////
// std::map style interface
size_t CrawlHashTable::size() const
{
return hash_map.size();
}
bool CrawlHashTable::empty() const
{
return hash_map.empty();
}
void CrawlHashTable::erase(const std::string key)
{
assert_validity();
hash_map_type::iterator i = hash_map.find(key);
if (i != hash_map.end())
{
CrawlHashValue &val = i->second;
ASSERT(!(val.flags & HFLAG_NO_ERASE));
hash_map.erase(i);
}
}
void CrawlHashTable::erase(const long index)
{
char buf[12];
sprintf(buf, "%ld", index);
erase(buf);
}
void CrawlHashTable::clear()
{
assert_validity();
ASSERT(!(default_flags & HFLAG_NO_ERASE));
hash_map_type::iterator i = hash_map.begin();
for (; i != hash_map.end(); i++)
ASSERT(!(i->second.flags & HFLAG_NO_ERASE));
hash_map.clear();
}
CrawlHashTable::hash_map_type::iterator CrawlHashTable::begin()
{
assert_validity();
return hash_map.begin();
}
CrawlHashTable::hash_map_type::iterator CrawlHashTable::end()
{
assert_validity();
return hash_map.end();
}
CrawlHashTable::hash_map_type::const_iterator CrawlHashTable::begin() const
{
assert_validity();
return hash_map.begin();
}
CrawlHashTable::hash_map_type::const_iterator CrawlHashTable::end() const
{
assert_validity();
return hash_map.end();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <typename T, hash_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper()
{
table = NULL;
}
template <typename T, hash_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable& _table)
{
wrap(_table);
}
template <typename T, hash_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable* _table)
{
wrap(_table);
}
template <typename T, hash_val_type TYPE>
void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable& _table)
{
wrap(&_table);
}
template <typename T, hash_val_type TYPE>
void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable* _table)
{
ASSERT(_table != NULL);
ASSERT(_table->get_type() == TYPE);
table = _table;
}
template <typename T, hash_val_type TYPE>
T& CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key)
{
return (T&) (*table)[key];
}
template <typename T, hash_val_type TYPE>
T& CrawlTableWrapper<T, TYPE>::operator[] (const long &index)
{
return (T&) (*table)[index];
}
template <typename T, hash_val_type TYPE>
const T CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key) const
{
return (T) (*table)[key];
}
template <typename T, hash_val_type TYPE>
const T CrawlTableWrapper<T, TYPE>::operator[] (const long &index) const
{
return (T) (*table)[index];
}
/*
* File: store.cc
* Summary: Saveable hash-table and vector capable of storing
* multiple types of data.
* Written by: Matthew Cline
*
* Modified for Crawl Reference by $Author$ on $Date$
*
* Change History (most recent first):
* <1> 10/5/07 MPC Created
*/
#ifndef STORE_H
#define STORE_H
#include <limits.h>
#include <map>
#include <string>
#include <vector>
struct tagHeader;
class CrawlHashTable;
class CrawlVector;
class item_def;
class coord_def;
typedef unsigned char hash_size;
typedef unsigned char vec_size;
typedef unsigned char store_flags;
#define VEC_MAX_SIZE 255
#define HASH_MAX_SIZE 255
// 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_LONG,
SV_FLOAT,
SV_STR,
SV_COORD,
SV_ITEM,
SV_HASH,
SV_VEC,
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)
};
// Can't just cast everything into a void pointer, since a float might
// not fit into a pointer on all systems.
typedef union StoreUnion StoreUnion;
union StoreUnion
{
bool boolean;
char byte;
short _short;
long _long;
float _float;
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 long &val);
CrawlStoreValue(const float &val);
CrawlStoreValue(const std::string &val);
CrawlStoreValue(const char* val);
CrawlStoreValue(const coord_def &val);
CrawlStoreValue(const item_def &val);
CrawlStoreValue(const CrawlHashTable &val);
CrawlStoreValue(const CrawlVector &val);
// Only needed for doing some assertion checking.
CrawlStoreValue &operator = (const CrawlStoreValue &other);
protected:
store_val_type type;
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(store_flags flags);
CrawlHashTable &new_table(store_val_type type, store_flags flags = 0);
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();
long &get_long();
float &get_float();
std::string &get_string();
coord_def &get_coord();
CrawlHashTable &get_table();
CrawlVector &get_vector();
item_def &get_item();
bool get_bool() const;
char get_byte() const;
short get_short() const;
long get_long() const;
float get_float() const;
std::string get_string() const;
coord_def get_coord() const;
const CrawlHashTable& get_table() const;
const CrawlVector& get_vector() const;
const item_def& get_item() const;
void set_bool(const bool val);
void set_byte(const char val);
void set_short(const short val);
void set_long(const long val);
void set_float(const float val);
void set_string(const std::string &val);
void set_coord(const coord_def &val);
void set_table(const CrawlHashTable &val);
void set_vector(const CrawlVector &val);
void set_item(const item_def &val);
public:
// NOTE: All operators will assert if the alue 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 (i.e., ++) 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 std::string &key);
CrawlStoreValue &operator [] (const vec_size &index);
const CrawlStoreValue &operator [] (const std::string &key) const;
const CrawlStoreValue &operator [] (const vec_size &index) const;
// Typecast operators
&operator bool();
&operator char();
&operator short();
&operator long();
&operator float();
&operator std::string();
&operator coord_def();
&operator CrawlHashTable();
&operator CrawlVector();
&operator item_def();
operator bool() const;
operator char() const;
operator short() const;
operator long() const;
operator float() const;
operator std::string() const;
operator coord_def() const;
// Assignment operators
CrawlStoreValue &operator = (const bool &val);
CrawlStoreValue &operator = (const char &val);
CrawlStoreValue &operator = (const short &val);
CrawlStoreValue &operator = (const long &val);
CrawlStoreValue &operator = (const float &val);
CrawlStoreValue &operator = (const std::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);
// Misc operators
std::string &operator += (const std::string &val);
// Prefix
long operator ++ ();
long operator -- ();
// Postfix
long operator ++ (int);
long operator -- (int);
protected:
CrawlStoreValue(const store_flags flags,
const store_val_type type = SV_NONE);
void write(tagHeader &th) const;
void read(tagHeader &th);
void unset(bool force = false);
friend class CrawlHashTable;
friend class CrawlVector;
};
// A hash table can have a maximum of 255 key/value pairs. If you
// want more than that you can use nested hash tables.
//
// 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 it's type (or lack of type) is immutable.
//
// An empty hash table will take up only 1 byte in the savefile. A
// non-empty hash table will have an overhead of 3 bytes for the hash
// table overall and 2 bytes per key/value pair, over and above the
// number of bytes needed to store the keys and values themselves.
class CrawlHashTable
{
public:
CrawlHashTable();
CrawlHashTable(store_flags flags);
CrawlHashTable(store_val_type type, store_flags flags = 0);
~CrawlHashTable();
typedef std::map<std::string, CrawlStoreValue> hash_map_type;
typedef hash_map_type::iterator iterator;
typedef hash_map_type::const_iterator const_iterator;
protected:
store_val_type type;
store_flags default_flags;
hash_map_type hash_map;
friend class CrawlStoreValue;
public:
void write(tagHeader &th) const;
void read(tagHeader &th);
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;
bool exists(const std::string key) const;
void assert_validity() const;
// 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 std::string &key);
CrawlStoreValue& operator[] (const std::string &key);
// 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 std::string &key) const;
const CrawlStoreValue& operator[] (const std::string &key) const;
// std::map style interface
hash_size size() const;
bool empty() const;
void erase(const std::string key);
void clear();
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
// 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 std::vector<CrawlStoreValue> vector_type;
typedef vector_type::iterator iterator;
typedef vector_type::const_iterator const_iterator;
protected:
store_val_type type;
store_flags default_flags;
vec_size max_size;
vector_type vector;
friend class CrawlStoreValue;
public:
void write(tagHeader &th) const;
void read(tagHeader &th);
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;
CrawlStoreValue& get_value(const vec_size &index);
CrawlStoreValue& operator[] (const vec_size &index);
// NOTE: If the const versions of get_value() or [] are given a
// 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;
// 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 coversion 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();
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
};
// A wrapper for non-heterogeneous hash tables, so that the values can
// be accessed without using get_foo(). T needs to have both normal
// and const type-cast operators defined by CrawlStoreValue for this
// template to work.
template <typename T, store_val_type TYPE>
class CrawlTableWrapper
{
public:
CrawlTableWrapper();
CrawlTableWrapper(CrawlHashTable& table);
CrawlTableWrapper(CrawlHashTable* table);
protected:
CrawlHashTable* table;
public:
void wrap(CrawlHashTable& table);
void wrap(CrawlHashTable* table);
CrawlHashTable* get_table();
T& operator[] (const std::string &key);
const CrawlHashTable* get_table() const;
const T operator[] (const std::string &key) const;
};
typedef CrawlTableWrapper<bool, SV_BOOL> CrawlBoolTable;
typedef CrawlTableWrapper<char, SV_BYTE> CrawlByteTable;
typedef CrawlTableWrapper<short, SV_SHORT> CrawlShortTable;
typedef CrawlTableWrapper<long, SV_LONG> CrawlLongTable;
typedef CrawlTableWrapper<float, SV_FLOAT> CrawlFloatTable;
typedef CrawlTableWrapper<std::string, SV_STR> CrawlStringTable;
typedef CrawlTableWrapper<coord_def, SV_COORD> CrawlCoordTable;
#endif
/*
* File: store.cc
* Summary: Saveable hash-table and vector capable of storing
* multiple types of data.
* Written by: Matthew Cline
*
* Modified for Crawl Reference by $Author$ on $Date$
*
* Change History (most recent first):
* <1> 10/5/07 MPC Created
*/
#include "AppHdr.h"
#include "store.h"
#include "externs.h"
#include "tags.h"
CrawlStoreValue::CrawlStoreValue()
: type(SV_NONE), flags(SFLAG_UNSET)
{
val.ptr = NULL;
}
CrawlStoreValue::CrawlStoreValue(const CrawlStoreValue &other)
{
ASSERT(other.type >= SV_NONE && other.type < NUM_STORE_VAL_TYPES);
type = other.type;
flags = other.flags;
if (flags & SFLAG_UNSET)
{
val = other.val;
return;
}
switch (type)
{
case SV_NONE:
case SV_BOOL:
case SV_BYTE:
case SV_SHORT:
case SV_LONG:
case SV_FLOAT:
val = other.val;
break;
case SV_STR:
{
std::string* str;
str = new std::string(*static_cast<std::string*>(other.val.ptr));
val.ptr = static_cast<void*>(str);
break;
}
case SV_COORD:
{
coord_def* coord;
coord = new coord_def(*static_cast<coord_def*>(other.val.ptr));
val.ptr = static_cast<void*>(coord);
break;
}
case SV_ITEM:
{
item_def* item;
item = new item_def(*static_cast<item_def*>(other.val.ptr));
val.ptr = static_cast<void*>(item);
break;
}
case SV_HASH:
{
CrawlHashTable* hash;
CrawlHashTable* tmp = static_cast<CrawlHashTable*>(other.val.ptr);
hash = new CrawlHashTable(*tmp);
val.ptr = static_cast<void*>(hash);
break;
}
case SV_VEC:
{
CrawlVector* vec;
CrawlVector* tmp = static_cast<CrawlVector*>(other.val.ptr);
vec = new CrawlVector(*tmp);
val.ptr = static_cast<void*>(vec);
break;
}
case NUM_STORE_VAL_TYPES:
ASSERT(false);
}
}
CrawlStoreValue::CrawlStoreValue(const store_flags _flags,
const store_val_type _type)
: type(_type), flags(_flags)
{
ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
ASSERT(!(flags & SFLAG_UNSET));
flags |= SFLAG_UNSET;
val.ptr = NULL;
}
// Conversion constructors
CrawlStoreValue::CrawlStoreValue(const bool _val)
: type(SV_BOOL), flags(0)
{
get_bool() = _val;
}
CrawlStoreValue::CrawlStoreValue(const char &_val)
: type(SV_BYTE), flags(0)
{
get_byte() = _val;
}
CrawlStoreValue::CrawlStoreValue(const short &_val)
: type(SV_SHORT), flags(0)
{
get_short() = _val;
}
CrawlStoreValue::CrawlStoreValue(const long &_val)
: type(SV_LONG), flags(0)
{
get_long() = _val;
}
CrawlStoreValue::CrawlStoreValue(const float &_val)
: type(SV_FLOAT), flags(0)
{
get_float() = _val;
}
CrawlStoreValue::CrawlStoreValue(const std::string &_val)
: type(SV_STR), flags(0)
{
get_string() = _val;
}
CrawlStoreValue::CrawlStoreValue(const char* _val)
: type(SV_STR), flags(0)
{
get_string() = _val;
}
CrawlStoreValue::CrawlStoreValue(const coord_def &_val)
: type(SV_COORD), flags(0)
{
get_coord() = _val;
}
CrawlStoreValue::CrawlStoreValue(const item_def &_val)
: type(SV_ITEM), flags(0)
{
get_item() = _val;
}
CrawlStoreValue::CrawlStoreValue(const CrawlHashTable &_val)
: type(SV_HASH), flags(0)
{
get_table() = _val;
}
CrawlStoreValue::CrawlStoreValue(const CrawlVector &_val)
: type(SV_VEC), flags(0)
{
get_vector() = _val;
}
CrawlStoreValue::~CrawlStoreValue()
{
unset(true);
}
void CrawlStoreValue::unset(bool force)
{
if (flags & SFLAG_UNSET)
return;
if (force)
flags &= ~SFLAG_NO_ERASE;
ASSERT(!(flags & SFLAG_NO_ERASE));
switch (type)
{
case SV_BOOL:
val.boolean = false;
break;
case SV_BYTE:
val.byte = 0;
break;
case SV_SHORT:
val._short = 0;
break;
case SV_LONG:
val._long = 0;
break;
case SV_FLOAT:
val._float = 0.0;
break;
case SV_STR:
{
std::string* str = static_cast<std::string*>(val.ptr);
delete str;
val.ptr = NULL;
break;
}
case SV_COORD:
{
coord_def* coord = static_cast<coord_def*>(val.ptr);
delete coord;
val.ptr = NULL;
break;
}
case SV_ITEM:
{
item_def* item = static_cast<item_def*>(val.ptr);
delete item;
val.ptr = NULL;
break;
}
case SV_HASH:
{
CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
delete hash;
val.ptr = NULL;
break;
}
case SV_VEC:
{
CrawlVector* vec = static_cast<CrawlVector*>(val.ptr);
delete vec;
val.ptr = NULL;
break;
}
case SV_NONE:
ASSERT(false);
case NUM_STORE_VAL_TYPES:
ASSERT(false);
}
flags |= SFLAG_UNSET;
}
// Only needed to do some assertion checking.
CrawlStoreValue &CrawlStoreValue::operator = (const CrawlStoreValue &other)
{
ASSERT(other.type >= SV_NONE && other.type < NUM_STORE_VAL_TYPES);
ASSERT(other.type != SV_NONE || type == SV_NONE);
// NOTE: We don't bother checking SFLAG_CONST_VAL, since the
// asignment operator is used when swapping two elements.
if (!(flags & SFLAG_UNSET))
{
if (flags & SFLAG_CONST_TYPE)
ASSERT(type == SV_NONE || type == other.type);
}
type = other.type;
flags = other.flags;
val = other.val;
return (*this);
}
///////////////////////////////////
// Meta-data accessors and changers
store_flags CrawlStoreValue::get_flags() const
{
return flags;
}
store_flags CrawlStoreValue::set_flags(store_flags _flags)
{
flags |= _flags;
return flags;
}
store_flags CrawlStoreValue::unset_flags(store_flags _flags)
{
flags &= ~_flags;
return flags;
}
store_val_type CrawlStoreValue::get_type() const
{
return type;
}
//////////////////////////////
// Read/write from/to savefile
void CrawlStoreValue::write(tagHeader &th) const
{
ASSERT(!(flags & SFLAG_UNSET));
marshallByte(th, (char) type);
marshallByte(th, (char) flags);
switch (type)
{
case SV_BOOL:
marshallBoolean(th, val.boolean);
break;
case SV_BYTE:
marshallByte(th, val.byte);
break;
case SV_SHORT:
marshallShort(th, val._short);
break;
case SV_LONG:
marshallLong(th, val._long);
break;
case SV_FLOAT:
marshallFloat(th, val._float);
break;
case SV_STR:
{
std::string* str = static_cast<std::string*>(val.ptr);
marshallString(th, *str);
break;
}
case SV_COORD:
{
coord_def* coord = static_cast<coord_def*>(val.ptr);
marshallCoord(th, *coord);
break;
}
case SV_ITEM:
{
item_def* item = static_cast<item_def*>(val.ptr);
marshallItem(th, *item);
break;
}
case SV_HASH:
{
CrawlHashTable* hash = static_cast<CrawlHashTable*>(val.ptr);
hash->write(th);
break;
}
case SV_VEC:
{
CrawlVector* vec = static_cast<CrawlVector*>(val.ptr);
vec->write(th);
break;
}
case SV_NONE:
ASSERT(false);
case NUM_STORE_VAL_TYPES:
ASSERT(false);
}
}
void CrawlStoreValue::read(tagHeader &th)
{
type = static_cast<store_val_type>(unmarshallByte(th));
flags = (store_flags) unmarshallByte(th);
ASSERT(!(flags & SFLAG_UNSET));
switch (type)
{
case SV_BOOL:
val.boolean = unmarshallBoolean(th);
break;
case SV_BYTE:
val.byte = unmarshallByte(th);
break;
case SV_SHORT:
val._short = unmarshallShort(th);
break;
case SV_LONG:
val._long = unmarshallLong(th);
break;
case SV_FLOAT:
val._float = unmarshallFloat(th);
break;
case SV_STR:
{
std::string str = unmarshallString(th);
val.ptr = (void*) new std::string(str);
break;
}
case SV_COORD:
{
coord_def coord;
unmarshallCoord(th, coord);
val.ptr = (void*) new coord_def(coord);
break;
}
case SV_ITEM:
{
item_def item;
unmarshallItem(th, item);
val.ptr = (void*) new item_def(item);
break;
}
case SV_HASH:
{
CrawlHashTable* hash = new CrawlHashTable();
hash->read(th);
val.ptr = (void*) hash;
break;
}
case SV_VEC:
{
CrawlVector* vec = new CrawlVector();
vec->read(th);
val.ptr = (void*) vec;
break;
}
case SV_NONE:
ASSERT(false);
case NUM_STORE_VAL_TYPES:
ASSERT(false);
}
}
////////////////////////////////////////////////////////////////
// Setup a new table with the given flags and/or type; assert if
// a table already exists.
CrawlHashTable &CrawlStoreValue::new_table(store_flags _flags)
{
return new_table(SV_NONE, flags);
}
CrawlHashTable &CrawlStoreValue::new_table(store_val_type _type,
store_flags _flags)
{
CrawlHashTable* old_table = static_cast<CrawlHashTable*>(val.ptr);
ASSERT(flags & SFLAG_UNSET);
ASSERT(type == SV_NONE
|| (type == SV_HASH
&& old_table->size() == 0
&& old_table->get_type() == SV_NONE
&& old_table->get_default_flags() == 0));
CrawlHashTable &table = get_table();
table.default_flags = _flags;
table.type = _type;
type = SV_HASH;
flags &= ~SFLAG_UNSET;
return table;
}
////////////////////////////////////////////////////////////////
// Setup a new vector with the given flags and/or type; assert if
// a vector already exists.
CrawlVector &CrawlStoreValue::new_vector(store_flags _flags,
vec_size max_size)
{
return new_vector(SV_NONE, flags, max_size);
}
CrawlVector &CrawlStoreValue::new_vector(store_val_type _type,
store_flags _flags,
vec_size _max_size)
{
CrawlVector* old_vector = static_cast<CrawlVector*>(val.ptr);
ASSERT(flags & SFLAG_UNSET);
ASSERT(type == SV_NONE
|| (type == SV_VEC
&& old_vector->size() == 0
&& old_vector->get_type() == SV_NONE
&& old_vector->get_default_flags() == 0
&& old_vector->get_max_size() == VEC_MAX_SIZE));
CrawlVector &vector = get_vector();
vector.default_flags = _flags;
vector.type = _type;
type = SV_VEC;
flags &= ~SFLAG_UNSET;
return vector;
}
///////////////////////////////////////////
// Dynamic type-checking accessor functions
#define GET_VAL(x, _type, field, value) \
ASSERT((flags & SFLAG_UNSET) || !(flags & SFLAG_CONST_VAL)); \
if (type != (x)) \
{ \
if (type == SV_NONE) \
{ \
type = (x); \
field = (value); \
} \
else \
{ \
ASSERT(!(flags & SFLAG_CONST_TYPE)); \
switch(type) \
{ \
case SV_BOOL: \
field = (_type) val.boolean; \
break; \
case SV_BYTE: \
field = (_type) val.byte; \
break; \
case SV_SHORT: \
field = (_type) val._short; \
break; \
case SV_LONG: \
field = (_type) val._long; \
break; \
case SV_FLOAT: \
field = (_type) val._float; \
break; \
default: \
ASSERT(false); \
} \
type = (x); \
} \
} \
flags &= ~SFLAG_UNSET; \
return field;
#define GET_VAL_PTR(x, _type, value) \
ASSERT((flags & SFLAG_UNSET) || !(flags & SFLAG_CONST_VAL)); \
if (type != (x)) \
{ \
if (type == SV_NONE) \
{ \
type = (x); \
val.ptr = (value); \
} \
else \
{ \
unset(); \
val.ptr = (value); \
type = (x); \
} \
} \
flags &= ~SFLAG_UNSET; \
return *((_type) val.ptr);
bool &CrawlStoreValue::get_bool()
{
GET_VAL(SV_BOOL, bool, val.boolean, false);
}
char &CrawlStoreValue::get_byte()
{
GET_VAL(SV_BYTE, char, val.byte, 0);
}
short &CrawlStoreValue::get_short()
{
GET_VAL(SV_SHORT, short, val._short, 0);
}
long &CrawlStoreValue::get_long()
{
GET_VAL(SV_LONG, long, val._long, 0);
}
float &CrawlStoreValue::get_float()
{
GET_VAL(SV_FLOAT, float, val._float, 0.0);
}
std::string &CrawlStoreValue::get_string()
{
GET_VAL_PTR(SV_STR, std::string*, new std::string(""));
}
coord_def &CrawlStoreValue::get_coord()
{
GET_VAL_PTR(SV_COORD, coord_def*, new coord_def());
}
item_def &CrawlStoreValue::get_item()
{
GET_VAL_PTR(SV_ITEM, item_def*, new item_def());
}
CrawlHashTable &CrawlStoreValue::get_table()
{
GET_VAL_PTR(SV_HASH, CrawlHashTable*, new CrawlHashTable());
}
CrawlVector &CrawlStoreValue::get_vector()
{
GET_VAL_PTR(SV_VEC, CrawlVector*, new CrawlVector());
}
CrawlStoreValue &CrawlStoreValue::operator [] (const std::string &key)
{
return get_table()[key];
}
CrawlStoreValue &CrawlStoreValue::operator [] (const vec_size &index)
{
return get_vector()[index];
}
///////////////////////////
// Const accessor functions
#define GET_CONST_SETUP(x) \
ASSERT(!(flags & SFLAG_UNSET)); \
ASSERT(type == (x));
bool CrawlStoreValue::get_bool() const
{
GET_CONST_SETUP(SV_BOOL);
return val.boolean;
}
char CrawlStoreValue::get_byte() const
{
GET_CONST_SETUP(SV_BYTE);
return val.byte;
}
short CrawlStoreValue::get_short() const
{
GET_CONST_SETUP(SV_SHORT);
return val._short;
}
long CrawlStoreValue::get_long() const
{
GET_CONST_SETUP(SV_LONG);
return val._long;
}
float CrawlStoreValue::get_float() const
{
GET_CONST_SETUP(SV_FLOAT);
return val._float;
}
std::string CrawlStoreValue::get_string() const
{
GET_CONST_SETUP(SV_STR);
return *((std::string*)val.ptr);
}
coord_def CrawlStoreValue::get_coord() const
{
GET_CONST_SETUP(SV_COORD);
return *((coord_def*)val.ptr);
}
const item_def& CrawlStoreValue::get_item() const
{
GET_CONST_SETUP(SV_ITEM);
return *((item_def*)val.ptr);
}
const CrawlHashTable& CrawlStoreValue::get_table() const
{
GET_CONST_SETUP(SV_HASH);
return *((CrawlHashTable*)val.ptr);
}
const CrawlVector& CrawlStoreValue::get_vector() const
{
GET_CONST_SETUP(SV_VEC);
return *((CrawlVector*)val.ptr);
}
const CrawlStoreValue &CrawlStoreValue::operator
[] (const std::string &key) const
{
return get_table()[key];
}
const CrawlStoreValue &CrawlStoreValue::operator
[](const vec_size &index) const
{
return get_vector()[index];
}
/////////////////////
// Typecast operators
&CrawlStoreValue::operator bool()
{
return get_bool();
}
&CrawlStoreValue::operator char()
{
return get_byte();
}
&CrawlStoreValue::operator short()
{
return get_short();
}
&CrawlStoreValue::operator float()
{
return get_float();
}
&CrawlStoreValue::operator long()
{
return get_long();
}
&CrawlStoreValue::operator std::string()
{
return get_string();
}
&CrawlStoreValue::operator coord_def()
{
return get_coord();
}
&CrawlStoreValue::operator CrawlHashTable()
{
return get_table();
}
&CrawlStoreValue::operator CrawlVector()
{
return get_vector();
}
&CrawlStoreValue::operator item_def()
{
return get_item();
}
///////////////////////////
// Const typecast operators
CrawlStoreValue::operator bool() const
{
return get_bool();
}
#define CONST_INT_CAST() \
switch(type) \
{ \
case SV_BYTE: \
return get_byte(); \
case SV_SHORT: \
return get_short(); \
case SV_LONG: \
return get_long(); \
default: \
ASSERT(false); \
return 0; \
}
CrawlStoreValue::operator char() const
{
CONST_INT_CAST();
}
CrawlStoreValue::operator short() const
{
CONST_INT_CAST();
}
CrawlStoreValue::operator long() const
{
CONST_INT_CAST();
}
CrawlStoreValue::operator float() const
{
return get_float();
}
CrawlStoreValue::operator std::string() const
{
return get_string();
}
CrawlStoreValue::operator coord_def() const
{
return get_coord();
}
///////////////////////
// Assignment operators
CrawlStoreValue &CrawlStoreValue::operator = (const bool &_val)
{
get_bool() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const char &_val)
{
get_byte() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const short &_val)
{
get_short() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const long &_val)
{
get_long() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const float &_val)
{
get_float() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const std::string &_val)
{
get_string() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const char* _val)
{
get_string() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const coord_def &_val)
{
get_coord() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const CrawlHashTable &_val)
{
get_table() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const CrawlVector &_val)
{
get_vector() = _val;
return (*this);
}
CrawlStoreValue &CrawlStoreValue::operator = (const item_def &_val)
{
get_item() = _val;
return (*this);
}
///////////////////////////////////////////////////
// Non-assignment operators which affect the lvalue
#define INT_OPERATOR_UNARY(op) \
switch(type) \
{ \
case SV_BYTE: \
{ \
char &temp = get_byte(); \
temp op; \
return temp; \
} \
\
case SV_SHORT: \
{ \
short &temp = get_short(); \
temp op; \
return temp; \
} \
case SV_LONG: \
{ \
long &temp = get_long(); \
temp op; \
return temp; \
} \
\
default: \
ASSERT(false); \
return 0; \
}
// Prefix
long CrawlStoreValue::operator ++ ()
{
INT_OPERATOR_UNARY(++);
}
long CrawlStoreValue::operator -- ()
{
INT_OPERATOR_UNARY(--);
}
// Postfix
long CrawlStoreValue::operator ++ (int)
{
INT_OPERATOR_UNARY(++);
}
long CrawlStoreValue::operator -- (int)
{
INT_OPERATOR_UNARY(--);
}
std::string &CrawlStoreValue::operator += (const std::string &_val)
{
return (get_string() += _val);
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
CrawlHashTable::CrawlHashTable()
: type(SV_NONE), default_flags(0)
{
}
CrawlHashTable::CrawlHashTable(store_flags flags)
: type(SV_NONE), default_flags(flags)
{
ASSERT(!(default_flags & SFLAG_UNSET));
}
CrawlHashTable::CrawlHashTable(store_val_type _type, store_flags flags)
: type(_type), default_flags(flags)
{
ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
ASSERT(!(default_flags & SFLAG_UNSET));
}
CrawlHashTable::~CrawlHashTable()
{
assert_validity();
}
//////////////////////////////
// Read/write from/to savefile
void CrawlHashTable::write(tagHeader &th) const
{
assert_validity();
if (empty())
{
marshallByte(th, 0);
return;
}
marshallByte(th, size());
marshallByte(th, static_cast<char>(type));
marshallByte(th, (char) default_flags);
CrawlHashTable::hash_map_type::const_iterator i = hash_map.begin();
for (; i != hash_map.end(); i++)
{
marshallString(th, i->first);
i->second.write(th);
}
assert_validity();
}
void CrawlHashTable::read(tagHeader &th)
{
assert_validity();
ASSERT(empty());
ASSERT(type == SV_NONE);
ASSERT(default_flags == 0);
hash_size _size = (hash_size) unmarshallByte(th);
if (_size == 0)
return;
type = static_cast<store_val_type>(unmarshallByte(th));
default_flags = (store_flags) unmarshallByte(th);
for (hash_size i = 0; i < _size; i++)
{
std::string key = unmarshallString(th);
CrawlStoreValue &val = (*this)[key];
val.read(th);
}
assert_validity();
}
//////////////////
// Misc functions
store_flags CrawlHashTable::get_default_flags() const
{
assert_validity();
return default_flags;
}
store_flags CrawlHashTable::set_default_flags(store_flags flags)
{
assert_validity();
ASSERT(!(flags & SFLAG_UNSET));
default_flags |= flags;
return default_flags;
}
store_flags CrawlHashTable::unset_default_flags(store_flags flags)
{
assert_validity();
ASSERT(!(flags & SFLAG_UNSET));
default_flags &= ~flags;
return default_flags;
}
store_val_type CrawlHashTable::get_type() const
{
assert_validity();
return type;
}
bool CrawlHashTable::exists(const std::string key) const
{
assert_validity();
hash_map_type::const_iterator i = hash_map.find(key);
return (i != hash_map.end());
}
void CrawlHashTable::assert_validity() const
{
#if DEBUG
ASSERT(!(default_flags & SFLAG_UNSET));
hash_map_type::const_iterator i = hash_map.begin();
unsigned long actual_size = 0;
for (; i != hash_map.end(); i++)
{
actual_size++;
const std::string &key = i->first;
const CrawlStoreValue &val = i->second;
ASSERT(key != "");
std::string trimmed = trimmed_string(key);
ASSERT(key == trimmed);
ASSERT(val.type != SV_NONE);
ASSERT(!(val.flags & SFLAG_UNSET));
switch(val.type)
{
case SV_STR:
case SV_COORD:
case SV_ITEM:
ASSERT(val.val.ptr != NULL);
break;
case SV_HASH:
{
ASSERT(val.val.ptr != NULL);
CrawlHashTable* nested;
nested = static_cast<CrawlHashTable*>(val.val.ptr);
nested->assert_validity();
break;
}
default:
break;
}
}
ASSERT(size() == actual_size);
#endif
}
////////////////////////////////
// Accessors to contained values
CrawlStoreValue& CrawlHashTable::get_value(const std::string &key)
{
assert_validity();
iterator i = hash_map.find(key);
if (i == hash_map.end())
{
hash_map[key] = CrawlStoreValue(default_flags);
CrawlStoreValue &val = hash_map[key];
if (type != SV_NONE)
{
val.type = type;
val.flags |= SFLAG_CONST_TYPE;
}
return (val);
}
return (i->second);
}
const CrawlStoreValue& CrawlHashTable::get_value(const std::string &key) const
{
assert_validity();
hash_map_type::const_iterator i = hash_map.find(key);
ASSERT(i != hash_map.end());
ASSERT(i->second.type != SV_NONE);
ASSERT(!(i->second.flags & SFLAG_UNSET));
return (i->second);
}
CrawlStoreValue& CrawlHashTable::operator[] (const std::string &key)
{
return get_value(key);
}
const CrawlStoreValue& CrawlHashTable::operator[] (const std::string &key)
const
{
return get_value(key);
}
///////////////////////////
// std::map style interface
hash_size CrawlHashTable::size() const
{
return hash_map.size();
}
bool CrawlHashTable::empty() const
{
return hash_map.empty();
}
void CrawlHashTable::erase(const std::string key)
{
assert_validity();
iterator i = hash_map.find(key);
if (i != hash_map.end())
{
CrawlStoreValue &val = i->second;
ASSERT(!(val.flags & SFLAG_NO_ERASE));
hash_map.erase(i);
}
}
void CrawlHashTable::clear()
{
assert_validity();
ASSERT(!(default_flags & SFLAG_NO_ERASE));
iterator i = hash_map.begin();
for (; i != hash_map.end(); i++)
ASSERT(!(i->second.flags & SFLAG_NO_ERASE));
hash_map.clear();
}
CrawlHashTable::iterator CrawlHashTable::begin()
{
assert_validity();
return hash_map.begin();
}
CrawlHashTable::iterator CrawlHashTable::end()
{
assert_validity();
return hash_map.end();
}
CrawlHashTable::const_iterator CrawlHashTable::begin() const
{
assert_validity();
return hash_map.begin();
}
CrawlHashTable::const_iterator CrawlHashTable::end() const
{
assert_validity();
return hash_map.end();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
CrawlVector::CrawlVector()
: type(SV_NONE), default_flags(0), max_size(VEC_MAX_SIZE)
{
}
CrawlVector::CrawlVector(store_flags flags, vec_size _max_size)
: type(SV_NONE), default_flags(flags), max_size(_max_size)
{
ASSERT(!(default_flags & SFLAG_UNSET));
ASSERT(max_size > 0);
}
CrawlVector::CrawlVector(store_val_type _type, store_flags flags,
vec_size _max_size)
: type(_type), default_flags(flags), max_size(_max_size)
{
ASSERT(type >= SV_NONE && type < NUM_STORE_VAL_TYPES);
ASSERT(!(default_flags & SFLAG_UNSET));
ASSERT(max_size > 0);
}
CrawlVector::~CrawlVector()
{
assert_validity();
}
//////////////////////////////
// Read/write from/to savefile
void CrawlVector::write(tagHeader &th) const
{
assert_validity();
if (empty())
{
marshallByte(th, 0);
return;
}
marshallByte(th, (char) size());
marshallByte(th, (char) max_size);
marshallByte(th, static_cast<char>(type));
marshallByte(th, (char) default_flags);
for (vec_size i = 0; i < size(); i++)
{
CrawlStoreValue val = vector[i];
ASSERT(val.type != SV_NONE);
ASSERT(!(val.flags & SFLAG_UNSET));
val.write(th);
}
assert_validity();
}
void CrawlVector::read(tagHeader &th)
{
assert_validity();
ASSERT(empty());
ASSERT(type == SV_NONE);
ASSERT(default_flags == 0);
ASSERT(max_size == VEC_MAX_SIZE);
vec_size _size = (vec_size) unmarshallByte(th);
if (_size == 0)
return;
max_size = static_cast<vec_size>(unmarshallByte(th));
type = static_cast<store_val_type>(unmarshallByte(th));
default_flags = static_cast<store_flags>(unmarshallByte(th));
ASSERT(_size <= max_size);
vector.resize(_size);
for (vec_size i = 0; i < _size; i++)
vector[i].read(th);
assert_validity();
}
//////////////////
// Misc functions
store_flags CrawlVector::get_default_flags() const
{
assert_validity();
return default_flags;
}
store_flags CrawlVector::set_default_flags(store_flags flags)
{
assert_validity();
ASSERT(!(flags & SFLAG_UNSET));
default_flags |= flags;
return default_flags;
}
store_flags CrawlVector::unset_default_flags(store_flags flags)
{
assert_validity();
ASSERT(!(flags & SFLAG_UNSET));
default_flags &= ~flags;
return default_flags;
}
store_val_type CrawlVector::get_type() const
{
assert_validity();
return type;
}
void CrawlVector::assert_validity() const
{
#if DEBUG
ASSERT(!(default_flags & SFLAG_UNSET));
ASSERT(max_size > 0);
ASSERT(max_size >= size());
for (vec_size i = 0, _size = size(); i < _size; i++)
{
const CrawlStoreValue &val = vector[i];
// A vector might be resize()'d and filled up with unset
// values, which are then set one by one, so we can't
// assert over that here.
if (val.type == SV_NONE || (val.flags & SFLAG_UNSET))
continue;
switch(val.type)
{
case SV_STR:
case SV_COORD:
case SV_ITEM:
ASSERT(val.val.ptr != NULL);
break;
case SV_HASH:
{
ASSERT(val.val.ptr != NULL);
CrawlVector* nested;
nested = static_cast<CrawlVector*>(val.val.ptr);
nested->assert_validity();
break;
}
case SV_VEC:
{
ASSERT(val.val.ptr != NULL);
CrawlVector* nested;
nested = static_cast<CrawlVector*>(val.val.ptr);
nested->assert_validity();
break;
}
default:
break;
}
}
#endif
}
void CrawlVector::set_max_size(vec_size _size)
{
ASSERT(_size > 0);
ASSERT(max_size == VEC_MAX_SIZE);
max_size = _size;
vector.reserve(max_size);
}
vec_size CrawlVector::get_max_size() const
{
return max_size;
}
////////////////////////////////
// Accessors to contained values
CrawlStoreValue& CrawlVector::get_value(const vec_size &index)
{
assert_validity();
ASSERT(index <= max_size);
ASSERT(index <= vector.size());
return vector[index];
}
const CrawlStoreValue& CrawlVector::get_value(const vec_size &index) const
{
assert_validity();
ASSERT(index <= max_size);
ASSERT(index <= vector.size());
return vector[index];
}
CrawlStoreValue& CrawlVector::operator[] (const vec_size &index)
{
return get_value(index);
}
const CrawlStoreValue& CrawlVector::operator[] (const vec_size &index) const
{
return get_value(index);
}
///////////////////////////
// std::vector style interface
vec_size CrawlVector::size() const
{
return vector.size();
}
bool CrawlVector::empty() const
{
return vector.empty();
}
CrawlStoreValue& CrawlVector::pop_back()
{
assert_validity();
ASSERT(vector.size() > 0);
CrawlStoreValue& val = vector[vector.size() - 1];
vector.pop_back();
return val;
}
void CrawlVector::push_back(CrawlStoreValue val)
{
assert_validity();
ASSERT(vector.size() < max_size);
ASSERT(type == SV_NONE
|| (val.type == SV_NONE && (val.flags & SFLAG_UNSET))
|| (val.type == type));
val.flags |= default_flags;
if (type != SV_NONE)
{
val.type = type;
val.flags |= SFLAG_CONST_TYPE;
}
vector.push_back(val);
}
void CrawlVector::insert(const vec_size index, CrawlStoreValue val)
{
assert_validity();
ASSERT(vector.size() < max_size);
ASSERT(type == SV_NONE
|| (val.type == SV_NONE && (val.flags & SFLAG_UNSET))
|| (val.type == type));
val.flags |= default_flags;
if (type != SV_NONE)
{
val.type = type;
val.flags |= SFLAG_CONST_TYPE;
}
vector.insert(vector.begin() + index, val);
}
void CrawlVector::resize(const vec_size _size)
{
assert_validity();
ASSERT(max_size == VEC_MAX_SIZE);
ASSERT(_size < max_size);
vec_size old_size = size();
vector.resize(_size);
for (vec_size i = old_size; i < _size; i++)
{
vector[i].flags = SFLAG_UNSET | default_flags;
vector[i].type = SV_NONE;
}
}
void CrawlVector::erase(const vec_size index)
{
assert_validity();
ASSERT(index <= max_size);
ASSERT(index <= vector.size());
vector.erase(vector.begin() + index);
}
void CrawlVector::clear()
{
assert_validity();
ASSERT(!(default_flags & SFLAG_NO_ERASE));
for (vec_size i = 0, _size = size(); i < _size; i++)
ASSERT(!(vector[i].flags & SFLAG_NO_ERASE));
vector.clear();
}
CrawlVector::iterator CrawlVector::begin()
{
assert_validity();
return vector.begin();
}
CrawlVector::iterator CrawlVector::end()
{
assert_validity();
return vector.end();
}
CrawlVector::const_iterator CrawlVector::begin() const
{
assert_validity();
return vector.begin();
}
CrawlVector::const_iterator CrawlVector::end() const
{
assert_validity();
return vector.end();
}
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
template <typename T, store_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper()
{
table = NULL;
}
template <typename T, store_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable& _table)
{
wrap(_table);
}
template <typename T, store_val_type TYPE>
CrawlTableWrapper<T, TYPE>::CrawlTableWrapper(CrawlHashTable* _table)
{
wrap(_table);
}
template <typename T, store_val_type TYPE>
void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable& _table)
{
wrap(&_table);
}
template <typename T, store_val_type TYPE>
void CrawlTableWrapper<T, TYPE>::wrap(CrawlHashTable* _table)
{
ASSERT(_table != NULL);
ASSERT(_table->get_type() == TYPE);
table = _table;
}
template <typename T, store_val_type TYPE>
T& CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key)
{
return (T&) (*table)[key];
}
template <typename T, store_val_type TYPE>
const T CrawlTableWrapper<T, TYPE>::operator[] (const std::string &key) const
{
return (T) (*table)[key];
}
msg += "Strange, this deck is already empty.";
int cards_left = 0;
if (deck.plus2 >= 0)
cards_left = deck.plus - deck.plus2;
else
cards_left = -deck.plus;
if (props["cards"].get_vector().get_type() != SV_BYTE)
msg::stream << "'cards' vector doesn't contain bytes. ";
msg += " But there should be been ";
msg += cards_left;
msg += " cards left.";
msg::stream << "Strange, this deck is already empty.";
int cards_left = 0;
if (deck.plus2 >= 0)
cards_left = deck.plus - deck.plus2;
else
cards_left = -deck.plus;
if (cards_left != 0)
{
msg::stream << " But there should be been ";
msg::stream << cards_left;
msg::stream << " cards left.";
}