| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_COMPILER_FUNCTIONAL_LIST_H_ |
| #define V8_COMPILER_FUNCTIONAL_LIST_H_ |
| |
| #include <iterator> |
| #include "src/zone/zone.h" |
| |
| namespace v8 { |
| namespace internal { |
| namespace compiler { |
| |
| // A generic stack implemented as a purely functional singly-linked list, which |
| // results in an O(1) copy operation. It is the equivalent of functional lists |
| // in ML-like languages, with the only difference that it also caches the length |
| // of the list in each node. |
| // TODO(tebbi): Use this implementation also for RedundancyElimination. |
| template <class A> |
| class FunctionalList { |
| private: |
| struct Cons : ZoneObject { |
| Cons(A top, Cons* rest) |
| : top(std::move(top)), rest(rest), size(1 + (rest ? rest->size : 0)) {} |
| A const top; |
| Cons* const rest; |
| size_t const size; |
| }; |
| |
| public: |
| FunctionalList() : elements_(nullptr) {} |
| |
| bool operator==(const FunctionalList<A>& other) const { |
| if (Size() != other.Size()) return false; |
| iterator it = begin(); |
| iterator other_it = other.begin(); |
| while (true) { |
| if (it == other_it) return true; |
| if (*it != *other_it) return false; |
| ++it; |
| ++other_it; |
| } |
| } |
| bool operator!=(const FunctionalList<A>& other) const { |
| return !(*this == other); |
| } |
| |
| bool TriviallyEquals(const FunctionalList<A>& other) const { |
| return elements_ == other.elements_; |
| } |
| |
| const A& Front() const { |
| DCHECK_GT(Size(), 0); |
| return elements_->top; |
| } |
| |
| FunctionalList Rest() const { |
| FunctionalList result = *this; |
| result.DropFront(); |
| return result; |
| } |
| |
| void DropFront() { |
| CHECK_GT(Size(), 0); |
| elements_ = elements_->rest; |
| } |
| |
| void PushFront(A a, Zone* zone) { |
| elements_ = zone->New<Cons>(std::move(a), elements_); |
| } |
| |
| // If {hint} happens to be exactly what we want to allocate, avoid allocation |
| // by reusing {hint}. |
| void PushFront(A a, Zone* zone, FunctionalList hint) { |
| if (hint.Size() == Size() + 1 && hint.Front() == a && |
| hint.Rest() == *this) { |
| *this = hint; |
| } else { |
| PushFront(a, zone); |
| } |
| } |
| |
| // Drop elements until the current stack is equal to the tail shared with |
| // {other}. The shared tail must not only be equal, but also refer to the |
| // same memory. |
| void ResetToCommonAncestor(FunctionalList other) { |
| while (other.Size() > Size()) other.DropFront(); |
| while (other.Size() < Size()) DropFront(); |
| while (elements_ != other.elements_) { |
| DropFront(); |
| other.DropFront(); |
| } |
| } |
| |
| size_t Size() const { return elements_ ? elements_->size : 0; } |
| |
| void Clear() { elements_ = nullptr; } |
| |
| class iterator : public std::iterator<std::forward_iterator_tag, A> { |
| public: |
| explicit iterator(Cons* cur) : current_(cur) {} |
| |
| const A& operator*() const { return current_->top; } |
| iterator& operator++() { |
| current_ = current_->rest; |
| return *this; |
| } |
| bool operator==(const iterator& other) const { |
| return this->current_ == other.current_; |
| } |
| bool operator!=(const iterator& other) const { return !(*this == other); } |
| |
| // Implemented so that std::find and friends can use std::iterator_traits |
| // for this iterator type. |
| typedef std::forward_iterator_tag iterator_category; |
| typedef ptrdiff_t difference_type; |
| typedef A value_type; |
| typedef A* pointer; |
| typedef A& reference; |
| |
| private: |
| Cons* current_; |
| }; |
| |
| iterator begin() const { return iterator(elements_); } |
| iterator end() const { return iterator(nullptr); } |
| |
| private: |
| Cons* elements_; |
| }; |
| |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_COMPILER_FUNCTIONAL_LIST_H_ |