/// <summary> /// Fills the given array with the dynamic part of the edge-data. /// </summary> public int FillWithDynamicData(ref uint[] data) { var p = _currentEdgePointer + _graph._fixedEdgeDataSize; if (DirectedDynamicGraph.IsLastField(_graph._edges[p])) { // no dynamic data! return(0); } var i = 0; p++; do { data[i] = _graph._edges[p]; if (DirectedDynamicGraph.IsLastField(data[i])) { data[i] = DirectedDynamicGraph.RemoveFlags(data[i]); break; } i++; p++; } while (true); return(i + 1); }
/// <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> /// Marks the edge at the given location as the last edge. /// </summary> /// <returns>False if there is no data at the given location, true otherwise.</returns> private bool MarkAsLast(uint edgePointer) { var data = _edges[edgePointer]; if (data == NO_EDGE) { return(false); } while (!DirectedDynamicGraph.IsLastField(data)) { edgePointer++; data = _edges[edgePointer]; } data = DirectedDynamicGraph.RemoveFlags(data); _edges[edgePointer] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag( data); return(true); }
/// <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; }