diff options
author | zelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-09 11:39:22 +0000 |
---|---|---|
committer | zelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-10-09 11:39:22 +0000 |
commit | 1202f9248def0a7f685700191d29e97c601c7500 (patch) | |
tree | c2833c8d4c574595bf178814fcf243a1a74ecd4e /crawl-ref | |
parent | 40101238e74b934e879e94e6ae5ec4a6ae86f337 (diff) | |
download | crawl-ref-1202f9248def0a7f685700191d29e97c601c7500.tar.gz crawl-ref-1202f9248def0a7f685700191d29e97c601c7500.zip |
Added an actual vector version of CrawlHashTable, and removed the code
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
Diffstat (limited to 'crawl-ref')
-rw-r--r-- | crawl-ref/source/decks.cc | 116 | ||||
-rw-r--r-- | crawl-ref/source/externs.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/hash.cc | 1260 | ||||
-rw-r--r-- | crawl-ref/source/hash.h | 308 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 4 | ||||
-rw-r--r-- | crawl-ref/source/makefile.obj | 4 | ||||
-rw-r--r-- | crawl-ref/source/store.cc | 1615 | ||||
-rw-r--r-- | crawl-ref/source/store.h | 402 |
8 files changed, 2081 insertions, 1630 deletions
diff --git a/crawl-ref/source/decks.cc b/crawl-ref/source/decks.cc index 1df11df893..5364ef2d44 100644 --- a/crawl-ref/source/decks.cc +++ b/crawl-ref/source/decks.cc @@ -144,7 +144,7 @@ static unsigned long cards_in_deck(const item_def &deck) const CrawlHashTable &props = deck.props; ASSERT(props.exists("cards")); - return (unsigned long) props["cards"].get_table().size(); + return (unsigned long) props["cards"].get_vector().size(); } static void shuffle_deck(item_def &deck) @@ -154,16 +154,14 @@ static void shuffle_deck(item_def &deck) CrawlHashTable &props = deck.props; ASSERT(props.exists("cards")); - CrawlHashTable &cards = props["cards"]; + CrawlVector &cards = props["cards"]; ASSERT(cards.size() > 1); - CrawlHashTable &flags = props["card_flags"]; + CrawlVector &flags = props["card_flags"]; ASSERT(flags.size() == cards.size()); // Don't use std::shuffle(), since we want to apply exactly the // same shuffling to both the cards vector and the flags vector. - // Also, the CrawlHashTable iterator doesn't provide the interface - // required for using it with std::shuffle(). std::vector<long> pos; for (unsigned long i = 0, size = cards.size(); i < size; i++) pos.push_back(random2(size)); @@ -179,8 +177,8 @@ static card_type get_card_and_flags(const item_def& deck, int idx, unsigned char& _flags) { const CrawlHashTable &props = deck.props; - const CrawlHashTable &cards = props["cards"].get_table(); - const CrawlHashTable &flags = props["card_flags"].get_table(); + const CrawlVector &cards = props["cards"].get_vector(); + const CrawlVector &flags = props["card_flags"].get_vector(); if (idx == -1) idx = (int) cards.size() - 1; @@ -194,8 +192,8 @@ static void set_card_and_flags(item_def& deck, int idx, card_type card, unsigned char _flags) { CrawlHashTable &props = deck.props; - CrawlHashTable &cards = props["cards"]; - CrawlHashTable &flags = props["card_flags"]; + CrawlVector &cards = props["cards"]; + CrawlVector &flags = props["card_flags"]; if (idx == -1) idx = (int) cards.size() - 1; @@ -365,8 +363,8 @@ static card_type draw_top_card(item_def& deck, bool message, unsigned char &_flags) { CrawlHashTable &props = deck.props; - CrawlHashTable &cards = props["cards"].get_table(); - CrawlHashTable &flags = props["card_flags"].get_table(); + CrawlVector &cards = props["cards"].get_vector(); + CrawlVector &flags = props["card_flags"].get_vector(); int num_cards = cards.size(); int idx = num_cards - 1; @@ -374,9 +372,8 @@ static card_type draw_top_card(item_def& deck, bool message, ASSERT(num_cards > 0); card_type card = get_card_and_flags(deck, idx, _flags); - - cards.erase(idx); - flags.erase(idx); + cards.pop_back(); + flags.pop_back(); retry_blank_card(card, deck, _flags); @@ -397,13 +394,11 @@ static void push_top_card(item_def& deck, card_type card, unsigned char _flags) { CrawlHashTable &props = deck.props; - CrawlHashTable &cards = props["cards"].get_table(); - CrawlHashTable &flags = props["card_flags"].get_table(); - - int idx = cards.size(); + CrawlVector &cards = props["cards"].get_vector(); + CrawlVector &flags = props["card_flags"].get_vector(); - cards[idx] = (char) card; - flags[idx] = (char) _flags; + cards.push_back((char) card); + flags.push_back((char) _flags); } static bool wielding_deck() @@ -425,33 +420,43 @@ static bool check_buggy_deck(item_def& deck) CrawlHashTable &props = deck.props; - if (!props.exists("cards") || cards_in_deck(deck) == 0) + if (!props.exists("cards") + || props["cards"].get_type() != SV_VEC + || props["cards"].get_vector().get_type() != SV_BYTE + || cards_in_deck(deck) == 0) { crawl_state.zero_turns_taken(); - std::string msg = ""; - if (!props.exists("cards")) - msg += "Seems this deck never had any cards in the first place!"; + msg::stream << "Seems this deck never had any cards in the " + "first place!"; + else if (props["cards"].get_type() != SV_VEC) + msg::stream << "'cards' property isn't a vector."; else { - 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. "; - if (cards_left != 0) + if (cards_in_deck(deck) == 0) { - 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."; + } } } + msg::stream << std::endl; - mpr(msg.c_str()); mpr("A swarm of software bugs snatches the deck from you and " "whisk it away."); @@ -466,32 +471,29 @@ static bool check_buggy_deck(item_def& deck) bool problems = false; - CrawlHashTable &cards = props["cards"].get_table(); - CrawlHashTable &flags = props["card_flags"].get_table(); - - problems = cards.fixup_indexed_array("the card stack"); - problems = flags.fixup_indexed_array("the flag stack"); + CrawlVector &cards = props["cards"].get_vector(); + CrawlVector &flags = props["card_flags"].get_vector(); unsigned long num_cards = cards.size(); unsigned long num_flags = flags.size(); unsigned int num_buggy = 0; unsigned int num_marked = 0; - unsigned int counted_cards = 0; for (unsigned long i = 0; i < num_cards; i++) { - unsigned char card = (unsigned char) cards[i].get_byte(); - unsigned char _flags = (unsigned char) flags[i].get_byte(); + unsigned char card = cards[i].get_byte(); + unsigned char _flags = flags[i].get_byte(); if (card >= NUM_CARDS) { cards.erase(i); flags.erase(i); + i--; + num_cards--; num_buggy++; } else { - counted_cards++; if (_flags & CFLAG_MARKED) num_marked++; } @@ -501,8 +503,6 @@ static bool check_buggy_deck(item_def& deck) { mprf("%d buggy cards found in the deck, discarding them.", num_buggy); - cards.compact_indicies(0, num_cards - 1); - flags.compact_indicies(0, num_flags - 1); deck.plus2 += num_buggy; @@ -512,7 +512,7 @@ static bool check_buggy_deck(item_def& deck) problems = true; } - if (num_cards == 0) + if (num_cards <= 0) { crawl_state.zero_turns_taken(); @@ -567,7 +567,7 @@ static bool check_buggy_deck(item_def& deck) problems = true; } - if (props["num_marked"].get_byte() > (char) counted_cards) + if (props["num_marked"].get_byte() > (char) num_cards) { mpr("More cards marked than in the deck?"); props["num_marked"] = (char) num_marked; @@ -686,8 +686,8 @@ bool deck_peek() return false; } - CrawlHashTable &cards = deck.props["cards"]; - int num_cards = cards.size(); + CrawlVector &cards = deck.props["cards"]; + int num_cards = cards.size(); card_type card1, card2, card3; unsigned char flags1, flags2, flags3; @@ -2141,8 +2141,6 @@ bool top_card_is_known(const item_def &deck) if (!is_deck(deck)) return false; - ASSERT(cards_in_deck(deck) > 0); - unsigned char flags; get_card_and_flags(deck, -1, flags); @@ -2154,8 +2152,6 @@ card_type top_card(const item_def &deck) if (!is_deck(deck)) return NUM_CARDS; - ASSERT(cards_in_deck(deck) > 0); - unsigned char flags; card_type card = get_card_and_flags(deck, -1, flags); @@ -2177,7 +2173,9 @@ bool bad_deck(const item_def &item) return false; return (!item.props.exists("cards") - || item.props["cards"].get_table().get_type() != HV_BYTE); + || item.props["cards"].get_type() != SV_VEC + || item.props["cards"].get_vector().get_type() != SV_BYTE + || cards_in_deck(item) == 0); } deck_rarity_type deck_rarity(const item_def &item) @@ -2221,10 +2219,10 @@ void init_deck(item_def &item) ASSERT(item.special >= DECK_RARITY_COMMON && item.special <= DECK_RARITY_LEGENDARY); - props.set_default_flags(HFLAG_CONST_TYPE); + props.set_default_flags(SFLAG_CONST_TYPE); - props["cards"].new_table(HV_BYTE); - props["card_flags"].new_table(HV_BYTE); + props["cards"].new_vector(SV_BYTE).resize(item.plus); + props["card_flags"].new_vector(SV_BYTE).resize(item.plus); for (int i = 0; i < item.plus; i++) { diff --git a/crawl-ref/source/externs.h b/crawl-ref/source/externs.h index f94cdd07f6..6d505674f4 100644 --- a/crawl-ref/source/externs.h +++ b/crawl-ref/source/externs.h @@ -30,9 +30,9 @@ #include "defines.h" #include "enum.h" #include "FixAry.h" -#include "hash.h" #include "libutil.h" #include "mpr.h" +#include "store.h" #define INFO_SIZE 200 // size of message buffers #define ITEMNAME_SIZE 200 // size of item names/shop names/etc diff --git a/crawl-ref/source/hash.cc b/crawl-ref/source/hash.cc deleted file mode 100644 index 60a5816f9c..0000000000 --- a/crawl-ref/source/hash.cc +++ /dev/null @@ -1,1260 +0,0 @@ -/* - * 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]; -} diff --git a/crawl-ref/source/hash.h b/crawl-ref/source/hash.h deleted file mode 100644 index 7c658c1667..0000000000 --- a/crawl-ref/source/hash.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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 diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 35e84a18d9..c50d7e5efc 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -264,6 +264,7 @@ bool dec_inv_item_quantity( int obj, int amount ) you.inv[obj].base_type = OBJ_UNASSIGNED; you.inv[obj].quantity = 0; + you.inv[obj].props.clear(); ret = true; @@ -462,6 +463,7 @@ void unlink_item( int dest ) mitm[dest].x = 0; mitm[dest].y = 0; mitm[dest].link = NON_ITEM; + mitm[dest].props.clear(); // Look through all items for links to this item. for (c = 0; c < MAX_ITEMS; c++) @@ -579,6 +581,7 @@ void lose_item_stack( int x, int y ) mitm[o].base_type = OBJ_UNASSIGNED; mitm[o].quantity = 0; + mitm[o].props.clear(); } o = next; @@ -601,6 +604,7 @@ void destroy_item_stack( int x, int y, int cause ) mitm[o].base_type = OBJ_UNASSIGNED; mitm[o].quantity = 0; + mitm[o].props.clear(); } o = next; diff --git a/crawl-ref/source/makefile.obj b/crawl-ref/source/makefile.obj index f871fa43f6..170eb8b367 100644 --- a/crawl-ref/source/makefile.obj +++ b/crawl-ref/source/makefile.obj @@ -12,8 +12,8 @@ cloud.o \ command.o \ database.o \ debug.o \ -delay.o \ decks.o \ +delay.o \ describe.o \ dgnevent.o \ direct.o \ @@ -24,7 +24,6 @@ files.o \ food.o \ format.o \ ghost.o \ -hash.o \ hiscores.o \ initfile.o \ insult.o \ @@ -76,6 +75,7 @@ spl-util.o \ sqldbm.o \ state.o \ stash.o \ +store.o \ stuff.o \ tags.o \ terrain.o \ diff --git a/crawl-ref/source/store.cc b/crawl-ref/source/store.cc new file mode 100644 index 0000000000..912369b27a --- /dev/null +++ b/crawl-ref/source/store.cc @@ -0,0 +1,1615 @@ +/* + * 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]; +} diff --git a/crawl-ref/source/store.h b/crawl-ref/source/store.h new file mode 100644 index 0000000000..b65298b514 --- /dev/null +++ b/crawl-ref/source/store.h @@ -0,0 +1,402 @@ +/* + * 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 |