This is my first attempt at implementing a heap data structure and I've decided to cover the methods `Peek`, `Pop`, `Push`, and `Replace`. Think appear to work correctly but I admittedly had a lot of trouble figuring out the "ideal" way to implement each function as the reference implementations I found were all over the place.

Any feedback, especially if it addresses concerns that aren't related to formatting/naming, is most appreciated.

```
public class BinaryHeap<T>
{
    private readonly Func<T, T, bool> m_comparer;
    private readonly IList<T> m_values;

    private int m_nextIndex;

    public int Capacity => m_values.Count;
    public int Count => m_nextIndex;

    public BinaryHeap(IList<T> values, Func<T, T, bool> comparer) {
        m_comparer = comparer;
        m_values = values;

        Grow(checked((int)(Operations.NextPowerOf2(Capacity) - 1)));
        Rebuild();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public T Peek() {
        return m_values[0];
    }
    public T Pop() {
        if (TryPop(out T value)) {
            return value;
        }
        else {
            throw new InvalidOperationException(message: "heap is empty");
        }
    }
    public int Push(T value) {
        var offset = Count;

        if (!(offset < Capacity)) {
            Grow(checked((int)(Operations.NextPowerOf2(Capacity + 1) - 1)));
        }

        while (0 < offset) {
            var parent = ((offset - 1) >> 1);

            if (m_comparer(m_values[parent], value)) {
                break;
            }

            m_values[offset] = m_values[parent];
            offset = parent;
        }

        m_values[offset] = value;

        return m_nextIndex++;
    }
    public T Replace(T newValue) {
        if (TryReplace(newValue, out T oldValue)) {
            return oldValue;
        }
        else {
            throw new InvalidOperationException(message: "heap is empty");
        }
    }
    public bool TryReplace(T newValue, out T oldValue) {
        if (0 < Count) {
            oldValue = Peek();
            m_values[0] = newValue;

            Heapify(0);

            return true;
        }
        else {
            oldValue = default;

            return false;
        }
    }
    public bool TryPop(out T value) {
        if (0 < Count) {
            value = Peek();
            m_values[0] = m_values[--m_nextIndex];
            m_values[m_nextIndex] = default;

            Heapify(0);

            return true;
        }
        else {
            value = default;

            return false;
        }
    }

    private void Grow(int maxCapacity) {
        var currentCapacity = Capacity;

        for (var i = currentCapacity; (i < maxCapacity); i++) {
            m_values.Add(default);
        }

        m_nextIndex = currentCapacity;
    }
    private void Heapify(int offset) {
        var count = Count;

        while (offset < count) {
            var left = ((offset << 1) + 1);
            var right = (left + 1);
            var parent = offset;

            if ((left < count) && m_comparer(m_values[left], m_values[parent])) {
                parent = left;
            }

            if ((right < count) && m_comparer(m_values[right], m_values[parent])) {
                parent = right;
            }

            if (offset == parent) {
                return;
            }

            Swap(ref offset, ref parent);
        }
    }
    private void Rebuild() {
        for (var i = ((Count - 1) >> 1); (-1 < i); i--) {
            Heapify(i);
        }
    }
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void Swap(ref int x, ref int y) {
        var temp = m_values[x];

        m_values[x] = m_values[y];
        m_values[y] = temp;

        x = y;
    }
}

```

As requested, here are the missing method(s):

```
public static class Operations
{
    public static long NextPowerOf2(long value) {
        return ((long)NextPowerOf2((ulong)value));
    }
    public static ulong NextPowerOf2(ulong value) {
        return (FoldBits(value) + 1);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static ulong FoldBits(ulong value) {
        value |= (value >> 1);
        value |= (value >> 2);
        value |= (value >> 4);
        value |= (value >> 8);
        value |= (value >> 16);

        return (value | (value >> 32));
    }
}

```