/* * Copyright (C) 2016 The Android Open Source Project * * 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 ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ #define ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ #include <stdint.h> #include <functional> #include <iterator> #include <memory> #include <type_traits> #include "base/logging.h" #include "base/macros.h" namespace art { struct IntrusiveForwardListHook { IntrusiveForwardListHook() : next_hook(nullptr) { } explicit IntrusiveForwardListHook(const IntrusiveForwardListHook* hook) : next_hook(hook) { } // Allow copyable values but do not copy the hook, it is not part of the value. IntrusiveForwardListHook(const IntrusiveForwardListHook& other ATTRIBUTE_UNUSED) : next_hook(nullptr) { } IntrusiveForwardListHook& operator=(const IntrusiveForwardListHook& src ATTRIBUTE_UNUSED) { return *this; } mutable const IntrusiveForwardListHook* next_hook; }; template <typename T, IntrusiveForwardListHook T::* NextPtr = &T::hook> class IntrusiveForwardListMemberHook; template <typename T, typename HookTraits = IntrusiveForwardListMemberHook<T>> class IntrusiveForwardList; template <typename T, typename HookTraits> class IntrusiveForwardListIterator : public std::iterator<std::forward_iterator_tag, T> { public: // Construct/copy/destroy (except the private constructor used by IntrusiveForwardList<>). IntrusiveForwardListIterator() : hook_(nullptr) { } IntrusiveForwardListIterator(const IntrusiveForwardListIterator& src) = default; IntrusiveForwardListIterator& operator=(const IntrusiveForwardListIterator& src) = default; // Conversion from iterator to const_iterator. template <typename OtherT, typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type> IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src) : hook_(src.hook_) { } // Iteration. IntrusiveForwardListIterator& operator++() { DCHECK(hook_ != nullptr); hook_ = hook_->next_hook; return *this; } IntrusiveForwardListIterator operator++(int) { IntrusiveForwardListIterator tmp(*this); ++*this; return tmp; } // Dereference T& operator*() const { DCHECK(hook_ != nullptr); return *HookTraits::GetValue(hook_); } T* operator->() const { return &**this; } private: explicit IntrusiveForwardListIterator(const IntrusiveForwardListHook* hook) : hook_(hook) { } const IntrusiveForwardListHook* hook_; template <typename OtherT, typename OtherTraits> friend class IntrusiveForwardListIterator; template <typename OtherT, typename OtherTraits> friend class IntrusiveForwardList; template <typename OtherT1, typename OtherT2, typename OtherTraits> friend typename std::enable_if<std::is_same<const OtherT1, const OtherT2>::value, bool>::type operator==(const IntrusiveForwardListIterator<OtherT1, OtherTraits>& lhs, const IntrusiveForwardListIterator<OtherT2, OtherTraits>& rhs); }; template <typename T, typename OtherT, typename HookTraits> typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator==( const IntrusiveForwardListIterator<T, HookTraits>& lhs, const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { return lhs.hook_ == rhs.hook_; } template <typename T, typename OtherT, typename HookTraits> typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator!=( const IntrusiveForwardListIterator<T, HookTraits>& lhs, const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { return !(lhs == rhs); } // Intrusive version of std::forward_list<>. See also slist<> in Boost.Intrusive. // // This class template provides the same interface as std::forward_list<> as long // as the functions are meaningful for an intrusive container; this excludes emplace // functions and functions taking an std::initializer_list<> as the container does // not construct elements. template <typename T, typename HookTraits> class IntrusiveForwardList { public: typedef HookTraits hook_traits; typedef T value_type; typedef T& reference; typedef const T& const_reference; typedef T* pointer; typedef const T* const_pointer; typedef IntrusiveForwardListIterator< T, hook_traits> iterator; typedef IntrusiveForwardListIterator<const T, hook_traits> const_iterator; // Construct/copy/destroy. IntrusiveForwardList() = default; template <typename InputIterator> IntrusiveForwardList(InputIterator first, InputIterator last) : IntrusiveForwardList() { insert_after(before_begin(), first, last); } IntrusiveForwardList(IntrusiveForwardList&& src) : first_(src.first_.next_hook) { src.first_.next_hook = nullptr; } IntrusiveForwardList& operator=(const IntrusiveForwardList& src) = delete; IntrusiveForwardList& operator=(IntrusiveForwardList&& src) { IntrusiveForwardList tmp(std::move(src)); tmp.swap(*this); return *this; } ~IntrusiveForwardList() = default; // Iterators. iterator before_begin() { return iterator(&first_); } const_iterator before_begin() const { return const_iterator(&first_); } iterator begin() { return iterator(first_.next_hook); } const_iterator begin() const { return const_iterator(first_.next_hook); } iterator end() { return iterator(nullptr); } const_iterator end() const { return const_iterator(nullptr); } const_iterator cbefore_begin() const { return const_iterator(&first_); } const_iterator cbegin() const { return const_iterator(first_.next_hook); } const_iterator cend() const { return const_iterator(nullptr); } // Capacity. bool empty() const { return begin() == end(); } size_t max_size() { return static_cast<size_t>(-1); } // Element access. reference front() { return *begin(); } const_reference front() const { return *begin(); } // Modifiers. template <typename InputIterator> void assign(InputIterator first, InputIterator last) { IntrusiveForwardList tmp(first, last); tmp.swap(*this); } void push_front(value_type& value) { insert_after(before_begin(), value); } void pop_front() { DCHECK(!empty()); erase_after(before_begin()); } iterator insert_after(const_iterator position, value_type& value) { const IntrusiveForwardListHook* new_hook = hook_traits::GetHook(&value); new_hook->next_hook = position.hook_->next_hook; position.hook_->next_hook = new_hook; return iterator(new_hook); } template <typename InputIterator> iterator insert_after(const_iterator position, InputIterator first, InputIterator last) { while (first != last) { position = insert_after(position, *first++); } return iterator(position.hook_); } iterator erase_after(const_iterator position) { const_iterator last = position; std::advance(last, 2); return erase_after(position, last); } iterator erase_after(const_iterator position, const_iterator last) { DCHECK(position != last); position.hook_->next_hook = last.hook_; return iterator(last.hook_); } void swap(IntrusiveForwardList& other) { std::swap(first_.next_hook, other.first_.next_hook); } void clear() { first_.next_hook = nullptr; } // Operations. void splice_after(const_iterator position, IntrusiveForwardList& src) { DCHECK(position != end()); splice_after(position, src, src.before_begin(), src.end()); } void splice_after(const_iterator position, IntrusiveForwardList&& src) { splice_after(position, src); // Use l-value overload. } // Splice the element after `i`. void splice_after(const_iterator position, IntrusiveForwardList& src, const_iterator i) { // The standard specifies that this version does nothing if `position == i` // or `position == ++i`. We must handle the latter here because the overload // `splice_after(position, src, first, last)` does not allow `position` inside // the range `(first, last)`. if (++const_iterator(i) == position) { return; } const_iterator last = i; std::advance(last, 2); splice_after(position, src, i, last); } // Splice the element after `i`. void splice_after(const_iterator position, IntrusiveForwardList&& src, const_iterator i) { splice_after(position, src, i); // Use l-value overload. } // Splice elements between `first` and `last`, i.e. open range `(first, last)`. void splice_after(const_iterator position, IntrusiveForwardList& src, const_iterator first, const_iterator last) { DCHECK(position != end()); DCHECK(first != last); if (++const_iterator(first) == last) { // Nothing to do. return; } // If position is just before end() and last is src.end(), we can finish this quickly. if (++const_iterator(position) == end() && last == src.end()) { position.hook_->next_hook = first.hook_->next_hook; first.hook_->next_hook = nullptr; return; } // Otherwise we need to find the position before last to fix up the hook. const_iterator before_last = first; while (++const_iterator(before_last) != last) { ++before_last; } // Detach (first, last). const IntrusiveForwardListHook* first_taken = first.hook_->next_hook; first.hook_->next_hook = last.hook_; // Attach the sequence to the new position. before_last.hook_->next_hook = position.hook_->next_hook; position.hook_->next_hook = first_taken; } // Splice elements between `first` and `last`, i.e. open range `(first, last)`. void splice_after(const_iterator position, IntrusiveForwardList&& src, const_iterator first, const_iterator last) { splice_after(position, src, first, last); // Use l-value overload. } void remove(const value_type& value) { remove_if([value](const value_type& v) { return value == v; }); } template <typename Predicate> void remove_if(Predicate pred) { iterator prev = before_begin(); for (iterator current = begin(); current != end(); ++current) { if (pred(*current)) { erase_after(prev); current = prev; } else { prev = current; } } } void unique() { unique(std::equal_to<value_type>()); } template <typename BinaryPredicate> void unique(BinaryPredicate pred) { if (!empty()) { iterator prev = begin(); iterator current = prev; ++current; for (; current != end(); ++current) { if (pred(*prev, *current)) { erase_after(prev); current = prev; } else { prev = current; } } } } void merge(IntrusiveForwardList& other) { merge(other, std::less<value_type>()); } void merge(IntrusiveForwardList&& other) { merge(other); // Use l-value overload. } template <typename Compare> void merge(IntrusiveForwardList& other, Compare cmp) { iterator prev = before_begin(); iterator current = begin(); iterator other_prev = other.before_begin(); iterator other_current = other.begin(); while (current != end() && other_current != other.end()) { if (cmp(*other_current, *current)) { ++other_current; splice_after(prev, other, other_prev); ++prev; } else { prev = current; ++current; } DCHECK(++const_iterator(prev) == current); DCHECK(++const_iterator(other_prev) == other_current); } splice_after(prev, other); } template <typename Compare> void merge(IntrusiveForwardList&& other, Compare cmp) { merge(other, cmp); // Use l-value overload. } void sort() { sort(std::less<value_type>()); } template <typename Compare> void sort(Compare cmp) { size_t n = std::distance(begin(), end()); if (n >= 2u) { const_iterator middle = before_begin(); std::advance(middle, n / 2u); IntrusiveForwardList second_half; second_half.splice_after(second_half.before_begin(), *this, middle, end()); sort(cmp); second_half.sort(cmp); merge(second_half, cmp); } } void reverse() { IntrusiveForwardList reversed; while (!empty()) { value_type& value = front(); erase_after(before_begin()); reversed.insert_after(reversed.before_begin(), value); } reversed.swap(*this); } // Extensions. bool HasExactlyOneElement() const { return !empty() && ++begin() == end(); } size_t SizeSlow() const { return std::distance(begin(), end()); } bool ContainsNode(const_reference node) const { for (auto&& n : *this) { if (std::addressof(n) == std::addressof(node)) { return true; } } return false; } private: static IntrusiveForwardListHook* ModifiableHook(const IntrusiveForwardListHook* hook) { return const_cast<IntrusiveForwardListHook*>(hook); } IntrusiveForwardListHook first_; }; template <typename T, typename HookTraits> void swap(IntrusiveForwardList<T, HookTraits>& lhs, IntrusiveForwardList<T, HookTraits>& rhs) { lhs.swap(rhs); } template <typename T, typename HookTraits> bool operator==(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { auto lit = lhs.begin(); auto rit = rhs.begin(); for (; lit != lhs.end() && rit != rhs.end(); ++lit, ++rit) { if (*lit != *rit) { return false; } } return lit == lhs.end() && rit == rhs.end(); } template <typename T, typename HookTraits> bool operator!=(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { return !(lhs == rhs); } template <typename T, typename HookTraits> bool operator<(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } template <typename T, typename HookTraits> bool operator>(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { return rhs < lhs; } template <typename T, typename HookTraits> bool operator<=(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { return !(rhs < lhs); } template <typename T, typename HookTraits> bool operator>=(const IntrusiveForwardList<T, HookTraits>& lhs, const IntrusiveForwardList<T, HookTraits>& rhs) { return !(lhs < rhs); } template <typename T, IntrusiveForwardListHook T::* NextPtr> class IntrusiveForwardListMemberHook { public: static const IntrusiveForwardListHook* GetHook(const T* value) { return &(value->*NextPtr); } static T* GetValue(const IntrusiveForwardListHook* hook) { return reinterpret_cast<T*>( reinterpret_cast<uintptr_t>(hook) - OFFSETOF_MEMBERPTR(T, NextPtr)); } }; } // namespace art #endif // ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_