Created
March 1, 2012 04:55
-
-
Save nikomatsakis/1947382 to your computer and use it in GitHub Desktop.
simple one-writer revisions in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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