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_SYMBOL_TABLE_H
17#define ECMASCRIPT_SYMBOL_TABLE_H
18
19#include "ecmascript/ecma_string.h"
20#include "ecmascript/ecma_vm.h"
21#include "ecmascript/js_symbol.h"
22#include "ecmascript/js_thread.h"
23#include "ecmascript/object_factory.h"
24#include "ecmascript/tagged_hash_table.h"
25
26namespace panda::ecmascript {
27class SymbolTable : public TaggedHashTable<SymbolTable> {
28public:
29    using HashTable = TaggedHashTable<SymbolTable>;
30    static SymbolTable *Cast(TaggedObject *object)
31    {
32        return reinterpret_cast<SymbolTable *>(object);
33    }
34    inline static int GetKeyIndex(int entry)
35    {
36        return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_KEY_INDEX;
37    }
38    inline static int GetValueIndex(int entry)
39    {
40        return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize() + ENTRY_VALUE_INDEX;
41    }
42    inline static int GetEntryIndex(int entry)
43    {
44        return HashTable::TABLE_HEADER_SIZE + entry * GetEntrySize();
45    }
46    inline static int GetEntrySize()
47    {
48        return ENTRY_SIZE;
49    }
50    static inline bool IsMatch(const JSTaggedValue &name, const JSTaggedValue &other)
51    {
52        if (name.IsHole() || name.IsUndefined()) {
53            return false;
54        }
55
56        auto *nameString = static_cast<EcmaString *>(name.GetTaggedObject());
57        auto *otherString = static_cast<EcmaString *>(other.GetTaggedObject());
58        return EcmaStringAccessor::StringsAreEqual(nameString, otherString);
59    }
60    static inline uint32_t Hash(const JSTaggedValue &obj)
61    {
62        if (obj.IsHeapObject()) {
63            if (obj.IsString()) {
64                auto *nameString = static_cast<EcmaString *>(obj.GetTaggedObject());
65                return EcmaStringAccessor(nameString).GetHashcode();
66            }
67            return JSSymbol::ComputeHash();
68        }
69        LOG_ECMA(FATAL) << "this branch is unreachable";
70        UNREACHABLE();
71    }
72
73    static const int DEFAULT_ELEMENTS_NUMBER = 64;
74    static JSHandle<SymbolTable> Create(JSThread *thread, int numberOfElements = DEFAULT_ELEMENTS_NUMBER)
75    {
76        return HashTable::Create(thread, numberOfElements);
77    }
78
79    inline bool ContainsKey(const JSTaggedValue &key)
80    {
81        int entry = FindEntry(key);
82        return entry != -1;
83    }
84
85    inline JSTaggedValue GetSymbol(const JSTaggedValue &key)
86    {
87        int entry = FindEntry(key);
88        ASSERT(entry != -1);
89        return GetValue(entry);
90    }
91
92    inline JSTaggedValue FindSymbol(const JSTaggedValue &value)
93    {
94        JSSymbol *symbol = JSSymbol::Cast(value.GetTaggedObject());
95        JSTaggedValue des = symbol->GetDescription();
96        if (!des.IsUndefined()) {
97            if (ContainsKey(des)) {
98                return des;
99            }
100        }
101        return JSTaggedValue::Undefined();
102    }
103    static int ComputeCompactSize([[maybe_unused]] const JSHandle<SymbolTable> &table, int computeHashTableSize,
104        [[maybe_unused]] int tableSize, [[maybe_unused]] int addedElements)
105    {
106        return computeHashTableSize;
107    }
108    static constexpr int ENTRY_KEY_INDEX = 0;
109    static constexpr int ENTRY_VALUE_INDEX = 1;
110    static constexpr int ENTRY_SIZE = 2;
111};
112}  // namespace panda::ecmascript
113#endif  // ECMASCRIPT_SYMBOL_TABLE_H