Skip to content

Commit 64b396b

Browse files
committed
replace field_offset and fieldoffset with fieldoffset
`field_offset` was untested, undocumented, unexported, and incorrect (off-by-one error in implementation) `fieldoffset` just isn't particularly optimal, since it has to allocate a new array each time also make minor cleanup and test-coverage enhancements to related reflection methods
1 parent 70477b7 commit 64b396b

File tree

9 files changed

+121
-75
lines changed

9 files changed

+121
-75
lines changed

base/deprecated.jl

+11
Original file line numberDiff line numberDiff line change
@@ -967,3 +967,14 @@ end
967967
#https://github.com/JuliaLang/julia/issues/14608
968968
@deprecate readall readstring
969969
@deprecate readbytes read
970+
971+
@deprecate field_offset(x::DataType, idx) fieldoffset(x, idx+1)
972+
@noinline function fieldoffsets(x::DataType)
973+
depwarn("fieldoffsets deprecated. use `map(idx->fieldoffset(x, idx), 1:nfields(x))` instead", :fieldoffsets)
974+
nf = nfields(x)
975+
offsets = Array(Int, nf)
976+
for i = 1:nf
977+
offsets[i] = fieldoffset(x, i)
978+
end
979+
return offsets
980+
end

base/docs/helpdb/Base.jl

-41
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,6 @@ Compute a "2d histogram" with respect to the bins delimited by the edges given i
313313
"""
314314
hist2d!
315315

316-
"""
317-
fieldtype(T, name::Symbol | index::Int)
318-
319-
Determine the declared type of a field (specified by name or index) in a composite DataType `T`.
320-
"""
321-
fieldtype
322-
323316
"""
324317
hypot(x, y)
325318
@@ -1968,13 +1961,6 @@ shift in each dimension.
19681961
"""
19691962
circshift
19701963

1971-
"""
1972-
fieldnames(x::DataType)
1973-
1974-
Get an array of the fields of a `DataType`.
1975-
"""
1976-
fieldnames
1977-
19781964
"""
19791965
yield()
19801966
@@ -2086,33 +2072,6 @@ Right bit shift operator, preserving the sign of `x`.
20862072
"""
20872073
Base.(:(>>))
20882074

2089-
"""
2090-
fieldoffsets(type)
2091-
2092-
The byte offset of each field of a type relative to the data start. For example, we could
2093-
use it in the following manner to summarize information about a struct type:
2094-
2095-
```jldoctest
2096-
julia> structinfo(T) = [zip(fieldoffsets(T),fieldnames(T),T.types)...];
2097-
2098-
julia> structinfo(StatStruct)
2099-
12-element Array{Tuple{Int64,Symbol,DataType},1}:
2100-
(0,:device,UInt64)
2101-
(8,:inode,UInt64)
2102-
(16,:mode,UInt64)
2103-
(24,:nlink,Int64)
2104-
(32,:uid,UInt64)
2105-
(40,:gid,UInt64)
2106-
(48,:rdev,UInt64)
2107-
(56,:size,Int64)
2108-
(64,:blksize,Int64)
2109-
(72,:blocks,Int64)
2110-
(80,:mtime,Float64)
2111-
(88,:ctime,Float64)
2112-
```
2113-
"""
2114-
fieldoffsets
2115-
21162075
"""
21172076
randn([rng], [dims...])
21182077

base/exports.jl

+2-1
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,8 @@ export
10481048

10491049
# types
10501050
convert,
1051-
fieldoffsets,
1051+
fieldoffset,
1052+
fieldname,
10521053
fieldnames,
10531054
isleaftype,
10541055
oftype,

base/reflection.jl

+50-14
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,26 @@ function resolve(g::GlobalRef; force::Bool=false)
5151
return g
5252
end
5353

54-
fieldnames(t::DataType) = Symbol[n for n in t.name.names ]
54+
"""
55+
fieldname(x::DataType, i)
56+
57+
Get the name of field `i` of a `DataType`.
58+
"""
59+
fieldname(t::DataType, i::Integer) = t.name.names[i]::Symbol
60+
61+
"""
62+
fieldnames(x::DataType)
63+
64+
Get an array of the fields of a `DataType`.
65+
"""
5566
function fieldnames(v)
5667
t = typeof(v)
5768
if !isa(t,DataType)
5869
throw(ArgumentError("cannot call fieldnames() on a non-composite type"))
5970
end
6071
return fieldnames(t)
6172
end
62-
63-
fieldname(t::DataType, i::Integer) = t.name.names[i]::Symbol
73+
fieldnames(t::DataType) = Symbol[fieldname(t, n) for n in 1:nfields(t)]
6474

6575
isconst(s::Symbol) = ccall(:jl_is_const, Int32, (Ptr{Void}, Any), C_NULL, s) != 0
6676

@@ -82,14 +92,41 @@ isleaftype(t::ANY) = (@_pure_meta; ccall(:jl_is_leaf_type, Int32, (Any,), t) !=
8292
typeintersect(a::ANY,b::ANY) = (@_pure_meta; ccall(:jl_type_intersection, Any, (Any,Any), a, b))
8393
typeseq(a::ANY,b::ANY) = (@_pure_meta; a<:b && b<:a)
8494

85-
function fieldoffsets(x::DataType)
86-
offsets = Array(Int, nfields(x))
87-
ccall(:jl_field_offsets, Void, (Any, Ptr{Int}), x, offsets)
88-
offsets
89-
end
90-
91-
type_alignment(x::DataType) = (@_pure_meta; ccall(:jl_get_alignment,Csize_t,(Any,),x))
92-
field_offset(x::DataType,idx) = (@_pure_meta; ccall(:jl_get_field_offset,Csize_t,(Any,Int32),x,idx))
95+
"""
96+
fieldoffset(type, i)
97+
98+
The byte offset of field `i` of a type relative to the data start. For example, we could
99+
use it in the following manner to summarize information about a struct type:
100+
101+
```jldoctest
102+
julia> structinfo(T) = [i -> (fieldoffset(T,i), fieldname(T,i), fieldtype(T,i)) for i = 1:nfields(T)];
103+
104+
julia> structinfo(StatStruct)
105+
12-element Array{Tuple{Int64,Symbol,DataType},1}:
106+
(0,:device,UInt64)
107+
(8,:inode,UInt64)
108+
(16,:mode,UInt64)
109+
(24,:nlink,Int64)
110+
(32,:uid,UInt64)
111+
(40,:gid,UInt64)
112+
(48,:rdev,UInt64)
113+
(56,:size,Int64)
114+
(64,:blksize,Int64)
115+
(72,:blocks,Int64)
116+
(80,:mtime,Float64)
117+
(88,:ctime,Float64)
118+
```
119+
"""
120+
fieldoffset(x::DataType, idx::Integer) = (@_pure_meta; ccall(:jl_get_field_offset, Csize_t, (Any, Cint), x, idx))
121+
122+
"""
123+
fieldtype(T, name::Symbol | index::Int)
124+
125+
Determine the declared type of a field (specified by name or index) in a composite DataType `T`.
126+
"""
127+
fieldtype
128+
129+
type_alignment(x::DataType) = (@_pure_meta; ccall(:jl_get_alignment, Csize_t, (Any,), x))
93130

94131
# return all instances, for types that can be enumerated
95132
function instances end
@@ -266,10 +303,9 @@ function code_typed(f::Function, types::ANY=Tuple; optimize=true)
266303
optimize=false)
267304
end
268305
if !isa(tree, Expr)
269-
push!(asts, ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, tree))
270-
else
271-
push!(asts, tree)
306+
tree = ccall(:jl_uncompress_ast, Any, (Any,Any), linfo, tree)
272307
end
308+
push!(asts, tree)
273309
end
274310
asts
275311
end

base/sparse/cholmod.jl

+1-3
Original file line numberDiff line numberDiff line change
@@ -1035,11 +1035,9 @@ sparse{Tv}(FC::FactorComponent{Tv,:LD}) = sparse(Sparse(Factor(FC)))
10351035

10361036
# Calculate the offset into the stype field of the cholmod_sparse_struct and
10371037
# change the value
1038-
let offidx=findfirst(fieldnames(C_Sparse) .== :stype)
1039-
1038+
let offset = fieldoffset(C_Sparse{Float64}, findfirst(fieldnames(C_Sparse) .== :stype))
10401039
global change_stype!
10411040
function change_stype!(A::Sparse, i::Integer)
1042-
offset = fieldoffsets(C_Sparse)[offidx]
10431041
unsafe_store!(convert(Ptr{Cint}, A.p), i, div(offset, 4) + 1)
10441042
return A
10451043
end

doc/devdocs/reflection.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ The internal representation of a :obj:`DataType` is critically important when in
7474
C code and several functions are available to inspect these details.
7575
:func:`isbits(T::DataType) <isbits>` returns true if ``T`` is
7676
stored with C-compatible alignment.
77-
:func:`fieldoffsets(T::DataType) <fieldoffsets>` returns the (byte) offset for each
78-
field relative to the start of the type.
77+
:func:`fieldoffset(T::DataType, i::Integer) <fieldoffset>` returns the (byte) offset for
78+
field `i` relative to the start of the type.
7979

8080
.. rubric:: Function methods
8181

doc/stdlib/base.rst

+9-3
Original file line numberDiff line numberDiff line change
@@ -520,15 +520,15 @@ Types
520520
521521
Assign ``x`` to a named field in ``value`` of composite type. The syntax ``a.b = c`` calls ``setfield!(a, :b, c)``\ , and the syntax ``a.(b) = c`` calls ``setfield!(a, b, c)``\ .
522522

523-
.. function:: fieldoffsets(type)
523+
.. function:: fieldoffset(type, i)
524524

525525
.. Docstring generated from Julia source
526526
527-
The byte offset of each field of a type relative to the data start. For example, we could use it in the following manner to summarize information about a struct type:
527+
The byte offset of field ``i`` of a type relative to the data start. For example, we could use it in the following manner to summarize information about a struct type:
528528

529529
.. doctest::
530530

531-
julia> structinfo(T) = [zip(fieldoffsets(T),fieldnames(T),T.types)...];
531+
julia> structinfo(T) = [i -> (fieldoffset(T,i), fieldname(T,i), fieldtype(T,i)) for i = 1:nfields(T)];
532532

533533
julia> structinfo(StatStruct)
534534
12-element Array{Tuple{Int64,Symbol,DataType},1}:
@@ -1252,6 +1252,12 @@ Reflection
12521252
12531253
Get an array of the fields of a ``DataType``\ .
12541254

1255+
.. function:: fieldname(x::DataType, i)
1256+
1257+
.. Docstring generated from Julia source
1258+
1259+
Get the name of field ``i`` of a ``DataType``\ .
1260+
12551261
.. function:: isconst([m::Module], s::Symbol) -> Bool
12561262

12571263
.. Docstring generated from Julia source

src/sys.c

+3-11
Original file line numberDiff line numberDiff line change
@@ -567,14 +567,6 @@ JL_DLLEXPORT jl_value_t *jl_is_char_signed(void)
567567
return ((char)255) < 0 ? jl_true : jl_false;
568568
}
569569

570-
JL_DLLEXPORT void jl_field_offsets(jl_datatype_t *dt, ssize_t *offsets)
571-
{
572-
size_t i;
573-
for(i=0; i < jl_datatype_nfields(dt); i++) {
574-
offsets[i] = jl_field_offset(dt, i);
575-
}
576-
}
577-
578570
// -- misc sysconf info --
579571

580572
#ifdef _OS_WINDOWS_
@@ -624,9 +616,9 @@ JL_DLLEXPORT long jl_SC_CLK_TCK(void)
624616

625617
JL_DLLEXPORT size_t jl_get_field_offset(jl_datatype_t *ty, int field)
626618
{
627-
if (field > jl_datatype_nfields(ty))
628-
jl_error("This type does not have that many fields");
629-
return jl_field_offset(ty, field);
619+
if (field > jl_datatype_nfields(ty) || field < 1)
620+
jl_bounds_error_int((jl_value_t*)ty, field);
621+
return jl_field_offset(ty, field - 1);
630622
}
631623

632624
JL_DLLEXPORT size_t jl_get_alignment(jl_datatype_t *ty)

test/reflection.jl

+43
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,21 @@ end
201201

202202
@test_throws ArgumentError which(is, Tuple{Int, Int})
203203

204+
module TestingExported
205+
using Base.Test
206+
import Base.isexported
207+
global this_is_not_defined
208+
export this_is_not_defined
209+
@test_throws ErrorException which(:this_is_not_defined)
210+
@test_throws ErrorException @which this_is_not_defined
211+
@test_throws ErrorException which(:this_is_not_exported)
212+
@test isexported(current_module(), :this_is_not_defined)
213+
@test !isexported(current_module(), :this_is_not_exported)
214+
const a_value = 1
215+
@test which(:a_value) == current_module()
216+
@test !isexported(current_module(), :a_value)
217+
end
218+
204219
# issue #13264
205220
@test isa((@which vcat(1...)), Method)
206221

@@ -219,3 +234,31 @@ let ex = :(a + b)
219234
ex.typ = Integer
220235
@test string(ex) == "(a + b)::Integer"
221236
end
237+
238+
type TLayout
239+
x::Int8
240+
y::Int16
241+
z::Int32
242+
end
243+
tlayout = TLayout(5,7,11)
244+
@test fieldnames(tlayout) == fieldnames(TLayout) == [:x, :y, :z]
245+
@test [(fieldoffset(TLayout,i), fieldname(TLayout,i), fieldtype(TLayout,i)) for i = 1:nfields(TLayout)] ==
246+
[(0, :x, Int8), (2, :y, Int16), (4, :z, Int32)]
247+
@test_throws BoundsError fieldtype(TLayout, 0)
248+
@test_throws BoundsError fieldname(TLayout, 0)
249+
@test_throws BoundsError fieldoffset(TLayout, 0)
250+
@test_throws BoundsError fieldtype(TLayout, 4)
251+
@test_throws BoundsError fieldname(TLayout, 4)
252+
@test_throws BoundsError fieldoffset(TLayout, 4)
253+
254+
import Base: isstructtype, type_alignment, return_types
255+
@test !isstructtype(Union{})
256+
@test !isstructtype(Union{Int,Float64})
257+
@test !isstructtype(Int)
258+
@test isstructtype(TLayout)
259+
@test type_alignment(UInt16) == 2
260+
@test type_alignment(TLayout) == 4
261+
let rts = return_types(TLayout)
262+
@test length(rts) >= 3 # general constructor, specific constructor, and call-to-convert adapter(s)
263+
@test all(rts .== TLayout)
264+
end

0 commit comments

Comments
 (0)