-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy path14.30b.h
151 lines (133 loc) · 3.92 KB
/
14.30b.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
/*
* Exercise 14.30: Add dereference and arrow operators to your StrBlobPtr class
* and to the ConstStrBlobPtr class that you defined in exercise 12.22 from §
* 12.1.6 (p. 476). Note that the operators in constStrBlobPtr must return
* const references because the data member in constStrBlobPtr points to a
* const vector.
*/
#ifndef STRING_BLOG_H
#define STRING_BLOG_H
#include <fstream>
#include <exception>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class ConstStrBlobPtr;
class StrBlob {
friend class ConstStrBlobPtr;
public:
using size_type = std::vector<std::string>::size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
ConstStrBlobPtr begin() const;
ConstStrBlobPtr end() const;
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
// add and remove elements
void push_back(const std::string &t) { data->push_back(t); }
void pop_back();
// element access
std::string& front();
std::string& back();
std::string& front() const;
std::string& back() const;
private:
std::shared_ptr<std::vector<std::string>> data;
// throws msg if data[i] isn't valid
void check(size_type, const std::string &) 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)) {}
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, "pop 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();
}
// ConstStrBlobPtr throws an exception on attempts to access a nonexistent element
class ConstStrBlobPtr {
public:
ConstStrBlobPtr() : curr(0) {}
ConstStrBlobPtr(const StrBlob &a, size_t sz = 0) :
wptr(a.data), curr(sz) {}
ConstStrBlobPtr& operator++();
ConstStrBlobPtr operator++(int);
const std::string& operator*() const;
const std::string* operator->() const;
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>>
ConstStrBlobPtr::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 ConstStrBlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret; // otherwise, return a shared_ptr to the vector
}
const std::string&
ConstStrBlobPtr::operator*() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
const std::string*
ConstStrBlobPtr::operator->() const
{
return & this->operator*();
}
// prefix: return a reference to the increment object
ConstStrBlobPtr&
ConstStrBlobPtr::operator++()
{
check(curr, "increment past end of ConstStrBlobPtr");
++curr;
return *this;
}
// postfix: increment object nut return a the unincrement object
ConstStrBlobPtr
ConstStrBlobPtr::operator++(int)
{
auto ret = *this;
check(curr, "increment past end of ConstStrBlobPtr");
++*this;
return ret;
}
// these members can't be defined until StrStrBlob and ConstStrBlobPtr are defined.
ConstStrBlobPtr StrBlob::begin() const { return ConstStrBlobPtr(*this); }
ConstStrBlobPtr StrBlob::end() const { return ConstStrBlobPtr(*this, data->size()); }
#endif