Vladimir Marko | 46817b8 | 2016-03-29 12:21:58 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #ifndef ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ |
| 18 | #define ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ |
| 19 | |
| 20 | #include <stdint.h> |
| 21 | #include <functional> |
| 22 | #include <iterator> |
| 23 | #include <memory> |
| 24 | #include <type_traits> |
| 25 | |
| 26 | #include "base/logging.h" |
| 27 | #include "base/macros.h" |
| 28 | |
| 29 | namespace art { |
| 30 | |
| 31 | struct IntrusiveForwardListHook { |
| 32 | IntrusiveForwardListHook() : next_hook(nullptr) { } |
| 33 | explicit IntrusiveForwardListHook(const IntrusiveForwardListHook* hook) : next_hook(hook) { } |
| 34 | |
| 35 | // Allow copyable values but do not copy the hook, it is not part of the value. |
| 36 | IntrusiveForwardListHook(const IntrusiveForwardListHook& other ATTRIBUTE_UNUSED) |
| 37 | : next_hook(nullptr) { } |
| 38 | IntrusiveForwardListHook& operator=(const IntrusiveForwardListHook& src ATTRIBUTE_UNUSED) { |
| 39 | return *this; |
| 40 | } |
| 41 | |
| 42 | mutable const IntrusiveForwardListHook* next_hook; |
| 43 | }; |
| 44 | |
| 45 | template <typename T, IntrusiveForwardListHook T::* NextPtr = &T::hook> |
| 46 | class IntrusiveForwardListMemberHook; |
| 47 | |
| 48 | template <typename T, typename HookTraits = IntrusiveForwardListMemberHook<T>> |
| 49 | class IntrusiveForwardList; |
| 50 | |
| 51 | template <typename T, typename HookTraits> |
| 52 | class IntrusiveForwardListIterator : public std::iterator<std::forward_iterator_tag, T> { |
| 53 | public: |
| 54 | // Construct/copy/destroy (except the private constructor used by IntrusiveForwardList<>). |
| 55 | IntrusiveForwardListIterator() : hook_(nullptr) { } |
| 56 | IntrusiveForwardListIterator(const IntrusiveForwardListIterator& src) = default; |
| 57 | IntrusiveForwardListIterator& operator=(const IntrusiveForwardListIterator& src) = default; |
| 58 | |
| 59 | // Conversion from iterator to const_iterator. |
| 60 | template <typename OtherT, |
| 61 | typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type> |
Chih-Hung Hsieh | a593118 | 2016-09-01 15:08:13 -0700 | [diff] [blame] | 62 | IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src) // NOLINT, implicit |
Vladimir Marko | 46817b8 | 2016-03-29 12:21:58 +0100 | [diff] [blame] | 63 | : hook_(src.hook_) { } |
| 64 | |
| 65 | // Iteration. |
| 66 | IntrusiveForwardListIterator& operator++() { |
| 67 | DCHECK(hook_ != nullptr); |
| 68 | hook_ = hook_->next_hook; |
| 69 | return *this; |
| 70 | } |
| 71 | IntrusiveForwardListIterator operator++(int) { |
| 72 | IntrusiveForwardListIterator tmp(*this); |
| 73 | ++*this; |
| 74 | return tmp; |
| 75 | } |
| 76 | |
| 77 | // Dereference |
| 78 | T& operator*() const { |
| 79 | DCHECK(hook_ != nullptr); |
| 80 | return *HookTraits::GetValue(hook_); |
| 81 | } |
| 82 | T* operator->() const { |
| 83 | return &**this; |
| 84 | } |
| 85 | |
| 86 | private: |
| 87 | explicit IntrusiveForwardListIterator(const IntrusiveForwardListHook* hook) : hook_(hook) { } |
| 88 | |
| 89 | const IntrusiveForwardListHook* hook_; |
| 90 | |
| 91 | template <typename OtherT, typename OtherTraits> |
| 92 | friend class IntrusiveForwardListIterator; |
| 93 | |
| 94 | template <typename OtherT, typename OtherTraits> |
| 95 | friend class IntrusiveForwardList; |
| 96 | |
| 97 | template <typename OtherT1, typename OtherT2, typename OtherTraits> |
| 98 | friend typename std::enable_if<std::is_same<const OtherT1, const OtherT2>::value, bool>::type |
| 99 | operator==(const IntrusiveForwardListIterator<OtherT1, OtherTraits>& lhs, |
| 100 | const IntrusiveForwardListIterator<OtherT2, OtherTraits>& rhs); |
| 101 | }; |
| 102 | |
| 103 | template <typename T, typename OtherT, typename HookTraits> |
| 104 | typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator==( |
| 105 | const IntrusiveForwardListIterator<T, HookTraits>& lhs, |
| 106 | const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { |
| 107 | return lhs.hook_ == rhs.hook_; |
| 108 | } |
| 109 | |
| 110 | template <typename T, typename OtherT, typename HookTraits> |
| 111 | typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator!=( |
| 112 | const IntrusiveForwardListIterator<T, HookTraits>& lhs, |
| 113 | const IntrusiveForwardListIterator<OtherT, HookTraits>& rhs) { |
| 114 | return !(lhs == rhs); |
| 115 | } |
| 116 | |
| 117 | // Intrusive version of std::forward_list<>. See also slist<> in Boost.Intrusive. |
| 118 | // |
| 119 | // This class template provides the same interface as std::forward_list<> as long |
| 120 | // as the functions are meaningful for an intrusive container; this excludes emplace |
| 121 | // functions and functions taking an std::initializer_list<> as the container does |
| 122 | // not construct elements. |
| 123 | template <typename T, typename HookTraits> |
| 124 | class IntrusiveForwardList { |
| 125 | public: |
| 126 | typedef HookTraits hook_traits; |
| 127 | typedef T value_type; |
| 128 | typedef T& reference; |
| 129 | typedef const T& const_reference; |
| 130 | typedef T* pointer; |
| 131 | typedef const T* const_pointer; |
| 132 | typedef IntrusiveForwardListIterator< T, hook_traits> iterator; |
| 133 | typedef IntrusiveForwardListIterator<const T, hook_traits> const_iterator; |
| 134 | |
| 135 | // Construct/copy/destroy. |
| 136 | IntrusiveForwardList() = default; |
| 137 | template <typename InputIterator> |
| 138 | IntrusiveForwardList(InputIterator first, InputIterator last) : IntrusiveForwardList() { |
| 139 | insert_after(before_begin(), first, last); |
| 140 | } |
| 141 | IntrusiveForwardList(IntrusiveForwardList&& src) : first_(src.first_.next_hook) { |
| 142 | src.first_.next_hook = nullptr; |
| 143 | } |
| 144 | IntrusiveForwardList& operator=(const IntrusiveForwardList& src) = delete; |
| 145 | IntrusiveForwardList& operator=(IntrusiveForwardList&& src) { |
| 146 | IntrusiveForwardList tmp(std::move(src)); |
| 147 | tmp.swap(*this); |
| 148 | return *this; |
| 149 | } |
| 150 | ~IntrusiveForwardList() = default; |
| 151 | |
| 152 | // Iterators. |
| 153 | iterator before_begin() { return iterator(&first_); } |
| 154 | const_iterator before_begin() const { return const_iterator(&first_); } |
| 155 | iterator begin() { return iterator(first_.next_hook); } |
| 156 | const_iterator begin() const { return const_iterator(first_.next_hook); } |
| 157 | iterator end() { return iterator(nullptr); } |
| 158 | const_iterator end() const { return const_iterator(nullptr); } |
| 159 | const_iterator cbefore_begin() const { return const_iterator(&first_); } |
| 160 | const_iterator cbegin() const { return const_iterator(first_.next_hook); } |
| 161 | const_iterator cend() const { return const_iterator(nullptr); } |
| 162 | |
| 163 | // Capacity. |
| 164 | bool empty() const { return begin() == end(); } |
| 165 | size_t max_size() { return static_cast<size_t>(-1); } |
| 166 | |
| 167 | // Element access. |
| 168 | reference front() { return *begin(); } |
| 169 | const_reference front() const { return *begin(); } |
| 170 | |
| 171 | // Modifiers. |
| 172 | template <typename InputIterator> |
| 173 | void assign(InputIterator first, InputIterator last) { |
| 174 | IntrusiveForwardList tmp(first, last); |
| 175 | tmp.swap(*this); |
| 176 | } |
| 177 | void push_front(value_type& value) { |
| 178 | insert_after(before_begin(), value); |
| 179 | } |
| 180 | void pop_front() { |
| 181 | DCHECK(!empty()); |
| 182 | erase_after(before_begin()); |
| 183 | } |
| 184 | iterator insert_after(const_iterator position, value_type& value) { |
| 185 | const IntrusiveForwardListHook* new_hook = hook_traits::GetHook(&value); |
| 186 | new_hook->next_hook = position.hook_->next_hook; |
| 187 | position.hook_->next_hook = new_hook; |
| 188 | return iterator(new_hook); |
| 189 | } |
| 190 | template <typename InputIterator> |
| 191 | iterator insert_after(const_iterator position, InputIterator first, InputIterator last) { |
| 192 | while (first != last) { |
| 193 | position = insert_after(position, *first++); |
| 194 | } |
| 195 | return iterator(position.hook_); |
| 196 | } |
| 197 | iterator erase_after(const_iterator position) { |
| 198 | const_iterator last = position; |
| 199 | std::advance(last, 2); |
| 200 | return erase_after(position, last); |
| 201 | } |
| 202 | iterator erase_after(const_iterator position, const_iterator last) { |
| 203 | DCHECK(position != last); |
| 204 | position.hook_->next_hook = last.hook_; |
| 205 | return iterator(last.hook_); |
| 206 | } |
| 207 | void swap(IntrusiveForwardList& other) { |
| 208 | std::swap(first_.next_hook, other.first_.next_hook); |
| 209 | } |
| 210 | void clear() { |
| 211 | first_.next_hook = nullptr; |
| 212 | } |
| 213 | |
| 214 | // Operations. |
| 215 | void splice_after(const_iterator position, IntrusiveForwardList& src) { |
| 216 | DCHECK(position != end()); |
| 217 | splice_after(position, src, src.before_begin(), src.end()); |
| 218 | } |
| 219 | void splice_after(const_iterator position, IntrusiveForwardList&& src) { |
| 220 | splice_after(position, src); // Use l-value overload. |
| 221 | } |
| 222 | // Splice the element after `i`. |
| 223 | void splice_after(const_iterator position, IntrusiveForwardList& src, const_iterator i) { |
Vladimir Marko | c6b5627 | 2016-04-20 18:45:25 +0100 | [diff] [blame] | 224 | // The standard specifies that this version does nothing if `position == i` |
| 225 | // or `position == ++i`. We must handle the latter here because the overload |
| 226 | // `splice_after(position, src, first, last)` does not allow `position` inside |
| 227 | // the range `(first, last)`. |
| 228 | if (++const_iterator(i) == position) { |
| 229 | return; |
| 230 | } |
Vladimir Marko | 46817b8 | 2016-03-29 12:21:58 +0100 | [diff] [blame] | 231 | const_iterator last = i; |
| 232 | std::advance(last, 2); |
| 233 | splice_after(position, src, i, last); |
| 234 | } |
| 235 | // Splice the element after `i`. |
| 236 | void splice_after(const_iterator position, IntrusiveForwardList&& src, const_iterator i) { |
| 237 | splice_after(position, src, i); // Use l-value overload. |
| 238 | } |
| 239 | // Splice elements between `first` and `last`, i.e. open range `(first, last)`. |
| 240 | void splice_after(const_iterator position, |
| 241 | IntrusiveForwardList& src, |
| 242 | const_iterator first, |
| 243 | const_iterator last) { |
| 244 | DCHECK(position != end()); |
| 245 | DCHECK(first != last); |
| 246 | if (++const_iterator(first) == last) { |
| 247 | // Nothing to do. |
| 248 | return; |
| 249 | } |
| 250 | // If position is just before end() and last is src.end(), we can finish this quickly. |
| 251 | if (++const_iterator(position) == end() && last == src.end()) { |
| 252 | position.hook_->next_hook = first.hook_->next_hook; |
| 253 | first.hook_->next_hook = nullptr; |
| 254 | return; |
| 255 | } |
| 256 | // Otherwise we need to find the position before last to fix up the hook. |
| 257 | const_iterator before_last = first; |
| 258 | while (++const_iterator(before_last) != last) { |
| 259 | ++before_last; |
| 260 | } |
| 261 | // Detach (first, last). |
| 262 | const IntrusiveForwardListHook* first_taken = first.hook_->next_hook; |
| 263 | first.hook_->next_hook = last.hook_; |
| 264 | // Attach the sequence to the new position. |
| 265 | before_last.hook_->next_hook = position.hook_->next_hook; |
| 266 | position.hook_->next_hook = first_taken; |
| 267 | } |
| 268 | // Splice elements between `first` and `last`, i.e. open range `(first, last)`. |
| 269 | void splice_after(const_iterator position, |
| 270 | IntrusiveForwardList&& src, |
| 271 | const_iterator first, |
| 272 | const_iterator last) { |
| 273 | splice_after(position, src, first, last); // Use l-value overload. |
| 274 | } |
| 275 | void remove(const value_type& value) { |
| 276 | remove_if([value](const value_type& v) { return value == v; }); |
| 277 | } |
| 278 | template <typename Predicate> |
| 279 | void remove_if(Predicate pred) { |
| 280 | iterator prev = before_begin(); |
| 281 | for (iterator current = begin(); current != end(); ++current) { |
| 282 | if (pred(*current)) { |
| 283 | erase_after(prev); |
| 284 | current = prev; |
| 285 | } else { |
| 286 | prev = current; |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | void unique() { |
| 291 | unique(std::equal_to<value_type>()); |
| 292 | } |
| 293 | template <typename BinaryPredicate> |
| 294 | void unique(BinaryPredicate pred) { |
| 295 | if (!empty()) { |
| 296 | iterator prev = begin(); |
| 297 | iterator current = prev; |
| 298 | ++current; |
| 299 | for (; current != end(); ++current) { |
| 300 | if (pred(*prev, *current)) { |
| 301 | erase_after(prev); |
| 302 | current = prev; |
| 303 | } else { |
| 304 | prev = current; |
| 305 | } |
| 306 | } |
| 307 | } |
| 308 | } |
| 309 | void merge(IntrusiveForwardList& other) { |
| 310 | merge(other, std::less<value_type>()); |
| 311 | } |
| 312 | void merge(IntrusiveForwardList&& other) { |
| 313 | merge(other); // Use l-value overload. |
| 314 | } |
| 315 | template <typename Compare> |
| 316 | void merge(IntrusiveForwardList& other, Compare cmp) { |
| 317 | iterator prev = before_begin(); |
| 318 | iterator current = begin(); |
| 319 | iterator other_prev = other.before_begin(); |
| 320 | iterator other_current = other.begin(); |
| 321 | while (current != end() && other_current != other.end()) { |
| 322 | if (cmp(*other_current, *current)) { |
| 323 | ++other_current; |
| 324 | splice_after(prev, other, other_prev); |
| 325 | ++prev; |
| 326 | } else { |
| 327 | prev = current; |
| 328 | ++current; |
| 329 | } |
| 330 | DCHECK(++const_iterator(prev) == current); |
| 331 | DCHECK(++const_iterator(other_prev) == other_current); |
| 332 | } |
| 333 | splice_after(prev, other); |
| 334 | } |
| 335 | template <typename Compare> |
| 336 | void merge(IntrusiveForwardList&& other, Compare cmp) { |
| 337 | merge(other, cmp); // Use l-value overload. |
| 338 | } |
| 339 | void sort() { |
| 340 | sort(std::less<value_type>()); |
| 341 | } |
| 342 | template <typename Compare> |
| 343 | void sort(Compare cmp) { |
| 344 | size_t n = std::distance(begin(), end()); |
| 345 | if (n >= 2u) { |
| 346 | const_iterator middle = before_begin(); |
| 347 | std::advance(middle, n / 2u); |
| 348 | IntrusiveForwardList second_half; |
| 349 | second_half.splice_after(second_half.before_begin(), *this, middle, end()); |
| 350 | sort(cmp); |
| 351 | second_half.sort(cmp); |
| 352 | merge(second_half, cmp); |
| 353 | } |
| 354 | } |
| 355 | void reverse() { |
| 356 | IntrusiveForwardList reversed; |
| 357 | while (!empty()) { |
| 358 | value_type& value = front(); |
| 359 | erase_after(before_begin()); |
| 360 | reversed.insert_after(reversed.before_begin(), value); |
| 361 | } |
| 362 | reversed.swap(*this); |
| 363 | } |
| 364 | |
| 365 | // Extensions. |
| 366 | bool HasExactlyOneElement() const { |
| 367 | return !empty() && ++begin() == end(); |
| 368 | } |
| 369 | size_t SizeSlow() const { |
| 370 | return std::distance(begin(), end()); |
| 371 | } |
| 372 | bool ContainsNode(const_reference node) const { |
| 373 | for (auto&& n : *this) { |
| 374 | if (std::addressof(n) == std::addressof(node)) { |
| 375 | return true; |
| 376 | } |
| 377 | } |
| 378 | return false; |
| 379 | } |
| 380 | |
| 381 | private: |
| 382 | static IntrusiveForwardListHook* ModifiableHook(const IntrusiveForwardListHook* hook) { |
| 383 | return const_cast<IntrusiveForwardListHook*>(hook); |
| 384 | } |
| 385 | |
| 386 | IntrusiveForwardListHook first_; |
| 387 | }; |
| 388 | |
| 389 | template <typename T, typename HookTraits> |
| 390 | void swap(IntrusiveForwardList<T, HookTraits>& lhs, IntrusiveForwardList<T, HookTraits>& rhs) { |
| 391 | lhs.swap(rhs); |
| 392 | } |
| 393 | |
| 394 | template <typename T, typename HookTraits> |
| 395 | bool operator==(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 396 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 397 | auto lit = lhs.begin(); |
| 398 | auto rit = rhs.begin(); |
| 399 | for (; lit != lhs.end() && rit != rhs.end(); ++lit, ++rit) { |
| 400 | if (*lit != *rit) { |
| 401 | return false; |
| 402 | } |
| 403 | } |
| 404 | return lit == lhs.end() && rit == rhs.end(); |
| 405 | } |
| 406 | |
| 407 | template <typename T, typename HookTraits> |
| 408 | bool operator!=(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 409 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 410 | return !(lhs == rhs); |
| 411 | } |
| 412 | |
| 413 | template <typename T, typename HookTraits> |
| 414 | bool operator<(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 415 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 416 | return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); |
| 417 | } |
| 418 | |
| 419 | template <typename T, typename HookTraits> |
| 420 | bool operator>(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 421 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 422 | return rhs < lhs; |
| 423 | } |
| 424 | |
| 425 | template <typename T, typename HookTraits> |
| 426 | bool operator<=(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 427 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 428 | return !(rhs < lhs); |
| 429 | } |
| 430 | |
| 431 | template <typename T, typename HookTraits> |
| 432 | bool operator>=(const IntrusiveForwardList<T, HookTraits>& lhs, |
| 433 | const IntrusiveForwardList<T, HookTraits>& rhs) { |
| 434 | return !(lhs < rhs); |
| 435 | } |
| 436 | |
| 437 | template <typename T, IntrusiveForwardListHook T::* NextPtr> |
| 438 | class IntrusiveForwardListMemberHook { |
| 439 | public: |
| 440 | static const IntrusiveForwardListHook* GetHook(const T* value) { |
| 441 | return &(value->*NextPtr); |
| 442 | } |
| 443 | |
| 444 | static T* GetValue(const IntrusiveForwardListHook* hook) { |
| 445 | return reinterpret_cast<T*>( |
| 446 | reinterpret_cast<uintptr_t>(hook) - OFFSETOF_MEMBERPTR(T, NextPtr)); |
| 447 | } |
| 448 | }; |
| 449 | |
| 450 | } // namespace art |
| 451 | |
| 452 | #endif // ART_COMPILER_UTILS_INTRUSIVE_FORWARD_LIST_H_ |