blob: 2d2d6432df134d60f39ada60367f2aefec2b2db5 [file] [log] [blame]
Howard Hinnant27e0e772011-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 Hinnanta47c6d52011-09-16 17:29:17 +000010#define _LIBCPP_DEBUG2 1
11#include "__config"
Howard Hinnant27e0e772011-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 Hinnant27e0e772011-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 Hinnantc90aa632011-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 Hinnant27e0e772011-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 Hinnantc90aa632011-09-16 19:52:23 +0000123 _LIBCPP_ASSERT(__cbeg_ != __cend_, "Container constructed in a translation unit with debug mode disabled."
124 " But it is being used in a translation unit with debug mode enabled."
125 " Enable it in the other translation unit with #define _LIBCPP_DEBUG2 1");
Howard Hinnant27e0e772011-09-14 18:33:51 +0000126 size_t hc = hash<const void*>()(__c) % (__cend_ - __cbeg_);
127 __c_node* c = __cbeg_[hc];
Howard Hinnantc90aa632011-09-16 19:52:23 +0000128 _LIBCPP_ASSERT(c != nullptr, "Container constructed in a translation unit with debug mode disabled."
129 " But it is being used in a translation unit with debug mode enabled."
130 " Enable it in the other translation unit with #define _LIBCPP_DEBUG2 1");
Howard Hinnant27e0e772011-09-14 18:33:51 +0000131 while (c->__c_ != __c)
132 {
133 c = c->__next_;
Howard Hinnantc90aa632011-09-16 19:52:23 +0000134 _LIBCPP_ASSERT(c != nullptr, "Container constructed in a translation unit with debug mode disabled."
135 " But it is being used in a translation unit with debug mode enabled."
136 " Enable it in the other translation unit with #define _LIBCPP_DEBUG2 1");
Howard Hinnant27e0e772011-09-14 18:33:51 +0000137 }
138 c->__add(i);
139 i->__c_ = c;
140}
141
142__c_node*
143__libcpp_db::__insert_c(void* __c)
144{
145 WLock _(mut());
146 if (__csz_ + 1 > __cend_ - __cbeg_)
147 {
148 size_t nc = __next_prime(2*(__cend_ - __cbeg_) + 1);
149 __c_node** cbeg = (__c_node**)calloc(nc, sizeof(void*));
150 if (cbeg == nullptr)
151 throw bad_alloc();
152 for (__c_node** p = __cbeg_; p != __cend_; ++p)
153 {
154 __c_node* q = *p;
155 while (q != nullptr)
156 {
157 size_t h = hash<void*>()(q->__c_) % nc;
158 __c_node* r = q->__next_;
159 q->__next_ = cbeg[h];
160 cbeg[h] = q;
161 q = r;
162 }
163 }
164 free(__cbeg_);
165 __cbeg_ = cbeg;
166 __cend_ = __cbeg_ + nc;
167 }
168 size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
169 __c_node* p = __cbeg_[hc];
170 __c_node* r = __cbeg_[hc] = (__c_node*)malloc(sizeof(__c_node));
171 if (__cbeg_[hc] == nullptr)
172 throw bad_alloc();
173 r->__c_ = __c;
174 r->__next_ = p;
175 ++__csz_;
176 return r;
177}
178
179void
180__libcpp_db::__erase_i(void* __i)
181{
182 WLock _(mut());
183 if (__ibeg_ != __iend_)
184 {
185 size_t hi = hash<void*>()(__i) % (__iend_ - __ibeg_);
186 __i_node* p = __ibeg_[hi];
187 if (p != nullptr)
188 {
189 __i_node* q = nullptr;
190 while (p->__i_ != __i)
191 {
192 q = p;
193 p = p->__next_;
194 if (p == nullptr)
195 return;
196 }
197 if (q == nullptr)
198 __ibeg_[hi] = p->__next_;
199 else
200 q->__next_ = p->__next_;
201 __c_node* c = p->__c_;
202 free(p);
203 --__isz_;
204 if (c != nullptr)
205 c->__remove(p);
206 }
207 }
208}
209
210void
211__libcpp_db::__invalidate_all(void* __c)
212{
213 WLock _(mut());
214 size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
215 __c_node* p = __cbeg_[hc];
216 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all A");
217 while (p->__c_ != __c)
218 {
219 p = p->__next_;
220 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __invalidate_all B");
221 }
222 while (p->end_ != p->beg_)
223 {
224 --p->end_;
225 (*p->end_)->__c_ = nullptr;
226 }
227}
228
229__c_node*
230__libcpp_db::__find_c_and_lock(void* __c) const
231{
232 mut().lock();
233 size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
234 __c_node* p = __cbeg_[hc];
235 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock A");
236 while (p->__c_ != __c)
237 {
238 p = p->__next_;
239 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c_and_lock B");
240 }
241 return p;
242}
243
244void
245__libcpp_db::unlock() const
246{
247 mut().unlock();
248}
249
250void
251__libcpp_db::__erase_c(void* __c)
252{
253 WLock _(mut());
254 size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
255 __c_node* p = __cbeg_[hc];
256 __c_node* q = nullptr;
257 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A");
258 while (p->__c_ != __c)
259 {
260 q = p;
261 p = p->__next_;
262 _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B");
263 }
264 if (q == nullptr)
265 __cbeg_[hc] = p->__next_;
266 else
267 q->__next_ = p->__next_;
268 while (p->end_ != p->beg_)
269 {
270 --p->end_;
271 (*p->end_)->__c_ = nullptr;
272 }
273 free(p->beg_);
274 free(p);
275 --__csz_;
276}
277
278void
279__libcpp_db::__iterator_copy(void* __i, const void* __i0)
280{
281 WLock _(mut());
282 __i_node* i = __find_iterator(__i);
283 __i_node* i0 = __find_iterator(__i0);
284 __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr;
285 if (i == nullptr && c0 != nullptr)
286 i = __insert_iterator(__i);
287 __c_node* c = i != nullptr ? i->__c_ : nullptr;
288 if (c != c0)
289 {
290 if (c != nullptr)
291 c->__remove(i);
292 if (i != nullptr)
293 {
294 i->__c_ = nullptr;
295 if (c0 != nullptr)
296 {
297 i->__c_ = c0;
298 i->__c_->__add(i);
299 }
300 }
301 }
302}
303
304bool
305__libcpp_db::__dereferenceable(const void* __i) const
306{
307 RLock _(mut());
308 __i_node* i = __find_iterator(__i);
309 return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i);
310}
311
312bool
313__libcpp_db::__decrementable(const void* __i) const
314{
315 RLock _(mut());
316 __i_node* i = __find_iterator(__i);
317 return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i);
318}
319
320bool
321__libcpp_db::__addable(const void* __i, ptrdiff_t __n) const
322{
323 RLock _(mut());
324 __i_node* i = __find_iterator(__i);
325 return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n);
326}
327
328bool
329__libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const
330{
331 RLock _(mut());
332 __i_node* i = __find_iterator(__i);
333 return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n);
334}
335
336bool
337__libcpp_db::__comparable(const void* __i, const void* __j) const
338{
339 RLock _(mut());
340 __i_node* i = __find_iterator(__i);
341 __i_node* j = __find_iterator(__j);
342 __c_node* ci = i != nullptr ? i->__c_ : nullptr;
343 __c_node* cj = j != nullptr ? j->__c_ : nullptr;
344 return ci != nullptr && ci == cj;
345}
346
347void
348__libcpp_db::swap(void* c1, void* c2)
349{
350 WLock _(mut());
351 size_t hc = hash<void*>()(c1) % (__cend_ - __cbeg_);
352 __c_node* p1 = __cbeg_[hc];
353 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A");
354 while (p1->__c_ != c1)
355 {
356 p1 = p1->__next_;
357 _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B");
358 }
359 hc = hash<void*>()(c2) % (__cend_ - __cbeg_);
360 __c_node* p2 = __cbeg_[hc];
361 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C");
362 while (p2->__c_ != c2)
363 {
364 p2 = p2->__next_;
365 _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D");
366 }
367 std::swap(p1->beg_, p2->beg_);
368 std::swap(p1->end_, p2->end_);
369 std::swap(p1->cap_, p2->cap_);
370 for (__i_node** p = p1->beg_; p != p1->end_; ++p)
371 (*p)->__c_ = p1;
372 for (__i_node** p = p2->beg_; p != p2->end_; ++p)
373 (*p)->__c_ = p2;
374}
375
Howard Hinnantc90aa632011-09-16 19:52:23 +0000376void
377__libcpp_db::__insert_i(void* __i)
378{
379 WLock _(mut());
380 __insert_iterator(__i);
381}
382
Howard Hinnant27e0e772011-09-14 18:33:51 +0000383// private api
384
385_LIBCPP_HIDDEN
386__i_node*
387__libcpp_db::__insert_iterator(void* __i)
388{
389 if (__isz_ + 1 > __iend_ - __ibeg_)
390 {
391 size_t nc = __next_prime(2*(__iend_ - __ibeg_) + 1);
392 __i_node** ibeg = (__i_node**)calloc(nc, sizeof(void*));
393 if (ibeg == nullptr)
394 throw bad_alloc();
395 for (__i_node** p = __ibeg_; p != __iend_; ++p)
396 {
397 __i_node* q = *p;
398 while (q != nullptr)
399 {
400 size_t h = hash<void*>()(q->__i_) % nc;
401 __i_node* r = q->__next_;
402 q->__next_ = ibeg[h];
403 ibeg[h] = q;
404 q = r;
405 }
406 }
407 free(__ibeg_);
408 __ibeg_ = ibeg;
409 __iend_ = __ibeg_ + nc;
410 }
411 size_t hi = hash<void*>()(__i) % (__iend_ - __ibeg_);
412 __i_node* p = __ibeg_[hi];
413 __i_node* r = __ibeg_[hi] = (__i_node*)malloc(sizeof(__i_node));
414 if (r == nullptr)
415 throw bad_alloc();
416 ::new(r) __i_node(__i, p, nullptr);
417 ++__isz_;
418 return r;
419}
420
421_LIBCPP_HIDDEN
422__i_node*
423__libcpp_db::__find_iterator(const void* __i) const
424{
425 __i_node* r = nullptr;
426 if (__ibeg_ != __iend_)
427 {
428 size_t h = hash<const void*>()(__i) % (__iend_ - __ibeg_);
429 for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_)
430 {
431 if (nd->__i_ == __i)
432 {
433 r = nd;
434 break;
435 }
436 }
437 }
438 return r;
439}
440
441_LIBCPP_HIDDEN
442void
443__c_node::__add(__i_node* i)
444{
445 if (end_ == cap_)
446 {
447 size_t nc = 2*(cap_ - beg_);
448 if (nc == 0)
449 nc = 1;
450 __i_node** beg = (__i_node**)malloc(nc * sizeof(__i_node*));
451 if (beg == nullptr)
452 throw bad_alloc();
453 if (nc > 1)
454 memcpy(beg, beg_, nc/2*sizeof(__i_node*));
455 free(beg_);
456 beg_ = beg;
457 end_ = beg_ + nc/2;
458 cap_ = beg_ + nc;
459 }
460 *end_++ = i;
461}
462
463_LIBCPP_HIDDEN
464void
465__c_node::__remove(__i_node* p)
466{
467 __i_node** r = find(beg_, end_, p);
468 _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove");
469 if (--end_ != r)
470 memmove(r, r+1, (end_ - r)*sizeof(__i_node*));
471}
472
473_LIBCPP_END_NAMESPACE_STD