-
-
Notifications
You must be signed in to change notification settings - Fork 988
/
fake_unit_ptr.cpp
147 lines (129 loc) · 4.18 KB
/
fake_unit_ptr.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
Copyright (C) 2014 - 2018 by Chris Beck <render787@gmail.com>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program 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; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "fake_unit_ptr.hpp"
#include "fake_unit_manager.hpp"
#include "resources.hpp"
#include "units/unit.hpp"
#include "units/ptr.hpp"
fake_unit_ptr::fake_unit_ptr() : unit_(), my_manager_(nullptr) {}
fake_unit_ptr::fake_unit_ptr(const internal_ptr & u) : unit_(u), my_manager_(nullptr) {}
fake_unit_ptr::fake_unit_ptr(const internal_ptr & u, fake_unit_manager * mgr) : unit_(u), my_manager_(nullptr)
{
place_on_fake_unit_manager(mgr);
}
fake_unit_ptr::fake_unit_ptr(const fake_unit_ptr & ptr)
: unit_(ptr.unit_)
, my_manager_(nullptr)
{}
fake_unit_ptr::fake_unit_ptr(fake_unit_ptr && ptr)
: unit_(std::move(ptr.unit_))
, my_manager_(ptr.my_manager_)
{
ptr.my_manager_ = nullptr;
}
void fake_unit_ptr::swap (fake_unit_ptr & o) {
std::swap(unit_, o.unit_);
std::swap(my_manager_, o.my_manager_);
}
fake_unit_ptr & fake_unit_ptr::operator=(fake_unit_ptr other) {
swap(other);
return *this;
}
/**
* Assignment operator, taking a unit.
* If already in the queue, @a this will be moved to the end of the
* queue (drawn last).
*
* This function is unsuitable for derived classes and MUST be overridden.
* Furthermore, derived classes must not explicitly call this version.
*
* The overriding function can be almost the same, except "new (this)" should
* be followed by the derived class instead of "fake_unit(a)".
*/
/*fake_unit & fake_unit::operator=(const unit& a)
{
if ( this != &a ) {
fake_unit_manager * mgr = my_manager_;
// Use the copy constructor to make sure we are coherent.
// (Methodology copied from unit::operator=)
this->~fake_unit();
new (this) fake_unit(a);
// Restore our old manager.
if ( mgr != nullptr )
place_on_fake_unit_manager(mgr);
}
return *this;
}*/
/**
* Removes the unit from the fake manager, and resets the internal unit pointer.
* After this, both pointers are null.
*/
void fake_unit_ptr::reset()
{
remove_from_fake_unit_manager();
unit_.reset();
}
/**
* Resets the internal unit pointer to match the given pointer.
* The value of my_manager_ is preserved -- the old unit is deregistered,
* and the new unit is registered with the same manager.
*/
void fake_unit_ptr::reset(const internal_ptr & ptr)
{
if (unit_.get() != ptr.get()) {
fake_unit_manager * mgr = my_manager_;
remove_from_fake_unit_manager();
unit_ = ptr;
if (mgr)
place_on_fake_unit_manager(mgr);
}
}
/**
* Removes @a this from the fake_units_ list if necessary.
*/
fake_unit_ptr::~fake_unit_ptr()
{
try {
// The fake_unit class exists for this one line, which removes the
// fake_unit from the managers's fake_units_ dequeue in the event of an
// exception.
if(my_manager_) {
//my_manager_ points to resources::fake_units, the next line fixes a bug whre this code would attempt to access a freed fake_unit_manager object, see https://github.com/wesnoth/wesnoth/issues/3008
if(resources::fake_units != nullptr) {
remove_from_fake_unit_manager();
}
}
} catch (...) {}
}
/**
* Place @a this on @a manager's fake_units_ dequeue.
* This will be added at the end (drawn last, over all other units).
* Duplicate additions are not allowed.
*/
void fake_unit_ptr::place_on_fake_unit_manager(fake_unit_manager * manager){
assert(my_manager_ == nullptr); //Can only be placed on 1 fake_unit_manager
my_manager_=manager;
my_manager_->place_temporary_unit(unit_.get());
}
/**
* Removes @a this from whatever fake_units_ list it is on (if any).
* @returns the number of fake_units deleted, which should be 0 or 1
* (any other number indicates an error).
*/
int fake_unit_ptr::remove_from_fake_unit_manager(){
int ret(0);
if(my_manager_ != nullptr){
ret = my_manager_->remove_temporary_unit(unit_.get());
my_manager_=nullptr;
}
return ret;
}