00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #ifndef MORE_GEN_RECYCLER_H
00031 #define MORE_GEN_RECYCLER_H
00032
00033 #include <more/gen/hook.h>
00034 #include <more/gen/ring.h>
00035 #include <more/gen/functional.h>
00036 #include <list>
00037 #include <stdexcept>
00038 #include <string>
00039 #ifdef MORE_ENABLE_LOGGING
00040 # include <iostream>
00041 #endif
00042
00043
00044 namespace more {
00045 namespace gen {
00046
00047
00048
00049
00050 extern bool opt_recycler_do_log;
00051
00052 class recycler_base;
00053
00054
00055
00056
00057 struct recycler_group
00058 {
00059 recycler_group() {}
00060 explicit recycler_group(void (*mark_all)())
00061 {
00062 mark_hook.insert(mark_all);
00063 }
00064 ~recycler_group();
00065
00066
00067
00068
00069
00070
00071 void register_marker(void (*mark_all)()) { mark_hook.insert(mark_all); }
00072
00073
00074 void collect();
00075
00076 private:
00077 hook<> mark_hook;
00078 std::list<recycler_base*> recyclers;
00079
00080 friend class recycler_base;
00081 };
00082
00083
00084
00085
00086
00087
00088
00089 struct recycler_base
00090 {
00091 typedef unsigned long size_type;
00092
00093
00094
00095 explicit recycler_base(recycler_group& rg)
00096 : group(&rg)
00097 {
00098 group->recyclers.push_back(this);
00099 }
00100
00101
00102 virtual ~recycler_base();
00103
00104 protected:
00105 virtual void clear_marks() = 0;
00106
00107 void collect() { group->collect(); }
00108
00109 private:
00110 recycler_group* group;
00111
00112 friend class recycler_group;
00113 };
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 template<typename T>
00143 struct recycler : recycler_base
00144 {
00145 typedef std::size_t size_type;
00146 typedef std::ptrdiff_t difference_type;
00147 typedef T* pointer;
00148 typedef T const* const_pointer;
00149 typedef T& reference;
00150 typedef T const& const_reference;
00151 typedef T value_type;
00152 template<typename U> struct rebind { typedef recycler<U> other; };
00153
00154
00155
00156
00157
00158 static const size_type value_count = 16;
00159
00160
00161
00162
00163
00164
00165 static const int filling_num = 2;
00166 static const int filling_denom = 3;
00167
00168
00169 private:
00170 struct chunk {
00171 chunk() {}
00172 private:
00173 chunk(chunk const&) {}
00174 public:
00175 value_type array[value_count];
00176 };
00177
00178 public:
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 explicit recycler(recycler_group& x)
00190 : recycler_base(x),
00191 n_allocs_since_gc(0),
00192 n_chunks_since_gc(0) {
00193 r_chunk.push_front();
00194 it_chunk = r_chunk.principal();
00195 v_cur = it_chunk->array;
00196 v_end = v_cur + value_count;
00197 v_gc = v_cur;
00198 }
00199 private:
00200 recycler(recycler const& rcyc) {}
00201 template<typename U> recycler(recycler<U> const&) {}
00202 public:
00203
00204
00205 pointer address(reference r) const { return &r; }
00206
00207 const_pointer address(const_reference r) const { return &r; }
00208
00209
00210
00211
00212
00213 T* allocate(size_type n, const_pointer p = 0) {
00214 #ifndef MORE_NDEBUG
00215 if (n != 1)
00216 throw std::logic_error("more::recycler: This allocator can "
00217 "not handle arrays.");
00218 #endif
00219 while (v_cur != v_end) {
00220 if (!v_cur->is_marked()) {
00221 ++n_allocs_since_gc;
00222 return v_cur++;
00223 }
00224 ++v_cur;
00225 }
00226 return expand_and_allocate();
00227 }
00228
00229
00230 void deallocate(pointer p, size_type n) {}
00231
00232
00233 void construct(T* p) { p->~T(); new((void*)p) T; }
00234
00235
00236 void construct(T* p, T const& x) { p->~T(); new((void*)p) T(x); }
00237
00238
00239 void destroy(T*) {}
00240
00241
00242 size_type max_size() { return 1; }
00243
00244 template<typename Function>
00245 void for_each(Function f) {
00246 chunk_iterator it = it_chunk;
00247 do {
00248 for (value_type* v = it->array;
00249 v != it->array + value_count; ++v)
00250 f(v);
00251 } while (++it != it_chunk);
00252 }
00253
00254 private:
00255 typedef ring<chunk> chunk_container;
00256 typedef typename chunk_container::iterator chunk_iterator;
00257
00258 T* expand_and_allocate() {
00259 while (v_cur != v_gc) {
00260 ++it_chunk;
00261 ++n_chunks_since_gc;
00262 v_cur = it_chunk->array;
00263 v_end = v_cur + value_count;
00264 if (v_cur <= v_gc && v_gc < v_end)
00265 v_end = v_gc;
00266
00267 redo:
00268 while (v_cur != v_end) {
00269 if (!v_cur->is_marked()) {
00270 ++n_allocs_since_gc;
00271 return v_cur++;
00272 }
00273 ++v_cur;
00274 }
00275 }
00276
00277 size_type n_skips
00278 = n_chunks_since_gc*value_count
00279 + (v_cur - it_chunk->array);
00280 #ifdef MORE_ENABLE_LOGGING
00281 if (opt_recycler_do_log)
00282 std::clog << "more::recycler: Availability ratio = "
00283 << n_allocs_since_gc << '/' << n_skips
00284 << ". ";
00285 #endif
00286 if (n_allocs_since_gc*filling_denom
00287 >= n_skips*(filling_denom - filling_num)) {
00288 #ifdef MORE_ENABLE_LOGGING
00289 std::clog << "Collecting.\n";
00290 std::clog.flush();
00291 #endif
00292 collect();
00293 goto redo;
00294 }
00295 else {
00296 #ifdef MORE_ENABLE_LOGGING
00297 std::clog << "Expanding.\n";
00298 std::clog.flush();
00299 #endif
00300 it_chunk = r_chunk.insert(it_chunk);
00301 v_cur = it_chunk->array;
00302 v_end = v_cur + value_count;
00303 ++n_allocs_since_gc;
00304 return v_cur++;
00305 }
00306 }
00307
00308 virtual void clear_marks() {
00309 chunk_iterator it = it_chunk;
00310 do {
00311 for (value_type* v = it->array;
00312 v != it->array + value_count; ++v)
00313 v->unset_mark();
00314 } while (++it != it_chunk);
00315 n_allocs_since_gc = 0;
00316 n_chunks_since_gc = 0;
00317 v_gc = v_cur;
00318 v_end = it_chunk->array + value_count;
00319 }
00320
00321 static void clear_marks_helper(chunk* ch) {
00322 while (ch) {
00323 for (value_type* v = ch->array;
00324 v != ch->array + value_count; ++v)
00325 v->unset_mark();
00326 ch = ch->prev;
00327 }
00328 }
00329
00330 chunk_container r_chunk;
00331 chunk_iterator it_chunk;
00332
00333 value_type* v_cur;
00334 value_type* v_end;
00335 value_type* v_gc;
00336
00337 size_type n_allocs_since_gc;
00338 size_type n_chunks_since_gc;
00339 };
00340 }}
00341
00342 #endif