|
@@ -0,0 +1,128 @@
|
|
|
+#ifndef STRBLOB_H
|
|
|
+#define STRBLOB_H
|
|
|
+
|
|
|
+
|
|
|
+#include <algorithm>
|
|
|
+#include <iostream>
|
|
|
+#include <string>
|
|
|
+#include <vector>
|
|
|
+#include <memory>
|
|
|
+
|
|
|
+
|
|
|
+class StrBlobPtr;
|
|
|
+
|
|
|
+
|
|
|
+class StrBlob {
|
|
|
+friend class StrBlobPtr;
|
|
|
+
|
|
|
+public:
|
|
|
+ typedef std::vector<std::string>::size_type size_type;
|
|
|
+ StrBlob();
|
|
|
+ StrBlob(std::initializer_list<std::string> il);
|
|
|
+
|
|
|
+ void push_back(const std::string &s) { data->push_back(s); }
|
|
|
+ void pop_back();
|
|
|
+
|
|
|
+ std::string &front();
|
|
|
+ const std::string &front() const;
|
|
|
+ std::string &back();
|
|
|
+ const std::string &back() const;
|
|
|
+
|
|
|
+ StrBlobPtr begin();
|
|
|
+ StrBlobPtr begin() const;
|
|
|
+ StrBlobPtr end();
|
|
|
+ StrBlobPtr end() const;
|
|
|
+
|
|
|
+ size_type size() const { return data->size(); }
|
|
|
+ bool empty() const { return data->empty(); }
|
|
|
+private:
|
|
|
+ std::shared_ptr<std::vector<std::string>> data;
|
|
|
+ void check(size_type i, const std::string &msg) const;
|
|
|
+}; // !StrBlob
|
|
|
+
|
|
|
+// functions of StrBlob
|
|
|
+inline StrBlob::StrBlob() : data(std::make_shared<std::vector<std::string>>()) {}
|
|
|
+
|
|
|
+inline StrBlob::StrBlob(std::initializer_list<std::string> il) : data(std::make_shared<std::vector<std::string>>(il)) {}
|
|
|
+
|
|
|
+inline void StrBlob::check(size_type i, const std::string &msg) const {
|
|
|
+ if (i >= data->size())
|
|
|
+ throw std::out_of_range(msg);
|
|
|
+}
|
|
|
+
|
|
|
+inline const std::string &StrBlob::front() const {
|
|
|
+ check(0, "front on empty StrBlob");
|
|
|
+ return data->front();
|
|
|
+}
|
|
|
+inline std::string &StrBlob::front() {
|
|
|
+ check(0, "front on empty StrBlob");
|
|
|
+ return data->front();
|
|
|
+}
|
|
|
+
|
|
|
+inline const std::string &StrBlob::back() const {
|
|
|
+ check(0, "back on empty StrBlob");
|
|
|
+ return data->back();
|
|
|
+}
|
|
|
+inline std::string &StrBlob::back() {
|
|
|
+ check(0, "back on empty StrBlob");
|
|
|
+ return data->back();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class StrBlobPtr {
|
|
|
+public:
|
|
|
+ StrBlobPtr() : curr(0) {}
|
|
|
+ StrBlobPtr(StrBlob &a, std::size_t sz = 0) : wptr(a.data), curr(sz) {}
|
|
|
+ StrBlobPtr(const StrBlob &a, std::size_t sz = 0) : wptr(a.data), curr(sz) {}
|
|
|
+
|
|
|
+ std::string &deref() const;
|
|
|
+ StrBlobPtr &incr();
|
|
|
+
|
|
|
+ bool equal(const StrBlobPtr &);
|
|
|
+
|
|
|
+private:
|
|
|
+ std::shared_ptr<std::vector<std::string>> check(std::size_t, const std::string &msg) const;
|
|
|
+ std::weak_ptr<std::vector<std::string>> wptr;
|
|
|
+ std::size_t curr;
|
|
|
+}; // !StrBlobPtr
|
|
|
+
|
|
|
+// functions of StrBlobPtr
|
|
|
+inline std::string &StrBlobPtr::deref() const {
|
|
|
+ auto p = check(curr, "deref pass end");
|
|
|
+ return (*p)[curr];
|
|
|
+}
|
|
|
+
|
|
|
+inline StrBlobPtr &StrBlobPtr::incr() {
|
|
|
+ ++curr;
|
|
|
+ return *this;
|
|
|
+}
|
|
|
+
|
|
|
+inline bool StrBlobPtr::equal(const StrBlobPtr &sbp) {
|
|
|
+ return (*this).curr == sbp.curr;
|
|
|
+}
|
|
|
+
|
|
|
+inline std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::string &msg) const {
|
|
|
+ auto ret = wptr.lock();
|
|
|
+ if (!ret)
|
|
|
+ throw std::runtime_error("unbound StrBlob");
|
|
|
+ if (i >= ret->size())
|
|
|
+ throw std::out_of_range(msg);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+// functions of StrBlob
|
|
|
+StrBlobPtr StrBlob::begin() {
|
|
|
+ return StrBlobPtr(*this);
|
|
|
+}
|
|
|
+StrBlobPtr StrBlob::begin() const {
|
|
|
+ return StrBlobPtr(*this);
|
|
|
+}
|
|
|
+
|
|
|
+StrBlobPtr StrBlob::end() {
|
|
|
+ return StrBlobPtr(*this, data->size());
|
|
|
+}
|
|
|
+StrBlobPtr StrBlob::end() const {
|
|
|
+ return StrBlobPtr(*this, data->size());
|
|
|
+}
|
|
|
+
|
|
|
+#endif // !STRBLOB_H
|