// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_ORDERED_HASH_TABLE_INL_H_
#define V8_OBJECTS_ORDERED_HASH_TABLE_INL_H_

#include "src/objects/ordered-hash-table.h"

#include "src/heap/heap.h"
#include "src/objects/compressed-slots.h"
#include "src/objects/fixed-array-inl.h"
#include "src/objects/js-collection-iterator.h"
#include "src/objects/objects-inl.h"
#include "src/objects/slots.h"

// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"

namespace v8 {
namespace internal {

CAST_ACCESSOR(OrderedNameDictionary)
CAST_ACCESSOR(SmallOrderedNameDictionary)
CAST_ACCESSOR(OrderedHashMap)
CAST_ACCESSOR(OrderedHashSet)
CAST_ACCESSOR(SmallOrderedHashMap)
CAST_ACCESSOR(SmallOrderedHashSet)

template <class Derived, int entrysize>
OrderedHashTable<Derived, entrysize>::OrderedHashTable(Address ptr)
    : FixedArray(ptr) {}

template <class Derived, int entrysize>
bool OrderedHashTable<Derived, entrysize>::IsKey(ReadOnlyRoots roots,
                                                 Object k) {
  return k != roots.the_hole_value();
}

OrderedHashSet::OrderedHashSet(Address ptr)
    : OrderedHashTable<OrderedHashSet, 1>(ptr) {
  SLOW_DCHECK(IsOrderedHashSet());
}

OrderedHashMap::OrderedHashMap(Address ptr)
    : OrderedHashTable<OrderedHashMap, 2>(ptr) {
  SLOW_DCHECK(IsOrderedHashMap());
}

OrderedNameDictionary::OrderedNameDictionary(Address ptr)
    : OrderedHashTable<OrderedNameDictionary, 3>(ptr) {
  SLOW_DCHECK(IsOrderedNameDictionary());
}

template <class Derived>
SmallOrderedHashTable<Derived>::SmallOrderedHashTable(Address ptr)
    : HeapObject(ptr) {}

template <class Derived>
Object SmallOrderedHashTable<Derived>::KeyAt(InternalIndex entry) const {
  DCHECK_LT(entry.as_int(), Capacity());
  Offset entry_offset = GetDataEntryOffset(entry.as_int(), Derived::kKeyIndex);
  return TaggedField<Object>::load(*this, entry_offset);
}

template <class Derived>
Object SmallOrderedHashTable<Derived>::GetDataEntry(int entry,
                                                    int relative_index) {
  DCHECK_LT(entry, Capacity());
  DCHECK_LE(static_cast<unsigned>(relative_index), Derived::kEntrySize);
  Offset entry_offset = GetDataEntryOffset(entry, relative_index);
  return TaggedField<Object>::load(*this, entry_offset);
}

OBJECT_CONSTRUCTORS_IMPL(SmallOrderedHashSet,
                         SmallOrderedHashTable<SmallOrderedHashSet>)
OBJECT_CONSTRUCTORS_IMPL(SmallOrderedHashMap,
                         SmallOrderedHashTable<SmallOrderedHashMap>)
OBJECT_CONSTRUCTORS_IMPL(SmallOrderedNameDictionary,
                         SmallOrderedHashTable<SmallOrderedNameDictionary>)

Handle<Map> OrderedHashSet::GetMap(ReadOnlyRoots roots) {
  return roots.ordered_hash_set_map_handle();
}

Handle<Map> OrderedHashMap::GetMap(ReadOnlyRoots roots) {
  return roots.ordered_hash_map_map_handle();
}

Handle<Map> OrderedNameDictionary::GetMap(ReadOnlyRoots roots) {
  return roots.ordered_name_dictionary_map_handle();
}

Handle<Map> SmallOrderedNameDictionary::GetMap(ReadOnlyRoots roots) {
  return roots.small_ordered_name_dictionary_map_handle();
}

Handle<Map> SmallOrderedHashMap::GetMap(ReadOnlyRoots roots) {
  return roots.small_ordered_hash_map_map_handle();
}

Handle<Map> SmallOrderedHashSet::GetMap(ReadOnlyRoots roots) {
  return roots.small_ordered_hash_set_map_handle();
}

inline Object OrderedHashMap::ValueAt(InternalIndex entry) {
  DCHECK_LT(entry.as_int(), UsedCapacity());
  return get(EntryToIndex(entry) + kValueOffset);
}

inline Object OrderedNameDictionary::ValueAt(InternalIndex entry) {
  DCHECK_LT(entry.as_int(), UsedCapacity());
  return get(EntryToIndex(entry) + kValueOffset);
}

Name OrderedNameDictionary::NameAt(InternalIndex entry) {
  return Name::cast(KeyAt(entry));
}

// Set the value for entry.
inline void OrderedNameDictionary::ValueAtPut(InternalIndex entry,
                                              Object value) {
  DCHECK_LT(entry.as_int(), UsedCapacity());
  this->set(EntryToIndex(entry) + kValueOffset, value);
}

// Returns the property details for the property at entry.
inline PropertyDetails OrderedNameDictionary::DetailsAt(InternalIndex entry) {
  DCHECK_LT(entry.as_int(), this->UsedCapacity());
  // TODO(gsathya): Optimize the cast away.
  return PropertyDetails(
      Smi::cast(get(EntryToIndex(entry) + kPropertyDetailsOffset)));
}

inline void OrderedNameDictionary::DetailsAtPut(InternalIndex entry,
                                                PropertyDetails value) {
  DCHECK_LT(entry.as_int(), this->UsedCapacity());
  // TODO(gsathya): Optimize the cast away.
  this->set(EntryToIndex(entry) + kPropertyDetailsOffset, value.AsSmi());
}

inline Object SmallOrderedNameDictionary::ValueAt(InternalIndex entry) {
  return this->GetDataEntry(entry.as_int(), kValueIndex);
}

// Set the value for entry.
inline void SmallOrderedNameDictionary::ValueAtPut(InternalIndex entry,
                                                   Object value) {
  this->SetDataEntry(entry.as_int(), kValueIndex, value);
}

// Returns the property details for the property at entry.
inline PropertyDetails SmallOrderedNameDictionary::DetailsAt(
    InternalIndex entry) {
  // TODO(gsathya): Optimize the cast away. And store this in the data table.
  return PropertyDetails(
      Smi::cast(this->GetDataEntry(entry.as_int(), kPropertyDetailsIndex)));
}

// Set the details for entry.
inline void SmallOrderedNameDictionary::DetailsAtPut(InternalIndex entry,
                                                     PropertyDetails value) {
  // TODO(gsathya): Optimize the cast away. And store this in the data table.
  this->SetDataEntry(entry.as_int(), kPropertyDetailsIndex, value.AsSmi());
}

inline bool OrderedHashSet::Is(Handle<HeapObject> table) {
  return table->IsOrderedHashSet();
}

inline bool OrderedHashMap::Is(Handle<HeapObject> table) {
  return table->IsOrderedHashMap();
}

inline bool OrderedNameDictionary::Is(Handle<HeapObject> table) {
  return table->IsOrderedNameDictionary();
}

inline bool SmallOrderedHashSet::Is(Handle<HeapObject> table) {
  return table->IsSmallOrderedHashSet();
}

inline bool SmallOrderedNameDictionary::Is(Handle<HeapObject> table) {
  return table->IsSmallOrderedNameDictionary();
}

inline bool SmallOrderedHashMap::Is(Handle<HeapObject> table) {
  return table->IsSmallOrderedHashMap();
}

template <class Derived>
void SmallOrderedHashTable<Derived>::SetDataEntry(int entry, int relative_index,
                                                  Object value) {
  DCHECK_NE(kNotFound, entry);
  int entry_offset = GetDataEntryOffset(entry, relative_index);
  RELAXED_WRITE_FIELD(*this, entry_offset, value);
  WRITE_BARRIER(*this, entry_offset, value);
}

template <class Derived, class TableType>
Object OrderedHashTableIterator<Derived, TableType>::CurrentKey() {
  TableType table = TableType::cast(this->table());
  int index = Smi::ToInt(this->index());
  DCHECK_LE(0, index);
  InternalIndex entry(index);
  Object key = table.KeyAt(entry);
  DCHECK(!key.IsTheHole());
  return key;
}

inline void SmallOrderedNameDictionary::SetHash(int hash) {
  DCHECK(PropertyArray::HashField::is_valid(hash));
  WriteField<int>(PrefixOffset(), hash);
}

inline int SmallOrderedNameDictionary::Hash() {
  int hash = ReadField<int>(PrefixOffset());
  DCHECK(PropertyArray::HashField::is_valid(hash));
  return hash;
}

inline void OrderedNameDictionary::SetHash(int hash) {
  DCHECK(PropertyArray::HashField::is_valid(hash));
  this->set(PrefixIndex(), Smi::FromInt(hash));
}

inline int OrderedNameDictionary::Hash() {
  Object hash_obj = this->get(PrefixIndex());
  int hash = Smi::ToInt(hash_obj);
  DCHECK(PropertyArray::HashField::is_valid(hash));
  return hash;
}

}  // namespace internal
}  // namespace v8

#include "src/objects/object-macros-undef.h"

#endif  // V8_OBJECTS_ORDERED_HASH_TABLE_INL_H_
