14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_LINKED_HASH_TABLE_H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_LINKED_HASH_TABLE_H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_handle.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_symbol.h" 224514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_number.h" 234514f5e3Sopenharmony_ci#include "ecmascript/tagged_array-inl.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_cinamespace panda::ecmascript { 264514f5e3Sopenharmony_ciclass LinkedHash { 274514f5e3Sopenharmony_cipublic: 284514f5e3Sopenharmony_ci static int Hash(const JSThread *thread, JSTaggedValue key); 294514f5e3Sopenharmony_ci}; 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ci/** 324514f5e3Sopenharmony_ci * memory in LinkedHashTable is divided into 3 parts 334514f5e3Sopenharmony_ci * 1.array[0-2] is used to store common information of hashtale such as numberOfElements and capacity 344514f5e3Sopenharmony_ci * 2.array[3,3+capacity] is buckets which store the position of entry 354514f5e3Sopenharmony_ci * 3.array[3+capacity+1,3+capacity + capacity*(entry_size+1)] is the entry stored in order, the last element of an entry 364514f5e3Sopenharmony_ci * is a number which point to next entry. 374514f5e3Sopenharmony_ci * */ 384514f5e3Sopenharmony_citemplate<typename Derived, typename HashObject> 394514f5e3Sopenharmony_ciclass LinkedHashTable : public TaggedArray { 404514f5e3Sopenharmony_cipublic: 414514f5e3Sopenharmony_ci static const int MIN_CAPACITY = 4; 424514f5e3Sopenharmony_ci static const int NUMBER_OF_ELEMENTS_INDEX = 0; 434514f5e3Sopenharmony_ci static const int NUMBER_OF_DELETED_ELEMENTS_INDEX = 1; 444514f5e3Sopenharmony_ci static const int CAPACITY_INDEX = 2; 454514f5e3Sopenharmony_ci static const int NEXT_TABLE_INDEX = 3; 464514f5e3Sopenharmony_ci static const int ELEMENTS_START_INDEX = 4; 474514f5e3Sopenharmony_ci // Don't shrink a HashTable below this capacity. 484514f5e3Sopenharmony_ci static const int MIN_SHRINK_CAPACITY = 16; 494514f5e3Sopenharmony_ci 504514f5e3Sopenharmony_ci static JSHandle<Derived> Create(const JSThread *thread, int numberOfElements, MemSpaceKind spaceKind); 514514f5e3Sopenharmony_ci 524514f5e3Sopenharmony_ci static JSHandle<Derived> Insert(const JSThread *thread, const JSHandle<Derived> &table, 534514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ci static JSHandle<Derived> InsertWeakRef(const JSThread *thread, const JSHandle<Derived> &table, 564514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_ci static JSHandle<Derived> GrowCapacity(const JSThread *thread, const JSHandle<Derived> &table, 594514f5e3Sopenharmony_ci int numberOfAddedElements = 1); 604514f5e3Sopenharmony_ci 614514f5e3Sopenharmony_ci static JSHandle<Derived> Remove(const JSThread *thread, const JSHandle<Derived> &table, 624514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 634514f5e3Sopenharmony_ci 644514f5e3Sopenharmony_ci static JSHandle<Derived> Shrink(const JSThread *thread, const JSHandle<Derived> &table, int additionalCapacity = 0); 654514f5e3Sopenharmony_ci 664514f5e3Sopenharmony_ci static int GetLengthOfTable(int numberOfElements) 674514f5e3Sopenharmony_ci { 684514f5e3Sopenharmony_ci return ELEMENTS_START_INDEX + numberOfElements + numberOfElements * (HashObject::ENTRY_SIZE + 1); 694514f5e3Sopenharmony_ci } 704514f5e3Sopenharmony_ci 714514f5e3Sopenharmony_ci inline bool HasSufficientCapacity(int numOfAddElements) const 724514f5e3Sopenharmony_ci { 734514f5e3Sopenharmony_ci int numberOfElements = NumberOfElements(); 744514f5e3Sopenharmony_ci int numOfDelElements = NumberOfDeletedElements(); 754514f5e3Sopenharmony_ci int capacity = Capacity(); 764514f5e3Sopenharmony_ci int nof = numberOfElements + numOfAddElements; 774514f5e3Sopenharmony_ci // Return true if: 784514f5e3Sopenharmony_ci // 50% is still free after adding numOfAddElements elements and 794514f5e3Sopenharmony_ci // at most 50% of the free elements are deleted elements. 804514f5e3Sopenharmony_ci if ((nof < capacity) && ((numOfDelElements <= (capacity - nof) / 2))) { // 2: half 814514f5e3Sopenharmony_ci int neededFree = nof / 2; // 2: half 824514f5e3Sopenharmony_ci if (nof + neededFree <= capacity) { 834514f5e3Sopenharmony_ci return true; 844514f5e3Sopenharmony_ci } 854514f5e3Sopenharmony_ci } 864514f5e3Sopenharmony_ci return false; 874514f5e3Sopenharmony_ci } 884514f5e3Sopenharmony_ci 894514f5e3Sopenharmony_ci inline int FindElement(const JSThread *thread, JSTaggedValue key) const 904514f5e3Sopenharmony_ci { 914514f5e3Sopenharmony_ci if (!IsKey(key)) { 924514f5e3Sopenharmony_ci return -1; 934514f5e3Sopenharmony_ci } 944514f5e3Sopenharmony_ci int hash = LinkedHash::Hash(thread, key); 954514f5e3Sopenharmony_ci uint32_t bucket = HashToBucket(hash); 964514f5e3Sopenharmony_ci for (JSTaggedValue entry = GetElement(BucketToIndex(bucket)); !entry.IsHole(); 974514f5e3Sopenharmony_ci entry = GetNextEntry(entry.GetInt())) { 984514f5e3Sopenharmony_ci JSTaggedValue element = GetKey(entry.GetInt()); 994514f5e3Sopenharmony_ci if (element.IsHole()) { 1004514f5e3Sopenharmony_ci continue; 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci if (element.IsWeak()) { 1034514f5e3Sopenharmony_ci element.RemoveWeakTag(); 1044514f5e3Sopenharmony_ci } 1054514f5e3Sopenharmony_ci if (HashObject::IsMatch(key, element)) { 1064514f5e3Sopenharmony_ci return entry.GetInt(); 1074514f5e3Sopenharmony_ci } 1084514f5e3Sopenharmony_ci } 1094514f5e3Sopenharmony_ci return -1; 1104514f5e3Sopenharmony_ci } 1114514f5e3Sopenharmony_ci 1124514f5e3Sopenharmony_ci inline void RemoveEntry(const JSThread *thread, int entry) 1134514f5e3Sopenharmony_ci { 1144514f5e3Sopenharmony_ci ASSERT_PRINT(entry >= 0 && entry < Capacity(), "entry must be a non-negative integer less than capacity"); 1154514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)); 1164514f5e3Sopenharmony_ci for (int i = 0; i < HashObject::ENTRY_SIZE; i++) { 1174514f5e3Sopenharmony_ci SetElement(thread, index + i, JSTaggedValue::Hole()); 1184514f5e3Sopenharmony_ci } 1194514f5e3Sopenharmony_ci SetNumberOfElements(thread, NumberOfElements() - 1); 1204514f5e3Sopenharmony_ci SetNumberOfDeletedElements(thread, NumberOfDeletedElements() + 1); 1214514f5e3Sopenharmony_ci } 1224514f5e3Sopenharmony_ci 1234514f5e3Sopenharmony_ci inline static int ComputeCapacity(uint32_t atLeastSpaceFor) 1244514f5e3Sopenharmony_ci { 1254514f5e3Sopenharmony_ci // Add 50% slack to make slot collisions sufficiently unlikely. 1264514f5e3Sopenharmony_ci // See matching computation in HashTable::HasSufficientCapacity(). 1274514f5e3Sopenharmony_ci uint32_t rawCap = atLeastSpaceFor + (atLeastSpaceFor >> 1UL); 1284514f5e3Sopenharmony_ci int capacity = static_cast<int>(helpers::math::GetPowerOfTwoValue32(rawCap)); 1294514f5e3Sopenharmony_ci return (capacity > MIN_CAPACITY) ? capacity : MIN_CAPACITY; 1304514f5e3Sopenharmony_ci } 1314514f5e3Sopenharmony_ci 1324514f5e3Sopenharmony_ci inline static int ComputeCapacityWithShrink(int currentCapacity, int atLeastSpaceFor) 1334514f5e3Sopenharmony_ci { 1344514f5e3Sopenharmony_ci // Shrink to fit the number of elements if only a quarter of the 1354514f5e3Sopenharmony_ci // capacity is filled with elements. 1364514f5e3Sopenharmony_ci if (atLeastSpaceFor > (currentCapacity / 4)) { // 4: quarter 1374514f5e3Sopenharmony_ci return currentCapacity; 1384514f5e3Sopenharmony_ci } 1394514f5e3Sopenharmony_ci // Recalculate the smaller capacity actually needed. 1404514f5e3Sopenharmony_ci int newCapacity = ComputeCapacity(atLeastSpaceFor); 1414514f5e3Sopenharmony_ci ASSERT_PRINT(newCapacity > atLeastSpaceFor, "new capacity must greater than atLeastSpaceFor"); 1424514f5e3Sopenharmony_ci // Don't go lower than room for MIN_SHRINK_CAPACITY elements. 1434514f5e3Sopenharmony_ci if (newCapacity < Derived::MIN_SHRINK_CAPACITY) { 1444514f5e3Sopenharmony_ci return currentCapacity; 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci return newCapacity; 1474514f5e3Sopenharmony_ci } 1484514f5e3Sopenharmony_ci 1494514f5e3Sopenharmony_ci inline int NumberOfElements() const 1504514f5e3Sopenharmony_ci { 1514514f5e3Sopenharmony_ci return Get(NUMBER_OF_ELEMENTS_INDEX).GetInt(); 1524514f5e3Sopenharmony_ci } 1534514f5e3Sopenharmony_ci 1544514f5e3Sopenharmony_ci inline int NumberOfDeletedElements() const 1554514f5e3Sopenharmony_ci { 1564514f5e3Sopenharmony_ci return Get(NUMBER_OF_DELETED_ELEMENTS_INDEX).GetInt(); 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci 1594514f5e3Sopenharmony_ci inline int Capacity() const 1604514f5e3Sopenharmony_ci { 1614514f5e3Sopenharmony_ci return JSTaggedValue(Get(CAPACITY_INDEX)).GetInt(); 1624514f5e3Sopenharmony_ci } 1634514f5e3Sopenharmony_ci 1644514f5e3Sopenharmony_ci inline JSTaggedValue GetKey(int entry) const 1654514f5e3Sopenharmony_ci { 1664514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)); 1674514f5e3Sopenharmony_ci return GetElement(index); 1684514f5e3Sopenharmony_ci } 1694514f5e3Sopenharmony_ci 1704514f5e3Sopenharmony_ci inline JSTaggedValue GetValue(int entry) const 1714514f5e3Sopenharmony_ci { 1724514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)) + HashObject::ENTRY_VALUE_INDEX; 1734514f5e3Sopenharmony_ci return GetElement(index); 1744514f5e3Sopenharmony_ci } 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ci inline static bool IsKey(JSTaggedValue key) 1774514f5e3Sopenharmony_ci { 1784514f5e3Sopenharmony_ci return !key.IsHole(); 1794514f5e3Sopenharmony_ci } 1804514f5e3Sopenharmony_ci 1814514f5e3Sopenharmony_ci inline void SetNumberOfElements(const JSThread *thread, int nof) 1824514f5e3Sopenharmony_ci { 1834514f5e3Sopenharmony_ci Set(thread, NUMBER_OF_ELEMENTS_INDEX, JSTaggedValue(nof)); 1844514f5e3Sopenharmony_ci } 1854514f5e3Sopenharmony_ci 1864514f5e3Sopenharmony_ci inline void SetNumberOfDeletedElements(const JSThread *thread, int nod) 1874514f5e3Sopenharmony_ci { 1884514f5e3Sopenharmony_ci Set(thread, NUMBER_OF_DELETED_ELEMENTS_INDEX, JSTaggedValue(nod)); 1894514f5e3Sopenharmony_ci } 1904514f5e3Sopenharmony_ci 1914514f5e3Sopenharmony_ci inline void SetCapacity(const JSThread *thread, int capacity) 1924514f5e3Sopenharmony_ci { 1934514f5e3Sopenharmony_ci Set(thread, CAPACITY_INDEX, JSTaggedValue(capacity)); 1944514f5e3Sopenharmony_ci } 1954514f5e3Sopenharmony_ci 1964514f5e3Sopenharmony_ci inline JSTaggedValue GetNextTable() const 1974514f5e3Sopenharmony_ci { 1984514f5e3Sopenharmony_ci return JSTaggedValue(Get(NEXT_TABLE_INDEX)); 1994514f5e3Sopenharmony_ci } 2004514f5e3Sopenharmony_ci 2014514f5e3Sopenharmony_ci inline void SetNextTable(const JSThread *thread, JSTaggedValue nextTable) 2024514f5e3Sopenharmony_ci { 2034514f5e3Sopenharmony_ci Set(thread, NEXT_TABLE_INDEX, nextTable); 2044514f5e3Sopenharmony_ci } 2054514f5e3Sopenharmony_ci 2064514f5e3Sopenharmony_ci inline int GetDeletedElementsAt(int entry) const 2074514f5e3Sopenharmony_ci { 2084514f5e3Sopenharmony_ci ASSERT_PRINT(!GetNextTable().IsUndefined(), "function only execute after rehash"); 2094514f5e3Sopenharmony_ci int currentEntry = entry - 1; 2104514f5e3Sopenharmony_ci if (NumberOfDeletedElements() == -1) { 2114514f5e3Sopenharmony_ci return entry; 2124514f5e3Sopenharmony_ci } 2134514f5e3Sopenharmony_ci while (currentEntry >= 0) { 2144514f5e3Sopenharmony_ci if (GetKey(currentEntry).IsHole()) { 2154514f5e3Sopenharmony_ci return GetDeletedNum(currentEntry); 2164514f5e3Sopenharmony_ci } 2174514f5e3Sopenharmony_ci currentEntry--; 2184514f5e3Sopenharmony_ci } 2194514f5e3Sopenharmony_ci return 0; 2204514f5e3Sopenharmony_ci } 2214514f5e3Sopenharmony_ci 2224514f5e3Sopenharmony_ci inline void Rehash(const JSThread *thread, Derived *newTable) 2234514f5e3Sopenharmony_ci { 2244514f5e3Sopenharmony_ci ASSERT_PRINT(newTable != nullptr && newTable->Capacity() > NumberOfElements(), "can not rehash to new table"); 2254514f5e3Sopenharmony_ci // Rehash elements to new table 2264514f5e3Sopenharmony_ci int numberOfAllElements = NumberOfElements() + NumberOfDeletedElements(); 2274514f5e3Sopenharmony_ci int desEntry = 0; 2284514f5e3Sopenharmony_ci int currentDeletedElements = 0; 2294514f5e3Sopenharmony_ci SetNextTable(thread, JSTaggedValue(newTable)); 2304514f5e3Sopenharmony_ci for (int i = 0; i < numberOfAllElements; i++) { 2314514f5e3Sopenharmony_ci int fromIndex = static_cast<int>(EntryToIndex(i)); 2324514f5e3Sopenharmony_ci JSTaggedValue key = GetElement(fromIndex); 2334514f5e3Sopenharmony_ci if (key.IsHole()) { 2344514f5e3Sopenharmony_ci // store num_of_deleted_element before entry i; it will be used when iterator update. 2354514f5e3Sopenharmony_ci currentDeletedElements++; 2364514f5e3Sopenharmony_ci SetDeletedNum(thread, i, JSTaggedValue(currentDeletedElements)); 2374514f5e3Sopenharmony_ci continue; 2384514f5e3Sopenharmony_ci } 2394514f5e3Sopenharmony_ci 2404514f5e3Sopenharmony_ci if (key.IsWeak()) { 2414514f5e3Sopenharmony_ci // If the key is a weak reference, we use the weak referent to calculate the new index in the new table. 2424514f5e3Sopenharmony_ci key.RemoveWeakTag(); 2434514f5e3Sopenharmony_ci } 2444514f5e3Sopenharmony_ci 2454514f5e3Sopenharmony_ci int bucket = static_cast<int>(newTable->HashToBucket(LinkedHash::Hash(thread, key))); 2464514f5e3Sopenharmony_ci newTable->InsertNewEntry(thread, bucket, desEntry); 2474514f5e3Sopenharmony_ci int desIndex = static_cast<int>(newTable->EntryToIndex(desEntry)); 2484514f5e3Sopenharmony_ci for (int j = 0; j < HashObject::ENTRY_SIZE; j++) { 2494514f5e3Sopenharmony_ci newTable->SetElement(thread, desIndex + j, GetElement(fromIndex + j)); 2504514f5e3Sopenharmony_ci } 2514514f5e3Sopenharmony_ci desEntry++; 2524514f5e3Sopenharmony_ci } 2534514f5e3Sopenharmony_ci newTable->SetNumberOfElements(thread, NumberOfElements()); 2544514f5e3Sopenharmony_ci newTable->SetNumberOfDeletedElements(thread, 0); 2554514f5e3Sopenharmony_ci } 2564514f5e3Sopenharmony_ci 2574514f5e3Sopenharmony_ciprotected: 2584514f5e3Sopenharmony_ci inline JSTaggedValue GetElement(int index) const 2594514f5e3Sopenharmony_ci { 2604514f5e3Sopenharmony_ci ASSERT(index >= 0 && index < static_cast<int>(GetLength())); 2614514f5e3Sopenharmony_ci return Get(index); 2624514f5e3Sopenharmony_ci } 2634514f5e3Sopenharmony_ci 2644514f5e3Sopenharmony_ci inline void SetElement(const JSThread *thread, int index, JSTaggedValue element) 2654514f5e3Sopenharmony_ci { 2664514f5e3Sopenharmony_ci ASSERT(index >= 0 && index < static_cast<int>(GetLength())); 2674514f5e3Sopenharmony_ci Set(thread, index, element); 2684514f5e3Sopenharmony_ci } 2694514f5e3Sopenharmony_ci 2704514f5e3Sopenharmony_ci inline void SetKey(const JSThread *thread, int entry, JSTaggedValue key) 2714514f5e3Sopenharmony_ci { 2724514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)); 2734514f5e3Sopenharmony_ci SetElement(thread, index, key); 2744514f5e3Sopenharmony_ci } 2754514f5e3Sopenharmony_ci 2764514f5e3Sopenharmony_ci inline void SetValue(const JSThread *thread, int entry, JSTaggedValue value) 2774514f5e3Sopenharmony_ci { 2784514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)) + HashObject::ENTRY_VALUE_INDEX; 2794514f5e3Sopenharmony_ci SetElement(thread, index, value); 2804514f5e3Sopenharmony_ci } 2814514f5e3Sopenharmony_ci 2824514f5e3Sopenharmony_ci inline JSTaggedValue GetNextEntry(int entry) const 2834514f5e3Sopenharmony_ci { 2844514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)) + HashObject::ENTRY_SIZE; 2854514f5e3Sopenharmony_ci return GetElement(index); 2864514f5e3Sopenharmony_ci } 2874514f5e3Sopenharmony_ci 2884514f5e3Sopenharmony_ci inline void SetNextEntry(const JSThread *thread, int entry, JSTaggedValue nextEntry) 2894514f5e3Sopenharmony_ci { 2904514f5e3Sopenharmony_ci int index = static_cast<int>(EntryToIndex(entry)) + HashObject::ENTRY_SIZE; 2914514f5e3Sopenharmony_ci SetElement(thread, index, nextEntry); 2924514f5e3Sopenharmony_ci } 2934514f5e3Sopenharmony_ci 2944514f5e3Sopenharmony_ci inline uint32_t HashToBucket(uint32_t hash) const 2954514f5e3Sopenharmony_ci { 2964514f5e3Sopenharmony_ci return hash & static_cast<uint32_t>(Capacity() - 1); 2974514f5e3Sopenharmony_ci } 2984514f5e3Sopenharmony_ci 2994514f5e3Sopenharmony_ci inline static uint32_t BucketToIndex(uint32_t bucket) 3004514f5e3Sopenharmony_ci { 3014514f5e3Sopenharmony_ci return bucket + ELEMENTS_START_INDEX; 3024514f5e3Sopenharmony_ci } 3034514f5e3Sopenharmony_ci 3044514f5e3Sopenharmony_ci // min entry = 0 3054514f5e3Sopenharmony_ci inline uint32_t EntryToIndex(uint32_t entry) const 3064514f5e3Sopenharmony_ci { 3074514f5e3Sopenharmony_ci return ELEMENTS_START_INDEX + Capacity() + static_cast<int>(entry) * (HashObject::ENTRY_SIZE + 1); 3084514f5e3Sopenharmony_ci } 3094514f5e3Sopenharmony_ci 3104514f5e3Sopenharmony_ci inline void InsertNewEntry(const JSThread *thread, int bucket, int entry) 3114514f5e3Sopenharmony_ci { 3124514f5e3Sopenharmony_ci int bucketIndex = static_cast<int>(BucketToIndex(bucket)); 3134514f5e3Sopenharmony_ci JSTaggedValue previousEntry = GetElement(bucketIndex); 3144514f5e3Sopenharmony_ci SetNextEntry(thread, entry, previousEntry); 3154514f5e3Sopenharmony_ci SetElement(thread, bucketIndex, JSTaggedValue(entry)); 3164514f5e3Sopenharmony_ci } 3174514f5e3Sopenharmony_ci 3184514f5e3Sopenharmony_ci inline int GetDeletedNum(int entry) const 3194514f5e3Sopenharmony_ci { 3204514f5e3Sopenharmony_ci ASSERT_PRINT(!GetNextTable().IsUndefined(), "function only execute after rehash"); 3214514f5e3Sopenharmony_ci return GetNextEntry(entry).GetInt(); 3224514f5e3Sopenharmony_ci } 3234514f5e3Sopenharmony_ci 3244514f5e3Sopenharmony_ci inline void SetDeletedNum(const JSThread *thread, int entry, JSTaggedValue num) 3254514f5e3Sopenharmony_ci { 3264514f5e3Sopenharmony_ci ASSERT_PRINT(!GetNextTable().IsUndefined(), "function only execute after rehash"); 3274514f5e3Sopenharmony_ci SetNextEntry(thread, entry, num); 3284514f5e3Sopenharmony_ci } 3294514f5e3Sopenharmony_ci}; 3304514f5e3Sopenharmony_ci 3314514f5e3Sopenharmony_ciclass LinkedHashMapObject { 3324514f5e3Sopenharmony_cipublic: 3334514f5e3Sopenharmony_ci // key must be string now for other object has no 'equals' method 3344514f5e3Sopenharmony_ci static inline bool IsMatch(JSTaggedValue key, JSTaggedValue other) 3354514f5e3Sopenharmony_ci { 3364514f5e3Sopenharmony_ci return JSTaggedValue::SameValueZero(key, other); 3374514f5e3Sopenharmony_ci } 3384514f5e3Sopenharmony_ci 3394514f5e3Sopenharmony_ci static const int ENTRY_SIZE = 2; 3404514f5e3Sopenharmony_ci static const int ENTRY_VALUE_INDEX = 1; 3414514f5e3Sopenharmony_ci}; 3424514f5e3Sopenharmony_ci 3434514f5e3Sopenharmony_ciclass LinkedHashMap : public LinkedHashTable<LinkedHashMap, LinkedHashMapObject> { 3444514f5e3Sopenharmony_cipublic: 3454514f5e3Sopenharmony_ci static LinkedHashMap *Cast(TaggedObject *obj) 3464514f5e3Sopenharmony_ci { 3474514f5e3Sopenharmony_ci return static_cast<LinkedHashMap *>(obj); 3484514f5e3Sopenharmony_ci } 3494514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> PUBLIC_API Create(const JSThread *thread, int numberOfElements = MIN_CAPACITY, 3504514f5e3Sopenharmony_ci MemSpaceKind spaceKind = MemSpaceKind::LOCAL); 3514514f5e3Sopenharmony_ci 3524514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> Delete(const JSThread *thread, const JSHandle<LinkedHashMap> &obj, 3534514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 3544514f5e3Sopenharmony_ci 3554514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> Set(const JSThread *thread, const JSHandle<LinkedHashMap> &obj, 3564514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 3574514f5e3Sopenharmony_ci 3584514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> SetWeakRef(const JSThread *thread, const JSHandle<LinkedHashMap> &obj, 3594514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 3604514f5e3Sopenharmony_ci 3614514f5e3Sopenharmony_ci JSTaggedValue Get(const JSThread *thread, JSTaggedValue key) const; 3624514f5e3Sopenharmony_ci 3634514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> Shrink(const JSThread *thread, const JSHandle<LinkedHashMap> &table, 3644514f5e3Sopenharmony_ci int additionalCapacity = 0); 3654514f5e3Sopenharmony_ci 3664514f5e3Sopenharmony_ci bool Has(const JSThread *thread, JSTaggedValue key) const; 3674514f5e3Sopenharmony_ci 3684514f5e3Sopenharmony_ci static JSHandle<LinkedHashMap> Clear(const JSThread *thread, const JSHandle<LinkedHashMap> &table); 3694514f5e3Sopenharmony_ci DECL_DUMP() 3704514f5e3Sopenharmony_ci}; 3714514f5e3Sopenharmony_ci 3724514f5e3Sopenharmony_ciclass LinkedHashSetObject { 3734514f5e3Sopenharmony_cipublic: 3744514f5e3Sopenharmony_ci // key must be string now for other object has no 'equals' method 3754514f5e3Sopenharmony_ci static inline bool IsMatch(JSTaggedValue key, JSTaggedValue other) 3764514f5e3Sopenharmony_ci { 3774514f5e3Sopenharmony_ci return JSTaggedValue::SameValueZero(key, other); 3784514f5e3Sopenharmony_ci } 3794514f5e3Sopenharmony_ci 3804514f5e3Sopenharmony_ci static const int ENTRY_SIZE = 1; 3814514f5e3Sopenharmony_ci static const int ENTRY_VALUE_INDEX = 0; 3824514f5e3Sopenharmony_ci}; 3834514f5e3Sopenharmony_ci 3844514f5e3Sopenharmony_ciclass LinkedHashSet : public LinkedHashTable<LinkedHashSet, LinkedHashSetObject> { 3854514f5e3Sopenharmony_cipublic: 3864514f5e3Sopenharmony_ci static LinkedHashSet *Cast(TaggedObject *obj) 3874514f5e3Sopenharmony_ci { 3884514f5e3Sopenharmony_ci return static_cast<LinkedHashSet *>(obj); 3894514f5e3Sopenharmony_ci } 3904514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> Create(const JSThread *thread, int numberOfElements = MIN_CAPACITY, 3914514f5e3Sopenharmony_ci MemSpaceKind spaceKind = MemSpaceKind::LOCAL); 3924514f5e3Sopenharmony_ci 3934514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> Delete(const JSThread *thread, const JSHandle<LinkedHashSet> &obj, 3944514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 3954514f5e3Sopenharmony_ci 3964514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> Add(const JSThread *thread, const JSHandle<LinkedHashSet> &obj, 3974514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 3984514f5e3Sopenharmony_ci 3994514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> AddWeakRef(const JSThread *thread, const JSHandle<LinkedHashSet> &obj, 4004514f5e3Sopenharmony_ci const JSHandle<JSTaggedValue> &key); 4014514f5e3Sopenharmony_ci 4024514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> Shrink(const JSThread *thread, const JSHandle<LinkedHashSet> &table, 4034514f5e3Sopenharmony_ci int additionalCapacity = 0); 4044514f5e3Sopenharmony_ci 4054514f5e3Sopenharmony_ci bool Has(const JSThread *thread, JSTaggedValue key) const; 4064514f5e3Sopenharmony_ci 4074514f5e3Sopenharmony_ci static JSHandle<LinkedHashSet> Clear(const JSThread *thread, const JSHandle<LinkedHashSet> &table); 4084514f5e3Sopenharmony_ci DECL_DUMP() 4094514f5e3Sopenharmony_ci}; 4104514f5e3Sopenharmony_ci} // namespace panda::ecmascript 4114514f5e3Sopenharmony_ci#endif // ECMASCRIPT_LINKED_HASH_TABLE_H 412