/// <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> /// Adds an edge with the associated data. /// </summary> public uint AddEdge(uint vertex1, uint vertex2, params uint[] data) { if (_readonly) { throw new Exception("Graph is readonly."); } if (vertex1 == vertex2) { throw new ArgumentException("Given vertices must be different."); } if (data == null || data.Length == 0) { throw new ArgumentException("Data payload must contain at least one entry."); } for (var i = 0; i < data.Length; i++) { if (data[i] > MAX_DYNAMIC_PAYLOAD) { throw new ArgumentOutOfRangeException("data", "One of the entries in the data payload is too big."); } } while (vertex1 > _vertices.Length - 1) { this.IncreaseVertexSize(); } while (vertex2 > _vertices.Length - 1) { this.IncreaseVertexSize(); } var vertexPointer = vertex1; var edgePointer = _vertices[vertexPointer]; var edgeId = uint.MaxValue; if (edgePointer == NO_EDGE) { // no edge yet, just add the end. _vertices[vertexPointer] = _nextEdgePointer; edgeId = _nextEdgePointer; if (_nextEdgePointer + data.Length >= _edges.Length) { // make sure we can add another edge. this.IncreaseEdgeSize(); } _edges[_nextEdgePointer] = vertex2; for (var i = 0; i < data.Length - 1; i++) { _edges[_nextEdgePointer + i + 1] = data[i]; } _edges[_nextEdgePointer + data.Length - 1 + 1] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data[data.Length - 1]); _nextEdgePointer += DirectedDynamicGraph.NextPowerOfTwoOrPowerOfTwo((uint)(1 + data.Length)); } else { // there are already edges present for this vertex. var startPointer = edgePointer; edgePointer += (uint)(_fixedEdgeDataSize - 1); while (true) { var e = _edges[edgePointer]; if (e != NO_EDGE && IsLastFieldInLastEdge(e)) { break; } edgePointer++; } // check size and allocate new space or move if needed. var size = edgePointer - startPointer + 1; var totalSpace = NextPowerOfTwoOrPowerOfTwo(size); var requiredSpace = size + 1 + (uint)data.Length; if (requiredSpace > totalSpace) { // allocate enough space. var newTotalSpace = NextPowerOfTwoOrPowerOfTwo(requiredSpace); if (startPointer + totalSpace == _nextEdgePointer) { // at the end, just make sure the edges array is big enough. while (newTotalSpace + startPointer >= _edges.Length) { this.IncreaseEdgeSize(); } _nextEdgePointer += (newTotalSpace - totalSpace); } else { // move everything to the end, there isn't enough free space here. // make sure the edges array is big enough. while (newTotalSpace + _nextEdgePointer >= _edges.Length) { this.IncreaseEdgeSize(); } // move existing data to the end and update pointer. _vertices[vertexPointer] = _nextEdgePointer; for (uint i = 0; i < size; i++) { _edges[_nextEdgePointer + i] = _edges[startPointer + i]; } edgePointer = _nextEdgePointer + size - 1; _nextEdgePointer += newTotalSpace; } } // mark the current field as the non-last field. _edges[edgePointer] = RemoveLastEdgeFlag(_edges[edgePointer]); // add new data. _edges[edgePointer + 1] = vertex2; for (var i = 0; i < data.Length - 1; i++) { _edges[edgePointer + i + 2] = data[i]; } _edges[edgePointer + data.Length - 1 + 2] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data[data.Length - 1]); } _edgeCount++; return(edgeId); }
/// <summary> /// Adds an edge with the associated data. /// </summary> public uint AddEdge(uint vertex1, uint vertex2, uint data) { if (_readonly) { throw new Exception("Graph is readonly."); } if (vertex1 == vertex2) { throw new ArgumentException("Given vertices must be different."); } if (data > MAX_DYNAMIC_PAYLOAD) { throw new ArgumentOutOfRangeException("data", "Data payload too big."); } _vertices.EnsureMinimumSize(Math.Max(vertex1, vertex2) + 1, NO_EDGE); var vertexPointer = vertex1; var edgePointer = _vertices[vertexPointer]; var edgeId = uint.MaxValue; if (edgePointer == NO_EDGE) { // no edge yet, just add the end. _vertices[vertexPointer] = _nextEdgePointer; edgeId = _nextEdgePointer; // make sure we can add another edge. _edges.EnsureMinimumSize(_nextEdgePointer + 2); _edges[_nextEdgePointer] = vertex2; _edges[_nextEdgePointer + 1] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data); _nextEdgePointer += 2; } else { // there are already edges present for this vertex. var startPointer = edgePointer; edgePointer += (uint)(_fixedEdgeDataSize - 1); while (true) { var e = _edges[edgePointer]; if (e != NO_EDGE && IsLastFieldInLastEdge(e)) { break; } edgePointer++; } // check size and allocate new space or move if needed. var size = edgePointer - startPointer + 1; var totalSpace = NextPowerOfTwoOrPowerOfTwo(size); var requiredSpace = size + 2; if (requiredSpace > totalSpace) { // allocate enough space. var newTotalSpace = NextPowerOfTwoOrPowerOfTwo(requiredSpace); if (startPointer + totalSpace == _nextEdgePointer) { // at the end, just make sure the edges array is big enough. _edges.EnsureMinimumSize(newTotalSpace + startPointer + 1); _nextEdgePointer += (newTotalSpace - totalSpace); } else { // move everything to the end, there isn't enough free space here. // make sure the edges array is big enough. _edges.EnsureMinimumSize(newTotalSpace + _nextEdgePointer + 1); // move existing data to the end and update pointer. _vertices[vertexPointer] = _nextEdgePointer; for (uint i = 0; i < size; i++) { _edges[_nextEdgePointer + i] = _edges[startPointer + i]; } edgePointer = _nextEdgePointer + size - 1; _nextEdgePointer += newTotalSpace; } } // mark the current field as the non-last field. _edges[edgePointer] = RemoveLastEdgeFlag(_edges[edgePointer]); // add new data. edgeId = edgePointer + 1; _edges[edgePointer + 1] = vertex2; _edges[edgePointer + 2] = DirectedDynamicGraph.AddLastEdgeAndLastFieldFlag(data); } _edgeCount++; return(edgeId); }