Skip to content

Commit 5e3aeb5

Browse files
authored
Use sampler-based Random API (#222)
1 parent 81297ff commit 5e3aeb5

File tree

3 files changed

+101
-79
lines changed

3 files changed

+101
-79
lines changed

src/ColorTypes.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const Fractional = Union{AbstractFloat, FixedPoint}
88

99
import Base: ==, <, isless, isapprox, isfinite, isinf, isnan, one, oneunit, zero,
1010
hash, eltype, length, real, convert, reinterpret, show
11-
using Random
12-
import Random: rand
11+
using Random: Random, AbstractRNG, SamplerType
12+
import Random: rand, rand!
1313

1414
## Types
1515
export Fractional

src/operations.jl

Lines changed: 86 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -50,79 +50,103 @@ gamutmax(::Type{T}) where {T<:HSL} = (360,1,1)
5050
gamutmin(::Type{T}) where {T<:HSL} = (0,0,0)
5151
gamutmax(::Type{T}) where {T<:Lab} = (100,128,128)
5252
gamutmin(::Type{T}) where {T<:Lab} = (0,-127,-127)
53-
gamutmax(::Type{T}) where {T<:LCHab} = (100,1,360)
53+
gamutmax(::Type{T}) where {T<:LCHab} = (100,1,360) # FIXME
5454
gamutmin(::Type{T}) where {T<:LCHab} = (0,0,0)
55-
gamutmax(::Type{T}) where {T<:YIQ} = (1,0.5226,0.5226)
56-
gamutmin(::Type{T}) where {T<:YIQ} = (0,-0.5957,-0.5957)
55+
gamutmax(::Type{T}) where {T<:YIQ} = (1,0.5226,0.5226) # FIXME
56+
gamutmin(::Type{T}) where {T<:YIQ} = (0,-0.5957,-0.5957) # FIXME
5757

5858
gamutmax(::Type{T}) where {T<:AbstractGray} = (1,)
59-
gamutmax(::Type{T}) where {T<:TransparentGray} = (1,1)
60-
gamutmax(::Type{T}) where {T<:AbstractRGB} = (1,1,1)
61-
gamutmax(::Type{T}) where {T<:TransparentRGB} = (1,1,1,1)
6259
gamutmin(::Type{T}) where {T<:AbstractGray} = (0,)
63-
gamutmin(::Type{T}) where {T<:TransparentGray} = (0,0)
60+
gamutmax(::Type{T}) where {T<:AbstractRGB} = (1,1,1)
6461
gamutmin(::Type{T}) where {T<:AbstractRGB} = (0,0,0)
65-
gamutmin(::Type{T}) where {T<:TransparentRGB} = (0,0,0,0)
62+
63+
gamutmax(::Type{C}) where {C<:TransparentColor} = (gamutmax(color_type(C))..., 1)
64+
gamutmin(::Type{C}) where {C<:TransparentColor} = (gamutmin(color_type(C))..., 0)
6665

6766
# rand
68-
for t in [Float16,Float32,Float64,N0f8,N0f16,N0f32]
69-
@eval _rand(::Type{T}) where {T<:Union{AbstractRGB{$t},AbstractGray{$t}}} =
70-
mapc(x->rand(eltype(T)), base_colorant_type(T)())
71-
end
72-
73-
function _rand(::Type{T}) where T<:Colorant
74-
Gmax = gamutmax(T)
75-
Gmin = gamutmin(T)
76-
Mi = eltype(T) <: FixedPoint ? 1.0/typemax(eltype(T)) : 1.0
77-
A = rand(eltype(T), length(T))
78-
for j in eachindex(Gmax)
79-
A[j] = A[j] * (Mi * (Gmax[j]-Gmin[j])) + Gmin[j]
80-
end
81-
T(A...)
82-
end
83-
84-
if Base.VERSION < v"1.6.0-DEV.1083"
85-
reinterpretc(::Type{T}, A::Array{C}) where {T<:Real,C<:AbstractGray} = reinterpret(T, A)
86-
reinterpretc(::Type{T}, A::Array{C}) where {T<:Real,C<:Colorant} = reshape(reinterpret(T, A), (sizeof(C)÷sizeof(T), size(A)...))
87-
else
88-
reinterpretc(::Type{T}, A::Array{C}) where {T<:Real,C<:Colorant} = reinterpret(reshape, T, A)
89-
end
90-
91-
function _rand(::Type{T}, sz::Dims) where T<:Colorant
92-
Mi = eltype(T) <: FixedPoint ? 1.0/typemax(eltype(T)) : 1.0
93-
A = Array{T}(undef, sz)
94-
Tr = eltype(T) <: FixedPoint ? FixedPointNumbers.rawtype(eltype(T)) : eltype(T)
95-
nchannels = sizeof(T)÷sizeof(eltype(T))
96-
Au = Random.UnsafeView(convert(Ptr{Tr}, pointer(A)), length(A)*nchannels)
97-
rand!(Au)
98-
99-
Gmax = gamutmax(T)
100-
Gmin = gamutmin(T)
101-
s = (Gmax .- Gmin) .* Mi
102-
if !all(iszero, Gmin) || !all(==(1), s)
103-
Ar = reinterpretc(eltype(T), A)
104-
if T<:AbstractGray
105-
s1, offset1 = s[1], Gmin[1]
106-
for I in CartesianIndices(A)
107-
Ar[I] = Ar[I] * s1 + offset1
108-
end
109-
else
110-
for I in CartesianIndices(A)
111-
for j in eachindex(s)
112-
Ar[j,I] = Ar[j,I] * s[j] + Gmin[j]
113-
end
114-
end
115-
end
67+
const Rand01Normd = Union{N0f8, N0f16, N0f32, N0f64}
68+
const Rand01Type = Union{AbstractFloat, Rand01Normd}
69+
70+
# TODO: Remove the following once it is guaranteed to be implemented in FixedPointNumbers.
71+
if which(rand, Tuple{AbstractRNG, SamplerType{<:FixedPoint}}).module === Random
72+
function rand(r::AbstractRNG, ::SamplerType{X}) where X <: FixedPoint
73+
reinterpret(X, rand(r, FixedPointNumbers.rawtype(X)))
11674
end
117-
return A
11875
end
11976

120-
rand(::Type{T}, sz::Dims...) where {T<:Colorant} = _rand(ccolor(T, base_colorant_type(T){Float64}), sz...)
77+
function rand(r::AbstractRNG, ::SamplerType{C}) where {C<:Colorant}
78+
rand(r, base_colorant_type(C){Float64})
79+
end
80+
function rand(r::AbstractRNG, ::SamplerType{C}) where {T, C<:Colorant{T}}
81+
Cmax = C(gamutmax(C)...)
82+
Cmin = C(gamutmin(C)...)
83+
mapc((m, n) -> T((m - n) * rand(r, floattype(T)) + n), Cmax, Cmin)
84+
end
85+
function rand(r::AbstractRNG, ::SamplerType{C}) where {T<:Rand01Type, C0<:AbstractGray{T},
86+
C<:Union{C0, TransparentGray{C0, T}}}
87+
mapc(_ -> rand(r, T), base_colorant_type(C)())
88+
end
89+
function rand(r::AbstractRNG, ::SamplerType{C}) where {T<:Rand01Type, C0<:AbstractRGB{T},
90+
C<:Union{C0, TransparentRGB{C0, T}}}
91+
mapc(_ -> rand(r, T), base_colorant_type(C)())
92+
end
93+
function rand(r::AbstractRNG, ::SamplerType{AGray32}) # Gray24 has little benefit of specialization.
94+
reinterpret(AGray32, (rand(r, UInt32) & 0xff0000ff) * 0x010101)
95+
end
96+
rand(r::AbstractRNG, ::SamplerType{RGB24}) = reinterpret(RGB24, rand(r, UInt32) & 0xffffff)
97+
rand(r::AbstractRNG, ::SamplerType{ARGB32}) = reinterpret(ARGB32, rand(r, UInt32))
98+
99+
function rand(r::AbstractRNG, ::Type{C}, dims::Dims) where {C <: Colorant}
100+
CC = isconcretetype(C) ? C : base_colorant_type(C){Float64}
101+
rand!(r, Array{CC}(undef, dims), CC)
102+
end
121103

122-
rand(::Type{Gray24}) = Gray24(rand(N0f8))
123-
rand(::Type{Gray24}, sz::Dims) = Gray24.(rand(N0f8,sz))
124-
rand(::Type{AGray32}) = AGray32(rand(N0f8),rand(N0f8))
125-
rand(::Type{AGray32}, sz::Dims) = AGray32.(rand(N0f8,sz),rand(N0f8,sz))
104+
# rand!
105+
function rand!(r::AbstractRNG, A::Array{C}, ::SamplerType{C}) where {C<:Colorant}
106+
rand!(r, A, SamplerType{base_colorant_type(C){Float64}}())
107+
end
108+
function rand!(r::AbstractRNG, A::Array{C}, ::SamplerType{C}) where {T, C<:Colorant{T}}
109+
A .= rand.((r,), C)
110+
end
111+
function _rand01!(r::AbstractRNG, A::Array{C},
112+
::SamplerType{C}) where {T<:Rand01Type, C<:Colorant{T}}
113+
N = sizeof(C) ÷ sizeof(T)
114+
T0 = T <: FixedPoint ? FixedPointNumbers.rawtype(T) : T
115+
At = unsafe_wrap(Array, reinterpret(Ptr{T0}, pointer(A)), (N, size(A)...))
116+
rand!(r, At, T0)
117+
A
118+
end
119+
function rand!(r::AbstractRNG, A::Array{C},
120+
s::SamplerType{C}) where {T<:AbstractFloat, C<:Colorant{T}}
121+
_rand01!(r, A, s)
122+
Cmin = C(gamutmin(C)...)
123+
Cs = C((gamutmax(C) .- gamutmin(C))...)
124+
f(c) = mapc((a, b) -> T(a + b), mapc(*, c, Cs), Cmin)
125+
A .= f.(A)
126+
end
127+
function rand!(r::AbstractRNG, A::Array{C},
128+
s::SamplerType{C}) where {T<:Rand01Type, C<:Union{Gray{T}, AGray{T}, GrayA{T}}}
129+
_rand01!(r, A, s)
130+
end
131+
function rand!(r::AbstractRNG, A::Array{C},
132+
s::SamplerType{C}) where {T<:Rand01Type,
133+
C<:Union{RGB{T}, ARGB{T}, RGBA{T}, XRGB{T}, RGBX{T},
134+
BGR{T}, ABGR{T}, BGRA{T}}}
135+
_rand01!(r, A, s)
136+
end
137+
function rand!(r::AbstractRNG, A::Array{C},
138+
::SamplerType{C}) where {C<:Union{Gray24, AGray32, RGB24, ARGB32}}
139+
At = unsafe_wrap(Array, reinterpret(Ptr{UInt32}, pointer(A)), size(A))
140+
rand!(r, At, UInt32)
141+
if C === Gray24
142+
At .= At .& 0xff .* 0x010101
143+
elseif C === AGray32
144+
At .= At .& 0xff0000ff .* 0x010101
145+
elseif C === RGB24
146+
At .&= 0xffffff
147+
end
148+
A
149+
end
126150

127151
# broadcast
128152

test/operations.jl

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ end
140140
all(((f, gmin, gmax),) -> gmin <= getfield(c, f) <= gmax,
141141
zip(ColorTypes.colorfields(C), gamutmin(C), gamutmax(C)))
142142
end
143-
eltypes = (N0f8, N2f6, N0f16, N2f14, N0f32, N2f30, Float16, Float32, Float64)
143+
eltypes = (N0f8, N2f6, N0f16, N2f14, N0f32, N2f30, Q3f12,
144+
Float16, Float32, Float64)
144145
@testset "rand($C)" for C in (
145146
(Gray{T} for T in eltypes)...,
146147
(RGB{T} for T in eltypes)...,
@@ -152,10 +153,6 @@ end
152153
RGB, ARGB, RGBA, BGR, ABGR, BGRA, XRGB, RGBX,
153154
HSV, HSL, Lab, LCHab, YIQ,
154155
AHSV, HSLA)
155-
if C <: Transparent3 && !(C <: TransparentRGB)
156-
@test_broken rand(C)
157-
continue
158-
end
159156
CC = isconcretetype(C) ? C : C{Float64}
160157
c = rand(C)
161158
@test c isa CC
@@ -168,24 +165,25 @@ end
168165
ap = a'
169166
@test ap[1, 1] == a[1, 1]
170167
end
171-
@testset "rand($C)" for C in (Gray24, AGray32)
168+
@testset "rand($C)" for C in (Gray24, AGray32, RGB24, ARGB32)
172169
c = rand(C)
173-
b = c.color
174-
@test b&0xff == (b>>8)&0xff == (b>>16)&0xff
175170
@test c isa C
176171
a = rand(C, 3, 5)
172+
@test eltype(a) === C
173+
@test size(a) == (3, 5)
174+
C in (RGB24, ARGB32) && continue
175+
b = c.color
176+
@test b&0xff == (b>>8)&0xff == (b>>16)&0xff
177177
for el in a
178178
b = el.color
179179
@test b&0xff == (b>>8)&0xff == (b>>16)&0xff
180180
end
181-
@test eltype(a) === C
182-
@test size(a) == (3, 5)
183181
end
184-
@test_broken rand(RGB24)
185-
@test_broken rand(ARGB32)
186-
@test_broken rand(MersenneTwister(), RGB{N0f8})
187-
@test_broken rand!(Gray{Float32}[0.0, 0.1])
188-
@test_broken all(all_in_range, rand(ARGB{Q3f12}, 10, 10))
182+
@test rand(MersenneTwister(), RGB{N0f8}) isa RGB{N0f8}
183+
@test rand!(Gray{Float32}[0.0, 0.1]) isa Vector{Gray{Float32}}
184+
a = rand!(Array{RGB}(undef, 3, 5))
185+
@test a isa Matrix{RGB}
186+
@test typeof(a[1,1]) === RGB{Float64}
189187
@test_broken all_in_range(LCHab(50, 10, 359))
190188
@test_broken all_in_range(YIQ(0.5, 0.59, 0.0))
191189
@test_broken !all_in_range(YIQ(0.5, 0.0, -0.53))

0 commit comments

Comments
 (0)