// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/// A collection of key/value pairs which provides efficient retrieval of
/// value by key.
///
/// This class implements a persistent map: extending this map with a new
/// key/value pair does not modify an existing instance but instead creates a
/// new instance.
///
/// Unlike [Map], this class does not support `null` as a key value and
/// implements only a functionality needed for a specific use case at the
/// core of the framework.
///
/// Underlying implementation uses a variation of *hash array mapped trie*
/// data structure with compressed (bitmap indexed) nodes.
///
/// See also:
///
///  * [Bagwell, Phil. Ideal hash trees.](https://infoscience.epfl.ch/record/64398);
///  * [Steindorfer, Michael J., and Jurgen J. Vinju. "Optimizing hash-array mapped tries for fast and lean immutable JVM collections."](https://dl.acm.org/doi/abs/10.1145/2814270.2814312);
///  * [Clojure's `PersistentHashMap`](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentHashMap.java).
///
class PersistentHashMap<K extends Object, V> {
  /// Creates an empty hash map.
  const PersistentHashMap.empty() : this._(null);

  const PersistentHashMap._(this._root);

  final _TrieNode? _root;

  /// If this map does not already contain the given [key] to [value]
  /// mapping then create a new version of the map which contains
  /// all mappings from the current one plus the given [key] to [value]
  /// mapping.
  PersistentHashMap<K, V> put(K key, V value) {
    final _TrieNode newRoot =
        (_root ?? _CompressedNode.empty).put(0, key, key.hashCode, value);
    if (newRoot == _root) {
      return this;
    }
    return PersistentHashMap<K, V>._(newRoot);
  }

  /// Returns value associated with the given [key] or `null` if [key]
  /// is not in the map.
  @pragma('dart2js:as:trust')
  V? operator[](K key) {
    if (_root == null) {
      return null;
    }

    // Unfortunately can not use unsafeCast<V?>(...) here because it leads
    // to worse code generation on VM.
    return _root!.get(0, key, key.hashCode) as V?;
  }
}

/// Base class for nodes in a hash trie.
///
/// This trie is keyed by hash code bits using [hashBitsPerLevel] bits
/// at each level.
abstract class _TrieNode {
  static const int hashBitsPerLevel = 5;
  static const int hashBitsPerLevelMask = (1 << hashBitsPerLevel) - 1;

  @pragma('vm:prefer-inline')
  static int trieIndex(int hash, int bitIndex) {
    return (hash >>> bitIndex) & hashBitsPerLevelMask;
  }

  /// Insert [key] to [value] mapping into the trie using bits from [keyHash]
  /// starting at [bitIndex].
  _TrieNode put(int bitIndex, Object key, int keyHash, Object? value);

  /// Lookup a value associated with the given [key] using bits from [keyHash]
  /// starting at [bitIndex].
  Object? get(int bitIndex, Object key, int keyHash);
}

/// A full (uncompressed) node in the trie.
///
/// It contains an array with `1<<_hashBitsPerLevel` elements which
/// are references to deeper nodes.
class _FullNode extends _TrieNode {
  _FullNode(this.descendants);

  static const int numElements = 1 << _TrieNode.hashBitsPerLevel;

  // Caveat: this array is actually List<_TrieNode?> but typing it like that
  // will introduce a type check when copying this array. For performance
  // reasons we instead omit the type and use (implicit) casts when accessing
  // it instead.
  final List<Object?> descendants;

  @override
  _TrieNode put(int bitIndex, Object key, int keyHash, Object? value) {
    final int index = _TrieNode.trieIndex(keyHash, bitIndex);
    final _TrieNode node = _unsafeCast<_TrieNode?>(descendants[index]) ?? _CompressedNode.empty;
    final _TrieNode newNode = node.put(bitIndex + _TrieNode.hashBitsPerLevel, key, keyHash, value);
    return identical(newNode, node)
        ? this
        : _FullNode(_copy(descendants)..[index] = newNode);
  }

  @override
  Object? get(int bitIndex, Object key, int keyHash) {
    final int index = _TrieNode.trieIndex(keyHash, bitIndex);

    final _TrieNode? node = _unsafeCast<_TrieNode?>(descendants[index]);
    return node?.get(bitIndex + _TrieNode.hashBitsPerLevel, key, keyHash);
  }
}

/// Compressed node in the trie.
///
/// Instead of storing the full array of outgoing edges this node uses a
/// compressed representation:
///
///   * [_CompressedNode.occupied] has a bit set for indices which are occupied.
///   * furthermore, each occupied index can either be a `(key, value)` pair
///     representing an actual key/value mapping or a `(null, trieNode)` pair
///     representing a descendant node.
///
/// Keys and values are stored together in a single array (instead of two
/// parallel arrays) for performance reasons: this improves memory access
/// locality and reduces memory usage (two arrays of length N take slightly
/// more space than one array of length 2*N).
class _CompressedNode extends _TrieNode {
  _CompressedNode(this.occupiedIndices, this.keyValuePairs);
  _CompressedNode._empty() : this(0, _emptyArray);

  factory _CompressedNode.single(int bitIndex, int keyHash, _TrieNode node) {
    final int bit = 1 << _TrieNode.trieIndex(keyHash, bitIndex);
    // A single (null, node) pair.
    final List<Object?> keyValuePairs = _makeArray(2)
      ..[1] = node;
    return _CompressedNode(bit, keyValuePairs);
  }

  static final _CompressedNode empty = _CompressedNode._empty();

  // Caveat: do not replace with <Object?>[] or const <Object?>[] this will
  // introduce polymorphism in the keyValuePairs field and significantly
  // degrade performance on the VM because it will no longer be able to
  // devirtualize method calls on keyValuePairs.
  static final List<Object?> _emptyArray = _makeArray(0);

  // This bitmap only uses 32bits due to [_TrieNode.hashBitsPerLevel] being `5`.
  final int occupiedIndices;
  final List<Object?> keyValuePairs;

  @override
  _TrieNode put(int bitIndex, Object key, int keyHash, Object? value) {
    final int bit = 1 << _TrieNode.trieIndex(keyHash, bitIndex);
    final int index = _compressedIndex(bit);

    if ((occupiedIndices & bit) != 0) {
      // Index is occupied.
      final Object? keyOrNull = keyValuePairs[2 * index];
      final Object? valueOrNode = keyValuePairs[2 * index + 1];

      // Is this a (null, trieNode) pair?
      if (identical(keyOrNull, null)) {
        final _TrieNode newNode = _unsafeCast<_TrieNode>(valueOrNode).put(
            bitIndex + _TrieNode.hashBitsPerLevel, key, keyHash, value);
        if (newNode == valueOrNode) {
          return this;
        }
        return _CompressedNode(
            occupiedIndices, _copy(keyValuePairs)..[2 * index + 1] = newNode);
      }

      if (key == keyOrNull) {
        // Found key/value pair with a matching key. If values match
        // then avoid doing anything otherwise copy and update.
        return identical(value, valueOrNode)
            ? this
            : _CompressedNode(
                occupiedIndices, _copy(keyValuePairs)..[2 * index + 1] = value);
      }

      // Two different keys at the same index, resolve collision.
      final _TrieNode newNode = _resolveCollision(
          bitIndex + _TrieNode.hashBitsPerLevel,
          keyOrNull,
          valueOrNode,
          key,
          keyHash,
          value);
      return _CompressedNode(
          occupiedIndices,
          _copy(keyValuePairs)
            ..[2 * index] = null
            ..[2 * index + 1] = newNode);
    } else {
      // Adding new key/value mapping.
      final int occupiedCount = _bitCount(occupiedIndices);
      if (occupiedCount >= 16) {
        // Too many occupied: inflate compressed node into full node and
        // update descendant at the corresponding index.
        return _inflate(bitIndex)
          ..descendants[_TrieNode.trieIndex(keyHash, bitIndex)] =
              _CompressedNode.empty.put(
                  bitIndex + _TrieNode.hashBitsPerLevel, key, keyHash, value);
      } else {
        // Grow keyValuePairs by inserting key/value pair at the given
        // index.
        final int prefixLength = 2 * index;
        final int totalLength = 2 * occupiedCount;
        final List<Object?> newKeyValuePairs = _makeArray(totalLength + 2);
        for (int srcIndex = 0; srcIndex < prefixLength; srcIndex++) {
          newKeyValuePairs[srcIndex] = keyValuePairs[srcIndex];
        }
        newKeyValuePairs[prefixLength] = key;
        newKeyValuePairs[prefixLength + 1] = value;
        for (int srcIndex = prefixLength, dstIndex = prefixLength + 2;
            srcIndex < totalLength;
            srcIndex++, dstIndex++) {
          newKeyValuePairs[dstIndex] = keyValuePairs[srcIndex];
        }
        return _CompressedNode(occupiedIndices | bit, newKeyValuePairs);
      }
    }
  }

  @override
  Object? get(int bitIndex, Object key, int keyHash) {
    final int bit = 1 << _TrieNode.trieIndex(keyHash, bitIndex);
    if ((occupiedIndices & bit) == 0) {
      return null;
    }
    final int index = _compressedIndex(bit);
    final Object? keyOrNull = keyValuePairs[2 * index];
    final Object? valueOrNode = keyValuePairs[2 * index + 1];
    if (keyOrNull == null) {
      final _TrieNode node = _unsafeCast<_TrieNode>(valueOrNode);
      return node.get(bitIndex + _TrieNode.hashBitsPerLevel, key, keyHash);
    }
    if (key == keyOrNull) {
      return valueOrNode;
    }
    return null;
  }

  /// Convert this node into an equivalent [_FullNode].
  _FullNode _inflate(int bitIndex) {
    final List<Object?> nodes = _makeArray(_FullNode.numElements);
    int srcIndex = 0;
    for (int dstIndex = 0; dstIndex < _FullNode.numElements; dstIndex++) {
      if (((occupiedIndices >>> dstIndex) & 1) != 0) {
        final Object? keyOrNull = keyValuePairs[srcIndex];
        if (keyOrNull == null) {
          nodes[dstIndex] = keyValuePairs[srcIndex + 1];
        } else {
          nodes[dstIndex] = _CompressedNode.empty.put(
              bitIndex + _TrieNode.hashBitsPerLevel,
              keyOrNull,
              keyValuePairs[srcIndex].hashCode,
              keyValuePairs[srcIndex + 1]);
        }
        srcIndex += 2;
      }
    }
    return _FullNode(nodes);
  }

  @pragma('vm:prefer-inline')
  int _compressedIndex(int bit) {
    return _bitCount(occupiedIndices & (bit - 1));
  }

  static _TrieNode _resolveCollision(int bitIndex, Object existingKey,
      Object? existingValue, Object key, int keyHash, Object? value) {
    final int existingKeyHash = existingKey.hashCode;
    // Check if this is a full hash collision and use _HashCollisionNode
    // in this case.
    return (existingKeyHash == keyHash)
        ? _HashCollisionNode.fromCollision(
            keyHash, existingKey, existingValue, key, value)
        : _CompressedNode.empty
            .put(bitIndex, existingKey, existingKeyHash, existingValue)
            .put(bitIndex, key, keyHash, value);
  }
}

/// Trie node representing a full hash collision.
///
/// Stores a list of key/value pairs (where all keys have the same hash code).
class _HashCollisionNode extends _TrieNode {
  _HashCollisionNode(this.hash, this.keyValuePairs);

  factory _HashCollisionNode.fromCollision(
      int keyHash, Object keyA, Object? valueA, Object keyB, Object? valueB) {
    final List<Object?> list = _makeArray(4);
    list[0] = keyA;
    list[1] = valueA;
    list[2] = keyB;
    list[3] = valueB;
    return _HashCollisionNode(keyHash, list);
  }

  final int hash;
  final List<Object?> keyValuePairs;

  @override
  _TrieNode put(int bitIndex, Object key, int keyHash, Object? val) {
    // Is this another full hash collision?
    if (keyHash == hash) {
      final int index = _indexOf(key);
      if (index != -1) {
        return identical(keyValuePairs[index + 1], val)
            ? this
            : _HashCollisionNode(
                keyHash, _copy(keyValuePairs)..[index + 1] = val);
      }
      final int length = keyValuePairs.length;
      final List<Object?> newArray = _makeArray(length + 2);
      for (int i = 0; i < length; i++) {
        newArray[i] = keyValuePairs[i];
      }
      newArray[length] = key;
      newArray[length + 1] = val;
      return _HashCollisionNode(keyHash, newArray);
    }

    // Not a full hash collision, need to introduce a _CompressedNode which
    // uses previously unused bits.
    return _CompressedNode.single(bitIndex, hash, this)
        .put(bitIndex, key, keyHash, val);
  }

  @override
  Object? get(int bitIndex, Object key, int keyHash) {
    final int index = _indexOf(key);
    return index < 0 ? null : keyValuePairs[index + 1];
  }

  int _indexOf(Object key) {
    final int length = keyValuePairs.length;
    for (int i = 0; i < length; i += 2) {
      if (key == keyValuePairs[i]) {
        return i;
      }
    }
    return -1;
  }
}

/// Returns number of bits set in a 32bit integer.
///
/// dart2js safe because we work with 32bit integers.
@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
int _bitCount(int n) {
  assert((n & 0xFFFFFFFF) == n);
  n = n - ((n >> 1) & 0x55555555);
  n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
  n = (n + (n >> 4)) & 0x0F0F0F0F;
  n = n + (n >> 8);
  n = n + (n >> 16);
  return n & 0x0000003F;
}

/// Create a copy of the given array.
///
/// Caveat: do not replace with List.of or similar methods. They are
/// considerably slower.
@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
List<Object?> _copy(List<Object?> array) {
  final List<Object?> clone = _makeArray(array.length);
  for (int j = 0; j < array.length; j++) {
    clone[j] = array[j];
  }
  return clone;
}

/// Create a fixed-length array of the given length filled with `null`.
///
/// We are using fixed length arrays because they are smaller and
/// faster to access on VM. Growable arrays are represented by 2 objects
/// (growable array instance pointing to a fixed array instance) and
/// consequently fixed length arrays are faster to allocated, require less
/// memory and are faster to access (less indirections).
@pragma('vm:prefer-inline')
@pragma('dart2js:tryInline')
List<Object?> _makeArray(int length) {
  return List<Object?>.filled(length, null);
}

/// This helper method becomes an no-op when compiled with dart2js on
/// with high level of optimizations enabled.
@pragma('dart2js:tryInline')
@pragma('dart2js:as:trust')
@pragma('vm:prefer-inline')
T _unsafeCast<T>(Object? o) {
  return o as T;
}
