summaryrefslogtreecommitdiff
path: root/src/script/api/script_priorityqueue.cpp
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2020-04-19 00:53:30 +0200
committerMichael Lutz <michi@icosahedron.de>2020-06-01 21:35:13 +0200
commit1c0ba07c3cb4f393b56063e2d631fbb2d73219b1 (patch)
tree899bd53ad86d592f8cc0ff5c5e29214f9d243619 /src/script/api/script_priorityqueue.cpp
parent764497206ab9457ab5dff3ea7851546da9259cc4 (diff)
downloadopenttd-1c0ba07c3cb4f393b56063e2d631fbb2d73219b1.tar.xz
Add: [Script] Native priority queue; useful e.g. for pathfinders.
Diffstat (limited to 'src/script/api/script_priorityqueue.cpp')
-rw-r--r--src/script/api/script_priorityqueue.cpp107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/script/api/script_priorityqueue.cpp b/src/script/api/script_priorityqueue.cpp
new file mode 100644
index 000000000..313008412
--- /dev/null
+++ b/src/script/api/script_priorityqueue.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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/>.
+ */
+
+/** @file script_priorityqueue.cpp Implementation of ScriptPriorityQueue. */
+
+#include "../../stdafx.h"
+#include "script_priorityqueue.hpp"
+#include "script_error.hpp"
+#include "../squirrel_helper.hpp"
+#include "../script_instance.hpp"
+#include "../../debug.h"
+#include <algorithm>
+
+#include "../../safeguards.h"
+
+
+static bool operator==(const ScriptPriorityQueue::PriorityItem &lhs, const HSQOBJECT &rhs)
+{
+ return lhs.second._type == rhs._type && lhs.second._unVal.raw == rhs._unVal.raw;
+}
+
+
+ScriptPriorityQueue::~ScriptPriorityQueue()
+{
+ /* Release reference to stored objects. */
+ auto inst = ScriptObject::GetActiveInstance();
+ if (!inst->InShutdown()) {
+ for (auto &i : this->queue) inst->ReleaseSQObject(const_cast<HSQOBJECT *>(&i.second));
+ }
+}
+
+SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm)
+{
+ HSQOBJECT item;
+ int64 priority;
+ sq_resetobject(&item);
+ sq_getstackobj(vm, 2, &item);
+ sq_getinteger(vm, 3, &priority);
+
+ sq_addref(vm, &item); // Keep object alive.
+
+ this->queue.emplace_back(priority, item);
+ std::push_heap(this->queue.begin(), this->queue.end(), this->comp);
+
+ return SQConvert::Return(vm, true);
+}
+
+SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
+{
+ if (this->IsEmpty()) {
+ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED);
+ sq_pushnull(vm);
+ return 1;
+ }
+
+ HSQOBJECT item = this->queue.front().second;
+ std::pop_heap(this->queue.begin(), this->queue.end(), this->comp);
+ this->queue.pop_back();
+
+ /* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */
+ auto ret = SQConvert::Return(vm, item);
+ sq_release(vm, &item);
+ return ret;
+}
+
+SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm)
+{
+ if (this->IsEmpty()) {
+ ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED);
+ sq_pushnull(vm);
+ return 1;
+ }
+
+ return SQConvert::Return(vm, this->queue.front().second);
+}
+
+SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
+{
+ HSQOBJECT item;
+ sq_resetobject(&item);
+ sq_getstackobj(vm, 2, &item);
+
+ return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
+}
+
+SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm)
+{
+ /* Release reference to stored objects. */
+ for (auto &i : this->queue) sq_release(vm, const_cast<HSQOBJECT *>(&i.second));
+ this->queue.clear();
+
+ return 0;
+}
+
+bool ScriptPriorityQueue::IsEmpty()
+{
+ return this->queue.empty();
+}
+
+SQInteger ScriptPriorityQueue::Count()
+{
+ return (SQInteger)this->queue.size();
+}