File diff r10695:3124a970a753 → r10696:8dfe83e30d01
src/ai/api/ai_abstractlist.cpp
Show inline comments
 
new file 100644
 
/* $Id$ */
 

	
 
/** @file ai_abstractlist.cpp Implementation of AIAbstractList. */
 

	
 
#include <squirrel.h>
 
#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;
 
}