-
Notifications
You must be signed in to change notification settings - Fork 33
/
14.28.h
295 lines (258 loc) · 7.03 KB
/
14.28.h
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
* Exercise 14.28: Define addition and subtraction for StrBlobPtr so that these
* operators implement pointer arithmetic (§ 3.5.3, p. 119).
*
* By Faisal Saadatmand
*/
#ifndef STR_BLOB_H
#define STR_BLOB_H
#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class StrBlobPtr;
class StrBlob {
friend bool operator==(const StrBlob &, const StrBlob &);
friend bool operator!=(const StrBlob &, const StrBlob &);
friend bool operator<(const StrBlob &, const StrBlob &);
public:
friend class StrBlobPtr;
using size_type = std::vector<std::string>::size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
StrBlob(const StrBlob &rhs) : // copy constructor
data(std::make_shared<std::vector<std::string>> (*rhs.data)) { }
StrBlob& operator=(const StrBlob &); // copy assignment operator
StrBlobPtr begin() const; // return StrBlobPtr to the first element
StrBlobPtr end() const; // and one past the last element
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
// add and remove elements
void push_back(const std::string &);
void push_back(std::string &&);
void pop_back();
// element access
std::string& front();
std::string& back();
std::string& front() const;
std::string& back() const;
std::string& operator[](std::size_t n) { return data->at(n); }
const std::string& operator[](std::size_t n) const
{ return data->at(n); }
private:
std::shared_ptr<std::vector<std::string>> data;
// throws msg if data[i] isn't valid
void check(size_type i, const std::string &msg) const;
};
// constructors
StrBlob::StrBlob() : data(std::make_shared<std::vector<std::string>>()) {}
StrBlob::StrBlob(std::initializer_list<std::string> il) :
data(std::make_shared<std::vector<std::string>>(il)) {}
// copy assignment operator
StrBlob&
StrBlob::operator=(const StrBlob &rhs)
{
auto temp = std::make_shared<std::vector<std::string>>(*rhs.data);
data = temp;
return *this;
}
// members
void StrBlob::check(size_t i, const std::string &msg) const
{
if (i >= data->size())
throw std::out_of_range(msg);
}
void StrBlob::pop_back()
{
check(0, "back on empty StrBlob");
data->pop_back();
}
std::string& StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
std::string& StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
std::string& StrBlob::back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
void
StrBlob::push_back(const std::string &t)
{
data->push_back(t);
std::cout << "bush_back(const std::string &) &\n";
}
void
StrBlob::push_back(std::string &&t)
{
data->push_back(std::move(t));
std::cout << "bush_back(const std::string &) &&\n";
}
// StrBlobPtr throws an exception on attempts to access a nonexistent element
class StrBlobPtr {
friend bool operator==(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator!=(const StrBlobPtr &, const StrBlobPtr &);
friend bool operator<(const StrBlobPtr &, const StrBlobPtr &);
friend StrBlobPtr operator-(const StrBlobPtr &, const StrBlobPtr &);
friend StrBlobPtr operator+(const StrBlobPtr &, const size_t);
friend StrBlobPtr operator-(const StrBlobPtr &, const size_t);
public:
StrBlobPtr() : curr(0) {}
StrBlobPtr(const StrBlob &a, size_t sz = 0) :
wptr(a.data), curr(sz) {}
std::string& deref() const;
std::string& operator[](std::size_t);
const std::string& operator[](std::size_t) const;
StrBlobPtr& operator-=(const StrBlobPtr &);
StrBlobPtr& operator+=(const size_t);
StrBlobPtr& operator-=(const size_t);
StrBlobPtr operator++();
StrBlobPtr operator++(int);
StrBlobPtr operator--();
StrBlobPtr operator--(int);
private:
// check returns a shared_ptr to the vector if the check succeeds
std::shared_ptr<std::vector<std::string>>
check(std::size_t, const std::string &) const;
// store a weak_ptr, which means the underlying vector might be destroyed
std::weak_ptr<std::vector<std::string>> wptr;
size_t curr; // current position within the array
};
std::shared_ptr<std::vector<std::string>>
StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
auto ret = wptr.lock(); // is the vector still around
if (!ret)
throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret; // otherwise, return a shared_ptr to the vector
}
std::string&
StrBlobPtr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr]; // (*p) is the vector to which this object points
}
// prefix: return a reference to the incremented object
StrBlobPtr
StrBlobPtr::operator++()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
// postfix: increment/decrement the object but return the unchanged value
StrBlobPtr
StrBlobPtr::operator++(int)
{
auto ret = *this;
++*this; // call class' prefix increment
return ret;
}
// prefix: return a reference to the decremented object
StrBlobPtr
StrBlobPtr::operator--()
{
check(curr, "increment past end of StrBlobPtr");
--curr;
return *this;
}
// postfix: decrement the object but return the unchanged value
StrBlobPtr
StrBlobPtr::operator--(int)
{
auto ret = *this;
--*this; // call class' prefix increment
return ret;
}
// subscript: return reference at n
std::string&
StrBlobPtr::operator[](std::size_t n)
{
auto p = check(n, "subscript out of bound");
return (*p)[n];
}
const std::string&
StrBlobPtr::operator[](std::size_t n) const
{
auto p = check(n, "subscript out of bound");
return (*p)[n];
}
StrBlobPtr&
StrBlobPtr::operator-=(const StrBlobPtr &rhs)
{
curr -= rhs.curr;
return *this;
}
StrBlobPtr&
StrBlobPtr::operator+=(const size_t n)
{
curr += n;
return *this;
}
StrBlobPtr&
StrBlobPtr::operator-=(const size_t n)
{
curr -= n;
return *this;
}
// these members can't be defined until StrStrBlob and StrBlobPtr are defined.
StrBlobPtr StrBlob::begin() const { return StrBlobPtr(*this); }
StrBlobPtr StrBlob::end() const { return StrBlobPtr(*this, data->size()); }
// non-member function
bool operator==(const StrBlob &lhs, const StrBlob &rhs)
{
return *lhs.data == *rhs.data;
}
bool operator!=(const StrBlob &lhs, const StrBlob &rhs)
{
return !(lhs == rhs); // delegates to == class operator
}
bool operator<(const StrBlob &lhs, const StrBlob &rhs)
{
return *lhs.data < *rhs.data;
}
bool operator==(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return lhs.deref() == rhs.deref();
}
bool operator!=(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return !(lhs == rhs);
}
bool operator<(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
return lhs.deref() < rhs.deref();
}
StrBlobPtr operator-(const StrBlobPtr &lhs, const StrBlobPtr &rhs)
{
auto total = lhs;
total -= rhs;
return total;
}
StrBlobPtr operator+(const StrBlobPtr &lhs, const size_t n)
{
auto sum = lhs;
sum += n;
return sum;
}
StrBlobPtr operator-(const StrBlobPtr &lhs, const size_t n)
{
auto total = lhs;
total -= n;
return total;
}
#endif