/// <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);
        }
Ejemplo n.º 3
0
        /// <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);
        }