blob: 2345f1d360539fe88561b67270943a7b8598f535 [file] [log] [blame]
// 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_