2009-08-21 22:21:05 +02:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
|
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
/** @file script_list.cpp Implementation of ScriptList. */
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2011-01-22 11:33:16 +01:00
|
|
|
#include "../../stdafx.h"
|
2011-11-30 00:07:38 +01:00
|
|
|
#include "script_list.hpp"
|
2016-05-30 23:03:11 +02:00
|
|
|
#include "script_controller.hpp"
|
2009-01-12 18:11:45 +01:00
|
|
|
#include "../../debug.h"
|
2009-02-08 02:51:48 +01:00
|
|
|
#include "../../script/squirrel.hpp"
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2014-04-23 22:13:33 +02:00
|
|
|
#include "../../safeguards.h"
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
/**
|
2011-11-30 00:15:35 +01:00
|
|
|
* Base class for any ScriptList sorter.
|
2009-01-12 18:11:45 +01:00
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
class ScriptListSorter {
|
2009-01-12 18:11:45 +01:00
|
|
|
protected:
|
2015-01-01 22:08:19 +01:00
|
|
|
ScriptList *list; ///< The list that's being sorted.
|
2011-05-01 11:24:19 +02:00
|
|
|
bool has_no_more_items; ///< Whether we have more items to iterate over.
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_next; ///< The next item we will show.
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
* Virtual dtor, needed to mute warnings.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
virtual ~ScriptListSorter() { }
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the first item of the sorter.
|
|
|
|
*/
|
2015-01-01 22:08:19 +01:00
|
|
|
virtual int64 Begin() = 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Stop iterating a sorter.
|
|
|
|
*/
|
|
|
|
virtual void End() = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the next item of the sorter.
|
|
|
|
*/
|
2015-01-01 22:08:19 +01:00
|
|
|
virtual int64 Next() = 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/**
|
2010-02-28 21:25:03 +01:00
|
|
|
* See if the sorter has reached the end.
|
2009-01-12 18:11:45 +01:00
|
|
|
*/
|
2011-05-01 11:24:19 +02:00
|
|
|
bool IsEnd()
|
|
|
|
{
|
|
|
|
return this->list->buckets.empty() || this->has_no_more_items;
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Callback from the list if an item gets removed.
|
|
|
|
*/
|
|
|
|
virtual void Remove(int item) = 0;
|
2014-09-21 18:25:15 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Attach the sorter to a new list. This assumes the content of the old list has been moved to
|
|
|
|
* the new list, too, so that we don't have to invalidate any iterators. Note that std::swap
|
|
|
|
* doesn't invalidate iterators on lists and maps, so that should be safe.
|
|
|
|
* @param target New list to attach to.
|
|
|
|
*/
|
|
|
|
virtual void Retarget(ScriptList *new_list)
|
|
|
|
{
|
|
|
|
this->list = new_list;
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort by value, ascending.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
class ScriptListSorterValueAscending : public ScriptListSorter {
|
2009-01-12 18:11:45 +01:00
|
|
|
private:
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets.
|
2012-03-04 17:54:12 +01:00
|
|
|
ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over.
|
|
|
|
ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list.
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
public:
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Create a new sorter.
|
|
|
|
* @param list The list to sort.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptListSorterValueAscending(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
this->list = list;
|
|
|
|
this->End();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Begin()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void End()
|
|
|
|
{
|
2019-04-10 23:07:06 +02:00
|
|
|
this->bucket_list = nullptr;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->has_no_more_items = true;
|
|
|
|
this->item_next = 0;
|
|
|
|
}
|
|
|
|
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Find the next item, and store that information.
|
|
|
|
*/
|
2009-01-12 18:11:45 +01:00
|
|
|
void FindNext()
|
|
|
|
{
|
2019-04-10 23:07:06 +02:00
|
|
|
if (this->bucket_list == nullptr) {
|
2009-01-12 18:11:45 +01:00
|
|
|
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()) {
|
2019-04-10 23:07:06 +02:00
|
|
|
this->bucket_list = nullptr;
|
2009-01-12 18:11:45 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this->bucket_list = &(*this->bucket_iter).second;
|
|
|
|
this->bucket_list_iter = this->bucket_list->begin();
|
|
|
|
}
|
|
|
|
this->item_next = *this->bucket_list_iter;
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Next()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Remove(int item)
|
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/* If we remove the 'next' item, skip to the next */
|
|
|
|
if (item == this->item_next) {
|
|
|
|
FindNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort by value, descending.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
class ScriptListSorterValueDescending : public ScriptListSorter {
|
2009-01-12 18:11:45 +01:00
|
|
|
private:
|
2014-08-16 22:40:26 +02:00
|
|
|
/* Note: We cannot use reverse_iterator.
|
|
|
|
* The iterators must only be invalidated when the element they are pointing to is removed.
|
|
|
|
* This only holds for forward iterators. */
|
2014-08-16 22:37:33 +02:00
|
|
|
ScriptList::ScriptListBucket::iterator bucket_iter; ///< The iterator over the list to find the buckets.
|
|
|
|
ScriptList::ScriptItemList *bucket_list; ///< The current bucket list we're iterator over.
|
|
|
|
ScriptList::ScriptItemList::iterator bucket_list_iter; ///< The iterator over the bucket list.
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
public:
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Create a new sorter.
|
|
|
|
* @param list The list to sort.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptListSorterValueDescending(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
this->list = list;
|
|
|
|
this->End();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Begin()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
if (this->list->buckets.empty()) return 0;
|
|
|
|
this->has_no_more_items = false;
|
|
|
|
|
|
|
|
/* Go to the end of the bucket-list */
|
2014-08-16 23:11:26 +02:00
|
|
|
this->bucket_iter = this->list->buckets.end();
|
|
|
|
--this->bucket_iter;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->bucket_list = &(*this->bucket_iter).second;
|
|
|
|
|
|
|
|
/* Go to the end of the items in the bucket */
|
2014-08-16 23:11:26 +02:00
|
|
|
this->bucket_list_iter = this->bucket_list->end();
|
|
|
|
--this->bucket_list_iter;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->item_next = *this->bucket_list_iter;
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:10:57 +02:00
|
|
|
void End()
|
|
|
|
{
|
2019-04-10 23:07:06 +02:00
|
|
|
this->bucket_list = nullptr;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->has_no_more_items = true;
|
|
|
|
this->item_next = 0;
|
|
|
|
}
|
|
|
|
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Find the next item, and store that information.
|
|
|
|
*/
|
2009-01-12 18:11:45 +01:00
|
|
|
void FindNext()
|
|
|
|
{
|
2019-04-10 23:07:06 +02:00
|
|
|
if (this->bucket_list == nullptr) {
|
2009-01-12 18:11:45 +01:00
|
|
|
this->has_no_more_items = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-08-16 22:37:33 +02:00
|
|
|
if (this->bucket_list_iter == this->bucket_list->begin()) {
|
|
|
|
if (this->bucket_iter == this->list->buckets.begin()) {
|
2019-04-10 23:07:06 +02:00
|
|
|
this->bucket_list = nullptr;
|
2009-01-12 18:11:45 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-08-16 22:37:33 +02:00
|
|
|
this->bucket_iter--;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->bucket_list = &(*this->bucket_iter).second;
|
2014-08-16 22:37:33 +02:00
|
|
|
/* Go to the end of the items in the bucket */
|
2014-08-16 23:11:26 +02:00
|
|
|
this->bucket_list_iter = this->bucket_list->end();
|
|
|
|
--this->bucket_list_iter;
|
2014-08-16 22:37:33 +02:00
|
|
|
} else {
|
|
|
|
this->bucket_list_iter--;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
this->item_next = *this->bucket_list_iter;
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Next()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Remove(int item)
|
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/* If we remove the 'next' item, skip to the next */
|
|
|
|
if (item == this->item_next) {
|
|
|
|
FindNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort by item, ascending.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
class ScriptListSorterItemAscending : public ScriptListSorter {
|
2009-01-12 18:11:45 +01:00
|
|
|
private:
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map.
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
public:
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Create a new sorter.
|
|
|
|
* @param list The list to sort.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptListSorterItemAscending(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
this->list = list;
|
|
|
|
this->End();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Begin()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void End()
|
|
|
|
{
|
|
|
|
this->has_no_more_items = true;
|
|
|
|
}
|
|
|
|
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Find the next item, and store that information.
|
|
|
|
*/
|
2009-01-12 18:11:45 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Next()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
2009-10-04 19:10:57 +02:00
|
|
|
void Remove(int item)
|
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/* If we remove the 'next' item, skip to the next */
|
|
|
|
if (item == this->item_next) {
|
|
|
|
FindNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort by item, descending.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
class ScriptListSorterItemDescending : public ScriptListSorter {
|
2009-01-12 18:11:45 +01:00
|
|
|
private:
|
2014-08-16 22:40:26 +02:00
|
|
|
/* Note: We cannot use reverse_iterator.
|
|
|
|
* The iterators must only be invalidated when the element they are pointing to is removed.
|
|
|
|
* This only holds for forward iterators. */
|
2014-08-16 22:37:33 +02:00
|
|
|
ScriptList::ScriptListMap::iterator item_iter; ///< The iterator over the items in the map.
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
public:
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Create a new sorter.
|
|
|
|
* @param list The list to sort.
|
|
|
|
*/
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptListSorterItemDescending(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
this->list = list;
|
|
|
|
this->End();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Begin()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
if (this->list->items.empty()) return 0;
|
|
|
|
this->has_no_more_items = false;
|
|
|
|
|
2014-08-16 23:11:26 +02:00
|
|
|
this->item_iter = this->list->items.end();
|
|
|
|
--this->item_iter;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->item_next = (*this->item_iter).first;
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void End()
|
|
|
|
{
|
|
|
|
this->has_no_more_items = true;
|
|
|
|
}
|
|
|
|
|
2011-05-01 11:24:19 +02:00
|
|
|
/**
|
|
|
|
* Find the next item, and store that information.
|
|
|
|
*/
|
2009-01-12 18:11:45 +01:00
|
|
|
void FindNext()
|
|
|
|
{
|
2014-08-16 22:37:33 +02:00
|
|
|
if (this->item_iter == this->list->items.end()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
this->has_no_more_items = true;
|
|
|
|
return;
|
|
|
|
}
|
2014-08-16 23:13:58 +02:00
|
|
|
if (this->item_iter == this->list->items.begin()) {
|
|
|
|
/* Use 'end' as marker for 'beyond begin' */
|
|
|
|
this->item_iter = this->list->items.end();
|
|
|
|
} else {
|
|
|
|
this->item_iter--;
|
|
|
|
}
|
2014-08-16 22:37:33 +02:00
|
|
|
if (this->item_iter != this->list->items.end()) item_next = (*this->item_iter).first;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 Next()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 item_current = this->item_next;
|
2009-01-12 18:11:45 +01:00
|
|
|
FindNext();
|
|
|
|
return item_current;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Remove(int item)
|
|
|
|
{
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) return;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
/* If we remove the 'next' item, skip to the next */
|
|
|
|
if (item == this->item_next) {
|
|
|
|
FindNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptList::ScriptList()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
/* Default sorter */
|
2011-11-30 00:15:35 +01:00
|
|
|
this->sorter = new ScriptListSorterValueDescending(this);
|
2009-01-12 18:11:45 +01:00
|
|
|
this->sorter_type = SORT_BY_VALUE;
|
|
|
|
this->sort_ascending = false;
|
|
|
|
this->initialized = false;
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications = 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptList::~ScriptList()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
delete this->sorter;
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
bool ScriptList::HasItem(int64 item)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
return this->items.count(item) == 1;
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::Clear()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
this->items.clear();
|
|
|
|
this->buckets.clear();
|
|
|
|
this->sorter->End();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::AddItem(int64 item, int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
if (this->HasItem(item)) return;
|
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
this->items[item] = value;
|
|
|
|
this->buckets[value].insert(item);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::RemoveItem(int64 item)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListMap::iterator item_iter = this->items.find(item);
|
|
|
|
if (item_iter == this->items.end()) return;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
int64 value = item_iter->second;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
this->sorter->Remove(item);
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListBucket::iterator bucket_iter = this->buckets.find(value);
|
|
|
|
assert(bucket_iter != this->buckets.end());
|
|
|
|
bucket_iter->second.erase(item);
|
|
|
|
if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter);
|
|
|
|
this->items.erase(item_iter);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 ScriptList::Begin()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
this->initialized = true;
|
|
|
|
return this->sorter->Begin();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 ScriptList::Next()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2021-06-16 23:21:21 +02:00
|
|
|
if (!this->initialized) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(script, 0, "Next() is invalid as Begin() is never called");
|
2010-02-28 20:53:11 +01:00
|
|
|
return 0;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
return this->sorter->Next();
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
bool ScriptList::IsEmpty()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
return this->items.empty();
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
bool ScriptList::IsEnd()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2021-06-16 23:21:21 +02:00
|
|
|
if (!this->initialized) {
|
2021-06-12 09:10:17 +02:00
|
|
|
Debug(script, 0, "IsEnd() is invalid as Begin() is never called");
|
2010-02-28 21:25:03 +01:00
|
|
|
return true;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
2010-02-28 21:25:03 +01:00
|
|
|
return this->sorter->IsEnd();
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
int32 ScriptList::Count()
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
|
|
|
return (int32)this->items.size();
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
int64 ScriptList::GetValue(int64 item)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListMap::const_iterator item_iter = this->items.find(item);
|
|
|
|
return item_iter == this->items.end() ? 0 : item_iter->second;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
bool ScriptList::SetValue(int64 item, int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListMap::iterator item_iter = this->items.find(item);
|
|
|
|
if (item_iter == this->items.end()) return false;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
int64 value_old = item_iter->second;
|
2010-03-07 18:38:40 +01:00
|
|
|
if (value_old == value) return true;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
this->sorter->Remove(item);
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListBucket::iterator bucket_iter = this->buckets.find(value_old);
|
|
|
|
assert(bucket_iter != this->buckets.end());
|
|
|
|
bucket_iter->second.erase(item);
|
|
|
|
if (bucket_iter->second.empty()) this->buckets.erase(bucket_iter);
|
|
|
|
item_iter->second = value;
|
2009-01-12 18:11:45 +01:00
|
|
|
this->buckets[value].insert(item);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::Sort(SorterType sorter, bool ascending)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
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:
|
2009-08-20 12:23:39 +02:00
|
|
|
if (ascending) {
|
2011-11-30 00:15:35 +01:00
|
|
|
this->sorter = new ScriptListSorterItemAscending(this);
|
2009-08-20 12:23:39 +02:00
|
|
|
} else {
|
2011-11-30 00:15:35 +01:00
|
|
|
this->sorter = new ScriptListSorterItemDescending(this);
|
2009-08-20 12:23:39 +02:00
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SORT_BY_VALUE:
|
2009-08-20 12:23:39 +02:00
|
|
|
if (ascending) {
|
2011-11-30 00:15:35 +01:00
|
|
|
this->sorter = new ScriptListSorterValueAscending(this);
|
2009-08-20 12:23:39 +02:00
|
|
|
} else {
|
2011-11-30 00:15:35 +01:00
|
|
|
this->sorter = new ScriptListSorterValueDescending(this);
|
2009-08-20 12:23:39 +02:00
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
break;
|
|
|
|
|
2013-11-23 19:13:30 +01:00
|
|
|
default: NOT_REACHED();
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
this->sorter_type = sorter;
|
|
|
|
this->sort_ascending = ascending;
|
2010-02-28 20:53:11 +01:00
|
|
|
this->initialized = false;
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::AddList(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2015-04-27 21:28:22 +02:00
|
|
|
if (list == this) return;
|
|
|
|
|
2020-04-25 22:41:19 +02:00
|
|
|
if (this->IsEmpty()) {
|
|
|
|
/* If this is empty, we can just take the items of the other list as is. */
|
|
|
|
this->items = list->items;
|
|
|
|
this->buckets = list->buckets;
|
|
|
|
this->modifications++;
|
|
|
|
} else {
|
|
|
|
ScriptListMap *list_items = &list->items;
|
|
|
|
for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
|
|
|
|
this->AddItem((*iter).first);
|
|
|
|
this->SetValue((*iter).first, (*iter).second);
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-21 18:25:15 +02:00
|
|
|
void ScriptList::SwapList(ScriptList *list)
|
|
|
|
{
|
2015-04-27 21:28:22 +02:00
|
|
|
if (list == this) return;
|
|
|
|
|
2014-09-21 18:25:15 +02:00
|
|
|
this->items.swap(list->items);
|
|
|
|
this->buckets.swap(list->buckets);
|
|
|
|
Swap(this->sorter, list->sorter);
|
|
|
|
Swap(this->sorter_type, list->sorter_type);
|
|
|
|
Swap(this->sort_ascending, list->sort_ascending);
|
|
|
|
Swap(this->initialized, list->initialized);
|
|
|
|
Swap(this->modifications, list->modifications);
|
|
|
|
this->sorter->Retarget(this);
|
|
|
|
list->sorter->Retarget(list);
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::RemoveAboveValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second > value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::RemoveBelowValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second < value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::RemoveBetweenValue(int64 start, int64 end)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second > start && (*iter).second < end) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::RemoveValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second == value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::RemoveTop(int32 count)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
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:
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListBucket::iterator iter = this->buckets.begin(); iter != this->buckets.end(); iter = this->buckets.begin()) {
|
2012-03-04 17:54:12 +01:00
|
|
|
ScriptItemList *items = &(*iter).second;
|
2009-01-12 18:11:45 +01:00
|
|
|
size_t size = items->size();
|
2012-03-04 17:54:12 +01:00
|
|
|
for (ScriptItemList::iterator iter = items->begin(); iter != items->end(); iter = items->begin()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
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:
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter = this->items.begin()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
if (--count < 0) return;
|
|
|
|
this->RemoveItem((*iter).first);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::RemoveBottom(int32 count)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
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:
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListBucket::reverse_iterator iter = this->buckets.rbegin(); iter != this->buckets.rend(); iter = this->buckets.rbegin()) {
|
2012-03-04 17:54:12 +01:00
|
|
|
ScriptItemList *items = &(*iter).second;
|
2009-01-12 18:11:45 +01:00
|
|
|
size_t size = items->size();
|
2012-03-04 17:54:12 +01:00
|
|
|
for (ScriptItemList::reverse_iterator iter = items->rbegin(); iter != items->rend(); iter = items->rbegin()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2013-11-23 19:13:30 +01:00
|
|
|
break;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
case SORT_BY_ITEM:
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::reverse_iterator iter = this->items.rbegin(); iter != this->items.rend(); iter = this->items.rbegin()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
if (--count < 0) return;
|
|
|
|
this->RemoveItem((*iter).first);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::RemoveList(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2015-04-27 21:28:22 +02:00
|
|
|
if (list == this) {
|
|
|
|
Clear();
|
|
|
|
} else {
|
|
|
|
ScriptListMap *list_items = &list->items;
|
|
|
|
for (ScriptListMap::iterator iter = list_items->begin(); iter != list_items->end(); iter++) {
|
|
|
|
this->RemoveItem((*iter).first);
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::KeepAboveValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second <= value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::KeepBelowValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second >= value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::KeepBetweenValue(int64 start, int64 end)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second <= start || (*iter).second >= end) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-01 22:08:19 +01:00
|
|
|
void ScriptList::KeepValue(int64 value)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator next_iter, iter = this->items.begin(); iter != this->items.end(); iter = next_iter) {
|
2009-01-12 18:11:45 +01:00
|
|
|
next_iter = iter; next_iter++;
|
2010-02-28 20:53:11 +01:00
|
|
|
if ((*iter).second != value) this->RemoveItem((*iter).first);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::KeepTop(int32 count)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
this->RemoveBottom(this->Count() - count);
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::KeepBottom(int32 count)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2009-01-12 18:11:45 +01:00
|
|
|
this->RemoveTop(this->Count() - count);
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
void ScriptList::KeepList(ScriptList *list)
|
2009-01-12 18:11:45 +01:00
|
|
|
{
|
2015-04-27 21:28:22 +02:00
|
|
|
if (list == this) return;
|
|
|
|
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptList tmp;
|
2015-04-27 21:28:22 +02:00
|
|
|
tmp.AddList(this);
|
2009-01-12 18:11:45 +01:00
|
|
|
tmp.RemoveList(list);
|
|
|
|
this->RemoveList(&tmp);
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
SQInteger ScriptList::_get(HSQUIRRELVM vm)
|
2009-03-09 23:14:47 +01:00
|
|
|
{
|
2009-01-12 18:11:45 +01:00
|
|
|
if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
|
|
|
|
|
|
|
|
SQInteger idx;
|
|
|
|
sq_getinteger(vm, 2, &idx);
|
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
ScriptListMap::const_iterator item_iter = this->items.find(idx);
|
|
|
|
if (item_iter == this->items.end()) return SQ_ERROR;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2015-02-23 00:04:02 +01:00
|
|
|
sq_pushinteger(vm, item_iter->second);
|
2009-01-12 18:11:45 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
SQInteger ScriptList::_set(HSQUIRRELVM vm)
|
2010-08-19 17:19:40 +02:00
|
|
|
{
|
|
|
|
if (sq_gettype(vm, 2) != OT_INTEGER) return SQ_ERROR;
|
2011-12-01 23:23:13 +01:00
|
|
|
if (sq_gettype(vm, 3) != OT_INTEGER && sq_gettype(vm, 3) != OT_NULL) {
|
2014-09-06 19:46:56 +02:00
|
|
|
return sq_throwerror(vm, "you can only assign integers to this list");
|
2010-08-19 17:19:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SQInteger idx, val;
|
|
|
|
sq_getinteger(vm, 2, &idx);
|
|
|
|
if (sq_gettype(vm, 3) == OT_NULL) {
|
|
|
|
this->RemoveItem(idx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sq_getinteger(vm, 3, &val);
|
|
|
|
if (!this->HasItem(idx)) {
|
|
|
|
this->AddItem(idx, val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
this->SetValue(idx, val);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
SQInteger ScriptList::_nexti(HSQUIRRELVM vm)
|
2009-03-09 23:14:47 +01:00
|
|
|
{
|
2009-01-12 18:11:45 +01:00
|
|
|
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);
|
|
|
|
|
2021-08-10 19:00:54 +02:00
|
|
|
SQInteger val = this->Next();
|
2010-02-28 21:25:03 +01:00
|
|
|
if (this->IsEnd()) {
|
2009-01-12 18:11:45 +01:00
|
|
|
sq_pushnull(vm);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sq_pushinteger(vm, val);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
SQInteger ScriptList::Valuate(HSQUIRRELVM vm)
|
2009-03-09 23:14:47 +01:00
|
|
|
{
|
2009-08-15 22:34:11 +02:00
|
|
|
this->modifications++;
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
/* The first parameter is the instance of ScriptList. */
|
2009-03-09 23:14:47 +01:00
|
|
|
int nparam = sq_gettop(vm) - 1;
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2009-03-09 23:14:47 +01:00
|
|
|
if (nparam < 1) {
|
2019-08-07 21:15:53 +02:00
|
|
|
return sq_throwerror(vm, "You need to give at least a Valuator as parameter to ScriptList::Valuate");
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
2009-03-09 23:14:47 +01:00
|
|
|
|
|
|
|
/* Make sure the valuator function is really a function, and not any
|
|
|
|
* other type. It's parameter 2 for us, but for the user it's the
|
|
|
|
* first parameter they give. */
|
|
|
|
SQObjectType valuator_type = sq_gettype(vm, 2);
|
|
|
|
if (valuator_type != OT_CLOSURE && valuator_type != OT_NATIVECLOSURE) {
|
2014-09-06 19:46:56 +02:00
|
|
|
return sq_throwerror(vm, "parameter 1 has an invalid type (expected function)");
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2009-01-14 19:25:48 +01:00
|
|
|
/* Don't allow docommand from a Valuator, as we can't resume in
|
2009-03-09 23:14:47 +01:00
|
|
|
* mid C++-code. */
|
2011-11-30 00:15:35 +01:00
|
|
|
bool backup_allow = ScriptObject::GetAllowDoCommand();
|
|
|
|
ScriptObject::SetAllowDoCommand(false);
|
2009-01-14 19:25:48 +01:00
|
|
|
|
2009-03-09 23:14:47 +01:00
|
|
|
/* Push the function to call */
|
|
|
|
sq_push(vm, 2);
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
for (ScriptListMap::iterator iter = this->items.begin(); iter != this->items.end(); iter++) {
|
2010-03-07 18:24:07 +01:00
|
|
|
/* Check for changing of items. */
|
|
|
|
int previous_modification_count = this->modifications;
|
|
|
|
|
2009-03-09 23:14:47 +01:00
|
|
|
/* Push the root table as instance object, this is what squirrel does for meta-functions. */
|
|
|
|
sq_pushroottable(vm);
|
|
|
|
/* Push all arguments for the valuator function. */
|
2011-12-21 13:28:02 +01:00
|
|
|
sq_pushinteger(vm, (*iter).first);
|
2009-03-09 23:14:47 +01:00
|
|
|
for (int i = 0; i < nparam - 1; i++) {
|
|
|
|
sq_push(vm, i + 3);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
|
2009-03-09 23:14:47 +01:00
|
|
|
/* Call the function. Squirrel pops all parameters and pushes the return value. */
|
|
|
|
if (SQ_FAILED(sq_call(vm, nparam + 1, SQTrue, SQTrue))) {
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
2009-01-14 19:25:48 +01:00
|
|
|
return SQ_ERROR;
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2013-01-08 23:46:42 +01:00
|
|
|
/* Retrieve the return value */
|
2009-01-12 18:11:45 +01:00
|
|
|
SQInteger value;
|
|
|
|
switch (sq_gettype(vm, -1)) {
|
|
|
|
case OT_INTEGER: {
|
|
|
|
sq_getinteger(vm, -1, &value);
|
2010-08-01 20:53:30 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
case OT_BOOL: {
|
|
|
|
SQBool v;
|
|
|
|
sq_getbool(vm, -1, &v);
|
|
|
|
value = v ? 1 : 0;
|
2010-08-01 20:53:30 +02:00
|
|
|
break;
|
|
|
|
}
|
2009-01-12 18:11:45 +01:00
|
|
|
|
|
|
|
default: {
|
2009-03-09 23:14:47 +01:00
|
|
|
/* See below for explanation. The extra pop is the return value. */
|
|
|
|
sq_pop(vm, nparam + 4);
|
2009-01-12 18:11:45 +01:00
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
2014-09-06 19:46:56 +02:00
|
|
|
return sq_throwerror(vm, "return value of valuator is not valid (not integer/bool)");
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-30 23:03:11 +02:00
|
|
|
/* Kill the script when the valuator call takes way too long.
|
|
|
|
* Triggered by nesting valuators, which then take billions of iterations. */
|
|
|
|
if (ScriptController::GetOpsTillSuspend() < -1000000) {
|
|
|
|
/* See below for explanation. The extra pop is the return value. */
|
|
|
|
sq_pop(vm, nparam + 4);
|
|
|
|
|
|
|
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
|
|
|
return sq_throwerror(vm, "excessive CPU usage in valuator function");
|
|
|
|
}
|
|
|
|
|
2009-08-15 22:34:11 +02:00
|
|
|
/* Was something changed? */
|
2010-03-07 18:24:07 +01:00
|
|
|
if (previous_modification_count != this->modifications) {
|
2009-08-15 22:34:11 +02:00
|
|
|
/* See below for explanation. The extra pop is the return value. */
|
|
|
|
sq_pop(vm, nparam + 4);
|
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
2014-09-06 19:46:56 +02:00
|
|
|
return sq_throwerror(vm, "modifying valuated list outside of valuator function");
|
2009-08-15 22:34:11 +02:00
|
|
|
}
|
|
|
|
|
2011-12-21 13:28:02 +01:00
|
|
|
this->SetValue((*iter).first, value);
|
2009-02-08 02:51:48 +01:00
|
|
|
|
2009-03-09 23:14:47 +01:00
|
|
|
/* Pop the return value. */
|
|
|
|
sq_poptop(vm);
|
|
|
|
|
2009-02-08 02:51:48 +01:00
|
|
|
Squirrel::DecreaseOps(vm, 5);
|
2009-01-12 18:11:45 +01:00
|
|
|
}
|
2009-03-09 23:14:47 +01:00
|
|
|
/* Pop from the squirrel stack:
|
|
|
|
* 1. The root stable (as instance object).
|
|
|
|
* 2. The valuator function.
|
|
|
|
* 3. The parameters given to this function.
|
2011-11-30 00:15:35 +01:00
|
|
|
* 4. The ScriptList instance object. */
|
2009-03-09 23:14:47 +01:00
|
|
|
sq_pop(vm, nparam + 3);
|
2009-01-14 19:25:48 +01:00
|
|
|
|
2011-11-30 00:15:35 +01:00
|
|
|
ScriptObject::SetAllowDoCommand(backup_allow);
|
2009-01-12 18:11:45 +01:00
|
|
|
return 0;
|
|
|
|
}
|