blob: 406b247b7fec7533678c3a0214f3766bc4a0b60a [file] [log] [blame]
Howard Hinnant7a563db2011-09-14 18:33:51 +00001//===-------------------------- debug.cpp ---------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is dual licensed under the MIT and the University of Illinois Open
6// Source Licenses. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Howard Hinnantabe26282011-09-16 17:29:17 +000010#define _LIBCPP_DEBUG2 1
11#include "__config"
Howard Hinnant7a563db2011-09-14 18:33:51 +000012#include "__debug"
13#include "functional"
14#include "algorithm"
15#include "__hash_table"
16#include "mutex"
17
18_LIBCPP_BEGIN_NAMESPACE_STD
19
20_LIBCPP_VISIBLE
21__libcpp_db*
22__get_db()
23{
24 static __libcpp_db db;
25 return &db;
26};
27
28_LIBCPP_VISIBLE
29const __libcpp_db*
30__get_const_db()
31{
32 return __get_db();
33}
34
35namespace
36{
37
38typedef mutex mutex_type;
Howard Hinnant7a563db2011-09-14 18:33:51 +000039typedef lock_guard<mutex_type> WLock;
40typedef lock_guard<mutex_type> RLock;
41
42mutex_type&
43mut()
44{
45 static mutex_type m;
46 return m;
47}
48
49} // unnamed namespace
50
51__i_node::~__i_node()
52{
53 if (__next_)
54 {
55 __next_->~__i_node();
56 free(__next_);
57 }
58}
59
60__c_node::~__c_node()
61{
62 free(beg_);
63 if (__next_)
64 {
65 __next_->~__c_node();
66 free(__next_);
67 }
68}
69
70__libcpp_db::__libcpp_db()
71 : __cbeg_(nullptr),
72 __cend_(nullptr),
73 __csz_(0),
74 __ibeg_(nullptr),
75 __iend_(nullptr),
76 __isz_(0)
77{
78}
79
80__libcpp_db::~__libcpp_db()
81{
82 if (__cbeg_)
83 {
84 for (__c_node** p = __cbeg_; p != __cend_; ++p)
85 {
86 if (*p != nullptr)
87 {
88 (*p)->~__c_node();
89 free(*p);
90 }
91 }
92 free(__cbeg_);
93 }
94 if (__ibeg_)
95 {
96 for (__i_node** p = __ibeg_; p != __iend_; ++p)
97 {
98 if (*p != nullptr)
99 {
100 (*p)->~__i_node();
101 free(*p);
102 }
103 }
104 free(__ibeg_);
105 }
106}
107
108void*
109__libcpp_db::__find_c_from_i(void* __i) const
110{
111 RLock _(mut());
112 __i_node* i = __find_iterator(__i);
Howard Hinnant7608b4a2011-09-16 19:52:23 +0000113 _LIBCPP_ASSERT(i != nullptr, "iterator constructed in translation unit with debug mode not enabled."
114 " #define _LIBCPP_DEBUG2 1 for that translation unit.");
115 return i->__c_ != nullptr ? i->__c_->__c_ : nullptr;
Howard Hinnant7a563db2011-09-14 18:33:51 +0000116}
117
118void
119__libcpp_db::__insert_ic(void* __i, const void* __c)
120{
121 WLock _(mut());
122 __i_node* i = __insert_iterator(__i);
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000123 const char* errmsg =
124 "Container constructed in a translation unit with debug mode disabled."
125 " But it is being used in a translation unit with debug mode enabled."
126 " Enable it in the other translation unit with #define _LIBCPP_DEBUG2 1";
127 _LIBCPP_ASSERT(__cbeg_ != __cend_, errmsg);
Howard Hinnantec3773c2011-12-01 20:21:04 +0000128 size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000129 __c_node* c = __cbeg_[hc];
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000130 _LIBCPP_ASSERT(c != nullptr, errmsg);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000131 while (c->__c_ != __c)
132 {
133 c = c->__next_;
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000134 _LIBCPP_ASSERT(c != nullptr, errmsg);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000135 }
136 c->__add(i);
137 i->__c_ = c;
138}
139
140__c_node*
141__libcpp_db::__insert_c(void* __c)
142{
143 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000144 if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_))
Howard Hinnant7a563db2011-09-14 18:33:51 +0000145 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000146 size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000147 __c_node** cbeg = (__c_node**)calloc(nc, sizeof(void*));
148 if (cbeg == nullptr)
149 throw bad_alloc();
150 for (__c_node** p = __cbeg_; p != __cend_; ++p)
151 {
152 __c_node* q = *p;
153 while (q != nullptr)
154 {
155 size_t h = hash<void*>()(q->__c_) % nc;
156 __c_node* r = q->__next_;
157 q->__next_ = cbeg[h];
158 cbeg[h] = q;
159 q = r;
160 }
161 }
162 free(__cbeg_);
163 __cbeg_ = cbeg;
164 __cend_ = __cbeg_ + nc;
165 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000166 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000167 __c_node* p = __cbeg_[hc];
168 __c_node* r = __cbeg_[hc] = (__c_node*)malloc(sizeof(__c_node));
169 if (__cbeg_[hc] == nullptr)
170 throw bad_alloc();
171 r->__c_ = __c;
172 r->__next_ = p;
173 ++__csz_;
174 return r;
175}
176
177void
178__libcpp_db::__erase_i(void* __i)
179{
180 WLock _(mut());
181 if (__ibeg_ != __iend_)
182 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000183 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000184 __i_node* p = __ibeg_[hi];
185 if (p != nullptr)
186 {
187 __i_node* q = nullptr;
188 while (p->__i_ != __i)
189 {
190 q = p;
191 p = p->__next_;
192 if (p == nullptr)
193 return;
194 }
195 if (q == nullptr)
196 __ibeg_[hi] = p->__next_;
197 else
198 q->__next_ = p->__next_;
199 __c_node* c = p->__c_;
200 free(p);
201 --__isz_;
202 if (c != nullptr)
203 c->__remove(p);
204 }
205 }
206}
207
208void
209__libcpp_db::__invalidate_all(void* __c)
210{
211 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000212 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000213 __c_node* p = __cbeg_[hc];
214 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all A");
215 while (p->__c_ != __c)
216 {
217 p = p->__next_;
218 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all B");
219 }
220 while (p->end_ != p->beg_)
221 {
222 --p->end_;
223 (*p->end_)->__c_ = nullptr;
224 }
225}
226
227__c_node*
228__libcpp_db::__find_c_and_lock(void* __c) const
229{
230 mut().lock();
Howard Hinnantec3773c2011-12-01 20:21:04 +0000231 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000232 __c_node* p = __cbeg_[hc];
233 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock A");
234 while (p->__c_ != __c)
235 {
236 p = p->__next_;
237 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock B");
238 }
239 return p;
240}
241
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000242__c_node*
243__libcpp_db::__find_c(void* __c) const
244{
Howard Hinnantec3773c2011-12-01 20:21:04 +0000245 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000246 __c_node* p = __cbeg_[hc];
247 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
248 while (p->__c_ != __c)
249 {
250 p = p->__next_;
251 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
252 }
253 return p;
254}
255
Howard Hinnant7a563db2011-09-14 18:33:51 +0000256void
257__libcpp_db::unlock() const
258{
259 mut().unlock();
260}
261
262void
263__libcpp_db::__erase_c(void* __c)
264{
265 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000266 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000267 __c_node* p = __cbeg_[hc];
268 __c_node* q = nullptr;
269 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
270 while (p->__c_ != __c)
271 {
272 q = p;
273 p = p->__next_;
274 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
275 }
276 if (q == nullptr)
277 __cbeg_[hc] = p->__next_;
278 else
279 q->__next_ = p->__next_;
280 while (p->end_ != p->beg_)
281 {
282 --p->end_;
283 (*p->end_)->__c_ = nullptr;
284 }
285 free(p->beg_);
286 free(p);
287 --__csz_;
288}
289
290void
291__libcpp_db::__iterator_copy(void* __i, const void* __i0)
292{
293 WLock _(mut());
294 __i_node* i = __find_iterator(__i);
295 __i_node* i0 = __find_iterator(__i0);
296 __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
297 if (i == nullptr && c0 != nullptr)
298 i = __insert_iterator(__i);
299 __c_node* c = i != nullptr ? i->__c_ : nullptr;
300 if (c != c0)
301 {
302 if (c != nullptr)
303 c->__remove(i);
304 if (i != nullptr)
305 {
306 i->__c_ = nullptr;
307 if (c0 != nullptr)
308 {
309 i->__c_ = c0;
310 i->__c_->__add(i);
311 }
312 }
313 }
314}
315
316bool
317__libcpp_db::__dereferenceable(const void* __i) const
318{
319 RLock _(mut());
320 __i_node* i = __find_iterator(__i);
321 return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
322}
323
324bool
325__libcpp_db::__decrementable(const void* __i) const
326{
327 RLock _(mut());
328 __i_node* i = __find_iterator(__i);
329 return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
330}
331
332bool
333__libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
334{
335 RLock _(mut());
336 __i_node* i = __find_iterator(__i);
337 return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
338}
339
340bool
341__libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
342{
343 RLock _(mut());
344 __i_node* i = __find_iterator(__i);
345 return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
346}
347
348bool
349__libcpp_db::__comparable(const void* __i, const void* __j) const
350{
351 RLock _(mut());
352 __i_node* i = __find_iterator(__i);
353 __i_node* j = __find_iterator(__j);
354 __c_node* ci = i != nullptr ? i->__c_ : nullptr;
355 __c_node* cj = j != nullptr ? j->__c_ : nullptr;
356 return ci != nullptr && ci == cj;
357}
358
359void
360__libcpp_db::swap(void* c1, void* c2)
361{
362 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000363 size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000364 __c_node* p1 = __cbeg_[hc];
365 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
366 while (p1->__c_ != c1)
367 {
368 p1 = p1->__next_;
369 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
370 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000371 hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000372 __c_node* p2 = __cbeg_[hc];
373 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
374 while (p2->__c_ != c2)
375 {
376 p2 = p2->__next_;
377 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
378 }
379 std::swap(p1->beg_, p2->beg_);
380 std::swap(p1->end_, p2->end_);
381 std::swap(p1->cap_, p2->cap_);
382 for (__i_node** p = p1->beg_; p != p1->end_; ++p)
383 (*p)->__c_ = p1;
384 for (__i_node** p = p2->beg_; p != p2->end_; ++p)
385 (*p)->__c_ = p2;
386}
387
Howard Hinnant7608b4a2011-09-16 19:52:23 +0000388void
389__libcpp_db::__insert_i(void* __i)
390{
391 WLock _(mut());
392 __insert_iterator(__i);
393}
394
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000395void
396__c_node::__add(__i_node* i)
397{
398 if (end_ == cap_)
399 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000400 size_t nc = 2*static_cast<size_t>(cap_ - beg_);
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000401 if (nc == 0)
402 nc = 1;
403 __i_node** beg = (__i_node**)malloc(nc * sizeof(__i_node*));
404 if (beg == nullptr)
405 throw bad_alloc();
406 if (nc > 1)
407 memcpy(beg, beg_, nc/2*sizeof(__i_node*));
408 free(beg_);
409 beg_ = beg;
410 end_ = beg_ + nc/2;
411 cap_ = beg_ + nc;
412 }
413 *end_++ = i;
414}
415
Howard Hinnant7a563db2011-09-14 18:33:51 +0000416// private api
417
418_LIBCPP_HIDDEN
419__i_node*
420__libcpp_db::__insert_iterator(void* __i)
421{
Howard Hinnantec3773c2011-12-01 20:21:04 +0000422 if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
Howard Hinnant7a563db2011-09-14 18:33:51 +0000423 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000424 size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000425 __i_node** ibeg = (__i_node**)calloc(nc, sizeof(void*));
426 if (ibeg == nullptr)
427 throw bad_alloc();
428 for (__i_node** p = __ibeg_; p != __iend_; ++p)
429 {
430 __i_node* q = *p;
431 while (q != nullptr)
432 {
433 size_t h = hash<void*>()(q->__i_) % nc;
434 __i_node* r = q->__next_;
435 q->__next_ = ibeg[h];
436 ibeg[h] = q;
437 q = r;
438 }
439 }
440 free(__ibeg_);
441 __ibeg_ = ibeg;
442 __iend_ = __ibeg_ + nc;
443 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000444 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000445 __i_node* p = __ibeg_[hi];
446 __i_node* r = __ibeg_[hi] = (__i_node*)malloc(sizeof(__i_node));
447 if (r == nullptr)
448 throw bad_alloc();
449 ::new(r) __i_node(__i, p, nullptr);
450 ++__isz_;
451 return r;
452}
453
454_LIBCPP_HIDDEN
455__i_node*
456__libcpp_db::__find_iterator(const void* __i) const
457{
458 __i_node* r = nullptr;
459 if (__ibeg_ != __iend_)
460 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000461 size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000462 for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
463 {
464 if (nd->__i_ == __i)
465 {
466 r = nd;
467 break;
468 }
469 }
470 }
471 return r;
472}
473
474_LIBCPP_HIDDEN
475void
Howard Hinnant7a563db2011-09-14 18:33:51 +0000476__c_node::__remove(__i_node* p)
477{
478 __i_node** r = find(beg_, end_, p);
479 _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
480 if (--end_ != r)
Howard Hinnantec3773c2011-12-01 20:21:04 +0000481 memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
Howard Hinnant7a563db2011-09-14 18:33:51 +0000482}
483
484_LIBCPP_END_NAMESPACE_STD