/*
Copyright 2013 Adobe Systems Incorporated
Distributed under the MIT License (see license at
http://stlab.adobe.com/licenses.html)
This file is intended as example code and is not production quality.
*/
#include <cassert>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;
/******************************************************************************/
// Library
template <typename T>
void draw(const T& x, ostream& out, size_t position)
{ out << string(position, ' ') << x << endl; }
class object_t {
public:
template <typename T>
object_t(T x) : self_(new model<T>(move(x)))
{ }
object_t(const object_t& x) : self_(x.self_->copy_())
{ }
object_t(object_t&&) noexcept = default;
object_t& operator=(const object_t& x)
{ object_t tmp(x); *this = move(tmp); return *this; }
object_t& operator=(object_t&&) noexcept = default;
friend void draw(const object_t& x, ostream& out, size_t position)
{ x.self_->draw_(out, position); }
private:
struct concept_t {
virtual ~concept_t() = default;
virtual concept_t* copy_() const = 0;
virtual void draw_(ostream&, size_t) const = 0;
};
template <typename T>
struct model : concept_t {
model(T x) : data_(move(x)) { }
concept_t* copy_() const { return new model(*this); }
void draw_(ostream& out, size_t position) const
{ draw(data_, out, position); }
T data_;
};
unique_ptr<const concept_t> self_;
};
using document_t = vector<object_t>;
void draw(const document_t& x, ostream& out, size_t position)
{
out << string(position, ' ') << "<document>" << endl;
for (auto& e : x) draw(e, out, position + 2);
out << string(position, ' ') << "</document>" << endl;
}
using history_t = vector<document_t>;
void commit(history_t& x) { assert(x.size()); x.push_back(x.back()); }
void undo(history_t& x) { assert(x.size()); x.pop_back(); }
document_t& current(history_t& x) { assert(x.size()); return x.back(); }
/******************************************************************************/
// Client
class my_class_t {
/* ... */
};
void draw(const my_class_t&, ostream& out, size_t position)
{ out << string(position, ' ') << "my_class_t" << endl; }
int main()
{
history_t h(1);
current(h).emplace_back(0);
current(h).emplace_back(string("Hello!"));
draw(current(h), cout, 0);
cout << "--------------------------" << endl;
commit(h);
current(h).emplace_back(current(h));
current(h).emplace_back(my_class_t());
current(h)[1] = string("World");
draw(current(h), cout, 0);
cout << "--------------------------" << endl;
undo(h);
draw(current(h), cout, 0);
}