/* * File: store.cc * Summary: Saveable hash-table and vector capable of storing * multiple types of data. * Written by: Matthew Cline */ #include "AppHdr.h" #include "store.h" #include "dlua.h" #include "externs.h" #include "monster.h" #include "tags.h" #include "travel.h" #include 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); val.ptr = NULL; 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(other.val.ptr)); val.ptr = static_cast(str); break; } case SV_COORD: { coord_def* coord; coord = new coord_def(*static_cast(other.val.ptr)); val.ptr = static_cast(coord); break; } case SV_ITEM: { item_def* item; item = new item_def(*static_cast(other.val.ptr)); val.ptr = static_cast(item); break; } case SV_HASH: { CrawlHashTable* hash; CrawlHashTable* tmp = static_cast(other.val.ptr); hash = new CrawlHashTable(*tmp); val.ptr = static_cast(hash); break; } case SV_VEC: { CrawlVector* vec; CrawlVector* tmp = static_cast(other.val.ptr); vec = new CrawlVector(*tmp); val.ptr = static_cast(vec); break; } case SV_LEV_ID: { level_id* id; id = new level_id(*static_cast(other.val.ptr)); val.ptr = static_cast(id); break; } case SV_LEV_POS: { level_pos* pos; pos = new level_pos(*static_cast(other.val.ptr)); val.ptr = static_cast(pos); break; } case SV_MONST: { monsters* mon; mon = new monsters(*static_cast(other.val.ptr)); val.ptr = static_cast(mon); break; } case SV_LUA: { dlua_chunk* chunk; chunk = new dlua_chunk(*static_cast(other.val.ptr)); val.ptr = static_cast(chunk); 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(SFLAG_UNSET) { get_bool() = _val; } CrawlStoreValue::CrawlStoreValue(const char &_val) : type(SV_BYTE), flags(SFLAG_UNSET) { get_byte() = _val; } CrawlStoreValue::CrawlStoreValue(const short &_val) : type(SV_SHORT), flags(SFLAG_UNSET) { get_short() = _val; } CrawlStoreValue::CrawlStoreValue(const long &_val) : type(SV_LONG), flags(SFLAG_UNSET) { get_long() = _val; } CrawlStoreValue::CrawlStoreValue(const float &_val) : type(SV_FLOAT), flags(SFLAG_UNSET) { get_float() = _val; } CrawlStoreValue::CrawlStoreValue(const std::string &_val) : type(SV_STR), flags(SFLAG_UNSET) { val.ptr = NULL; get_string() = _val; } CrawlStoreValue::CrawlStoreValue(const char* _val) : type(SV_STR), flags(SFLAG_UNSET) { val.ptr = NULL; get_string() = _val; } CrawlStoreValue::CrawlStoreValue(const coord_def &_val) : type(SV_COORD), flags(SFLAG_UNSET) { val.ptr = NULL; get_coord() = _val; } CrawlStoreValue::CrawlStoreValue(const item_def &_val) : type(SV_ITEM), flags(SFLAG_UNSET) { val.ptr = NULL; get_item() = _val; } CrawlStoreValue::CrawlStoreValue(const CrawlHashTable &_val) : type(SV_HASH), flags(SFLAG_UNSET) { val.ptr = NULL; get_table() = _val; } CrawlStoreValue::CrawlStoreValue(const CrawlVector &_val) : type(SV_VEC), flags(SFLAG_UNSET) { val.ptr = NULL; get_vector() = _val; } CrawlStoreValue::CrawlStoreValue(const level_id &_val) : type(SV_LEV_ID), flags(SFLAG_UNSET) { val.ptr = NULL; get_level_id() = _val; } CrawlStoreValue::CrawlStoreValue(const level_pos &_val) : type(SV_LEV_POS), flags(SFLAG_UNSET) { val.ptr = NULL; get_level_pos() = _val; } CrawlStoreValue::CrawlStoreValue(const monsters &_val) : type(SV_MONST), flags(SFLAG_UNSET) { val.ptr = NULL; get_monster() = _val; } CrawlStoreValue::CrawlStoreValue(const dlua_chunk &_val) : type(SV_LUA), flags(SFLAG_UNSET) { val.ptr = NULL; get_lua() = _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(val.ptr); delete str; val.ptr = NULL; break; } case SV_COORD: { coord_def* coord = static_cast(val.ptr); delete coord; val.ptr = NULL; break; } case SV_ITEM: { item_def* item = static_cast(val.ptr); delete item; val.ptr = NULL; break; } case SV_HASH: { CrawlHashTable* hash = static_cast(val.ptr); delete hash; val.ptr = NULL; break; } case SV_VEC: { CrawlVector* vec = static_cast(val.ptr); delete vec; val.ptr = NULL; break; } case SV_LEV_ID: { level_id* id = static_cast(val.ptr); delete id; val.ptr = NULL; break; } case SV_LEV_POS: { level_pos* pos = static_cast(val.ptr); delete pos; val.ptr = NULL; break; } case SV_MONST: { monsters* mon = static_cast(val.ptr); delete mon; val.ptr = NULL; break; } case SV_LUA: { dlua_chunk* chunk = static_cast(val.ptr); delete chunk; val.ptr = NULL; break; } case SV_NONE: DEBUGSTR("CrawlStoreValue::unset: unsetting nothing"); break; default: DEBUGSTR("CrawlStoreValue::unset: unsetting invalid type"); break; } flags |= SFLAG_UNSET; } #define COPY_PTR(ptr_type) \ { \ ptr_type *ptr = static_cast(val.ptr); \ if (ptr != NULL) \ delete ptr; \ ptr = static_cast(other.val.ptr); \ val.ptr = (void*) new ptr_type (*ptr); \ } 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; 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: COPY_PTR(std::string); break; case SV_COORD: COPY_PTR(coord_def); break; case SV_ITEM: COPY_PTR(item_def); break; case SV_HASH: COPY_PTR(CrawlHashTable); break; case SV_VEC: COPY_PTR(CrawlVector); break; case SV_LEV_ID: COPY_PTR(level_id); break; case SV_LEV_POS: COPY_PTR(level_pos); break; default: DEBUGSTR("CrawlStoreValue has invalid type"); break; } 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(writer &th) const { ASSERT(type != SV_NONE || (flags & SFLAG_UNSET)); ASSERT(!(flags & SFLAG_UNSET) || (type == SV_NONE)); 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(val.ptr); marshallString(th, *str); break; } case SV_COORD: { coord_def* coord = static_cast(val.ptr); marshallCoord(th, *coord); break; } case SV_ITEM: { item_def* item = static_cast(val.ptr); marshallItem(th, *item); break; } case SV_HASH: { CrawlHashTable* hash = static_cast(val.ptr); hash->write(th); break; } case SV_VEC: { CrawlVector* vec = static_cast(val.ptr); vec->write(th); break; } case SV_LEV_ID: { level_id* id = static_cast(val.ptr); id->save(th); break; } case SV_LEV_POS: { level_pos* pos = static_cast(val.ptr); pos->save(th); break; } case SV_MONST: { monsters* mon = static_cast(val.ptr); marshallMonster(th, *mon); break; } case SV_LUA: { dlua_chunk* chunk = static_cast(val.ptr); chunk->write(th); break; } case SV_NONE: break; case NUM_STORE_VAL_TYPES: ASSERT(false); } } void CrawlStoreValue::read(reader &th) { type = static_cast(unmarshallByte(th)); flags = (store_flags) unmarshallByte(th); ASSERT(type != SV_NONE || (flags & SFLAG_UNSET)); ASSERT(!(flags & SFLAG_UNSET) || (type == SV_NONE)); 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_LEV_ID: { level_id* id = new level_id(); id->load(th); val.ptr = (void*) id; break; } case SV_LEV_POS: { level_pos* pos = new level_pos(); pos->load(th); val.ptr = (void*) pos; break; } case SV_MONST: { monsters mon; unmarshallMonster(th, mon); val.ptr = (void*) new monsters(mon); break; } case SV_LUA: { dlua_chunk chunk; chunk.read(th); val.ptr = (void*) new dlua_chunk(chunk); break; } case SV_NONE: break; case NUM_STORE_VAL_TYPES: ASSERT(false); } } CrawlHashTable &CrawlStoreValue::new_table() { return get_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) { #ifdef DEBUG CrawlVector* old_vector = static_cast(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)); #endif 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) || (flags & SFLAG_UNSET)) \ { \ if (type == SV_NONE) \ { \ type = (x); \ val.ptr = (value); \ } \ else \ { \ unset(); \ val.ptr = (value); \ type = (x); \ } \ } \ else \ delete (value); \ 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()); } level_id &CrawlStoreValue::get_level_id() { GET_VAL_PTR(SV_LEV_ID, level_id*, new level_id()); } level_pos &CrawlStoreValue::get_level_pos() { GET_VAL_PTR(SV_LEV_POS, level_pos*, new level_pos()); } monsters &CrawlStoreValue::get_monster() { GET_VAL_PTR(SV_MONST, monsters*, new monsters()); } dlua_chunk &CrawlStoreValue::get_lua() { GET_VAL_PTR(SV_LUA, dlua_chunk*, new dlua_chunk()); } 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); } level_id CrawlStoreValue::get_level_id() const { GET_CONST_SETUP(SV_LEV_ID); return *((level_id*)val.ptr); } level_pos CrawlStoreValue::get_level_pos() const { GET_CONST_SETUP(SV_LEV_POS); return *((level_pos*)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(); } CrawlStoreValue::operator level_id&() { return get_level_id(); } CrawlStoreValue::operator level_pos&() { return get_level_pos(); } CrawlStoreValue::operator monsters&() { return get_monster(); } CrawlStoreValue::operator dlua_chunk&() { return get_lua(); } /////////////////////////// // 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(); } CrawlStoreValue::operator level_id() const { return get_level_id(); } CrawlStoreValue::operator level_pos() const { return get_level_pos(); } /////////////////////// // 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); } CrawlStoreValue &CrawlStoreValue::operator = (const level_id &_val) { get_level_id() = _val; return (*this); } CrawlStoreValue &CrawlStoreValue::operator = (const level_pos &_val) { get_level_pos() = _val; return (*this); } CrawlStoreValue &CrawlStoreValue::operator = (const monsters &_val) { get_monster() = _val; return (*this); } CrawlStoreValue &CrawlStoreValue::operator = (const dlua_chunk &_val) { get_lua() = _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() { hash_map = NULL; } CrawlHashTable::CrawlHashTable(const CrawlHashTable& other) { if (other.hash_map == NULL) { hash_map = NULL; return; } hash_map = new hash_map_type(*(other.hash_map)); } CrawlHashTable::~CrawlHashTable() { // NOTE: Not using std::auto_ptr because making hash_map an auto_ptr // causes compile weirdness in externs.h if (hash_map == NULL) return; delete hash_map; hash_map = NULL; } CrawlHashTable &CrawlHashTable::operator = (const CrawlHashTable &other) { if (hash_map != NULL) delete hash_map; if (other.hash_map == NULL) { hash_map = NULL; return (*this); } hash_map = new hash_map_type(*(other.hash_map)); return (*this); } ////////////////////////////// // Read/write from/to savefile void CrawlHashTable::write(writer &th) const { assert_validity(); if (empty()) { marshallByte(th, 0); return; } marshallByte(th, size()); 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(reader &th) { assert_validity(); ASSERT(empty()); hash_size _size = (hash_size) unmarshallByte(th); if (_size == 0) return; init_hash_map(); for (hash_size i = 0; i < _size; i++) { std::string key = unmarshallString(th); CrawlStoreValue &val = (*this)[key]; val.read(th); } assert_validity(); } ////////////////// // Misc functions bool CrawlHashTable::exists(const std::string &key) const { if (hash_map == NULL) return (false); assert_validity(); hash_map_type::const_iterator i = hash_map->find(key); return (i != hash_map->end()); } void CrawlHashTable::assert_validity() const { #ifdef DEBUG if (hash_map == NULL) return; 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.empty()); 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: case SV_LEV_ID: case SV_LEV_POS: ASSERT(val.val.ptr != NULL); break; case SV_HASH: { ASSERT(val.val.ptr != NULL); CrawlHashTable* nested; nested = static_cast(val.val.ptr); nested->assert_validity(); break; } case SV_VEC: { ASSERT(val.val.ptr != NULL); CrawlVector* nested; nested = static_cast(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(); init_hash_map(); iterator i = hash_map->find(key); if (i == hash_map->end()) { (*hash_map)[key] = CrawlStoreValue(); CrawlStoreValue &val = (*hash_map)[key]; return (val); } return (i->second); } const CrawlStoreValue& CrawlHashTable::get_value(const std::string &key) const { ASSERT(hash_map != NULL); 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 { if (hash_map == NULL) return (0); return hash_map->size(); } bool CrawlHashTable::empty() const { if (hash_map == NULL) return (true); return hash_map->empty(); } void CrawlHashTable::erase(const std::string key) { assert_validity(); init_hash_map(); iterator i = hash_map->find(key); if (i != hash_map->end()) { #ifdef DEBUG CrawlStoreValue &val = i->second; ASSERT(!(val.flags & SFLAG_NO_ERASE)); #endif hash_map->erase(i); } } void CrawlHashTable::clear() { assert_validity(); if (hash_map == NULL) return; delete hash_map; hash_map = NULL; } CrawlHashTable::iterator CrawlHashTable::begin() { assert_validity(); init_hash_map(); return hash_map->begin(); } CrawlHashTable::iterator CrawlHashTable::end() { assert_validity(); init_hash_map(); return hash_map->end(); } CrawlHashTable::const_iterator CrawlHashTable::begin() const { ASSERT(hash_map != NULL); assert_validity(); return hash_map->begin(); } CrawlHashTable::const_iterator CrawlHashTable::end() const { ASSERT(hash_map != NULL); assert_validity(); return hash_map->end(); } void CrawlHashTable::init_hash_map() { if (hash_map != NULL) return; hash_map = new hash_map_type(); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// 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(writer &th) const { assert_validity(); if (empty()) { marshallByte(th, 0); return; } marshallByte(th, (char) size()); marshallByte(th, (char) max_size); marshallByte(th, static_cast(type)); marshallByte(th, (char) default_flags); for (vec_size i = 0; i < size(); i++) { CrawlStoreValue val = vector[i]; val.write(th); } assert_validity(); } void CrawlVector::read(reader &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(unmarshallByte(th)); type = static_cast(unmarshallByte(th)); default_flags = static_cast(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 { #ifdef 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]; if (type != SV_NONE) ASSERT(val.type == SV_NONE || val.type == type); // 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: case SV_LEV_ID: case SV_LEV_POS: ASSERT(val.val.ptr != NULL); break; case SV_HASH: { ASSERT(val.val.ptr != NULL); CrawlHashTable* nested; nested = static_cast(val.val.ptr); nested->assert_validity(); break; } case SV_VEC: { ASSERT(val.val.ptr != NULL); CrawlVector* nested; nested = static_cast(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); 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) { #ifdef DEBUG if (type != SV_NONE) ASSERT(type == val.type); switch (val.type) { case SV_STR: case SV_COORD: case SV_ITEM: case SV_LEV_ID: case SV_LEV_POS: ASSERT(val.val.ptr != NULL); break; case SV_HASH: { ASSERT(val.val.ptr != NULL); CrawlHashTable* nested; nested = static_cast(val.val.ptr); nested->assert_validity(); break; } case SV_VEC: { ASSERT(val.val.ptr != NULL); CrawlVector* nested; nested = static_cast(val.val.ptr); nested->assert_validity(); break; } default: break; } #endif 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); assert_validity(); } 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(); default_flags = 0; type = SV_NONE; } 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 CrawlTableWrapper::CrawlTableWrapper() { table = NULL; } template CrawlTableWrapper::CrawlTableWrapper(CrawlHashTable& _table) { wrap(_table); } template CrawlTableWrapper::CrawlTableWrapper(CrawlHashTable* _table) { wrap(_table); } template void CrawlTableWrapper::wrap(CrawlHashTable& _table) { wrap(&_table); } template void CrawlTableWrapper::wrap(CrawlHashTable* _table) { ASSERT(_table != NULL); table = _table; } template T& CrawlTableWrapper::operator[] (const std::string &key) { return (T&) (*table)[key]; } template const T CrawlTableWrapper::operator[] (const std::string &key) const { return (T) (*table)[key]; }