truelight@9579: /* $Id$ */ truelight@9579: truelight@9593: /** @file ai_abstractlist.cpp Implementation of AIAbstractList */ truelight@9579: truelight@9593: #include "ai_abstractlist.hpp" truelight@9579: truelight@9579: /** truelight@9593: * Base class for any AIAbstractList sorter. truelight@9579: */ truelight@9593: class AIAbstractListSorter { truelight@9579: protected: truelight@9593: AIAbstractList *list; truelight@9579: truelight@9579: public: truelight@9579: /** truelight@9579: * Virtual dtor, needed to mute warnings. truelight@9579: */ truelight@9593: virtual ~AIAbstractListSorter() { } truelight@9579: truelight@9579: /** truelight@9579: * Get the first item of the sorter. truelight@9579: */ truelight@9579: virtual int32 Begin() = 0; truelight@9579: truelight@9579: /** truelight@9579: * Get the next item of the sorter. truelight@9579: */ truelight@9579: virtual int32 Next() = 0; truelight@9579: truelight@9579: /** truelight@9579: * See if there is a next item of the sorter. truelight@9579: */ truelight@9579: virtual bool HasNext() = 0; truelight@9579: }; truelight@9579: truelight@9579: /** truelight@9579: * Sort by value, ascending. truelight@9579: */ truelight@9593: class AIAbstractListSorterValueAscending : public AIAbstractListSorter { truelight@9579: private: truelight@9593: AIAbstractList::AIAbstractListBucket::iterator bucket_iter; truelight@9593: AIAbstractList::AIItemList *bucket_list; truelight@9593: AIAbstractList::AIItemList::iterator bucket_list_iter; truelight@9579: truelight@9579: public: truelight@9593: AIAbstractListSorterValueAscending(AIAbstractList *list) truelight@9579: { truelight@9579: this->list = list; truelight@9579: } truelight@9579: truelight@9579: int32 Begin() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return 0; truelight@9606: truelight@9579: this->bucket_iter = this->list->buckets.begin(); truelight@9579: this->bucket_list = &(*this->bucket_iter).second; truelight@9579: this->bucket_list_iter = this->bucket_list->begin(); truelight@9579: return *bucket_list_iter; truelight@9579: } truelight@9579: truelight@9579: int32 Next() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return 0; truelight@9606: truelight@9579: this->bucket_list_iter++; truelight@9579: if (this->bucket_list_iter == this->bucket_list->end()) { truelight@9579: this->bucket_iter++; truelight@9579: if (this->bucket_iter == this->list->buckets.end()) return 0; truelight@9579: this->bucket_list = &(*this->bucket_iter).second; truelight@9579: this->bucket_list_iter = this->bucket_list->begin(); truelight@9579: } truelight@9579: return *bucket_list_iter; truelight@9579: } truelight@9579: truelight@9579: bool HasNext() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return false; truelight@9606: truelight@9579: return this->bucket_iter != this->list->buckets.end() && this->bucket_list_iter != this->bucket_list->end(); truelight@9579: } truelight@9579: }; truelight@9579: truelight@9579: /** truelight@9579: * Sort by value, descending. truelight@9579: */ truelight@9593: class AIAbstractListSorterValueDescending : public AIAbstractListSorter { truelight@9579: private: truelight@9593: AIAbstractList::AIAbstractListBucket::reverse_iterator bucket_iter; truelight@9593: AIAbstractList::AIItemList *bucket_list; truelight@9593: AIAbstractList::AIItemList::reverse_iterator bucket_list_iter; truelight@9579: truelight@9579: public: truelight@9593: AIAbstractListSorterValueDescending(AIAbstractList *list) truelight@9579: { truelight@9579: this->list = list; truelight@9579: } truelight@9579: truelight@9579: int32 Begin() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return 0; truelight@9606: truelight@9579: this->bucket_iter = this->list->buckets.rbegin(); truelight@9579: this->bucket_list = &(*this->bucket_iter).second; truelight@9579: this->bucket_list_iter = this->bucket_list->rbegin(); truelight@9579: return *bucket_list_iter; truelight@9579: } truelight@9579: truelight@9579: int32 Next() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return 0; truelight@9606: truelight@9579: this->bucket_list_iter++; truelight@9579: if (this->bucket_list_iter == this->bucket_list->rend()) { truelight@9579: this->bucket_iter++; truelight@9579: if (this->bucket_iter == this->list->buckets.rend()) return 0; truelight@9579: this->bucket_list = &(*this->bucket_iter).second; truelight@9579: this->bucket_list_iter = this->bucket_list->rbegin(); truelight@9579: } truelight@9579: return *bucket_list_iter; truelight@9579: } truelight@9579: truelight@9579: bool HasNext() truelight@9579: { truelight@9606: if (this->list->buckets.empty()) return false; truelight@9606: truelight@9579: return this->bucket_iter != this->list->buckets.rend() && this->bucket_list_iter != this->bucket_list->rend(); truelight@9579: } truelight@9579: }; truelight@9579: truelight@9579: /** truelight@9579: * Sort by item, ascending. truelight@9579: */ truelight@9593: class AIAbstractListSorterItemAscending : public AIAbstractListSorter { truelight@9579: private: truelight@9593: AIAbstractList::AIAbstractListMap::iterator item_iter; truelight@9579: truelight@9579: public: truelight@9593: AIAbstractListSorterItemAscending(AIAbstractList *list) truelight@9579: { truelight@9579: this->list = list; truelight@9579: } truelight@9579: truelight@9579: int32 Begin() truelight@9579: { truelight@9606: if (this->list->items.empty()) return 0; truelight@9606: truelight@9579: this->item_iter = this->list->items.begin(); truelight@9579: return (*this->item_iter).first; truelight@9579: } truelight@9579: truelight@9579: int32 Next() truelight@9579: { truelight@9606: if (this->list->items.empty()) return 0; truelight@9606: truelight@9579: this->item_iter++; truelight@9579: return (*this->item_iter).first; truelight@9579: } truelight@9579: truelight@9579: bool HasNext() truelight@9579: { truelight@9606: if (this->list->items.empty()) return false; truelight@9606: truelight@9579: return this->item_iter != this->list->items.end(); truelight@9579: } truelight@9579: }; truelight@9579: truelight@9579: /** truelight@9579: * Sort by item, descending. truelight@9579: */ truelight@9593: class AIAbstractListSorterItemDescending : public AIAbstractListSorter { truelight@9579: private: truelight@9593: AIAbstractList::AIAbstractListMap::reverse_iterator item_iter; truelight@9579: truelight@9579: public: truelight@9593: AIAbstractListSorterItemDescending(AIAbstractList *list) truelight@9579: { truelight@9579: this->list = list; truelight@9579: } truelight@9579: truelight@9579: int32 Begin() truelight@9579: { truelight@9606: if (this->list->items.empty()) return 0; truelight@9606: truelight@9579: this->item_iter = this->list->items.rbegin(); truelight@9579: return (*this->item_iter).first; truelight@9579: } truelight@9579: truelight@9579: int32 Next() truelight@9579: { truelight@9606: if (this->list->items.empty()) return 0; truelight@9606: truelight@9579: this->item_iter++; truelight@9579: return (*this->item_iter).first; truelight@9579: } truelight@9579: truelight@9579: bool HasNext() truelight@9579: { truelight@9606: if (this->list->items.empty()) return false; truelight@9606: truelight@9579: return this->item_iter != this->list->items.rend(); truelight@9579: } truelight@9579: }; truelight@9579: truelight@9579: truelight@9579: truelight@9593: AIAbstractList::AIAbstractList() truelight@9579: { truelight@9579: /* Default sorter */ rubidium@9665: this->sorter = new AIAbstractListSorterValueDescending(this); rubidium@9665: this->sorter_type = SORT_BY_VALUE; rubidium@9665: this->sort_ascending = false; truelight@9579: } truelight@9579: truelight@9593: AIAbstractList::~AIAbstractList() truelight@9579: { truelight@9579: delete this->sorter; truelight@9579: } truelight@9579: truelight@9593: bool AIAbstractList::HasItem(int32 item) truelight@9579: { truelight@9579: return this->items.count(item) == 1; truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::Clear() truelight@9579: { truelight@9579: this->items.clear(); truelight@9579: this->buckets.clear(); truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::AddItem(int32 item) truelight@9579: { truelight@9579: if (this->HasItem(item)) return; truelight@9579: truelight@9579: this->items[item] = 0; truelight@9579: this->buckets[0].insert(item); truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::RemoveItem(int32 item) truelight@9579: { truelight@9579: if (!this->HasItem(item)) return; truelight@9579: truelight@9579: this->buckets[this->GetValue(item)].erase(item); truelight@9664: if (this->buckets[this->GetValue(item)].empty()) this->buckets.erase(this->GetValue(item)); truelight@9579: this->items.erase(item); truelight@9579: } truelight@9579: truelight@9593: int32 AIAbstractList::Begin() truelight@9579: { truelight@9579: return this->sorter->Begin(); truelight@9579: } truelight@9579: truelight@9593: int32 AIAbstractList::Next() truelight@9579: { truelight@9579: return this->sorter->Next(); truelight@9579: } truelight@9579: truelight@9593: bool AIAbstractList::IsEmpty() truelight@9579: { truelight@9579: return this->items.empty(); truelight@9579: } truelight@9579: truelight@9593: bool AIAbstractList::HasNext() truelight@9579: { truelight@9579: return this->sorter->HasNext(); truelight@9579: } truelight@9579: truelight@9593: int32 AIAbstractList::Count() truelight@9579: { truelight@9579: return this->items.size(); truelight@9579: } truelight@9579: truelight@9593: int32 AIAbstractList::GetValue(int32 item) truelight@9579: { truelight@9579: if (!this->HasItem(item)) return 0; truelight@9579: truelight@9579: return this->items[item]; truelight@9579: } truelight@9579: truelight@9664: bool AIAbstractList::SetValue(int32 item, int32 value) truelight@9664: { truelight@9664: if (!this->HasItem(item)) return false; truelight@9664: truelight@9664: this->buckets[this->GetValue(item)].erase(item); truelight@9664: if (this->buckets[this->GetValue(item)].empty()) this->buckets.erase(this->GetValue(item)); truelight@9664: this->items[item] = value; truelight@9664: this->buckets[value].insert(item); truelight@9664: truelight@9664: return true; truelight@9664: } truelight@9664: rubidium@9665: void AIAbstractList::Sort(SorterType sorter, bool ascending) truelight@9579: { rubidium@9665: if (sorter == this->sorter_type && ascending == this->sort_ascending) return; rubidium@9665: truelight@9579: delete this->sorter; rubidium@9665: switch (sorter) { rubidium@9665: case SORT_BY_ITEM: rubidium@9665: if (ascending) this->sorter = new AIAbstractListSorterItemAscending(this); rubidium@9665: else this->sorter = new AIAbstractListSorterItemDescending(this); rubidium@9665: break; truelight@9579: rubidium@9665: case SORT_BY_VALUE: rubidium@9702: if (ascending) this->sorter = new AIAbstractListSorterValueAscending(this); rubidium@9702: else this->sorter = new AIAbstractListSorterValueDescending(this); rubidium@9665: break; rubidium@9665: rubidium@9665: default: rubidium@9665: this->Sort(SORT_BY_ITEM, false); rubidium@9665: return; rubidium@9665: } rubidium@9665: this->sorter_type = sorter; rubidium@9665: this->sort_ascending = ascending; truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::RemoveAboveValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second > value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first > value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::RemoveBelowValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second < value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first < value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::RemoveBetweenValue(int32 start, int32 end) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second > start && (*iter).second < end) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::RemoveValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second == value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first == value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: rubidium@9665: void AIAbstractList::RemoveTop(int32 count) rubidium@9665: { rubidium@9665: if (!this->sort_ascending) { rubidium@9665: this->Sort(this->sorter_type, !this->sort_ascending); rubidium@9665: this->RemoveBottom(count); rubidium@9665: this->Sort(this->sorter_type, !this->sort_ascending); rubidium@9665: return; rubidium@9665: } rubidium@9665: rubidium@9665: switch (this->sorter_type) { rubidium@9665: default: NOT_REACHED(); rubidium@9665: case SORT_BY_VALUE: glx@9731: for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) { rubidium@9665: AIItemList *items = &(*iter).second; glx@9731: size_t size = items->size(); glx@9731: for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) { rubidium@9665: if (--count < 0) return; rubidium@9665: this->RemoveItem(*iter); glx@9731: /* When the last item is removed from the bucket, the bucket itself is removed. glx@9731: * This means that the iterators can be invalid after a call to RemoveItem. glx@9731: */ glx@9731: if (--size == 0) break; rubidium@9665: } rubidium@9665: } rubidium@9665: break; rubidium@9665: rubidium@9665: case SORT_BY_ITEM: glx@9731: for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) { rubidium@9665: if (--count < 0) return; rubidium@9665: this->RemoveItem((*iter).first); rubidium@9665: } rubidium@9665: break; rubidium@9665: } rubidium@9665: } rubidium@9665: rubidium@9665: void AIAbstractList::RemoveBottom(int32 count) rubidium@9665: { rubidium@9665: if (!this->sort_ascending) { rubidium@9665: this->Sort(this->sorter_type, !this->sort_ascending); rubidium@9665: this->RemoveTop(count); rubidium@9665: this->Sort(this->sorter_type, !this->sort_ascending); rubidium@9665: return; rubidium@9665: } rubidium@9665: rubidium@9665: switch (this->sorter_type) { rubidium@9665: default: NOT_REACHED(); rubidium@9665: case SORT_BY_VALUE: glx@9731: for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) { rubidium@9665: AIItemList *items = &(*iter).second; glx@9731: size_t size = items->size(); glx@9731: for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) { rubidium@9665: if (--count < 0) return; glx@9731: this->RemoveItem(*iter); glx@9731: /* When the last item is removed from the bucket, the bucket itself is removed. glx@9731: * This means that the iterators can be invalid after a call to RemoveItem. rubidium@9721: */ glx@9731: if (--size == 0) break; rubidium@9665: } rubidium@9665: } rubidium@9665: rubidium@9665: case SORT_BY_ITEM: glx@9731: for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) { rubidium@9665: if (--count < 0) return; rubidium@9665: this->RemoveItem((*iter).first); rubidium@9665: } rubidium@9665: break; rubidium@9665: } rubidium@9665: } rubidium@9665: rubidium@9665: void AIAbstractList::RemoveList(AIAbstractList *list) rubidium@9665: { rubidium@9665: AIAbstractListMap *list_items = &list->items; rubidium@9665: for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) { rubidium@9665: this->RemoveItem((*iter).first); rubidium@9665: } rubidium@9665: } rubidium@9665: truelight@9593: void AIAbstractList::KeepAboveValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second <= value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first <= value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::KeepBelowValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second >= value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first >= value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::KeepBetweenValue(int32 start, int32 end) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: truelight@9593: void AIAbstractList::KeepValue(int32 value) truelight@9579: { truelight@9593: for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).second != value) this->items.erase(iter); truelight@9579: } truelight@9579: truelight@9593: for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { truelight@9581: next_iter = iter; next_iter++; truelight@9579: if ((*iter).first != value) this->buckets.erase(iter); truelight@9579: } truelight@9579: } truelight@9579: rubidium@9665: void AIAbstractList::KeepTop(int32 count) rubidium@9665: { rubidium@9665: this->RemoveBottom(this->Count() - count); rubidium@9665: } rubidium@9665: rubidium@9665: void AIAbstractList::KeepBottom(int32 count) rubidium@9665: { rubidium@9665: this->RemoveTop(this->Count() - count); rubidium@9665: } rubidium@9665: rubidium@9665: void AIAbstractList::KeepList(AIAbstractList *list) rubidium@9665: { rubidium@9665: AIAbstractList tmp; rubidium@9665: for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) { rubidium@9665: tmp.AddItem((*iter).first); rubidium@9665: tmp.SetValue((*iter).first, (*iter).second); rubidium@9665: } rubidium@9665: rubidium@9665: tmp.RemoveList(list); rubidium@9665: this->RemoveList(&tmp); rubidium@9665: } rubidium@9665: truelight@9593: void AIAbstractList::Valuate(const AIAbstractList::Valuator &proc) truelight@9579: { truelight@9579: this->buckets.clear(); truelight@9593: for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) { truelight@9589: int32 value = proc.Valuate((*iter).first); truelight@9579: (*iter).second = value; truelight@9579: this->buckets[value].insert((*iter).first); truelight@9579: } truelight@9579: }