Add: julia-0.6.2
Former-commit-id: ccc667cf67d569f3fb3df39aa57c2134755a7551
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module ModInts
|
||||
export ModInt
|
||||
|
||||
import Base: +, -, *, /, inv
|
||||
|
||||
struct ModInt{n} <: Integer
|
||||
k::Int
|
||||
ModInt{n}(k) where n = new(mod(k,n))
|
||||
end
|
||||
|
||||
Base.show{n}(io::IO, k::ModInt{n}) =
|
||||
print(io, get(io, :compact, false) ? k.k : "$(k.k) mod $n")
|
||||
|
||||
+{n}(a::ModInt{n}, b::ModInt{n}) = ModInt{n}(a.k+b.k)
|
||||
-{n}(a::ModInt{n}, b::ModInt{n}) = ModInt{n}(a.k-b.k)
|
||||
*{n}(a::ModInt{n}, b::ModInt{n}) = ModInt{n}(a.k*b.k)
|
||||
-{n}(a::ModInt{n}) = ModInt{n}(-a.k)
|
||||
|
||||
inv{n}(a::ModInt{n}) = ModInt{n}(invmod(a.k, n))
|
||||
/{n}(a::ModInt{n}, b::ModInt{n}) = a*inv(b) # broaden for non-coprime?
|
||||
|
||||
Base.promote_rule{n}(::Type{ModInt{n}}, ::Type{Int}) = ModInt{n}
|
||||
Base.convert{n}(::Type{ModInt{n}}, i::Int) = ModInt{n}(i)
|
||||
|
||||
end # module
|
||||
@@ -0,0 +1,19 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
import Base.Sort
|
||||
struct BubbleSortAlg <: Sort.Algorithm end
|
||||
const BubbleSort = BubbleSortAlg()
|
||||
|
||||
function Base.sort!(v::AbstractVector, lo::Int, hi::Int, ::BubbleSortAlg, o::Sort.Ordering)
|
||||
while true
|
||||
clean = true
|
||||
for i = lo:hi-1
|
||||
if Sort.lt(o, v[i+1], v[i])
|
||||
v[i+1], v[i] = v[i], v[i+1]
|
||||
clean = false
|
||||
end
|
||||
end
|
||||
clean && break
|
||||
end
|
||||
return v
|
||||
end
|
||||
@@ -0,0 +1,27 @@
|
||||
This is a proof-of-concept that uses ZeroMQ as transport.
|
||||
It uses a star topology as opposed to the native mesh network.
|
||||
|
||||
Package ZMQ must be installed. All workers only run on localhost.
|
||||
|
||||
All Julia nodes only connect to a "broker" process that listens on known ports
|
||||
8100 and 8101 via ZMQ sockets.
|
||||
|
||||
|
||||
All commands must be run from `examples/clustermanager/0mq` directory
|
||||
|
||||
First, start the broker. In a new console type:
|
||||
julia broker.jl
|
||||
|
||||
This does not return.
|
||||
|
||||
Next, start a Julia REPL and type:
|
||||
include("ZMQCM.jl")
|
||||
ZMQCM.start_master(4) # start with four workers
|
||||
|
||||
|
||||
Alternatively, head.jl, a test script could be run. It just launches the requested number of workers,
|
||||
executes a simple command on all of them and exits.
|
||||
julia head.jl 4
|
||||
|
||||
NOTE: As stated this is a proof-of-concept. A real Julia cluster using ZMQ will probably use
|
||||
different ZMQ socket types and optimize the transport.
|
||||
@@ -0,0 +1,277 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
using ZMQ
|
||||
|
||||
import Base: launch, manage, connect, kill
|
||||
|
||||
const BROKER_SUB_PORT = 8100
|
||||
const BROKER_PUB_PORT = 8101
|
||||
|
||||
const SELF_INITIATED = 0
|
||||
const REMOTE_INITIATED = 1
|
||||
|
||||
const PAYLOAD_MSG = "J"
|
||||
const CONTROL_MSG = "Z"
|
||||
|
||||
const REQUEST_ACK = "R"
|
||||
const ACK_MSG = "A"
|
||||
const KILL_MSG = "K"
|
||||
|
||||
mutable struct ZMQCMan <: ClusterManager
|
||||
map_zmq_julia::Dict{Int, Tuple}
|
||||
c::Condition
|
||||
isfree::Bool
|
||||
ctx
|
||||
pub
|
||||
sub
|
||||
zid_self
|
||||
ZMQCMan() = new(Dict{Int, Tuple}(), Condition(), true)
|
||||
end
|
||||
|
||||
const manager = ZMQCMan()
|
||||
|
||||
function lock_for_send()
|
||||
if manager.isfree == true
|
||||
manager.isfree = false
|
||||
else
|
||||
while manager.isfree == false
|
||||
wait(manager.c)
|
||||
if manager.isfree == true
|
||||
manager.isfree = false
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function release_lock_for_send()
|
||||
manager.isfree = true
|
||||
notify(manager.c, all=true)
|
||||
end
|
||||
|
||||
function init_node(zid=0)
|
||||
manager.ctx = Context(1)
|
||||
pub=Socket(manager.ctx, PUB) # Outbound
|
||||
connect(pub, "tcp://127.0.0.1:$BROKER_SUB_PORT")
|
||||
|
||||
sub=Socket(manager.ctx, SUB) # In bound
|
||||
connect(sub, "tcp://127.0.0.1:$BROKER_PUB_PORT")
|
||||
ZMQ.set_subscribe(sub, string(zid))
|
||||
|
||||
manager.pub = pub
|
||||
manager.sub = sub
|
||||
manager.zid_self = zid
|
||||
|
||||
(pub, sub)
|
||||
end
|
||||
|
||||
function send_data(zid, mtype, data)
|
||||
lock_for_send()
|
||||
ZMQ.send(manager.pub, Message(string(zid)), SNDMORE)
|
||||
ZMQ.send(manager.pub, Message(string(manager.zid_self)), SNDMORE)
|
||||
#println("Sending message of type $mtype to $zid")
|
||||
ZMQ.send(manager.pub, Message(mtype), SNDMORE)
|
||||
ZMQ.send(manager.pub, Message(data))
|
||||
release_lock_for_send()
|
||||
end
|
||||
|
||||
function setup_connection(zid, initiated_by)
|
||||
try
|
||||
read_stream=BufferStream()
|
||||
write_stream=BufferStream()
|
||||
|
||||
if initiated_by == REMOTE_INITIATED
|
||||
test_remote = false
|
||||
else
|
||||
test_remote = true
|
||||
end
|
||||
|
||||
manager.map_zmq_julia[zid] = (read_stream, write_stream, test_remote)
|
||||
|
||||
@schedule begin
|
||||
while true
|
||||
(r_s, w_s, do_test_remote) = manager.map_zmq_julia[zid]
|
||||
if do_test_remote
|
||||
send_data(zid, CONTROL_MSG, REQUEST_ACK)
|
||||
sleep(0.5)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
(r_s, w_s, do_test_remote) = manager.map_zmq_julia[zid]
|
||||
|
||||
while true
|
||||
data = readavailable(w_s)
|
||||
send_data(zid, PAYLOAD_MSG, data)
|
||||
end
|
||||
end
|
||||
(read_stream, write_stream)
|
||||
catch e
|
||||
Base.show_backtrace(STDOUT,catch_backtrace())
|
||||
println(e)
|
||||
rethrow(e)
|
||||
end
|
||||
end
|
||||
|
||||
# BROKER
|
||||
function start_broker()
|
||||
ctx=Context(1)
|
||||
xpub=Socket(ctx, XPUB)
|
||||
xsub=Socket(ctx, XSUB)
|
||||
|
||||
ZMQ.bind(xsub, "tcp://127.0.0.1:$(BROKER_SUB_PORT)")
|
||||
ZMQ.bind(xpub, "tcp://127.0.0.1:$(BROKER_PUB_PORT)")
|
||||
|
||||
ccall((:zmq_proxy, :libzmq), Cint, (Ptr{Void}, Ptr{Void}, Ptr{Void}), xsub.data, xpub.data, C_NULL)
|
||||
# proxy(xsub, xpub)
|
||||
|
||||
# control never comes here
|
||||
ZMQ.close(xpub)
|
||||
ZMQ.close(xsub)
|
||||
ZMQ.close(ctx)
|
||||
end
|
||||
|
||||
function recv_data()
|
||||
try
|
||||
#println("On $(manager.zid_self) waiting to recv message")
|
||||
zid = parse(Int,String(ZMQ.recv(manager.sub)))
|
||||
assert(zid == manager.zid_self)
|
||||
|
||||
from_zid = parse(Int,String(ZMQ.recv(manager.sub)))
|
||||
mtype = String(ZMQ.recv(manager.sub))
|
||||
|
||||
#println("$zid received message of type $mtype from $from_zid")
|
||||
|
||||
data = ZMQ.recv(manager.sub)
|
||||
if mtype == CONTROL_MSG
|
||||
cmsg = String(data)
|
||||
if cmsg == REQUEST_ACK
|
||||
#println("$from_zid REQUESTED_ACK from $zid")
|
||||
# send back a control_msg
|
||||
send_data(from_zid, CONTROL_MSG, ACK_MSG)
|
||||
elseif cmsg == ACK_MSG
|
||||
#println("$zid got ACK_MSG from $from_zid")
|
||||
(r_s, w_s, test_remote) = manager.map_zmq_julia[from_zid]
|
||||
manager.map_zmq_julia[from_zid] = (r_s, w_s, false)
|
||||
elseif cmsg == KILL_MSG
|
||||
exit(0)
|
||||
else
|
||||
error("Unknown control message : ", cmsg)
|
||||
end
|
||||
data = ""
|
||||
end
|
||||
|
||||
(from_zid, data)
|
||||
catch e
|
||||
Base.show_backtrace(STDOUT,catch_backtrace())
|
||||
println(e)
|
||||
rethrow(e)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# MASTER
|
||||
function start_master(np)
|
||||
init_node()
|
||||
@schedule begin
|
||||
try
|
||||
while true
|
||||
(from_zid, data) = recv_data()
|
||||
|
||||
#println("master recv data from $from_zid")
|
||||
|
||||
(r_s, w_s, t_r) = manager.map_zmq_julia[from_zid]
|
||||
unsafe_write(r_s, pointer(data), length(data))
|
||||
end
|
||||
catch e
|
||||
Base.show_backtrace(STDOUT,catch_backtrace())
|
||||
println(e)
|
||||
rethrow(e)
|
||||
end
|
||||
end
|
||||
|
||||
addprocs(manager; np=np)
|
||||
end
|
||||
|
||||
|
||||
function launch(manager::ZMQCMan, params::Dict, launched::Array, c::Condition)
|
||||
#println("launch $(params[:np])")
|
||||
for i in 1:params[:np]
|
||||
io, pobj = open(`$(params[:exename]) worker.jl $i $(Base.cluster_cookie())`, "r")
|
||||
|
||||
wconfig = WorkerConfig()
|
||||
wconfig.userdata = Dict(:zid=>i, :io=>io)
|
||||
push!(launched, wconfig)
|
||||
notify(c)
|
||||
end
|
||||
end
|
||||
|
||||
function connect(manager::ZMQCMan, pid::Int, config::WorkerConfig)
|
||||
#println("connect_m2w")
|
||||
if myid() == 1
|
||||
zid = get(config.userdata)[:zid]
|
||||
config.connect_at = zid # This will be useful in the worker-to-worker connection setup.
|
||||
|
||||
print_worker_stdout(get(config.userdata)[:io], pid)
|
||||
else
|
||||
#println("connect_w2w")
|
||||
zid = get(config.connect_at)
|
||||
config.userdata = Dict{Symbol, Any}(:zid=>zid)
|
||||
end
|
||||
|
||||
streams = setup_connection(zid, SELF_INITIATED)
|
||||
|
||||
udata = get(config.userdata)
|
||||
udata[:streams] = streams
|
||||
|
||||
streams
|
||||
end
|
||||
|
||||
# WORKER
|
||||
function start_worker(zid, cookie)
|
||||
#println("start_worker")
|
||||
Base.init_worker(cookie, ZMQCMan())
|
||||
init_node(zid)
|
||||
|
||||
while true
|
||||
(from_zid, data) = recv_data()
|
||||
|
||||
#println("worker recv data from $from_zid")
|
||||
|
||||
streams = get(manager.map_zmq_julia, from_zid, nothing)
|
||||
if streams === nothing
|
||||
# First time..
|
||||
(r_s, w_s) = setup_connection(from_zid, REMOTE_INITIATED)
|
||||
Base.process_messages(r_s, w_s)
|
||||
else
|
||||
(r_s, w_s, t_r) = streams
|
||||
end
|
||||
|
||||
unsafe_write(r_s, pointer(data), length(data))
|
||||
end
|
||||
end
|
||||
|
||||
function manage(manager::ZMQCMan, id::Int, config::WorkerConfig, op)
|
||||
nothing
|
||||
end
|
||||
|
||||
function kill(manager::ZMQCMan, pid::Int, config::WorkerConfig)
|
||||
send_data(get(config.userdata)[:zid], CONTROL_MSG, KILL_MSG)
|
||||
(r_s, w_s) = get(config.userdata)[:streams]
|
||||
close(r_s)
|
||||
close(w_s)
|
||||
|
||||
# remove from our map
|
||||
delete!(manager.map_zmq_julia, get(config.userdata)[:zid])
|
||||
|
||||
nothing
|
||||
end
|
||||
|
||||
|
||||
function print_worker_stdout(io, pid)
|
||||
@schedule while !eof(io)
|
||||
line = readline(io)
|
||||
println("\tFrom worker $(pid):\t$line")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("ZMQCM.jl")
|
||||
start_broker()
|
||||
@@ -0,0 +1,11 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("ZMQCM.jl")
|
||||
|
||||
# @spawn run(`julia broker.jl`)
|
||||
|
||||
start_master(parse(Int,ARGS[1]))
|
||||
|
||||
resp = pmap(x -> myid() *2, [1:nworkers()])
|
||||
|
||||
println(resp)
|
||||
@@ -0,0 +1,5 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("ZMQCM.jl")
|
||||
|
||||
start_worker(parse(Int,ARGS[1]), ARGS[2])
|
||||
@@ -0,0 +1,12 @@
|
||||
This is a simple proof-of-concept that uses UNIX domain sockets as transport.
|
||||
|
||||
All commands must be run from `examples/clustermanager/simple` directory
|
||||
|
||||
Start a Julia REPL and type:
|
||||
include("UnixDomainCM.jl")
|
||||
addprocs(UnixDomainCM(4)) # start with four workers
|
||||
|
||||
Alternatively, head.jl, a test script could be run. It just launches the requested number of workers,
|
||||
executes a simple command on all of them and exits.
|
||||
julia head.jl 4
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
import Base: launch, manage, connect, exit
|
||||
|
||||
mutable struct UnixDomainCM <: ClusterManager
|
||||
np::Integer
|
||||
end
|
||||
|
||||
function launch(manager::UnixDomainCM, params::Dict, launched::Array, c::Condition)
|
||||
# println("launch $(manager.np)")
|
||||
cookie = Base.cluster_cookie()
|
||||
for i in 1:manager.np
|
||||
sockname = tempname()
|
||||
try
|
||||
cmd = `$(params[:exename]) --startup-file=no $(@__FILE__) udwrkr $sockname $cookie`
|
||||
io, pobj = open(cmd, "r")
|
||||
|
||||
wconfig = WorkerConfig()
|
||||
wconfig.userdata = Dict(:sockname=>sockname, :io=>io, :process=>pobj)
|
||||
push!(launched, wconfig)
|
||||
notify(c)
|
||||
catch e
|
||||
println(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function connect(manager::UnixDomainCM, pid::Int, config::WorkerConfig)
|
||||
if myid() == 1
|
||||
# println("connect_m2w")
|
||||
config.connect_at = get(config.userdata)[:sockname] # This will be useful in the worker-to-worker connection setup.
|
||||
|
||||
print_worker_stdout(get(config.userdata)[:io], pid)
|
||||
else
|
||||
# println("connect_w2w")
|
||||
sockname = get(config.connect_at)
|
||||
config.userdata = Dict{Symbol, Any}(:sockname=>sockname)
|
||||
end
|
||||
|
||||
t = time()
|
||||
while true
|
||||
try
|
||||
address = get(config.userdata)[:sockname]
|
||||
if isa(address, Tuple)
|
||||
sock = connect(address...)
|
||||
else
|
||||
sock = connect(address)
|
||||
end
|
||||
return (sock, sock)
|
||||
catch e
|
||||
if (time() - t) > 30.0
|
||||
rethrow(e)
|
||||
else
|
||||
sleep(0.1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# WORKER
|
||||
function start_worker(sockname, cookie)
|
||||
Base.init_worker(cookie, UnixDomainCM(0))
|
||||
|
||||
srvr = listen(sockname)
|
||||
while true
|
||||
sock = accept(srvr)
|
||||
Base.process_messages(sock, sock)
|
||||
end
|
||||
end
|
||||
|
||||
function manage(manager::UnixDomainCM, id::Int, config::WorkerConfig, op)
|
||||
# Does not seem to be required, filesystem entry cleanup is happening automatically on process exit
|
||||
# if op == :deregister
|
||||
# try
|
||||
# rm(get(config.userdata)[:sockname])
|
||||
# end
|
||||
# end
|
||||
nothing
|
||||
end
|
||||
|
||||
function print_worker_stdout(io, pid)
|
||||
@schedule while !eof(io)
|
||||
line = readline(io)
|
||||
println("\tFrom worker $(pid):\t$line")
|
||||
end
|
||||
end
|
||||
|
||||
if (length(ARGS) > 0) && (ARGS[1] == "udwrkr")
|
||||
# script has been launched as a worker
|
||||
start_worker(ARGS[2], ARGS[3])
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
include("UnixDomainCM.jl")
|
||||
|
||||
addprocs(UnixDomainCM(parse(Int,ARGS[1])))
|
||||
resp = pmap(x -> myid() *2, [1:nworkers()])
|
||||
println(resp)
|
||||
@@ -0,0 +1,12 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
cmanpath = joinpath(dirname(@__FILE__), "UnixDomainCM.jl")
|
||||
include(cmanpath)
|
||||
|
||||
npids = addprocs(UnixDomainCM(2))
|
||||
assert(length(npids) == 2)
|
||||
test_pids = [remotecall_fetch(myid, x) for x in npids]
|
||||
assert(npids == test_pids)
|
||||
rmprocs(npids; waitfor=1.0)
|
||||
|
||||
exit(0)
|
||||
@@ -0,0 +1,34 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
import Base: put!, wait, isready, take!, fetch
|
||||
|
||||
mutable struct DictChannel <: AbstractChannel
|
||||
d::Dict
|
||||
cond_take::Condition # waiting for data to become available
|
||||
DictChannel() = new(Dict(), Condition())
|
||||
end
|
||||
|
||||
function put!(D::DictChannel, k, v)
|
||||
D.d[k] = v
|
||||
notify(D.cond_take)
|
||||
D
|
||||
end
|
||||
|
||||
function take!(D::DictChannel, k)
|
||||
v=fetch(D,k)
|
||||
delete!(D.d, k)
|
||||
v
|
||||
end
|
||||
|
||||
isready(D::DictChannel) = length(D.d) > 1
|
||||
isready(D::DictChannel, k) = haskey(D.d,k)
|
||||
function fetch(D::DictChannel, k)
|
||||
wait(D,k)
|
||||
D.d[k]
|
||||
end
|
||||
|
||||
function wait(D::DictChannel, k)
|
||||
while !isready(D, k)
|
||||
wait(D.cond_take)
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,2 @@
|
||||
/embedding
|
||||
/embedding-debug
|
||||
@@ -0,0 +1,53 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# This Makefile template requires the following variables to be set
|
||||
# in the environment or on the command-line:
|
||||
# JULIA: path to julia[.exe] executable
|
||||
# BIN: binary build directory
|
||||
|
||||
ifndef JULIA
|
||||
$(error "Please pass JULIA=[path of target julia binary], or set as environment variable!")
|
||||
endif
|
||||
ifndef BIN
|
||||
$(error "Please pass BIN=[path of build directory], or set as environment variable!")
|
||||
endif
|
||||
|
||||
#=============================================================================
|
||||
# this source directory where embedding.c is located
|
||||
SRCDIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||
|
||||
# get the executable suffix, if any
|
||||
EXE := $(suffix $(abspath $(JULIA)))
|
||||
|
||||
# get compiler and linker flags. (see: `contrib/julia-config.jl`)
|
||||
JULIA_CONFIG := $(JULIA) -e 'include(joinpath(JULIA_HOME, Base.DATAROOTDIR, "julia", "julia-config.jl"))' --
|
||||
CPPFLAGS_ADD :=
|
||||
CFLAGS_ADD = $(shell $(JULIA_CONFIG) --cflags)
|
||||
LDFLAGS_ADD = -lm $(shell $(JULIA_CONFIG) --ldflags --ldlibs)
|
||||
|
||||
DEBUGFLAGS += -g
|
||||
|
||||
#=============================================================================
|
||||
|
||||
release: $(BIN)/embedding$(EXE)
|
||||
debug: $(BIN)/embedding-debug$(EXE)
|
||||
|
||||
$(BIN)/embedding$(EXE): $(SRCDIR)/embedding.c
|
||||
$(CC) $^ -o $@ $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS)
|
||||
|
||||
$(BIN)/embedding-debug$(EXE): $(SRCDIR)/embedding.c
|
||||
$(CC) $^ -o $@ $(CPPFLAGS_ADD) $(CPPFLAGS) $(CFLAGS_ADD) $(CFLAGS) $(LDFLAGS_ADD) $(LDFLAGS) $(DEBUGFLAGS)
|
||||
|
||||
check: $(BIN)/embedding$(EXE)
|
||||
$(JULIA) $(SRCDIR)/embedding-test.jl $<
|
||||
@echo SUCCESS
|
||||
|
||||
clean:
|
||||
-rm -f $(BIN)/embedding-debug$(EXE) $(BIN)/embedding$(EXE)
|
||||
|
||||
.PHONY: release debug clean check
|
||||
|
||||
# Makefile debugging trick:
|
||||
# call print-VARIABLE to see the runtime value of any variable
|
||||
print-%:
|
||||
@echo '$*=$($*)'
|
||||
@@ -0,0 +1,22 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# tests the output of the embedding example is correct
|
||||
using Base.Test
|
||||
|
||||
@test length(ARGS) == 1
|
||||
@testset "embedding example" begin
|
||||
stdout = Pipe()
|
||||
stderr = Pipe()
|
||||
p = spawn(pipeline(Cmd(ARGS), stdin=DevNull, stdout=stdout, stderr=stderr))
|
||||
close(stdout.in)
|
||||
close(stderr.in)
|
||||
stdout_task = @async readlines(stdout)
|
||||
stderr = readstring(stderr)
|
||||
@test stderr == "MethodError: no method matching this_function_has_no_methods()\n"
|
||||
@test success(p)
|
||||
lines = wait(stdout_task)
|
||||
@test length(lines) == 9
|
||||
@test parse(Float64, lines[1]) ≈ sqrt(2)
|
||||
@test lines[8] == "called bar"
|
||||
@test lines[9] == "calling new bar"
|
||||
end
|
||||
@@ -0,0 +1,153 @@
|
||||
// This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
#include <julia.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
#ifdef _OS_WINDOWS_
|
||||
__declspec(dllexport) __cdecl
|
||||
#endif
|
||||
double my_c_sqrt(double x)
|
||||
{
|
||||
return sqrt(x);
|
||||
}
|
||||
|
||||
jl_value_t *checked_eval_string(const char* code)
|
||||
{
|
||||
jl_value_t *result = jl_eval_string(code);
|
||||
if (jl_exception_occurred()) {
|
||||
// none of these allocate, so a gc-root (JL_GC_PUSH) is not necessary
|
||||
jl_call2(jl_get_function(jl_base_module, "showerror"),
|
||||
jl_stderr_obj(),
|
||||
jl_exception_occurred());
|
||||
jl_printf(jl_stderr_stream(), "\n");
|
||||
jl_atexit_hook(1);
|
||||
exit(1);
|
||||
}
|
||||
assert(result && "Missing return value but no exception occurred!");
|
||||
return result;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
jl_init();
|
||||
|
||||
{
|
||||
// Simple running of Julia code
|
||||
|
||||
checked_eval_string("println(sqrt(2.0))");
|
||||
}
|
||||
|
||||
{
|
||||
// Accessing the return value
|
||||
|
||||
jl_value_t *ret = checked_eval_string("sqrt(2.0)");
|
||||
double retDouble = jl_unbox_float64(ret);
|
||||
printf("sqrt(2.0) in C: %e\n", retDouble);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
{
|
||||
// Same as above but with function handle (more flexible)
|
||||
|
||||
jl_function_t *func = jl_get_function(jl_base_module, "sqrt");
|
||||
jl_value_t* argument = jl_box_float64(2.0);
|
||||
jl_value_t* ret = jl_call1(func, argument);
|
||||
double retDouble = jl_unbox_float64(ret);
|
||||
printf("sqrt(2.0) in C: %e\n", retDouble);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
{
|
||||
// 1D arrays
|
||||
|
||||
jl_value_t* array_type = jl_apply_array_type((jl_value_t*)jl_float64_type, 1);
|
||||
jl_array_t* x = jl_alloc_array_1d(array_type, 10);
|
||||
// JL_GC_PUSH* is required here to ensure that `x` is not deleted before
|
||||
// (aka, is gc-rooted until) the program reaches the corresponding JL_GC_POP()
|
||||
JL_GC_PUSH1(&x);
|
||||
|
||||
double* xData = jl_array_data(x);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < jl_array_len(x); i++)
|
||||
xData[i] = i;
|
||||
|
||||
jl_function_t *func = jl_get_function(jl_base_module, "reverse!");
|
||||
jl_call1(func, (jl_value_t*) x);
|
||||
|
||||
printf("x = [");
|
||||
for (i = 0; i < jl_array_len(x); i++)
|
||||
printf("%e ", xData[i]);
|
||||
printf("]\n");
|
||||
fflush(stdout);
|
||||
|
||||
JL_GC_POP();
|
||||
}
|
||||
|
||||
{
|
||||
// Defining a Julia function and calling it
|
||||
|
||||
checked_eval_string("my_func(x) = 2 * x");
|
||||
|
||||
jl_function_t *func = jl_get_function(jl_current_module, "my_func");
|
||||
jl_value_t* arg = jl_box_float64(5.0);
|
||||
double ret = jl_unbox_float64(jl_call1(func, arg));
|
||||
|
||||
printf("my_func(5.0) = %f\n", ret);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
{
|
||||
// Calling a C function from Julia (from C)
|
||||
|
||||
// in a shared library (exported, by name)
|
||||
checked_eval_string("println( ccall(:my_c_sqrt, Float64, (Float64,), 2.0) )");
|
||||
|
||||
// or via a pointer
|
||||
jl_value_t *call_by_ptr = checked_eval_string(
|
||||
"my_c_sqrt -> println( ccall(my_c_sqrt, Float64, (Float64,), 2.0) )");
|
||||
jl_call1(call_by_ptr, jl_box_voidpointer(my_c_sqrt));
|
||||
}
|
||||
|
||||
{
|
||||
// Handling exceptions gracefully
|
||||
|
||||
jl_value_t *f = checked_eval_string("function this_function_has_no_methods end");
|
||||
jl_call0(f);
|
||||
|
||||
if (jl_exception_occurred()) {
|
||||
jl_call2(jl_get_function(jl_base_module, "showerror"),
|
||||
jl_stderr_obj(),
|
||||
jl_exception_occurred());
|
||||
jl_printf(jl_stderr_stream(), "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
// Creating and using a native C function handle
|
||||
// to a Julia function signature
|
||||
|
||||
checked_eval_string(
|
||||
"function bar()\n"
|
||||
" println(\"called bar\")\n"
|
||||
" random_return_value = 42\n"
|
||||
"end");
|
||||
checked_eval_string(
|
||||
"function bar_from_c()\n"
|
||||
" bar()\n"
|
||||
" nothing\n"
|
||||
"end");
|
||||
typedef void (*Func_VOID__VOID)(void);
|
||||
jl_value_t *pbar = jl_eval_string("cfunction(bar_from_c, Void, ())");
|
||||
Func_VOID__VOID bar = (Func_VOID__VOID)jl_unbox_voidpointer(pbar);
|
||||
bar();
|
||||
checked_eval_string("bar() = println(\"calling new bar\")");
|
||||
bar();
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
jl_atexit_hook(ret);
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,130 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module LRUExample
|
||||
# An LRU (Least Recently Used) cache is an associative data structure which
|
||||
# maintains its contents in an order such that the most recently used item
|
||||
# is at the beginning of the structure, and the least recently used at the end.
|
||||
#
|
||||
# This file specifies two types of LRU caches, both with and without a size
|
||||
# limit. BoundedLRU has a limit and evicts the LRU item if a new item is added
|
||||
# after that bound is reached. UnboundedLRU does not have a maximum size, but
|
||||
# can be used as a basis for more complex LRUs.
|
||||
#
|
||||
# LRUs should follow the interfaces for general collections, indexable
|
||||
# collections, and associative collections.
|
||||
|
||||
# The standard implementation of an LRU backs a hash table with a doubly-linked
|
||||
# list for O(1) operations when reordering on access and eviction. The Julia
|
||||
# implementation instead backs the table with a Vector. For moderately-sized
|
||||
# collections, the difference in performance is small, and this implmentation
|
||||
# is simpler and easier to understand.
|
||||
|
||||
import Base.isempty, Base.length, Base.sizeof
|
||||
import Base.start, Base.next, Base.done
|
||||
import Base.haskey, Base.get
|
||||
import Base.setindex!, Base.getindex, Base.delete!, Base.empty!
|
||||
import Base.show
|
||||
|
||||
abstract type LRU{K,V} <: Associative{K,V} end
|
||||
|
||||
# Default cache size
|
||||
const __MAXCACHE = 1024
|
||||
|
||||
mutable struct CacheItem{K,V}
|
||||
k::K
|
||||
v::V
|
||||
end
|
||||
|
||||
mutable struct UnboundedLRU{K,V} <: LRU{K,V}
|
||||
ht::Dict
|
||||
q::Vector{CacheItem}
|
||||
|
||||
UnboundedLRU{K,V}() where {K,V} = new(Dict(), similar(Array{CacheItem}(1), 0))
|
||||
end
|
||||
UnboundedLRU() = UnboundedLRU{Any, Any}()
|
||||
|
||||
mutable struct BoundedLRU{K,V} <: LRU{K,V}
|
||||
ht::Dict
|
||||
q::Vector{CacheItem}
|
||||
maxsize::Int
|
||||
|
||||
BoundedLRU{K,V}(m) where {K,V} = new(Dict(), similar(Array{CacheItem}(1), 0), m)
|
||||
BoundedLRU{K,V}() where {K,V} = BoundedLRU(__MAXCACHE)
|
||||
end
|
||||
BoundedLRU(m) = BoundedLRU{Any, Any}(m)
|
||||
BoundedLRU() = BoundedLRU{Any, Any}()
|
||||
|
||||
## collections ##
|
||||
|
||||
isempty(lru::LRU) = isempty(lru.q)
|
||||
length(lru::LRU) = length(lru.q)
|
||||
|
||||
## associative ##
|
||||
|
||||
# Should this check count as an access?
|
||||
haskey(lru::LRU, key) = haskey(lru.ht, key)
|
||||
|
||||
get(lru::LRU, key, default) = haskey(lru, key) ? lru[key] : default
|
||||
|
||||
function empty!(lru::LRU)
|
||||
empty!(lru.ht)
|
||||
empty!(lru.q)
|
||||
end
|
||||
|
||||
|
||||
show(io::IO, lru::UnboundedLRU) = print(io,"UnboundedLRU()")
|
||||
show(io::IO, lru::BoundedLRU) = print(io,"BoundedLRU($(lru.maxsize))")
|
||||
|
||||
## indexable ##
|
||||
|
||||
# Method to do the second, slow lookup in the list with early return.
|
||||
function locate(q, x)
|
||||
for i = 1:length(q)
|
||||
if q[i] == x
|
||||
return i
|
||||
end
|
||||
end
|
||||
error("Item not found.")
|
||||
end
|
||||
|
||||
function getindex(lru::LRU, key)
|
||||
item = lru.ht[key]
|
||||
idx = locate(lru.q, item)
|
||||
splice!(lru.q, idx)
|
||||
unshift!(lru.q, item)
|
||||
item.v
|
||||
end
|
||||
|
||||
function setindex!(lru::LRU, v, key)
|
||||
if haskey(lru, key)
|
||||
item = lru.ht[key]
|
||||
idx = locate(lru.q, item)
|
||||
item.v = v
|
||||
splice!(lru.q, idx)
|
||||
else
|
||||
item = CacheItem(key, v)
|
||||
lru.ht[key] = item
|
||||
end
|
||||
unshift!(lru.q, item)
|
||||
end
|
||||
|
||||
# Eviction
|
||||
function setindex!{V,K}(lru::BoundedLRU, v::V, key::K)
|
||||
invoke(setindex!, Tuple{LRU,V,K}, lru, v, key)
|
||||
nrm = length(lru) - lru.maxsize
|
||||
for i in 1:nrm
|
||||
rm = pop!(lru.q)
|
||||
delete!(lru.ht, rm.k)
|
||||
end
|
||||
end
|
||||
|
||||
## associative ##
|
||||
|
||||
function delete!(lru::LRU, key)
|
||||
item = lru.ht[key]
|
||||
idx = locate(lru.q, item)
|
||||
delete!(lru.ht, key)
|
||||
delete!(lru.q, idx)
|
||||
end
|
||||
|
||||
end # module
|
||||
@@ -0,0 +1,47 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
using .LRUExample
|
||||
|
||||
TestLRU = LRUExample.UnboundedLRU{String, String}()
|
||||
TestBLRU = LRUExample.BoundedLRU{String, String}(1000)
|
||||
|
||||
get_str(i) = String(vcat(map(x->[x>>4; x&0x0F], reinterpret(UInt8, [Int32(i)]))...))
|
||||
|
||||
isbounded{L<:LRUExample.LRU}(::Type{L}) = any(map(n->n==:maxsize, fieldnames(L)))
|
||||
isbounded{L<:LRUExample.LRU}(l::L) = isbounded(L)
|
||||
|
||||
nmax = round.(Int, logspace(2, 5, 4))
|
||||
|
||||
function lrutest()
|
||||
#println("LRU consistency tests")
|
||||
for lru in (TestLRU,TestBLRU)
|
||||
for n in nmax
|
||||
empty!(lru)
|
||||
#@printf(" %s, %d items\n", lru, n)
|
||||
#print(" Simple eviction: ")
|
||||
for i in 1:n
|
||||
str = get_str(i)
|
||||
lru[str] = str
|
||||
@assert lru.q[1].v == str
|
||||
if isbounded(lru) && length(lru) >= lru.maxsize
|
||||
tailstr = get_str(i-lru.maxsize+1)
|
||||
@assert lru.q[end].v == tailstr
|
||||
end
|
||||
end
|
||||
#println("pass")
|
||||
|
||||
#print(" Lookup, random access: ")
|
||||
for i in 1:n
|
||||
str = get_str(rand(1:n))
|
||||
if haskey(lru, str) # the bounded LRUs can have cache misses
|
||||
blah = lru[str]
|
||||
@assert lru.q[1].v == blah
|
||||
end
|
||||
end
|
||||
#println("pass")
|
||||
end
|
||||
empty!(lru)
|
||||
end
|
||||
end
|
||||
|
||||
lrutest()
|
||||
@@ -0,0 +1,52 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
ndgrid(v::AbstractVector) = copy(v)
|
||||
|
||||
function ndgrid{T}(v1::AbstractVector{T}, v2::AbstractVector{T})
|
||||
m, n = length(v1), length(v2)
|
||||
v1 = reshape(v1, m, 1)
|
||||
v2 = reshape(v2, 1, n)
|
||||
(repmat(v1, 1, n), repmat(v2, m, 1))
|
||||
end
|
||||
|
||||
function ndgrid_fill(a, v, s, snext)
|
||||
for j = 1:length(a)
|
||||
a[j] = v[div(rem(j-1, snext), s)+1]
|
||||
end
|
||||
end
|
||||
|
||||
function ndgrid{T}(vs::AbstractVector{T}...)
|
||||
n = length(vs)
|
||||
sz = map(length, vs)
|
||||
out = ntuple(i->Array{T}(sz), n)
|
||||
s = 1
|
||||
for i=1:n
|
||||
a = out[i]::Array
|
||||
v = vs[i]
|
||||
snext = s*size(a,i)
|
||||
ndgrid_fill(a, v, s, snext)
|
||||
s = snext
|
||||
end
|
||||
out
|
||||
end
|
||||
|
||||
meshgrid(v::AbstractVector) = meshgrid(v, v)
|
||||
|
||||
function meshgrid{T}(vx::AbstractVector{T}, vy::AbstractVector{T})
|
||||
m, n = length(vy), length(vx)
|
||||
vx = reshape(vx, 1, n)
|
||||
vy = reshape(vy, m, 1)
|
||||
(repmat(vx, m, 1), repmat(vy, 1, n))
|
||||
end
|
||||
|
||||
function meshgrid{T}(vx::AbstractVector{T}, vy::AbstractVector{T},
|
||||
vz::AbstractVector{T})
|
||||
m, n, o = length(vy), length(vx), length(vz)
|
||||
vx = reshape(vx, 1, n, 1)
|
||||
vy = reshape(vy, m, 1, 1)
|
||||
vz = reshape(vz, 1, 1, o)
|
||||
om = ones(Int, m)
|
||||
on = ones(Int, n)
|
||||
oo = ones(Int, o)
|
||||
(vx[om, :, oo], vy[:, on, oo], vz[om, on, :])
|
||||
end
|
||||
@@ -0,0 +1,28 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# n-queens (nqueens) solver, for nsquaresx-by-nsquaresy board
|
||||
|
||||
struct Queen
|
||||
x::Int
|
||||
y::Int
|
||||
end
|
||||
hitshorz(queena, queenb) = queena.x == queenb.x
|
||||
hitsvert(queena, queenb) = queena.y == queenb.y
|
||||
hitsdiag(queena, queenb) = abs(queena.x - queenb.x) == abs(queena.y - queenb.y)
|
||||
hitshvd(qa, qb) = hitshorz(qa, qb) || hitsvert(qa, qb) || hitsdiag(qa, qb)
|
||||
hitsany(testqueen, queens) = any(q -> hitshvd(testqueen, q), queens)
|
||||
|
||||
function trysolve(nsquaresx, nsquaresy, nqueens, presqueens = ())
|
||||
nqueens == 0 && return presqueens
|
||||
for xsquare in 1:nsquaresx
|
||||
for ysquare in 1:nsquaresy
|
||||
testqueen = Queen(xsquare, ysquare)
|
||||
if !hitsany(testqueen, presqueens)
|
||||
tryqueens = (presqueens..., testqueen)
|
||||
maybesol = trysolve(nsquaresx, nsquaresy, nqueens - 1, tryqueens)
|
||||
maybesol !== nothing && return maybesol
|
||||
end
|
||||
end
|
||||
end
|
||||
return nothing
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
x="println(\"# This file is a part of Julia. License is MIT: https://julialang.org/license\\n\\nx=\$(repr(x))\\n\$x\")"
|
||||
println("# This file is a part of Julia. License is MIT: https://julialang.org/license\n\nx=$(repr(x))\n$x")
|
||||
@@ -0,0 +1,61 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
function add_method(gf, an, at, body)
|
||||
argexs = [Expr(Symbol("::"), an[i], at[i]) for i=1:length(an)]
|
||||
def = quote
|
||||
let __F__=($gf)
|
||||
function __F__($(argexs...))
|
||||
$body
|
||||
end
|
||||
end
|
||||
end
|
||||
eval(def)
|
||||
end
|
||||
|
||||
macro staged(fdef)
|
||||
if !isa(fdef,Expr) || fdef.head !== :function
|
||||
error("@staged: expected method definition")
|
||||
end
|
||||
fname = fdef.args[1].args[1]
|
||||
argspec = fdef.args[1].args[2:end]
|
||||
argnames = map(x->(isa(x,Expr) ? x.args[1] : x), argspec)
|
||||
qargnames = map(x->Expr(:quote,x), argnames)
|
||||
fbody = fdef.args[2]
|
||||
@gensym gengf argtypes expander genbody
|
||||
quote
|
||||
let ($gengf)
|
||||
global ($fname) # should be "outer"
|
||||
local ($expander)
|
||||
function ($expander)($(argnames...))
|
||||
$fbody
|
||||
end
|
||||
($gengf)() = 0 # should be initially empty GF
|
||||
function ($fname)($(argspec...))
|
||||
($argtypes) = typeof(tuple($(argnames...)))
|
||||
if !method_exists($gengf, $argtypes)
|
||||
($genbody) = apply(($expander), ($argtypes))
|
||||
add_method($gengf, Any[$(qargnames...)],
|
||||
$argtypes, $genbody)
|
||||
end
|
||||
return ($gengf)($(argnames...))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# example
|
||||
|
||||
@staged function nloops(dims::Tuple)
|
||||
names = map(x->gensym(), dims)
|
||||
ex = quote
|
||||
println([$(names...)])
|
||||
end
|
||||
for i = 1:length(dims)
|
||||
ex = quote
|
||||
for $(names[i]) in dims[$i]
|
||||
$ex
|
||||
end
|
||||
end
|
||||
end
|
||||
ex
|
||||
end
|
||||
@@ -0,0 +1,45 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module Time
|
||||
export TimeDelta
|
||||
|
||||
import Base.show, Base.+, Base.-, Base.convert, Base.promote_rule
|
||||
|
||||
struct TimeDelta{p}
|
||||
v::Int64
|
||||
end
|
||||
|
||||
const PREFIXES = [
|
||||
"yocto", "zepto", "atto", "femto", "pico", "nano", "micro", "milli",
|
||||
"", "kilo", "mega", "giga", "tera", "peta", "exa", "zetta", "yotta",
|
||||
]
|
||||
const ZERO_INDEX = 9
|
||||
const MAX_INDEX = 17
|
||||
|
||||
function show{p}(io::IO, x::TimeDelta{p})
|
||||
k = max(1,min(MAX_INDEX,fld(p,3)+ZERO_INDEX))
|
||||
r = p-3(k-ZERO_INDEX)
|
||||
prefix = PREFIXES[k]
|
||||
if r == 0
|
||||
s = x.v == 1 ? "" : "s"
|
||||
print(io, "$(x.v) $(prefix)second$s")
|
||||
elseif r > 0
|
||||
print(io, "$(x.v*10^r) $(prefix)seconds")
|
||||
else
|
||||
print(io, "$(x.v/10^-r) $(prefix)seconds")
|
||||
end
|
||||
end
|
||||
|
||||
convert{p,q}(::Type{TimeDelta{p}}, x::TimeDelta{q}) =
|
||||
TimeDelta{p}(p <= q ? x.v*10^(q-p) : div(x.v,10^(p-q)))
|
||||
|
||||
promote_rule{p,q}(::Type{TimeDelta{p}}, ::Type{TimeDelta{q}}) = TimeDelta{min(p,q)}
|
||||
|
||||
-{p}(x::TimeDelta{p}) = TimeDelta{p}(-x.v)
|
||||
+{p}(x::TimeDelta{p}, y::TimeDelta{p}) = TimeDelta{p}(x.v+y.v)
|
||||
-{p}(x::TimeDelta{p}, y::TimeDelta{p}) = TimeDelta{p}(x.v-y.v)
|
||||
|
||||
+(x::TimeDelta, y::TimeDelta) = +(promote(x,y)...)
|
||||
-(x::TimeDelta, y::TimeDelta) = -(promote(x,y)...)
|
||||
|
||||
end # module
|
||||
@@ -0,0 +1,154 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
module TypeTrees
|
||||
##
|
||||
# Generate a text graphic of Julia modules type tree
|
||||
##
|
||||
|
||||
struct Binding
|
||||
mod::Module
|
||||
sym::Symbol
|
||||
end
|
||||
Binding(tn::TypeName) = Binding(tn.module, tn.name)
|
||||
Base.isless(a::Binding, b::Binding) = isless(a.sym, b.sym)
|
||||
|
||||
# The node type holds the type of the current node and a dict of subtypes
|
||||
struct TTNode
|
||||
typ # ::Type
|
||||
subtypes::Dict{Binding, TTNode}
|
||||
|
||||
TTNode(t::ANY) = new(t, Dict{Binding, TTNode}())
|
||||
end
|
||||
|
||||
# Add a node to a dict if not added
|
||||
function add_ttnode(subtypes::Dict{Binding, TTNode}, sname::Binding, tnode::TTNode)
|
||||
return get!(subtypes, sname, tnode)
|
||||
end
|
||||
|
||||
function add_ttnode(subtypes::Dict{Binding, TTNode}, sname::Binding, t::Type)
|
||||
return get!(subtypes, sname, TTNode(t))
|
||||
end
|
||||
|
||||
# Store a type and its type hierarchy chain
|
||||
# Recurse till we reach the top level type
|
||||
function store_type(sname::Binding, t::Union)
|
||||
suptype = Union
|
||||
tnode = TTNode(t)
|
||||
|
||||
# store unions under Union type
|
||||
subtypes = store_type(Binding(suptype.name), suptype)
|
||||
add_ttnode(subtypes, sname, tnode)
|
||||
store_union(sname, tnode, t)
|
||||
|
||||
# unions are also in a sense related to the types of their components
|
||||
|
||||
return tnode.subtypes
|
||||
end
|
||||
function store_union(sname::Binding, tnode::TTNode, t::ANY)
|
||||
t = Base.unwrap_unionall(t)
|
||||
if isa(t, Union)
|
||||
store_union(sname, tnode, t.a)
|
||||
store_union(sname, tnode, t.b)
|
||||
elseif isa(t, DataType)
|
||||
binding = Binding(t.name)
|
||||
subtypes = store_type(binding, t)
|
||||
add_ttnode(subtypes, sname, tnode)
|
||||
end
|
||||
nothing
|
||||
end
|
||||
|
||||
function store_type(sname::Binding, t::UnionAll)
|
||||
suptype = Base.unwrap_unionall(t)
|
||||
binding = isa(suptype, DataType) ? Binding(suptype.name) : Binding(Main, string(suptype::Union))
|
||||
subtypes = store_type(binding, suptype)
|
||||
tnode = add_ttnode(subtypes, sname, t)
|
||||
return tnode.subtypes
|
||||
end
|
||||
|
||||
function store_type(sname::Binding, t::DataType)
|
||||
suptype = supertype(t)
|
||||
subtypes = (suptype != t) ? store_type(Binding(suptype.name), suptype) : types_tree
|
||||
tnode = add_ttnode(subtypes, sname, t)
|
||||
return tnode.subtypes
|
||||
end
|
||||
|
||||
# examine all symbols in module and store those that are types
|
||||
function store_all_from(m::Module)
|
||||
for s in names(m, true)
|
||||
if isdefined(m, s) && !Base.isdeprecated(m, s)
|
||||
t = getfield(m, s)
|
||||
if isa(t, Type) && t !== Union{}
|
||||
store_type(Binding(m, s), t)
|
||||
elseif isa(t, Module) && module_name(t) === s && module_parent(t) === m && t !== m
|
||||
store_all_from(t)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
type_props(typ) = ""
|
||||
type_props(typ::DataType) = string("<<",
|
||||
typ.abstract ? " abstract" : " concrete",
|
||||
typ.mutable ? " mutable" : " immutable",
|
||||
typ.layout != C_NULL ? string(
|
||||
Base.datatype_pointerfree(typ) ? " pointerfree" : "",
|
||||
Base.datatype_haspadding(typ) ? " haspadding" : "",
|
||||
" nfields:", Core.nfields(typ),
|
||||
" size:", typ.size,
|
||||
", align:", Base.datatype_alignment(typ)) : "",
|
||||
" >>")
|
||||
|
||||
function print_tree(subtypes::Dict{Binding, TTNode}, pfx::String="")
|
||||
for b in sort!(collect(keys(subtypes)))
|
||||
v = subtypes[b]
|
||||
ishidden = unsafe_load(Base.unsafe_convert(Ptr{UInt8}, b.sym)) == UInt8('#')
|
||||
if ishidden && supertype(v.typ) === Function
|
||||
continue
|
||||
end
|
||||
if b.mod === Main
|
||||
n = string(b.sym)
|
||||
elseif !isa(v.typ, DataType) || v.typ.name.module != b.mod || v.typ.name.name != b.sym
|
||||
n_io = IOBuffer()
|
||||
print(n_io, b.mod, '.', b.sym)
|
||||
ua = v.typ
|
||||
if isa(ua, UnionAll)
|
||||
print(n_io, "{")
|
||||
while true
|
||||
print(n_io, ua.var)
|
||||
ua = ua.body
|
||||
if isa(ua, UnionAll)
|
||||
print(n_io, ", ")
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
print(n_io, "}")
|
||||
end
|
||||
n = String(take!(n_io))
|
||||
else
|
||||
n = string(v.typ)
|
||||
end
|
||||
if n == string(v.typ)
|
||||
println(pfx, "+- ", n, " ", type_props(v.typ))
|
||||
else
|
||||
println(pfx, "+- ", n, " = ", v.typ, " ", type_props(v.typ))
|
||||
end
|
||||
v.typ === Function && println(pfx, ". ## hiding implicit Function subtypes ##")
|
||||
print_tree(v.subtypes, pfx * ". ")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# TODO: optionally take module names in command line
|
||||
# TODO: option to list subtrees of type tree, or other symbol types
|
||||
const types_tree = Dict{Binding, TTNode}()
|
||||
|
||||
store_all_from(Main)
|
||||
|
||||
# print_tree(types_tree)
|
||||
|
||||
end # module
|
||||
|
||||
if !isinteractive()
|
||||
TypeTrees.print_tree(TypeTrees.types_tree)
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# wordcount.jl
|
||||
#
|
||||
# Implementation of parallelized "word-count" of a text, inspired by the
|
||||
# Hadoop WordCount example. Uses @spawn and fetch() to parallelize
|
||||
# the "map" task. Reduce is currently done single-threaded.
|
||||
#
|
||||
# To run in parallel on a string stored in variable `text`:
|
||||
# julia -p <N>
|
||||
# julia> require("<julia_doc_dir>/examples/wordcount.jl")
|
||||
# julia> ...(define text)...
|
||||
# julia> counts=parallel_wordcount(text)
|
||||
#
|
||||
# Or to run on a group of files, writing results to an output file:
|
||||
# julia -p <N>
|
||||
# julia> require("<julia_doc_dir>/examples/wordcount.jl")
|
||||
# julia> wordcount_files("/tmp/output.txt", "/tmp/input1.txt","/tmp/input2.txt",...)
|
||||
|
||||
# "Map" function.
|
||||
# Takes a string. Returns a Dict with the number of times each word
|
||||
# appears in that string.
|
||||
function wordcount(text)
|
||||
words=split(text,[' ','\n','\t','-','.',',',':',';'];keep=false)
|
||||
counts=Dict()
|
||||
for w = words
|
||||
counts[w]=get(counts,w,0)+1
|
||||
end
|
||||
return counts
|
||||
end
|
||||
|
||||
# "Reduce" function.
|
||||
# Takes a collection of Dicts in the format returned by wordcount()
|
||||
# Returns a Dict in which words that appear in multiple inputs
|
||||
# have their totals added together.
|
||||
function wcreduce(wcs)
|
||||
counts=Dict()
|
||||
for c in wcs, (k,v) in c
|
||||
counts[k] = get(counts,k,0)+v
|
||||
end
|
||||
return counts
|
||||
end
|
||||
|
||||
# Splits input string into nprocs() equal-sized chunks (last one rounds up),
|
||||
# and @spawns wordcount() for each chunk to run in parallel. Then fetch()s
|
||||
# results and performs wcreduce().
|
||||
function parallel_wordcount(text)
|
||||
lines=split(text,'\n';keep=false)
|
||||
np=nprocs()
|
||||
unitsize=ceil(length(lines)/np)
|
||||
wcounts=[]
|
||||
rrefs=[]
|
||||
# spawn procs
|
||||
for i=1:np
|
||||
first=unitsize*(i-1)+1
|
||||
last=unitsize*i
|
||||
if last>length(lines)
|
||||
last=length(lines)
|
||||
end
|
||||
subtext=join(lines[Int(first):Int(last)],"\n")
|
||||
push!(rrefs, @spawn wordcount( subtext ) )
|
||||
end
|
||||
# fetch results
|
||||
while length(rrefs)>0
|
||||
push!(wcounts,fetch(pop!(rrefs)))
|
||||
end
|
||||
# reduce
|
||||
count=wcreduce(wcounts)
|
||||
return count
|
||||
end
|
||||
|
||||
# Takes the name of a result file, and a list of input file names.
|
||||
# Combines the contents of all files, then performs a parallel_wordcount
|
||||
# on the resulting string. Writes the results to result_file.
|
||||
function wordcount_files(result_file,inputs...)
|
||||
text = ""
|
||||
for file in inputs
|
||||
text *= readstring(file)
|
||||
end
|
||||
wc = parallel_wordcount(text)
|
||||
open(result_file,"w") do f
|
||||
for (k,v) in wc
|
||||
println(f, k,"=",v)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16.5mm"
|
||||
height="8.6603003mm"
|
||||
viewBox="0 0 58.464567 30.686103"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="arrow.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.2"
|
||||
inkscape:cx="14.209234"
|
||||
inkscape:cy="29.780479"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1053"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1021.6761)">
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 0,1021.6761 35.433071,0 -17.716536,30.6861 z"
|
||||
id="path4140"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* The default CSS style for Documenter.jl generated sites
|
||||
*
|
||||
* Heavily inspired by the Julia Sphinx theme
|
||||
* https://github.com/JuliaLang/JuliaDoc
|
||||
* which extends the sphinx_rtd_theme
|
||||
* https://github.com/snide/sphinx_rtd_theme
|
||||
*
|
||||
* Part of Documenter.jl
|
||||
* https://github.com/JuliaDocs/Documenter.jl
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
/* fonts */
|
||||
body, input {
|
||||
font-family: 'Lato', 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
color: #222;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: 'Roboto Mono', Monaco, courier, monospace;
|
||||
font-size: 0.90em;
|
||||
}
|
||||
|
||||
pre code {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #2980b9;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #3091d1;
|
||||
}
|
||||
|
||||
a:visited {
|
||||
color: #9b59b6;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
h1 { font-size: 1.75em; }
|
||||
h2 { font-size: 1.50em; }
|
||||
h3 { font-size: 1.25em; }
|
||||
h4 { font-size: 1.15em; }
|
||||
h5 { font-size: 1.10em; }
|
||||
h6 { font-size: 1em; }
|
||||
|
||||
h4, h5, h6 {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #e1e4e5;
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #f3f6f6;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
/* Inline code and code blocks */
|
||||
|
||||
code {
|
||||
padding: 0.1em;
|
||||
background-color: rgba(0,0,0,.04);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 3px;
|
||||
padding: 0.5em;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
pre code {
|
||||
padding: 0;
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
/* Headers in admonitions and docstrings */
|
||||
.admonition h1,
|
||||
article section.docstring h1 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.admonition h2,
|
||||
article section.docstring h2 {
|
||||
font-size: 1.10em;
|
||||
}
|
||||
|
||||
.admonition h3,
|
||||
.admonition h4,
|
||||
.admonition h5,
|
||||
.admonition h6,
|
||||
article section.docstring h3,
|
||||
article section.docstring h4,
|
||||
article section.docstring h5,
|
||||
article section.docstring h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
nav.toc {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 20em;
|
||||
overflow-y: auto;
|
||||
padding: 1em 0;
|
||||
background-color: #fcfcfc;
|
||||
box-shadow: inset -14px 0px 5px -12px rgb(210,210,210);
|
||||
}
|
||||
|
||||
nav.toc .logo {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
max-height: 6em;
|
||||
max-width: 18em;
|
||||
}
|
||||
|
||||
nav.toc h1 {
|
||||
text-align: center;
|
||||
margin-top: .57em;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
nav.toc select {
|
||||
display: block;
|
||||
height: 2em;
|
||||
padding: 0 1.6em 0 1em;
|
||||
min-width: 7em;
|
||||
max-width: 90%;
|
||||
max-width: calc(100% - 5em);
|
||||
margin: 0 auto;
|
||||
font-size: .83em;
|
||||
border: 1px solid #c9c9c9;
|
||||
border-radius: 1em;
|
||||
|
||||
/* TODO: doesn't seem to be centered on Safari */
|
||||
text-align: center;
|
||||
text-align-last: center;
|
||||
|
||||
appearance: none;
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none;
|
||||
|
||||
background: white url("arrow.svg");
|
||||
background-size: 1.155em;
|
||||
background-repeat: no-repeat;
|
||||
background-position: right;
|
||||
}
|
||||
|
||||
nav.toc select:hover {
|
||||
border: 1px solid #a0a0a0;
|
||||
}
|
||||
|
||||
nav.toc select option {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
nav.toc input {
|
||||
display: block;
|
||||
height: 2em;
|
||||
width: 90%;
|
||||
width: calc(100% - 5em);
|
||||
margin: 1.2em auto;
|
||||
padding: 0 1em;
|
||||
border: 1px solid #c9c9c9;
|
||||
border-radius: 1em;
|
||||
font-size: .83em;
|
||||
}
|
||||
|
||||
nav.toc > ul * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
nav.toc ul {
|
||||
color: #404040;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
nav.toc ul .toctext {
|
||||
color: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
nav.toc ul a:hover {
|
||||
color: #fcfcfc;
|
||||
background-color: #4e4a4a;
|
||||
}
|
||||
|
||||
nav.toc ul.internal a {
|
||||
color: inherit;
|
||||
display: block;
|
||||
}
|
||||
|
||||
nav.toc ul.internal a:hover {
|
||||
background-color: #d6d6d6;
|
||||
}
|
||||
|
||||
nav.toc ul.internal {
|
||||
background-color: #e3e3e3;
|
||||
box-shadow: inset -14px 0px 5px -12px rgb(210,210,210);
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
nav.toc ul.internal li.toplevel {
|
||||
border-top: 1px solid #c9c9c9;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
nav.toc ul.internal li.toplevel:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
nav.toc .toctext {
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.3em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
nav.toc ul .toctext {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
nav.toc ul ul .toctext {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
nav.toc ul ul ul .toctext {
|
||||
padding-left: 3em;
|
||||
}
|
||||
|
||||
nav.toc li.current > .toctext {
|
||||
border-top: 1px solid #c9c9c9;
|
||||
border-bottom: 1px solid #c9c9c9;
|
||||
color: #404040;
|
||||
font-weight: bold;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
article {
|
||||
margin-left: 20em;
|
||||
min-width: 20em;
|
||||
max-width: 48em;
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
article > header {}
|
||||
|
||||
article > header div#topbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
article > header nav ul {
|
||||
display: inline-block;
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
article > header nav li {
|
||||
display: inline-block;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
article > header nav li:before {
|
||||
content: "»";
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
article > header .edit-page {
|
||||
float: right;
|
||||
}
|
||||
|
||||
article > footer {}
|
||||
|
||||
article > footer a.prev {
|
||||
float: left;
|
||||
}
|
||||
article > footer a.next {
|
||||
float: right;
|
||||
}
|
||||
|
||||
article > footer a .direction:after {
|
||||
content: ": ";
|
||||
}
|
||||
|
||||
article hr {
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
article section.docstring {
|
||||
border: 1px solid #ddd;
|
||||
margin: 0.5em 0;
|
||||
padding: 0.5em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
article section.docstring .docstring-header {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
article section.docstring .docstring-binding {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
article section.docstring .docstring-category {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
article section.docstring a.source-link {
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-anchor,
|
||||
.nav-anchor:hover,
|
||||
.nav-anchor:visited {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/*
|
||||
* Admonitions
|
||||
*
|
||||
* Colors (title, body)
|
||||
* warning: #f0b37e #ffedcc (orange)
|
||||
* note: #6ab0de #e7f2fa (blue)
|
||||
* tip: #1abc9c #dbfaf4 (green)
|
||||
*/
|
||||
.admonition {
|
||||
border-radius: 3px;
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
|
||||
.admonition-title {
|
||||
border-radius: 3px 3px 0 0;
|
||||
background-color: #9b9b9b;
|
||||
padding: 0.15em 0.5em;
|
||||
}
|
||||
|
||||
.admonition-text {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.admonition-text > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.admonition-text > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.admonition > .admonition-title:before {
|
||||
font-family: "FontAwesome";
|
||||
margin-right: 5px;
|
||||
content: "\f06a";
|
||||
}
|
||||
|
||||
.admonition.warning > .admonition-title {
|
||||
background-color: #f0b37e;
|
||||
}
|
||||
|
||||
.admonition.warning {
|
||||
background-color: #ffedcc;
|
||||
}
|
||||
|
||||
.admonition.note > .admonition-title {
|
||||
background-color: #6ab0de;
|
||||
}
|
||||
|
||||
.admonition.note {
|
||||
background-color: #e7f2fa;
|
||||
}
|
||||
|
||||
.admonition.tip > .admonition-title {
|
||||
background-color: #1abc9c;
|
||||
}
|
||||
|
||||
.admonition.tip {
|
||||
background-color: #dbfaf4;
|
||||
}
|
||||
|
||||
|
||||
/* footnotes */
|
||||
.footnote {
|
||||
padding-left: 0.8em;
|
||||
border-left: 2px solid #ccc;
|
||||
}
|
||||
|
||||
/* Search page */
|
||||
#search-results .category {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#search-results .category:before {
|
||||
content: " ";
|
||||
}
|
||||
|
||||
/* Overriding the <code> block style of highligh.js.
|
||||
* We have to override the padding and the background-color, since we style this
|
||||
* part ourselves. Specifically, we style the <pre> surrounding the <code>, while
|
||||
* highlight.js applies the .hljs style directly to the <code> tag.
|
||||
*/
|
||||
.hljs {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
nav.toc {
|
||||
position: fixed;
|
||||
overflow-y: scroll;
|
||||
width: 16em;
|
||||
left: -16em;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
-webkit-transition-property: left; /* Safari */
|
||||
-webkit-transition-duration: 0.3s; /* Safari */
|
||||
transition-property: left;
|
||||
transition-duration: 0.3s;
|
||||
-webkit-transition-timing-function: ease-out; /* Safari */
|
||||
transition-timing-function: ease-out;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
nav.toc.show {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
article {
|
||||
margin-left: 0;
|
||||
padding: 3em 0.9em 0 0.9em; /* top right bottom left */
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
article > header {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
article > header nav, hr {
|
||||
display: none;
|
||||
}
|
||||
|
||||
article > header div#topbar {
|
||||
display: block; /* is mobile */
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 1.5em;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
background-color: #fcfcfc;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.26);
|
||||
top: 0;
|
||||
-webkit-transition-property: top; /* Safari */
|
||||
-webkit-transition-duration: 0.3s; /* Safari */
|
||||
transition-property: top;
|
||||
transition-duration: 0.3s;
|
||||
}
|
||||
|
||||
article > header div#topbar.headroom--unpinned.headroom--not-top.headroom--not-bottom {
|
||||
top: -4em;
|
||||
-webkit-transition-property: top; /* Safari */
|
||||
-webkit-transition-duration: 0.7s; /* Safari */
|
||||
transition-property: top;
|
||||
transition-duration: 0.7s;
|
||||
}
|
||||
|
||||
article > header div#topbar span {
|
||||
position: fixed;
|
||||
width: 80%;
|
||||
height: 1.5em;
|
||||
margin-top: -0.1em;
|
||||
margin-left: 0.9em;
|
||||
font-size: 1.2em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
article > header div#topbar a.fa-bars {
|
||||
float: right;
|
||||
padding: 0.6em;
|
||||
margin-top: -0.6em;
|
||||
margin-right: 0.3em;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
article > header div#topbar a.fa-bars:visited {
|
||||
color: #3091d1;
|
||||
}
|
||||
|
||||
article table {
|
||||
overflow-x: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
article div.MathJax_Display {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
article span.MathJax {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 320px) {
|
||||
body {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Part of Documenter.jl
|
||||
* https://github.com/JuliaDocs/Documenter.jl
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
requirejs.config({
|
||||
paths: {
|
||||
'jquery': 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min',
|
||||
'jqueryui': 'https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min',
|
||||
'headroom': 'https://cdnjs.cloudflare.com/ajax/libs/headroom/0.9.3/headroom.min',
|
||||
'mathjax': 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS_HTML',
|
||||
'highlight': 'highlightjs/highlight',
|
||||
},
|
||||
shim: {
|
||||
'mathjax' : {
|
||||
exports: "MathJax"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Load MathJax
|
||||
require(['mathjax'], function(MathJax) {
|
||||
MathJax.Hub.Config({
|
||||
"tex2jax": {
|
||||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||||
processEscapes: true
|
||||
}
|
||||
});
|
||||
MathJax.Hub.Config({
|
||||
config: ["MMLorHTML.js"],
|
||||
jax: [
|
||||
"input/TeX",
|
||||
"output/HTML-CSS",
|
||||
"output/NativeMML"
|
||||
],
|
||||
extensions: [
|
||||
"MathMenu.js",
|
||||
"MathZoom.js",
|
||||
"TeX/AMSmath.js",
|
||||
"TeX/AMSsymbols.js",
|
||||
"TeX/autobold.js",
|
||||
"TeX/autoload-all.js"
|
||||
]
|
||||
});
|
||||
MathJax.Hub.Config({
|
||||
TeX: { equationNumbers: { autoNumber: "AMS" } }
|
||||
});
|
||||
})
|
||||
|
||||
require(['jquery', 'highlight'], function($, hljs) {
|
||||
$(document).ready(function() {
|
||||
hljs.initHighlighting();
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// update the version selector with info from the siteinfo.js and ../versions.js files
|
||||
require(['jquery'], function($) {
|
||||
$(document).ready(function() {
|
||||
var version_selector = $("#version-selector");
|
||||
|
||||
// add the current version to the selector based on siteinfo.js, but only if the selector is empty
|
||||
if (typeof DOCUMENTER_CURRENT_VERSION !== 'undefined' && $('#version-selector > option').length == 0) {
|
||||
var option = $("<option value='#' selected='selected'>" + DOCUMENTER_CURRENT_VERSION + "</option>");
|
||||
version_selector.append(option);
|
||||
}
|
||||
|
||||
if (typeof DOC_VERSIONS !== 'undefined') {
|
||||
var existing_versions = $('#version-selector > option');
|
||||
var existing_versions_texts = existing_versions.map(function(i,x){return x.text});
|
||||
DOC_VERSIONS.forEach(function(each) {
|
||||
var version_url = documenterBaseURL + "/../" + each;
|
||||
var existing_id = $.inArray(each, existing_versions_texts);
|
||||
// if not already in the version selector, add it as a new option,
|
||||
// otherwise update the old option with the URL and enable it
|
||||
if (existing_id == -1) {
|
||||
var option = $("<option value='" + version_url + "'>" + each + "</option>");
|
||||
version_selector.append(option);
|
||||
} else {
|
||||
var option = existing_versions[existing_id];
|
||||
option.value = version_url;
|
||||
option.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// only show the version selector if the selector has been populated
|
||||
if ($('#version-selector > option').length > 0) {
|
||||
version_selector.css("visibility", "visible");
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// mobile
|
||||
require(['jquery', 'headroom'], function($, Headroom) {
|
||||
$(document).ready(function() {
|
||||
var navtoc = $("nav.toc");
|
||||
$("nav.toc li.current a.toctext").click(function() {
|
||||
navtoc.toggleClass('show');
|
||||
});
|
||||
$("article > header div#topbar a.fa-bars").click(function(ev) {
|
||||
ev.preventDefault();
|
||||
navtoc.toggleClass('show');
|
||||
if (navtoc.hasClass('show')) {
|
||||
var title = $("article > header div#topbar span").text();
|
||||
$("nav.toc ul li a:contains('" + title + "')").focus();
|
||||
}
|
||||
});
|
||||
$("article#docs").bind('click', function(ev) {
|
||||
if ($(ev.target).is('div#topbar a.fa-bars')) {
|
||||
return;
|
||||
}
|
||||
if (navtoc.hasClass('show')) {
|
||||
navtoc.removeClass('show');
|
||||
}
|
||||
});
|
||||
if ($("article > header div#topbar").css('display') == 'block') {
|
||||
var headroom = new Headroom(document.querySelector("article > header div#topbar"), {"tolerance": {"up": 10, "down": 10}});
|
||||
headroom.init();
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
|
||||
Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
|
||||
|
||||
*/
|
||||
|
||||
.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 0.5em;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
|
||||
/* Base color: saturation 0; */
|
||||
|
||||
.hljs,
|
||||
.hljs-subst {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.hljs-comment {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.hljs-keyword,
|
||||
.hljs-attribute,
|
||||
.hljs-selector-tag,
|
||||
.hljs-meta-keyword,
|
||||
.hljs-doctag,
|
||||
.hljs-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
/* User color: hue: 0 */
|
||||
|
||||
.hljs-type,
|
||||
.hljs-string,
|
||||
.hljs-number,
|
||||
.hljs-selector-id,
|
||||
.hljs-selector-class,
|
||||
.hljs-quote,
|
||||
.hljs-template-tag,
|
||||
.hljs-deletion {
|
||||
color: #880000;
|
||||
}
|
||||
|
||||
.hljs-title,
|
||||
.hljs-section {
|
||||
color: #880000;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.hljs-regexp,
|
||||
.hljs-symbol,
|
||||
.hljs-variable,
|
||||
.hljs-template-variable,
|
||||
.hljs-link,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-pseudo {
|
||||
color: #BC6060;
|
||||
}
|
||||
|
||||
|
||||
/* Language color: hue: 90; */
|
||||
|
||||
.hljs-literal {
|
||||
color: #78A960;
|
||||
}
|
||||
|
||||
.hljs-built_in,
|
||||
.hljs-bullet,
|
||||
.hljs-code,
|
||||
.hljs-addition {
|
||||
color: #397300;
|
||||
}
|
||||
|
||||
|
||||
/* Meta color: hue: 200 */
|
||||
|
||||
.hljs-meta {
|
||||
color: #1f7199;
|
||||
}
|
||||
|
||||
.hljs-meta-string {
|
||||
color: #4d99bf;
|
||||
}
|
||||
|
||||
|
||||
/* Misc effects */
|
||||
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.hljs-strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Part of Documenter.jl
|
||||
* https://github.com/JuliaDocs/Documenter.jl
|
||||
*
|
||||
* License: MIT
|
||||
*/
|
||||
|
||||
// parseUri 1.2.2
|
||||
// (c) Steven Levithan <stevenlevithan.com>
|
||||
// MIT License
|
||||
function parseUri (str) {
|
||||
var o = parseUri.options,
|
||||
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
|
||||
uri = {},
|
||||
i = 14;
|
||||
|
||||
while (i--) uri[o.key[i]] = m[i] || "";
|
||||
|
||||
uri[o.q.name] = {};
|
||||
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
|
||||
if ($1) uri[o.q.name][$1] = $2;
|
||||
});
|
||||
|
||||
return uri;
|
||||
};
|
||||
parseUri.options = {
|
||||
strictMode: false,
|
||||
key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
|
||||
q: {
|
||||
name: "queryKey",
|
||||
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
|
||||
},
|
||||
parser: {
|
||||
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
|
||||
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
|
||||
}
|
||||
};
|
||||
|
||||
requirejs.config({
|
||||
paths: {
|
||||
'jquery': 'https://code.jquery.com/jquery-3.1.0.js?',
|
||||
'lunr': 'https://cdnjs.cloudflare.com/ajax/libs/lunr.js/0.7.1/lunr.min',
|
||||
}
|
||||
});
|
||||
|
||||
var currentScript = document.currentScript;
|
||||
|
||||
require(["jquery", "lunr"], function($, lunr) {
|
||||
var index = lunr(function () {
|
||||
this.ref('location')
|
||||
this.field('title', {boost: 10})
|
||||
this.field('text')
|
||||
})
|
||||
var store = {}
|
||||
|
||||
documenterSearchIndex['docs'].forEach(function(e) {
|
||||
index.add(e)
|
||||
store[e.location] = e
|
||||
})
|
||||
|
||||
$(function(){
|
||||
function update_search(query) {
|
||||
results = index.search(query)
|
||||
$('#search-info').text("Number of results: " + results.length)
|
||||
$('#search-results').empty()
|
||||
results.forEach(function(result) {
|
||||
data = store[result.ref]
|
||||
link = $('<a>')
|
||||
link.text(data.title)
|
||||
link.attr('href', documenterBaseURL+'/'+result.ref)
|
||||
cat = $('<span class="category">('+data.category+')</span>')
|
||||
li = $('<li>').append(link).append(cat)
|
||||
$('#search-results').append(li)
|
||||
})
|
||||
}
|
||||
|
||||
function update_search_box() {
|
||||
query = $('#search-query').val()
|
||||
update_search(query)
|
||||
}
|
||||
|
||||
$('#search-query').keyup(update_search_box)
|
||||
$('#search-query').change(update_search_box)
|
||||
|
||||
search_query = parseUri(window.location).queryKey["q"]
|
||||
if(search_query !== undefined) {
|
||||
$("#search-query").val(search_query)
|
||||
}
|
||||
update_search_box();
|
||||
})
|
||||
})
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user