diff --git a/src/Graphs.jl b/src/Graphs.jl index 86bc0946..982974d1 100644 --- a/src/Graphs.jl +++ b/src/Graphs.jl @@ -463,6 +463,7 @@ and tutorials are available at the Graphs include("interface.jl") include("utils.jl") +include("frozenvector.jl") include("deprecations.jl") include("core.jl") diff --git a/src/SimpleGraphs/SimpleGraphs.jl b/src/SimpleGraphs/SimpleGraphs.jl index 7c2589d7..242ff35c 100644 --- a/src/SimpleGraphs/SimpleGraphs.jl +++ b/src/SimpleGraphs/SimpleGraphs.jl @@ -15,6 +15,7 @@ import Graphs: AbstractGraph, AbstractEdge, AbstractEdgeIter, + FrozenVector, src, dst, edgetype, @@ -152,8 +153,8 @@ add_edge!(g::AbstractSimpleGraph, x) = add_edge!(g, edgetype(g)(x)) has_edge(g::AbstractSimpleGraph, x, y) = has_edge(g, edgetype(g)(x, y)) add_edge!(g::AbstractSimpleGraph, x, y) = add_edge!(g, edgetype(g)(x, y)) -inneighbors(g::AbstractSimpleGraph, v::Integer) = badj(g, v) -outneighbors(g::AbstractSimpleGraph, v::Integer) = fadj(g, v) +inneighbors(g::AbstractSimpleGraph, v::Integer) = FrozenVector(badj(g, v)) +outneighbors(g::AbstractSimpleGraph, v::Integer) = FrozenVector(fadj(g, v)) function issubset(g::T, h::T) where {T<:AbstractSimpleGraph} nv(g) <= nv(h) || return false diff --git a/src/core.jl b/src/core.jl index cb8abd17..95ca786c 100644 --- a/src/core.jl +++ b/src/core.jl @@ -220,9 +220,10 @@ For directed graphs, the default is equivalent to [`outneighbors`](@ref); use [`all_neighbors`](@ref) to list inbound and outbound neighbors. ### Implementation Notes -Returns a reference to the current graph's internal structures, not a copy. -Do not modify result. If the graph is modified, the behavior is undefined: +In some cases might return a reference to the current graph's internal structures, +not a copy. Do not modify result. If the graph is modified, the behavior is undefined: the array behind this reference may be modified too, but this is not guaranteed. +If you need to modify the result use `collect` or `copy` to create a copy. # Examples ```jldoctest @@ -235,14 +236,14 @@ julia> add_edge!(g, 2, 3); julia> add_edge!(g, 3, 1); julia> neighbors(g, 1) -Int64[] +0-element Graphs.FrozenVector{Int64} julia> neighbors(g, 2) -1-element Vector{Int64}: +1-element Graphs.FrozenVector{Int64}: 3 julia> neighbors(g, 3) -1-element Vector{Int64}: +1-element Graphs.FrozenVector{Int64}: 1 ``` """ @@ -256,9 +257,10 @@ For undirected graphs, this is equivalent to both [`outneighbors`](@ref) and [`inneighbors`](@ref). ### Implementation Notes -Returns a reference to the current graph's internal structures, not a copy. -Do not modify result. If the graph is modified, the behavior is undefined: +In some cases might return a reference to the current graph's internal structures, +not a copy. Do not modify result. If the graph is modified, the behavior is undefined: the array behind this reference may be modified too, but this is not guaranteed. +If you need to modify the result use `collect` or `copy` to create a copy. # Examples ```jldoctest diff --git a/src/frozenvector.jl b/src/frozenvector.jl new file mode 100644 index 00000000..701a4c27 --- /dev/null +++ b/src/frozenvector.jl @@ -0,0 +1,23 @@ +""" + FrozenVector(v::Vector) <: AbstractVector + +A data structure that wraps a `Vector` but does not allow modifications. +""" +struct FrozenVector{T} <: AbstractVector{T} + wrapped::Vector{T} +end + +Base.size(v::FrozenVector) = Base.size(v.wrapped) + +Base.@propagate_inbounds Base.getindex(v::FrozenVector, i::Int) = Base.getindex(v.wrapped, i) + +Base.IndexStyle(v::Type{FrozenVector{T}}) where {T} = Base.IndexStyle(Vector{T}) + +Base.iterate(v::FrozenVector) = Base.iterate(v.wrapped) +Base.iterate(v::FrozenVector, state) = Base.iterate(v.wrapped, state) + +Base.similar(v::FrozenVector) = Base.similar(v.wrapped) +Base.similar(v::FrozenVector, T::Type) = Base.similar(v.wrapped, T) +Base.similar(v::FrozenVector, T::Type, dims::Base.Dims) = Base.similar(v.wrapped, T, dims) + +Base.copy(v::FrozenVector) = Base.copy(v.wrapped) diff --git a/src/interface.jl b/src/interface.jl index 280efcb2..695b46db 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -281,9 +281,10 @@ has_edge(g, e) = has_edge(g, src(e), dst(e)) Return a list of all neighbors connected to vertex `v` by an incoming edge. ### Implementation Notes -Returns a reference to the current graph's internal structures, not a copy. -Do not modify result. If the graph is modified, the behavior is undefined: +In some cases might return a reference to the current graph's internal structures, +not a copy. Do not modify result. If the graph is modified, the behavior is undefined: the array behind this reference may be modified too, but this is not guaranteed. +If you need to modify the result use `collect` or `copy` to create a copy. # Examples ```jldoctest @@ -292,7 +293,7 @@ julia> using Graphs julia> g = SimpleDiGraph([0 1 0 0 0; 0 0 1 0 0; 1 0 0 1 0; 0 0 0 0 1; 0 0 0 1 0]); julia> inneighbors(g, 4) -2-element Vector{Int64}: +2-element Graphs.FrozenVector{Int64}: 3 5 ``` @@ -305,9 +306,10 @@ inneighbors(x, v) = _NI("inneighbors") Return a list of all neighbors connected to vertex `v` by an outgoing edge. # Implementation Notes -Returns a reference to the current graph's internal structures, not a copy. -Do not modify result. If the graph is modified, the behavior is undefined: +In some cases might return a reference to the current graph's internal structures, +not a copy. Do not modify result. If the graph is modified, the behavior is undefined: the array behind this reference may be modified too, but this is not guaranteed. +If you need to modify the result use `collect` or `copy` to create a copy. # Examples ```jldoctest @@ -316,7 +318,7 @@ julia> using Graphs julia> g = SimpleDiGraph([0 1 0 0 0; 0 0 1 0 0; 1 0 0 1 0; 0 0 0 0 1; 0 0 0 1 0]); julia> outneighbors(g, 4) -1-element Vector{Int64}: +1-element Graphs.FrozenVector{Int64}: 5 ``` """