// 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 "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);
|
}
|
|
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_ = new (zone) 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; }
|
|
class iterator {
|
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); }
|
|
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_
|