Exemple #1
0
        /// <summary>
        /// Calculates the hash for a requested span.
        /// This will try to use a cached hash if the data was already accessed before, to avoid re-hashing.
        /// </summary>
        /// <param name="data">Data to be hashed</param>
        /// <returns>Hash of the data</returns>
        private uint CalcHashCached(ReadOnlySpan <byte> data)
        {
            HashState state = default;
            bool      found = false;

            for (int i = _cachedHashes.Count - 1; i >= 0; i--)
            {
                int cachedHashSize = _cachedHashes.Keys[i];

                if (cachedHashSize < data.Length)
                {
                    state = _cachedHashes.Values[i];
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                state = new HashState();
                state.Initialize();
            }

            state.Continue(data);
            _cachedHashes[data.Length & ~7] = state;
            return(state.Finalize(data));
        }
Exemple #2
0
        /// <summary>
        /// One shot hash calculation for a given data.
        /// </summary>
        /// <param name="data">Data to be hashed</param>
        /// <returns>Hash of the given data</returns>
        public static uint CalcHash(ReadOnlySpan <byte> data)
        {
            HashState state = new HashState();

            state.Initialize();
            state.Continue(data);
            return(state.Finalize(data));
        }
        /// <summary>
        /// Gets an existing item from the table, or adds a new one if not present.
        /// </summary>
        /// <param name="data">Data</param>
        /// <param name="item">Item associated with the data</param>
        /// <returns>Existing item, or <paramref name="item"/> if not present</returns>
        public T GetOrAdd(byte[] data, T item)
        {
            SizeEntry sizeEntry;

            int index = BinarySearch(_sizeTable, data.Length);

            if (index < _sizeTable.Count && _sizeTable[index].Size == data.Length)
            {
                sizeEntry = _sizeTable[index];
            }
            else
            {
                if (index < _sizeTable.Count && _sizeTable[index].Size < data.Length)
                {
                    index++;
                }

                sizeEntry = new SizeEntry(data.Length);

                _sizeTable.Insert(index, sizeEntry);

                for (int i = index + 1; i < _sizeTable.Count; i++)
                {
                    _sizeTable[i].FillPartials(sizeEntry);
                }
            }

            HashState hashState = new HashState();

            hashState.Initialize();

            for (int i = 0; i < index; i++)
            {
                ReadOnlySpan <byte> dataSlice = new ReadOnlySpan <byte>(data).Slice(0, _sizeTable[i].Size);
                hashState.Continue(dataSlice);
                _sizeTable[i].AddPartial(data, hashState.Finalize(dataSlice));
            }

            hashState.Continue(data);
            return(sizeEntry.GetOrAdd(data, hashState.Finalize(data), item));
        }
        /// <summary>
        /// Adds a partial entry to the hash table.
        /// </summary>
        /// <param name="ownerData">Full data</param>
        /// <param name="ownSize">Size of the sub-region of <paramref name="ownerData"/> used by the partial entry</param>
        /// <returns>True if added, false otherwise</returns>
        public bool AddPartial(byte[] ownerData, int ownSize)
        {
            ReadOnlySpan <byte> data = new ReadOnlySpan <byte>(ownerData).Slice(0, ownSize);

            return(AddPartial(ownerData, HashState.CalcHash(data), ownSize));
        }