11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_COMPILER_FUNCTIONAL_LIST_H_
61cb0ef41Sopenharmony_ci#define V8_COMPILER_FUNCTIONAL_LIST_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/iterator.h"
91cb0ef41Sopenharmony_ci#include "src/zone/zone.h"
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cinamespace v8 {
121cb0ef41Sopenharmony_cinamespace internal {
131cb0ef41Sopenharmony_cinamespace compiler {
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_ci// A generic stack implemented with a singly-linked list, which results in an
161cb0ef41Sopenharmony_ci// O(1) copy operation. It can be used to model immutable lists like those in
171cb0ef41Sopenharmony_ci// functional languages. Compared to typical functional lists, this also caches
181cb0ef41Sopenharmony_ci// the length of the list in each node.
191cb0ef41Sopenharmony_ci// Note: The underlying implementation is mutable, so if you want to use this as
201cb0ef41Sopenharmony_ci// an immutable list, make sure to create a copy by passing it by value and
211cb0ef41Sopenharmony_ci// operate on the copy.
221cb0ef41Sopenharmony_ci// TODO(turbofan): Use this implementation also for RedundancyElimination.
231cb0ef41Sopenharmony_citemplate <class A>
241cb0ef41Sopenharmony_ciclass FunctionalList {
251cb0ef41Sopenharmony_ci private:
261cb0ef41Sopenharmony_ci  struct Cons : ZoneObject {
271cb0ef41Sopenharmony_ci    Cons(A top, Cons* rest)
281cb0ef41Sopenharmony_ci        : top(std::move(top)), rest(rest), size(1 + (rest ? rest->size : 0)) {}
291cb0ef41Sopenharmony_ci    A const top;
301cb0ef41Sopenharmony_ci    Cons* const rest;
311cb0ef41Sopenharmony_ci    size_t const size;
321cb0ef41Sopenharmony_ci  };
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci public:
351cb0ef41Sopenharmony_ci  FunctionalList() : elements_(nullptr) {}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  bool operator==(const FunctionalList<A>& other) const {
381cb0ef41Sopenharmony_ci    if (Size() != other.Size()) return false;
391cb0ef41Sopenharmony_ci    iterator it = begin();
401cb0ef41Sopenharmony_ci    iterator other_it = other.begin();
411cb0ef41Sopenharmony_ci    while (true) {
421cb0ef41Sopenharmony_ci      if (it == other_it) return true;
431cb0ef41Sopenharmony_ci      if (*it != *other_it) return false;
441cb0ef41Sopenharmony_ci      ++it;
451cb0ef41Sopenharmony_ci      ++other_it;
461cb0ef41Sopenharmony_ci    }
471cb0ef41Sopenharmony_ci  }
481cb0ef41Sopenharmony_ci  bool operator!=(const FunctionalList<A>& other) const {
491cb0ef41Sopenharmony_ci    return !(*this == other);
501cb0ef41Sopenharmony_ci  }
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ci  bool TriviallyEquals(const FunctionalList<A>& other) const {
531cb0ef41Sopenharmony_ci    return elements_ == other.elements_;
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci  const A& Front() const {
571cb0ef41Sopenharmony_ci    DCHECK_GT(Size(), 0);
581cb0ef41Sopenharmony_ci    return elements_->top;
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  FunctionalList Rest() const {
621cb0ef41Sopenharmony_ci    FunctionalList result = *this;
631cb0ef41Sopenharmony_ci    result.DropFront();
641cb0ef41Sopenharmony_ci    return result;
651cb0ef41Sopenharmony_ci  }
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  void DropFront() {
681cb0ef41Sopenharmony_ci    CHECK_GT(Size(), 0);
691cb0ef41Sopenharmony_ci    elements_ = elements_->rest;
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  void PushFront(A a, Zone* zone) {
731cb0ef41Sopenharmony_ci    elements_ = zone->New<Cons>(std::move(a), elements_);
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  // If {hint} happens to be exactly what we want to allocate, avoid allocation
771cb0ef41Sopenharmony_ci  // by reusing {hint}.
781cb0ef41Sopenharmony_ci  void PushFront(A a, Zone* zone, FunctionalList hint) {
791cb0ef41Sopenharmony_ci    if (hint.Size() == Size() + 1 && hint.Front() == a &&
801cb0ef41Sopenharmony_ci        hint.Rest() == *this) {
811cb0ef41Sopenharmony_ci      *this = hint;
821cb0ef41Sopenharmony_ci    } else {
831cb0ef41Sopenharmony_ci      PushFront(a, zone);
841cb0ef41Sopenharmony_ci    }
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci  // Drop elements until the current stack is equal to the tail shared with
881cb0ef41Sopenharmony_ci  // {other}. The shared tail must not only be equal, but also refer to the
891cb0ef41Sopenharmony_ci  // same memory.
901cb0ef41Sopenharmony_ci  void ResetToCommonAncestor(FunctionalList other) {
911cb0ef41Sopenharmony_ci    while (other.Size() > Size()) other.DropFront();
921cb0ef41Sopenharmony_ci    while (other.Size() < Size()) DropFront();
931cb0ef41Sopenharmony_ci    while (elements_ != other.elements_) {
941cb0ef41Sopenharmony_ci      DropFront();
951cb0ef41Sopenharmony_ci      other.DropFront();
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  size_t Size() const { return elements_ ? elements_->size : 0; }
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ci  void Clear() { elements_ = nullptr; }
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci  class iterator : public base::iterator<std::forward_iterator_tag, A> {
1041cb0ef41Sopenharmony_ci   public:
1051cb0ef41Sopenharmony_ci    explicit iterator(Cons* cur) : current_(cur) {}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci    const A& operator*() const { return current_->top; }
1081cb0ef41Sopenharmony_ci    iterator& operator++() {
1091cb0ef41Sopenharmony_ci      current_ = current_->rest;
1101cb0ef41Sopenharmony_ci      return *this;
1111cb0ef41Sopenharmony_ci    }
1121cb0ef41Sopenharmony_ci    bool operator==(const iterator& other) const {
1131cb0ef41Sopenharmony_ci      return this->current_ == other.current_;
1141cb0ef41Sopenharmony_ci    }
1151cb0ef41Sopenharmony_ci    bool operator!=(const iterator& other) const { return !(*this == other); }
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci   private:
1181cb0ef41Sopenharmony_ci    Cons* current_;
1191cb0ef41Sopenharmony_ci  };
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  iterator begin() const { return iterator(elements_); }
1221cb0ef41Sopenharmony_ci  iterator end() const { return iterator(nullptr); }
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci private:
1251cb0ef41Sopenharmony_ci  Cons* elements_;
1261cb0ef41Sopenharmony_ci};
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci}  // namespace compiler
1291cb0ef41Sopenharmony_ci}  // namespace internal
1301cb0ef41Sopenharmony_ci}  // namespace v8
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci#endif  // V8_COMPILER_FUNCTIONAL_LIST_H_
133