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