//===-------------------------- debug.cpp ---------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "__config" #include "__debug" #include "functional" #include "algorithm" #include "string" #include "cstdio" #include "__hash_table" #include "mutex" _LIBCPP_BEGIN_NAMESPACE_STD static std::string make_what_str(__libcpp_debug_info const& info) { string msg = info.__file_; msg += ":" + to_string(info.__line_) + ": _LIBCPP_ASSERT '"; msg += info.__pred_; msg += "' failed. "; msg += info.__msg_; return msg; } _LIBCPP_SAFE_STATIC __libcpp_debug_function_type __libcpp_debug_function = __libcpp_abort_debug_function; bool __libcpp_set_debug_function(__libcpp_debug_function_type __func) { __libcpp_debug_function = __func; return true; } _LIBCPP_NORETURN void __libcpp_abort_debug_function(__libcpp_debug_info const& info) { std::fprintf(stderr, "%s\n", make_what_str(info).c_str()); std::abort(); } _LIBCPP_NORETURN void __libcpp_throw_debug_function(__libcpp_debug_info const& info) { #ifndef _LIBCPP_NO_EXCEPTIONS throw __libcpp_debug_exception(info); #else __libcpp_abort_debug_function(info); #endif } struct __libcpp_debug_exception::__libcpp_debug_exception_imp { __libcpp_debug_info __info_; std::string __what_str_; }; __libcpp_debug_exception::__libcpp_debug_exception() _NOEXCEPT : __imp_(nullptr) { } __libcpp_debug_exception::__libcpp_debug_exception( __libcpp_debug_info const& info) : __imp_(new __libcpp_debug_exception_imp) { __imp_->__info_ = info; __imp_->__what_str_ = make_what_str(info); } __libcpp_debug_exception::__libcpp_debug_exception( __libcpp_debug_exception const& other) : __imp_(nullptr) { if (other.__imp_) __imp_ = new __libcpp_debug_exception_imp(*other.__imp_); } __libcpp_debug_exception::~__libcpp_debug_exception() _NOEXCEPT { if (__imp_) delete __imp_; } const char* __libcpp_debug_exception::what() const _NOEXCEPT { if (__imp_) return __imp_->__what_str_.c_str(); return "__libcpp_debug_exception"; } _LIBCPP_FUNC_VIS __libcpp_db* __get_db() { static __libcpp_db db; return &db; } _LIBCPP_FUNC_VIS const __libcpp_db* __get_const_db() { return __get_db(); } namespace { #ifndef _LIBCPP_HAS_NO_THREADS typedef mutex mutex_type; typedef lock_guard<mutex_type> WLock; typedef lock_guard<mutex_type> RLock; mutex_type& mut() { static mutex_type m; return m; } #endif // !_LIBCPP_HAS_NO_THREADS } // unnamed namespace __i_node::~__i_node() { if (__next_) { __next_->~__i_node(); free(__next_); } } __c_node::~__c_node() { free(beg_); if (__next_) { __next_->~__c_node(); free(__next_); } } __libcpp_db::__libcpp_db() : __cbeg_(nullptr), __cend_(nullptr), __csz_(0), __ibeg_(nullptr), __iend_(nullptr), __isz_(0) { } __libcpp_db::~__libcpp_db() { if (__cbeg_) { for (__c_node** p = __cbeg_; p != __cend_; ++p) { if (*p != nullptr) { (*p)->~__c_node(); free(*p); } } free(__cbeg_); } if (__ibeg_) { for (__i_node** p = __ibeg_; p != __iend_; ++p) { if (*p != nullptr) { (*p)->~__i_node(); free(*p); } } free(__ibeg_); } } void* __libcpp_db::__find_c_from_i(void* __i) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); _LIBCPP_ASSERT(i != nullptr, "iterator not found in debug database."); return i->__c_ != nullptr ? i->__c_->__c_ : nullptr; } void __libcpp_db::__insert_ic(void* __i, const void* __c) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif if (__cbeg_ == __cend_) return; size_t hc = hash<const void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* c = __cbeg_[hc]; if (c == nullptr) return; while (c->__c_ != __c) { c = c->__next_; if (c == nullptr) return; } __i_node* i = __insert_iterator(__i); c->__add(i); i->__c_ = c; } __c_node* __libcpp_db::__insert_c(void* __c) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif if (__csz_ + 1 > static_cast<size_t>(__cend_ - __cbeg_)) { size_t nc = __next_prime(2*static_cast<size_t>(__cend_ - __cbeg_) + 1); __c_node** cbeg = static_cast<__c_node**>(calloc(nc, sizeof(void*))); if (cbeg == nullptr) __throw_bad_alloc(); for (__c_node** p = __cbeg_; p != __cend_; ++p) { __c_node* q = *p; while (q != nullptr) { size_t h = hash<void*>()(q->__c_) % nc; __c_node* r = q->__next_; q->__next_ = cbeg[h]; cbeg[h] = q; q = r; } } free(__cbeg_); __cbeg_ = cbeg; __cend_ = __cbeg_ + nc; } size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; __c_node* r = __cbeg_[hc] = static_cast<__c_node*>(malloc(sizeof(__c_node))); if (__cbeg_[hc] == nullptr) __throw_bad_alloc(); r->__c_ = __c; r->__next_ = p; ++__csz_; return r; } void __libcpp_db::__erase_i(void* __i) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif if (__ibeg_ != __iend_) { size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_); __i_node* p = __ibeg_[hi]; if (p != nullptr) { __i_node* q = nullptr; while (p->__i_ != __i) { q = p; p = p->__next_; if (p == nullptr) return; } if (q == nullptr) __ibeg_[hi] = p->__next_; else q->__next_ = p->__next_; __c_node* c = p->__c_; --__isz_; if (c != nullptr) c->__remove(p); free(p); } } } void __libcpp_db::__invalidate_all(void* __c) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif if (__cend_ != __cbeg_) { size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; if (p == nullptr) return; while (p->__c_ != __c) { p = p->__next_; if (p == nullptr) return; } while (p->end_ != p->beg_) { --p->end_; (*p->end_)->__c_ = nullptr; } } } __c_node* __libcpp_db::__find_c_and_lock(void* __c) const { #ifndef _LIBCPP_HAS_NO_THREADS mut().lock(); #endif if (__cend_ == __cbeg_) { #ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); #endif return nullptr; } size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; if (p == nullptr) { #ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); #endif return nullptr; } while (p->__c_ != __c) { p = p->__next_; if (p == nullptr) { #ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); #endif return nullptr; } } return p; } __c_node* __libcpp_db::__find_c(void* __c) const { size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c A"); while (p->__c_ != __c) { p = p->__next_; _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __find_c B"); } return p; } void __libcpp_db::unlock() const { #ifndef _LIBCPP_HAS_NO_THREADS mut().unlock(); #endif } void __libcpp_db::__erase_c(void* __c) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif if (__cend_ != __cbeg_) { size_t hc = hash<void*>()(__c) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p = __cbeg_[hc]; if (p == nullptr) return; __c_node* q = nullptr; _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c A"); while (p->__c_ != __c) { q = p; p = p->__next_; if (p == nullptr) return; _LIBCPP_ASSERT(p != nullptr, "debug mode internal logic error __erase_c B"); } if (q == nullptr) __cbeg_[hc] = p->__next_; else q->__next_ = p->__next_; while (p->end_ != p->beg_) { --p->end_; (*p->end_)->__c_ = nullptr; } free(p->beg_); free(p); --__csz_; } } void __libcpp_db::__iterator_copy(void* __i, const void* __i0) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif __i_node* i = __find_iterator(__i); __i_node* i0 = __find_iterator(__i0); __c_node* c0 = i0 != nullptr ? i0->__c_ : nullptr; if (i == nullptr && i0 != nullptr) i = __insert_iterator(__i); __c_node* c = i != nullptr ? i->__c_ : nullptr; if (c != c0) { if (c != nullptr) c->__remove(i); if (i != nullptr) { i->__c_ = nullptr; if (c0 != nullptr) { i->__c_ = c0; i->__c_->__add(i); } } } } bool __libcpp_db::__dereferenceable(const void* __i) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__dereferenceable(__i); } bool __libcpp_db::__decrementable(const void* __i) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__decrementable(__i); } bool __libcpp_db::__addable(const void* __i, ptrdiff_t __n) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__addable(__i, __n); } bool __libcpp_db::__subscriptable(const void* __i, ptrdiff_t __n) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); return i != nullptr && i->__c_ != nullptr && i->__c_->__subscriptable(__i, __n); } bool __libcpp_db::__less_than_comparable(const void* __i, const void* __j) const { #ifndef _LIBCPP_HAS_NO_THREADS RLock _(mut()); #endif __i_node* i = __find_iterator(__i); __i_node* j = __find_iterator(__j); __c_node* ci = i != nullptr ? i->__c_ : nullptr; __c_node* cj = j != nullptr ? j->__c_ : nullptr; return ci != nullptr && ci == cj; } void __libcpp_db::swap(void* c1, void* c2) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif size_t hc = hash<void*>()(c1) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p1 = __cbeg_[hc]; _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap A"); while (p1->__c_ != c1) { p1 = p1->__next_; _LIBCPP_ASSERT(p1 != nullptr, "debug mode internal logic error swap B"); } hc = hash<void*>()(c2) % static_cast<size_t>(__cend_ - __cbeg_); __c_node* p2 = __cbeg_[hc]; _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap C"); while (p2->__c_ != c2) { p2 = p2->__next_; _LIBCPP_ASSERT(p2 != nullptr, "debug mode internal logic error swap D"); } std::swap(p1->beg_, p2->beg_); std::swap(p1->end_, p2->end_); std::swap(p1->cap_, p2->cap_); for (__i_node** p = p1->beg_; p != p1->end_; ++p) (*p)->__c_ = p1; for (__i_node** p = p2->beg_; p != p2->end_; ++p) (*p)->__c_ = p2; } void __libcpp_db::__insert_i(void* __i) { #ifndef _LIBCPP_HAS_NO_THREADS WLock _(mut()); #endif __insert_iterator(__i); } void __c_node::__add(__i_node* i) { if (end_ == cap_) { size_t nc = 2*static_cast<size_t>(cap_ - beg_); if (nc == 0) nc = 1; __i_node** beg = static_cast<__i_node**>(malloc(nc * sizeof(__i_node*))); if (beg == nullptr) __throw_bad_alloc(); if (nc > 1) memcpy(beg, beg_, nc/2*sizeof(__i_node*)); free(beg_); beg_ = beg; end_ = beg_ + nc/2; cap_ = beg_ + nc; } *end_++ = i; } // private api _LIBCPP_HIDDEN __i_node* __libcpp_db::__insert_iterator(void* __i) { if (__isz_ + 1 > static_cast<size_t>(__iend_ - __ibeg_)) { size_t nc = __next_prime(2*static_cast<size_t>(__iend_ - __ibeg_) + 1); __i_node** ibeg = static_cast<__i_node**>(calloc(nc, sizeof(void*))); if (ibeg == nullptr) __throw_bad_alloc(); for (__i_node** p = __ibeg_; p != __iend_; ++p) { __i_node* q = *p; while (q != nullptr) { size_t h = hash<void*>()(q->__i_) % nc; __i_node* r = q->__next_; q->__next_ = ibeg[h]; ibeg[h] = q; q = r; } } free(__ibeg_); __ibeg_ = ibeg; __iend_ = __ibeg_ + nc; } size_t hi = hash<void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_); __i_node* p = __ibeg_[hi]; __i_node* r = __ibeg_[hi] = static_cast<__i_node*>(malloc(sizeof(__i_node))); if (r == nullptr) __throw_bad_alloc(); ::new(r) __i_node(__i, p, nullptr); ++__isz_; return r; } _LIBCPP_HIDDEN __i_node* __libcpp_db::__find_iterator(const void* __i) const { __i_node* r = nullptr; if (__ibeg_ != __iend_) { size_t h = hash<const void*>()(__i) % static_cast<size_t>(__iend_ - __ibeg_); for (__i_node* nd = __ibeg_[h]; nd != nullptr; nd = nd->__next_) { if (nd->__i_ == __i) { r = nd; break; } } } return r; } _LIBCPP_HIDDEN void __c_node::__remove(__i_node* p) { __i_node** r = find(beg_, end_, p); _LIBCPP_ASSERT(r != end_, "debug mode internal logic error __c_node::__remove"); if (--end_ != r) memmove(r, r+1, static_cast<size_t>(end_ - r)*sizeof(__i_node*)); } _LIBCPP_END_NAMESPACE_STD