Skip to content

Instantly share code, notes, and snippets.

@nikomatsakis
Created March 1, 2012 04:55
Show Gist options
  • Save nikomatsakis/1947382 to your computer and use it in GitHub Desktop.
Save nikomatsakis/1947382 to your computer and use it in GitHub Desktop.
simple one-writer revisions in C++
namespace revisions {
using namespace std;
class graph_t;
class version_t {
private:
graph_t *graph;
unsigned id;
unsigned ref_cnt;
version_t *prev;
public:
version_t(graph_t *aGraph)
: graph(aGraph)
, id(0)
, ref_cnt(0)
, prev(NULL)
{}
version_t(version_t *aPrev)
: graph(aPrev->graph)
, id(aPrev->id + 1)
, ref_cnt(0)
, prev(aPrev)
{}
void inc_ref();
void dec_ref();
};
template<class T>
struct vdata_t {
version_t *rev;
T data;
vdata_t *prev;
vdata_t(version_t *aRev, T aData, vdata_t *aPrev)
: rev(aRev)
, data(aData)
, prev(aPrev)
{}
};
template<class T>
struct versioned_t {
private:
vdata_t<T> *vdata;
public:
void write(graph_t *gr, T (^blk)(const T&));
};
template<class T>
class handle_t {
private:
version_t *version;
versioned_t<T> *obj;
T &find();
public:
handle_t(version_t *aVersion, versioned_t<T> *anObj)
: version(aVersion)
, obj(anObj)
{
version->inc_ref();
}
~handle_t() {
version->dec_ref();
}
template<class A> A read(A(^blk)(const T&)) {
return blk(find());
}
};
class graph_t {
private:
version_t *head;
public:
graph_t()
: head(new version_t(this))
{}
version_t *freeze();
template<class A> versioned_t<A> mk_versioned();
template<class A> handle_t<A> mk_handle(versioned_t<A> *v);
};
//
void
version_t::inc_ref() {
ref_cnt++; // make atomic
}
void
version_t::dec_ref() {
ref_cnt--; // make atomic
}
version_t *
graph_t::freeze() {
version_t *prev = head;
head = new version_t(prev);
return prev;
}
template<class A>
versioned_t<A>
graph_t::mk_versioned() {
return new versioned_t<A>();
}
template<class A>
handle_t<A>
graph_t::mk_handle(versioned_t<A> *v) {
version_t *ver = freeze();
handle_t<A> *result = new handle_t<A>(ver, v);
return result;
}
template<class T>
void
versioned_t<T>::write(graph_t *gr, T (^blk)(const T&)) {
vdata = new vdata_t<T>(
gr,
blk(&vdata->data),
vdata);
}
template<class T>
T &
handle_t<T>::find() {
vdata_t<T> *vdata = obj->vdata;
unsigned ver_id = version->id;
while (vdata->rev->id > ver_id) {
vdata = vdata->prev;
}
return vdata->data;
}
} // end namespace revisions
namespace dom {
using namespace revisions;
class dom_node
{
public:
versioned_t<dom_node> *parent;
versioned_t<dom_node> *child;
versioned_t<dom_node> *sibling;
dom_node(versioned_t<dom_node> *aParent,
versioned_t<dom_node> *aChild,
versioned_t<dom_node> *aSibling)
: parent(aParent)
, child(aChild)
, sibling(aSibling)
{}
dom_node with_parent(versioned_t<dom_node> *parent) const
{
return dom_node(parent, child, sibling);
}
dom_node with_child(versioned_t<dom_node> *child) const
{
return dom_node(parent, child, sibling);
}
dom_node with_sibling(versioned_t<dom_node> *sibling) const
{
return dom_node(parent, child, sibling);
}
};
void set_parent(graph_t *gr,
versioned_t<dom_node> *node,
versioned_t<dom_node> *parent)
{
node->write(
gr,
^(const dom_node &d) { return d.with_parent(parent); });
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment