#include <vector>
#include <string>
#include <memory>
#include <cassert>
using namespace std;
template<typename T>
void draw(const T& x, ostream& out, size_t pos) {
out << string(pos, ' ') << x << "\n";
}
class object_t {
public:
template<typename T>
object_t(T x) : self_(make_shared<model<T>>(move(x))) {
cout << "ctor\n";
}
friend void draw(const object_t& x, ostream& out, size_t pos) {
x.self_->draw_(out, pos);
}
private:
struct concept_t {
virtual ~concept_t() = default;
virtual void draw_(ostream&, size_t) const = 0;
};
template<typename T>
struct model: concept_t {
model(T x) : data_(move(x)) {
}
void draw_(ostream& out, size_t pos) const {
draw(data_, out, pos);
}
T data_;
};
private:
shared_ptr< const concept_t> self_;
};
using document_t = vector<object_t>;
class my_class_t {
};
void draw(const my_class_t&, ostream& out, size_t pos) {
out << string(pos, ' ') << "my_class_t\n";
}
void draw(const document_t& x, ostream& out, size_t pos) {
out << string(pos, ' ') << "<document>\n";
for (const auto& e: x) {
draw(e, out, pos + 2);
}
out << string(pos, ' ') << "</document>\n";
}
using history_t = vector<document_t>;
void commit(history_t& x) {
assert(!x.empty());
x.push_back(x.back());
}
void undo(history_t& x) {
assert(!x.empty());
x.pop_back();
}
document_t& current(history_t& x) {
assert(!x.empty());
return x.back();
}
int main() {
history_t h(1);
current(h).emplace_back(0);
current(h).emplace_back(string("hello"));
draw(current(h), cout, 0);
cout << "-----------------------\n";
commit(h);
current(h).emplace_back(current(h));
current(h).emplace_back(my_class_t());
cout << "change hello\n";
current(h)[1] = string("world");
draw(current(h), cout, 0);
cout << "-----------------------\n";
undo(h);
draw(current(h), cout, 0);
return 0;
}