1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_MEM_ECMALIST_H
17#define ECMASCRIPT_MEM_ECMALIST_H
18
19#include "ecmascript/mem/mem.h"
20
21namespace panda::ecmascript {
22//  Invoking std::list will cause cross invoking, which is time-consuming.
23//  Therefore, we implement ecma list inside the vm.
24
25template<class T>
26class EcmaList {
27public:
28    EcmaList() : first_(nullptr), last_(nullptr) {}
29
30    explicit EcmaList(T *node) : first_(node), last_(node)
31    {
32        node->LinkPrev(nullptr);
33        node->LinkNext(nullptr);
34    }
35    ~EcmaList() = default;
36    NO_COPY_SEMANTIC(EcmaList);
37    NO_MOVE_SEMANTIC(EcmaList);
38    void AddNode(T *node)
39    {
40        ASSERT(node != nullptr);
41        if (LIKELY(first_ != nullptr)) {
42            T *lastNext = last_->GetNext();
43            node->LinkNext(lastNext);
44            node->LinkPrev(last_);
45            last_->LinkNext(node);
46            if (lastNext) {
47                lastNext->LinkPrev(node);
48            } else {
49                last_ = node;
50            }
51        } else {
52            node->LinkPrev(nullptr);
53            node->LinkNext(nullptr);
54            first_ = last_ = node;
55        }
56        length_++;
57    }
58
59    void AddNodeToFront(T *node)
60    {
61        ASSERT(node != nullptr);
62        if (LIKELY(last_ != nullptr)) {
63            node->LinkNext(first_);
64            node->LinkPrev(first_->GetPrev());
65            first_->LinkPrev(node);
66            first_ = node;
67        } else {
68            node->LinkPrev(nullptr);
69            node->LinkNext(nullptr);
70            first_ = last_ = node;
71        }
72        length_++;
73    }
74
75    T *PopBack()
76    {
77        T *node = last_;
78        RemoveNode(last_);
79        return node;
80    }
81
82    void RemoveNode(T *node)
83    {
84        ASSERT(HasNode(node));
85        if (last_ == node) {
86            // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
87            last_ = node->GetPrev();
88        }
89        if (first_ == node) {
90            // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
91            first_ = node->GetNext();
92        }
93        // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
94        T *next = node->GetNext();
95        // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
96        T *prev = node->GetPrev();
97        if (next != nullptr) {
98            next->LinkPrev(prev);
99        }
100        if (prev != nullptr) {
101            prev->LinkNext(next);
102        }
103        // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
104        node->LinkPrev(nullptr);
105        // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
106        node->LinkNext(nullptr);
107        length_--;
108    }
109
110    bool HasNode(T *node)
111    {
112        T *it = first_;
113        while (it != nullptr) {
114            if (it == node) {
115                return true;
116            }
117            it = it->GetNext();
118        }
119        return false;
120    }
121
122    T *GetFirst() const
123    {
124        return first_;
125    }
126
127    T *GetLast() const
128    {
129        return last_;
130    }
131
132    bool IsEmpty() const
133    {
134        return last_ == nullptr;
135    }
136
137    void Clear()
138    {
139        first_ = last_ = nullptr;
140        length_ = 0;
141    }
142
143    uint32_t GetLength() const
144    {
145        return length_;
146    }
147
148private:
149    T *first_;
150    T *last_;
151    uint32_t length_{0};
152};
153}  // namespace panda::ecmascript
154
155#endif  // ECMASCRIPT_MEM_ECMALIST_H
156