blob: 2d4b094baac018f07dfaa539ba437e13599f141d [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
Howard Hinnant83eade62013-03-06 23:30:19 +000020_LIBCPP_FUNC_VIS
Howard Hinnant7a563db2011-09-14 18:33:51 +000021__libcpp_db*
22__get_db()
23{
24 static __libcpp_db db;
25 return &db;
Howard Hinnantc6e54b92012-12-27 18:46:00 +000026}
Howard Hinnant7a563db2011-09-14 18:33:51 +000027
Howard Hinnant83eade62013-03-06 23:30:19 +000028_LIBCPP_FUNC_VIS
Howard Hinnant7a563db2011-09-14 18:33:51 +000029const __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)
Howard Hinnant3882d392012-08-24 22:15:12 +0000149#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnant7a563db2011-09-14 18:33:51 +0000150 throw bad_alloc();
Howard Hinnant3882d392012-08-24 22:15:12 +0000151#else
152 abort();
153#endif
Howard Hinnant7a563db2011-09-14 18:33:51 +0000154 for (__c_node** p = __cbeg_; p != __cend_; ++p)
155 {
156 __c_node* q = *p;
157 while (q != nullptr)
158 {
159 size_t h = hash<void*>()(q->__c_) % nc;
160 __c_node* r = q->__next_;
161 q->__next_ = cbeg[h];
162 cbeg[h] = q;
163 q = r;
164 }
165 }
166 free(__cbeg_);
167 __cbeg_ = cbeg;
168 __cend_ = __cbeg_ + nc;
169 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000170 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000171 __c_node* p = __cbeg_[hc];
172 __c_node* r = __cbeg_[hc] = (__c_node*)malloc(sizeof(__c_node));
173 if (__cbeg_[hc] == nullptr)
Howard Hinnant3882d392012-08-24 22:15:12 +0000174#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnant7a563db2011-09-14 18:33:51 +0000175 throw bad_alloc();
Howard Hinnant3882d392012-08-24 22:15:12 +0000176#else
177 abort();
178#endif
Howard Hinnant7a563db2011-09-14 18:33:51 +0000179 r->__c_ = __c;
180 r->__next_ = p;
181 ++__csz_;
182 return r;
183}
184
185void
186__libcpp_db::__erase_i(void* __i)
187{
188 WLock _(mut());
189 if (__ibeg_ != __iend_)
190 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000191 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000192 __i_node* p = __ibeg_[hi];
193 if (p != nullptr)
194 {
195 __i_node* q = nullptr;
196 while (p->__i_ != __i)
197 {
198 q = p;
199 p = p->__next_;
200 if (p == nullptr)
201 return;
202 }
203 if (q == nullptr)
204 __ibeg_[hi] = p->__next_;
205 else
206 q->__next_ = p->__next_;
207 __c_node* c = p->__c_;
208 free(p);
209 --__isz_;
210 if (c != nullptr)
211 c->__remove(p);
212 }
213 }
214}
215
216void
217__libcpp_db::__invalidate_all(void* __c)
218{
219 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000220 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000221 __c_node* p = __cbeg_[hc];
222 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all A");
223 while (p->__c_ != __c)
224 {
225 p = p->__next_;
226 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all B");
227 }
228 while (p->end_ != p->beg_)
229 {
230 --p->end_;
231 (*p->end_)->__c_ = nullptr;
232 }
233}
234
235__c_node*
236__libcpp_db::__find_c_and_lock(void* __c) const
237{
238 mut().lock();
Howard Hinnantec3773c2011-12-01 20:21:04 +0000239 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000240 __c_node* p = __cbeg_[hc];
241 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock A");
242 while (p->__c_ != __c)
243 {
244 p = p->__next_;
245 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock B");
246 }
247 return p;
248}
249
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000250__c_node*
251__libcpp_db::__find_c(void* __c) const
252{
Howard Hinnantec3773c2011-12-01 20:21:04 +0000253 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000254 __c_node* p = __cbeg_[hc];
255 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A");
256 while (p->__c_ != __c)
257 {
258 p = p->__next_;
259 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B");
260 }
261 return p;
262}
263
Howard Hinnant7a563db2011-09-14 18:33:51 +0000264void
265__libcpp_db::unlock() const
266{
267 mut().unlock();
268}
269
270void
271__libcpp_db::__erase_c(void* __c)
272{
273 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000274 size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000275 __c_node* p = __cbeg_[hc];
276 __c_node* q = nullptr;
277 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
278 while (p->__c_ != __c)
279 {
280 q = p;
281 p = p->__next_;
282 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
283 }
284 if (q == nullptr)
285 __cbeg_[hc] = p->__next_;
286 else
287 q->__next_ = p->__next_;
288 while (p->end_ != p->beg_)
289 {
290 --p->end_;
291 (*p->end_)->__c_ = nullptr;
292 }
293 free(p->beg_);
294 free(p);
295 --__csz_;
296}
297
298void
299__libcpp_db::__iterator_copy(void* __i, const void* __i0)
300{
301 WLock _(mut());
302 __i_node* i = __find_iterator(__i);
303 __i_node* i0 = __find_iterator(__i0);
304 __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
305 if (i == nullptr && c0 != nullptr)
306 i = __insert_iterator(__i);
307 __c_node* c = i != nullptr ? i->__c_ : nullptr;
308 if (c != c0)
309 {
310 if (c != nullptr)
311 c->__remove(i);
312 if (i != nullptr)
313 {
314 i->__c_ = nullptr;
315 if (c0 != nullptr)
316 {
317 i->__c_ = c0;
318 i->__c_->__add(i);
319 }
320 }
321 }
322}
323
324bool
325__libcpp_db::__dereferenceable(const void* __i) const
326{
327 RLock _(mut());
328 __i_node* i = __find_iterator(__i);
329 return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
330}
331
332bool
333__libcpp_db::__decrementable(const void* __i) const
334{
335 RLock _(mut());
336 __i_node* i = __find_iterator(__i);
337 return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
338}
339
340bool
341__libcpp_db::__addable(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_->__addable(__i, __n);
346}
347
348bool
349__libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
350{
351 RLock _(mut());
352 __i_node* i = __find_iterator(__i);
353 return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
354}
355
356bool
357__libcpp_db::__comparable(const void* __i, const void* __j) const
358{
359 RLock _(mut());
360 __i_node* i = __find_iterator(__i);
361 __i_node* j = __find_iterator(__j);
362 __c_node* ci = i != nullptr ? i->__c_ : nullptr;
363 __c_node* cj = j != nullptr ? j->__c_ : nullptr;
364 return ci != nullptr && ci == cj;
365}
366
367void
368__libcpp_db::swap(void* c1, void* c2)
369{
370 WLock _(mut());
Howard Hinnantec3773c2011-12-01 20:21:04 +0000371 size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000372 __c_node* p1 = __cbeg_[hc];
373 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
374 while (p1->__c_ != c1)
375 {
376 p1 = p1->__next_;
377 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
378 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000379 hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000380 __c_node* p2 = __cbeg_[hc];
381 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
382 while (p2->__c_ != c2)
383 {
384 p2 = p2->__next_;
385 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
386 }
387 std::swap(p1->beg_, p2->beg_);
388 std::swap(p1->end_, p2->end_);
389 std::swap(p1->cap_, p2->cap_);
390 for (__i_node** p = p1->beg_; p != p1->end_; ++p)
391 (*p)->__c_ = p1;
392 for (__i_node** p = p2->beg_; p != p2->end_; ++p)
393 (*p)->__c_ = p2;
394}
395
Howard Hinnant7608b4a2011-09-16 19:52:23 +0000396void
397__libcpp_db::__insert_i(void* __i)
398{
399 WLock _(mut());
400 __insert_iterator(__i);
401}
402
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000403void
404__c_node::__add(__i_node* i)
405{
406 if (end_ == cap_)
407 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000408 size_t nc = 2*static_cast<size_t>(cap_ - beg_);
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000409 if (nc == 0)
410 nc = 1;
411 __i_node** beg = (__i_node**)malloc(nc * sizeof(__i_node*));
412 if (beg == nullptr)
Howard Hinnant3882d392012-08-24 22:15:12 +0000413#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000414 throw bad_alloc();
Howard Hinnant3882d392012-08-24 22:15:12 +0000415#else
416 abort();
417#endif
Howard Hinnant1c3ec6d2011-09-27 23:55:03 +0000418 if (nc > 1)
419 memcpy(beg, beg_, nc/2*sizeof(__i_node*));
420 free(beg_);
421 beg_ = beg;
422 end_ = beg_ + nc/2;
423 cap_ = beg_ + nc;
424 }
425 *end_++ = i;
426}
427
Howard Hinnant7a563db2011-09-14 18:33:51 +0000428// private api
429
430_LIBCPP_HIDDEN
431__i_node*
432__libcpp_db::__insert_iterator(void* __i)
433{
Howard Hinnantec3773c2011-12-01 20:21:04 +0000434 if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_))
Howard Hinnant7a563db2011-09-14 18:33:51 +0000435 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000436 size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000437 __i_node** ibeg = (__i_node**)calloc(nc, sizeof(void*));
438 if (ibeg == nullptr)
Howard Hinnant3882d392012-08-24 22:15:12 +0000439#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnant7a563db2011-09-14 18:33:51 +0000440 throw bad_alloc();
Howard Hinnant3882d392012-08-24 22:15:12 +0000441#else
442 abort();
443#endif
Howard Hinnant7a563db2011-09-14 18:33:51 +0000444 for (__i_node** p = __ibeg_; p != __iend_; ++p)
445 {
446 __i_node* q = *p;
447 while (q != nullptr)
448 {
449 size_t h = hash<void*>()(q->__i_) % nc;
450 __i_node* r = q->__next_;
451 q->__next_ = ibeg[h];
452 ibeg[h] = q;
453 q = r;
454 }
455 }
456 free(__ibeg_);
457 __ibeg_ = ibeg;
458 __iend_ = __ibeg_ + nc;
459 }
Howard Hinnantec3773c2011-12-01 20:21:04 +0000460 size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000461 __i_node* p = __ibeg_[hi];
462 __i_node* r = __ibeg_[hi] = (__i_node*)malloc(sizeof(__i_node));
463 if (r == nullptr)
Howard Hinnant3882d392012-08-24 22:15:12 +0000464#ifndef _LIBCPP_NO_EXCEPTIONS
Howard Hinnant7a563db2011-09-14 18:33:51 +0000465 throw bad_alloc();
Howard Hinnant3882d392012-08-24 22:15:12 +0000466#else
467 abort();
468#endif
Howard Hinnant7a563db2011-09-14 18:33:51 +0000469 ::new(r) __i_node(__i, p, nullptr);
470 ++__isz_;
471 return r;
472}
473
474_LIBCPP_HIDDEN
475__i_node*
476__libcpp_db::__find_iterator(const void* __i) const
477{
478 __i_node* r = nullptr;
479 if (__ibeg_ != __iend_)
480 {
Howard Hinnantec3773c2011-12-01 20:21:04 +0000481 size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_);
Howard Hinnant7a563db2011-09-14 18:33:51 +0000482 for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
483 {
484 if (nd->__i_ == __i)
485 {
486 r = nd;
487 break;
488 }
489 }
490 }
491 return r;
492}
493
494_LIBCPP_HIDDEN
495void
Howard Hinnant7a563db2011-09-14 18:33:51 +0000496__c_node::__remove(__i_node* p)
497{
498 __i_node** r = find(beg_, end_, p);
499 _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
500 if (--end_ != r)
Howard Hinnantec3773c2011-12-01 20:21:04 +0000501 memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*));
Howard Hinnant7a563db2011-09-14 18:33:51 +0000502}
503
504_LIBCPP_END_NAMESPACE_STD