1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
8 /** @file script_priorityqueue.cpp Implementation of ScriptPriorityQueue. */
9
10 #include "../../stdafx.h"
11 #include "script_priorityqueue.hpp"
12 #include "script_error.hpp"
13 #include "../squirrel_helper.hpp"
14 #include "../script_instance.hpp"
15 #include "../../debug.h"
16
17 #include "../../safeguards.h"
18
19
operator ==(const ScriptPriorityQueue::PriorityItem & lhs,const HSQOBJECT & rhs)20 static bool operator==(const ScriptPriorityQueue::PriorityItem &lhs, const HSQOBJECT &rhs)
21 {
22 return lhs.second._type == rhs._type && lhs.second._unVal.raw == rhs._unVal.raw;
23 }
24
25
~ScriptPriorityQueue()26 ScriptPriorityQueue::~ScriptPriorityQueue()
27 {
28 /* Release reference to stored objects. */
29 auto inst = ScriptObject::GetActiveInstance();
30 if (!inst->InShutdown()) {
31 for (auto &i : this->queue) inst->ReleaseSQObject(const_cast<HSQOBJECT *>(&i.second));
32 }
33 }
34
Insert(HSQUIRRELVM vm)35 SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm)
36 {
37 HSQOBJECT item;
38 int64 priority;
39 sq_resetobject(&item);
40 sq_getstackobj(vm, 2, &item);
41 sq_getinteger(vm, 3, &priority);
42
43 sq_addref(vm, &item); // Keep object alive.
44
45 this->queue.emplace_back(priority, item);
46 std::push_heap(this->queue.begin(), this->queue.end(), this->comp);
47
48 return SQConvert::Return(vm, true);
49 }
50
Pop(HSQUIRRELVM vm)51 SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
52 {
53 if (this->IsEmpty()) {
54 ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED);
55 sq_pushnull(vm);
56 return 1;
57 }
58
59 HSQOBJECT item = this->queue.front().second;
60 std::pop_heap(this->queue.begin(), this->queue.end(), this->comp);
61 this->queue.pop_back();
62
63 /* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */
64 auto ret = SQConvert::Return(vm, item);
65 sq_release(vm, &item);
66 return ret;
67 }
68
Peek(HSQUIRRELVM vm)69 SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm)
70 {
71 if (this->IsEmpty()) {
72 ScriptObject::SetLastError(ScriptError::ERR_PRECONDITION_FAILED);
73 sq_pushnull(vm);
74 return 1;
75 }
76
77 return SQConvert::Return(vm, this->queue.front().second);
78 }
79
Exists(HSQUIRRELVM vm)80 SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
81 {
82 HSQOBJECT item;
83 sq_resetobject(&item);
84 sq_getstackobj(vm, 2, &item);
85
86 return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
87 }
88
Clear(HSQUIRRELVM vm)89 SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm)
90 {
91 /* Release reference to stored objects. */
92 for (auto &i : this->queue) sq_release(vm, const_cast<HSQOBJECT *>(&i.second));
93 this->queue.clear();
94
95 return 0;
96 }
97
IsEmpty()98 bool ScriptPriorityQueue::IsEmpty()
99 {
100 return this->queue.empty();
101 }
102
Count()103 SQInteger ScriptPriorityQueue::Count()
104 {
105 return (SQInteger)this->queue.size();
106 }
107