/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef OHOS_HIVIEWDFX_HASHLIST_HPP #define OHOS_HIVIEWDFX_HASHLIST_HPP #include "hashlist.h" namespace OHOS { namespace HiviewDFX { // implementation of template class LinkNode template LinkNode::LinkNode(const Key &key) : key_ {key} {} template LinkNode::LinkNode(const Key &key, const Val &val) : key_ {key}, val_ {val} {} template LinkNode::LinkNode(const Key &key, Val &&val) : key_ {key}, val_ {std::move(val)} {} template LinkNode::LinkNode(const LinkNode& node) :link_ {node.link_}, key_ {node.key_}, val_ {node.val_} {} template LinkNode::LinkNode(LinkNode&& node) :link_ {std::move(node.link_)}, key_ {std::move(node.key_)}, val_ {std::move(node.val_)} {} template auto LinkNode::operator=(const LinkNode& node) -> LinkNode& { link_ = node.link_; key_ = node.key_; val_ = node.val_; } template auto LinkNode::operator=(LinkNode&& node) -> LinkNode& { link_ = std::move(node.link_); key_ = std::move(node.key_); val_ = std::move(node.val_); } template auto LinkNode::GetLinkNode(Val *pval) -> LinkNode* { if (pval) { LinkNode *pnode {nullptr}; Val* offset = &pnode->val_; auto nodeAddr = reinterpret_cast(pval) - reinterpret_cast(offset); return reinterpret_cast*>(nodeAddr); } return nullptr; } template auto LinkNode::GetLinkNode(Link *plink) -> LinkNode* { if (plink) { LinkNode *pnode {nullptr}; Link* offset = &pnode->link_; auto nodeAddr = reinterpret_cast(plink) - reinterpret_cast(offset); return reinterpret_cast*>(nodeAddr); } return nullptr; } // end of LinkNode // implementation of template class Iterator template HashList::Iterator::Iterator(LinkNode *pnode, HashList *phashList) : pnode_ {pnode}, phashList_ {phashList} { if (phashList_ == nullptr) { pnode_ = nullptr; } } template HashList::Iterator::Iterator(const LinkNode *pnode, const HashList *phashList) : pnode_ {const_cast*>(pnode)}, phashList_ {const_cast(phashList)} { if (phashList_ == nullptr) { pnode_ = nullptr; } } template HashList::Iterator::Iterator(const Iterator& itr) : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} {} template HashList::Iterator::Iterator(Iterator&& itr) : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} { itr.pnode_ = nullptr; itr.phashList_ = nullptr; } template auto HashList::Iterator::operator=(const Iterator& itr) -> HashList::Iterator& { Iterator temp {itr}; swap(temp); return *this; } template auto HashList::Iterator::operator=(Iterator&& itr) -> HashList::Iterator& { Iterator temp {std::move(itr)}; swap(temp); return *this; } template auto HashList::Iterator::operator++() noexcept -> HashList::Iterator & { if (pnode_ == nullptr or phashList_ == nullptr) { phashList_ = nullptr; return *this; } Link* plink = pnode_->link_.next_; if (plink == &phashList_->dataHead_) { pnode_ = nullptr; return *this; } auto pnode = LinkNode::GetLinkNode(plink); pnode_ = pnode; return *this; } template auto HashList::Iterator::operator++(int) noexcept -> HashList::Iterator { Iterator res {*this}; if (pnode_ == nullptr or phashList_ == nullptr) { phashList_ = nullptr; return res; } Link* plink = pnode_->link_.next_; if (plink == &phashList_->dataHead_) { pnode_ = nullptr; return res; } auto pnode = LinkNode::GetLinkNode(plink); pnode_ = pnode; return res; } template auto HashList::Iterator::operator--() noexcept -> HashList::Iterator & { if (phashList_ == nullptr) { return *this; } Link* plink {nullptr}; if (pnode_ == nullptr) { plink = phashList_->dataHead_.prev_; } else { plink = pnode_->link_.prev_; } if (plink == &phashList_->dataHead_) { pnode_ = nullptr; phashList_ = nullptr; return *this; } pnode_ = LinkNode::GetLinkNode(plink); return *this; } template auto HashList::Iterator::operator--(int) noexcept -> HashList::Iterator { Iterator res {*this}; if (phashList_ == nullptr) { return res; } Link* plink {nullptr}; if (pnode_ == nullptr) { plink = phashList_->dataHead_.prev_; } else { plink = pnode_->link_.prev_; } if (plink == &phashList_->dataHead_) { pnode_ = nullptr; phashList_ = nullptr; return res; } pnode_ = LinkNode::GetLinkNode(plink); return res; } template bool HashList::Iterator::operator<(const HashList::Iterator &itr) const noexcept { if (IsDangled() or itr.IsDangled()) { return false; } if (phashList_ != itr.phashList_) { return false; } Iterator tempItr {*this}; if (tempItr == itr) { return false; } while (!tempItr.IsDangled()) { tempItr++; if (tempItr == itr) { return true; } } return false; } template bool HashList::Iterator::operator==(const HashList::Iterator &itr) const noexcept { if (IsDangled() or itr.IsDangled()) { return false; } if (phashList_ != itr.phashList_) { return false; } return pnode_ == itr.pnode_; } template Val& HashList::Iterator::operator*() { return pnode_->val_; } template const Val& HashList::Iterator::operator*() const { return pnode_->val_; } template Val* HashList::Iterator::operator->() { return &pnode_->val_; } template const Val* HashList::Iterator::operator->() const { return &pnode_->val_; } template void HashList::Iterator::swap(HashList::Iterator& other) { using std::swap; swap(pnode_, other.pnode_); swap(phashList_, other.phashList_); } // end of Iterator // Implementation of ReverseIterator template HashList::ReverseIterator::ReverseIterator(LinkNode *pnode, HashList *phashList) : pnode_ {pnode}, phashList_ {phashList} { if (phashList_ == nullptr) { pnode_ = nullptr; } } template HashList::ReverseIterator::ReverseIterator(const LinkNode *pnode, const HashList *phashList) : pnode_ {const_cast *>(pnode)}, phashList_ {const_cast(phashList)} { if (phashList_ == nullptr) { pnode_ = nullptr; } } template HashList::ReverseIterator::ReverseIterator(const ReverseIterator &itr) : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} {} template HashList::ReverseIterator::ReverseIterator(ReverseIterator &&itr) : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} { itr.pnode_ = nullptr; itr.phashList_ = nullptr; } template auto HashList::ReverseIterator::operator=(const ReverseIterator& itr) -> HashList::ReverseIterator& { ReverseIterator temp {itr}; swap(temp); return *this; } template auto HashList::ReverseIterator::operator=(ReverseIterator&& itr) -> HashList::ReverseIterator& { ReverseIterator temp {std::move(itr)}; swap(temp); return *this; } template auto HashList::ReverseIterator::operator++() noexcept -> HashList::ReverseIterator & { if (pnode_ == nullptr or phashList_ == nullptr) { phashList_ = nullptr; return *this; } Link* plink = &pnode_->link_; plink = plink->prev_; if (plink == &phashList_->dataHead_) { pnode_ = nullptr; return *this; } pnode_ = LinkNode::GetLinkNode(plink); return *this; } template auto HashList::ReverseIterator::operator++(int) noexcept -> HashList::ReverseIterator { ReverseIterator res {*this}; if (pnode_ == nullptr or phashList_ == nullptr) { phashList_ = nullptr; return res; } Link* plink = &pnode_->link_; plink = plink->prev_; if (plink == &phashList_->dataHead_) { pnode_ = nullptr; return res; } pnode_ = LinkNode::GetLinkNode(plink); return res; } template auto HashList::ReverseIterator::operator--() noexcept -> HashList::ReverseIterator & { if (phashList_ == nullptr) { return *this; } Link* plink {nullptr}; if (pnode_ == nullptr) { plink = phashList_->dataHead_.next_; } else { plink = pnode_->link_.next_; } if (plink == &phashList_->dataHead_) { pnode_ = nullptr; phashList_ = nullptr; return *this; } pnode_ = LinkNode::GetLinkNode(plink); return *this; } template auto HashList::ReverseIterator::operator--(int) noexcept -> HashList::ReverseIterator { ReverseIterator res {*this}; if (phashList_ == nullptr) { return res; } Link* plink {nullptr}; if (pnode_ == nullptr) { plink = phashList_->dataHead_.next_; } else { plink = pnode_->link_.next_; } if (plink == &phashList_->dataHead_) { pnode_ = nullptr; phashList_ = nullptr; return res; } pnode_ = LinkNode::GetLinkNode(plink); return res; } template bool HashList::ReverseIterator::operator<( const HashList::ReverseIterator &itr) const noexcept { if (IsDangled() or itr.IsDangled()) { return false; } if (phashList_ != itr.phashList_) { return false; } HashList::ReverseIterator tempItr {*this}; if (tempItr == itr) { return false; } while (!tempItr.IsDangled()) { tempItr++; if (tempItr == itr) { return true; } } return false; } template bool HashList::ReverseIterator::operator==( const HashList::ReverseIterator &itr) const noexcept { if (IsDangled() or itr.IsDangled()) { return false; } if (phashList_ != itr.phashList_) { return false; } return pnode_ == itr.pnode_; } template Val& HashList::ReverseIterator::operator*() { return pnode_->val_; } template const Val& HashList::ReverseIterator::operator*() const { return pnode_->val_; } template Val* HashList::ReverseIterator::operator->() { return &pnode_->val_; } template const Val* HashList::ReverseIterator::operator->() const { return &pnode_->val_; } template void HashList::ReverseIterator::swap(HashList::ReverseIterator& other) { using std::swap; swap(pnode_, other.pnode_); swap(phashList_, other.phashList_); } // end of ReverseIterator // implementation of template class HashList template HashList::HashList(const std::size_t numItem) : numItem_ {numItem} { dataHead_.next_ = &dataHead_; dataHead_.prev_ = &dataHead_; if (numItem_ != 0) { valueTab_.reserve(numItem_); pData_ = new(std::nothrow) LinkNode[numItem_]; if (pData_) { freeHead_.next_ = &(pData_[0].link_); std::size_t last {numItem_ - 1}; for (std::size_t index = 0; index < last;) { LinkNode &curNnode = pData_[index]; curNnode.link_.next_ = &(pData_[++index].link_); } pData_[last].link_.next_ = &freeHead_; } else { numItem_ = 0; freeHead_.next_ = &freeHead_; freeHead_.prev_ = &freeHead_; } } } template int HashList::reserve(const std::size_t numItem) { if (numItem_ != 0) { return -1; } if (numItem != 0) { numItem_ = numItem; valueTab_.reserve(numItem_); pData_ = new(std::nothrow) LinkNode[numItem_]; dataHead_.next_ = &dataHead_; dataHead_.prev_ = &dataHead_; if (pData_) { freeHead_.next_ = &(pData_[0].link_); std::size_t last {numItem_ - 1}; for (std::size_t index = 0; index < last;) { LinkNode &curNnode = pData_[index]; curNnode.link_.next_ = &(pData_[++index].link_); } pData_[last].link_.next_ = &freeHead_; } else { numItem_ = 0; freeHead_.next_ = &freeHead_; freeHead_.prev_ = &freeHead_; } } return numItem_; } template HashList::~HashList() { if (pData_) { delete[] pData_; pData_ = nullptr; } valueTab_.clear(); dataHead_.next_ = &dataHead_; dataHead_.prev_ = &dataHead_; freeHead_.next_ = nullptr; freeHead_.prev_ = nullptr; numItem_ = 0; } template HashList::HashList(HashList &&source) : numItem_ {source.numItem_}, pData_ {source.pData_}, dataHead_ {std::move(source.dataHead_)}, freeHead_ {std::move(source.freeHead_)}, valueTab_ {std::move(source.valueTab_)} { source.pData_ = nullptr; } template auto HashList::operator=(HashList &&source) -> HashList& { if (this == &source) { return *this; } if (pData_) { delete[] pData_; pData_ = nullptr; } numItem_ = source.numItem_; pData_ = source.pData_; source.pData_ = nullptr; dataHead_ = std::move(source.dataHead_); freeHead_ = std::move(source.freeHead_); valueTab_ = std::move(source.valueTab_); return *this; } template auto HashList::begin() -> HashList::Iterator { if (empty()) { return end(); } return Iterator(LinkNode::GetLinkNode(dataHead_.next_), this); } template auto HashList::cbegin() const -> const HashList::Iterator { if (empty()) { return cend(); } return Iterator(LinkNode::GetLinkNode(dataHead_.next_), this); } template auto HashList::end() -> HashList::Iterator { return Iterator(nullptr, this); } template auto HashList::cend() const -> const HashList::Iterator { return Iterator(nullptr, this); } template auto HashList::rbegin() -> HashList::ReverseIterator { if (empty()) { return rend(); } return ReverseIterator(LinkNode::GetLinkNode(dataHead_.prev_), this); } template auto HashList::crbegin() const -> const HashList::ReverseIterator { if (empty()) { return crend(); } return ReverseIterator(LinkNode::GetLinkNode(dataHead_.prev_), this); } template auto HashList::rend() -> HashList::ReverseIterator { return ReverseIterator(nullptr, this); } template auto HashList::crend() const -> const HashList::ReverseIterator { return ReverseIterator(nullptr, this); } template Val& HashList::front() { LinkNode *pnode = LinkNode::GetLinkNode(dataHead_.next_); return pnode->val_; } template const Val& HashList::front() const { return front(); } template Val& HashList::back(bool prepend) { auto pnode = LinkNode::GetLinkNode(dataHead_.prev_); if (prepend) { MoveToHead(pnode); } return pnode->val_; } template Val& HashList::operator[](const Key &key) { LinkNode *pnode {nullptr}; if (valueTab_.find(key) == valueTab_.end()) { pnode = AllocateNode(key); valueTab_[key] = pnode; } else { pnode = valueTab_[key]; } if (pnode) { MoveToHead(pnode); } return pnode->val_; } template auto HashList::find(const Key &key) -> HashList::Iterator { const auto &itr = valueTab_.find(key); if (itr == valueTab_.end()) { return end(); } return Iterator(itr->second, this); } template void HashList::push_front(const Key& key, const Val& val) { if (valueTab_.find(key) == valueTab_.end()) { LinkNode* pnode = AllocateNode(key, val); MoveToHead(pnode); valueTab_[pnode->key_] = pnode; } else { MoveToHead(valueTab_[key]); this->operator[](key) = val; } } template void HashList::push_front(const Key& key, Val&& val) { if (valueTab_.find(key) == valueTab_.end()) { LinkNode* pnode = AllocateNode(key, std::move(val)); MoveToHead(pnode); valueTab_[pnode->key_] = pnode; } else { MoveToHead(valueTab_[key]); this->operator[](key) = val; } } template void HashList::push_back(const Key& key, const Val& val) { if (valueTab_.find(key) == valueTab_.end()) { LinkNode* pnode = AllocateNode(key, val); MoveToTail(pnode); valueTab_[pnode->key_] = pnode; } else { MoveToTail(valueTab_[key]); this->operator[](key) = val; } } template void HashList::push_back(const Key& key, Val&& val) { if (valueTab_.find(key) == valueTab_.end()) { LinkNode* pnode = AllocateNode(key, std::move(val)); MoveToTail(pnode); valueTab_[pnode->key_] = pnode; } else { MoveToTail(valueTab_[key]); this->operator[](key) = val; } } template void HashList::pop_front() { if (empty()) { return; } LinkNode* pnode = LinkNode::GetLinkNode(dataHead_.next_); valueTab_.erase(pnode->key_); ReclaimNode(pnode); } template void HashList::pop_back() { if (empty()) { return; } LinkNode* pnode = LinkNode::GetLinkNode(dataHead_.prev_); valueTab_.erase(pnode->key_); ReclaimNode(pnode); } template auto HashList::erase(const Key& key) -> HashList::Iterator { if (valueTab_.find(key) == valueTab_.end()) { return end(); } LinkNode *pnode = valueTab_[key]; valueTab_.erase(key); Link* plink = pnode->link_.next_; Iterator tempItr {LinkNode::GetLinkNode(plink), this}; ReclaimNode(pnode); return tempItr; } template auto HashList::erase(const Iterator pos) -> HashList::Iterator { // assume pos is valid, otherwise the result is undefined Iterator tempItr {pos}; ++tempItr; LinkNode *pnode = pos.GetNode(); valueTab_.erase(pnode->key_); ReclaimNode(pnode); return tempItr; } template auto HashList::erase(const Iterator first, const Iterator last) -> HashList::Iterator { // assume pos is valid, otherwise the result is undefined if (first <= last) { Iterator curPos {first}; while (curPos < last) { curPos = erase(curPos); } return last; } return end(); } template bool HashList::MoveNode(const Iterator& pos, LinkNode *&pnode) const { LinkNode *curNode = pos.GetNode(); if (curNode == pnode) { return true; } if (pnode->link_.next_ == &curNode->link_) { return true; } Link* prevLink = pnode->link_.prev_; Link* nextLink = pnode->link_.next_; if (prevLink and nextLink) { prevLink->next_ = nextLink; nextLink->prev_ = prevLink; } Link *currLink = &curNode->link_; prevLink = currLink->prev_; nextLink = &pnode->link_; prevLink->next_ = nextLink; nextLink->prev_ = prevLink; nextLink->next_ = currLink; currLink->prev_ = nextLink; return true; } template void HashList::MoveToHead(LinkNode *&pnode) { if (pnode->link_.prev_ and pnode->link_.next_) { Link* prev = pnode->link_.prev_; Link* next = pnode->link_.next_; prev->next_ = next; next->prev_ = prev; } pnode->link_.next_ = dataHead_.next_; dataHead_.next_->prev_ = &pnode->link_; dataHead_.next_ = &pnode->link_; pnode->link_.prev_ = &dataHead_; } template void HashList::MoveToTail(LinkNode *&pnode) { if (pnode->link_.prev_ and pnode->link_.next_) { Link* prev = pnode->link_.prev_; Link* next = pnode->link_.next_; prev->next_ = next; next->prev_ = prev; } pnode->link_.prev_ = dataHead_.prev_; dataHead_.prev_->next_ = &pnode->link_; pnode->link_.next_ = &dataHead_; dataHead_.prev_ = &pnode->link_; } template auto HashList::AllocateNode(const Key &key) ->LinkNode * { if (IsFull()) { pop_back(); } LinkNode * pnode = LinkNode::GetLinkNode(freeHead_.next_); freeHead_.next_ = freeHead_.next_->next_; pnode->link_.next_ = nullptr; pnode->link_.prev_ = nullptr; pnode->key_ = key; pnode->val_ = Val(); return pnode; } template auto HashList::AllocateNode(const Key &key, const Val &val) ->LinkNode * { if (IsFull()) { pop_back(); } LinkNode *pnode = LinkNode::GetLinkNode(freeHead_.next_); freeHead_.next_ = freeHead_.next_->next_; pnode->link_.next_ = nullptr; pnode->link_.prev_ = nullptr; pnode->key_ = key; pnode->val_ = val; return pnode; } template auto HashList::AllocateNode(const Key &key, Val &&val) ->LinkNode * { if (IsFull()) { pop_back(); } LinkNode * pnode = LinkNode::GetLinkNode(freeHead_.next_); freeHead_.next_ = freeHead_.next_->next_; pnode->link_.next_ = nullptr; pnode->link_.prev_ = nullptr; pnode->key_ = key; pnode->val_ = std::move(val); return pnode; } template void HashList::ReclaimNode(LinkNode *&pnode) { Link *prevLink = pnode->link_.prev_; Link *nextLink = pnode->link_.next_; prevLink->next_ = nextLink; nextLink->prev_ = prevLink; pnode->link_.prev_ = nullptr; pnode->link_.next_ = freeHead_.next_; freeHead_.next_ = &pnode->link_; return; } } // namespace HiviewDFX } // namespace OHOS #endif // OHOS_HIVIEWDFX_HASHLIST_HPP