Str_blob && Str_blob_ptr
/****************************************
* IDE: VS2010
****************************************/
#include
using std::shared_ptr; using std::make_shared; using std::weak_ptr;
#include
using std::vector;
#include
using std::string;
#include
using std::out_of_range; using std::runtime_error;
#include
using std::begin; using std::end;
#include
using std::cin; using std::cout; using std::endl;
// forward declaration
class Str_blob_ptr;
// class I define usually begin with an uppercase letter.
// class Str_blob should be defined in Str_blob.h,
// and implemented in Str_blob.cpp.
class Str_blob
{
friend class Str_blob_ptr;
public:
typedef vector::size_type size_type;
// constructors
Str_blob() : data(make_shared>()) { }
Str_blob(string *b, string *e);
// size operation
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
// add and remove elements
void push_back(const string &t) { data->push_back(t); }
void pop_back();
// element access
string &front();
string &back();
// interface to Str_blob_ptr
Str_blob_ptr begin();
Str_blob_ptr end();
private:
shared_ptr> data;
// throw msg if data[i] isn't valid
void check(size_type i, const string &msg) const;
};
// constructor
inline Str_blob::Str_blob(string *b, string *e) :
data(make_shared>(b, e)) { }
void Str_blob::check(size_type i, const string &msg) const
{
if (i >= data->size())
{
throw out_of_range(msg);
}
}
// Str_blob_ptr throws an exception on attempts to access a nonexistent element
class Str_blob_ptr
{
friend bool eq(const Str_blob_ptr &, const Str_blob_ptr &);
public:
Str_blob_ptr() : curr(0) { }
Str_blob_ptr(Str_blob &a, size_t sz = 0) :
wptr(a.data), curr(sz) { }
string &deref() const;
Str_blob_ptr &incr(); // prefix version
Str_blob_ptr &decr(); // prefix version
private:
// check returns a shared_ptr to the vector if the check succeeds
shared_ptr> check(size_t, const string &) const;
// store a weak_ptr, which means the underlying vector might be destroyed
weak_ptr> wptr;
size_t curr; // current position within the array
};
string &Str_blob::front()
{
// if the vector is empty, check will throw
check(0, "front on empty Str_blob");
return data->front();
}
string &Str_blob::back()
{
check(0, "back on empty Str_blob");
return data->back();
}
void Str_blob::pop_back()
{
check(0, "pop_back on empty Str_blob");
data->pop_back();
}
inline
shared_ptr>
Str_blob_ptr::check(size_t i, const string &msg) const
{
auto ret = wptr.lock();
if (!ret)
{
throw runtime_error("unbound Str_blob_ptr");
}
if (i >= ret->size())
{
throw out_of_range(msg);
}
return ret;
}
inline string &Str_blob_ptr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
// prefix: return a reference to the increment object
inline Str_blob_ptr &Str_blob_ptr::incr()
{
// if curr already points past the end of the container, can't increment it
check(curr, "increment past end of Str_blob_ptr");
++curr;
return *this;
}
inline Str_blob_ptr &Str_blob_ptr::decr()
{
// if curr is zero, decrementing it will yield an invalid subscript
--curr;
check(-1, "decrement past begin of Str_blob_ptr");
return *this;
}
// begin and end members for str_blob
inline Str_blob_ptr Str_blob::begin()
{
return Str_blob_ptr(*this);
}
inline Str_blob_ptr Str_blob::end()
{
Str_blob_ptr ret = Str_blob_ptr(*this, data->size());
return ret;
}
inline bool eq(const Str_blob_ptr &lhs, const Str_blob_ptr &rhs)
{
auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
if (l == r)
{
// then they're equal if they're both null or
// if they point to the same element
return (!r || lhs.curr == rhs.curr);
}
else
{
return false;
}
}
inline bool neq(const Str_blob_ptr &lhs, const Str_blob_ptr &rhs)
{
return !eq(lhs, rhs);
}
int main(void)
{
/* Str_blob b1;
{
string temp[] = { "a", "an", "the" };
Str_blob b2(begin(temp), end(temp));
b1 = b2;
b2.push_back("about");
cout << b2.size() << endl;
}
cout << b1.size() << endl;*/
Str_blob b1;
string word;
while (cin >> word)
{
b1.push_back(word);
}
for (Str_blob_ptr it = b1.begin(); neq(it, b1.end()); it.incr())
{
cout << it.deref() << endl;
}
return 0;
}