debug.cpp revision 227825
1//===-------------------------- 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
10#define _LIBCPP_DEBUG2 1
11#include "__config"
12#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;
39typedef 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);
113    _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;
116}
117
118void
119__libcpp_db::__insert_ic(void* __i, const void* __c)
120{
121    WLock _(mut());
122    __i_node* i = __insert_iterator(__i);
123    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);
128    size_t hc = hash<const void*>()(__c) % (__cend_ - __cbeg_);
129    __c_node* c = __cbeg_[hc];
130    _LIBCPP_ASSERT(c != nullptr, errmsg);
131    while (c->__c_ != __c)
132    {
133        c = c->__next_;
134        _LIBCPP_ASSERT(c != nullptr, errmsg);
135    }
136    c->__add(i);
137    i->__c_ = c;
138}
139
140__c_node*
141__libcpp_db::__insert_c(void* __c)
142{
143    WLock _(mut());
144    if (__csz_ + 1 > __cend_ - __cbeg_)
145    {
146        size_t nc = __next_prime(2*(__cend_ - __cbeg_) + 1);
147        __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    }
166    size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
167    __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    {
183        size_t hi = hash<void*>()(__i) % (__iend_ - __ibeg_);
184        __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());
212    size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
213    __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();
231    size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
232    __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
242__c_node*
243__libcpp_db::__find_c(void* __c) const
244{
245    size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
246    __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
256void
257__libcpp_db::unlock() const
258{
259    mut().unlock();
260}
261
262void
263__libcpp_db::__erase_c(void* __c)
264{
265    WLock _(mut());
266    size_t hc = hash<void*>()(__c) % (__cend_ - __cbeg_);
267    __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());
363    size_t hc = hash<void*>()(c1) % (__cend_ - __cbeg_);
364    __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    }
371    hc = hash<void*>()(c2) % (__cend_ - __cbeg_);
372    __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
388void
389__libcpp_db::__insert_i(void* __i)
390{
391    WLock _(mut());
392    __insert_iterator(__i);
393}
394
395void
396__c_node::__add(__i_node* i)
397{
398    if (end_ == cap_)
399    {
400        size_t nc = 2*(cap_ - beg_);
401        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
416// private api
417
418_LIBCPP_HIDDEN
419__i_node*
420__libcpp_db::__insert_iterator(void* __i)
421{
422    if (__isz_ + 1 > __iend_ - __ibeg_)
423    {
424        size_t nc = __next_prime(2*(__iend_ - __ibeg_) + 1);
425        __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    }
444    size_t hi = hash<void*>()(__i) % (__iend_ - __ibeg_);
445    __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    {
461        size_t h = hash<const void*>()(__i) % (__iend_ - __ibeg_);
462        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
476__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)
481        memmove(r, r+1, (end_ - r)*sizeof(__i_node*));
482}
483
484_LIBCPP_END_NAMESPACE_STD
485