#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
class StrBlobPtr;
class StrBlob
{
public:
friend class StrBlobPtr;
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string> il);
size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }
void push_back(const std::string &t) { data->push_back(t); }
void pop_back();
std::string& front();
std::string& back();
std::string& front() const;
std::string& back() const;
StrBlobPtr begin() { return StrBlobPtr(*this); }
StrBlobPtr end()
{
auto ret = StrBlobPtr(*this, data->size());
return ret;
}
private:
std::shared_ptr<std::vector<std::string>> data;
void check(size_type i, const std::string &msg) const;
};
class StrBlobPtr
{
public:
typedef std::shared_ptr<std::vector<std::string>> sh_ptr;
StrBlobPtr() : curr(0) {}
StrBlobPtr(StrBlob &a, std::size_t sz)
: wptr(a.data), curr(sz) {}
std::string& deref() const;
StrBlobPtr& incr();
private:
sh_ptr check(std::size_t, const std::string&) const;
std::weak_ptr<std::vector<std::string>> wptr;
std::size_t curr;
};
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_type i, const std::string &msg) const
{
if (i >= data->size())
throw std::out_of_range(msg);
}
std::string& StrBlob::front()
{
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::front() const
{
check(0, "const back on empty StrBlob");
return data->front();
}
std::string& StrBlob::back() const
{
check(0, "const back on empty StrBlob");
return data->back();
}
void StrBlob::pop_back()
{
check(0, "pop_back on empty StrBlob");
return data->pop_back();
}
StrBlobPtr::sh_ptr StrBlobPtr::check(std::size_t i, const std::string &msg) const
{
auto ret = wptr.lock();
if (!ret)
throw std::runtime_error("Unbound StrBlobPtr");
if (i >= ret->size())
throw std::out_of_range(msg);
return ret;
}
std::string& StrBlobPtr::deref() const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& StrBlobPtr::incr()
{
auto p = check(curr, "increment past end");
++curr;
return *this;
}