summaryrefslogtreecommitdiff
path: root/starts/meaning-vm/level-0/memorystore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'starts/meaning-vm/level-0/memorystore.cpp')
-rw-r--r--starts/meaning-vm/level-0/memorystore.cpp152
1 files changed, 130 insertions, 22 deletions
diff --git a/starts/meaning-vm/level-0/memorystore.cpp b/starts/meaning-vm/level-0/memorystore.cpp
index adae8b2..220d0c3 100644
--- a/starts/meaning-vm/level-0/memorystore.cpp
+++ b/starts/meaning-vm/level-0/memorystore.cpp
@@ -3,26 +3,75 @@
#include "errors.hpp"
#include "ref.hpp"
-#include <unordered_set>
+#include <memory>
+#include <unordered_map>
namespace intellect {
namespace level0 {
-static auto & concepts()
+static auto & index()
{
- static std::unordered_set<ref, std::hash<concept*>> concepts;
- return concepts;
+ static std::unordered_map<ref, std::unique_ptr<concept>, std::hash<concept*>> index;
+ return index;
}
-ref alloc(std::any data) {
- concept * r = new concept();
- r->data = data;
- concepts().insert(r);
+
+namespace concepts {
+ ref allocator() { static ref ret = basic_alloc(); return ret; };
+ ref allocates() { static ref ret = basic_alloc(); return ret; };
+ ref allocations() { static ref ret = basic_alloc(); return ret; };
+ ref level0allocations() { static ref ret = basic_alloc(); return ret; };
+}
+
+struct init { init()
+{
+ concepts::allocator().link(concepts::allocator(), concepts::level0allocations());
+ concepts::level0allocations().link(concepts::allocates(), concepts::allocator());
+
+ concepts::allocates().link(concepts::allocator(), concepts::level0allocations());
+ concepts::level0allocations().link(concepts::allocates(), concepts::allocates());
+
+ concepts::allocations().link(concepts::allocator(), concepts::level0allocations());
+ concepts::level0allocations().link(concepts::allocates(), concepts::allocations());
+
+ concepts::level0allocations().link(concepts::allocator(), concepts::level0allocations());
+ concepts::level0allocations().link(concepts::allocates(), concepts::level0allocations());
+} } _init;
+
+ref basic_alloc(std::any data)
+{
+ ref r = new concept();
+ r.ptr()->data = data;
+ index().emplace(r, r.ptr());
+ return r;
+}
+
+ref alloc(ref source, std::any data)
+{
+ ref r = basic_alloc(data);
+ alloc(r, source);
return r;
}
-static concept* referenced(ref r) {
- for (ref r2 : concepts()) {
+void alloc(ref r, ref source)
+{
+ r.link(concepts::allocator(), source);
+ source.link(concepts::allocates(), r);
+}
+
+void realloc(ref r, ref newsource)
+{
+ ref oldsource = r.get(concepts::allocator());
+ alloc(r, newsource);
+ dealloc(r, oldsource);
+}
+
+static concept* referenced(ref r, concept* source = 0) {
+ for (auto & r2pair : index()) {
+ ref r2 = r2pair.first;
+ if (r2.ptr() == source) {
+ continue;
+ }
if (r2 == r) {
continue;
}
@@ -38,28 +87,87 @@ static concept* referenced(ref r) {
return 0;
}
-void dealloc(ref r) {
+void basic_dealloc(ref r)
+{
+ auto it = index().find(r);
+ if (it == index().end()) { throw no_such_concept(r); }
+
concept * referenced = intellect::level0::referenced(r);
if (referenced) {
throw still_referenced_by(r, referenced);
}
- for (
- auto it = concepts().begin();
- it != concepts().end();
- ++ it)
- {
- if (*it == r) {
- concepts().erase(it);
- delete (concept*)r;
- return;
+
+ index().erase(it);
+}
+
+void dealloc_from(ref source)
+{
+ std::remove_reference<decltype(index())>::type forgotten;
+
+ auto ours = source.getAll(concepts::allocates());
+ for (auto allocation : ours) {
+ source.unlink(concepts::allocates(), allocation);
+ allocation.unlink(concepts::allocator(), source);
+ if (allocation.linked(concepts::allocator())) { continue; }
+
+ auto it = index().find(allocation);
+ if (it != index().end()) {
+ forgotten.insert(index().extract(it));
+ }
+ }
+ try {
+ for (auto allocation : ours ) {
+ if (allocation.linked(concepts::allocates())) {
+ dealloc_from(allocation);
+ }
+ }
+ for (auto ghost : ours) {
+ concept * referenced = intellect::level0::referenced(ghost, source);
+ if (referenced) {
+ throw still_referenced_by(ghost, referenced);
+ }
+ }
+ } catch(...) {
+ // NOTE: this doesn't rebuild deallocated subgroups, but that could be done
+ // by returning them.
+ index().merge(forgotten);
+ for (auto allocation : ours) {
+ source.link(concepts::allocates(), allocation);
+ allocation.link(concepts::allocator(), source);
+ }
+ throw;
+ }
+
+ // concepts in forgotten will be deallocated when they leave scope
+ // note: scoped allocation is just a plan to forget (at the end of a { } block)
+}
+
+void dealloc(ref r, ref source)
+{
+ auto it = index().find(r);
+ if (it == index().end()) { throw no_such_concept(r); }
+
+ source.unlink(concepts::allocates(), r);
+ r.unlink(concepts::allocator(), source);
+ if (r.linked(concepts::allocator())) { return; }
+
+ try {
+ dealloc_from(r);
+ concept * referenced = intellect::level0::referenced(r, source);
+ if (referenced) {
+ throw still_referenced_by(r, referenced);
}
+
+ index().erase(it);
+ } catch(...) {
+ source.link(concepts::allocates(), r);
+ r.link(concepts::allocator(), source);
}
- throw no_such_concept(r);
}
std::size_t allocated()
{
- return concepts().size();
+ return index().size();
}
}