@@ -7,14 +7,68 @@ module BitFlags
77import Core. Intrinsics. bitcast
88export BitFlag, @bitflag
99
10- function basetype end
10+ function namemap end
11+ function haszero end
1112
1213abstract type BitFlag{T<: Integer } end
1314
15+ basetype (:: Type{<:BitFlag{T}} ) where {T<: Integer } = T
16+
1417(:: Type{T} )(x:: BitFlag{T2} ) where {T<: Integer ,T2<: Unsigned } = T (bitcast (T2, x)):: T
1518Base. cconvert (:: Type{T} , x:: BitFlag{T2} ) where {T<: Unsigned ,T2<: Unsigned } = T (x)
1619Base. write (io:: IO , x:: BitFlag{T} ) where {T<: Unsigned } = write (io, T (x))
17- Base. read (io:: IO , :: Type{T} ) where {T<: BitFlag } = T (read (io, BitFlags. basetype (T)))
20+ Base. read (io:: IO , :: Type{T} ) where {T<: BitFlag } = T (read (io, basetype (T)))
21+
22+ Base. isless (x:: T , y:: T ) where {T<: BitFlag } = isless (basetype (T)(x), basetype (T)(y))
23+ Base.:| (x:: T , y:: T ) where {T<: BitFlag } = T (Integer (x) | Integer (y))
24+ Base.:& (x:: T , y:: T ) where {T<: BitFlag } = T (Integer (x) & Integer (y))
25+
26+ function Base. print (io:: IO , x:: T ) where T<: BitFlag
27+ compact = get (io, :compact , false )
28+ xi = Integer (x)
29+ multi = (haszero (T) && ! iszero (xi)) && ! compact && ! ispow2 (xi)
30+ first = true
31+ sep = compact ? " |" : " | "
32+ for (i, sym) in Iterators. reverse (namemap (T))
33+ if haszero (T) && iszero (i) && iszero (xi)
34+ print (io, sym)
35+ break
36+ end
37+ if ! iszero (i & xi)
38+ if first
39+ multi && print (io, " (" )
40+ first = false
41+ else
42+ print (io, sep)
43+ end
44+ print (io, sym)
45+ end
46+ end
47+ multi && print (io, " )" )
48+ nothing
49+ end
50+ function Base. show (io:: IO , x:: BitFlag )
51+ if get (io, :compact , false )
52+ print (io, x)
53+ else
54+ print (io, x, " ::" )
55+ show (IOContext (io, :compact => true ), typeof (x))
56+ print (io, " = " )
57+ show (io, Integer (x))
58+ end
59+ end
60+ function Base. show (io:: IO , t:: Type{BitFlag} )
61+ Base. show_datatype (io, t)
62+ end
63+ function Base. show (io:: IO , :: MIME"text/plain" , t:: Type{<:BitFlag} )
64+ print (io, " BitFlag " )
65+ Base. show_datatype (io, t)
66+ print (io, " :" )
67+ for x in instances (t)
68+ print (io, " \n " , Symbol (x), " = " )
69+ show (io, Integer (x))
70+ end
71+ end
1872
1973# generate code to test whether expr is in the given set of values
2074function membershiptest (expr, zmask)
@@ -86,7 +140,9 @@ macro bitflag(T, syms...)
86140 elseif ! isa (T, Symbol)
87141 throw (ArgumentError (" invalid type expression for bit flag $T " ))
88142 end
89- vals = Vector {Tuple{Symbol,Unsigned}} ()
143+ values = basetype[]
144+ seen = Set {Symbol} ()
145+ namemap = Vector {Tuple{basetype,Symbol}} ()
90146 lo = hi = zero (basetype)
91147 maskzero, maskother = false , zero (basetype)
92148 i = oneunit (basetype)
@@ -120,26 +176,33 @@ macro bitflag(T, syms...)
120176 end
121177 if ! Base. isidentifier (s)
122178 throw (ArgumentError (" invalid name for BitFlag $typename ; "
123- * " \" $s \" is not a valid identifier. " ))
179+ * " \" $s \" is not a valid identifier" ))
124180 end
125181 if (iszero (i) && maskzero) || (i & maskother) != 0
126182 throw (ArgumentError (" values for BitFlag $typename are not unique" ))
127183 end
128- push! (vals, (s,i))
184+ push! (namemap, (i,s))
185+ push! (values, i)
186+ if s in seen
187+ throw (ArgumentError (" name \" $s \" in BitFlag $typename is not unique" ))
188+ end
189+ push! (seen, s)
129190 if iszero (i)
130191 maskzero = true
131192 else
132193 maskother |= i
133194 end
134- if length (vals ) == 1
195+ if length (values ) == 1
135196 lo = hi = i
136197 else
137198 lo = min (lo, i)
138199 hi = max (hi, i)
139200 end
140201 i = iszero (i) ? oneunit (i) : two* i
141202 end
142- values = basetype[i[2 ] for i in vals]
203+ order = sortperm ([v[1 ] for v in namemap])
204+ permute! (namemap, order)
205+ permute! (values, order)
143206 blk = quote
144207 # bitflag definition
145208 Base. @__doc__ (primitive type $ (esc (typename)) <: BitFlag{$(basetype)} $ (sizeof (basetype) * 8 ) end )
@@ -148,67 +211,16 @@ macro bitflag(T, syms...)
148211 bitflag_argument_error ($ (Expr (:quote , typename)), x)
149212 return bitcast ($ (esc (typename)), convert ($ (basetype), x))
150213 end
151- BitFlags. basetype (:: Type{$(esc(typename))} ) = $ (esc (basetype))
214+ BitFlags. namemap (:: Type{$(esc(typename))} ) = $ (esc (namemap))
215+ BitFlags. haszero (:: Type{$(esc(typename))} ) = $ (esc (maskzero))
152216 Base. typemin (x:: Type{$(esc(typename))} ) = $ (esc (typename))($ lo)
153217 Base. typemax (x:: Type{$(esc(typename))} ) = $ (esc (typename))($ hi)
154- Base. isless (x:: $ (esc (typename)), y:: $ (esc (typename))) =
155- isless ($ basetype (x), $ basetype (y))
156- Base.:| (x:: $ (esc (typename)), y:: $ (esc (typename))) =
157- $ (esc (typename))($ basetype (x) | $ basetype (y))
158- Base.:& (x:: $ (esc (typename)), y:: $ (esc (typename))) =
159- $ (esc (typename))($ basetype (x) & $ basetype (y))
160- let insts = ntuple (i-> $ (esc (typename))($ values[i]), $ (length (vals)))
218+ let insts = ntuple (i-> $ (esc (typename))($ values[i]), $ (length (values)))
161219 Base. instances (:: Type{$(esc(typename))} ) = insts
162220 end
163- function Base. print (io:: IO , x:: $ (esc (typename)))
164- compact = get (io, :compact , false )
165- xi = $ (basetype)(x)
166- multi = ($ maskzero && ! iszero (xi)) && ! compact && ! ispow2 (xi)
167- first = true
168- sep = compact ? " |" : " | "
169- for (sym, i) in $ vals
170- if $ maskzero && iszero (i) && iszero (xi)
171- print (io, sym)
172- break
173- end
174- if ! iszero (i & xi)
175- if first
176- multi && print (io, " (" )
177- first = false
178- else
179- print (io, sep)
180- end
181- print (io, sym)
182- end
183- end
184- multi && print (io, " )" )
185- nothing
186- end
187- function Base. show (io:: IO , x:: $ (esc (typename)))
188- if get (io, :compact , false )
189- print (io, x)
190- else
191- print (io, x, " ::" )
192- show (IOContext (io, :compact => true ), typeof (x))
193- print (io, " = " )
194- show (io, $ basetype (x))
195- end
196- end
197- function Base. show (io:: IO , t:: Type{$(esc(typename))} )
198- Base. show_datatype (io, t)
199- end
200- function Base. show (io:: IO , :: MIME"text/plain" , t:: Type{$(esc(typename))} )
201- print (io, " BitFlag " )
202- Base. show_datatype (io, t)
203- print (io, " :" )
204- for (sym, i) in $ vals
205- print (io, " \n " , sym, " = " )
206- show (io, i)
207- end
208- end
209221 end
210222 if isa (typename, Symbol)
211- for (sym,i ) in vals
223+ for (i, sym ) in namemap
212224 push! (blk. args, :(const $ (esc (sym)) = $ (esc (typename))($ i)))
213225 end
214226 end
0 commit comments