-
Notifications
You must be signed in to change notification settings - Fork 9
/
misc.jl
128 lines (112 loc) · 3.97 KB
/
misc.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
value_with_default(stats::GroupBy, key, default) =
haskey(stats.value, key) ? value(stats[key]) : default
# somehow Julia doesn't have that? (double check)
inf(object::T) where {T<:Number} = inf(T)
inf(T::Type{Float16}) = Inf16
inf(T::Type{Float32}) = Inf32
inf(T::Type{Float64}) = Inf
sqr_norm(x) = sum(abs2, x)
julia_cmd_no_start_up() = `$(Base.julia_cmd()) --startup-file=no --banner=no`
"""
$SIGNATURES
From one splittable random object, one can conceptualize an infinite list of splittable random objects.
Return a slice from this infinite list.
"""
function split_slice(
slice::UnitRange, # NB: assumes slice is contiguous, i.e. don't duck-type UnitRate
rng)
@assert slice[1] ≥ 1
# todo: could be done more efficiently with a tree but low priority
# get rid of stuff at left of slice
n_to_burn = slice[1] - 1
[split(rng) for i in 1:n_to_burn]
# get the slice of random objects by splitting:
return [split(rng) for i in slice]
end
"""
$SIGNATURES
Heuristic to automate the process
of sorting `include()`'s.
Topological sorting of the source files under src
(excluding `main`) is attempted, if successful, print the
include string to copy and paste to the main file, otherwise,
print the detected loops.
Internally, this function will:
1. Construct a graph where the vertices are the .jl files
under src, excluding the provided `main` file (i.e. where the module is
defined and the includes will sit in).
2. Each file starting with a capital letter is assumed to
contain a struct with the same name as the file after
removal of the .jl suffix. Similarly, files starting
with `@` are assumed to contain a macro with the similarly
obtained name.
3. Each source file is inspected to see if the above struct and
macro strings are detected. This defines edges in the graph.
(known limitation: this includes spurious edges when e.g.
the string occurs in a comment).
"""
function sort_includes!(main)
sorted = sort_includes(main)
if isfile("src/includes.jl")
mv("src/includes.jl", "src/.includes_bu.jl", force = true)
println("Created back-up of src/includes.jl as src/.includes_bu.jl")
end
includes = map(x -> "include(\"$x\")", sorted)
write( "src/includes.jl",
"""
# include()'s generated using: sort_includes!(\"main\")
$(join(includes, "\n"))
"""
)
return nothing
end
function sort_includes(main)
@assert isfile("src/" * main)
source_files = String[]
for (dir, sub_dir, files) in walkdir("src")
for file in files
if endswith(file, ".jl") &&
file != main && # ignore entrypoint
file != "includes.jl" &&
!startswith(file, ".") # ignore backup
push!(source_files, "$dir/$file")
end
end
end
indexer = Indexer(source_files)
graph = SimpleDiGraph(length(indexer.i2t))
for file1 in source_files
index1 = indexer.t2i[file1]
for file2 in source_files
index2 = indexer.t2i[file2]
name = replace(basename(file2), ".jl" => "")
if (name[1] == '@' || isuppercase(name[1])) && file1 != file2
contents = read(file1, String)
if contains(contents, name)
add_edge!(graph, index2, index1)
end
end
end
end
try
sorted = Graphs.topological_sort_by_dfs(graph)
output = []
for index in sorted
path = replace(indexer.i2t[index], "src/" => "")
push!(output, path)
end
return output
catch e
loops = Graphs.simplecycles_hawick_james(graph)
msg = "loops detected:\n"
for loop in loops
if length(loop) > 1
msg *= "loop:\n"
for i in loop
msg *= " $(indexer.i2t[i])\n"
end
end
end
error(msg)
end
end