//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- #pragma once namespace JsUtil { namespace { template struct ChooseSmallerHelper { typedef T2 type; }; template struct ChooseSmallerHelper { typedef T1 type; }; template using ChooseSmaller = typename ChooseSmallerHelper::type; template class ValueEntryData { protected: TValue value; // data of entry public: int next; // Index of next entry, -1 if last }; template class KeyValueEntryDataLayout1 { protected: TValue value; // data of entry TKey key; // key of entry public: int next; // Index of next entry, -1 if last }; template class KeyValueEntryDataLayout2 { protected: TValue value; // data of entry public: int next; // Index of next entry, -1 if last protected: TKey key; // key of entry }; // Packing matters because we make so many dictionary entries. // The int pointing to the next item in the list may be included // either after the value or after the key, depending on which // packs better. template using KeyValueEntryData = ChooseSmaller, KeyValueEntryDataLayout2>; template > class ValueEntry : public TData { protected: void Set(TValue const& value) { this->value = value; } public: static bool SupportsCleanup() { return false; } static bool NeedsCleanup(ValueEntry&) { return false; } void Clear() { ClearValue::Clear(&this->value); } TValue const& Value() const { return this->value; } TValue& Value() { return this->value; } void SetValue(TValue const& value) { this->value = value; } }; // Used by BaseHashSet, the default is that the key is the same as the value template class ImplicitKeyValueEntry : public ValueEntry { public: TKey Key() const { return ValueToKey::ToKey(this->value); } void Set(TKey const& key, TValue const& value) { __super::Set(value); } }; template class KeyValueEntry : public ValueEntry> { protected: void Set(TKey const& key, TValue const& value) { __super::Set(value); this->key = key; } public: TKey const& Key() const { return this->key; } void Clear() { __super::Clear(); this->key = TKey(); } }; } template struct ValueToKey { static TKey ToKey(const TValue &value) { return static_cast(value); } }; template struct ClearValue { static inline void Clear(TValue* value) { *value = TValue(); } }; template class KeyEntry : public ValueEntry { public: TKey const& Key() const { return this->value; } }; template class THashEntry> class DefaultHashedEntry : public THashEntry { public: template inline bool KeyEquals(TLookup const& otherKey, hash_t otherHashCode) { return Comparer::Equals(this->Key(), otherKey); } template inline hash_t GetHashCode() { return ((Comparer::GetHashCode(this->Key()) & 0x7fffffff) << 1) | 1; } void Set(TKey const& key, TValue const& value, int hashCode) { __super::Set(key, value); } }; template class THashKeyEntry> class DefaultHashedKeyEntry : public THashKeyEntry { public: template inline bool KeyEquals(TLookup const& otherKey, hash_t otherHashCode) { return Comparer::Equals(this->Key(), otherKey); } template inline hash_t GetHashCode() { return ((Comparer::GetHashCode(this->Key()) & 0x7fffffff) << 1) | 1; } void Set(TKey const& key, int hashCode) { __super::Set(key); } }; template class THashEntry> class CacheHashedEntry : public THashEntry { hash_t hashCode; // Lower 31 bits of hash code << 1 | 1, 0 if unused public: static const int INVALID_HASH_VALUE = 0; template inline bool KeyEquals(TLookup const& otherKey, hash_t otherHashCode) { Assert(TAGHASH(Comparer::GetHashCode(this->Key())) == this->hashCode); return this->hashCode == otherHashCode && Comparer::Equals(this->Key(), otherKey); } template inline hash_t GetHashCode() { Assert(TAGHASH(Comparer::GetHashCode(this->Key())) == this->hashCode); return hashCode; } void Set(TKey const& key, TValue const& value, hash_t hashCode) { __super::Set(key, value); this->hashCode = hashCode; } void Clear() { __super::Clear(); this->hashCode = INVALID_HASH_VALUE; } }; template class SimpleHashedEntry : public DefaultHashedEntry {}; template class HashedEntry : public CacheHashedEntry {}; template class SimpleDictionaryEntry : public DefaultHashedEntry {}; template class DictionaryEntry: public CacheHashedEntry {}; template class WeakRefValueDictionaryEntry: public SimpleDictionaryEntry { public: void Clear() { this->key = TKey(); this->value = TValue(); } static bool SupportsCleanup() { return true; } static bool NeedsCleanup(WeakRefValueDictionaryEntry const& entry) { TValue weakReference = entry.Value(); return (weakReference == nullptr || weakReference->Get() == nullptr); } }; template class SimpleDictionaryKeyEntry : public DefaultHashedKeyEntry {}; }