summaryrefslogtreecommitdiff
path: root/intellect-framework-from-internet/starts/meaning-vm/level-0/memorystore.cpp
blob: 24e91b0a786d0c7a0e53b98ad4de38e6c678db24 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "memorystore.hpp"
#include "concept.hpp"
#include "errors.hpp"
#include "ref.hpp"

#include <memory>
#include <unordered_map>

namespace intellect {
namespace level0 {

static auto & index()
{
	static std::unordered_map<ref, std::unique_ptr<concept>, std::hash<concept*>> index;
	return index;
}


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;
}

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;
		}
		for (auto & l : r2.links()) {
			if (ref(l.first) == r) {
				return r2;
			}
			if (ref(l.second) == r) {
				return r2;
			}
		}
	}
	return 0;
}

void basic_dealloc(ref r)
{
	if (r.crucial()) { throw crucial_concept(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);
	}

	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) {
		if (allocation.crucial()) { throw crucial_concept(allocation); }
		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 ) {
			for (auto suballocation : allocation.getAll(concepts::allocates())) {
				// check for this link to find subgroups
				throw still_referenced_by(allocation, suballocation);
			}
		}
		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 {
		if (r.crucial()) { throw crucial_concept(r); }
		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;
	}
}

std::size_t allocated()
{
	return index().size();
}

}
}