• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #38182

15 Aug 2025 03:55AM UTC coverage: 77.87% (-0.4%) from 78.28%
#38182

push

local

web-flow
🤖 [master] Bump the SparseArrays stdlib from 30201ab to bb5ecc0 (#59263)

Stdlib: SparseArrays
URL: https://github.com/JuliaSparse/SparseArrays.jl.git
Stdlib branch: main
Julia branch: master
Old commit: 30201ab
New commit: bb5ecc0
Julia version: 1.13.0-DEV
SparseArrays version: 1.13.0
Bump invoked by: @ViralBShah
Powered by:
[BumpStdlibs.jl](https://github.com/JuliaLang/BumpStdlibs.jl)

Diff:
https://github.com/JuliaSparse/SparseArrays.jl/compare/30201abcb...bb5ecc091

```
$ git log --oneline 30201ab..bb5ecc0
bb5ecc0 fast quadratic form for dense matrix, sparse vectors (#640)
34ece87 Extend 3-arg `dot` to generic `HermOrSym` sparse matrices (#643)
095b685 Exclude unintended complex symmetric sparse matrices from 3-arg `dot` (#642)
8049287 Fix signature for 2-arg matrix-matrix `dot` (#641)
cff971d Make cond(::SparseMatrix, 1 / Inf) discoverable from 2-norm error (#629)
```

Co-authored-by: ViralBShah <744411+ViralBShah@users.noreply.github.com>

48274 of 61993 relevant lines covered (77.87%)

9571166.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.84
/base/set.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
"""
4
    Set{T} <: AbstractSet{T}
5

6
`Set`s are mutable containers that provide fast membership testing.
7

8
`Set`s have efficient implementations of set operations such as `in`, `union` and `intersect`.
9
Elements in a `Set` are unique, as determined by the elements' definition of `isequal`.
10
The order of elements in a `Set` is an implementation detail and cannot be relied on.
11

12
See also: [`AbstractSet`](@ref), [`BitSet`](@ref), [`Dict`](@ref),
13
[`push!`](@ref), [`empty!`](@ref), [`union!`](@ref), [`in`](@ref), [`isequal`](@ref)
14

15
# Examples
16
```jldoctest; filter = r"^  '.'"ma
17
julia> s = Set("aaBca")
18
Set{Char} with 3 elements:
19
  'a'
20
  'c'
21
  'B'
22

23
julia> push!(s, 'b')
24
Set{Char} with 4 elements:
25
  'a'
26
  'b'
27
  'B'
28
  'c'
29

30
julia> s = Set([NaN, 0.0, 1.0, 2.0]);
31

32
julia> -0.0 in s # isequal(0.0, -0.0) is false
33
false
34

35
julia> NaN in s # isequal(NaN, NaN) is true
36
true
37
```
38
"""
39
struct Set{T} <: AbstractSet{T}
40
    dict::Dict{T,Nothing}
41

42
    global _Set(dict::Dict{T,Nothing}) where {T} = new{T}(dict)
12,521✔
43
end
44

45
Set{T}() where {T} = _Set(Dict{T,Nothing}())
17,352✔
46
Set{T}(s::Set{T}) where {T} = _Set(Dict{T,Nothing}(s.dict))
25✔
47
Set{T}(itr) where {T} = union!(Set{T}(), itr)
2,659✔
48
Set() = Set{Any}()
619✔
49

50
function Set{T}(s::KeySet{T, <:Dict{T}}) where {T}
51
    d = s.dict
435✔
52
    slots = copy(d.slots)
867✔
53
    keys = copy(d.keys)
867✔
54
    vals = similar(d.vals, Nothing)
435✔
55
    _Set(Dict{T,Nothing}(slots, keys, vals, d.ndel, d.count, d.age, d.idxfloor, d.maxprobe))
435✔
56
end
57

58
Set(itr) = _Set(itr, IteratorEltype(itr))
1,068✔
59
_Set(itr, ::HasEltype) = Set{eltype(itr)}(itr)
1,030✔
60

61
function _Set(itr, ::EltypeUnknown)
62
    T = @default_eltype(itr)
93✔
63
    (isconcretetype(T) || T === Union{}) || return grow_to!(Set{T}(), itr)
93✔
64
    return Set{T}(itr)
88✔
65
end
66

67
empty(s::AbstractSet{T}, ::Type{U}=T) where {T,U} = Set{U}()
5✔
68

69
# return an empty set with eltype T, which is mutable (can be grown)
70
# by default, a Set is returned
71
emptymutable(s::AbstractSet{T}, ::Type{U}=T) where {T,U} = Set{U}()
421✔
72

73
_similar_for(c::AbstractSet, ::Type{T}, itr, isz, len) where {T} = empty(c, T)
×
74

75
function show(io::IO, s::Set)
5✔
76
    if isempty(s)
5✔
77
        if get(io, :typeinfo, Any) == typeof(s)
3✔
78
            print(io, "Set()")
×
79
        else
80
            show(io, typeof(s))
1✔
81
            print(io, "()")
1✔
82
        end
83
    else
84
        print(io, "Set(")
4✔
85
        show_vector(io, s)
4✔
86
        print(io, ')')
4✔
87
    end
88
end
89

90
isempty(s::Set) = isempty(s.dict)
136,191✔
91
length(s::Set)  = length(s.dict)
308,960✔
92
in(x, s::Set) = haskey(s.dict, x)
23,973,027✔
93

94
"""
95
    in!(x, s::AbstractSet)::Bool
96

97
If `x` is in `s`, return `true`. If not, push `x` into `s` and return `false`.
98
This is equivalent to `in(x, s) ? true : (push!(s, x); false)`, but may have a
99
more efficient implementation.
100

101
See also: [`in`](@ref), [`push!`](@ref), [`Set`](@ref)
102

103
!!! compat "Julia 1.11"
104
    This function requires at least 1.11.
105

106
# Examples
107
```jldoctest; filter = r"^\\s+\\d\$"m
108
julia> s = Set{Any}([1, 2, 3]); in!(4, s)
109
false
110

111
julia> length(s)
112
4
113

114
julia> in!(0x04, s)
115
true
116

117
julia> s
118
Set{Any} with 4 elements:
119
  4
120
  2
121
  3
122
  1
123
```
124
"""
125
function in!(x, s::AbstractSet)
×
126
    x ∈ s ? true : (push!(s, x); false)
×
127
end
128

129
function in!(x, s::Set)
251✔
130
    xT = convert(eltype(s), x)
380,567✔
131
    idx, sh = ht_keyindex2_shorthash!(s.dict, xT)
383,324✔
132
    idx > 0 && return true
383,324✔
133
    _setindex!(s.dict, nothing, xT, -idx, sh)
20,148✔
134
    return false
19,974✔
135
end
136

137
push!(s::Set, x) = (s.dict[x] = nothing; s)
4,109,546✔
138

139
function pop!(s::Set, x, default)
×
140
    dict = s.dict
×
141
    index = ht_keyindex(dict, x)
×
142
    if index > 0
×
143
        @inbounds key = dict.keys[index]
×
144
        _delete!(dict, index)
×
145
        return key
×
146
    else
147
        return default
×
148
    end
149
end
150

151
function pop!(s::Set, x)
4,765✔
152
    index = ht_keyindex(s.dict, x)
9,487✔
153
    index < 1 && throw(KeyError(x))
4,766✔
154
    result = @inbounds s.dict.keys[index]
4,766✔
155
    _delete!(s.dict, index)
4,766✔
156
    result
4,766✔
157
end
158

159
function pop!(s::Set)
×
160
    isempty(s) && throw(ArgumentError("set must be non-empty"))
×
161
    return pop!(s.dict)[1]
×
162
end
163

164
delete!(s::Set, x) = (delete!(s.dict, x); s)
3,800,984✔
165

166
copy(s::Set) = copymutable(s)
11✔
167

168
copymutable(s::Set{T}) where {T} = Set{T}(s)
25✔
169
# Set is the default mutable fall-back
170
copymutable(s::AbstractSet{T}) where {T} = Set{T}(s)
860✔
171

172
sizehint!(s::Set, newsz::Integer; shrink::Bool=true) = (sizehint!(s.dict, newsz; shrink); s)
14,198✔
173
empty!(s::Set) = (empty!(s.dict); s)
4,250✔
174
rehash!(s::Set) = (rehash!(s.dict); s)
×
175

176
iterate(s::Set, i...)       = iterate(KeySet(s.dict), i...)
1,616,410✔
177

178
@propagate_inbounds Iterators.only(s::Set) = Iterators._only(s, first)
7✔
179

180
# In case the size(s) is smaller than size(t) its more efficient to iterate through
181
# elements of s instead and only delete the ones also contained in t.
182
# The threshold for this decision boils down to a tradeoff between
183
# size(s) * cost(in() + delete!()) ≶ size(t) * cost(delete!())
184
# Empirical observations on Ints point towards a threshold of 0.8.
185
# To be on the safe side (e.g. cost(in) >>> cost(delete!) ) a
186
# conservative threshold of 0.5 was chosen.
187
function setdiff!(s::Set, t::Set)
14✔
188
    if 2 * length(s) < length(t)
14✔
189
        for x in s
×
190
            x in t && delete!(s, x)
×
191
        end
×
192
    else
193
        for x in t
28✔
194
            delete!(s, x)
180✔
195
        end
180✔
196
    end
197
    return s
14✔
198
end
199

200
"""
201
    unique(itr)
202

203
Return an array containing only the unique elements of collection `itr`,
204
as determined by [`isequal`](@ref) and [`hash`](@ref), in the order that the first of each
205
set of equivalent elements originally appears. The element type of the
206
input is preserved.
207

208
See also: [`unique!`](@ref), [`allunique`](@ref), [`allequal`](@ref).
209

210
# Examples
211
```jldoctest
212
julia> unique([1, 2, 6, 2])
213
3-element Vector{Int64}:
214
 1
215
 2
216
 6
217

218
julia> unique(Real[1, 1.0, 2])
219
2-element Vector{Real}:
220
 1
221
 2
222
```
223
"""
224
function unique(itr)
6,863✔
225
    if isa(IteratorEltype(itr), HasEltype)
6,864✔
226
        T = eltype(itr)
6,864✔
227
        out = Vector{T}()
6,864✔
228
        seen = Set{T}()
6,864✔
229
        for x in itr
6,865✔
230
            !in!(x, seen) && push!(out, x)
396,199✔
231
        end
382,457✔
232
        return out
6,864✔
233
    end
234
    T = @default_eltype(itr)
×
235
    y = iterate(itr)
×
236
    y === nothing && return T[]
×
237
    x, i = y
×
238
    S = typeof(x)
×
239
    R = isconcretetype(T) ? T : S
×
240
    return _unique_from(itr, R[x], Set{R}((x,)), i)
×
241
end
242

243
_unique_from(itr, out, seen, i) = unique_from(itr, out, seen, i)
×
244
@inline function unique_from(itr, out::Vector{T}, seen, i) where T
×
245
    while true
×
246
        y = iterate(itr, i)
×
247
        y === nothing && break
×
248
        x, i = y
×
249
        S = typeof(x)
×
250
        if !(S === T || S <: T)
×
251
            R = promote_typejoin(S, T)
×
252
            seenR = convert(Set{R}, seen)
×
253
            outR = convert(Vector{R}, out)
×
254
            !in!(x, seenR) && push!(outR, x)
×
255
            return _unique_from(itr, outR, seenR, i)
×
256
        end
257
        !in!(x, seen) && push!(out, x)
×
258
    end
×
259
    return out
×
260
end
261

262
unique(r::AbstractRange) = allunique(r) ? r : oftype(r, r[begin]:r[begin])
15✔
263

264
"""
265
    unique(f, itr)
266

267
Return an array containing one value from `itr` for each unique value produced by `f`
268
applied to elements of `itr`.
269

270
# Examples
271
```jldoctest
272
julia> unique(x -> x^2, [1, -1, 3, -3, 4])
273
3-element Vector{Int64}:
274
 1
275
 3
276
 4
277
```
278
This functionality can also be used to extract the *indices* of the first
279
occurrences of unique elements in an array:
280
```jldoctest
281
julia> a = [3.1, 4.2, 5.3, 3.1, 3.1, 3.1, 4.2, 1.7];
282

283
julia> i = unique(i -> a[i], eachindex(a))
284
4-element Vector{Int64}:
285
 1
286
 2
287
 3
288
 8
289

290
julia> a[i]
291
4-element Vector{Float64}:
292
 3.1
293
 4.2
294
 5.3
295
 1.7
296

297
julia> a[i] == unique(a)
298
true
299
```
300
"""
301
function unique(f, C; seen::Union{Nothing,Set}=nothing)
12✔
302
    out = Vector{eltype(C)}()
6✔
303
    if seen !== nothing
6✔
304
        for x in C
2✔
305
            !in!(f(x), seen) && push!(out, x)
4✔
306
        end
2✔
307
        return out
2✔
308
    end
309

310
    s = iterate(C)
4✔
311
    if s === nothing
4✔
312
        return out
×
313
    end
314
    (x, i) = s
4✔
315
    y = f(x)
8✔
316
    seen = Set{typeof(y)}()
6✔
317
    push!(seen, y)
5✔
318
    push!(out, x)
8✔
319

320
    return _unique!(f, out, C, seen, i)
4✔
321
end
322

323
function _unique!(f, out::AbstractVector, C, seen::Set, i)
4✔
324
    s = iterate(C, i)
4✔
325
    while s !== nothing
16✔
326
        (x, i) = s
12✔
327
        y = f(x)
24✔
328
        if y ∉ seen
12✔
329
            push!(out, x)
20✔
330
            if y isa eltype(seen)
10✔
331
                push!(seen, y)
10✔
332
            else
333
                seen2 = convert(Set{promote_typejoin(eltype(seen), typeof(y))}, seen)
×
334
                push!(seen2, y)
×
335
                return _unique!(f, out, C, seen2, i)
×
336
            end
337
        end
338
        s = iterate(C, i)
12✔
339
    end
12✔
340

341
    return out
4✔
342
end
343

344
"""
345
    unique!(f, A::AbstractVector)
346

347
Selects one value from `A` for each unique value produced by `f` applied to
348
elements of `A`, then return the modified A.
349

350
!!! compat "Julia 1.1"
351
    This method is available as of Julia 1.1.
352

353
# Examples
354
```jldoctest
355
julia> unique!(x -> x^2, [1, -1, 3, -3, 4])
356
3-element Vector{Int64}:
357
 1
358
 3
359
 4
360

361
julia> unique!(n -> n%3, [5, 1, 8, 9, 3, 4, 10, 7, 2, 6])
362
3-element Vector{Int64}:
363
 5
364
 1
365
 9
366

367
julia> unique!(iseven, [2, 3, 5, 7, 9])
368
2-element Vector{Int64}:
369
 2
370
 3
371
```
372
"""
373
function unique!(f, A::AbstractVector; seen::Union{Nothing,Set}=nothing)
524✔
374
    if length(A) <= 1
266✔
375
        return A
148✔
376
    end
377

378
    i = firstindex(A)::Int
118✔
379
    x = @inbounds A[i]
118✔
380
    y = f(x)
219✔
381
    if seen === nothing
118✔
382
        seen = Set{typeof(y)}()
118✔
383
    end
384
    push!(seen, y)
118✔
385
    return _unique!(f, A, seen, i, i+1)
118✔
386
end
387

388
function _unique!(f, A::AbstractVector, seen::Set, current::Integer, i::Integer)
118✔
389
    while i <= lastindex(A)
118✔
390
        x = @inbounds A[i]
5,757✔
391
        y = f(x)
10,960✔
392
        if y ∉ seen
5,809✔
393
            current += 1
5,735✔
394
            @inbounds A[current] = x
5,735✔
395
            if y isa eltype(seen)
5,735✔
396
                push!(seen, y)
5,735✔
397
            else
398
                seen2 = convert(Set{promote_typejoin(eltype(seen), typeof(y))}, seen)
×
399
                push!(seen2, y)
×
400
                return _unique!(f, A, seen2, current, i+1)
×
401
            end
402
        end
403
        i += 1
5,757✔
404
    end
5,757✔
405
    return resize!(A, current - firstindex(A)::Int + 1)::typeof(A)
118✔
406
end
407

408

409
# If A is not grouped, then we will need to keep track of all of the elements that we have
410
# seen so far.
411
_unique!(A::AbstractVector) = unique!(identity, A::AbstractVector)
42✔
412

413
# If A is grouped, so that each unique element is in a contiguous group, then we only
414
# need to keep track of one element at a time. We replace the elements of A with the
415
# unique elements that we see in the order that we see them. Once we have iterated
416
# through A, we resize A based on the number of unique elements that we see.
417
function _groupedunique!(A::AbstractVector)
15✔
418
    isempty(A) && return A
15✔
419
    idxs = eachindex(A)
6✔
420
    y = first(A)
6✔
421
    # We always keep the first element
422
    T = NTuple{2,Any} # just to eliminate `iterate(idxs)::Nothing` candidate
6✔
423
    it = iterate(idxs, (iterate(idxs)::T)[2])
6✔
424
    count = 1
6✔
425
    for x in Iterators.drop(A, 1)
12✔
426
        if !isequal(x, y)
×
427
            it = it::T
×
428
            y = A[it[1]] = x
×
429
            count += 1
×
430
            it = iterate(idxs, it[2])
×
431
        end
432
    end
×
433
    resize!(A, count)::typeof(A)
6✔
434
end
435

436
"""
437
    unique!(A::AbstractVector)
438

439
Remove duplicate items as determined by [`isequal`](@ref) and [`hash`](@ref), then return the modified `A`.
440
`unique!` will return the elements of `A` in the order that they occur. If you do not care
441
about the order of the returned data, then calling `(sort!(A); unique!(A))` will be much
442
more efficient as long as the elements of `A` can be sorted.
443

444
# Examples
445
```jldoctest
446
julia> unique!([1, 1, 1])
447
1-element Vector{Int64}:
448
 1
449

450
julia> A = [7, 3, 2, 3, 7, 5];
451

452
julia> unique!(A)
453
4-element Vector{Int64}:
454
 7
455
 3
456
 2
457
 5
458

459
julia> B = [7, 6, 42, 6, 7, 42];
460

461
julia> sort!(B);  # unique! is able to process sorted data much more efficiently.
462

463
julia> unique!(B)
464
3-element Vector{Int64}:
465
  6
466
  7
467
 42
468
```
469
"""
470
function unique!(itr)
28✔
471
    if isa(itr, AbstractVector)
42✔
472
        if OrderStyle(eltype(itr)) === Ordered()
42✔
473
            (issorted(itr) || issorted(itr, rev=true)) && return _groupedunique!(itr)
33✔
474
        end
475
    end
476
    isempty(itr) && return itr
27✔
477
    return _unique!(itr)
25✔
478
end
479

480
"""
481
    allunique(itr)::Bool
482
    allunique(f, itr)::Bool
483

484
Return `true` if all values from `itr` are distinct when compared with [`isequal`](@ref).
485
Or if all of `[f(x) for x in itr]` are distinct, for the second method.
486

487
Note that `allunique(f, itr)` may call `f` fewer than `length(itr)` times.
488
The precise number of calls is regarded as an implementation detail.
489

490
`allunique` may use a specialized implementation when the input is sorted.
491

492
See also: [`unique`](@ref), [`issorted`](@ref), [`allequal`](@ref).
493

494
!!! compat "Julia 1.11"
495
    The method `allunique(f, itr)` requires at least Julia 1.11.
496

497
# Examples
498
```jldoctest
499
julia> allunique([1, 2, 3])
500
true
501

502
julia> allunique([1, 2, 1, 2])
503
false
504

505
julia> allunique(Real[1, 1.0, 2])
506
false
507

508
julia> allunique([NaN, 2.0, NaN, 4.0])
509
false
510

511
julia> allunique(abs, [1, -1, 2])
512
false
513
```
514
"""
515
function allunique(C)
×
516
    if haslength(C)
×
517
        length(C) < 2 && return true
×
518
        length(C) < 32 && return _indexed_allunique(collect(C))
×
519
    end
520
    return _hashed_allunique(C)
×
521
end
522

523
allunique(f, xs) = allunique(Generator(f, xs))
×
524

525
function _hashed_allunique(C)
8✔
526
    seen = Set{@default_eltype(C)}()
8✔
527
    x = iterate(C)
8✔
528
    if haslength(C) && length(C) > 1000
8✔
529
        for i in OneTo(1000)
×
530
            v, s = something(x)
×
531
            in!(v, seen) && return false
×
532
            x = iterate(C, s)
×
533
        end
×
534
        sizehint!(seen, length(C))
×
535
    end
536
    while x !== nothing
3,429✔
537
        v, s = x
3,421✔
538
        in!(v, seen) && return false
6,842✔
539
        x = iterate(C, s)
3,421✔
540
    end
3,421✔
541
    return true
8✔
542
end
543

544
allunique(::Union{AbstractSet,AbstractDict}) = true
×
545

546
allunique(r::AbstractRange) = !iszero(step(r)) || length(r) <= 1
17✔
547

548
function allunique(A::StridedArray)
16✔
549
    if length(A) < 32
16✔
550
        _indexed_allunique(A)
8✔
551
    elseif OrderStyle(eltype(A)) === Ordered()
8✔
552
        a1, rest1 = Iterators.peel(A)::Tuple{Any,Any}
14✔
553
        a2, rest = Iterators.peel(rest1)::Tuple{Any,Any}
14✔
554
        if !isequal(a1, a2)
7✔
555
            compare = isless(a1, a2) ? isless : (a,b) -> isless(b,a)
11✔
556
            for a in rest
7✔
557
                if compare(a2, a)
22✔
558
                    a2 = a
6✔
559
                elseif isequal(a2, a)
7✔
560
                    return false
×
561
                else
562
                    return _hashed_allunique(A)
7✔
563
                end
564
            end
6✔
565
        else # isequal(a1, a2)
566
            return false
×
567
        end
568
        return true
×
569
    else
570
        _hashed_allunique(A)
1✔
571
    end
572
end
573

574
function _indexed_allunique(A)
1✔
575
    length(A) < 2 && return true
8✔
576
    iter = eachindex(A)
8✔
577
    I = iterate(iter)
8✔
578
    while I !== nothing
53✔
579
        i, s = I
45✔
580
        a = A[i]
45✔
581
        for j in Iterators.rest(iter, s)
82✔
582
            isequal(a, @inbounds A[j]) && return false
145✔
583
        end
253✔
584
        I = iterate(iter, s)
82✔
585
    end
45✔
586
    return true
8✔
587
end
588

589
function allunique(t::Tuple)
1✔
590
    length(t) < 32 || return _hashed_allunique(t)
3✔
591
    a = afoldl(true, tail(t)...) do b, x
3✔
592
        b & !isequal(first(t), x)
3✔
593
    end
594
    return a && allunique(tail(t))
3✔
595
end
596
allunique(t::Tuple{}) = true
×
597

598
function allunique(f::F, t::Tuple) where {F}
×
599
    length(t) < 2 && return true
×
600
    length(t) < 32 || return _hashed_allunique(Generator(f, t))
×
601
    return allunique(map(f, t))
×
602
end
603

604
"""
605
    allequal(itr)::Bool
606
    allequal(f, itr)::Bool
607

608
Return `true` if all values from `itr` are equal when compared with [`isequal`](@ref).
609
Or if all of `[f(x) for x in itr]` are equal, for the second method.
610

611
Note that `allequal(f, itr)` may call `f` fewer than `length(itr)` times.
612
The precise number of calls is regarded as an implementation detail.
613

614
See also: [`unique`](@ref), [`allunique`](@ref).
615

616
!!! compat "Julia 1.8"
617
    The `allequal` function requires at least Julia 1.8.
618

619
!!! compat "Julia 1.11"
620
    The method `allequal(f, itr)` requires at least Julia 1.11.
621

622
# Examples
623
```jldoctest
624
julia> allequal([])
625
true
626

627
julia> allequal([1])
628
true
629

630
julia> allequal([1, 1])
631
true
632

633
julia> allequal([1, 2])
634
false
635

636
julia> allequal(Dict(:a => 1, :b => 1))
637
false
638

639
julia> allequal(abs2, [1, -1])
640
true
641
```
642
"""
643
function allequal(itr)
15✔
644
    if haslength(itr)
53✔
645
        length(itr) <= 1 && return true
53✔
646
    end
647
    pl = Iterators.peel(itr)
63✔
648
    isnothing(pl) && return true
63✔
649
    a, rest = pl
51✔
650
    return all(isequal(a), rest)
51✔
651
end
652

653
allequal(c::Union{AbstractSet,AbstractDict}) = length(c) <= 1
×
654

655
allequal(r::AbstractRange) = iszero(step(r)) || length(r) <= 1
×
656

657
allequal(f, xs) = allequal(Generator(f, xs))
4✔
658

659
function allequal(f, xs::Tuple)
×
660
    length(xs) <= 1 && return true
×
661
    f1 = f(xs[1])
×
662
    for x in tail(xs)
×
663
        isequal(f1, f(x)) || return false
×
664
    end
×
665
    return true
×
666
end
667

668
filter!(f, s::Set) = unsafe_filter!(f, s)
505✔
669

670
const hashs_seed = UInt === UInt64 ? 0x852ada37cfe8e0ce : 0xcfe8e0ce
671
function hash(s::AbstractSet, h::UInt)
509✔
672
    hv = hashs_seed
509✔
673
    for x in s
1,019✔
674
        hv ⊻= hash(x)
5,696✔
675
    end
12,144✔
676
    hash(hv, h)
509✔
677
end
678

679
convert(::Type{T}, s::T) where {T<:AbstractSet} = s
×
680
convert(::Type{T}, s::AbstractSet) where {T<:AbstractSet} = T(s)::T
592✔
681

682

683
## replace/replace! ##
684

685
function check_count(count::Integer)
1✔
686
    count < 0 && throw(DomainError(count, "`count` must not be negative (got $count)"))
519✔
687
    return min(count, typemax(Int)) % Int
519✔
688
end
689

690
# TODO: use copy!, which is currently unavailable from here since it is defined in Future
691
_copy_oftype(x, ::Type{T}) where {T} = copyto!(similar(x, T), x)
×
692
# TODO: use similar() once deprecation is removed and it preserves keys
693
_copy_oftype(x::AbstractDict, ::Type{Pair{K,V}}) where {K,V} = merge!(empty(x, K, V), x)
×
694
_copy_oftype(x::AbstractSet, ::Type{T}) where {T} = union!(empty(x, T), x)
×
695

696
_copy_oftype(x::AbstractArray{T}, ::Type{T}) where {T} = copy(x)
×
697
_copy_oftype(x::AbstractDict{K,V}, ::Type{Pair{K,V}}) where {K,V} = copy(x)
×
698
_copy_oftype(x::AbstractSet{T}, ::Type{T}) where {T} = copy(x)
×
699

700
_similar_or_copy(x::Any) = similar(x)
68✔
701
_similar_or_copy(x::Any, ::Type{T}) where {T} = similar(x, T)
1,236✔
702
# Make a copy on construction since it is faster than inserting elements separately
703
_similar_or_copy(x::Union{AbstractDict,AbstractSet}) = copy(x)
×
704
_similar_or_copy(x::Union{AbstractDict,AbstractSet}, ::Type{T}) where {T} = _copy_oftype(x, T)
×
705

706
# to make replace/replace! work for a new container type Cont, only
707
# _replace!(new::Callable, res::Cont, A::Cont, count::Int)
708
# has to be implemented
709

710
"""
711
    replace!(A, old_new::Pair...; [count::Integer])
712

713
For each pair `old=>new` in `old_new`, replace all occurrences
714
of `old` in collection `A` by `new`.
715
Equality is determined using [`isequal`](@ref).
716
If `count` is specified, then replace at most `count` occurrences in total.
717
See also [`replace`](@ref replace(A, old_new::Pair...)).
718

719
# Examples
720
```jldoctest; filter = r"^\\s+\\d\$"m
721
julia> replace!([1, 2, 1, 3], 1=>0, 2=>4, count=2)
722
4-element Vector{Int64}:
723
 0
724
 4
725
 1
726
 3
727

728
julia> replace!(Set([1, 2, 3]), 1=>0)
729
Set{Int64} with 3 elements:
730
  0
731
  2
732
  3
733
```
734
"""
735
replace!(A, old_new::Pair...; count::Integer=typemax(Int)) =
890✔
736
    replace_pairs!(A, A, check_count(count), old_new)
737

738
function replace_pairs!(res, A, count::Int, old_new::Tuple{Vararg{Pair}})
1✔
739
    @inline function new(x)
1,682✔
740
        for o_n in old_new
1,138✔
741
            isequal(first(o_n), x) && return last(o_n)
1,138✔
742
        end
918✔
743
        return x # no replace
918✔
744
    end
745
    _replace!(new, res, A, count)
1,681✔
746
end
747

748
"""
749
    replace!(new::Union{Function, Type}, A; [count::Integer])
750

751
Replace each element `x` in collection `A` by `new(x)`.
752
If `count` is specified, then replace at most `count` values in total
753
(replacements being defined as `new(x) !== x`).
754

755
# Examples
756
```jldoctest; filter = r"^\\s+\\d+(\\s+=>\\s+\\d)?\$"m
757
julia> replace!(x -> isodd(x) ? 2x : x, [1, 2, 3, 4])
758
4-element Vector{Int64}:
759
 2
760
 2
761
 6
762
 4
763

764
julia> replace!(Dict(1=>2, 3=>4)) do kv
765
           first(kv) < 3 ? first(kv)=>3 : kv
766
       end
767
Dict{Int64, Int64} with 2 entries:
768
  3 => 4
769
  1 => 3
770

771
julia> replace!(x->2x, Set([3, 6]))
772
Set{Int64} with 2 elements:
773
  6
774
  12
775
```
776
"""
777
replace!(new::Callable, A; count::Integer=typemax(Int)) =
12✔
778
    _replace!(new, A, A, check_count(count))
779

780
"""
781
    replace(A, old_new::Pair...; [count::Integer])
782

783
Return a copy of collection `A` where, for each pair `old=>new` in `old_new`,
784
all occurrences of `old` are replaced by `new`.
785
Equality is determined using [`isequal`](@ref).
786
If `count` is specified, then replace at most `count` occurrences in total.
787

788
The element type of the result is chosen using promotion (see [`promote_type`](@ref))
789
based on the element type of `A` and on the types of the `new` values in pairs.
790
If `count` is omitted and the element type of `A` is a `Union`, the element type
791
of the result will not include singleton types which are replaced with values of
792
a different type: for example, `Union{T,Missing}` will become `T` if `missing` is
793
replaced.
794

795
See also [`replace!`](@ref), [`splice!`](@ref), [`delete!`](@ref), [`insert!`](@ref).
796

797
!!! compat "Julia 1.7"
798
    Version 1.7 is required to replace elements of a `Tuple`.
799

800
# Examples
801
```jldoctest
802
julia> replace([1, 2, 1, 3], 1=>0, 2=>4, count=2)
803
4-element Vector{Int64}:
804
 0
805
 4
806
 1
807
 3
808

809
julia> replace([1, missing], missing=>0)
810
2-element Vector{Int64}:
811
 1
812
 0
813
```
814
"""
815
function replace(A, old_new::Pair...; count::Union{Integer,Nothing}=nothing)
1,236✔
816
    V = promote_valuetype(old_new...)
1,236✔
817
    if count isa Nothing
1,236✔
818
        T = promote_type(subtract_singletontype(eltype(A), old_new...), V)
1,236✔
819
        replace_pairs!(_similar_or_copy(A, T), A, typemax(Int), old_new)
1,236✔
820
    else
821
        U = promote_type(eltype(A), V)
×
822
        replace_pairs!(_similar_or_copy(A, U), A, check_count(count), old_new)
×
823
    end
824
end
825

826
promote_valuetype(x::Pair{K, V}) where {K, V} = V
236✔
827
promote_valuetype(x::Pair{K, V}, y::Pair...) where {K, V} =
×
828
    promote_type(V, promote_valuetype(y...))
829

830
# Subtract singleton types which are going to be replaced
831
function subtract_singletontype(::Type{T}, x::Pair{K}) where {T, K}
832
    if issingletontype(K)
236✔
833
        typesplit(T, K)
×
834
    else
835
        T
236✔
836
    end
837
end
838
subtract_singletontype(::Type{T}, x::Pair{K}, y::Pair...) where {T, K} =
×
839
    subtract_singletontype(subtract_singletontype(T, y...), x)
840

841
"""
842
    replace(new::Union{Function, Type}, A; [count::Integer])
843

844
Return a copy of `A` where each value `x` in `A` is replaced by `new(x)`.
845
If `count` is specified, then replace at most `count` values in total
846
(replacements being defined as `new(x) !== x`).
847

848
!!! compat "Julia 1.7"
849
    Version 1.7 is required to replace elements of a `Tuple`.
850

851
# Examples
852
```jldoctest; filter = r"^\\s+\\S+\\s+=>\\s+\\d\$"m
853
julia> replace(x -> isodd(x) ? 2x : x, [1, 2, 3, 4])
854
4-element Vector{Int64}:
855
 2
856
 2
857
 6
858
 4
859

860
julia> replace(Dict(1=>2, 3=>4)) do kv
861
           first(kv) < 3 ? first(kv)=>3 : kv
862
       end
863
Dict{Int64, Int64} with 2 entries:
864
  3 => 4
865
  1 => 3
866
```
867
"""
868
replace(new::Callable, A; count::Integer=typemax(Int)) =
136✔
869
    _replace!(new, _similar_or_copy(A), A, check_count(count))
870

871
# Handle ambiguities
872
replace!(a::Callable, b::Pair; count::Integer=-1) = throw(MethodError(replace!, (a, b)))
×
873
replace!(a::Callable, b::Pair, c::Pair; count::Integer=-1) = throw(MethodError(replace!, (a, b, c)))
×
874
replace(a::Callable, b::Pair; count::Integer=-1) = throw(MethodError(replace, (a, b)))
×
875
replace(a::Callable, b::Pair, c::Pair; count::Integer=-1) = throw(MethodError(replace, (a, b, c)))
×
876

877
### replace! for AbstractDict/AbstractSet
878

879
askey(k, ::AbstractDict) = k.first
×
880
askey(k, ::AbstractSet) = k
×
881

882
function _replace!(new::Callable, res::Union{AbstractDict,AbstractSet},
×
883
                   A::Union{AbstractDict,AbstractSet}, count::Int)
884
    @assert res isa AbstractDict && A isa AbstractDict ||
×
885
        res isa AbstractSet && A isa AbstractSet
886
    count == 0 && return res
×
887
    c = 0
×
888
    if res === A # cannot replace elements while iterating over A
×
889
        repl = Pair{eltype(A),eltype(A)}[]
×
890
        for x in A
×
891
            y = new(x)
×
892
            if x !== y
×
893
                push!(repl, x => y)
×
894
                c += 1
×
895
                c == count && break
×
896
            end
897
        end
×
898
        for oldnew in repl
×
899
            pop!(res, askey(first(oldnew), res))
×
900
        end
×
901
        for oldnew in repl
×
902
            push!(res, last(oldnew))
×
903
        end
×
904
    else
905
        for x in A
×
906
            y = new(x)
×
907
            if x !== y
×
908
                pop!(res, askey(x, res))
×
909
                push!(res, y)
×
910
                c += 1
×
911
                c == count && break
×
912
            end
913
        end
×
914
    end
915
    res
×
916
end
917

918
### replace! for AbstractArray
919

920
function _replace!(new::Callable, res::AbstractArray, A::AbstractArray, count::Int)
310✔
921
    c = 0
310✔
922
    if count >= length(A) # simpler loop allows for SIMD
310✔
923
        if res === A # for optimization only
310✔
924
            for i in eachindex(A)
6✔
925
                @inbounds Ai = A[i]
22,020✔
926
                y = new(Ai)
44,040✔
927
                @inbounds A[i] = y
22,020✔
928
            end
44,034✔
929
        else
930
            for i in eachindex(A)
588✔
931
                @inbounds Ai = A[i]
1,849✔
932
                y = new(Ai)
14,100✔
933
                @inbounds res[i] = y
1,849✔
934
            end
1,849✔
935
        end
936
    else
937
        for i in eachindex(A)
×
938
            @inbounds Ai = A[i]
×
939
            if c < count
×
940
                y = new(Ai)
×
941
                @inbounds res[i] = y
×
942
                c += (Ai !== y)
×
943
            else
944
                @inbounds res[i] = Ai
×
945
            end
946
        end
×
947
    end
948
    res
310✔
949
end
950

951
### specialization for Dict / Set
952

953
function _replace!(new::Callable, t::Dict{K,V}, A::AbstractDict, count::Int) where {K,V}
445✔
954
    # we ignore A, which is supposed to be equal to the destination t,
955
    # as it can generally be faster to just replace inline
956
    count == 0 && return t
445✔
957
    c = 0
445✔
958
    news = Pair{K,V}[]
445✔
959
    i = skip_deleted_floor!(t)
2,615✔
960
    @inbounds while i != 0
445✔
961
        k1, v1 = t.keys[i], t.vals[i]
445✔
962
        x1 = Pair{K,V}(k1, v1)
445✔
963
        x2 = new(x1)
662✔
964
        if x1 !== x2
445✔
965
            k2, v2 = first(x2), last(x2)
218✔
966
            if isequal(k1, k2)
218✔
967
                t.keys[i] = k2
×
968
                t.vals[i] = v2
×
969
                t.age += 1
×
970
            else
971
                _delete!(t, i)
218✔
972
                push!(news, x2)
218✔
973
            end
974
            c += 1
218✔
975
            c == count && break
218✔
976
        end
977
        i = i == typemax(Int) ? 0 : skip_deleted(t, i+1)
890✔
978
    end
445✔
979
    for n in news
445✔
980
        push!(t, n)
218✔
981
    end
218✔
982
    t
445✔
983
end
984

985
function _replace!(new::Callable, t::Set{T}, ::AbstractSet, count::Int) where {T}
1✔
986
    _replace!(t.dict, t.dict, count) do kv
445✔
987
        k = first(kv)
445✔
988
        k2 = new(k)
672✔
989
        k2 === k ? kv : k2 => nothing
662✔
990
    end
991
    t
445✔
992
end
993

994
### replace for tuples
995

996
function _replace(f::Callable, t::Tuple, count::Int)
×
997
    if count == 0 || isempty(t)
×
998
        t
×
999
    else
1000
        x = f(t[1])
×
1001
        (x, _replace(f, tail(t), count - !==(x, t[1]))...)
×
1002
    end
1003
end
1004

1005
replace(f::Callable, t::Tuple; count::Integer=typemax(Int)) =
×
1006
    _replace(f, t, check_count(count))
1007

1008
function _replace(t::Tuple, count::Int, old_new::Tuple{Vararg{Pair}})
×
1009
    _replace(t, count) do x
×
1010
        @inline
×
1011
        for o_n in old_new
×
1012
            isequal(first(o_n), x) && return last(o_n)
×
1013
        end
×
1014
        return x
×
1015
    end
1016
end
1017

1018
replace(t::Tuple, old_new::Pair...; count::Integer=typemax(Int)) =
×
1019
    _replace(t, check_count(count), old_new)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc