25
25
#include < new>
26
26
#include < set>
27
27
28
- #include < meevax/memory/region .hpp>
28
+ #include < meevax/memory/tracer .hpp>
29
29
#include < meevax/memory/simple_allocator.hpp>
30
30
#include < meevax/string/header.hpp>
31
31
@@ -44,68 +44,108 @@ inline namespace memory
44
44
* ------------------------------------------------------------------------- */
45
45
{
46
46
public:
47
- struct collectable
47
+ class traceable
48
48
{
49
+ friend class collector ;
50
+
51
+ memory::tracer * tracer = nullptr ;
52
+
53
+ explicit traceable (memory::tracer * tracer)
54
+ : tracer { tracer }
55
+ {
56
+ if (tracer)
57
+ {
58
+ auto const lock = std::unique_lock (resource);
59
+ traceables.insert (std::end (traceables), this );
60
+ }
61
+ }
62
+
63
+ auto reset (memory::tracer * after) -> void
64
+ {
65
+ if (auto before = std::exchange (tracer, after); not before and after)
66
+ {
67
+ auto const lock = std::unique_lock (resource);
68
+ traceables.insert (this );
69
+ }
70
+ else if (before and not after)
71
+ {
72
+ traceables.erase (this );
73
+ }
74
+ }
75
+
76
+ auto locate (void * const data)
77
+ {
78
+ assert (data);
79
+
80
+ if (newest_tracer->contains (data)) // Heuristic-based optimization.
81
+ {
82
+ return newest_tracer;
83
+ }
84
+ else
85
+ {
86
+ auto dummy = memory::tracer (data, 0 );
87
+ auto iter = tracers.lower_bound (&dummy);
88
+ assert (iter != std::end (tracers));
89
+ return *iter;
90
+ }
91
+ }
92
+
49
93
protected:
50
- region * context = nullptr ;
94
+ explicit traceable () = default ;
51
95
52
- explicit constexpr collectable () = default;
96
+ explicit traceable (traceable const & other)
97
+ : traceable { other.tracer }
98
+ {}
53
99
54
100
template <typename Pointer>
55
- explicit collectable (Pointer const p)
56
- : collectable { collector::reset (p, deallocator<Pointer>::deallocate) }
101
+ explicit traceable (Pointer const p)
102
+ : traceable { p ? locate (p) : nullptr }
57
103
{}
58
104
59
- explicit collectable (region * region)
60
- : context { region }
105
+ ~traceable ()
61
106
{
62
- if (context )
107
+ if (tracer )
63
108
{
64
109
auto const lock = std::unique_lock (resource);
65
- objects. try_emplace (this , context );
110
+ traceables. erase (this );
66
111
}
67
112
}
68
113
69
- ~collectable ()
114
+ auto reset ()
70
115
{
71
- auto const lock = std::unique_lock (resource);
72
- objects.erase (this );
116
+ reset (nullptr );
73
117
}
74
118
75
119
template <typename Pointer>
76
120
auto reset (Pointer const p) -> void
77
121
{
78
- reset (collector::reset (p, deallocator<Pointer>::deallocate) );
122
+ reset (p ? locate (p) : nullptr );
79
123
}
80
124
81
- auto reset (region * region ) -> void
125
+ auto reset (traceable const & other ) -> void
82
126
{
83
- if (context = region)
84
- {
85
- auto const lock = std::unique_lock (resource);
86
- objects.insert_or_assign (this , context);
87
- }
127
+ reset (other.tracer );
88
128
}
89
129
};
90
130
91
131
private:
92
- static inline std::mutex resource;
93
-
94
- static inline simple_allocator<region> region_allocator {};
95
-
96
132
template <typename T>
97
133
using set = std::set<T, std::less<T>, simple_allocator<T>>;
98
134
99
- static inline set<region *> regions;
135
+ protected:
136
+ static inline std::mutex resource;
137
+
138
+ static inline simple_allocator<tracer> tracer_source {};
139
+
140
+ static inline tracer * newest_tracer = nullptr ;
100
141
101
- template <typename T, typename U>
102
- using map = std::map<T, U, std::less<T>, simple_allocator<std::pair<T, U>>>;
142
+ static inline set<tracer *> tracers {};
103
143
104
- static inline map<collectable * const , region *> objects ;
144
+ static inline set<traceable *> traceables {} ;
105
145
106
- static inline std::size_t allocation;
146
+ static inline std::size_t allocation = 0 ;
107
147
108
- static inline std::size_t threshold;
148
+ static inline std::size_t threshold = 8_MiB ;
109
149
110
150
public:
111
151
explicit collector ();
@@ -120,33 +160,48 @@ inline namespace memory
120
160
121
161
auto operator =(collector const &) -> collector & = delete ;
122
162
123
- static auto allocate (std::size_t const ) -> void *;
163
+ template <typename T, typename ... Ts>
164
+ static auto make (Ts&&... xs)
165
+ {
166
+ if (auto data = new T (std::forward<decltype (xs)>(xs)...); data)
167
+ {
168
+ if (allocation += sizeof (T); threshold < allocation)
169
+ {
170
+ collect ();
171
+ }
172
+
173
+ newest_tracer = tracer_source.new_ (data, sizeof (T), deallocator<T>::deallocate);
174
+
175
+ assert (tracers.find (newest_tracer) == std::end (tracers));
176
+
177
+ tracers.insert (std::end (tracers), newest_tracer);
178
+
179
+ return data;
180
+ }
181
+ else
182
+ {
183
+ throw std::bad_alloc ();
184
+ }
185
+ }
124
186
125
187
static auto clear () -> void;
126
188
127
189
static auto collect () -> std::size_t;
128
190
129
191
static auto count () noexcept -> std::size_t;
130
192
131
- static auto deallocate (void * const , std::size_t const = 0 ) -> void;
132
-
133
193
static auto mark () -> void;
134
194
135
- static auto region_of (void const * const ) -> decltype(regions)::iterator;
136
-
137
- static auto reset (void * const , deallocator<void >::signature const ) -> region *;
195
+ static auto tracer_of (void * const ) -> decltype(tracers)::iterator;
138
196
139
197
static auto reset_threshold (std::size_t const = std::numeric_limits<std::size_t >::max()) -> void;
140
198
141
199
static auto sweep () -> void;
142
200
143
- static auto traverse (region * const ) -> void;
144
- } static gc;
201
+ static auto trace (tracer * const ) -> void;
202
+ }
203
+ static gc;
145
204
} // namespace memory
146
205
} // namespace meevax
147
206
148
- auto operator new (std::size_t const , meevax::collector &) -> void *;
149
-
150
- void operator delete (void * const , meevax::collector &) noexcept ;
151
-
152
207
#endif // INCLUDED_MEEVAX_MEMORY_COLLECTOR_HPP
0 commit comments