Blob.h
#pragma once
#include <vector>
#include <memory>
#include <stdexcept>
#include <string>
template <typename T> class BlobPtr;
template <typename T> class Blob;
template <typename T>
bool operator==(const Blob<T> &, const Blob<T> &);
template <typename T> class Blob {
friend class BlobPtr<T>;
friend bool operator==<T>(const Blob<T> &lhs, const Blob<T> &rhs);
public:
Blob();
Blob(std::initializer_list<T> il);
template <typename T>
template <typename Itr>
Blob(Itr b, Itr e)
: data(std::shared_ptr<std::vector<T>>(b, e)) {}
size_t size() const;
bool empty() const;
void push_back(const T&);
void push_back(T &&);
void pop_back();
T &back() const;
T &operator[](size_t index) const;
private:
void check(size_t i, const std::string &msg) const;
std::shared_ptr<std::vector<T>> data;
};
template <typename T>
Blob<T>::Blob() : data(new std::vector<T>) {}
template <typename T>
Blob<T>::Blob(std::initializer_list<T> il)
: data(new std::vector<T>(il)) {}
template <typename T>
size_t Blob<T>::size() const {
return data->size();
}
template <typename T>
bool Blob<T>::empty() const {
return data->empty();
}
template <typename T>
void Blob<T>::push_back(const T &t) {
data->push_back(t);
}
template <typename T>
void Blob<T>::push_back(T &&t) {
data->push_back(std::move(t));
}
template <typename T>
void Blob<T>::pop_back() {
check(0, "pop back on empty Blob");
data->pop_back();
}
template <typename T>
T &Blob<T>::back() const {
check(0, "get back on empty Blob");
return data->back();
}
template <typename T>
T &Blob<T>::operator[](size_t index) const {
check(index, "get element pass the boundary");
return (*data)[index];
}
template <typename T>
void Blob<T>::check(size_t index, const std::string &msg) const {
if (index >= data->size()) {
throw std::out_of_range(msg);
}
}
BlobPtr.h
#pragma once
#include "Blob.h"
template <typename T>
class BlobPtr{
public:
BlobPtr() = default;
BlobPtr(Blob<T> &b, size_t sz);
T& operator*() const;
BlobPtr& operator++();
BlobPtr& operator--();
private:
std::shared_ptr<std::vector<T>>
check(size_t, const std::string &) const;
std::weak_ptr<std::vector<T>> wptr;
size_t curr = 0;
};
template <typename T>
BlobPtr<T>::BlobPtr(Blob<T> &b, size_t sz)
: wptr(b.data), curr(sz) {}
template <typename T>
T& BlobPtr<T>::operator*() const {
auto ptr = check(curr, "dereference pass the end");
return (*ptr)[curr];
}
template <typename T>
BlobPtr<T> &BlobPtr<T>::operator++() {
check(curr + 1, "increase index pass the end");
++curr;
return *this;
}
template <typename T>
BlobPtr<T> &BlobPtr<T>::operator--() {
check(curr - 1, "decrease index pass the beg");
--curr;
return *this;
}
template <typename T>
std::shared_ptr<std::vector<T>>
BlobPtr<T>::check(size_t index, const std::string &msg) const {
auto p = wptr.lock();
if (p) {
if (p->size() > index) {
return p;
} else {
throw std::out_of_range(msg);
}
} else {
throw "unbind BlobPtr";
}
}
main.cpp
#include <iostream>
#include "Blob.h"
#include "BlobPtr.h"
using namespace std;
int main() {
std::initializer_list<int> il{1,2,3,4,5};
Blob<int> b(il);
cout << b.empty() << endl;
cout << b.size() << endl;
cout << b.back() << endl;
b.push_back(6);
cout << b.back() << endl;
b.pop_back();
cout << b.back() << endl;
cout << b.size() << endl;
cout << "=========================================" << endl;
std::initializer_list<int> il{1,2,3,4,5};
Blob<int> b(il);
BlobPtr<int> ptr(b, 0);
cout << *ptr << endl;
cout << *++ptr << endl;
}