diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 000000000..4861be137 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,54 @@ +name: CI +on: + pull_request: + push: + branches: + - release-0.18 + tags: '*' + +concurrency: + # group by workflow and ref; the last slightly strange component ensures that for pull + # requests, we limit to 1 concurrent job, but for the default repository branch we don't + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.ref_name != github.event.repository.default_branch || github.run_number }} + # Cancel intermediate builds, but only if it is a pull request build. + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} + +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.0' + - '1' +# - 'nightly' + os: + - ubuntu-latest + - macos-latest + - windows-latest + arch: + - '' + exclude: + - os: macos-latest # Apple Silicon + version: '1.0' + arch: '' + include: + - os: macos-latest # Apple Silicon + version: '1.0' + # Install an x86_64 build of Julia, and run it under Rosetta 2 emulation + arch: 'x64' + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: ${{ matrix.version }} + arch: ${{ (matrix.arch == '') && runner.arch || matrix.arch }} + - uses: julia-actions/cache@v2 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/Documenter.yml b/.github/workflows/Documenter.yml new file mode 100644 index 000000000..f5ad19980 --- /dev/null +++ b/.github/workflows/Documenter.yml @@ -0,0 +1,29 @@ +name: Documenter +on: + push: + branches: [main, master] + tags: ["v*"] + pull_request: + workflow_dispatch: + +permissions: + actions: write # needed to allow julia-actions/cache to delete old caches that it has created + contents: write # needed to allow deploying docs + statuses: write + +jobs: + Documenter: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v2 + with: + version: '1' # replace this with whatever version you need + show-versioninfo: true # this causes versioninfo to be printed to the action log + - uses: julia-actions/cache@v2 # cache using https://github.com/julia-actions/cache + - uses: julia-actions/julia-buildpkg@v1 # if package requires Pkg.build() + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml index d77d3a0c3..7cb7ca2da 100644 --- a/.github/workflows/TagBot.yml +++ b/.github/workflows/TagBot.yml @@ -1,11 +1,31 @@ name: TagBot on: - schedule: - - cron: 0 * * * * + issue_comment: + types: + - created + workflow_dispatch: + inputs: + lookback: + default: 3 +# permissions: +# actions: read +# checks: read +# contents: write +# deployments: read +# issues: read +# discussions: read +# packages: read +# pages: read +# pull-requests: read +# repository-projects: read +# security-events: read +# statuses: read jobs: TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' runs-on: ubuntu-latest steps: - uses: JuliaRegistries/TagBot@v1 with: token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 6b53b3bf9..000000000 --- a/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -# Documentation: http://docs.travis-ci.com/user/languages/julia/ -language: julia -os: - - linux - - osx -julia: - - 1.0 - - nightly -notifications: - email: false -# uncomment the following lines to override the default test script -#script: -# - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi -# - julia -e 'Pkg.clone(pwd()); Pkg.build("DataStructures"); Pkg.test("DataStructures"; coverage=true)' -after_success: - # push coverage results to Coveralls - - julia -e 'import Pkg; cd(Pkg.dir("DataStructures")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())' - # push coverage results to Codecov - - julia -e 'import Pkg; cd(Pkg.dir("DataStructures")); Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())' -# Documenter auto-deploy -# https://juliadocs.github.io/Documenter.jl/stable/man/hosting/#.travis.yml-Configuration-1 -jobs: - allow_failures: - - julia: nightly - include: - - name: "Benchmark" - julia: 1.2 - os: linux - before_script: - - git fetch origin '+refs/heads/master:refs/remotes/origin/master' - - git branch baseline origin/master - # Run benchmark outside `script` so that it's hidden by default: - - julia --project=benchmark -e ' - using Pkg; Pkg.instantiate(); - include("benchmark/runjudge.jl");' - - script: - - julia --project=benchmark -e ' - using Pkg; Pkg.instantiate(); - include("benchmark/pprintjudge.jl");' - after_success: skip - if: type = pull_request - - stage: "Documentation" - julia: 1.2 - os: linux - script: - - julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); - Pkg.instantiate()' - - julia --project=docs/ docs/make.jl - after_success: skip diff --git a/Project.toml b/Project.toml index 5e79352bb..622a6559e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,6 @@ name = "DataStructures" uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" -version = "0.18.8" - +version = "0.18.22" [deps] Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" @@ -9,7 +8,7 @@ InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" [compat] -Compat = "3.0.0" +Compat = "3,4" OrderedCollections = "1.1.0" julia = "1" diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 55ef8a7fb..000000000 --- a/appveyor.yml +++ /dev/null @@ -1,36 +0,0 @@ -environment: - matrix: - - julia_version: 1.0 - - julia_version: latest - -platform: - - x86 # 32-bit - - x64 # 64-bit - -## uncomment the following lines to allow failures on nightly julia -## (tests will run but not make your overall status red) -matrix: - allow_failures: - - julia_version: latest - -branches: - only: - - master - - /release-.*/ - -notifications: - - provider: Email - on_build_success: false - on_build_failure: false - on_build_status_changed: false - -install: - - ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1")) - -build_script: - - echo "%JL_BUILD_SCRIPT%" - - C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%" - -test_script: - - echo "%JL_TEST_SCRIPT%" - - C:\julia\bin\julia -e "%JL_TEST_SCRIPT%" diff --git a/docs/Project.toml b/docs/Project.toml index d7906fcfe..1814eb330 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,4 +2,4 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" [compat] -Documenter = "0.23" +Documenter = "1" diff --git a/docs/make.jl b/docs/make.jl index ca04d6658..7b483bbc8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,6 +5,7 @@ DocMeta.setdocmeta!(DataStructures, :DocTestSetup, :(using DataStructures); recu makedocs( sitename = "DataStructures.jl", + warnonly = true, # FIXME: address all warnings and resolve them pages = [ "index.md", "deque.md", diff --git a/docs/src/priority-queue.md b/docs/src/priority-queue.md index 4958f652c..4f1a107a7 100644 --- a/docs/src/priority-queue.md +++ b/docs/src/priority-queue.md @@ -33,14 +33,14 @@ julia> # Julia code julia> # Insert keys with associated priorities pq["a"] = 10; pq["b"] = 5; pq["c"] = 15; pq -PriorityQueue{Any,Any,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{Any, Any, Base.Order.ForwardOrdering} with 3 entries: "b" => 5 "a" => 10 "c" => 15 julia> # Change the priority of an existing key pq["a"] = 0; pq -PriorityQueue{Any,Any,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{Any, Any, Base.Order.ForwardOrdering} with 3 entries: "a" => 0 "b" => 5 "c" => 15 diff --git a/docs/src/robin_dict.md b/docs/src/robin_dict.md index eee655634..849e308e0 100644 --- a/docs/src/robin_dict.md +++ b/docs/src/robin_dict.md @@ -13,14 +13,14 @@ Examples: ```jldoctest julia> d = RobinDict{Int, Char}(1 => 'a', 2 => 'b') -RobinDict{Int64,Char} with 2 entries: +RobinDict{Int64, Char} with 2 entries: 2 => 'b' 1 => 'a' julia> d[3] = 'c'; julia> collect(d) -3-element Array{Pair{Int64,Char},1}: +3-element Vector{Pair{Int64, Char}}: 2 => 'b' 3 => 'c' 1 => 'a' @@ -31,7 +31,7 @@ julia> d[1] 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase) julia> d -RobinDict{Int64,Char} with 2 entries: +RobinDict{Int64, Char} with 2 entries: 3 => 'c' 1 => 'a' diff --git a/docs/src/swiss_dict.md b/docs/src/swiss_dict.md index b620404d8..916de95a0 100644 --- a/docs/src/swiss_dict.md +++ b/docs/src/swiss_dict.md @@ -12,14 +12,14 @@ Examples: ```jldoctest julia> d = SwissDict(1 => 'a', 2 => 'b') -SwissDict{Int64,Char} with 2 entries: +SwissDict{Int64, Char} with 2 entries: 1 => 'a' 2 => 'b' julia> d[3] = 'c'; julia> collect(d) -3-element Array{Pair{Int64,Char},1}: +3-element Vector{Pair{Int64, Char}}: 1 => 'a' 2 => 'b' 3 => 'c' @@ -30,7 +30,7 @@ julia> d[1] 'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase) julia> d -SwissDict{Int64,Char} with 2 entries: +SwissDict{Int64, Char} with 2 entries: 1 => 'a' 3 => 'c' diff --git a/src/DataStructures.jl b/src/DataStructures.jl index c9d386f39..b94be869b 100644 --- a/src/DataStructures.jl +++ b/src/DataStructures.jl @@ -112,4 +112,10 @@ module DataStructures include("splay_tree.jl") include("deprecations.jl") -end \ No newline at end of file + + @static if VERSION <= v"1.3" + _unsetindex!(a, i) = a + else + import Base._unsetindex! + end +end diff --git a/src/accumulator.jl b/src/accumulator.jl index c9fab92e4..015b0ebfd 100644 --- a/src/accumulator.jl +++ b/src/accumulator.jl @@ -55,8 +55,6 @@ Base.setindex!(ct::Accumulator, x, v) = setindex!(ct.map, x, v) Base.haskey(ct::Accumulator, x) = haskey(ct.map, x) -Base.keys(ct::Accumulator) = keys(ct.map) - Base.values(ct::Accumulator) = values(ct.map) Base.sum(ct::Accumulator) = sum(values(ct.map)) diff --git a/src/balanced_tree.jl b/src/balanced_tree.jl index 13d15e575..81cf7c83d 100644 --- a/src/balanced_tree.jl +++ b/src/balanced_tree.jl @@ -354,6 +354,7 @@ end ## done whether the iterm ## is already in the tree, so insertion of a new item always succeeds. + function Base.insert!(t::BalancedTree23{K,D,Ord}, k, d, allowdups::Bool) where {K,D,Ord <: Ordering} ## First we find the greatest data node that is <= k. @@ -395,134 +396,122 @@ function Base.insert!(t::BalancedTree23{K,D,Ord}, k, d, allowdups::Bool) where { ## go back and fix the parent. newind = push_or_reuse!(t.data, t.freedatainds, KDRec{K,D}(0,k,d)) + push!(t.useddatacells, newind) p1 = parent - oldchild = leafind newchild = newind minkeynewchild = k splitroot = false curdepth = depth + existingchild = leafind + ## This loop ascends the tree (i.e., follows the path from a leaf to the root) ## starting from the parent p1 of - ## where the new key k would go. For each 3-node we encounter + ## where the new key k will go. + ## Variables updated by the loop: + ## p1: parent of where the new node goes + ## newchild: index of the child to be inserted + ## minkeynewchild: the minimum key in the subtree rooted at newchild + ## existingchild: a child of p1; the newchild must + ## be inserted in the slot to the right of existingchild + ## curdepth: depth of newchild + ## For each 3-node we encounter ## during the ascent, we add a new child, which requires splitting ## the 3-node into two 2-nodes. Then we keep going until we hit the root. ## If we encounter a 2-node, then the ascent can stop; we can - ## change the 2-node to a 3-node with the new child. Invariants - ## during this loop are: - ## p1: the parent node (a tree node index) where the insertion must occur - ## oldchild,newchild: the two children of the parent node; oldchild - ## was already in the tree; newchild was just added to it. - ## minkeynewchild: This is the key that is the minimum value in - ## the subtree rooted at newchild. - - while t.tree[p1].child3 > 0 - isleaf = (curdepth == depth) - oldtreenode = t.tree[p1] - - ## Node p1 index a 3-node. There are three cases for how to - ## insert new child. All three cases involve splitting the - ## existing node (oldtreenode, numbered p1) into - ## two new nodes. One keeps the index p1; the other has - ## has a new index called newparentnum. - - - cmp = isleaf ? cmp3_leaf(ord, oldtreenode, minkeynewchild) : - cmp3_nonleaf(ord, oldtreenode, minkeynewchild) - - if cmp == 1 - lefttreenodenew = TreeNode{K}(oldtreenode.child1, newchild, 0, - oldtreenode.parent, - minkeynewchild, minkeynewchild) - righttreenodenew = TreeNode{K}(oldtreenode.child2, oldtreenode.child3, 0, - oldtreenode.parent, oldtreenode.splitkey2, - oldtreenode.splitkey2) - minkeynewchild = oldtreenode.splitkey1 - whichp = 1 - elseif cmp == 2 - lefttreenodenew = TreeNode{K}(oldtreenode.child1, oldtreenode.child2, 0, - oldtreenode.parent, - oldtreenode.splitkey1, oldtreenode.splitkey1) - righttreenodenew = TreeNode{K}(newchild, oldtreenode.child3, 0, - oldtreenode.parent, - oldtreenode.splitkey2, oldtreenode.splitkey2) - whichp = 2 + ## change the 2-node to a 3-node with the new child. + + while true + + + # Let newchild1,...newchild4 be the new children of + # the parent node + # Initially, take the three children of the existing parent + # node and set newchild4 to 0. + + newchild1 = t.tree[p1].child1 + newchild2 = t.tree[p1].child2 + minkeychild2 = t.tree[p1].splitkey1 + newchild3 = t.tree[p1].child3 + minkeychild3 = t.tree[p1].splitkey2 + p1parent = t.tree[p1].parent + newchild4 = 0 + + # Now figure out which of the 4 children is the new node + # and insert it into newchild1 ... newchild4 + + if newchild1 == existingchild + newchild4 = newchild3 + minkeychild4 = minkeychild3 + newchild3 = newchild2 + minkeychild3 = minkeychild2 + newchild2 = newchild + minkeychild2 = minkeynewchild + elseif newchild2 == existingchild + newchild4 = newchild3 + minkeychild4 = minkeychild3 + newchild3 = newchild + minkeychild3 = minkeynewchild + elseif newchild3 == existingchild + newchild4 = newchild + minkeychild4 = minkeynewchild else - lefttreenodenew = TreeNode{K}(oldtreenode.child1, oldtreenode.child2, 0, - oldtreenode.parent, - oldtreenode.splitkey1, oldtreenode.splitkey1) - righttreenodenew = TreeNode{K}(oldtreenode.child3, newchild, 0, - oldtreenode.parent, - minkeynewchild, minkeynewchild) - minkeynewchild = oldtreenode.splitkey2 - whichp = 2 + throw(AssertionError("Tree structure is corrupted 1")) + end + + # Two cases: either we need to split the tree node + # if newchild4>0 else we convert a 2-node to a 3-node + # if newchild4==0 + + if newchild4 == 0 + # Change the parent from a 2-node to a 3-node + t.tree[p1] = TreeNode{K}(newchild1, newchild2, newchild3, + p1parent, minkeychild2, minkeychild3) + if curdepth == depth + replaceparent!(t.data, newchild, p1) + else + replaceparent!(t.tree, newchild, p1) + end + break end - # Replace p1 with a new 2-node and insert another 2-node at - # index newparentnum. - t.tree[p1] = lefttreenodenew - newparentnum = push_or_reuse!(t.tree, t.freetreeinds, righttreenodenew) - if isleaf - par = (whichp == 1) ? p1 : newparentnum - # fix the parent of the new datanode. - replaceparent!(t.data, newind, par) - push!(t.useddatacells, newind) - replaceparent!(t.data, righttreenodenew.child1, newparentnum) - replaceparent!(t.data, righttreenodenew.child2, newparentnum) + # Split the parent + t.tree[p1] = TreeNode{K}(newchild1, newchild2, 0, + p1parent, minkeychild2, minkeychild2) + newtreenode = TreeNode{K}(newchild3, newchild4, 0, + p1parent, minkeychild4, minkeychild2) + newparentnum = push_or_reuse!(t.tree, t.freetreeinds, newtreenode) + if curdepth == depth + replaceparent!(t.data, newchild2, p1) + replaceparent!(t.data, newchild3, newparentnum) + replaceparent!(t.data, newchild4, newparentnum) else - # If this is not a leaf, we still have to fix the - # parent fields of the two nodes that are now children - ## of the newparent. - replaceparent!(t.tree, righttreenodenew.child1, newparentnum) - replaceparent!(t.tree, righttreenodenew.child2, newparentnum) + replaceparent!(t.tree, newchild2, p1) + replaceparent!(t.tree, newchild3, newparentnum) + replaceparent!(t.tree, newchild4, newparentnum) end - oldchild = p1 + # Update the loop variables for the next level of the + # ascension + existingchild = p1 newchild = newparentnum - ## If p1 is the root (i.e., we have encountered only 3-nodes during - ## our ascent of the tree), then the root must be split. - if p1 == t.rootloc - @invariant curdepth == 1 + p1 = p1parent + minkeynewchild = minkeychild3 + curdepth -= 1 + if curdepth == 0 splitroot = true break end - p1 = t.tree[oldchild].parent - curdepth -= 1 end - ## big loop terminated either because a 2-node was reached - ## (splitroot == false) or we went up the whole tree seeing - ## only 3-nodes (splitroot == true). - if !splitroot - - ## If our ascent reached a 2-node, then we convert it to - ## a 3-node by giving it a child3 field that is >0. - ## Encountering a 2-node halts the ascent up the tree. - - isleaf = curdepth == depth - oldtreenode = t.tree[p1] - cmpres = isleaf ? cmp2_leaf(ord, oldtreenode, minkeynewchild) : - cmp2_nonleaf(ord, oldtreenode, minkeynewchild) - - - t.tree[p1] = cmpres == 1 ? - TreeNode{K}(oldtreenode.child1, newchild, oldtreenode.child2, - oldtreenode.parent, - minkeynewchild, oldtreenode.splitkey1) : - TreeNode{K}(oldtreenode.child1, oldtreenode.child2, newchild, - oldtreenode.parent, - oldtreenode.splitkey1, minkeynewchild) - if isleaf - replaceparent!(t.data, newind, p1) - push!(t.useddatacells, newind) - end - else - ## Splitroot is set if the ascent of the tree encountered only 3-nodes. - ## In this case, the root itself was replaced by two nodes, so we need - ## a new root above those two. + # If the root has been split, then we need to add a level + # to the tree that is the parent of the old root and the new node. - newroot = TreeNode{K}(oldchild, newchild, 0, 0, - minkeynewchild, minkeynewchild) + if splitroot + @invariant existingchild == t.rootloc + newroot = TreeNode{K}(existingchild, newchild, 0, + 0, minkeynewchild, minkeynewchild) + newrootloc = push_or_reuse!(t.tree, t.freetreeinds, newroot) - replaceparent!(t.tree, oldchild, newrootloc) + replaceparent!(t.tree, existingchild, newrootloc) replaceparent!(t.tree, newchild, newrootloc) t.rootloc = newrootloc t.depth += 1 @@ -615,7 +604,7 @@ end ##, 1 if i2 precedes i1. function compareInd(t::BalancedTree23, i1::Int, i2::Int) - @assert(i1 in t.useddatacells && i2 in t.useddatacells) + @invariant(i1 in t.useddatacells && i2 in t.useddatacells) if i1 == i2 return 0 end @@ -624,6 +613,7 @@ function compareInd(t::BalancedTree23, i1::Int, i2::Int) p1 = t.data[i1].parent p2 = t.data[i2].parent @invariant_support_statement curdepth = t.depth + curdepth = t.depth while true @invariant curdepth > 0 if p1 == p2 @@ -647,6 +637,7 @@ function compareInd(t::BalancedTree23, i1::Int, i2::Int) p1 = t.tree[i1a].parent p2 = t.tree[i2a].parent @invariant_support_statement curdepth -= 1 + curdepth -= 1 end end diff --git a/src/circ_deque.jl b/src/circ_deque.jl index 3159d7d6a..6c03e8463 100644 --- a/src/circ_deque.jl +++ b/src/circ_deque.jl @@ -63,6 +63,7 @@ end @inline Base.@propagate_inbounds function Base.pop!(D::CircularDeque) v = last(D) + _unsetindex!(D.buffer, D.last) # see issue/884 D.n -= 1 tmp = D.last - 1 D.last = ifelse(tmp < 1, D.capacity, tmp) @@ -90,6 +91,7 @@ Remove the element at the front. """ @inline Base.@propagate_inbounds function Base.popfirst!(D::CircularDeque) v = first(D) + _unsetindex!(D.buffer, D.first) # see issue/884 D.n -= 1 tmp = D.first + 1 D.first = ifelse(tmp > D.capacity, 1, tmp) diff --git a/src/circular_buffer.jl b/src/circular_buffer.jl index 3d991cd61..bab84e39e 100644 --- a/src/circular_buffer.jl +++ b/src/circular_buffer.jl @@ -154,8 +154,6 @@ Return the number of elements currently in the buffer. """ Base.length(cb::CircularBuffer) = cb.length -Base.eltype(::Type{CircularBuffer{T}}) where T = T - """ size(cb::CircularBuffer) @@ -163,8 +161,6 @@ Return a tuple with the size of the buffer. """ Base.size(cb::CircularBuffer) = (length(cb),) -Base.convert(::Type{Array}, cb::CircularBuffer{T}) where {T} = T[x for x in cb] - """ isempty(cb::CircularBuffer) @@ -179,6 +175,11 @@ Return capacity of CircularBuffer. """ capacity(cb::CircularBuffer) = cb.capacity +# Base might define `isfull` from julia 1.11 onwards, see julia PR #53159 +if isdefined(Base, :isfull) + import Base: isfull +end + """ isfull(cb::CircularBuffer) diff --git a/src/deque.jl b/src/deque.jl index dd6c0b503..5ae47459a 100644 --- a/src/deque.jl +++ b/src/deque.jl @@ -276,6 +276,7 @@ function Base.pop!(q::Deque{T}) where T @assert rear.back >= rear.front @inbounds x = rear.data[rear.back] + _unsetindex!(rear.data, rear.back) # see issue/884 rear.back -= 1 if rear.back < rear.front if q.nblocks > 1 @@ -301,6 +302,7 @@ function Base.popfirst!(q::Deque{T}) where T @assert head.back >= head.front @inbounds x = head.data[head.front] + _unsetindex!(head.data, head.front) # see issue/884 head.front += 1 if head.back < head.front if q.nblocks > 1 diff --git a/src/heaps/arrays_as_heaps.jl b/src/heaps/arrays_as_heaps.jl index b2202bea0..9911de879 100644 --- a/src/heaps/arrays_as_heaps.jl +++ b/src/heaps/arrays_as_heaps.jl @@ -2,6 +2,7 @@ using Base.Order: Forward, Ordering, lt +const DefaultReverseOrdering = Base.ReverseOrdering{Base.ForwardOrdering} # Heap operations on flat arrays # ------------------------------ @@ -44,7 +45,7 @@ function percolate_up!(xs::AbstractArray, i::Integer, x=xs[i], o::Ordering=Forwa xs[i] = x end -percolate_up!(xs::AbstractArray, i::Integer, o::Ordering) = percolate_up!(xs, i, xs[i], o) +@inline percolate_up!(xs::AbstractArray, i::Integer, o::Ordering) = percolate_up!(xs, i, xs[i], o) """ heappop!(v, [ord]) @@ -67,7 +68,7 @@ end Given a binary heap-ordered array, push a new element `x`, preserving the heap property. For efficiency, this function does not check that the array is indeed heap-ordered. """ -function heappush!(xs::AbstractArray, x, o::Ordering=Forward) +@inline function heappush!(xs::AbstractArray, x, o::Ordering=Forward) push!(xs, x) percolate_up!(xs, length(xs), o) return xs @@ -80,7 +81,7 @@ end In-place [`heapify`](@ref). """ -function heapify!(xs::AbstractArray, o::Ordering=Forward) +@inline function heapify!(xs::AbstractArray, o::Ordering=Forward) for i in heapparent(length(xs)):-1:1 percolate_down!(xs, i, o) end @@ -121,7 +122,7 @@ Return `true` if an array is heap-ordered according to the given order. ```jldoctest julia> a = [1,2,3] -3-element Array{Int64,1}: +3-element Vector{Int64}: 1 2 3 diff --git a/src/heaps/binary_heap.jl b/src/heaps/binary_heap.jl index 503852e92..9edf718ab 100644 --- a/src/heaps/binary_heap.jl +++ b/src/heaps/binary_heap.jl @@ -50,8 +50,6 @@ BinaryHeap(ordering::Base.Ordering, xs::AbstractVector{T}) where T = BinaryHeap{ BinaryHeap{T, O}() where {T, O<:Base.Ordering} = BinaryHeap{T}(O()) BinaryHeap{T, O}(xs::AbstractVector) where {T, O<:Base.Ordering} = BinaryHeap{T}(O(), xs) -const DefaultReverseOrdering = Base.ReverseOrdering{Base.ForwardOrdering} - # These constructors needed for BinaryMaxHeap, until we have https://github.com/JuliaLang/julia/pull/37822 BinaryHeap{T, DefaultReverseOrdering}() where {T} = BinaryHeap{T}(Base.Reverse) BinaryHeap{T, DefaultReverseOrdering}(xs::AbstractVector) where {T} = BinaryHeap{T}(Base.Reverse, xs) @@ -89,7 +87,7 @@ Base.isempty(h::BinaryHeap) = isempty(h.valtree) Adds the `value` element to the heap `h`. """ -function Base.push!(h::BinaryHeap, v) +@inline function Base.push!(h::BinaryHeap, v) heappush!(h.valtree, v, h.ordering) return h end diff --git a/src/heaps/mutable_binary_heap.jl b/src/heaps/mutable_binary_heap.jl index cc6525de7..699aa538c 100644 --- a/src/heaps/mutable_binary_heap.jl +++ b/src/heaps/mutable_binary_heap.jl @@ -179,9 +179,13 @@ MutableBinaryHeap(ordering::Base.Ordering, xs::AbstractVector{T}) where T = Muta MutableBinaryHeap{T, O}() where {T, O<:Base.Ordering} = MutableBinaryHeap{T}(O()) MutableBinaryHeap{T, O}(xs::AbstractVector) where {T, O<:Base.Ordering} = MutableBinaryHeap{T}(O(), xs) +# These constructors needed for BinaryMaxHeap, until we have https://github.com/JuliaLang/julia/pull/37822 +MutableBinaryHeap{T, DefaultReverseOrdering}() where {T} = MutableBinaryHeap{T}(Base.Reverse) +MutableBinaryHeap{T, DefaultReverseOrdering}(xs::AbstractVector) where {T} = MutableBinaryHeap{T}(Base.Reverse, xs) + # Forward/reverse ordering type aliases const MutableBinaryMinHeap{T} = MutableBinaryHeap{T, Base.ForwardOrdering} -const MutableBinaryMaxHeap{T} = MutableBinaryHeap{T, Base.ReverseOrdering} +const MutableBinaryMaxHeap{T} = MutableBinaryHeap{T, DefaultReverseOrdering} MutableBinaryMinHeap(xs::AbstractVector{T}) where T = MutableBinaryMinHeap{T}(xs) MutableBinaryMaxHeap(xs::AbstractVector{T}) where T = MutableBinaryMaxHeap{T}(xs) diff --git a/src/mutable_list.jl b/src/mutable_list.jl index 13b8827b7..27e8c2fa4 100644 --- a/src/mutable_list.jl +++ b/src/mutable_list.jl @@ -68,7 +68,7 @@ end function Base.map(f::Base.Callable, l::MutableLinkedList{T}) where T if isempty(l) && f isa Function - S = Core.Compiler.return_type(f, (T,)) + S = Core.Compiler.return_type(f, Tuple{T}) return MutableLinkedList{S}() elseif isempty(l) && f isa Type return MutableLinkedList{f}() diff --git a/src/ordered_robin_dict.jl b/src/ordered_robin_dict.jl index fcbe29a36..2184ae70e 100644 --- a/src/ordered_robin_dict.jl +++ b/src/ordered_robin_dict.jl @@ -12,7 +12,7 @@ are taken from 2-tuples `(key,value)` generated by the argument. # Examples ```jldoctest julia> OrderedRobinDict([("A", 1), ("B", 2)]) -OrderedRobinDict{String,Int64} with 2 entries: +OrderedRobinDict{String, Int64} with 2 entries: "A" => 1 "B" => 2 ``` @@ -21,7 +21,7 @@ Alternatively, a sequence of pair arguments may be passed. ```jldoctest julia> OrderedRobinDict("A"=>1, "B"=>2) -OrderedRobinDict{String,Int64} with 2 entries: +OrderedRobinDict{String, Int64} with 2 entries: "A" => 1 "B" => 2 ``` @@ -94,14 +94,14 @@ Remove all elements from a `collection`. # Examples ```jldoctest julia> A = OrderedRobinDict("a" => 1, "b" => 2) -OrderedRobinDict{String,Int64} with 2 entries: +OrderedRobinDict{String, Int64} with 2 entries: "a" => 1 "b" => 2 julia> empty!(A); julia> A -OrderedRobinDict{String,Int64} with 0 entries +OrderedRobinDict{String, Int64}() ``` """ function Base.empty!(h::OrderedRobinDict{K,V}) where {K, V} @@ -131,7 +131,7 @@ function Base.setindex!(h::OrderedRobinDict{K, V}, v0, key0) where {K,V} else @assert haskey(h, key0) @inbounds orig_v = h.vals[index] - (orig_v != v0) && (@inbounds h.vals[index] = v0) + !isequal(orig_v, v0) && (@inbounds h.vals[index] = v0) end check_for_rehash(h) && rehash!(h) @@ -198,7 +198,7 @@ julia> get!(d, "d", 4) 4 julia> d -OrderedRobinDict{String,Int64} with 4 entries: +OrderedRobinDict{String, Int64} with 4 entries: "a" => 1 "b" => 2 "c" => 3 @@ -291,7 +291,7 @@ Determine whether a collection has a mapping for a given `key`. # Examples ```jldoctest julia> D = OrderedRobinDict('a'=>2, 'b'=>3) -OrderedRobinDict{Char,Int64} with 2 entries: +OrderedRobinDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -302,8 +302,8 @@ julia> haskey(D, 'c') false ``` """ -Base.haskey(h::OrderedRobinDict, key) = (get(h.dict, key, -2) > 0) -Base.in(key, v::Base.KeySet{K,T}) where {K,T<:OrderedRobinDict{K}} = (get(v.dict, key, -1) >= 0) +Base.haskey(h::OrderedRobinDict, key) = (get(h.dict, key, -1) > 0) +Base.in(key, v::Base.KeySet{K,T}) where {K,T<:OrderedRobinDict{K}} = (get(v.dict.dict, key, -1) >= 0) """ getkey(collection, key, default) @@ -313,7 +313,7 @@ Return the key matching argument `key` if one exists in `collection`, otherwise # Examples ```jldoctest julia> D = OrderedRobinDict('a'=>2, 'b'=>3) -OrderedRobinDict{Char,Int64} with 2 entries: +OrderedRobinDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -389,12 +389,12 @@ Delete the mapping for the given key in a collection, and return the collection. # Examples ```jldoctest julia> d = OrderedRobinDict("a"=>1, "b"=>2) -OrderedRobinDict{String,Int64} with 2 entries: +OrderedRobinDict{String, Int64} with 2 entries: "a" => 1 "b" => 2 julia> delete!(d, "b") -OrderedRobinDict{String,Int64} with 1 entry: +OrderedRobinDict{String, Int64} with 1 entry: "a" => 1 ``` """ diff --git a/src/priorityqueue.jl b/src/priorityqueue.jl index aa75ca038..5ead48242 100644 --- a/src/priorityqueue.jl +++ b/src/priorityqueue.jl @@ -17,7 +17,7 @@ lowest priority element. ```jldoctest julia> PriorityQueue(Base.Order.Forward, "a" => 2, "b" => 3, "c" => 1) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 3 entries: "c" => 1 "a" => 2 "b" => 3 @@ -212,13 +212,13 @@ Insert the a key `k` into a priority queue `pq` with priority `v`. ```jldoctest julia> a = PriorityQueue(PriorityQueue("a"=>1, "b"=>2, "c"=>3)) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 3 entries: "a" => 1 "b" => 2 "c" => 3 julia> enqueue!(a, "d"=>4) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 4 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 4 entries: "a" => 1 "b" => 2 "c" => 3 @@ -253,7 +253,7 @@ Remove and return the lowest priority key from a priority queue. ```jldoctest julia> a = PriorityQueue(Base.Order.Forward, ["a" => 2, "b" => 3, "c" => 1]) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 3 entries: "c" => 1 "a" => 2 "b" => 3 @@ -262,7 +262,7 @@ julia> dequeue!(a) "c" julia> a -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 2 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 2 entries: "a" => 2 "b" => 3 ``` @@ -293,7 +293,7 @@ Remove and return a the lowest priority key and value from a priority queue as a ```jldoctest julia> a = PriorityQueue(Base.Order.Forward, "a" => 2, "b" => 3, "c" => 1) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 3 entries: "c" => 1 "a" => 2 "b" => 3 @@ -302,7 +302,7 @@ julia> dequeue_pair!(a) "c" => 1 julia> a -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 2 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 2 entries: "a" => 2 "b" => 3 ``` @@ -332,7 +332,7 @@ Delete the mapping for the given key in a priority queue, and return the priorit # Examples ```jldoctest julia> q = PriorityQueue(Base.Order.Forward, "a"=>2, "b"=>3, "c"=>1) -PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries: +PriorityQueue{String, Int64, Base.Order.ForwardOrdering} with 3 entries: "c" => 1 "a" => 2 "b" => 3 diff --git a/src/robin_dict.jl b/src/robin_dict.jl index 8cec85205..cde095f4f 100644 --- a/src/robin_dict.jl +++ b/src/robin_dict.jl @@ -12,7 +12,7 @@ are taken from 2-tuples `(key,value)` generated by the argument. # Examples ```jldoctest julia> RobinDict([("A", 1), ("B", 2)]) -RobinDict{String,Int64} with 2 entries: +RobinDict{String, Int64} with 2 entries: "B" => 2 "A" => 1 ``` @@ -21,7 +21,7 @@ Alternatively, a sequence of pair arguments may be passed. ```jldoctest julia> RobinDict("A"=>1, "B"=>2) -RobinDict{String,Int64} with 2 entries: +RobinDict{String, Int64} with 2 entries: "B" => 2 "A" => 1 ``` @@ -197,8 +197,8 @@ function rehash!(h::RobinDict{K,V}, newsz = length(h.keys)) where {K, V} sz = length(oldk) newsz = _tablesz(newsz) if h.count == 0 - resize!(h.keys, sz) - resize!(h.vals, sz) + resize!(h.keys, newsz) + resize!(h.vals, newsz) resize!(h.hashes, newsz) fill!(h.hashes, 0) h.count = 0 @@ -259,14 +259,14 @@ Remove all elements from a `collection`. # Examples ```jldoctest julia> A = RobinDict("a" => 1, "b" => 2) -RobinDict{String,Int64} with 2 entries: +RobinDict{String, Int64} with 2 entries: "b" => 2 "a" => 1 julia> empty!(A); julia> A -RobinDict{String,Int64} with 0 entries +RobinDict{String, Int64}() ``` """ function Base.empty!(h::RobinDict{K,V}) where {K, V} @@ -317,7 +317,7 @@ julia> get!(d, "d", 4) 4 julia> d -RobinDict{String,Int64} with 4 entries: +RobinDict{String, Int64} with 4 entries: "c" => 3 "b" => 2 "a" => 1 @@ -414,7 +414,7 @@ Determine whether a collection has a mapping for a given `key`. # Examples ```jldoctest julia> D = RobinDict('a'=>2, 'b'=>3) -RobinDict{Char,Int64} with 2 entries: +RobinDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -436,7 +436,7 @@ Return the key matching argument `key` if one exists in `collection`, otherwise # Examples ```jldoctest julia> D = RobinDict('a'=>2, 'b'=>3) -RobinDict{Char,Int64} with 2 entries: +RobinDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -547,12 +547,12 @@ Delete the mapping for the given key in a collection, and return the collection. # Examples ```jldoctest julia> d = RobinDict("a"=>1, "b"=>2) -RobinDict{String,Int64} with 2 entries: +RobinDict{String, Int64} with 2 entries: "b" => 2 "a" => 1 julia> delete!(d, "b") -RobinDict{String,Int64} with 1 entry: +RobinDict{String, Int64} with 1 entry: "a" => 1 ``` """ diff --git a/src/sorted_dict.jl b/src/sorted_dict.jl index db2afe34a..0598e8018 100644 --- a/src/sorted_dict.jl +++ b/src/sorted_dict.jl @@ -308,7 +308,7 @@ Returns the key type for SortedDict, SortedMultiDict and SortedSet. This function may also be applied to the type itself. Time: O(1) """ @inline Base.keytype(m::SortedDict{K,D,Ord}) where {K,D,Ord <: Ordering} = K -@inline Base.keytype(::Type{SortedDict{K,D,Ord}}) where {K,D,Ord <: Ordering} = K +@inline Base.valtype(m::SortedDict{K,D,Ord}) where {K,D,Ord <: Ordering} = D """ valtype(sc) @@ -316,8 +316,6 @@ This function may also be applied to the type itself. Time: O(1) Returns the value type for SortedDict and SortedMultiDict. This function may also be applied to the type itself. Time: O(1) """ -@inline Base.valtype(m::SortedDict{K,D,Ord}) where {K,D,Ord <: Ordering} = D -@inline Base.valtype(::Type{SortedDict{K,D,Ord}}) where {K,D,Ord <: Ordering} = D """ ordtype(sc) diff --git a/src/sorted_set.jl b/src/sorted_set.jl index 8547e91fc..a885137de 100644 --- a/src/sorted_set.jl +++ b/src/sorted_set.jl @@ -174,14 +174,6 @@ end return exactfound end -""" - eltype(sc) - -Returns the key type for SortedSet. -This function may also be applied to the type itself. Time: O(1) -""" -@inline Base.eltype(::Type{SortedSet{K,Ord}}) where {K,Ord <: Ordering} = K - """ keytype(sc) diff --git a/src/swiss_dict.jl b/src/swiss_dict.jl index 3fcc71931..09eed48f0 100644 --- a/src/swiss_dict.jl +++ b/src/swiss_dict.jl @@ -12,18 +12,18 @@ are taken from 2-tuples `(key,value)` generated by the argument. # Examples ```jldoctest julia> SwissDict([("A", 1), ("B", 2)]) -SwissDict{String,Int64} with 2 entries: - "B" => 2 +SwissDict{String, Int64} with 2 entries: "A" => 1 + "B" => 2 ``` Alternatively, a sequence of pair arguments may be passed. ```jldoctest julia> SwissDict("A"=>1, "B"=>2) -SwissDict{String,Int64} with 2 entries: - "B" => 2 +SwissDict{String, Int64} with 2 entries: "A" => 1 + "B" => 2 ``` """ mutable struct SwissDict{K,V} <: AbstractDict{K,V} @@ -356,14 +356,14 @@ Remove all elements from a `collection`. # Examples ```jldoctest julia> A = SwissDict("a" => 1, "b" => 2) -SwissDict{String,Int64} with 2 entries: - "b" => 2 +SwissDict{String, Int64} with 2 entries: "a" => 1 + "b" => 2 julia> empty!(A); julia> A -SwissDict{String,Int64} with 0 entries +SwissDict{String, Int64}() ``` """ function Base.empty!(h::SwissDict{K,V}) where {K, V} @@ -417,10 +417,10 @@ julia> get!(d, "d", 4) 4 julia> d -SwissDict{String,Int64} with 4 entries: - "c" => 3 - "b" => 2 +SwissDict{String, Int64} with 4 entries: "a" => 1 + "b" => 2 + "c" => 3 "d" => 4 ``` """ @@ -520,7 +520,7 @@ Determine whether a collection has a mapping for a given `key`. # Examples ```jldoctest julia> D = SwissDict('a'=>2, 'b'=>3) -SwissDict{Char,Int64} with 2 entries: +SwissDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -542,7 +542,7 @@ Return the key matching argument `key` if one exists in `collection`, otherwise # Examples ```jldoctest julia> D = SwissDict('a'=>2, 'b'=>3) -SwissDict{Char,Int64} with 2 entries: +SwissDict{Char, Int64} with 2 entries: 'a' => 2 'b' => 3 @@ -617,12 +617,12 @@ Delete the mapping for the given key in a collection, and return the collection. # Examples ```jldoctest julia> d = SwissDict("a"=>1, "b"=>2) -SwissDict{String,Int64} with 2 entries: - "b" => 2 +SwissDict{String, Int64} with 2 entries: "a" => 1 + "b" => 2 julia> delete!(d, "b") -SwissDict{String,Int64} with 1 entry: +SwissDict{String, Int64} with 1 entry: "a" => 1 ``` """ diff --git a/test/runtests.jl b/test/runtests.jl index 7a5aa7686..9fa3f2e64 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,7 +7,8 @@ import DataStructures: IntSet @test [] == detect_ambiguities(Base, Core, DataStructures) -tests = ["deprecations", +tests = [ + "deprecations", "int_set", "sparse_int_set", "deque", diff --git a/test/test_circ_deque.jl b/test/test_circ_deque.jl index adf3ddd6d..269d8a76c 100644 --- a/test/test_circ_deque.jl +++ b/test/test_circ_deque.jl @@ -81,6 +81,29 @@ for i in 1:5 push!(D, i) end @test collect([i for i in D]) == collect(1:5) end + + VERSION >= v"1.3" && @testset "pop! and popfirst! do not leak" begin + D = CircularDeque{String}(5) + + @testset "pop! doesn't leak" begin + push!(D,"foo") + push!(D,"bar") + ss2 = Base.summarysize(D) + pop!(D) + GC.gc(true) + ss1 = Base.summarysize(D) + @test ss1 < ss2 + end + @testset "popfirst! doesn't leak" begin + push!(D,"baz") + push!(D,"bug") + ss2 = Base.summarysize(D) + popfirst!(D) + GC.gc(true) + ss1 = Base.summarysize(D) + @test ss1 < ss2 + end + end end nothing diff --git a/test/test_deque.jl b/test/test_deque.jl index 8c35ba289..35f78ea5c 100644 --- a/test/test_deque.jl +++ b/test/test_deque.jl @@ -197,4 +197,28 @@ @test typeof(empty!(q)) === typeof(Deque{Int}()) @test isempty(q) end + + VERSION >= v"1.3" && @testset "pop! and popfirst! don't leak" begin + q = Deque{String}(5) + GC.gc(true) + + @testset "pop! doesn't leak" begin + push!(q,"foo") + push!(q,"bar") + ss2 = Base.summarysize(q.head) + pop!(q) + GC.gc(true) + ss1 = Base.summarysize(q.head) + @test ss1 < ss2 + end + @testset "popfirst! doesn't leak" begin + push!(q,"baz") + push!(q,"bug") + ss2 = Base.summarysize(q.head) + popfirst!(q) + GC.gc(true) + ss1 = Base.summarysize(q.head) + @test ss1 < ss2 + end + end end # @testset Deque diff --git a/test/test_mutable_binheap.jl b/test/test_mutable_binheap.jl index 9af1d963b..2a40501d6 100644 --- a/test/test_mutable_binheap.jl +++ b/test/test_mutable_binheap.jl @@ -78,6 +78,12 @@ end @test true end + @testset "Type Aliases" begin + # https://github.com/JuliaCollections/DataStructures.jl/issues/686 + @test MutableBinaryMaxHeap{Int}() isa MutableBinaryMaxHeap{Int} + @test MutableBinaryMinHeap{Int}() isa MutableBinaryMinHeap{Int} + end + @testset "basic tests" begin h = MutableBinaryMinHeap{Int}() diff --git a/test/test_ordered_robin_dict.jl b/test/test_ordered_robin_dict.jl index 2a78fc7aa..79efa6572 100644 --- a/test/test_ordered_robin_dict.jl +++ b/test/test_ordered_robin_dict.jl @@ -78,6 +78,13 @@ @test od60[14] == 15 end + @testset "Fixes issue 857" begin + h = OrderedRobinDict{Any,Any}([("a", missing), ("b", -2)]) + @test 5 == (h["a"] = 5) + @test "b" in keys(h) + @test haskey(h,"b") + end + # ############################# # Copied and modified from Base/test/dict.jl diff --git a/test/test_sorted_containers.jl b/test/test_sorted_containers.jl index 846d1f915..3d4b7df5c 100644 --- a/test/test_sorted_containers.jl +++ b/test/test_sorted_containers.jl @@ -1403,6 +1403,32 @@ function testSortedMultiDict() end # issue #216 my_assert(DataStructures.isordered(SortedMultiDict{Int, String})) + # issue #773 + s = SortedMultiDict{Int, Int}() + insert!(s, 4, 41) + insert!(s, 3, 31) + insert!(s, 2, 21) + insert!(s, 2, 22) + insert!(s, 2, 23) + insert!(s, 2, 24) + insert!(s, 2, 25) + insert!(s, 2, 26) + insert!(s, 1, 11) + insert!(s, 1, 12) + st1 = insert!(s, 1, 13) + st2 = insert!(s, 1, 14) + st3 = insert!(s, 1, 15) + st4 = insert!(s, 1, 16) + st5 = insert!(s, 1, 17) + st6 = insert!(s, 1, 18) + delete!((s, st6)) + delete!((s, st5)) + delete!((s, st4)) + delete!((s, st3)) + delete!((s, st2)) + delete!((s, st1)) + insert!(s, 1, 19) + checkcorrectness(s.bt, true) true end diff --git a/test/test_sorting.jl b/test/test_sorting.jl index 445420b0d..173bb1199 100644 --- a/test/test_sorting.jl +++ b/test/test_sorting.jl @@ -29,16 +29,9 @@ @test d == rev end - @testset "sort unordered" begin - unordered = Dict(zip('a':'z', 26:-1:1)) - @test sort(unordered) == forward - @test sort(unordered; rev=true) == rev - @test sort(unordered; byvalue=true) == rev - @test sort(unordered; byvalue=true, rev=true) == forward - end end @testset "Bug DataStructures.jl/#394" begin - @test sort(Dict(k=>string(k) for k in 1:3))[1] == "1" + @test sort(OrderedDict(k=>string(k) for k in 1:3))[1] == "1" end end