-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsmarter_list_lib.cc
164 lines (147 loc) · 4.42 KB
/
smarter_list_lib.cc
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#include "smarter_list.hh"
#include <cassert>
#include <errno.h>
using namespace std;
namespace smarter_list {
// The explicit definition is needed because the compiler always pick this ctor
// rather than the default when no arguments are provided. Is this due somehow
// to Most Vexing Parse?
ListNode::ListNode(const ListNode *ln) {
if (ln) {
name.assign(ln->name);
}
}
bool operator==(const ListNode &a, const ListNode &b) {
return (a.name == b.name);
}
bool operator!=(ListNode &a, ListNode &b) { return !(a == b); }
void SmarterList::Prepend(unique_ptr<ListNode> ln) {
// The default ListNode ctor initializes the name string to empty. Therefore
// it's necessary to define a ListNode with an empty name and a nullptr next
// pointer as empty and then write over it.
if (!head_ || head_->empty()) {
ln->next = unique_ptr<ListNode>();
} else {
ln->next = move(head_);
}
head_ = move(ln);
}
void SmarterList::Reverse() {
if (empty() || !head_->next) {
return;
}
unique_ptr<ListNode> cursor = move(head_);
unique_ptr<ListNode> cursor_next;
while (cursor) {
cursor_next = move(cursor->next);
Prepend(move(cursor));
cursor = move(cursor_next);
}
}
SmarterList::SmarterList(::std::vector<::std::string> strvec) {
// Explicitly initializing with a nullptr
// head_ = std::make_unique<ListNode>(nullptr);
// results in a runtime error.
head_ = std::make_unique<ListNode>();
for (auto it = strvec.begin(); it != strvec.end(); it++) {
Prepend(std::make_unique<ListNode>(*it));
}
Reverse();
cursor_ = head_.get();
}
// Callers of the function must check that the return value is not null and
// refrain from calling the function again if it is.
ListNode *SmarterList::operator++() const {
if (!empty() && cursor_) {
cursor_ = cursor_->next.get();
} else {
cursor_ = nullptr;
}
return cursor_;
}
ListNode *SmarterList::operator--() const {
if (!cursor_) {
return nullptr;
}
if (empty() || (*cursor_ == *(head_.get()))) {
cursor_ = nullptr;
return nullptr;
}
ListNode *previous = head_.get();
while (previous && previous->next.get() != cursor_) {
previous = previous->next.get();
}
cursor_ = previous;
return cursor_;
}
bool operator==(const SmarterList &a, const SmarterList &b) {
if ((!a.empty() && b.empty()) || (!b.empty() && a.empty())) {
return false;
}
a.reset();
b.reset();
while (nullptr != a.current()) {
if (nullptr == b.current()) {
return false;
}
if (*a.current() != *b.current()) {
return false;
}
++a;
++b;
}
// b has one more ListNode.
if (nullptr != b.current()) {
return false;
}
return true;
}
bool operator!=(const SmarterList &a, const SmarterList &b) {
return !(a == b);
}
ostream &operator<<(ostream &out, const SmarterList &sl) {
sl.reset();
for (const ListNode *ln = sl.begin(); ln != nullptr; ln = ++sl) {
out << ln->name << ", ";
}
out << endl;
return out;
}
// Note that the ListNodes returned in the pairs must be moved even though they
// are anonymous and not available outside the pairs. Failed with error about
// deleted ListNode copy ctor when the default move ctor was used.
pair<int, ListNode> SmarterList::operator[](const int i) {
if (empty() || (i < 0)) {
// While moving the empyt ListNode makes the function compile, trying to
// access it causes a runtime error. The problem is that the compiler
// chooses ListNode(smarter_list::ListNode const*) over the default ctor.
return make_pair(ENODATA, move(ListNode()));
}
int j = 0;
// Without resetting the cursor_ to head_, the behavior is unpredictable. This
// is puzzling, as the ctors initialized the value of cursor_.
reset();
while (j != i) {
this->operator++();
j++;
if (nullptr == current()) {
return make_pair(ENODATA, move(ListNode()));
}
}
return make_pair(0, move(ListNode(current()->name)));
}
// It's also possible to make the input non-const and move() it, but the next
// data member will get overwritten anyway.
// Would be better called Postpend().
void SmarterList::operator+(const ListNode &ln) {
if (nullptr == head_) {
Prepend(std::make_unique<ListNode>(ListNode(ln.name)));
return;
}
// No need to reset(), as we want the last node anyway.
while (nullptr != cursor_->next) {
cursor_ = cursor_->next.get();
}
cursor_->next = std::make_unique<ListNode>(ListNode(ln.name));
}
} // namespace smarter_list