Skip to content

Commit fa9518c

Browse files
authored
Attack the add_opt method recompilation proliferation with conversion to Dicts. (#1936)
1 parent 5d0a652 commit fa9518c

6 files changed

Lines changed: 40 additions & 19 deletions

File tree

src/common_options.jl

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,10 @@ end
23072307

23082308
# ---------------------------------------------------------------------------------------------------
23092309
function add_opt(d::Dict, cmd::String, opt::String, mapa::NamedTuple)::String
2310+
# Thin wrapper: convert NT to Dict to compile _add_opt only once
2311+
_add_opt_1(d, cmd, opt, nt2dict(mapa))
2312+
end
2313+
function _add_opt_1(d::Dict, cmd::String, opt::String, mapa::Dict)::String
23102314
cmd_::String = ""
23112315
for k in keys(mapa)
23122316
((val_ = find_in_dict(d, [k], false)[1]) === nothing) && continue # This mapa key was not used
@@ -2333,6 +2337,13 @@ end
23332337
#
23342338

23352339
function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, mapa; grow_mat=nothing, del::Bool=true, expand::Bool=false, expand_str::Bool=false)::String
2340+
# Thin wrapper: convert NamedTuple mapa to Dict to avoid recompilation for each distinct NT type
2341+
mapa_is_nt = isa(mapa, NamedTuple)
2342+
_mapa = mapa_is_nt ? nt2dict(mapa) : mapa
2343+
_add_opt_2(d, cmd, opt, symbs, _mapa; grow_mat=grow_mat, del=del, expand=expand, expand_str=expand_str, mapa_is_nt=mapa_is_nt)
2344+
end
2345+
2346+
function _add_opt_2(d::Dict, cmd::String, opt::String, symbs::VMs, mapa; grow_mat=nothing, del::Bool=true, expand::Bool=false, expand_str::Bool=false, mapa_is_nt::Bool=false)::String
23362347
# Scan the D Dict for SYMBS keys and if found create the new option OPT and append it to CMD
23372348
# If DEL == false we do not remove the found key.
23382349
# 'grow_mat=mat', is a special case to append to a matrix (can't realy be done in Julia)
@@ -2343,13 +2354,13 @@ function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, mapa; grow_mat=n
23432354
(SHOW_KWARGS[]) && return print_kwarg_opts(symbs, mapa) # Just print the kwargs of this option call
23442355

23452356
if ((val = find_in_dict(d, symbs, del)[1]) === nothing)
2346-
if (expand && isa(mapa, NamedTuple))
2347-
cmd = add_opt(d, cmd, opt, mapa)
2357+
if (expand && mapa_is_nt)
2358+
cmd = _add_opt_1(d, cmd, opt, mapa)
23482359
end
23492360
return cmd
23502361
elseif (val === true || val === "") # Just the flag. With the === we avoid the case 1 == true
23512362
return string(cmd, " -", opt)
2352-
elseif (expand_str && isa(mapa, NamedTuple)) # Use the mapa KEYS as possibe values of 'val'
2363+
elseif (expand_str && mapa_is_nt) # Use the mapa KEYS as possibe values of 'val'
23532364
cmd_ = ""
23542365
for k in keys(mapa)
23552366
if (string(val) == string(k))
@@ -2364,16 +2375,18 @@ function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, mapa; grow_mat=n
23642375

23652376
args::Vector{String} = Vector{String}(undef,1)
23662377
isa(val, AbstractDict) && (val = Base.invokelatest(dict2nt, val))
2367-
if (isa(val, NamedTuple) && isa(mapa, NamedTuple))
2368-
args[1] = Base.invokelatest(add_opt, val, mapa, grow_mat)
2378+
if (isa(val, NamedTuple) && mapa_is_nt)
2379+
_arg = (grow_mat === nothing || isempty(grow_mat)) ? Float64[] : grow_mat
2380+
args[1] = Base.invokelatest(add_opt_1, val, mapa, _arg)
23692381
elseif (isa(val, NamedTuple) && mapa === nothing)
23702382
# Happens when the inline 'inset' passed a NT with options for inset itself and not the module it called
23712383
return cmd
23722384
elseif (isa(val, Tuple) && length(val) > 1 && isa(val[1], NamedTuple)) # In fact, all val[i] -> NT
23732385
# Used in recursive calls for options like -I, -N , -W of pscoast. Here we assume that opt != ""
23742386
_args::String = ""
2387+
_arg2 = (grow_mat === nothing || isempty(grow_mat)) ? Float64[] : grow_mat
23752388
for k = 1:numel(val)
2376-
_args *= " -" * opt * Base.invokelatest(add_opt, val[k], mapa, grow_mat)::String
2389+
_args *= " -" * opt * Base.invokelatest(add_opt_1, val[k], mapa, _arg2)::String
23772390
end
23782391
return cmd * _args
23792392
elseif (isa(mapa, Tuple) && length(mapa) > 1 && isa(mapa[2], Function)) # grdcontour -G
@@ -2384,7 +2397,7 @@ function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, mapa; grow_mat=n
23842397
end
23852398
else
23862399
args[1] = arg2str(val)::String
2387-
if isa(mapa, NamedTuple) # Let aa=(bb=true,...) be addressed as aa=:bb
2400+
if mapa_is_nt # Let aa=(bb=true,...) be addressed as aa=:bb
23882401
s = Symbol(args[1])
23892402
for k in keys(mapa)
23902403
(s != k) && continue
@@ -2555,6 +2568,11 @@ end
25552568

25562569
# ---------------------------------------------------------------------------------------------------
25572570
function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, need_symb::Symbol, args, nt_opts::NamedTuple)
2571+
# Thin wrapper: nospecialize args, convert nt_opts NT to Dict
2572+
_add_opt_3(d, cmd, opt, symbs, need_symb, args, nt2dict(nt_opts))
2573+
end
2574+
2575+
function _add_opt_3(d::Dict, cmd::String, opt::String, symbs::VMs, need_symb::Symbol, @nospecialize(args), nt_opts_d::Dict)
25582576
# This version specializes in the case where an option may transmit an array, or read a file, with optional flags.
25592577
# When optional flags are used we need to use NamedTuples (the NT_OPTS arg). In that case the NEED_SYMB
25602578
# is the keyword name (a symbol) whose value holds the array. An error is raised if this symbol is missing in D
@@ -2570,7 +2588,7 @@ function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, need_symb::Symbo
25702588
isa(val, AbstractDict) && (val = Base.invokelatest(dict2nt, val))
25712589
if (isa(val, Tuple) && length(val) == 2)
25722590
# This is crazzy trickery to accept also (e.g) C=(pratt,"200k") instead of C=(pts=pratt,dist="200k")
2573-
d[symb] = Base.invokelatest(dict2nt, Dict(need_symb => val[1], keys(nt_opts)[1] => val[2])) # Need to patch also the input option
2591+
d[symb] = Base.invokelatest(dict2nt, Dict(need_symb => val[1], keys(nt_opts_d)[1] => val[2])) # Need to patch also the input option
25742592
val = d[symb]
25752593
end
25762594
if (isa(val, NamedTuple))
@@ -2580,7 +2598,7 @@ function add_opt(d::Dict, cmd::String, opt::String, symbs::VMs, need_symb::Symbo
25802598
opt = string(opt,val)
25812599
to_slot = false
25822600
end
2583-
cmd = add_opt(d, cmd, opt, symbs, nt_opts)
2601+
cmd = _add_opt_2(d, cmd, opt, symbs, nt_opts_d; mapa_is_nt=true)
25842602
elseif (isa(val, Array{<:Real}) || isa(val, GDtype) || isa(val, GMTcpt) || typeof(val) <: AbstractRange)
25852603
if (typeof(val) <: AbstractRange) val = collect(val) end
25862604
cmd = string(cmd, " -", opt)
@@ -2611,6 +2629,10 @@ end
26112629
# ---------------------------------------------------------------------------------------------------
26122630
function add_opt_cpt(d::Dict, cmd::String, symbs::VMs, opt::Char, N_args::Int=0, arg1=nothing, arg2=nothing,
26132631
store::Bool=false, def::Bool=false, opt_T::String="", in_bag::Bool=false)
2632+
_add_opt_cpt(d, cmd, symbs, opt, N_args, arg1, arg2, store, def, opt_T, in_bag)
2633+
end
2634+
function _add_opt_cpt(d::Dict, cmd::String, symbs::VMs, opt::Char, N_args::Int, @nospecialize(arg1), @nospecialize(arg2),
2635+
store::Bool, def::Bool, opt_T::String, in_bag::Bool)
26142636
# Deal with options of the form -Ccolor, where color can be a string or a GMTcpt type
26152637
# SYMBS is normally: CPTaliases
26162638
# N_args only applyies to when a GMTcpt was transmitted. Then it's either 0, case in which
@@ -2681,7 +2703,7 @@ function add_opt_cpt(d::Dict, cmd::String, symbs::VMs, opt::Char, N_args::Int=0,
26812703
return cmd, arg1, arg2, N_args
26822704
end
26832705
# ---------------------
2684-
function helper_add_cpt(cmd::String, opt, N_args::Int, arg1, arg2, val::GMTcpt, store::Bool)
2706+
function helper_add_cpt(cmd::String, opt, N_args::Int, @nospecialize(arg1), @nospecialize(arg2), val::GMTcpt, store::Bool)
26852707
# Helper function to avoid repeating 3 times the same code in add_opt_cpt
26862708
(N_args == 0) ? arg1 = val : arg2 = val; N_args += 1
26872709
if (store) global CURRENT_CPT[] = val end
@@ -2706,7 +2728,7 @@ function add_opt_fill(cmd::String, d::Dict, symbs::VMs, opt="", del::Bool=true):
27062728
return add_opt_fill(val, cmd, opt)
27072729
end
27082730

2709-
function add_opt_fill(val, cmd::String="", opt="")::String
2731+
function add_opt_fill(@nospecialize(val), cmd::String="", opt="")::String
27102732
# This method can be called directy with VAL as a NT or a string
27112733
if (isa(val, Tuple) && length(val) == 2 && (isa(val[1], Tuple) || isa(val[1], NamedTuple)))
27122734
# wiggle, for example, may want to repeat the call to fill (-G). Then we expect a Tuple of -G's

src/grdpaste.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ Parameters
1919
To see the full documentation type: ``@? grdpaste``
2020
"""
2121
function grdpaste(G1::GItype, G2::GItype; kw...)
22-
(GMTver < v"6.5.0") && (@warn("This module doesn't work for the installed GMT version. Run 'upGMT(true)' to update it."); return nothing)
2322
(G1.layout != "" && G1.layout[2] == 'R') && error("Pasting row oriented grids (such those produced by GDAL) is not implemented.")
2423
d = init_module(false, kw...)[1]
2524
grdpaste(G1, G2, d)

src/grdtrack.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function grdtrack(cmd0::String, arg1=nothing, arg2=nothing; kwargs...)
1414
grdtrack_helper(cmd0, arg1, arg2, d)
1515
end
1616

17-
function grdtrack_helper(cmd0::String, arg1, arg2, d::Dict{Symbol, Any})
17+
function grdtrack_helper(cmd0::String, @nospecialize(arg1), @nospecialize(arg2), d::Dict{Symbol, Any})
1818

1919
cmd, = parse_common_opts(d, "", [:R :V_params :bi :bo :di :e :f :g :h :i :n :o :s :w :yx])
2020
cmd = parse_these_opts(cmd, d, [[:A :interp_path :resample], [:C :crossprofile :equidistant], [:D :dfile],
@@ -85,7 +85,7 @@ function grdtrack_helper(cmd0::String, arg1, arg2, d::Dict{Symbol, Any})
8585
end
8686

8787
# ---------------------------------------------------------------------------------------------------
88-
function parse_G_grdtrk(d::Dict, symbs::Vector{<:Symbol}, cmd::String, arg1, arg2)
88+
function parse_G_grdtrk(d::Dict, symbs::Vector{<:Symbol}, cmd::String, @nospecialize(arg1), @nospecialize(arg2))
8989

9090
(SHOW_KWARGS[]) && return (print_kwarg_opts(symbs, "GMTgrid | Tuple | String"), nothing,arg1,arg2)
9191

src/grdtrend.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ function grdtrend(cmd0::String, arg1=nothing, arg2=nothing; kwargs...)
2929
grdtrend_helper(cmd0, arg1, arg2, d)
3030
end
3131

32-
function grdtrend_helper(cmd0::String, arg1, arg2, d::Dict{Symbol, Any})
32+
function grdtrend_helper(cmd0::String, @nospecialize(arg1), @nospecialize(arg2), d::Dict{Symbol, Any})
3333

3434
cmd, = parse_R(d, "")
3535
cmd = parse_V_params(d, cmd)
@@ -53,7 +53,7 @@ function grdtrend_helper(cmd0::String, arg1, arg2, d::Dict{Symbol, Any})
5353
end
5454

5555
# ---------------------------------------------------------------------------------------------------
56-
function parse_W_grdtrend(d::Dict, symbs::Array{<:Symbol}, cmd::String, arg1, arg2)
56+
function parse_W_grdtrend(d::Dict, symbs::Array{<:Symbol}, cmd::String, @nospecialize(arg1), @nospecialize(arg2))
5757

5858
(SHOW_KWARGS[]) && return (print_kwarg_opts(symbs, "Tuple | String"), arg1,arg2)
5959

src/utils_types.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2442,7 +2442,7 @@ function grid2img(G::GMTgrid{<:Unsigned})
24422442
end
24432443

24442444
# ---------------------------------------------------------------------------------------------------
2445-
function grdimg_hdr_xy(mat, reg, hdr, x=Float64[], y=Float64[], is_transposed=false)
2445+
function grdimg_hdr_xy(@nospecialize(mat), reg, hdr, x=Float64[], y=Float64[], is_transposed=false)
24462446
# Thin wrapper: convert to concrete types, then call the single-compilation implementation
24472447
_grdimg_hdr_xy(mat, Int(reg)::Int, Float64.(vec(hdr)), Float64.(vec(x)), Float64.(vec(y)), is_transposed == 1)
24482448
end

test/test_mgd77.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@testset "MAGREF" begin
2-
@test magref(R=[-180,180,-90,90], I=0.25, onetime=2000, alt=10, F=:H, Vd=dbg2) == "mgd77magref -A+a10+t2000+y -Frh/H"
3-
@test magref([0. 0], onetime=2000, alt=10, H=1, Vd=dbg2) == "mgd77magref -A+a10+t2000+y -Fh/0"
2+
@test magref(R=[-180,180,-90,90], I=0.25, onetime=2000, alt=10, F=:H, Vd=dbg2) == "mgd77magref -A+t2000+a10+y -Frh/H"
3+
@test magref([0. 0], onetime=2000, alt=10, H=1, Vd=dbg2) == "mgd77magref -A+t2000+a10+y -Fh/0"
44
@test magref([0. 0], alt=10, H=1, CM4core=true, Vd=dbg2) == "mgd77magref -A+a10 -Fh/1"
55
@test magref([0. 0], alt=10, F=:CM4litho, L=:iono_p, Vd=dbg2) == "mgd77magref -A+a10 -Frt/2"
66
@test magref([0. 0], alt=10, L=:iono_p, Vd=dbg2) == "mgd77magref -A+a10 -Lrt/2"

0 commit comments

Comments
 (0)