forked from JuliaParallel/MPI.jl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
info.jl
153 lines (131 loc) · 4.25 KB
/
info.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
"""
Info <: AbstractDict{Symbol,String}
`MPI.Info` objects store key-value pairs, and are typically used for passing optional
arguments to MPI functions.
# Usage
These will typically be hidden from user-facing APIs by splatting keywords, e.g.
```julia
function f(args...; kwargs...)
info = Info(kwargs...)
# pass `info` object to `ccall`
end
```
For manual usage, `Info` objects act like Julia `Dict` objects:
```julia
info = Info(init=true) # keyword argument is required
info[key] = value
x = info[key]
delete!(info, key)
```
If `init=false` is used in the costructor (the default), a "null" `Info` object will be
returned: no keys can be added to such an object.
"""
mutable struct Info <: AbstractDict{Symbol,String}
val::MPI_Info
end
Base.:(==)(a::Info, b::Info) = a.val == b.val
Base.cconvert(::Type{MPI_Info}, info::Info) = info
Base.unsafe_convert(::Type{MPI_Info}, info::Info) = info.val
Base.unsafe_convert(::Type{Ptr{MPI_Info}}, info::Info) = convert(Ptr{MPI_Info}, pointer_from_objref(info))
const INFO_NULL = Info(API.MPI_INFO_NULL[])
add_load_time_hook!(() -> INFO_NULL.val = API.MPI_INFO_NULL[])
function Info(;init=false)
info = Info(INFO_NULL.val)
if init
API.MPI_Info_create(info)
finalizer(free, info)
end
return info
end
function free(info::Info)
if info != INFO_NULL && !Finalized()
# int MPI_Info_free(MPI_Info *info)
API.MPI_Info_free(info)
end
return nothing
end
function Base.setindex!(info::Info, value::AbstractString, key::Symbol)
skey = String(key)
@assert isascii(skey) && isascii(value) &&
length(skey) <= API.MPI_MAX_INFO_KEY && length(value) <= API.MPI_MAX_INFO_VAL
API.MPI_Info_set(info, skey, value)
end
Base.setindex!(info::Info, value::Any, key::Symbol) = info[key] = infoval(value)
"""
infoval(x)
Convert Julia object `x` to a string representation for storing in an [`Info`](@ref) object.
The MPI specification allows passing strings, Boolean values, integers, and lists.
"""
infoval(x::String) = x
infoval(x::Bool) = string(x) # "true"/"false"
infoval(x::Integer) = string(x) # decimal values
infoval(xs::AbstractVector) = join(map(infoval, xs), ',') # separated by commas
infoval(xs::Tuple) = join(map(infoval, xs), ',') # separated by commas
function Info(kvs::Pair...)
info = Info(;init=true)
for (k,v) in kvs
info[k] = v
end
return info
end
function Base.getindex(info::Info, key::Symbol)
skey = String(key)
@assert isascii(skey) && length(skey) <= API.MPI_MAX_INFO_KEY
valuelen = Ref{Cint}()
flag = Ref{Cint}()
# int MPI_Info_get_valuelen(MPI_Info info, const char *key, int *valuelen, int *flag)
API.MPI_Info_get_valuelen(info, skey, valuelen, flag)
if flag[] == 0
throw(KeyError(key))
end
# According to the MPI standard:
# "`valuelen` should be one less than the amount of allocated
# space to allow for the null terminator."
# But MS-MPI will insists on setting the `n`th character as NUL,
# so we simply pad both to avoid problems.
n = valuelen[]
buffer = Vector{UInt8}(undef, n+2)
# int MPI_Info_get(MPI_Info info, const char *key, int valuelen, char *value, int *flag)
API.MPI_Info_get(info, skey, n+1, buffer, flag)
return String(resize!(buffer,n))
end
function Base.delete!(info::Info,key::Symbol)
skey = String(key)
@assert isascii(skey) && length(skey) <= API.MPI_MAX_INFO_KEY
API.MPI_Info_delete(info, skey)
end
function Base.length(info::Info)
if info == INFO_NULL
return 0
end
nkeys = Ref{Cint}()
API.MPI_Info_get_nkeys(info, nkeys)
return Int(nkeys[])
end
function nthkey(info::Info, n::Integer)
buffer = Vector{UInt8}(undef, API.MPI_MAX_INFO_KEY+1)
API.MPI_Info_get_nthkey(info, n, buffer)
i = findfirst(isequal(UInt8(0)), buffer)
if i !== nothing
resize!(buffer, i-1)
end
Symbol(buffer)
end
function Base.iterate(infokeys::Base.KeySet{Symbol,Info}, i=0)
info = infokeys.dict
if i < length(info)
key = nthkey(info, i)
return key, i+1
else
return nothing
end
end
function Base.iterate(info::Info, i=0)
if i < length(info)
key = nthkey(info, i)
val = info[key]
return key=>val, i+1
else
return nothing
end
end