/* $Id$ */ /** @file ai_abstractlist.cpp Implementation of AIAbstractList. */ #include #include "ai_abstractlist.hpp" #include "../../debug.h" #include "../../core/alloc_func.hpp" /** * Base class for any AIAbstractList sorter. */ class AIAbstractListSorter { protected: AIAbstractList *list; public: /** * Virtual dtor, needed to mute warnings. */ virtual ~AIAbstractListSorter() { } /** * Get the first item of the sorter. */ virtual int32 Begin() = 0; /** * Stop iterating a sorter. */ virtual void End() = 0; /** * Get the next item of the sorter. */ virtual int32 Next() = 0; /** * See if there is a next item of the sorter. */ virtual bool HasNext() = 0; /** * Callback from the list if an item gets removed. */ virtual void Remove(int item) = 0; }; /** * Sort by value, ascending. */ class AIAbstractListSorterValueAscending : public AIAbstractListSorter { private: AIAbstractList::AIAbstractListBucket::iterator bucket_iter; AIAbstractList::AIItemList *bucket_list; AIAbstractList::AIItemList::iterator bucket_list_iter; bool has_no_more_items; int32 item_next; public: AIAbstractListSorterValueAscending(AIAbstractList *list) { this->list = list; this->End(); } int32 Begin() { if (this->list->buckets.empty()) return 0; this->has_no_more_items = false; this->bucket_iter = this->list->buckets.begin(); this->bucket_list = &(*this->bucket_iter).second; this->bucket_list_iter = this->bucket_list->begin(); this->item_next = *this->bucket_list_iter; int32 item_current = this->item_next; FindNext(); return item_current; } void End() { this->bucket_list = NULL; this->has_no_more_items = true; this->item_next = 0; } void FindNext() { if (this->bucket_list == NULL) { this->has_no_more_items = true; return; } this->bucket_list_iter++; if (this->bucket_list_iter == this->bucket_list->end()) { this->bucket_iter++; if (this->bucket_iter == this->list->buckets.end()) { this->bucket_list = NULL; return; } this->bucket_list = &(*this->bucket_iter).second; this->bucket_list_iter = this->bucket_list->begin(); } this->item_next = *this->bucket_list_iter; } int32 Next() { if (!this->HasNext()) return 0; int32 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (!this->HasNext()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } bool HasNext() { return !(this->list->buckets.empty() || this->has_no_more_items); } }; /** * Sort by value, descending. */ class AIAbstractListSorterValueDescending : public AIAbstractListSorter { private: AIAbstractList::AIAbstractListBucket::iterator bucket_iter; AIAbstractList::AIItemList *bucket_list; AIAbstractList::AIItemList::iterator bucket_list_iter; bool has_no_more_items; int32 item_next; public: AIAbstractListSorterValueDescending(AIAbstractList *list) { this->list = list; this->End(); } int32 Begin() { if (this->list->buckets.empty()) return 0; this->has_no_more_items = false; /* Go to the end of the bucket-list */ this->bucket_iter = this->list->buckets.begin(); for (size_t i = this->list->buckets.size(); i > 1; i--) this->bucket_iter++; this->bucket_list = &(*this->bucket_iter).second; /* Go to the end of the items in the bucket */ this->bucket_list_iter = this->bucket_list->begin(); for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++; this->item_next = *this->bucket_list_iter; int32 item_current = this->item_next; FindNext(); return item_current; } void End() { this->bucket_list = NULL; this->has_no_more_items = true; this->item_next = 0; } void FindNext() { if (this->bucket_list == NULL) { this->has_no_more_items = true; return; } if (this->bucket_list_iter == this->bucket_list->begin()) { if (this->bucket_iter == this->list->buckets.begin()) { this->bucket_list = NULL; return; } this->bucket_iter--; this->bucket_list = &(*this->bucket_iter).second; /* Go to the end of the items in the bucket */ this->bucket_list_iter = this->bucket_list->begin(); for (size_t i = this->bucket_list->size(); i > 1; i--) this->bucket_list_iter++; } else { this->bucket_list_iter--; } this->item_next = *this->bucket_list_iter; } int32 Next() { if (!this->HasNext()) return 0; int32 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (!this->HasNext()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } bool HasNext() { return !(this->list->buckets.empty() || this->has_no_more_items); } }; /** * Sort by item, ascending. */ class AIAbstractListSorterItemAscending : public AIAbstractListSorter { private: AIAbstractList::AIAbstractListMap::iterator item_iter; bool has_no_more_items; int32 item_next; public: AIAbstractListSorterItemAscending(AIAbstractList *list) { this->list = list; this->End(); } int32 Begin() { if (this->list->items.empty()) return 0; this->has_no_more_items = false; this->item_iter = this->list->items.begin(); this->item_next = (*this->item_iter).first; int32 item_current = this->item_next; FindNext(); return item_current; } void End() { this->has_no_more_items = true; } void FindNext() { if (this->item_iter == this->list->items.end()) { this->has_no_more_items = true; return; } this->item_iter++; if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first; } int32 Next() { if (!this->HasNext()) return 0; int32 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (!this->HasNext()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } bool HasNext() { return !(this->list->items.empty() || this->has_no_more_items); } }; /** * Sort by item, descending. */ class AIAbstractListSorterItemDescending : public AIAbstractListSorter { private: AIAbstractList::AIAbstractListMap::iterator item_iter; bool has_no_more_items; int32 item_next; public: AIAbstractListSorterItemDescending(AIAbstractList *list) { this->list = list; this->End(); } int32 Begin() { if (this->list->items.empty()) return 0; this->has_no_more_items = false; this->item_iter = this->list->items.begin(); for (size_t i = this->list->items.size(); i > 1; i--) this->item_iter++; this->item_next = (*this->item_iter).first; int32 item_current = this->item_next; FindNext(); return item_current; } void End() { this->has_no_more_items = true; } void FindNext() { if (this->item_iter == this->list->items.end()) { this->has_no_more_items = true; return; } this->item_iter--; if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first; } int32 Next() { if (!this->HasNext()) return 0; int32 item_current = this->item_next; FindNext(); return item_current; } void Remove(int item) { if (!this->HasNext()) return; /* If we remove the 'next' item, skip to the next */ if (item == this->item_next) { FindNext(); return; } } bool HasNext() { return !(this->list->items.empty() || this->has_no_more_items); } }; AIAbstractList::AIAbstractList() { /* Default sorter */ this->sorter = new AIAbstractListSorterValueDescending(this); this->sorter_type = SORT_BY_VALUE; this->sort_ascending = false; this->initialized = false; } AIAbstractList::~AIAbstractList() { delete this->sorter; } bool AIAbstractList::HasItem(int32 item) { return this->items.count(item) == 1; } void AIAbstractList::Clear() { this->items.clear(); this->buckets.clear(); this->sorter->End(); } void AIAbstractList::AddItem(int32 item) { if (this->HasItem(item)) return; this->items[item] = 0; this->buckets[0].insert(item); } void AIAbstractList::RemoveItem(int32 item) { if (!this->HasItem(item)) return; int32 value = this->GetValue(item); this->sorter->Remove(item); this->buckets[value].erase(item); if (this->buckets[value].empty()) this->buckets.erase(value); this->items.erase(item); } int32 AIAbstractList::Begin() { this->initialized = true; return this->sorter->Begin(); } int32 AIAbstractList::Next() { if (this->initialized == false) { DEBUG(ai, 0, "ERROR: Next() is invalid as Begin() is never called"); return false; } return this->sorter->Next(); } bool AIAbstractList::IsEmpty() { return this->items.empty(); } bool AIAbstractList::HasNext() { if (this->initialized == false) { DEBUG(ai, 0, "ERROR: HasNext() is invalid as Begin() is never called"); return false; } return this->sorter->HasNext(); } int32 AIAbstractList::Count() { return (int32)this->items.size(); } int32 AIAbstractList::GetValue(int32 item) { if (!this->HasItem(item)) return 0; return this->items[item]; } bool AIAbstractList::SetValue(int32 item, int32 value) { if (!this->HasItem(item)) return false; int32 value_old = this->GetValue(item); this->sorter->Remove(item); this->buckets[value_old].erase(item); if (this->buckets[value_old].empty()) this->buckets.erase(value_old); this->items[item] = value; this->buckets[value].insert(item); return true; } void AIAbstractList::Sort(SorterType sorter, bool ascending) { if (sorter != SORT_BY_VALUE && sorter != SORT_BY_ITEM) return; if (sorter == this->sorter_type && ascending == this->sort_ascending) return; delete this->sorter; switch (sorter) { case SORT_BY_ITEM: if (ascending) this->sorter = new AIAbstractListSorterItemAscending(this); else this->sorter = new AIAbstractListSorterItemDescending(this); break; case SORT_BY_VALUE: if (ascending) this->sorter = new AIAbstractListSorterValueAscending(this); else this->sorter = new AIAbstractListSorterValueDescending(this); break; default: this->Sort(SORT_BY_ITEM, false); return; } this->sorter_type = sorter; this->sort_ascending = ascending; } void AIAbstractList::AddList(AIAbstractList *list) { AIAbstractListMap *list_items = &list->items; for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) { this->AddItem((*iter).first); this->SetValue((*iter).first, (*iter).second); } } void AIAbstractList::RemoveAboveValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second > value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first > value) this->buckets.erase(iter); } } void AIAbstractList::RemoveBelowValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second < value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first < value) this->buckets.erase(iter); } } void AIAbstractList::RemoveBetweenValue(int32 start, int32 end) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second > start && (*iter).second < end) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first > start && (*iter).first < end) this->buckets.erase(iter); } } void AIAbstractList::RemoveValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second == value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first == value) this->buckets.erase(iter); } } void AIAbstractList::RemoveTop(int32 count) { if (!this->sort_ascending) { this->Sort(this->sorter_type, !this->sort_ascending); this->RemoveBottom(count); this->Sort(this->sorter_type, !this->sort_ascending); return; } switch (this->sorter_type) { default: NOT_REACHED(); case SORT_BY_VALUE: for (AIAbstractListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) { AIItemList *items = &(*iter).second; size_t size = items->size(); for (AIItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) { if (--count < 0) return; this->RemoveItem(*iter); /* When the last item is removed from the bucket, the bucket itself is removed. * This means that the iterators can be invalid after a call to RemoveItem. */ if (--size == 0) break; } } break; case SORT_BY_ITEM: for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) { if (--count < 0) return; this->RemoveItem((*iter).first); } break; } } void AIAbstractList::RemoveBottom(int32 count) { if (!this->sort_ascending) { this->Sort(this->sorter_type, !this->sort_ascending); this->RemoveTop(count); this->Sort(this->sorter_type, !this->sort_ascending); return; } switch (this->sorter_type) { default: NOT_REACHED(); case SORT_BY_VALUE: for (AIAbstractListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) { AIItemList *items = &(*iter).second; size_t size = items->size(); for (AIItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) { if (--count < 0) return; this->RemoveItem(*iter); /* When the last item is removed from the bucket, the bucket itself is removed. * This means that the iterators can be invalid after a call to RemoveItem. */ if (--size == 0) break; } } case SORT_BY_ITEM: for (AIAbstractListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) { if (--count < 0) return; this->RemoveItem((*iter).first); } break; } } void AIAbstractList::RemoveList(AIAbstractList *list) { AIAbstractListMap *list_items = &list->items; for (AIAbstractListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) { this->RemoveItem((*iter).first); } } void AIAbstractList::KeepAboveValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second <= value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first <= value) this->buckets.erase(iter); } } void AIAbstractList::KeepBelowValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second >= value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first >= value) this->buckets.erase(iter); } } void AIAbstractList::KeepBetweenValue(int32 start, int32 end) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second <= start || (*iter).second >= end) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first <= start || (*iter).first >= end) this->buckets.erase(iter); } } void AIAbstractList::KeepValue(int32 value) { for (AIAbstractListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).second != value) this->items.erase(iter); } for (AIAbstractListBucket::iterator next_iter, iter = this->buckets.begin(); iter != this->buckets.end(); iter = next_iter) { next_iter = iter; next_iter++; if ((*iter).first != value) this->buckets.erase(iter); } } void AIAbstractList::KeepTop(int32 count) { this->RemoveBottom(this->Count() - count); } void AIAbstractList::KeepBottom(int32 count) { this->RemoveTop(this->Count() - count); } void AIAbstractList::KeepList(AIAbstractList *list) { AIAbstractList tmp; for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) { tmp.AddItem((*iter).first); tmp.SetValue((*iter).first, (*iter).second); } tmp.RemoveList(list); this->RemoveList(&tmp); } SQInteger AIAbstractList::_get(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR; SQInteger idx; sq_getinteger(vm, 2, &idx); if (!this->HasItem(idx)) return SQ_ERROR; sq_pushinteger(vm, this->GetValue(idx)); return 1; } SQInteger AIAbstractList::_nexti(HSQUIRRELVM vm) { if (sq_gettype(vm, 2) == OT_NULL) { if (this->IsEmpty()) { sq_pushnull(vm); return 1; } sq_pushinteger(vm, this->Begin()); return 1; } SQInteger idx; sq_getinteger(vm, 2, &idx); int val = this->Next(); if (!this->HasNext()) { sq_pushnull(vm); return 1; } sq_pushinteger(vm, val); return 1; } SQInteger AIAbstractList::Valuate(HSQUIRRELVM vm) { int nparam = sq_gettop(vm) - 2; /* Get the list instance and the function to call */ HSQOBJECT obj_list, obj_func; sq_getstackobj(vm, 1, &obj_list); sq_getstackobj(vm, 2, &obj_func); if (sq_isclass(obj_list)) { return sq_throwerror(vm, _SC("parameter 1 has an invalid type (expected instance)")); } if (sq_isfunction(obj_func)) { return sq_throwerror(vm, _SC("parameter 2 has an invalid type (expected function)")); } sq_addref(vm, &obj_func); /* Read the params */ HSQOBJECT *obj_params = AllocaM(HSQOBJECT, nparam); for (int i = 0; i < nparam; i++) { sq_getstackobj(vm, i + 3, &obj_params[i]); sq_addref(vm, &obj_params[i]); } /* Remove all unneeded stuff */ sq_pop(vm, nparam + 1); /* Walk all items, and query the result */ this->buckets.clear(); for (AIAbstractListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) { /* The function to call */ sq_pushobject(vm, obj_func); /* The 'list' instance; this is most likely wrong, but we need to send something ;) */ sq_pushobject(vm, obj_list); /* Now send the params */ sq_pushinteger(vm, (*iter).first); for (int i = 0; i < nparam; i++) { sq_pushobject(vm, obj_params[i]); } /* Call the function */ if (SQ_FAILED(sq_call(vm, nparam + 2, SQTrue, SQTrue))) return SQ_ERROR; /* Retreive the return value */ SQInteger value; switch (sq_gettype(vm, -1)) { case OT_INTEGER: { sq_getinteger(vm, -1, &value); } break; case OT_BOOL: { SQBool v; sq_getbool(vm, -1, &v); value = v ? 1 : 0; } break; default: { sq_pop(vm, 3); sq_release(vm, &obj_func); for (int i = 0; i < nparam; i++) sq_release(vm, &obj_params[i]); return sq_throwerror(vm, _SC("return value of valuator is not valid (not integer/bool)")); } } /* Remove junk */ sq_pop(vm, 2); (*iter).second = (int32)value; this->buckets[(int32)value].insert((*iter).first); } sq_release(vm, &obj_func); for (int i = 0; i < nparam; i++) sq_release(vm, &obj_params[i]); return 0; }