Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve MutableLinkedList for 1.0 #873

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

laborg
Copy link
Collaborator

@laborg laborg commented Oct 13, 2023

It started as a simple inspection into MutableLinkedList and ended into a thorough refactoring of the code. As a consequence bugs have been fixed, and the API is now in alignment with Base.

  • refactored: reduce code duplication by introducin a couple of functions basic (_insert, _remove!, _traverse)
  • refactored: removed @boundscheck: traversal (=indexing) is O(n), so the @boundscheck are not going to be a big deal.
  • improvement: depending on the index it will either traverse the list from front or from the back
  • improvement: show() is now limited to the space given and has the same apperance as Vector
  • added: verbose, readable tests for functions and a comparison of all functions against Vector{T}()
  • added: append!(l,collections...)
  • added: filter!(f,l)
  • added: reverse!(l)
  • added: empty!(l)
  • added: splice!(l,idx)
  • added: splice!(l,range) there is another PR for splice! but I found that it was flawed
  • added: constructor MutableLinkedList(iter) without a type parameter infers the eltype from iter
  • changed: last and first return a BoundsError if the list is empty instead of an ArgumentError to mirror Vector
  • changed: popat!(l,idx) throws a BoundsError if the list is emtpy instead of an ArgumentError to mirror Vector
  • deprecated: delete! has been deprecated to deleteat!
  • fixed: allow i:j with j <= i for delete
  • fixed: append!() will not mutate the last element

Fixes

Supersedes:

In case this gets merge it needs to be squashed, the single commits aren't useful on their own.

Copy link
Member

@oxinabox oxinabox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor feedback.
I have given you merge rights so merge this when you are happy and mark this file done in the issue

Comment on lines +26 to +36
function Base.delete!(l::MutableLinkedList, idx)
Expr(:meta, :noinline)
Base.depwarn("`delete!(l::MutableLinkedList,idx::Int)` is deprecated, use `deleteat!(l,idx)` instead.", :delete!)
deleteat!(l,idx)
end

function Base.delete!(l::MutableLinkedList, r::UnitRange)
Expr(:meta, :noinline)
Base.depwarn("`delete!(l::MutableLinkedList,r::UnitRange)` is deprecated, use `deleteat!(l,idx)` instead.", :delete!)
deleteat!(l,r)
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't this be done with the @deprecate macro?


Base.iterate(l::MutableLinkedList) = l.len == 0 ? nothing : (l.node.next.data, l.node.next.next)
Base.iterate(l::MutableLinkedList, n::ListNode) = n === l.node ? nothing : (n.data, n.next)

Base.isempty(l::MutableLinkedList) = l.len == 0
Base.length(l::MutableLinkedList) = l.len
Base.collect(l::MutableLinkedList{T}) where T = T[x for x in l]
Base.eltype(::Type{<:MutableLinkedList{T}}) where T = T
Base.collect(l::MutableLinkedList{T}) where {T} = T[x for x in l]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this?
I would have thought it would fall back to this if we didn't define it.

length(l1) == length(l2) || return false
for (i, j) in zip(l1, l2)
i == j || return false
end
return true
end

function Base.map(f::Base.Callable, l::MutableLinkedList{T}) where T
function Base.map(f::Base.Callable, l::MutableLinkedList{T}) where {T}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to strip out a lot of these constraints that do not follow modern practices.

Suggested change
function Base.map(f::Base.Callable, l::MutableLinkedList{T}) where {T}
function Base.map(f, l::MutableLinkedList{T}) where {T}

@@ -89,162 +113,227 @@ function Base.map(f::Base.Callable, l::MutableLinkedList{T}) where T
end
end

function Base.filter(f::Function, l::MutableLinkedList{T}) where T
function Base.filter(f::Function, l::MutableLinkedList{T}) where {T}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function Base.filter(f::Function, l::MutableLinkedList{T}) where {T}
function Base.filter(f, l::MutableLinkedList{T}) where {T}

@laborg
Copy link
Collaborator Author

laborg commented Oct 26, 2023

minor feedback. I have given you merge rights so merge this when you are happy and mark this file done in the issue

Thanks for the review. As soon as I've time I'll look into your recommendations. In the meantime: I can't merge the PR via user interface. Shouldn't this work since you gave me merge rights? Nevermind, the existing conflicts will probably prevent merging.

@JordiManyer
Copy link

Hi! Is this PR alive?

I am running into issues, where append! for linked lists is still broken on the relase version v0.18.20 but not broken on the master branch. Is there any intention of merging this at some point? Or releasing a version of the package where the append! but is fixed?

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants