contrek 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/Gemfile.lock +1 -1
- data/README.md +102 -6
- data/ext/cpp_polygon_finder/PolygonFinder/Makefile +4 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +5 -4
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp +3 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.cpp +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cluster.h +1 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.cpp +28 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Cursor.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +12 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.cpp +5 -5
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Hub.h +11 -7
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Part.h +2 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.cpp +108 -66
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Partitionable.h +5 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.cpp +33 -28
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Polyline.h +5 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Position.cpp +2 -3
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Queueable.h +15 -20
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +128 -131
- data/lib/contrek/bitmaps/rgb_color.rb +0 -15
- data/lib/contrek/bitmaps/rgb_cpp_color.rb +10 -0
- data/lib/contrek/finder/concurrent/cluster.rb +2 -2
- data/lib/contrek/finder/concurrent/cursor.rb +32 -15
- data/lib/contrek/finder/concurrent/finder.rb +23 -9
- data/lib/contrek/finder/concurrent/hub.rb +2 -2
- data/lib/contrek/finder/concurrent/part.rb +6 -1
- data/lib/contrek/finder/concurrent/partitionable.rb +61 -33
- data/lib/contrek/finder/concurrent/polyline.rb +44 -2
- data/lib/contrek/finder/concurrent/queueable.rb +12 -20
- data/lib/contrek/finder/polygon_finder.rb +8 -6
- data/lib/contrek/finder/result.rb +13 -0
- data/lib/contrek/results/cpp_result.rb +21 -0
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +6 -3
- metadata +5 -2
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
#include <vector>
|
|
10
10
|
#include <utility>
|
|
11
11
|
#include <iostream>
|
|
12
|
+
#include <algorithm>
|
|
12
13
|
#include "Partitionable.h"
|
|
13
14
|
#include "Polyline.h"
|
|
14
15
|
#include "Sequence.h"
|
|
@@ -31,6 +32,17 @@ void Partitionable::add_part(Part* new_part)
|
|
|
31
32
|
new_part->circular_next = this->parts_.front();
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
void Partitionable::insert_after(Part* part, Part* new_part) {
|
|
36
|
+
auto it = std::find(parts_.begin(), parts_.end(), part);
|
|
37
|
+
if (it != parts_.end()) parts_.insert(it + 1, new_part);
|
|
38
|
+
new_part->prev = part;
|
|
39
|
+
new_part->next = part->next;
|
|
40
|
+
new_part->circular_next = part->next;
|
|
41
|
+
if (part->next) part->next->prev = new_part;
|
|
42
|
+
part->next = new_part;
|
|
43
|
+
part->circular_next = new_part;
|
|
44
|
+
}
|
|
45
|
+
|
|
34
46
|
void Partitionable::partition()
|
|
35
47
|
{ this->parts_.clear();
|
|
36
48
|
Polyline *polyline = dynamic_cast<Polyline*>(this);
|
|
@@ -73,85 +85,115 @@ Part* Partitionable::find_first_part_by_position(Position* position) {
|
|
|
73
85
|
return(nullptr);
|
|
74
86
|
}
|
|
75
87
|
|
|
76
|
-
std::pair<
|
|
77
|
-
std::vector<
|
|
78
|
-
std::vector<std::vector<Point*>>
|
|
79
|
-
>
|
|
80
|
-
Partitionable::sew(std::vector<Point*> intersection, Polyline* other)
|
|
81
|
-
{ std::vector<int> matching_part_indexes;
|
|
82
|
-
for (int i = 0; i < static_cast<int>(parts_.size()); ++i) {
|
|
83
|
-
Part* part = parts_[i];
|
|
84
|
-
if (!part || part->trasmuted) continue;
|
|
85
|
-
if (part->intersection_with_array(intersection)) {
|
|
86
|
-
matching_part_indexes.push_back(i);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
88
|
+
std::optional<SewReturnData> Partitionable::sew(std::vector<std::pair<int, int>> intersection, Polyline* other)
|
|
89
|
+
{ std::vector<int> matching_part_indexes;
|
|
89
90
|
std::vector<int> other_matching_part_indexes;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
matching_part_indexes.reserve(intersection.size());
|
|
92
|
+
other_matching_part_indexes.reserve(intersection.size());
|
|
93
|
+
|
|
94
|
+
// traspose
|
|
95
|
+
for (const auto& pair : intersection) {
|
|
96
|
+
matching_part_indexes.push_back(pair.first);
|
|
97
|
+
other_matching_part_indexes.push_back(pair.second);
|
|
96
98
|
}
|
|
97
|
-
std::
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
std::sort(matching_part_indexes.begin(), matching_part_indexes.end());
|
|
100
|
+
std::sort(other_matching_part_indexes.begin(), other_matching_part_indexes.end());
|
|
101
|
+
|
|
102
|
+
auto start_it_before = other->parts_.begin() + other_matching_part_indexes.back() + 1;
|
|
103
|
+
auto end_it_before = other->parts_.end();
|
|
104
|
+
std::vector<Part*> before_parts(start_it_before, end_it_before);
|
|
105
|
+
auto start_it_after = other->parts_.begin();
|
|
106
|
+
auto end_it_after = other->parts_.begin() + other_matching_part_indexes.front();
|
|
107
|
+
std::vector<Part*> after_parts(start_it_after, end_it_after);
|
|
108
|
+
|
|
109
|
+
int start_idx = matching_part_indexes.front();
|
|
110
|
+
int end_idx = matching_part_indexes.back();
|
|
111
|
+
Part* part_start = parts_[start_idx];
|
|
112
|
+
Part* part_end = parts_[end_idx];
|
|
113
|
+
|
|
114
|
+
auto collect_sequences = [&](const std::vector<int>& indices, std::vector<Part*>& p_list)
|
|
115
|
+
-> std::vector<std::vector<Point*>> {
|
|
116
|
+
std::vector<std::vector<Point*>> result;
|
|
117
|
+
int last_n = -1;
|
|
118
|
+
if (indices.size() < 2) return result;
|
|
119
|
+
for (int n = indices.front() + 1; n < indices.back(); ++n) {
|
|
120
|
+
if (std::find(indices.begin(), indices.end(), n) == indices.end()) {
|
|
121
|
+
Part* part = p_list[n];
|
|
122
|
+
if (part->is(Part::SEAM) && part->size > 0 && !part->delayed) {
|
|
123
|
+
part->delayed = true;
|
|
124
|
+
result.clear();
|
|
125
|
+
result.push_back({nullptr});
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
if (last_n == (n - 1) && !result.empty()) {
|
|
129
|
+
std::vector<Point*> pts = part->to_vector();
|
|
130
|
+
result.back().insert(result.back().end(), pts.begin(), pts.end());
|
|
131
|
+
} else {
|
|
132
|
+
result.push_back(part->to_vector());
|
|
133
|
+
}
|
|
134
|
+
last_n = n;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
};
|
|
139
|
+
auto left = collect_sequences(matching_part_indexes, this->parts_);
|
|
140
|
+
if (!left.empty() && !left[0].empty() && left[0][0] == nullptr) {
|
|
141
|
+
return std::nullopt;
|
|
101
142
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
143
|
+
auto right = collect_sequences(other_matching_part_indexes, other->parts_);
|
|
144
|
+
if (!right.empty() && !right[0].empty() && right[0][0] == nullptr) {
|
|
145
|
+
return std::nullopt;
|
|
105
146
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
part_start->replace(sequence);
|
|
115
|
-
part_start->type = Part::EXCLUSIVE;
|
|
116
|
-
if (part_start != part_end) part_end->reset();
|
|
117
|
-
|
|
118
|
-
std::vector<std::vector<Point*>> left;
|
|
119
|
-
|
|
120
|
-
for (int n = matching_part_indexes.front() + 1;
|
|
121
|
-
n <= matching_part_indexes.back() - 1;
|
|
122
|
-
++n)
|
|
123
|
-
{ if (std::find(matching_part_indexes.begin(),
|
|
124
|
-
matching_part_indexes.end(),
|
|
125
|
-
n) == matching_part_indexes.end())
|
|
126
|
-
{ auto pts = parts_[n]->to_vector();
|
|
127
|
-
left.push_back(pts);
|
|
147
|
+
|
|
148
|
+
if (part_start != part_end) {
|
|
149
|
+
for (int n = end_idx - 1; n > start_idx; --n) {
|
|
150
|
+
Part* delete_part = parts_[n];
|
|
151
|
+
// Topological detachment of pointers
|
|
152
|
+
if (delete_part->prev) delete_part->prev->next = delete_part->next;
|
|
153
|
+
if (delete_part->next) delete_part->next->prev = delete_part->prev;
|
|
154
|
+
parts_.erase(parts_.begin() + n);
|
|
128
155
|
}
|
|
129
156
|
}
|
|
130
157
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
158
|
+
std::vector<Part*> all_parts;
|
|
159
|
+
Polyline* polyline = dynamic_cast<Polyline*>(this);
|
|
160
|
+
all_parts.reserve(before_parts.size() + after_parts.size());
|
|
161
|
+
all_parts.insert(all_parts.end(), before_parts.begin(), before_parts.end());
|
|
162
|
+
all_parts.insert(all_parts.end(), after_parts.begin(), after_parts.end());
|
|
163
|
+
Part* will_be_last = all_parts.empty() ? nullptr : all_parts.back();
|
|
164
|
+
for (auto it = all_parts.rbegin(); it != all_parts.rend(); ++it) {
|
|
165
|
+
Part* p = *it;
|
|
166
|
+
this->insert_after(part_start, p);
|
|
167
|
+
auto& op = other->parts_;
|
|
168
|
+
op.erase(std::remove(op.begin(), op.end(), p), op.end());
|
|
169
|
+
p->set_polyline(polyline);
|
|
139
170
|
}
|
|
140
171
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
172
|
+
part_start->type = Part::EXCLUSIVE;
|
|
173
|
+
PartPool& pool = polyline->tile->cluster->parts_pool;
|
|
174
|
+
Part* new_end_part = pool.acquire(Part::EXCLUSIVE, polyline);
|
|
175
|
+
new_end_part->add(part_end->tail);
|
|
176
|
+
part_start->singleton();
|
|
177
|
+
|
|
178
|
+
// deletes part_end
|
|
179
|
+
if (part_start != part_end) {
|
|
180
|
+
if (part_end->prev) part_end->prev->next = part_end->next;
|
|
181
|
+
if (part_end->next) part_end->next->prev = part_end->prev;
|
|
182
|
+
auto it = std::find(parts_.begin(), parts_.end(), part_end);
|
|
183
|
+
if (it != parts_.end()) {
|
|
184
|
+
parts_.erase(it);
|
|
150
185
|
}
|
|
151
186
|
}
|
|
152
|
-
|
|
187
|
+
|
|
188
|
+
Part* reference_part = (will_be_last != nullptr) ? will_be_last : part_start;
|
|
189
|
+
this->insert_after(reference_part, new_end_part);
|
|
190
|
+
|
|
191
|
+
polyline->reset_tracked_endpoints();
|
|
192
|
+
|
|
193
|
+
return std::make_pair(left, right);
|
|
153
194
|
}
|
|
154
195
|
|
|
196
|
+
|
|
155
197
|
void Partitionable::trasmute_parts()
|
|
156
198
|
{ std::vector<Part*> insides;
|
|
157
199
|
for (Part* p : parts_) {
|
|
@@ -9,22 +9,24 @@
|
|
|
9
9
|
#pragma once
|
|
10
10
|
#include <vector>
|
|
11
11
|
#include <utility>
|
|
12
|
+
#include <optional>
|
|
12
13
|
#include "Part.h"
|
|
13
14
|
|
|
15
|
+
using SewReturnData = std::pair<std::vector<std::vector<Point*>>, std::vector<std::vector<Point*>>>;
|
|
16
|
+
|
|
14
17
|
class Partitionable {
|
|
15
18
|
public:
|
|
16
19
|
explicit Partitionable() {}
|
|
17
20
|
virtual ~Partitionable() = default;
|
|
18
21
|
void partition();
|
|
19
22
|
Part* find_first_part_by_position(Position* position);
|
|
20
|
-
std::pair<
|
|
21
|
-
std::vector<std::vector<Point*>>,
|
|
22
|
-
std::vector<std::vector<Point*>>> sew(std::vector<Point*> intersection, Polyline* other);
|
|
23
|
+
std::optional<SewReturnData> sew(std::vector<std::pair<int, int>> intersection, Polyline* other);
|
|
23
24
|
|
|
24
25
|
protected:
|
|
25
26
|
std::vector<Part*> parts_;
|
|
26
27
|
|
|
27
28
|
private:
|
|
28
29
|
void add_part(Part* new_part);
|
|
30
|
+
void insert_after(Part* part, Part* new_part);
|
|
29
31
|
void trasmute_parts();
|
|
30
32
|
};
|
|
@@ -48,6 +48,10 @@ bool Polyline::boundary() {
|
|
|
48
48
|
return( tile->tg_border(Point{min_x, 0}) || tile->tg_border(Point{max_x, 0}));
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
void Polyline::reset_tracked_endpoints() {
|
|
52
|
+
tracked_endpoints.clear();
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
void Polyline::find_boundary() {
|
|
52
56
|
if (raw_.empty()) return;
|
|
53
57
|
min_x = std::numeric_limits<int>::max();
|
|
@@ -65,40 +69,41 @@ void Polyline::find_boundary() {
|
|
|
65
69
|
}
|
|
66
70
|
}
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
bool operator()(const Point* p1, const Point* p2) const {
|
|
80
|
-
if (!p1 || !p2) return p1 == p2;
|
|
81
|
-
return *p1 == *p2;
|
|
72
|
+
std::vector<std::pair<int, int>> Polyline::intersection(const Polyline* other) const {
|
|
73
|
+
if (this->tracked_endpoints.empty()) {
|
|
74
|
+
for (int i = 0; i < parts_.size(); ++i) {
|
|
75
|
+
auto& part = parts_[i];
|
|
76
|
+
if (!part->is(Part::SEAM) && part->trasmuted) continue;
|
|
77
|
+
part->each([&](QNode<Point>* pos) -> bool {
|
|
78
|
+
Position *position = dynamic_cast<Position*>(pos);
|
|
79
|
+
this->tracked_endpoints[position->end_point()] = i;
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
82
83
|
}
|
|
83
|
-
};
|
|
84
84
|
|
|
85
|
-
std::vector<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
for (Point* p : other->raw()) {
|
|
91
|
-
if (p) other_set.insert(p);
|
|
92
|
-
}
|
|
93
|
-
for (Point* p : raw_) {
|
|
94
|
-
if (!p) continue;
|
|
95
|
-
if (other_set.count(p)) {
|
|
96
|
-
result.push_back(p);
|
|
85
|
+
std::vector<std::pair<int, int>> matching_parts;
|
|
86
|
+
for (int j = 0; j < other->parts_.size(); ++j) {
|
|
87
|
+
auto& other_part = other->parts_[j];
|
|
88
|
+
if (!other_part->is(Part::SEAM) && other_part->trasmuted) {
|
|
89
|
+
continue;
|
|
97
90
|
}
|
|
91
|
+
other_part->each([&](QNode<Point>* pos) -> bool {
|
|
92
|
+
Position *position = dynamic_cast<Position*>(pos);
|
|
93
|
+
auto it = this->tracked_endpoints.find(position->end_point());
|
|
94
|
+
if (it != this->tracked_endpoints.end()) {
|
|
95
|
+
int self_index = it->second;
|
|
96
|
+
matching_parts.push_back({self_index, j});
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
return true;
|
|
100
|
+
});
|
|
98
101
|
}
|
|
99
|
-
|
|
102
|
+
|
|
103
|
+
return matching_parts;
|
|
100
104
|
}
|
|
101
105
|
|
|
106
|
+
|
|
102
107
|
void Polyline::clear() {
|
|
103
108
|
this->raw_.clear();
|
|
104
109
|
}
|
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
#include <list>
|
|
11
11
|
#include <cstdint>
|
|
12
12
|
#include <optional>
|
|
13
|
+
#include <utility>
|
|
13
14
|
#include <vector>
|
|
15
|
+
#include <unordered_map>
|
|
14
16
|
#include "Partitionable.h"
|
|
15
17
|
#include "../RectBounds.h"
|
|
16
18
|
|
|
@@ -37,11 +39,12 @@ class Polyline : public Partitionable {
|
|
|
37
39
|
std::vector<Point*> raw() const { return raw_; }
|
|
38
40
|
const std::list<Shape*>& next_tile_eligible_shapes() const { return next_tile_eligible_shapes_; }
|
|
39
41
|
const std::vector<Part*>& parts() const { return parts_; }
|
|
40
|
-
std::vector<
|
|
42
|
+
std::vector<std::pair<int, int>> intersection(const Polyline* other) const;
|
|
41
43
|
const int max_y() const { return max_y_; }
|
|
42
44
|
void clear();
|
|
43
45
|
bool is_empty();
|
|
44
46
|
bool vert_intersect(Polyline& other);
|
|
47
|
+
void reset_tracked_endpoints();
|
|
45
48
|
|
|
46
49
|
private:
|
|
47
50
|
std::vector<Point*> raw_;
|
|
@@ -49,4 +52,5 @@ class Polyline : public Partitionable {
|
|
|
49
52
|
void find_boundary();
|
|
50
53
|
uint32_t flags_ = 0;
|
|
51
54
|
std::list<Shape*> next_tile_eligible_shapes_;
|
|
55
|
+
mutable std::unordered_map<const EndPoint*, int> tracked_endpoints;
|
|
52
56
|
};
|
|
@@ -11,11 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
Position::Position(Hub* hub, Point* point)
|
|
13
13
|
: QNode<Point>(point)
|
|
14
|
-
{ int key = point->y * hub->width() + point->x;
|
|
14
|
+
{ int key = point->y * hub->width() + (point->x - hub->start_x());
|
|
15
15
|
EndPoint* existing_ep = hub->get(key);
|
|
16
16
|
if (existing_ep == nullptr)
|
|
17
|
-
{ end_point_ = hub->spawn_end_point();
|
|
18
|
-
hub->put(key, end_point_);
|
|
17
|
+
{ end_point_ = hub->put(key, hub->spawn_end_point());
|
|
19
18
|
} else {
|
|
20
19
|
end_point_ = existing_ep;
|
|
21
20
|
}
|
|
@@ -79,9 +79,21 @@ class Queueable {
|
|
|
79
79
|
head = nullptr;
|
|
80
80
|
tail = nullptr;
|
|
81
81
|
_iterator = nullptr;
|
|
82
|
+
_started = false;
|
|
82
83
|
size = 0;
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
void singleton()
|
|
87
|
+
{ if (head && head->next) {
|
|
88
|
+
head->next->prev = nullptr;
|
|
89
|
+
head->next = nullptr;
|
|
90
|
+
}
|
|
91
|
+
tail = nullptr;
|
|
92
|
+
size = 1;
|
|
93
|
+
_iterator = nullptr;
|
|
94
|
+
_started = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
85
97
|
void replace(Queueable<T>& q) {
|
|
86
98
|
reset();
|
|
87
99
|
append(q);
|
|
@@ -130,8 +142,8 @@ class Queueable {
|
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
void next_of(QNode<T>* node) {
|
|
133
|
-
if (!node) throw std::runtime_error("nil node");
|
|
134
|
-
if (node->owner != this) throw std::runtime_error("wrong node");
|
|
145
|
+
// if (!node) throw std::runtime_error("nil node");
|
|
146
|
+
// if (node->owner != this) throw std::runtime_error("wrong node");
|
|
135
147
|
_iterator = node->next;
|
|
136
148
|
_started = true;
|
|
137
149
|
}
|
|
@@ -181,23 +193,6 @@ class Queueable {
|
|
|
181
193
|
return out;
|
|
182
194
|
}
|
|
183
195
|
|
|
184
|
-
bool intersection_with_array(const std::vector<T*>& array) {
|
|
185
|
-
if (array.empty() || size == 0) return false;
|
|
186
|
-
|
|
187
|
-
QNode<T>* current = head;
|
|
188
|
-
while (current) {
|
|
189
|
-
if (current->payload) {
|
|
190
|
-
for (T* item : array) {
|
|
191
|
-
if (item && *item == *(current->payload)) {
|
|
192
|
-
return true;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
current = current->next;
|
|
197
|
-
}
|
|
198
|
-
return false;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
196
|
QNode<T>* pop() {
|
|
202
197
|
if (!tail) return nullptr;
|
|
203
198
|
return rem(tail);
|
|
@@ -220,7 +215,7 @@ class Queueable {
|
|
|
220
215
|
|
|
221
216
|
for (T* current : source) {
|
|
222
217
|
if (!result.empty() && *result.back() == *current) {
|
|
223
|
-
result.pop_back();
|
|
218
|
+
result.pop_back();
|
|
224
219
|
} else {
|
|
225
220
|
result.push_back(current);
|
|
226
221
|
}
|