Skip to content

Commit 7179745

Browse files
authored
Once Base defines radix sort, use that for ::RadixSortAlg (#63)
1 parent 80c14f5 commit 7179745

File tree

1 file changed

+106
-99
lines changed

1 file changed

+106
-99
lines changed

src/SortingAlgorithms.jl

Lines changed: 106 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -67,105 +67,6 @@ function sort!(v::AbstractVector, lo::Int, hi::Int, a::HeapSortAlg, o::Ordering)
6767
end
6868

6969

70-
## Radix sort
71-
72-
# Map a bits-type to an unsigned int, maintaining sort order
73-
uint_mapping(::ForwardOrdering, x::Unsigned) = x
74-
for (signedty, unsignedty) in ((Int8, UInt8), (Int16, UInt16), (Int32, UInt32), (Int64, UInt64), (Int128, UInt128))
75-
# In Julia 0.4 we can just use unsigned() here
76-
@eval uint_mapping(::ForwardOrdering, x::$signedty) = reinterpret($unsignedty, xor(x, typemin(typeof(x))))
77-
end
78-
uint_mapping(::ForwardOrdering, x::Float32) = (y = reinterpret(Int32, x); reinterpret(UInt32, ifelse(y < 0, ~y, xor(y, typemin(Int32)))))
79-
uint_mapping(::ForwardOrdering, x::Float64) = (y = reinterpret(Int64, x); reinterpret(UInt64, ifelse(y < 0, ~y, xor(y, typemin(Int64)))))
80-
81-
uint_mapping(::Sort.Float.Left, x::Float16) = ~reinterpret(Int16, x)
82-
uint_mapping(::Sort.Float.Right, x::Float16) = reinterpret(Int16, x)
83-
uint_mapping(::Sort.Float.Left, x::Float32) = ~reinterpret(Int32, x)
84-
uint_mapping(::Sort.Float.Right, x::Float32) = reinterpret(Int32, x)
85-
uint_mapping(::Sort.Float.Left, x::Float64) = ~reinterpret(Int64, x)
86-
uint_mapping(::Sort.Float.Right, x::Float64) = reinterpret(Int64, x)
87-
88-
uint_mapping(rev::ReverseOrdering, x) = ~uint_mapping(rev.fwd, x)
89-
uint_mapping(::ReverseOrdering{ForwardOrdering}, x::Real) = ~uint_mapping(Forward, x) # maybe unnecessary; needs benchmark
90-
91-
uint_mapping(o::By, x ) = uint_mapping(Forward, o.by(x))
92-
uint_mapping(o::Perm, i::Int) = uint_mapping(o.order, o.data[i])
93-
uint_mapping(o::Lt, x ) = error("uint_mapping does not work with general Lt Orderings")
94-
95-
const RADIX_SIZE = 11
96-
const RADIX_MASK = 0x7FF
97-
98-
function sort!(vs::AbstractVector{T}, lo::Int, hi::Int, ::RadixSortAlg, o::Ordering, ts::AbstractVector{T}=similar(vs)) where T
99-
# Input checking
100-
if lo >= hi; return vs; end
101-
102-
# Make sure we're sorting a bits type
103-
OT = Base.Order.ordtype(o, vs)
104-
if !isbitstype(OT)
105-
error("Radix sort only sorts bits types (got $OT)")
106-
end
107-
108-
# Init
109-
iters = ceil(Integer, sizeof(OT)*8/RADIX_SIZE)
110-
bin = zeros(UInt32, 2^RADIX_SIZE, iters)
111-
if lo > 1; bin[1,:] .= lo-1; end
112-
113-
# Histogram for each element, radix
114-
for i = lo:hi
115-
v = uint_mapping(o, vs[i])
116-
for j = 1:iters
117-
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
118-
@inbounds bin[idx,j] += 1
119-
end
120-
end
121-
122-
# Sort!
123-
swaps = 0
124-
len = hi-lo+1
125-
for j = 1:iters
126-
# Unroll first data iteration, check for degenerate case
127-
v = uint_mapping(o, vs[hi])
128-
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
129-
130-
# are all values the same at this radix?
131-
if bin[idx,j] == len; continue; end
132-
133-
cbin = cumsum(bin[:,j])
134-
ci = cbin[idx]
135-
ts[ci] = vs[hi]
136-
cbin[idx] -= 1
137-
138-
# Finish the loop...
139-
@inbounds for i in hi-1:-1:lo
140-
v = uint_mapping(o, vs[i])
141-
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
142-
ci = cbin[idx]
143-
ts[ci] = vs[i]
144-
cbin[idx] -= 1
145-
end
146-
vs,ts = ts,vs
147-
swaps += 1
148-
end
149-
150-
if isodd(swaps)
151-
vs,ts = ts,vs
152-
for i = lo:hi
153-
vs[i] = ts[i]
154-
end
155-
end
156-
vs
157-
end
158-
159-
function Base.Sort.Float.fpsort!(v::AbstractVector, ::RadixSortAlg, o::Ordering)
160-
@static if VERSION >= v"1.7.0-DEV"
161-
lo, hi = Base.Sort.Float.specials2end!(v, RadixSort, o)
162-
else
163-
lo, hi = Base.Sort.Float.nans2end!(v, o)
164-
end
165-
sort!(v, lo, hi, RadixSort, o)
166-
end
167-
168-
16970
# Implementation of TimSort based on the algorithm description at:
17071
#
17172
# http://svn.python.org/projects/python/trunk/Objects/listsort.txt
@@ -605,6 +506,7 @@ function sort!(v::AbstractVector, lo::Int, hi::Int, ::TimSortAlg, o::Ordering)
605506
return v
606507
end
607508

509+
608510
function sort!(v::AbstractVector, lo::Int, hi::Int, ::CombSortAlg, o::Ordering)
609511
interval = (3 * (hi-lo+1)) >> 2
610512

@@ -619,4 +521,109 @@ function sort!(v::AbstractVector, lo::Int, hi::Int, ::CombSortAlg, o::Ordering)
619521
return sort!(v, lo, hi, InsertionSort, o)
620522
end
621523

524+
525+
## Radix sort
526+
@static if VERSION >= v"1.9.0-DEV.482" # Base introduced radixsort in 1.9
527+
function sort!(vs::AbstractVector{T}, lo::Int, hi::Int, ::RadixSortAlg, o::Ordering, ts::Union{Nothing, AbstractVector{T}}=nothing) where T
528+
sort!(vs, lo, hi, Base.DEFAULT_STABLE, o)
529+
end
530+
else
531+
532+
# Map a bits-type to an unsigned int, maintaining sort order
533+
uint_mapping(::ForwardOrdering, x::Unsigned) = x
534+
for (signedty, unsignedty) in ((Int8, UInt8), (Int16, UInt16), (Int32, UInt32), (Int64, UInt64), (Int128, UInt128))
535+
# In Julia 0.4 we can just use unsigned() here
536+
@eval uint_mapping(::ForwardOrdering, x::$signedty) = reinterpret($unsignedty, xor(x, typemin(typeof(x))))
537+
end
538+
uint_mapping(::ForwardOrdering, x::Float32) = (y = reinterpret(Int32, x); reinterpret(UInt32, ifelse(y < 0, ~y, xor(y, typemin(Int32)))))
539+
uint_mapping(::ForwardOrdering, x::Float64) = (y = reinterpret(Int64, x); reinterpret(UInt64, ifelse(y < 0, ~y, xor(y, typemin(Int64)))))
540+
541+
uint_mapping(::Sort.Float.Left, x::Float16) = ~reinterpret(Int16, x)
542+
uint_mapping(::Sort.Float.Right, x::Float16) = reinterpret(Int16, x)
543+
uint_mapping(::Sort.Float.Left, x::Float32) = ~reinterpret(Int32, x)
544+
uint_mapping(::Sort.Float.Right, x::Float32) = reinterpret(Int32, x)
545+
uint_mapping(::Sort.Float.Left, x::Float64) = ~reinterpret(Int64, x)
546+
uint_mapping(::Sort.Float.Right, x::Float64) = reinterpret(Int64, x)
547+
548+
uint_mapping(rev::ReverseOrdering, x) = ~uint_mapping(rev.fwd, x)
549+
uint_mapping(::ReverseOrdering{ForwardOrdering}, x::Real) = ~uint_mapping(Forward, x) # maybe unnecessary; needs benchmark
550+
551+
uint_mapping(o::By, x ) = uint_mapping(Forward, o.by(x))
552+
uint_mapping(o::Perm, i::Int) = uint_mapping(o.order, o.data[i])
553+
uint_mapping(o::Lt, x ) = error("uint_mapping does not work with general Lt Orderings")
554+
555+
const RADIX_SIZE = 11
556+
const RADIX_MASK = 0x7FF
557+
558+
function sort!(vs::AbstractVector{T}, lo::Int, hi::Int, ::RadixSortAlg, o::Ordering, ts::AbstractVector{T}=similar(vs)) where T
559+
# Input checking
560+
if lo >= hi; return vs; end
561+
562+
# Make sure we're sorting a bits type
563+
OT = Base.Order.ordtype(o, vs)
564+
if !isbitstype(OT)
565+
error("Radix sort only sorts bits types (got $OT)")
566+
end
567+
568+
# Init
569+
iters = ceil(Integer, sizeof(OT)*8/RADIX_SIZE)
570+
bin = zeros(UInt32, 2^RADIX_SIZE, iters)
571+
if lo > 1; bin[1,:] .= lo-1; end
572+
573+
# Histogram for each element, radix
574+
for i = lo:hi
575+
v = uint_mapping(o, vs[i])
576+
for j = 1:iters
577+
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
578+
@inbounds bin[idx,j] += 1
579+
end
580+
end
581+
582+
# Sort!
583+
swaps = 0
584+
len = hi-lo+1
585+
for j = 1:iters
586+
# Unroll first data iteration, check for degenerate case
587+
v = uint_mapping(o, vs[hi])
588+
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
589+
590+
# are all values the same at this radix?
591+
if bin[idx,j] == len; continue; end
592+
593+
cbin = cumsum(bin[:,j])
594+
ci = cbin[idx]
595+
ts[ci] = vs[hi]
596+
cbin[idx] -= 1
597+
598+
# Finish the loop...
599+
@inbounds for i in hi-1:-1:lo
600+
v = uint_mapping(o, vs[i])
601+
idx = Int((v >> ((j-1)*RADIX_SIZE)) & RADIX_MASK) + 1
602+
ci = cbin[idx]
603+
ts[ci] = vs[i]
604+
cbin[idx] -= 1
605+
end
606+
vs,ts = ts,vs
607+
swaps += 1
608+
end
609+
610+
if isodd(swaps)
611+
vs,ts = ts,vs
612+
for i = lo:hi
613+
vs[i] = ts[i]
614+
end
615+
end
616+
vs
617+
end
618+
619+
function Base.Sort.Float.fpsort!(v::AbstractVector, ::RadixSortAlg, o::Ordering)
620+
@static if VERSION >= v"1.7.0-DEV"
621+
lo, hi = Base.Sort.Float.specials2end!(v, RadixSort, o)
622+
else
623+
lo, hi = Base.Sort.Float.nans2end!(v, o)
624+
end
625+
sort!(v, lo, hi, RadixSort, o)
626+
end
627+
end
628+
622629
end # module

0 commit comments

Comments
 (0)