|
263 | 263 |
|
264 | 264 | @eval split_rest(t::Tuple, n::Int, i=1) = ($(Expr(:meta, :aggressive_constprop)); (t[i:end-n], t[end-n+1:end])) |
265 | 265 |
|
266 | | -# Use dispatch to avoid a branch in first |
267 | | -first(::Tuple{}) = throw(ArgumentError("tuple must be non-empty")) |
268 | | -first(t::Tuple) = t[1] |
| 266 | +function first(t::Tuple) |
| 267 | + f(t::Tuple) = t[1] |
| 268 | + function f(::Tuple{}) |
| 269 | + @noinline |
| 270 | + throw(ArgumentError("tuple must be non-empty")) |
| 271 | + end |
| 272 | + f(t) |
| 273 | +end |
269 | 274 |
|
270 | 275 | # eltype |
271 | 276 |
|
@@ -577,71 +582,95 @@ function _eq(t1::Any32, t2::Any32) |
577 | 582 | end |
578 | 583 |
|
579 | 584 | const tuplehash_seed = UInt === UInt64 ? 0x77cfa1eef01bca90 : 0xf01bca90 |
580 | | -hash(::Tuple{}, h::UInt) = h ⊻ tuplehash_seed |
581 | | -hash(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h)) |
582 | | -function hash(t::Any32, h::UInt) |
583 | | - out = h ⊻ tuplehash_seed |
584 | | - for i = length(t):-1:1 |
585 | | - out = hash(t[i], out) |
| 585 | +function hash(t::Tuple, h::UInt) |
| 586 | + f(::Tuple{}, h::UInt) = h ⊻ tuplehash_seed |
| 587 | + f(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h)) |
| 588 | + function f(t::Any32, h::UInt) |
| 589 | + out = h ⊻ tuplehash_seed |
| 590 | + for i = length(t):-1:1 |
| 591 | + out = hash(t[i], out) |
| 592 | + end |
| 593 | + return out |
586 | 594 | end |
587 | | - return out |
| 595 | + f(t, h) |
588 | 596 | end |
589 | 597 |
|
590 | | -<(::Tuple{}, ::Tuple{}) = false |
591 | | -<(::Tuple{}, ::Tuple) = true |
592 | | -<(::Tuple, ::Tuple{}) = false |
593 | 598 | function <(t1::Tuple, t2::Tuple) |
594 | | - a, b = t1[1], t2[1] |
595 | | - eq = (a == b) |
596 | | - if ismissing(eq) |
597 | | - return missing |
598 | | - elseif !eq |
599 | | - return a < b |
600 | | - end |
601 | | - return tail(t1) < tail(t2) |
602 | | -end |
603 | | -function <(t1::Any32, t2::Any32) |
604 | | - n1, n2 = length(t1), length(t2) |
605 | | - for i = 1:min(n1, n2) |
606 | | - a, b = t1[i], t2[i] |
| 599 | + f(::Tuple{}, ::Tuple{}) = false |
| 600 | + f(::Tuple{}, ::Tuple) = true |
| 601 | + f(::Tuple, ::Tuple{}) = false |
| 602 | + function f(t1::Tuple, t2::Tuple) |
| 603 | + a, b = t1[1], t2[1] |
607 | 604 | eq = (a == b) |
608 | 605 | if ismissing(eq) |
609 | 606 | return missing |
610 | 607 | elseif !eq |
611 | | - return a < b |
| 608 | + return a < b |
| 609 | + end |
| 610 | + return tail(t1) < tail(t2) |
| 611 | + end |
| 612 | + function f(t1::Any32, t2::Any32) |
| 613 | + n1, n2 = length(t1), length(t2) |
| 614 | + for i = 1:min(n1, n2) |
| 615 | + a, b = t1[i], t2[i] |
| 616 | + eq = (a == b) |
| 617 | + if ismissing(eq) |
| 618 | + return missing |
| 619 | + elseif !eq |
| 620 | + return a < b |
| 621 | + end |
612 | 622 | end |
| 623 | + return n1 < n2 |
613 | 624 | end |
614 | | - return n1 < n2 |
| 625 | + f(t1, t2) |
615 | 626 | end |
616 | 627 |
|
617 | | -isless(::Tuple{}, ::Tuple{}) = false |
618 | | -isless(::Tuple{}, ::Tuple) = true |
619 | | -isless(::Tuple, ::Tuple{}) = false |
| 628 | +# copy of `BitInteger` defined later during bootstrap in int.jl |
| 629 | +const _BitInteger = Union{ |
| 630 | + Int8, Int16, Int32, Int64, Int128, |
| 631 | + UInt8, UInt16, UInt32, UInt64, UInt128, |
| 632 | +} |
620 | 633 |
|
621 | 634 | """ |
622 | 635 | isless(t1::Tuple, t2::Tuple) |
623 | 636 |
|
624 | 637 | Return `true` when `t1` is less than `t2` in lexicographic order. |
625 | 638 | """ |
626 | 639 | function isless(t1::Tuple, t2::Tuple) |
627 | | - a, b = t1[1], t2[1] |
628 | | - isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2))) |
629 | | -end |
630 | | -function isless(t1::Any32, t2::Any32) |
631 | | - n1, n2 = length(t1), length(t2) |
632 | | - for i = 1:min(n1, n2) |
633 | | - a, b = t1[i], t2[i] |
634 | | - if !isequal(a, b) |
635 | | - return isless(a, b) |
| 640 | + f(::Tuple{}, ::Tuple{}) = false |
| 641 | + f(::Tuple{}, ::Tuple) = true |
| 642 | + f(::Tuple, ::Tuple{}) = false |
| 643 | + function f(t1::Tuple, t2::Tuple) |
| 644 | + a, b = t1[1], t2[1] |
| 645 | + isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2))) |
| 646 | + end |
| 647 | + function f(t1::Any32, t2::Any32) |
| 648 | + n1, n2 = length(t1), length(t2) |
| 649 | + for i = 1:min(n1, n2) |
| 650 | + a, b = t1[i], t2[i] |
| 651 | + if !isequal(a, b) |
| 652 | + return isless(a, b) |
| 653 | + end |
636 | 654 | end |
| 655 | + return n1 < n2 |
| 656 | + end |
| 657 | + # Performance optimization to reduce branching |
| 658 | + # This is useful for sorting tuples of integers |
| 659 | + # TODO: remove this when the compiler can optimize the generic version better |
| 660 | + # See #48724 and #48753 |
| 661 | + function isless(a::Tuple{_BitInteger, _BitInteger}, b::Tuple{_BitInteger, _BitInteger}) |
| 662 | + isless(a[1], b[1]) | (isequal(a[1], b[1]) & isless(a[2], b[2])) |
637 | 663 | end |
638 | | - return n1 < n2 |
| 664 | + f(t1, t2) |
639 | 665 | end |
640 | 666 |
|
641 | 667 | ## functions ## |
642 | 668 |
|
643 | | -isempty(x::Tuple{}) = true |
644 | | -isempty(@nospecialize x::Tuple) = false |
| 669 | +function isempty(x::Tuple) |
| 670 | + f(x::Tuple{}) = true |
| 671 | + f(@nospecialize x::Tuple) = false |
| 672 | + f(x) |
| 673 | +end |
645 | 674 |
|
646 | 675 | revargs() = () |
647 | 676 | revargs(x, r...) = (revargs(r...)..., x) |
@@ -679,11 +708,14 @@ empty(@nospecialize x::Tuple) = () |
679 | 708 | foreach(f, itr::Tuple) = foldl((_, x) -> (f(x); nothing), itr, init=nothing) |
680 | 709 | foreach(f, itr::Tuple, itrs::Tuple...) = foldl((_, xs) -> (f(xs...); nothing), zip(itr, itrs...), init=nothing) |
681 | 710 |
|
682 | | -circshift((@nospecialize t::Union{Tuple{},Tuple{Any}}), @nospecialize _::Integer) = t |
683 | | -circshift(t::Tuple{Any,Any}, shift::Integer) = iseven(shift) ? t : reverse(t) |
684 | | -function circshift(x::Tuple{Any,Any,Any,Vararg{Any,N}}, shift::Integer) where {N} |
685 | | - @inline |
686 | | - len = N + 3 |
687 | | - j = mod1(shift, len) |
688 | | - ntuple(k -> getindex(x, k-j+ifelse(k>j,0,len)), Val(len))::Tuple |
| 711 | +function circshift(t::Tuple, shift::Integer) |
| 712 | + f((@nospecialize t::Union{Tuple{},Tuple{Any}}), @nospecialize _::Integer) = t |
| 713 | + f(t::Tuple{Any,Any}, shift::Integer) = iseven(shift) ? t : reverse(t) |
| 714 | + function f(x::Tuple{Any,Any,Any,Vararg{Any,N}}, shift::Integer) where {N} |
| 715 | + @inline |
| 716 | + len = N + 3 |
| 717 | + j = mod1(shift, len) |
| 718 | + ntuple(k -> getindex(x, k-j+ifelse(k>j,0,len)), Val(len))::Tuple |
| 719 | + end |
| 720 | + f(t, shift) |
689 | 721 | end |
0 commit comments