/// <summary>
        /// Moves to the next edge and returns the pointer of that next edge. Returns NO_EDGE if no next edge was found.
        ///
        /// The given pointer is expected to be the first position of an edge.
        /// </summary>
        private uint MoveNextEdge(uint edgePointer)
        {
            // move past first fixed-data fields to the last one.
            var data = _edges[edgePointer];

            if (data == NO_EDGE)
            { // just move to the first non-NO_EDGE field.
                while (data == NO_EDGE)
                {
                    edgePointer++;
                    data = _edges[edgePointer];
                }
                return(edgePointer);
            }
            edgePointer += (uint)_fixedEdgeDataSize;
            data         = _edges[edgePointer];
            while (!DirectedDynamicGraph.IsLastField(data))
            { // move until the last data field.
                edgePointer++;
                data = _edges[edgePointer];
            }
            if (DirectedDynamicGraph.IsLastFieldInLastEdge(data))
            { // if the last data field is the last edge then just stop.
                return(NO_EDGE);
            }
            edgePointer++;
            data = _edges[edgePointer];
            while (data == NO_EDGE)
            {
                edgePointer++;
                data = _edges[edgePointer];
            }
            return(edgePointer);
        }
        /// <summary>
        /// Removes an edge and moves to the next edge after the removed edge. Returns NO_EDGE if no next edge was found.
        ///
        /// The given pointer is expected to be the first position of an edge starting a the given vertex. The previous edge pointer is NO_EDGE if there is not previous edge.
        /// </summary>
        private uint RemoveEdge(uint vertex, uint previousEdgePointer, uint edgePointer, uint nextPointer)
        {
            var originalEdgePointer = edgePointer;

            if (previousEdgePointer == NO_EDGE && nextPointer == NO_EDGE)
            { // only one edge left.
                _vertices[vertex] = NO_EDGE;
                return(NO_EDGE);
            }

            var startPointer = edgePointer;

            // remove the fixed-data.
            for (var i = 0; i < _fixedEdgeDataSize - 1; i++)
            {
                _edges[edgePointer] = NO_EDGE;
                edgePointer++;
            }
            var data = _edges[edgePointer];

            while (!DirectedDynamicGraph.IsLastField(data))
            { // move until the last data field.
                _edges[edgePointer] = NO_EDGE;
                edgePointer++;
                data = _edges[edgePointer];
            }
            if (DirectedDynamicGraph.IsLastFieldInLastEdge(data))
            {     // if the last data field is the last edge then just stop.
                if (!this.MarkAsLast(previousEdgePointer))
                { // there is no data at the previous edge, this can only mean one thing: no more edges left.
                    _vertices[vertex] = NO_EDGE;
                }
                return(NO_EDGE);
            }
            _edges[edgePointer] = NO_EDGE;
            return(edgePointer + 1);
        }
        /// <summary>
        /// Compresses the data in this graph to it's smallest size.
        /// </summary>
        public void Compress(bool toReadonly, out long maxEdgeId)
        {
            // trim first.
            this.Trim();

            // build a list of all vertices sorted by their first position.
            var sortedVertices = new MemoryArray <uint>(_vertices.Length);

            for (uint i = 0; i < sortedVertices.Length; i++)
            {
                sortedVertices[i] = i;
            }

            // sort vertices and coordinates.
            QuickSort.Sort((i) => _vertices[sortedVertices[i]] * sortedVertices.Length +
                           sortedVertices[i],
                           (i, j) =>
            {
                var tempRef       = sortedVertices[i];
                sortedVertices[i] = sortedVertices[j];
                sortedVertices[j] = tempRef;
            }, 0, this.VertexCount - 1);

            // move data down.
            uint pointer = 0;

            for (uint i = 0; i < sortedVertices.Length; i++)
            {
                var vertex        = sortedVertices[i];
                var vertexPointer = _vertices[vertex];
                if (vertexPointer == NO_EDGE)
                {
                    continue;
                }
                _vertices[vertex] = pointer;

                // skip removed data.
                var pointerBefore = pointer;
                while (_edges[vertexPointer] == NO_EDGE)
                {
                    vertexPointer++;
                }
                do
                {
                    // copy fixed-data.
                    for (var e = 0; e < _fixedEdgeDataSize; e++)
                    {
                        _edges[pointer + e] = _edges[vertexPointer + e];
                    }
                    pointer       += (uint)_fixedEdgeDataSize;
                    vertexPointer += (uint)_fixedEdgeDataSize;
                    while (!DirectedDynamicGraph.IsLastField(_edges[pointer - 1]))
                    {
                        _edges[pointer] = _edges[vertexPointer];
                        pointer++;
                        vertexPointer++;
                    }
                } while (!DirectedDynamicGraph.IsLastFieldInLastEdge(_edges[pointer - 1]));

                var count = pointer - pointerBefore;
                if (!toReadonly && count > 2 && !((count & (count - 1)) == 0))
                { // next power of 2, don't do this on readonly to save space.
                    count |= count >> 1;
                    count |= count >> 2;
                    count |= count >> 4;
                    count |= count >> 8;
                    count |= count >> 16;
                    count++;

                    pointer += (count - (pointer - pointerBefore));
                }
            }
            _nextEdgePointer = pointer;
            _readonly        = toReadonly;

            // store the max edge id.
            _edges.Resize(_nextEdgePointer);
            maxEdgeId = _edges.Length;
        }