public bool TryGetVertexAt(
            int index,
            out VertexAdjacency <TEdgeData> vertex)
        {
            if (ContainsVertexAt(index))
            {
                vertex = this[index];
                return(true);
            }

            vertex = default;
            return(false);
        }
        /// <summary>
        /// Determines whether the specified vertices are equal.
        /// The vertices are equal if references are equal or if both vertices have the same number of adjacent edges and the second vertex
        /// contains all edges of the first one.
        /// Two edges are equal if destination vertices are equal and execution of <see cref=" IEqualityComparer{T}.Equals(T,T)" />
        /// method for edges data of <paramref name="edgeDataComparer" /> returns <c>true</c>.
        /// </summary>
        /// <typeparam name="TEdgeData">The type of the edge data.</typeparam>
        /// <param name="source">The first vertex to compare.</param>
        /// <param name="other">The second vertex to compare.</param>
        /// <param name="edgeDataComparer">The edge data comparer.</param>
        /// <returns><c>true</c> if the specified vertices are equal; otherwise, <c>false</c>.</returns>
        public static bool IsEquivalent <TEdgeData>(this VertexAdjacency <TEdgeData> source,
                                                    VertexAdjacency <TEdgeData> other,
                                                    IEqualityComparer <TEdgeData> edgeDataComparer = null)
        {
            if (ReferenceEquals(source, other))
            {
                return(true);
            }

            if (source == null || other == null)
            {
                return(false);
            }

            if (source.EdgesCount != other.EdgesCount)
            {
                return(false);
            }

            if (source.HasEmptyEdgeData())
            {
                return(source.AdjacentIndexes.All(other.ContainsEdgeToIndex));
            }

            edgeDataComparer ??= EqualityComparer <TEdgeData> .Default;

            foreach (var edgeTo in source)
            {
                if (!other.TryGetEdgeToIndex(edgeTo.Destination, out var edgeData) || !edgeDataComparer.Equals(edgeData, edgeTo.Data))
                {
                    return(false);
                }
            }

            return(true);
        }
        /// <summary>
        ///     Enumerates vertices to the last not empty vertex (trims the last empty vertices).
        ///     Replaces all empty (in-between) vertices by the <paramref name="empty" /> instance.
        /// </summary>
        /// <typeparam name="T">The type of the vertex.</typeparam>
        /// <param name="source">The source of an extension of <see cref="IEnumerable{IVertex}" /> interface.</param>
        /// <param name="empty">The empty vertex.</param>
        /// <returns>
        ///     Sequence of vertices without last empty ones.
        /// </returns>
        public static IEnumerable <VertexAdjacency <T> > TrimEmptyEnd <T>(this IEnumerable <VertexAdjacency <T> > source,
                                                                          VertexAdjacency <T> empty)
        {
            var emptyCount = 0;

            foreach (var item in source)
            {
                if (item.Count <= 0)
                {
                    emptyCount++;
                }
                else
                {
                    for (var idx = 0; idx < emptyCount; idx++)
                    {
                        yield return(empty);
                    }

                    emptyCount = 0;

                    yield return(item);
                }
            }
        }
        public GraphConnectivityDefinition <TTargetEdgeData> Create <TSrcEdgeData, TTargetEdgeData>(
            IReadOnlyList <VertexAdjacency <TSrcEdgeData> > sourceAdjacency,
            IVertexAdjacencyFactory <TTargetEdgeData> verticesFactory   = null,
            Func <TSrcEdgeData, TTargetEdgeData> targetEdgeDataSelector = null,
            bool sharedVerticesInstances = false,
            IEqualityComparer <VertexAdjacency <TSrcEdgeData> > vertexEqualityComparer = null)
        {
            if (sourceAdjacency == null || sourceAdjacency.Count <= 0)
            {
                return(GetEmpty <TTargetEdgeData>());
            }

            if (verticesFactory == null)
            {
                verticesFactory = new VertexAdjacencyFactory <TTargetEdgeData>();
            }

            if (targetEdgeDataSelector == null)
            {
                if (EmptyValue.IsEmptyValueType <TTargetEdgeData>())
                {
                    targetEdgeDataSelector = _ => (TTargetEdgeData)(object)EmptyValue.Value;
                }
                else
                {
                    if (!typeof(TTargetEdgeData).IsAssignableFrom(typeof(TSrcEdgeData)))
                    {
                        throw new ArgumentNullException(nameof(targetEdgeDataSelector),
                                                        "Edge data selector can't be evaluated for specified types and must be defined.");
                    }

                    targetEdgeDataSelector = prev => (TTargetEdgeData)(object)prev;
                }
            }

            var oldVertices = sourceAdjacency;

            var destItemsCount = oldVertices.GetIndexOfLastNotEmptyVertex() + 1;

            var newVertices = new VertexAdjacency <TTargetEdgeData> [destItemsCount];

            var oldToNewVertexInstanceMap = sharedVerticesInstances
                                ? new Dictionary <VertexAdjacency <TSrcEdgeData>, VertexAdjacency <TTargetEdgeData> >(
                vertexEqualityComparer ?? VertexAdjacencyComparer <TSrcEdgeData> .DefaultWithHighestNumberOfEdgesFirst)
                                : null;

            for (var idx = 0; idx < destItemsCount; idx++)
            {
                var oldVertex = oldVertices[idx];

                VertexAdjacency <TTargetEdgeData> newVertex;

                if (oldToNewVertexInstanceMap != null)
                {
                    if (!oldToNewVertexInstanceMap.TryGetValue(oldVertex, out newVertex))
                    {
                        newVertex = verticesFactory.GetInstance(
                            oldVertex.Select(e => AdjacentEdge.Create(e.Destination, targetEdgeDataSelector.Invoke(e.Data))),
                            oldVertex.Count);

                        oldToNewVertexInstanceMap.Add(oldVertex, newVertex);
                    }
                }
                else
                {
                    newVertex = verticesFactory.GetInstance(
                        oldVertex.Select(e => AdjacentEdge.Create(e.Destination, targetEdgeDataSelector.Invoke(e.Data))),
                        oldVertex.Count);
                }

                newVertices[idx] = newVertex;
            }

            return(CreateEmptyTailWrapperOf(newVertices, oldVertices.Count));
        }
 /// <summary>Determines whether the source vertex has empty edge data (of <see cref="EmptyValue"/> type).</summary>
 /// <typeparam name="TEdgeData">The type of the edge data.</typeparam>
 /// <param name="source">The source.</param>
 /// <returns><c>true</c> if the edge data is of <see cref="EmptyValue"/>; otherwise, <c>false</c>.</returns>
 public static bool HasEmptyEdgeData <TEdgeData>(this VertexAdjacency <TEdgeData> _)
 {
     return(EmptyValue.IsEmptyValueType <TEdgeData>());
 }