Skip to content

Instantly share code, notes, and snippets.

@MikeInnes
Created October 31, 2016 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MikeInnes/c2d11b57a58d7f2466b8013b88df1f1c to your computer and use it in GitHub Desktop.
Save MikeInnes/c2d11b57a58d7f2466b8013b88df1f1c to your computer and use it in GitHub Desktop.
This file has been truncated, but you can view the full file.
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Enums
import Core.Intrinsics.box
export Enum, @enum
abstract Enum
Base.convert{T<:Integer}(::Type{T}, x::Enum) = convert(T, box(Int32, x))
Base.write(io::IO, x::Enum) = write(io, Int32(x))
Base.read{T<:Enum}(io::IO, ::Type{T}) = T(read(io, Int32))
# generate code to test whether expr is in the given set of values
function membershiptest(expr, values)
lo, hi = extrema(values)
if length(values) == hi - lo + 1
:($lo <= $expr <= $hi)
elseif length(values) < 20
foldl((x1,x2)->:($x1 || ($expr == $x2)), :($expr == $(values[1])), values[2:end])
else
:($expr in $(Set(values)))
end
end
@noinline enum_argument_error(typename, x) = throw(ArgumentError(string("invalid value for Enum $(typename): $x")))
"""
@enum EnumName EnumValue1[=x] EnumValue2[=y]
Create an [`Enum`](:obj:`Enum`) type with name `EnumName` and enum member values of
`EnumValue1` and `EnumValue2` with optional assigned values of `x` and `y`, respectively.
`EnumName` can be used just like other types and enum member values as regular values, such as
```jldoctest
julia> @enum FRUIT apple=1 orange=2 kiwi=3
julia> f(x::FRUIT) = "I'm a FRUIT with value: \$(Int(x))"
f (generic function with 1 method)
julia> f(apple)
"I'm a FRUIT with value: 1"
```
"""
macro enum(T,syms...)
if isempty(syms)
throw(ArgumentError("no arguments given for Enum $T"))
end
if !isa(T,Symbol)
throw(ArgumentError("invalid type expression for enum $T"))
end
typename = T
vals = Array{Tuple{Symbol,Integer}}(0)
lo = hi = 0
i = Int32(-1)
hasexpr = false
for s in syms
if isa(s,Symbol)
if i == typemax(typeof(i))
throw(ArgumentError("overflow in value \"$s\" of Enum $typename"))
end
i += one(i)
elseif isa(s,Expr) &&
(s.head == :(=) || s.head == :kw) &&
length(s.args) == 2 && isa(s.args[1],Symbol)
i = eval(current_module(),s.args[2]) # allow exprs, e.g. uint128"1"
if !isa(i, Integer)
throw(ArgumentError("invalid value for Enum $typename, $s=$i; values must be integers"))
end
i = convert(Int32, i)
s = s.args[1]
hasexpr = true
else
throw(ArgumentError(string("invalid argument for Enum ", typename, ": ", s)))
end
if !Base.isidentifier(s)
throw(ArgumentError("invalid name for Enum $typename; \"$s\" is not a valid identifier."))
end
push!(vals, (s,i))
if length(vals) == 1
lo = hi = i
else
lo = min(lo, i)
hi = max(hi, i)
end
end
values = Int32[i[2] for i in vals]
if hasexpr && values != unique(values)
throw(ArgumentError("values for Enum $typename are not unique"))
end
blk = quote
# enum definition
Base.@__doc__(bitstype 32 $(esc(T)) <: Enum)
function Base.convert(::Type{$(esc(typename))}, x::Integer)
$(membershiptest(:x, values)) || enum_argument_error($(Expr(:quote, typename)), x)
box($(esc(typename)), convert(Int32, x))
end
Base.typemin(x::Type{$(esc(typename))}) = $(esc(typename))($lo)
Base.typemax(x::Type{$(esc(typename))}) = $(esc(typename))($hi)
Base.isless(x::$(esc(typename)), y::$(esc(typename))) = isless(Int32(x), Int32(y))
let insts = ntuple(i->$(esc(typename))($values[i]), $(length(vals)))
Base.instances(::Type{$(esc(typename))}) = insts
end
function Base.print(io::IO, x::$(esc(typename)))
for (sym, i) in $vals
if i == Int32(x)
print(io, sym); break
end
end
end
function Base.show(io::IO, x::$(esc(typename)))
if get(io, :compact, false)
print(io, x)
else
print(io, x, "::")
showcompact(io, typeof(x))
print(io, " = ", Int(x))
end
end
function Base.show(io::IO, t::Type{$(esc(typename))})
Base.show_datatype(io, t)
end
function Base.show(io::IO, ::MIME"text/plain", t::Type{$(esc(typename))})
print(io, "Enum ")
Base.show_datatype(io, t)
print(io, ":")
for (sym, i) in $vals
print(io, "\n", sym, " = ", i)
end
end
end
if isa(T,Symbol)
for (sym,i) in vals
push!(blk.args, :(const $(esc(sym)) = $(esc(T))($i)))
end
end
push!(blk.args, :nothing)
blk.head = :toplevel
return blk
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
module LineEdit
using ..Terminals
import ..Terminals: raw!, width, height, cmove, getX,
getY, clear_line, beep
import Base: ensureroom, peek, show, AnyDict
abstract TextInterface
abstract ModeState
export run_interface, Prompt, ModalInterface, transition, reset_state, edit_insert, keymap
immutable ModalInterface <: TextInterface
modes
end
type MIState
interface::ModalInterface
current_mode
aborted::Bool
mode_state
kill_buffer::String
previous_key::Array{Char,1}
key_repeats::Int
end
MIState(i, c, a, m) = MIState(i, c, a, m, "", Char[], 0)
function show(io::IO, s::MIState)
print(io, "MI State (", s.current_mode, " active)")
end
type Prompt <: TextInterface
prompt
# A string or function to be printed before the prompt. May not change the length of the prompt.
# This may be used for changing the color, issuing other terminal escape codes, etc.
prompt_prefix
# Same as prefix except after the prompt
prompt_suffix
keymap_dict
keymap_func_data
complete
on_enter
on_done
hist
sticky::Bool
end
show(io::IO, x::Prompt) = show(io, string("Prompt(\"", x.prompt, "\",...)"))
immutable InputAreaState
num_rows::Int64
curs_row::Int64
end
type PromptState <: ModeState
terminal
p::Prompt
input_buffer::IOBuffer
ias::InputAreaState
indent::Int
end
input_string(s::PromptState) = String(s.input_buffer)
input_string_newlines(s::PromptState) = count(c->(c == '\n'), input_string(s))
function input_string_newlines_aftercursor(s::PromptState)
str = input_string(s)
isempty(str) && return 0
rest = str[nextind(str, position(s.input_buffer)):end]
return count(c->(c == '\n'), rest)
end
abstract HistoryProvider
abstract CompletionProvider
type EmptyCompletionProvider <: CompletionProvider
end
type EmptyHistoryProvider <: HistoryProvider
end
reset_state(::EmptyHistoryProvider) = nothing
complete_line(c::EmptyCompletionProvider, s) = [], true, true
terminal(s::IO) = s
terminal(s::PromptState) = s.terminal
for f in [:terminal, :edit_insert, :on_enter, :add_history, :buffer, :edit_backspace, :(Base.isempty),
:replace_line, :refresh_multi_line, :input_string, :edit_move_left, :edit_move_right,
:edit_move_word_left, :edit_move_word_right, :update_display_buffer]
@eval ($f)(s::MIState, args...) = $(f)(s.mode_state[s.current_mode], args...)
end
function common_prefix(completions)
ret = ""
c1 = completions[1]
isempty(c1) && return ret
i = 1
cc, nexti = next(c1, i)
while true
for c in completions
(i > endof(c) || c[i] != cc) && return ret
end
ret = string(ret, cc)
i >= endof(c1) && return ret
i = nexti
cc, nexti = next(c1, i)
end
end
# Show available completions
function show_completions(s::PromptState, completions)
colmax = maximum(map(length, completions))
num_cols = max(div(width(terminal(s)), colmax+2), 1)
entries_per_col, r = divrem(length(completions), num_cols)
entries_per_col += r != 0
# skip any lines of input after the cursor
cmove_down(terminal(s), input_string_newlines_aftercursor(s))
println(terminal(s))
for row = 1:entries_per_col
for col = 0:num_cols
idx = row + col*entries_per_col
if idx <= length(completions)
cmove_col(terminal(s), (colmax+2)*col)
print(terminal(s), completions[idx])
end
end
println(terminal(s))
end
# make space for the prompt
for i = 1:input_string_newlines(s)
println(terminal(s))
end
end
# Prompt Completions
complete_line(s::MIState) = complete_line(s.mode_state[s.current_mode], s.key_repeats)
function complete_line(s::PromptState, repeats)
completions, partial, should_complete = complete_line(s.p.complete, s)
if isempty(completions)
beep(terminal(s))
elseif !should_complete
# should_complete is false for cases where we only want to show
# a list of possible completions but not complete, e.g. foo(\t
show_completions(s, completions)
elseif length(completions) == 1
# Replace word by completion
prev_pos = position(s.input_buffer)
seek(s.input_buffer, prev_pos-sizeof(partial))
edit_replace(s, position(s.input_buffer), prev_pos, completions[1])
else
p = common_prefix(completions)
if !isempty(p) && p != partial
# All possible completions share the same prefix, so we might as
# well complete that
prev_pos = position(s.input_buffer)
seek(s.input_buffer, prev_pos-sizeof(partial))
edit_replace(s, position(s.input_buffer), prev_pos, p)
elseif repeats > 0
show_completions(s, completions)
end
end
end
clear_input_area(terminal, s) = (_clear_input_area(terminal, s.ias); s.ias = InputAreaState(0, 0))
clear_input_area(s) = clear_input_area(s.terminal, s)
function _clear_input_area(terminal, state::InputAreaState)
# Go to the last line
if state.curs_row < state.num_rows
cmove_down(terminal, state.num_rows - state.curs_row)
end
# Clear lines one by one going up
for j = 2:state.num_rows
clear_line(terminal)
cmove_up(terminal)
end
# Clear top line
clear_line(terminal)
end
prompt_string(s::PromptState) = s.p.prompt
prompt_string(s::AbstractString) = s
refresh_multi_line(s::ModeState) = refresh_multi_line(terminal(s), s)
refresh_multi_line(termbuf::TerminalBuffer, s::ModeState) = refresh_multi_line(termbuf, terminal(s), s)
refresh_multi_line(termbuf::TerminalBuffer, term, s::ModeState) = (@assert term == terminal(s); refresh_multi_line(termbuf,s))
function refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal, buf, state::InputAreaState, prompt = ""; indent = 0)
_clear_input_area(termbuf, state)
cols = width(terminal)
curs_row = -1 # relative to prompt (1-based)
curs_pos = -1 # 1-based column position of the cursor
cur_row = 0 # count of the number of rows
buf_pos = position(buf)
line_pos = buf_pos
# Write out the prompt string
write_prompt(termbuf, prompt)
prompt = prompt_string(prompt)
# Count the '\n' at the end of the line if the terminal emulator does (specific to DOS cmd prompt)
miscountnl = @static is_windows() ? (isa(Terminals.pipe_reader(terminal), Base.TTY) && !Base.ispty(Terminals.pipe_reader(terminal))) : false
lindent = strwidth(prompt)
# Now go through the buffer line by line
seek(buf, 0)
moreinput = true # add a blank line if there is a trailing newline on the last line
while moreinput
l = readline(buf)
moreinput = endswith(l, "\n")
# We need to deal with on-screen characters, so use strwidth to compute occupied columns
llength = strwidth(l)
slength = sizeof(l)
cur_row += 1
cmove_col(termbuf, lindent + 1)
write(termbuf, l)
# We expect to be line after the last valid output line (due to
# the '\n' at the end of the previous line)
if curs_row == -1
# in this case, we haven't yet written the cursor position
line_pos -= slength # '\n' gets an extra pos
if line_pos < 0 || !moreinput
num_chars = (line_pos >= 0 ? llength : strwidth(l[1:(line_pos + slength)]))
curs_row, curs_pos = divrem(lindent + num_chars - 1, cols)
curs_row += cur_row
curs_pos += 1
# There's an issue if the cursor is after the very right end of the screen. In that case we need to
# move the cursor to the next line, and emit a newline if needed
if curs_pos == cols
# only emit the newline if the cursor is at the end of the line we're writing
if line_pos == 0
write(termbuf, "\n")
cur_row += 1
end
curs_row += 1
curs_pos = 0
cmove_col(termbuf, 1)
end
end
end
cur_row += div(max(lindent + llength + miscountnl - 1, 0), cols)
lindent = indent
end
seek(buf, buf_pos)
# Let's move the cursor to the right position
# The line first
n = cur_row - curs_row
if n > 0
cmove_up(termbuf, n)
end
#columns are 1 based
cmove_col(termbuf, curs_pos + 1)
# Updated cur_row,curs_row
return InputAreaState(cur_row, curs_row)
end
function refresh_multi_line(terminal::UnixTerminal, args...; kwargs...)
outbuf = IOBuffer()
termbuf = TerminalBuffer(outbuf)
ret = refresh_multi_line(termbuf, terminal, args...;kwargs...)
# Output the entire refresh at once
write(terminal, takebuf_array(outbuf))
flush(terminal)
return ret
end
# Edit functionality
is_non_word_char(c) = c in " \t\n\"\\'`@\$><=:;|&{}()[].,+-*/?%^~"
function reset_key_repeats(f::Function, s::MIState)
key_repeats_sav = s.key_repeats
try
s.key_repeats = 0
f()
finally
s.key_repeats = key_repeats_sav
end
end
char_move_left(s::PromptState) = char_move_left(s.input_buffer)
function char_move_left(buf::IOBuffer)
while position(buf) > 0
seek(buf, position(buf)-1)
c = peek(buf)
(((c & 0x80) == 0) || ((c & 0xc0) == 0xc0)) && break
end
pos = position(buf)
c = read(buf, Char)
seek(buf, pos)
c
end
function edit_move_left(buf::IOBuffer)
if position(buf) > 0
#move to the next base UTF8 character to the left
while true
c = char_move_left(buf)
if charwidth(c) != 0 || c == '\n' || position(buf) == 0
break
end
end
return true
end
return false
end
edit_move_left(s::PromptState) = edit_move_left(s.input_buffer) && refresh_line(s)
function edit_move_word_left(s)
if position(s.input_buffer) > 0
char_move_word_left(s.input_buffer)
refresh_line(s)
end
end
char_move_right(s) = char_move_right(buffer(s))
function char_move_right(buf::IOBuffer)
!eof(buf) && read(buf, Char)
end
function char_move_word_right(buf::IOBuffer, is_delimiter=is_non_word_char)
while !eof(buf) && is_delimiter(char_move_right(buf))
end
while !eof(buf)
pos = position(buf)
if is_delimiter(char_move_right(buf))
seek(buf, pos)
break
end
end
end
function char_move_word_left(buf::IOBuffer, is_delimiter=is_non_word_char)
while position(buf) > 0 && is_delimiter(char_move_left(buf))
end
while position(buf) > 0
pos = position(buf)
if is_delimiter(char_move_left(buf))
seek(buf, pos)
break
end
end
end
char_move_word_right(s) = char_move_word_right(buffer(s))
char_move_word_left(s) = char_move_word_left(buffer(s))
function edit_move_right(buf::IOBuffer)
if !eof(buf)
# move to the next base UTF8 character to the right
while true
c = char_move_right(buf)
eof(buf) && break
pos = position(buf)
nextc = read(buf,Char)
seek(buf,pos)
(charwidth(nextc) != 0 || nextc == '\n') && break
end
return true
end
return false
end
edit_move_right(s::PromptState) = edit_move_right(s.input_buffer) && refresh_line(s)
function edit_move_word_right(s)
if !eof(s.input_buffer)
char_move_word_right(s)
refresh_line(s)
end
end
## Move line up/down
# Querying the terminal is expensive, memory access is cheap
# so to find the current column, we find the offset for the start
# of the line.
function edit_move_up(buf::IOBuffer)
npos = rsearch(buf.data, '\n', position(buf))
npos == 0 && return false # we're in the first line
# We're interested in character count, not byte count
offset = length(String(buf.data[(npos+1):(position(buf))]))
npos2 = rsearch(buf.data, '\n', npos-1)
seek(buf, npos2)
for _ = 1:offset
pos = position(buf)
if read(buf, Char) == '\n'
seek(buf, pos)
break
end
end
return true
end
function edit_move_up(s)
changed = edit_move_up(buffer(s))
changed && refresh_line(s)
changed
end
function edit_move_down(buf::IOBuffer)
npos = rsearch(buf.data[1:buf.size], '\n', position(buf))
# We're interested in character count, not byte count
offset = length(String(buf.data[(npos+1):(position(buf))]))
npos2 = search(buf.data[1:buf.size], '\n', position(buf)+1)
if npos2 == 0 #we're in the last line
return false
end
seek(buf, npos2)
for _ = 1:offset
pos = position(buf)
if eof(buf) || read(buf, Char) == '\n'
seek(buf, pos)
break
end
end
return true
end
function edit_move_down(s)
changed = edit_move_down(buffer(s))
changed && refresh_line(s)
changed
end
# splice! for IOBuffer: convert from 0-indexed positions, update the size,
# and keep the cursor position stable with the text
function splice_buffer!{T<:Integer}(buf::IOBuffer, r::UnitRange{T}, ins::AbstractString = "")
pos = position(buf)
if !isempty(r) && pos in r
seek(buf, first(r))
elseif pos > last(r)
seek(buf, pos - length(r))
end
splice!(buf.data, r .+ 1, ins.data) # position(), etc, are 0-indexed
buf.size = buf.size + sizeof(ins) - length(r)
seek(buf, position(buf) + sizeof(ins))
end
function edit_replace(s, from, to, str)
splice_buffer!(buffer(s), from:to-1, str)
end
function edit_insert(s::PromptState, c)
buf = s.input_buffer
function line_size()
p = position(buf)
seek(buf, rsearch(buf.data, '\n', p))
ls = p - position(buf)
seek(buf, p)
return ls
end
str = string(c)
edit_insert(buf, str)
offset = s.ias.curs_row == 1 ? sizeof(s.p.prompt) : s.indent
if !('\n' in str) && eof(buf) &&
((line_size() + offset + sizeof(str) - 1) < width(terminal(s)))
# Avoid full update when appending characters to the end
# and an update of curs_row isn't necessary (conservatively estimated)
write(terminal(s), str)
else
refresh_line(s)
end
end
function edit_insert(buf::IOBuffer, c)
if eof(buf)
return write(buf, c)
else
s = string(c)
splice_buffer!(buf, position(buf):position(buf)-1, s)
return sizeof(s)
end
end
function edit_backspace(s::PromptState)
if edit_backspace(s.input_buffer)
refresh_line(s)
else
beep(terminal(s))
end
end
function edit_backspace(buf::IOBuffer)
if position(buf) > 0
oldpos = position(buf)
char_move_left(buf)
splice_buffer!(buf, position(buf):oldpos-1)
return true
else
return false
end
end
edit_delete(s) = edit_delete(buffer(s)) ? refresh_line(s) : beep(terminal(s))
function edit_delete(buf::IOBuffer)
eof(buf) && return false
oldpos = position(buf)
char_move_right(buf)
splice_buffer!(buf, oldpos:position(buf)-1)
true
end
function edit_werase(buf::IOBuffer)
pos1 = position(buf)
char_move_word_left(buf, isspace)
pos0 = position(buf)
pos0 < pos1 || return false
splice_buffer!(buf, pos0:pos1-1)
true
end
function edit_werase(s)
edit_werase(buffer(s)) && refresh_line(s)
end
function edit_delete_prev_word(buf::IOBuffer)
pos1 = position(buf)
char_move_word_left(buf)
pos0 = position(buf)
pos0 < pos1 || return false
splice_buffer!(buf, pos0:pos1-1)
true
end
function edit_delete_prev_word(s)
edit_delete_prev_word(buffer(s)) && refresh_line(s)
end
function edit_delete_next_word(buf::IOBuffer)
pos0 = position(buf)
char_move_word_right(buf)
pos1 = position(buf)
pos0 < pos1 || return false
splice_buffer!(buf, pos0:pos1-1)
true
end
function edit_delete_next_word(s)
edit_delete_next_word(buffer(s)) && refresh_line(s)
end
function edit_yank(s::MIState)
edit_insert(buffer(s), s.kill_buffer)
refresh_line(s)
end
function edit_kill_line(s::MIState)
buf = buffer(s)
pos = position(buf)
killbuf = readline(buf)
if length(killbuf) > 1 && killbuf[end] == '\n'
killbuf = killbuf[1:end-1]
char_move_left(buf)
end
s.kill_buffer = s.key_repeats > 0 ? s.kill_buffer * killbuf : killbuf
splice_buffer!(buf, pos:position(buf)-1)
refresh_line(s)
end
edit_transpose(s) = edit_transpose(buffer(s)) && refresh_line(s)
function edit_transpose(buf::IOBuffer)
position(buf) == 0 && return false
eof(buf) && char_move_left(buf)
char_move_left(buf)
pos = position(buf)
a, b = read(buf, Char), read(buf, Char)
seek(buf, pos)
write(buf, b, a)
return true
end
edit_clear(buf::IOBuffer) = truncate(buf, 0)
function edit_clear(s::MIState)
edit_clear(buffer(s))
refresh_line(s)
end
function replace_line(s::PromptState, l::IOBuffer)
s.input_buffer = copy(l)
end
function replace_line(s::PromptState, l)
s.input_buffer.ptr = 1
s.input_buffer.size = 0
write(s.input_buffer, l)
end
history_prev(::EmptyHistoryProvider) = ("", false)
history_next(::EmptyHistoryProvider) = ("", false)
history_search(::EmptyHistoryProvider, args...) = false
add_history(::EmptyHistoryProvider, s) = nothing
add_history(s::PromptState) = add_history(mode(s).hist, s)
history_next_prefix(s, hist, prefix) = false
history_prev_prefix(s, hist, prefix) = false
function history_prev(s, hist)
l, ok = history_prev(mode(s).hist)
if ok
replace_line(s, l)
move_input_start(s)
refresh_line(s)
else
beep(terminal(s))
end
end
function history_next(s, hist)
l, ok = history_next(mode(s).hist)
if ok
replace_line(s, l)
move_input_end(s)
refresh_line(s)
else
beep(terminal(s))
end
end
refresh_line(s) = refresh_multi_line(s)
refresh_line(s, termbuf) = refresh_multi_line(termbuf, s)
default_completion_cb(::IOBuffer) = []
default_enter_cb(_) = true
write_prompt(terminal, s::PromptState) = write_prompt(terminal, s.p)
function write_prompt(terminal, p::Prompt)
prefix = isa(p.prompt_prefix,Function) ? p.prompt_prefix() : p.prompt_prefix
suffix = isa(p.prompt_suffix,Function) ? p.prompt_suffix() : p.prompt_suffix
write(terminal, prefix)
write(terminal, p.prompt)
write(terminal, Base.text_colors[:normal])
write(terminal, suffix)
end
write_prompt(terminal, s::String) = write(terminal, s)
### Keymap Support
normalize_key(key::Char) = string(key)
normalize_key(key::Integer) = normalize_key(Char(key))
function normalize_key(key::AbstractString)
'\0' in key && error("Matching \\0 not currently supported.")
buf = IOBuffer()
i = start(key)
while !done(key, i)
c, i = next(key, i)
if c == '*'
write(buf, '\0')
elseif c == '^'
c, i = next(key, i)
write(buf, uppercase(c)-64)
elseif c == '\\'
c, i = next(key, i)
if c == 'C'
c, i = next(key, i)
@assert c == '-'
c, i = next(key, i)
write(buf, uppercase(c)-64)
elseif c == 'M'
c, i = next(key, i)
@assert c == '-'
c, i = next(key, i)
write(buf, '\e')
write(buf, c)
end
else
write(buf, c)
end
end
return takebuf_string(buf)
end
function normalize_keys(keymap::Dict)
ret = Dict{Any,Any}()
for (k,v) in keymap
normalized = normalize_key(k)
if haskey(ret,normalized)
error("""Multiple spellings of a key in a single keymap
(\"$k\" conflicts with existing mapping)""")
end
ret[normalized] = v
end
return ret
end
function add_nested_key!(keymap::Dict, key, value; override = false)
i = start(key)
while !done(key, i)
c, i = next(key, i)
if c in keys(keymap)
if done(key, i) && override
# isa(keymap[c], Dict) - In this case we're overriding a prefix of an existing command
keymap[c] = value
break
else
if !isa(keymap[c], Dict)
error("Conflicting definitions for keyseq " * escape_string(key) * " within one keymap")
end
end
elseif done(key, i)
keymap[c] = value
break
else
keymap[c] = Dict{Char,Any}()
end
keymap = keymap[c]
end
end
# Redirect a key as if `seq` had been the keysequence instead in a lazy fashion.
# This is different from the default eager redirect, which only looks at the current and lower
# layers of the stack.
immutable KeyAlias
seq::String
KeyAlias(seq) = new(normalize_key(seq))
end
match_input(k::Function, s, term, cs, keymap) = (update_key_repeats(s, cs); return keymap_fcn(k, String(cs)))
match_input(k::Void, s, term, cs, keymap) = (s,p) -> return :ok
match_input(k::KeyAlias, s, term, cs, keymap) = match_input(keymap, s, IOBuffer(k.seq), Char[], keymap)
function match_input(k::Dict, s, term=terminal(s), cs=Char[], keymap = k)
# if we run out of characters to match before resolving an action,
# return an empty keymap function
eof(term) && return keymap_fcn(nothing, "")
c = read(term, Char)
push!(cs, c)
key = haskey(k, c) ? c : '\0'
# if we don't match on the key, look for a default action then fallback on 'nothing' to ignore
return match_input(get(k, key, nothing), s, term, cs, keymap)
end
keymap_fcn(f::Void, c) = (s, p) -> return :ok
function keymap_fcn(f::Function, c)
return function (s, p)
r = f(s, p, c)
if isa(r, Symbol)
return r
else
return :ok
end
end
end
update_key_repeats(s, keystroke) = nothing
function update_key_repeats(s::MIState, keystroke)
s.key_repeats = s.previous_key == keystroke ? s.key_repeats + 1 : 0
s.previous_key = keystroke
return
end
## Conflict fixing
# Consider a keymap of the form
#
# {
# "**" => f
# "ab" => g
# }
#
# Naively this is transformed into a tree as
#
# {
# '*' => {
# '*' => f
# }
# 'a' => {
# 'b' => g
# }
# }
#
# However, that's not what we want, because now "ac" is
# is not defined. We need to fix this up and turn it into
#
# {
# '*' => {
# '*' => f
# }
# 'a' => {
# '*' => f
# 'b' => g
# }
# }
#
# i.e. copy over the appropraite default subdict
#
# deep merge where target has higher precedence
function keymap_merge!(target::Dict, source::Dict)
for k in keys(source)
if !haskey(target, k)
target[k] = source[k]
elseif isa(target[k], Dict)
keymap_merge!(target[k], source[k])
else
# Ignore, target has higher precedence
end
end
end
fixup_keymaps!(d, l, s, sk) = nothing
function fixup_keymaps!(dict::Dict, level, s, subkeymap)
if level > 0
for d in values(dict)
fixup_keymaps!(d, level-1, s, subkeymap)
end
else
if haskey(dict, s)
if isa(dict[s], Dict) && isa(subkeymap, Dict)
keymap_merge!(dict[s], subkeymap)
end
else
dict[s] = deepcopy(subkeymap)
end
end
end
function add_specialisations(dict, subdict, level)
default_branch = subdict['\0']
if isa(default_branch, Dict)
# Go through all the keymaps in the default branch
# and copy them over to dict
for s in keys(default_branch)
s == '\0' && add_specialisations(dict, default_branch, level+1)
fixup_keymaps!(dict, level, s, default_branch[s])
end
end
end
postprocess!(others) = nothing
function postprocess!(dict::Dict)
# needs to be done first for every branch
if haskey(dict, '\0')
add_specialisations(dict, dict, 1)
end
for (k,v) in dict
k == '\0' && continue
postprocess!(v)
end
end
function getEntry(keymap,key)
v = keymap
for c in key
if !haskey(v,c)
return nothing
end
v = v[c]
end
return v
end
# `target` is the total keymap being built up, already being a nested tree of Dicts.
# source is the keymap specified by the user (with normalized keys)
function keymap_merge(target,source)
ret = copy(target)
direct_keys = filter((k,v) -> isa(v, Union{Function, KeyAlias, Void}), source)
# first direct entries
for key in keys(direct_keys)
add_nested_key!(ret, key, source[key]; override = true)
end
# then redirected entries
for key in setdiff(keys(source), keys(direct_keys))
# We first resolve redirects in the source
value = source[key]
visited = Array{Any}(0)
while isa(value, Union{Char,AbstractString})
value = normalize_key(value)
if value in visited
error("Eager redirection cycle detected for key " * escape_string(key))
end
push!(visited,value)
if !haskey(source,value)
break
end
value = source[value]
end
if isa(value, Union{Char,AbstractString})
value = getEntry(ret, value)
if value === nothing
error("Could not find redirected value " * escape_string(source[key]))
end
end
add_nested_key!(ret, key, value; override = true)
end
ret
end
function keymap_unify(keymaps)
ret = Dict{Char,Any}()
for keymap in keymaps
ret = keymap_merge(ret, keymap)
end
postprocess!(ret)
return ret
end
function validate_keymap(keymap)
for key in keys(keymap)
visited_keys = Any[key]
v = getEntry(keymap,key)
while isa(v,KeyAlias)
if v.seq in visited_keys
error("Alias cycle detected in keymap")
end
push!(visited_keys,v.seq)
v = getEntry(keymap,v.seq)
end
end
end
function keymap{D<:Dict}(keymaps::Array{D})
# keymaps is a vector of prioritized keymaps, with highest priority first
ret = keymap_unify(map(normalize_keys, reverse(keymaps)))
validate_keymap(ret)
ret
end
const escape_defaults = merge!(
AnyDict(Char(i) => nothing for i=vcat(1:26, 28:31)), # Ignore control characters by default
AnyDict( # And ignore other escape sequences by default
"\e*" => nothing,
"\e[*" => nothing,
"\eO*" => nothing,
# Also ignore extended escape sequences
# TODO: Support ranges of characters
"\e[1**" => nothing,
"\e[2**" => nothing,
"\e[3**" => nothing,
"\e[4**" => nothing,
"\e[5**" => nothing,
"\e[6**" => nothing,
# less commonly used VT220 editing keys
"\e[2~" => nothing, # insert
"\e[3~" => nothing, # delete
"\e[5~" => nothing, # page up
"\e[6~" => nothing, # page down
# These are different spellings of arrow keys, home keys, etc.
# and should always do the same as the canonical key sequence
"\e[1~" => KeyAlias("\e[H"), # home
"\e[4~" => KeyAlias("\e[F"), # end
"\e[7~" => KeyAlias("\e[H"), # home
"\e[8~" => KeyAlias("\e[F"), # end
"\eOA" => KeyAlias("\e[A"),
"\eOB" => KeyAlias("\e[B"),
"\eOC" => KeyAlias("\e[C"),
"\eOD" => KeyAlias("\e[D"),
"\eOH" => KeyAlias("\e[H"),
"\eOF" => KeyAlias("\e[F"),
),
# set mode commands
AnyDict("\e[$(c)h" => nothing for c in 1:20),
# reset mode commands
AnyDict("\e[$(c)l" => nothing for c in 1:20)
)
function write_response_buffer(s::PromptState, data)
offset = s.input_buffer.ptr
ptr = data.response_buffer.ptr
seek(data.response_buffer, 0)
write(s.input_buffer, readstring(data.response_buffer))
s.input_buffer.ptr = offset + ptr - 2
data.response_buffer.ptr = ptr
refresh_line(s)
end
type SearchState <: ModeState
terminal
histprompt
#rsearch (true) or ssearch (false)
backward::Bool
query_buffer::IOBuffer
response_buffer::IOBuffer
ias::InputAreaState
#The prompt whose input will be replaced by the matched history
parent
SearchState(terminal, histprompt, backward, query_buffer, response_buffer) =
new(terminal, histprompt, backward, query_buffer, response_buffer, InputAreaState(0,0))
end
terminal(s::SearchState) = s.terminal
function update_display_buffer(s::SearchState, data)
history_search(data.histprompt.hp, data.query_buffer, data.response_buffer, data.backward, false) || beep(terminal(s))
refresh_line(s)
end
function history_next_result(s::MIState, data::SearchState)
history_search(data.histprompt.hp, data.query_buffer, data.response_buffer, data.backward, true) || beep(terminal(s))
refresh_line(data)
end
function history_set_backward(s::SearchState, backward)
s.backward = backward
end
input_string(s::SearchState) = String(s.query_buffer)
function reset_state(s::SearchState)
if s.query_buffer.size != 0
s.query_buffer.size = 0
s.query_buffer.ptr = 1
end
if s.response_buffer.size != 0
s.response_buffer.size = 0
s.response_buffer.ptr = 1
end
reset_state(s.histprompt.hp)
end
type HistoryPrompt{T<:HistoryProvider} <: TextInterface
hp::T
complete
keymap_dict::Dict{Char,Any}
HistoryPrompt(hp) = new(hp, EmptyCompletionProvider())
end
HistoryPrompt{T<:HistoryProvider}(hp::T) = HistoryPrompt{T}(hp)
init_state(terminal, p::HistoryPrompt) = SearchState(terminal, p, true, IOBuffer(), IOBuffer())
type PrefixSearchState <: ModeState
terminal
histprompt
prefix::String
response_buffer::IOBuffer
ias::InputAreaState
indent::Int
# The modal interface state, if present
mi
#The prompt whose input will be replaced by the matched history
parent
PrefixSearchState(terminal, histprompt, prefix, response_buffer) =
new(terminal, histprompt, prefix, response_buffer, InputAreaState(0,0), 0)
end
function show(io::IO, s::PrefixSearchState)
print(io, "PrefixSearchState ", isdefined(s,:parent) ?
string("(", s.parent, " active)") : "(no parent)", " for ",
isdefined(s,:mi) ? s.mi : "no MI")
end
refresh_multi_line(termbuf::TerminalBuffer, terminal::UnixTerminal,
s::Union{PromptState,PrefixSearchState}) = s.ias =
refresh_multi_line(termbuf, terminal, buffer(s), s.ias, s, indent = s.indent)
input_string(s::PrefixSearchState) = String(s.response_buffer)
# a meta-prompt that presents itself as parent_prompt, but which has an independent keymap
# for prefix searching
type PrefixHistoryPrompt{T<:HistoryProvider} <: TextInterface
hp::T
parent_prompt::Prompt
complete
keymap_dict::Dict{Char,Any}
PrefixHistoryPrompt(hp, parent_prompt) = new(hp, parent_prompt, EmptyCompletionProvider())
end
PrefixHistoryPrompt{T<:HistoryProvider}(hp::T, parent_prompt) = PrefixHistoryPrompt{T}(hp, parent_prompt)
init_state(terminal, p::PrefixHistoryPrompt) = PrefixSearchState(terminal, p, "", IOBuffer())
write_prompt(terminal, s::PrefixSearchState) = write_prompt(terminal, s.histprompt.parent_prompt)
prompt_string(s::PrefixSearchState) = s.histprompt.parent_prompt.prompt
terminal(s::PrefixSearchState) = s.terminal
function reset_state(s::PrefixSearchState)
if s.response_buffer.size != 0
s.response_buffer.size = 0
s.response_buffer.ptr = 1
end
reset_state(s.histprompt.hp)
end
function transition(f::Function, s::PrefixSearchState, mode)
if isdefined(s, :mi)
transition(s.mi, mode)
end
s.parent = mode
s.histprompt.parent_prompt = mode
if isdefined(s, :mi)
transition(f, s.mi, s.histprompt)
else
f()
end
end
replace_line(s::PrefixSearchState, l::IOBuffer) = s.response_buffer = l
function replace_line(s::PrefixSearchState, l)
s.response_buffer.ptr = 1
s.response_buffer.size = 0
write(s.response_buffer, l)
end
function refresh_multi_line(termbuf::TerminalBuffer, s::SearchState)
buf = IOBuffer()
unsafe_write(buf, pointer(s.query_buffer.data), s.query_buffer.ptr-1)
write(buf, "': ")
offset = buf.ptr
ptr = s.response_buffer.ptr
seek(s.response_buffer, 0)
write(buf, readstring(s.response_buffer))
buf.ptr = offset + ptr - 1
s.response_buffer.ptr = ptr
s.ias = refresh_multi_line(termbuf, s.terminal, buf, s.ias, s.backward ? "(reverse-i-search)`" : "(forward-i-search)`")
end
state(s::MIState, p) = s.mode_state[p]
state(s::PromptState, p) = (@assert s.p == p; s)
mode(s::MIState) = s.current_mode
mode(s::PromptState) = s.p
mode(s::SearchState) = @assert false
mode(s::PrefixSearchState) = s.histprompt.parent_prompt
# Search Mode completions
function complete_line(s::SearchState, repeats)
completions, partial, should_complete = complete_line(s.histprompt.complete, s)
# For now only allow exact completions in search mode
if length(completions) == 1
prev_pos = position(s.query_buffer)
seek(s.query_buffer, prev_pos-sizeof(partial))
edit_replace(s, position(s.query_buffer), prev_pos, completions[1])
end
end
function accept_result(s, p)
parent = state(s, p).parent
transition(s, parent) do
replace_line(state(s, parent), state(s, p).response_buffer)
end
end
function copybuf!(dst::IOBuffer, src::IOBuffer)
n = src.size
ensureroom(dst, n)
copy!(dst.data, 1, src.data, 1, n)
dst.size = src.size
dst.ptr = src.ptr
end
function enter_search(s::MIState, p::HistoryPrompt, backward::Bool)
# a bit of hack to help fix #6325
buf = copy(buffer(s))
parent = mode(s)
p.hp.last_mode = mode(s)
p.hp.last_buffer = buf
transition(s, p) do
ss = state(s, p)
ss.parent = parent
ss.backward = backward
truncate(ss.query_buffer, 0)
copybuf!(ss.response_buffer, buf)
end
end
function enter_prefix_search(s::MIState, p::PrefixHistoryPrompt, backward::Bool)
buf = copy(buffer(s))
parent = mode(s)
transition(s, p) do
pss = state(s, p)
pss.parent = parent
pss.histprompt.parent_prompt = parent
pss.prefix = String(buf.data[1:position(buf)])
copybuf!(pss.response_buffer, buf)
pss.indent = state(s, parent).indent
pss.mi = s
end
pss = state(s, p)
if backward
history_prev_prefix(pss, pss.histprompt.hp, pss.prefix)
else
history_next_prefix(pss, pss.histprompt.hp, pss.prefix)
end
end
function setup_search_keymap(hp)
p = HistoryPrompt(hp)
pkeymap = AnyDict(
"^R" => (s,data,c)->(history_set_backward(data, true); history_next_result(s, data)),
"^S" => (s,data,c)->(history_set_backward(data, false); history_next_result(s, data)),
'\r' => (s,o...)->accept_result(s, p),
'\n' => '\r',
# Limited form of tab completions
'\t' => (s,data,c)->(complete_line(s); update_display_buffer(s, data)),
"^L" => (s,data,c)->(Terminals.clear(terminal(s)); update_display_buffer(s, data)),
# Backspace/^H
'\b' => (s,data,c)->(edit_backspace(data.query_buffer) ?
update_display_buffer(s, data) : beep(terminal(s))),
127 => KeyAlias('\b'),
# Meta Backspace
"\e\b" => (s,data,c)->(edit_delete_prev_word(data.query_buffer) ?
update_display_buffer(s, data) : beep(terminal(s))),
"\e\x7f" => "\e\b",
# Word erase to whitespace
"^W" => (s,data,c)->(edit_werase(data.query_buffer) ?
update_display_buffer(s, data) : beep(terminal(s))),
# ^C and ^D
"^C" => (s,data,c)->(edit_clear(data.query_buffer);
edit_clear(data.response_buffer);
update_display_buffer(s, data);
reset_state(data.histprompt.hp);
transition(s, data.parent)),
"^D" => "^C",
# Other ways to cancel search mode (it's difficult to bind \e itself)
"^G" => "^C",
"\e\e" => "^C",
"^K" => (s,o...)->transition(s, state(s, p).parent),
"^Y" => (s,data,c)->(edit_yank(s); update_display_buffer(s, data)),
"^U" => (s,data,c)->(edit_clear(data.query_buffer);
edit_clear(data.response_buffer);
update_display_buffer(s, data)),
# Right Arrow
"\e[C" => (s,o...)->(accept_result(s, p); edit_move_right(s)),
# Left Arrow
"\e[D" => (s,o...)->(accept_result(s, p); edit_move_left(s)),
# Up Arrow
"\e[A" => (s,o...)->(accept_result(s, p); edit_move_up(s)),
# Down Arrow
"\e[B" => (s,o...)->(accept_result(s, p); edit_move_down(s)),
"^B" => (s,o...)->(accept_result(s, p); edit_move_left(s)),
"^F" => (s,o...)->(accept_result(s, p); edit_move_right(s)),
# Meta B
"\eb" => (s,o...)->(accept_result(s, p); edit_move_word_left(s)),
# Meta F
"\ef" => (s,o...)->(accept_result(s, p); edit_move_word_right(s)),
# Ctrl-Left Arrow
"\e[1;5D" => "\eb",
# Ctrl-Left Arrow on rxvt
"\eOd" => "\eb",
# Ctrl-Right Arrow
"\e[1;5C" => "\ef",
# Ctrl-Right Arrow on rxvt
"\eOc" => "\ef",
"^A" => (s,o...)->(accept_result(s, p); move_line_start(s); refresh_line(s)),
"^E" => (s,o...)->(accept_result(s, p); move_line_end(s); refresh_line(s)),
"^Z" => (s,o...)->(return :suspend),
# Try to catch all Home/End keys
"\e[H" => (s,o...)->(accept_result(s, p); move_input_start(s); refresh_line(s)),
"\e[F" => (s,o...)->(accept_result(s, p); move_input_end(s); refresh_line(s)),
# Use ^N and ^P to change search directions and iterate through results
"^N" => (s,data,c)->(history_set_backward(data, false); history_next_result(s, data)),
"^P" => (s,data,c)->(history_set_backward(data, true); history_next_result(s, data)),
# Bracketed paste mode
"\e[200~" => (s,data,c)-> begin
ps = state(s, mode(s))
input = readuntil(ps.terminal, "\e[201~")[1:(end-6)]
edit_insert(data.query_buffer, input); update_display_buffer(s, data)
end,
"*" => (s,data,c)->(edit_insert(data.query_buffer, c); update_display_buffer(s, data))
)
p.keymap_dict = keymap([pkeymap, escape_defaults])
skeymap = AnyDict(
"^R" => (s,o...)->(enter_search(s, p, true)),
"^S" => (s,o...)->(enter_search(s, p, false)),
)
(p, skeymap)
end
keymap(state, p::Union{HistoryPrompt,PrefixHistoryPrompt}) = p.keymap_dict
keymap_data(state, ::Union{HistoryPrompt, PrefixHistoryPrompt}) = state
Base.isempty(s::PromptState) = s.input_buffer.size == 0
on_enter(s::PromptState) = s.p.on_enter(s)
move_input_start(s) = (seek(buffer(s), 0))
move_input_end(buf::IOBuffer) = seekend(buf)
move_input_end(s) = move_input_end(buffer(s))
function move_line_start(s::MIState)
buf = buffer(s)
curpos = position(buf)
curpos == 0 && return
if s.key_repeats > 0
move_input_start(s)
else
seek(buf, rsearch(buf.data, '\n', curpos))
end
end
function move_line_end(s::MIState)
s.key_repeats > 0 ?
move_input_end(s) :
move_line_end(buffer(s))
end
function move_line_end(buf::IOBuffer)
eof(buf) && return
pos = search(buf.data, '\n', position(buf)+1)
if pos == 0
move_input_end(buf)
return
end
seek(buf, pos-1)
end
function commit_line(s)
move_input_end(s)
refresh_line(s)
println(terminal(s))
add_history(s)
state(s, mode(s)).ias = InputAreaState(0, 0)
end
"""
`Base.LineEdit.tabwidth` controls the presumed tab width of code pasted into the REPL.
You can modify it by doing `eval(Base.LineEdit, :(tabwidth = 4))`, for example.
Must satisfy `0 < tabwidth <= 16`.
"""
global tabwidth = 8
function bracketed_paste(s)
ps = state(s, mode(s))
input = readuntil(ps.terminal, "\e[201~")[1:(end-6)]
input = replace(input, '\r', '\n')
if position(buffer(s)) == 0
indent = Base.indentation(input; tabwidth=tabwidth)[1]
input = Base.unindent(input, indent; tabwidth=tabwidth)
end
return replace(input, '\t', " "^tabwidth)
end
const default_keymap =
AnyDict(
# Tab
'\t' => (s,o...)->begin
buf = buffer(s)
# Yes, we are ignoring the possiblity
# the we could be in the middle of a multi-byte
# sequence, here but that's ok, since any
# whitespace we're interested in is only one byte
i = position(buf)
if i != 0
c = buf.data[i]
if c == UInt8('\n') || c == UInt8('\t') ||
# hack to allow path completion in cmds
# after a space, e.g., `cd <tab>`, while still
# allowing multiple indent levels
(c == UInt8(' ') && i > 3 && buf.data[i-1] == UInt8(' '))
edit_insert(s, " "^4)
return
end
end
complete_line(s)
refresh_line(s)
end,
# Enter
'\r' => (s,o...)->begin
if on_enter(s) || (eof(buffer(s)) && s.key_repeats > 1)
commit_line(s)
return :done
else
edit_insert(s, '\n')
end
end,
'\n' => KeyAlias('\r'),
# Backspace/^H
'\b' => (s,o...)->edit_backspace(s),
127 => KeyAlias('\b'),
# Meta Backspace
"\e\b" => (s,o...)->edit_delete_prev_word(s),
"\e\x7f" => "\e\b",
# ^D
"^D" => (s,o...)->begin
if buffer(s).size > 0
edit_delete(s)
else
println(terminal(s))
return :abort
end
end,
"^B" => (s,o...)->edit_move_left(s),
"^F" => (s,o...)->edit_move_right(s),
# Meta B
"\eb" => (s,o...)->edit_move_word_left(s),
# Meta F
"\ef" => (s,o...)->edit_move_word_right(s),
# Ctrl-Left Arrow
"\e[1;5D" => "\eb",
# Ctrl-Left Arrow on rxvt
"\eOd" => "\eb",
# Ctrl-Right Arrow
"\e[1;5C" => "\ef",
# Ctrl-Right Arrow on rxvt
"\eOc" => "\ef",
# Meta Enter
"\e\r" => (s,o...)->(edit_insert(s, '\n')),
"\e\n" => "\e\r",
# Simply insert it into the buffer by default
"*" => (s,data,c)->(edit_insert(s, c)),
"^U" => (s,o...)->edit_clear(s),
"^K" => (s,o...)->edit_kill_line(s),
"^Y" => (s,o...)->edit_yank(s),
"^A" => (s,o...)->(move_line_start(s); refresh_line(s)),
"^E" => (s,o...)->(move_line_end(s); refresh_line(s)),
# Try to catch all Home/End keys
"\e[H" => (s,o...)->(move_input_start(s); refresh_line(s)),
"\e[F" => (s,o...)->(move_input_end(s); refresh_line(s)),
"^L" => (s,o...)->(Terminals.clear(terminal(s)); refresh_line(s)),
"^W" => (s,o...)->edit_werase(s),
# Meta D
"\ed" => (s,o...)->edit_delete_next_word(s),
"^C" => (s,o...)->begin
try # raise the debugger if present
ccall(:jl_raise_debugger, Int, ())
end
move_input_end(s)
refresh_line(s)
print(terminal(s), "^C\n\n")
transition(s, :reset)
refresh_line(s)
end,
"^Z" => (s,o...)->(return :suspend),
# Right Arrow
"\e[C" => (s,o...)->edit_move_right(s),
# Left Arrow
"\e[D" => (s,o...)->edit_move_left(s),
# Up Arrow
"\e[A" => (s,o...)->edit_move_up(s),
# Down Arrow
"\e[B" => (s,o...)->edit_move_down(s),
# Delete
"\e[3~" => (s,o...)->edit_delete(s),
# Bracketed Paste Mode
"\e[200~" => (s,o...)->begin
input = bracketed_paste(s)
edit_insert(s, input)
end,
"^T" => (s,o...)->edit_transpose(s)
)
const history_keymap = AnyDict(
"^P" => (s,o...)->(history_prev(s, mode(s).hist)),
"^N" => (s,o...)->(history_next(s, mode(s).hist)),
# Up Arrow
"\e[A" => (s,o...)->(edit_move_up(s) || history_prev(s, mode(s).hist)),
# Down Arrow
"\e[B" => (s,o...)->(edit_move_down(s) || history_next(s, mode(s).hist)),
# Page Up
"\e[5~" => (s,o...)->(history_prev(s, mode(s).hist)),
# Page Down
"\e[6~" => (s,o...)->(history_next(s, mode(s).hist))
)
const prefix_history_keymap = merge!(
AnyDict(
# Up Arrow
"\e[A" => (s,data,c)->history_prev_prefix(data, data.histprompt.hp, data.prefix),
# Down Arrow
"\e[B" => (s,data,c)->history_next_prefix(data, data.histprompt.hp, data.prefix),
# by default, pass thru to the parent mode
"*" => (s,data,c)->begin
accept_result(s, data.histprompt);
ps = state(s, mode(s))
map = keymap(ps, mode(s))
match_input(map, s, IOBuffer(c))(s, keymap_data(ps, mode(s)))
end,
# match escape sequences for pass thru
"\e*" => "*",
"\e[*" => "*",
"\eO*" => "*",
"\e[1;5*" => "*", # Ctrl-Arrow
"\e[200~" => "*"
),
# VT220 editing commands
AnyDict("\e[$(n)~" => "*" for n in 1:8),
# set mode commands
AnyDict("\e[$(c)h" => "*" for c in 1:20),
# reset mode commands
AnyDict("\e[$(c)l" => "*" for c in 1:20)
)
function setup_prefix_keymap(hp, parent_prompt)
p = PrefixHistoryPrompt(hp, parent_prompt)
p.keymap_dict = keymap([prefix_history_keymap])
pkeymap = AnyDict(
# Up Arrow
"\e[A" => (s,o...)->(edit_move_up(s) || enter_prefix_search(s, p, true)),
# Down Arrow
"\e[B" => (s,o...)->(edit_move_down(s) || enter_prefix_search(s, p, false)),
)
(p, pkeymap)
end
function deactivate(p::TextInterface, s::ModeState, termbuf, term::TextTerminal)
clear_input_area(termbuf, s)
s
end
function activate(p::TextInterface, s::ModeState, termbuf, term::TextTerminal)
s.ias = InputAreaState(0, 0)
refresh_line(s, termbuf)
end
function activate(p::TextInterface, s::MIState, termbuf, term::TextTerminal)
@assert p == s.current_mode
activate(p, s.mode_state[s.current_mode], termbuf, term)
end
activate(m::ModalInterface, s::MIState, termbuf, term::TextTerminal) =
activate(s.current_mode, s, termbuf, term)
commit_changes(t::UnixTerminal, termbuf) = write(t, takebuf_array(termbuf.out_stream))
function transition(f::Function, s::MIState, mode)
if mode === :abort
s.aborted = true
return
end
if mode === :reset
reset_state(s)
return
end
if !haskey(s.mode_state,mode)
s.mode_state[mode] = init_state(terminal(s), mode)
end
termbuf = TerminalBuffer(IOBuffer())
t = terminal(s)
s.mode_state[s.current_mode] = deactivate(s.current_mode, s.mode_state[s.current_mode], termbuf, t)
s.current_mode = mode
f()
activate(mode, s.mode_state[mode], termbuf, t)
commit_changes(t, termbuf)
end
transition(s::MIState, mode) = transition((args...)->nothing, s, mode)
function reset_state(s::PromptState)
if s.input_buffer.size != 0
s.input_buffer.size = 0
s.input_buffer.ptr = 1
end
s.ias = InputAreaState(0, 0)
end
function reset_state(s::MIState)
for (mode,state) in s.mode_state
reset_state(state)
end
end
const default_keymap_dict = keymap([default_keymap, escape_defaults])
function Prompt(prompt;
prompt_prefix = "",
prompt_suffix = "",
keymap_dict = default_keymap_dict,
keymap_func_data = nothing,
complete = EmptyCompletionProvider(),
on_enter = default_enter_cb,
on_done = ()->nothing,
hist = EmptyHistoryProvider(),
sticky = false)
Prompt(prompt, prompt_prefix, prompt_suffix, keymap_dict, keymap_func_data,
complete, on_enter, on_done, hist, sticky)
end
run_interface(::Prompt) = nothing
init_state(terminal, prompt::Prompt) = PromptState(terminal, prompt, IOBuffer(), InputAreaState(1, 1), #=indent(spaces)=#strwidth(prompt.prompt))
function init_state(terminal, m::ModalInterface)
s = MIState(m, m.modes[1], false, Dict{Any,Any}())
for mode in m.modes
s.mode_state[mode] = init_state(terminal, mode)
end
s
end
function run_interface(terminal, m::ModalInterface)
s::MIState = init_state(terminal, m)
while !s.aborted
p = s.current_mode
buf, ok, suspend = prompt!(terminal, m, s)
while suspend
@static if is_unix(); ccall(:jl_repl_raise_sigtstp, Cint, ()); end
buf, ok, suspend = prompt!(terminal, m, s)
end
mode(state(s, s.current_mode)).on_done(s, buf, ok)
end
end
buffer(s::PromptState) = s.input_buffer
buffer(s::SearchState) = s.query_buffer
buffer(s::PrefixSearchState) = s.response_buffer
keymap(s::PromptState, prompt::Prompt) = prompt.keymap_dict
keymap_data(s::PromptState, prompt::Prompt) = prompt.keymap_func_data
keymap(ms::MIState, m::ModalInterface) = keymap(ms.mode_state[ms.current_mode], ms.current_mode)
keymap_data(ms::MIState, m::ModalInterface) = keymap_data(ms.mode_state[ms.current_mode], ms.current_mode)
function prompt!(term, prompt, s = init_state(term, prompt))
Base.reseteof(term)
raw!(term, true)
enable_bracketed_paste(term)
try
activate(prompt, s, term, term)
while true
map = keymap(s, prompt)
fcn = match_input(map, s)
# errors in keymaps shouldn't cause the REPL to fail, so wrap in a
# try/catch block
local state
try
state = fcn(s, keymap_data(s, prompt))
catch e
warn("Caught an exception in the keymap:")
warn(e)
state = :done
end
if state === :abort
return buffer(s), false, false
elseif state === :done
return buffer(s), true, false
elseif state === :suspend
if is_unix()
return buffer(s), true, true
end
else
@assert state === :ok
end
end
finally
raw!(term, false) && disable_bracketed_paste(term)
end
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
module REPL
using Base.Meta
using ..Terminals
using ..LineEdit
using ..REPLCompletions
export
BasicREPL,
LineEditREPL,
StreamREPL
import Base:
Display,
display,
show,
AnyDict,
==
import ..LineEdit:
CompletionProvider,
HistoryProvider,
add_history,
complete_line,
history_next,
history_next_prefix,
history_prev,
history_prev_prefix,
history_search,
accept_result,
terminal
abstract AbstractREPL
answer_color(::AbstractREPL) = ""
const JULIA_PROMPT = "julia> "
type REPLBackend
"channel for AST"
repl_channel::Channel
"channel for results: (value, nothing) or (error, backtrace)"
response_channel::Channel
"flag indicating the state of this backend"
in_eval::Bool
"current backend task"
backend_task::Task
REPLBackend(repl_channel, response_channel, in_eval) =
new(repl_channel, response_channel, in_eval)
end
function eval_user_input(ast::ANY, backend::REPLBackend)
iserr, lasterr = false, ((), nothing)
Base.sigatomic_begin()
while true
try
Base.sigatomic_end()
if iserr
put!(backend.response_channel, lasterr)
iserr, lasterr = false, ()
else
backend.in_eval = true
value = eval(Main, ast)
backend.in_eval = false
# note: value wrapped in a closure to ensure it doesn't get passed through expand
eval(Main, Expr(:(=), :ans, Expr(:call, ()->value)))
put!(backend.response_channel, (value, nothing))
end
break
catch err
if iserr
println("SYSTEM ERROR: Failed to report error to REPL frontend")
println(err)
end
iserr, lasterr = true, (err, catch_backtrace())
end
end
Base.sigatomic_end()
end
function start_repl_backend(repl_channel::Channel, response_channel::Channel)
backend = REPLBackend(repl_channel, response_channel, false)
backend.backend_task = @schedule begin
# include looks at this to determine the relative include path
# nothing means cwd
while true
tls = task_local_storage()
tls[:SOURCE_PATH] = nothing
ast, show_value = take!(backend.repl_channel)
if show_value == -1
# exit flag
break
end
eval_user_input(ast, backend)
end
end
backend
end
function ip_matches_func(ip, func::Symbol)
for fr in StackTraces.lookup(ip)
if fr === StackTraces.UNKNOWN || fr.from_c
return false
end
fr.func === func && return true
end
return false
end
function display_error(io::IO, er, bt)
Base.with_output_color(:red, io) do io
print(io, "ERROR: ")
# remove REPL-related frames from interactive printing
eval_ind = findlast(addr->ip_matches_func(addr, :eval), bt)
if eval_ind != 0
bt = bt[1:eval_ind-1]
end
Base.showerror(io, er, bt)
end
end
immutable REPLDisplay{R<:AbstractREPL} <: Display
repl::R
end
==(a::REPLDisplay, b::REPLDisplay) = a.repl === b.repl
function display(d::REPLDisplay, mime::MIME"text/plain", x)
io = outstream(d.repl)
Base.have_color && write(io, answer_color(d.repl))
show(IOContext(io, :limit => true), mime, x)
println(io)
end
display(d::REPLDisplay, x) = display(d, MIME("text/plain"), x)
function print_response(repl::AbstractREPL, val::ANY, bt, show_value::Bool, have_color::Bool)
repl.waserror = bt !== nothing
print_response(outstream(repl), val, bt, show_value, have_color, specialdisplay(repl))
end
function print_response(errio::IO, val::ANY, bt, show_value::Bool, have_color::Bool, specialdisplay=nothing)
Base.sigatomic_begin()
while true
try
Base.sigatomic_end()
if bt !== nothing
display_error(errio, val, bt)
println(errio)
iserr, lasterr = false, ()
else
if val !== nothing && show_value
try
if specialdisplay === nothing
display(val)
else
display(specialdisplay,val)
end
catch err
println(errio, "Error showing value of type ", typeof(val), ":")
rethrow(err)
end
end
end
break
catch err
if bt !== nothing
println(errio, "SYSTEM: show(lasterr) caused an error")
break
end
val = err
bt = catch_backtrace()
end
end
Base.sigatomic_end()
end
# A reference to a backend
immutable REPLBackendRef
repl_channel::Channel
response_channel::Channel
end
function run_repl(repl::AbstractREPL, consumer = x->nothing)
repl_channel = Channel(1)
response_channel = Channel(1)
backend = start_repl_backend(repl_channel, response_channel)
consumer(backend)
run_frontend(repl, REPLBackendRef(repl_channel,response_channel))
return backend
end
## BasicREPL ##
type BasicREPL <: AbstractREPL
terminal::TextTerminal
waserror::Bool
BasicREPL(t) = new(t,false)
end
outstream(r::BasicREPL) = r.terminal
function run_frontend(repl::BasicREPL, backend::REPLBackendRef)
d = REPLDisplay(repl)
dopushdisplay = !in(d,Base.Multimedia.displays)
dopushdisplay && pushdisplay(d)
repl_channel, response_channel = backend.repl_channel, backend.response_channel
hit_eof = false
while true
Base.reseteof(repl.terminal)
write(repl.terminal, JULIA_PROMPT)
line = ""
ast = nothing
interrupted = false
while true
try
line *= readline(repl.terminal)
catch e
if isa(e,InterruptException)
try # raise the debugger if present
ccall(:jl_raise_debugger, Int, ())
end
line = ""
interrupted = true
break
elseif isa(e,EOFError)
hit_eof = true
break
else
rethrow()
end
end
ast = Base.parse_input_line(line)
(isa(ast,Expr) && ast.head == :incomplete) || break
end
if !isempty(line)
put!(repl_channel, (ast, 1))
val, bt = take!(response_channel)
if !ends_with_semicolon(line)
print_response(repl, val, bt, true, false)
end
end
write(repl.terminal, '\n')
((!interrupted && isempty(line)) || hit_eof) && break
end
# terminate backend
put!(repl_channel, (nothing, -1))
dopushdisplay && popdisplay(d)
end
## LineEditREPL ##
type LineEditREPL <: AbstractREPL
t::TextTerminal
hascolor::Bool
prompt_color::String
input_color::String
answer_color::String
shell_color::String
help_color::String
history_file::Bool
in_shell::Bool
in_help::Bool
envcolors::Bool
waserror::Bool
specialdisplay
interface
backendref::REPLBackendRef
LineEditREPL(t,hascolor,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell,in_help,envcolors) =
new(t,true,prompt_color,input_color,answer_color,shell_color,help_color,history_file,in_shell,
in_help,envcolors,false,nothing)
end
outstream(r::LineEditREPL) = r.t
specialdisplay(r::LineEditREPL) = r.specialdisplay
specialdisplay(r::AbstractREPL) = nothing
terminal(r::LineEditREPL) = r.t
LineEditREPL(t::TextTerminal, envcolors = false) = LineEditREPL(t,
true,
julia_green,
Base.input_color(),
Base.answer_color(),
Base.text_colors[:red],
Base.text_colors[:yellow],
false, false, false, envcolors)
type REPLCompletionProvider <: CompletionProvider
r::LineEditREPL
end
type ShellCompletionProvider <: CompletionProvider
r::LineEditREPL
end
immutable LatexCompletions <: CompletionProvider; end
beforecursor(buf::IOBuffer) = String(buf.data[1:buf.ptr-1])
function complete_line(c::REPLCompletionProvider, s)
partial = beforecursor(s.input_buffer)
full = LineEdit.input_string(s)
ret, range, should_complete = completions(full, endof(partial))
return ret, partial[range], should_complete
end
function complete_line(c::ShellCompletionProvider, s)
# First parse everything up to the current position
partial = beforecursor(s.input_buffer)
full = LineEdit.input_string(s)
ret, range, should_complete = shell_completions(full, endof(partial))
return ret, partial[range], should_complete
end
function complete_line(c::LatexCompletions, s)
partial = beforecursor(LineEdit.buffer(s))
full = LineEdit.input_string(s)
ret, range, should_complete = bslash_completions(full, endof(partial))[2]
return ret, partial[range], should_complete
end
type REPLHistoryProvider <: HistoryProvider
history::Array{String,1}
history_file
start_idx::Int
cur_idx::Int
last_idx::Int
last_buffer::IOBuffer
last_mode
mode_mapping
modes::Array{Symbol,1}
end
REPLHistoryProvider(mode_mapping) =
REPLHistoryProvider(String[], nothing, 0, 0, -1, IOBuffer(),
nothing, mode_mapping, UInt8[])
invalid_history_message(path::String) = """
Invalid history file ($path) format:
If you have a history file left over from an older version of Julia,
try renaming or deleting it.
Invalid character: """
munged_history_message(path::String) = """
Invalid history file ($path) format:
An editor may have converted tabs to spaces at line """
function hist_getline(file)
while !eof(file)
line = readline(file)
isempty(line) && return line
line[1] in "\r\n" || return line
end
return ""
end
function hist_from_file(hp, file, path)
hp.history_file = file
seek(file, 0)
countlines = 0
while true
mode = :julia
line = hist_getline(file)
isempty(line) && break
countlines += 1
line[1] != '#' &&
error(invalid_history_message(path), repr(line[1]), " at line ", countlines)
while !isempty(line)
m = match(r"^#\s*(\w+)\s*:\s*(.*?)\s*$", line)
m === nothing && break
if m.captures[1] == "mode"
mode = Symbol(m.captures[2])
end
line = hist_getline(file)
countlines += 1
end
isempty(line) && break
# Make sure starts with tab
line[1] == ' ' &&
error(munged_history_message(path), countlines)
line[1] != '\t' &&
error(invalid_history_message(path), repr(line[1]), " at line ", countlines)
lines = String[]
while !isempty(line)
push!(lines, chomp(line[2:end]))
eof(file) && break
ch = Char(Base.peek(file))
ch == ' ' && error(munged_history_message(path), countlines)
ch != '\t' && break
line = hist_getline(file)
countlines += 1
end
push!(hp.modes, mode)
push!(hp.history, join(lines, '\n'))
end
seekend(file)
hp.start_idx = length(hp.history)
hp
end
function mode_idx(hist::REPLHistoryProvider, mode)
c = :julia
for (k,v) in hist.mode_mapping
isequal(v, mode) && (c = k)
end
return c
end
function add_history(hist::REPLHistoryProvider, s)
str = rstrip(String(s.input_buffer))
isempty(strip(str)) && return
mode = mode_idx(hist, LineEdit.mode(s))
!isempty(hist.history) &&
isequal(mode, hist.modes[end]) && str == hist.history[end] && return
push!(hist.modes, mode)
push!(hist.history, str)
hist.history_file === nothing && return
entry = """
# time: $(Libc.strftime("%Y-%m-%d %H:%M:%S %Z", time()))
# mode: $mode
$(replace(str, r"^"ms, "\t"))
"""
# TODO: write-lock history file
seekend(hist.history_file)
print(hist.history_file, entry)
flush(hist.history_file)
end
function history_move(s::Union{LineEdit.MIState,LineEdit.PrefixSearchState}, hist::REPLHistoryProvider, idx::Int, save_idx::Int = hist.cur_idx)
max_idx = length(hist.history) + 1
@assert 1 <= hist.cur_idx <= max_idx
(1 <= idx <= max_idx) || return :none
idx != hist.cur_idx || return :none
# save the current line
if save_idx == max_idx
hist.last_mode = LineEdit.mode(s)
hist.last_buffer = copy(LineEdit.buffer(s))
else
hist.history[save_idx] = LineEdit.input_string(s)
hist.modes[save_idx] = mode_idx(hist, LineEdit.mode(s))
end
# load the saved line
if idx == max_idx
last_buffer = hist.last_buffer
LineEdit.transition(s, hist.last_mode) do
LineEdit.replace_line(s, last_buffer)
end
hist.last_mode = nothing
hist.last_buffer = IOBuffer()
else
if haskey(hist.mode_mapping, hist.modes[idx])
LineEdit.transition(s, hist.mode_mapping[hist.modes[idx]]) do
LineEdit.replace_line(s, hist.history[idx])
end
else
return :skip
end
end
hist.cur_idx = idx
return :ok
end
# Modified version of accept_result that also transitions modes
function LineEdit.accept_result(s, p::LineEdit.HistoryPrompt{REPLHistoryProvider})
parent = LineEdit.state(s, p).parent
hist = p.hp
if 1 <= hist.cur_idx <= length(hist.modes)
m = hist.mode_mapping[hist.modes[hist.cur_idx]]
LineEdit.transition(s, m) do
LineEdit.replace_line(LineEdit.state(s, m), LineEdit.state(s, p).response_buffer)
end
else
LineEdit.transition(s, parent)
end
end
function history_prev(s::LineEdit.MIState, hist::REPLHistoryProvider,
save_idx::Int = hist.cur_idx)
hist.last_idx = -1
m = history_move(s, hist, hist.cur_idx-1, save_idx)
if m === :ok
LineEdit.move_input_start(s)
LineEdit.reset_key_repeats(s) do
LineEdit.move_line_end(s)
end
LineEdit.refresh_line(s)
elseif m === :skip
hist.cur_idx -= 1
history_prev(s, hist, save_idx)
else
Terminals.beep(LineEdit.terminal(s))
end
end
function history_next(s::LineEdit.MIState, hist::REPLHistoryProvider,
save_idx::Int = hist.cur_idx)
cur_idx = hist.cur_idx
max_idx = length(hist.history) + 1
if cur_idx == max_idx && 0 < hist.last_idx
# issue #6312
cur_idx = hist.last_idx
hist.last_idx = -1
end
m = history_move(s, hist, cur_idx+1, save_idx)
if m === :ok
LineEdit.move_input_end(s)
LineEdit.refresh_line(s)
elseif m === :skip
hist.cur_idx += 1
history_next(s, hist, save_idx)
else
Terminals.beep(LineEdit.terminal(s))
end
end
function history_move_prefix(s::LineEdit.PrefixSearchState,
hist::REPLHistoryProvider,
prefix::AbstractString,
backwards::Bool,
cur_idx = hist.cur_idx)
cur_response = String(LineEdit.buffer(s))
# when searching forward, start at last_idx
if !backwards && hist.last_idx > 0
cur_idx = hist.last_idx
end
hist.last_idx = -1
max_idx = length(hist.history)+1
idxs = backwards ? ((cur_idx-1):-1:1) : ((cur_idx+1):max_idx)
for idx in idxs
if (idx == max_idx) || (startswith(hist.history[idx], prefix) && (hist.history[idx] != cur_response || hist.modes[idx] != LineEdit.mode(s)))
m = history_move(s, hist, idx)
if m === :ok
if idx == max_idx
# on resuming the in-progress edit, leave the cursor where the user last had it
elseif isempty(prefix)
# on empty prefix search, move cursor to the end
LineEdit.move_input_end(s)
else
# otherwise, keep cursor at the prefix position as a visual cue
seek(LineEdit.buffer(s), sizeof(prefix))
end
LineEdit.refresh_line(s)
return :ok
elseif m === :skip
return history_move_prefix(s,hist,prefix,backwards,idx)
end
end
end
Terminals.beep(LineEdit.terminal(s))
end
history_next_prefix(s::LineEdit.PrefixSearchState, hist::REPLHistoryProvider, prefix::AbstractString) =
history_move_prefix(s, hist, prefix, false)
history_prev_prefix(s::LineEdit.PrefixSearchState, hist::REPLHistoryProvider, prefix::AbstractString) =
history_move_prefix(s, hist, prefix, true)
function history_search(hist::REPLHistoryProvider, query_buffer::IOBuffer, response_buffer::IOBuffer,
backwards::Bool=false, skip_current::Bool=false)
qpos = position(query_buffer)
qpos > 0 || return true
searchdata = beforecursor(query_buffer)
response_str = String(response_buffer)
# Alright, first try to see if the current match still works
a = position(response_buffer) + 1
b = min(endof(response_str), prevind(response_str, a + sizeof(searchdata)))
!skip_current && searchdata == response_str[a:b] && return true
searchfunc, searchstart, skipfunc = backwards ? (rsearch, b, prevind) :
(search, a, nextind)
skip_current && (searchstart = skipfunc(response_str, searchstart))
# Start searching
# First the current response buffer
if 1 <= searchstart <= endof(response_str)
match = searchfunc(response_str, searchdata, searchstart)
if match != 0:-1
seek(response_buffer, prevind(response_str, first(match)))
return true
end
end
# Now search all the other buffers
idxs = backwards ? ((hist.cur_idx-1):-1:1) : ((hist.cur_idx+1):length(hist.history))
for idx in idxs
h = hist.history[idx]
match = searchfunc(h, searchdata)
if match != 0:-1 && h != response_str && haskey(hist.mode_mapping, hist.modes[idx])
truncate(response_buffer, 0)
write(response_buffer, h)
seek(response_buffer, prevind(h, first(match)))
hist.cur_idx = idx
return true
end
end
return false
end
function history_reset_state(hist::REPLHistoryProvider)
if hist.cur_idx != length(hist.history) + 1
hist.last_idx = hist.cur_idx
hist.cur_idx = length(hist.history) + 1
end
end
LineEdit.reset_state(hist::REPLHistoryProvider) = history_reset_state(hist)
const julia_green = "\033[1m\033[32m"
function return_callback(s)
ast = Base.syntax_deprecation_warnings(false) do
Base.parse_input_line(String(LineEdit.buffer(s)))
end
if !isa(ast, Expr) || (ast.head != :continue && ast.head != :incomplete)
return true
else
return false
end
end
function find_hist_file()
filename = ".julia_history"
if isfile(filename)
return filename
elseif haskey(ENV, "JULIA_HISTORY")
return ENV["JULIA_HISTORY"]
else
return joinpath(homedir(), filename)
end
end
backend(r::AbstractREPL) = r.backendref
send_to_backend(ast, backend::REPLBackendRef) = send_to_backend(ast, backend.repl_channel, backend.response_channel)
function send_to_backend(ast, req, rep)
put!(req, (ast, 1))
val, bt = take!(rep)
end
function respond(f, repl, main; pass_empty = false)
(s,buf,ok)->begin
if !ok
return transition(s, :abort)
end
line = takebuf_string(buf)
if !isempty(line) || pass_empty
reset(repl)
val, bt = send_to_backend(f(line), backend(repl))
if !ends_with_semicolon(line) || bt !== nothing
print_response(repl, val, bt, true, Base.have_color)
end
end
prepare_next(repl)
reset_state(s)
s.current_mode.sticky || transition(s, main)
end
end
function reset(repl::LineEditREPL)
raw!(repl.t, false)
print(repl.t,Base.text_colors[:normal])
end
function prepare_next(repl::LineEditREPL)
println(terminal(repl))
end
function mode_keymap(julia_prompt)
AnyDict(
'\b' => function (s,o...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
buf = copy(LineEdit.buffer(s))
transition(s, julia_prompt) do
LineEdit.state(s, julia_prompt).input_buffer = buf
end
else
LineEdit.edit_backspace(s)
end
end,
"^C" => function (s,o...)
LineEdit.move_input_end(s)
LineEdit.refresh_line(s)
print(LineEdit.terminal(s), "^C\n\n")
transition(s, julia_prompt)
transition(s, :reset)
LineEdit.refresh_line(s)
end)
end
repl_filename(repl, hp::REPLHistoryProvider) = "REPL[$(length(hp.history)-hp.start_idx)]"
repl_filename(repl, hp) = "REPL"
const JL_PROMT_PASTE = Ref(true)
enable_promtpaste(v::Bool) = JL_PROMT_PASTE[] = v
function setup_interface(repl::LineEditREPL; hascolor = repl.hascolor, extra_repl_keymap = Dict{Any,Any}[])
###
#
# This function returns the main interface that describes the REPL
# functionality, it is called internally by functions that setup a
# Terminal-based REPL frontend, but if you want to customize your REPL
# or embed the REPL in another interface, you may call this function
# directly and append it to your interface.
#
# Usage:
#
# repl_channel,response_channel = Channel(),Channel()
# start_repl_backend(repl_channel, response_channel)
# setup_interface(REPLDisplay(t),repl_channel,response_channel)
#
###
###
# We setup the interface in two stages.
# First, we set up all components (prompt,rsearch,shell,help)
# Second, we create keymaps with appropriate transitions between them
# and assign them to the components
#
###
############################### Stage I ################################
# This will provide completions for REPL and help mode
replc = REPLCompletionProvider(repl)
# Set up the main Julia prompt
julia_prompt = Prompt(JULIA_PROMPT;
# Copy colors from the prompt object
prompt_prefix = hascolor ? repl.prompt_color : "",
prompt_suffix = hascolor ?
(repl.envcolors ? Base.input_color : repl.input_color) : "",
keymap_func_data = repl,
complete = replc,
on_enter = return_callback)
# Setup help mode
help_mode = Prompt("help?> ",
prompt_prefix = hascolor ? repl.help_color : "",
prompt_suffix = hascolor ?
(repl.envcolors ? Base.input_color : repl.input_color) : "",
keymap_func_data = repl,
complete = replc,
# When we're done transform the entered line into a call to help("$line")
on_done = respond(Docs.helpmode, repl, julia_prompt))
# Set up shell mode
shell_mode = Prompt("shell> ";
prompt_prefix = hascolor ? repl.shell_color : "",
prompt_suffix = hascolor ?
(repl.envcolors ? Base.input_color : repl.input_color) : "",
keymap_func_data = repl,
complete = ShellCompletionProvider(repl),
# Transform "foo bar baz" into `foo bar baz` (shell quoting)
# and pass into Base.repl_cmd for processing (handles `ls` and `cd`
# special)
on_done = respond(repl, julia_prompt) do line
Expr(:call, :(Base.repl_cmd), macroexpand(Expr(:macrocall, Symbol("@cmd"),line)), outstream(repl))
end)
################################# Stage II #############################
# Setup history
# We will have a unified history for all REPL modes
hp = REPLHistoryProvider(Dict{Symbol,Any}(:julia => julia_prompt,
:shell => shell_mode,
:help => help_mode))
if repl.history_file
try
hist_path = find_hist_file()
f = open(hist_path, true, true, true, false, false)
finalizer(replc, replc->close(f))
hist_from_file(hp, f, hist_path)
catch e
print_response(repl, e, catch_backtrace(), true, Base.have_color)
println(outstream(repl))
info("Disabling history file for this session.")
repl.history_file = false
end
end
history_reset_state(hp)
julia_prompt.hist = hp
shell_mode.hist = hp
help_mode.hist = hp
julia_prompt.on_done = respond(x->Base.parse_input_line(x,filename=repl_filename(repl,hp)), repl, julia_prompt)
search_prompt, skeymap = LineEdit.setup_search_keymap(hp)
search_prompt.complete = LatexCompletions()
# Canonicalize user keymap input
if isa(extra_repl_keymap, Dict)
extra_repl_keymap = [extra_repl_keymap]
end
const repl_keymap = AnyDict(
';' => function (s,o...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
buf = copy(LineEdit.buffer(s))
transition(s, shell_mode) do
LineEdit.state(s, shell_mode).input_buffer = buf
end
else
edit_insert(s, ';')
end
end,
'?' => function (s,o...)
if isempty(s) || position(LineEdit.buffer(s)) == 0
buf = copy(LineEdit.buffer(s))
transition(s, help_mode) do
LineEdit.state(s, help_mode).input_buffer = buf
end
else
edit_insert(s, '?')
end
end,
# Bracketed Paste Mode
"\e[200~" => (s,o...)->begin
input = LineEdit.bracketed_paste(s) # read directly from s until reaching the end-bracketed-paste marker
sbuffer = LineEdit.buffer(s)
curspos = position(sbuffer)
seek(sbuffer, 0)
shouldeval = (nb_available(sbuffer) == curspos && search(sbuffer, UInt8('\n')) == 0)
seek(sbuffer, curspos)
if curspos == 0
# if pasting at the beginning, strip leading whitespace
input = lstrip(input)
end
if !shouldeval
# when pasting in the middle of input, just paste in place
# don't try to execute all the WIP, since that's rather confusing
# and is often ill-defined how it should behave
edit_insert(s, input)
return
end
edit_insert(sbuffer, input)
input = takebuf_string(sbuffer)
oldpos = start(input)
firstline = true
isprompt_paste = false
while !done(input, oldpos) # loop until all lines have been executed
if JL_PROMT_PASTE[]
# Check if the next statement starts with "julia> ", in that case
# skip it. But first skip whitespace
while input[oldpos] in ('\n', ' ', '\t')
oldpos = nextind(input, oldpos)
oldpos >= sizeof(input) && return
end
# Check if input line starts with "julia> ", remove it if we are in prompt paste mode
jl_prompt_len = 7
if (firstline || isprompt_paste) && (oldpos + jl_prompt_len <= sizeof(input) && input[oldpos:oldpos+jl_prompt_len-1] == JULIA_PROMPT)
isprompt_paste = true
oldpos += jl_prompt_len
# If we are prompt pasting and current statement does not begin with julia> , skip to next line
elseif isprompt_paste
while input[oldpos] != '\n'
oldpos = nextind(input, oldpos)
oldpos >= sizeof(input) && return
end
continue
end
end
ast, pos = Base.syntax_deprecation_warnings(false) do
Base.parse(input, oldpos, raise=false)
end
if (isa(ast, Expr) && (ast.head == :error || ast.head == :continue || ast.head == :incomplete)) ||
(done(input, pos) && !endswith(input, '\n'))
# remaining text is incomplete (an error, or parser ran to the end but didn't stop with a newline):
# Insert all the remaining text as one line (might be empty)
tail = input[oldpos:end]
if !firstline
# strip leading whitespace, but only if it was the result of executing something
# (avoids modifying the user's current leading wip line)
tail = lstrip(tail)
end
LineEdit.replace_line(s, tail)
LineEdit.refresh_line(s)
break
end
# get the line and strip leading and trailing whitespace
line = strip(input[oldpos:prevind(input, pos)])
if !isempty(line)
# put the line on the screen and history
LineEdit.replace_line(s, line)
LineEdit.commit_line(s)
# execute the statement
terminal = LineEdit.terminal(s) # This is slightly ugly but ok for now
raw!(terminal, false) && disable_bracketed_paste(terminal)
LineEdit.mode(s).on_done(s, LineEdit.buffer(s), true)
raw!(terminal, true) && enable_bracketed_paste(terminal)
end
oldpos = pos
firstline = false
end
end,
)
prefix_prompt, prefix_keymap = LineEdit.setup_prefix_keymap(hp, julia_prompt)
a = Dict{Any,Any}[skeymap, repl_keymap, prefix_keymap, LineEdit.history_keymap, LineEdit.default_keymap, LineEdit.escape_defaults]
prepend!(a, extra_repl_keymap)
julia_prompt.keymap_dict = LineEdit.keymap(a)
mk = mode_keymap(julia_prompt)
b = Dict{Any,Any}[skeymap, mk, prefix_keymap, LineEdit.history_keymap, LineEdit.default_keymap, LineEdit.escape_defaults]
prepend!(b, extra_repl_keymap)
shell_mode.keymap_dict = help_mode.keymap_dict = LineEdit.keymap(b)
ModalInterface([julia_prompt, shell_mode, help_mode, search_prompt, prefix_prompt])
end
function run_frontend(repl::LineEditREPL, backend)
d = REPLDisplay(repl)
dopushdisplay = repl.specialdisplay === nothing && !in(d,Base.Multimedia.displays)
dopushdisplay && pushdisplay(d)
if !isdefined(repl,:interface)
interface = repl.interface = setup_interface(repl)
else
interface = repl.interface
end
repl.backendref = backend
run_interface(repl.t, interface)
dopushdisplay && popdisplay(d)
end
if isdefined(Base, :banner_color)
banner(io, t) = banner(io, hascolor(t))
banner(io, x::Bool) = print(io, x ? Base.banner_color : Base.banner_plain)
else
banner(io,t) = Base.banner(io)
end
## StreamREPL ##
type StreamREPL <: AbstractREPL
stream::IO
prompt_color::String
input_color::String
answer_color::String
waserror::Bool
StreamREPL(stream,pc,ic,ac) = new(stream,pc,ic,ac,false)
end
StreamREPL(stream::IO) = StreamREPL(stream, julia_green, Base.input_color(), Base.answer_color())
run_repl(stream::IO) = run_repl(StreamREPL(stream))
outstream(s::StreamREPL) = s.stream
answer_color(r::LineEditREPL) = r.envcolors ? Base.answer_color() : r.answer_color
answer_color(r::StreamREPL) = r.answer_color
input_color(r::LineEditREPL) = r.envcolors ? Base.input_color() : r.input_color
input_color(r::StreamREPL) = r.input_color
function ends_with_semicolon(line)
match = rsearch(line, ';')
if match != 0
for c in line[(match+1):end]
isspace(c) || return c == '#'
end
return true
end
return false
end
function run_frontend(repl::StreamREPL, backend::REPLBackendRef)
have_color = Base.have_color
banner(repl.stream, have_color)
d = REPLDisplay(repl)
dopushdisplay = !in(d,Base.Multimedia.displays)
dopushdisplay && pushdisplay(d)
repl_channel, response_channel = backend.repl_channel, backend.response_channel
while !eof(repl.stream)
if have_color
print(repl.stream,repl.prompt_color)
end
print(repl.stream, "julia> ")
if have_color
print(repl.stream, input_color(repl))
end
line = readline(repl.stream)
if !isempty(line)
ast = Base.parse_input_line(line)
if have_color
print(repl.stream, Base.color_normal)
end
put!(repl_channel, (ast, 1))
val, bt = take!(response_channel)
if !ends_with_semicolon(line)
print_response(repl, val, bt, true, have_color)
end
end
end
# Terminate Backend
put!(repl_channel, (nothing, -1))
dopushdisplay && popdisplay(d)
end
function start_repl_server(port)
listen(port) do server, status
client = accept(server)
run_repl(client)
end
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
module REPLCompletions
export completions, shell_completions, bslash_completions
using Base.Meta
function completes_global(x, name)
return startswith(x, name) && !('#' in x)
end
function filtered_mod_names(ffunc::Function, mod::Module, name::AbstractString, all::Bool=false, imported::Bool=false)
ssyms = names(mod, all, imported)
filter!(ffunc, ssyms)
syms = String[string(s) for s in ssyms]
filter!(x->completes_global(x, name), syms)
end
# REPL Symbol Completions
function complete_symbol(sym, ffunc)
# Maybe be smarter in the future
context_module = Main
mod = context_module
name = sym
lookup_module = true
t = Union{}
if rsearch(sym, non_identifier_chars) < rsearch(sym, '.')
# Find module
lookup_name, name = rsplit(sym, ".", limit=2)
ex = Base.syntax_deprecation_warnings(false) do
parse(lookup_name, raise=false)
end
b, found = get_value(ex, context_module)
if found
if isa(b, Module)
mod = b
lookup_module = true
elseif Base.isstructtype(typeof(b))
lookup_module = false
t = typeof(b)
end
else # If the value is not found using get_value, the expression contain an advanced expression
lookup_module = false
t, found = get_type(ex, context_module)
end
found || return String[]
# Ensure REPLCompletion do not crash when asked to complete a tuple, #15329
!lookup_module && t <: Tuple && return String[]
end
suggestions = String[]
if lookup_module
# We will exclude the results that the user does not want, as well
# as excluding Main.Main.Main, etc., because that's most likely not what
# the user wants
p = s->(!Base.isdeprecated(mod, s) && s != module_name(mod) && ffunc(mod, s))
# Looking for a binding in a module
if mod == context_module
# Also look in modules we got through `using`
mods = ccall(:jl_module_usings, Any, (Any,), Main)
for m in mods
append!(suggestions, filtered_mod_names(p, m, name))
end
append!(suggestions, filtered_mod_names(p, mod, name, true, true))
else
append!(suggestions, filtered_mod_names(p, mod, name, true, false))
end
else
# Looking for a member of a type
fields = fieldnames(t)
for field in fields
s = string(field)
if startswith(s, name)
push!(suggestions, s)
end
end
end
suggestions
end
function complete_keyword(s::String)
const sorted_keywords = [
"abstract", "baremodule", "begin", "bitstype", "break", "catch", "ccall",
"const", "continue", "do", "else", "elseif", "end", "export", "false",
"finally", "for", "function", "global", "if", "immutable", "import",
"importall", "let", "local", "macro", "module", "quote", "return",
"true", "try", "type", "typealias", "using", "while"]
r = searchsorted(sorted_keywords, s)
i = first(r)
n = length(sorted_keywords)
while i <= n && startswith(sorted_keywords[i],s)
r = first(r):i
i += 1
end
sorted_keywords[r]
end
function complete_path(path::AbstractString, pos; use_envpath=false)
if Base.is_unix() && ismatch(r"^~(?:/|$)", path)
# if the path is just "~", don't consider the expanded username as a prefix
if path == "~"
dir, prefix = homedir(), ""
else
dir, prefix = splitdir(homedir() * path[2:end])
end
else
dir, prefix = splitdir(path)
end
local files
try
if isempty(dir)
files = readdir()
elseif isdir(dir)
files = readdir(dir)
else
return String[], 0:-1, false
end
catch
return String[], 0:-1, false
end
matches = Set{String}()
for file in files
if startswith(file, prefix)
id = try isdir(joinpath(dir, file)) catch; false end
# joinpath is not used because windows needs to complete with double-backslash
push!(matches, id ? file * (@static is_windows() ? "\\\\" : "/") : file)
end
end
if use_envpath && length(dir) == 0
# Look for files in PATH as well
local pathdirs = split(ENV["PATH"], @static is_windows() ? ";" : ":")
for pathdir in pathdirs
local actualpath
try
actualpath = realpath(pathdir)
catch
# Bash doesn't expect every folder in PATH to exist, so neither shall we
continue
end
if actualpath != pathdir && in(actualpath,pathdirs)
# Remove paths which (after resolving links) are in the env path twice.
# Many distros eg. point /bin to /usr/bin but have both in the env path.
continue
end
local filesinpath
try
filesinpath = readdir(pathdir)
catch e
# Bash allows dirs in PATH that can't be read, so we should as well.
if isa(e, SystemError)
continue
else
# We only handle SystemErrors here
rethrow(e)
end
end
for file in filesinpath
# In a perfect world, we would filter on whether the file is executable
# here, or even on whether the current user can execute the file in question.
if startswith(file, prefix) && isfile(joinpath(pathdir, file))
push!(matches, file)
end
end
end
end
matchList = String[replace(s, r"\s", "\\ ") for s in matches]
startpos = pos - endof(prefix) + 1 - length(matchall(r" ", prefix))
# The pos - endof(prefix) + 1 is correct due to `endof(prefix)-endof(prefix)==0`,
# hence we need to add one to get the first index. This is also correct when considering
# pos, because pos is the `endof` a larger string which `endswith(path)==true`.
return matchList, startpos:pos, !isempty(matchList)
end
# Determines whether method_complete should be tried. It should only be done if
# the string endswiths ',' or '(' when disregarding whitespace_chars
function should_method_complete(s::AbstractString)
method_complete = false
for c in reverse(s)
if c in [',', '(']
method_complete = true
break
elseif !(c in whitespace_chars)
method_complete = false
break
end
end
method_complete
end
# Returns a range that includes the method name in front of the first non
# closed start brace from the end of the string.
function find_start_brace(s::AbstractString; c_start='(', c_end=')')
braces = 0
r = RevString(s)
i = start(r)
in_single_quotes = false
in_double_quotes = false
in_back_ticks = false
while !done(r, i)
c, i = next(r, i)
if !in_single_quotes && !in_double_quotes && !in_back_ticks
if c == c_start
braces += 1
elseif c == c_end
braces -= 1
elseif c == '\''
in_single_quotes = true
elseif c == '"'
in_double_quotes = true
elseif c == '`'
in_back_ticks = true
end
else
if !in_back_ticks && !in_double_quotes && c == '\'' && !done(r, i) && next(r, i)[1]!='\\'
in_single_quotes = !in_single_quotes
elseif !in_back_ticks && !in_single_quotes && c == '"' && !done(r, i) && next(r, i)[1]!='\\'
in_double_quotes = !in_double_quotes
elseif !in_single_quotes && !in_double_quotes && c == '`' && !done(r, i) && next(r, i)[1]!='\\'
in_back_ticks = !in_back_ticks
end
end
braces == 1 && break
end
braces != 1 && return 0:-1, -1
method_name_end = reverseind(r, i)
startind = nextind(s, rsearch(s, non_identifier_chars, method_name_end))
return (startind:endof(s), method_name_end)
end
# Returns the value in a expression if sym is defined in current namespace fn.
# This method is used to iterate to the value of a expression like:
# :(Base.REPLCompletions.whitespace_chars) a `dump` of this expression
# will show it consist of Expr, QuoteNode's and Symbol's which all needs to
# be handled differently to iterate down to get the value of whitespace_chars.
function get_value(sym::Expr, fn)
sym.head != :. && return (nothing, false)
for ex in sym.args
fn, found = get_value(ex, fn)
!found && return (nothing, false)
end
return (fn, true)
end
get_value(sym::Symbol, fn) = isdefined(fn, sym) ? (getfield(fn, sym), true) : (nothing, false)
get_value(sym::QuoteNode, fn) = isdefined(fn, sym.value) ? (getfield(fn, sym.value), true) : (nothing, false)
get_value(sym, fn) = (sym, true)
# Return the value of a getfield call expression
function get_value_getfield(ex::Expr, fn)
# Example :((top(getfield))(Base,:max))
val, found = get_value_getfield(ex.args[2],fn) #Look up Base in Main and returns the module
found || return (nothing, false)
return get_value_getfield(ex.args[3], val) #Look up max in Base and returns the function if found.
end
get_value_getfield(sym, fn) = get_value(sym, fn)
# Determines the return type with Base.return_types of a function call using the type information of the arguments.
function get_type_call(expr::Expr)
f_name = expr.args[1]
# The if statement should find the f function. How f is found depends on how f is referenced
if isa(f_name, GlobalRef) && isconst(f_name.mod,f_name.name) && isdefined(f_name.mod,f_name.name)
ft = typeof(eval(f_name))
found = true
else
ft, found = get_type(f_name, Main)
end
found || return (Any, false) # If the function f is not found return Any.
args = Any[]
for ex in expr.args[2:end] # Find the type of the function arguments
typ, found = get_type(ex, Main)
found ? push!(args, typ) : push!(args, Any)
end
# use _methods_by_ftype as the function is supplied as a type
mt = Base._methods_by_ftype(Tuple{ft, args...}, -1)
length(mt) == 1 || return (Any, false)
m = first(mt)
# Typeinference
params = Core.Inference.InferenceParams()
return_type = Core.Inference.typeinf_type(m[3], m[1], m[2], true, params)
return_type === nothing && return (Any, false)
return (return_type, true)
end
# Returns the return type. example: get_type(:(Base.strip("",' ')),Main) returns (String,true)
function get_type(sym::Expr, fn)
sym=expand(sym)
val, found = get_value(sym, fn)
found && return Base.typesof(val).parameters[1], found
if sym.head === :call
# getfield call is special cased as the evaluation of getfield provides good type information,
# is inexpensive and it is also performed in the complete_symbol function.
a1 = sym.args[1]
if isa(a1,GlobalRef) && isconst(a1.mod,a1.name) && isdefined(a1.mod,a1.name) &&
eval(a1) === Core.getfield
val, found = get_value_getfield(sym, Main)
return found ? Base.typesof(val).parameters[1] : Any, found
end
return get_type_call(sym)
end
return (Any, false)
end
function get_type(sym, fn)
val, found = get_value(sym, fn)
return found ? Base.typesof(val).parameters[1] : Any, found
end
# Method completion on function call expression that look like :(max(1))
function complete_methods(ex_org::Expr)
args_ex = DataType[]
func, found = get_value(ex_org.args[1], Main)
!found && return String[]
for ex in ex_org.args[2:end]
val, found = get_type(ex, Main)
push!(args_ex, val)
end
out = String[]
t_in = Tuple{Core.Typeof(func), args_ex...} # Input types
na = length(args_ex)+1
ml = methods(func)
kwtype = isdefined(ml.mt, :kwsorter) ? Nullable{DataType}(typeof(ml.mt.kwsorter)) : Nullable{DataType}()
io = IOBuffer()
for method in ml
# Check if the method's type signature intersects the input types
if typeintersect(Tuple{method.sig.parameters[1 : min(na, end)]...}, t_in) != Union{}
show(io, method, kwtype=kwtype)
push!(out, takebuf_string(io))
end
end
return out
end
include("latex_symbols.jl")
include("emoji_symbols.jl")
const non_identifier_chars = [" \t\n\r\"\\'`\$><=:;|&{}()[],+-*/?%^~"...]
const whitespace_chars = [" \t\n\r"...]
# "\"'`"... is added to whitespace_chars as non of the bslash_completions
# characters contain any of these characters. It prohibits the
# bslash_completions function to try and complete on escaped characters in strings
const bslash_separators = [whitespace_chars..., "\"'`"...]
# Aux function to detect whether we're right after a
# using or import keyword
function afterusing(string::String, startpos::Int)
(isempty(string) || startpos == 0) && return false
str = string[1:prevind(string,startpos)]
isempty(str) && return false
rstr = reverse(str)
r = search(rstr, r"\s(gnisu|tropmi)\b")
isempty(r) && return false
fr = reverseind(str, last(r))
return ismatch(r"^\b(using|import)\s*(\w+\s*,\s*)*\w*$", str[fr:end])
end
function bslash_completions(string, pos)
slashpos = rsearch(string, '\\', pos)
if (rsearch(string, bslash_separators, pos) < slashpos &&
!(1 < slashpos && (string[prevind(string, slashpos)]=='\\')))
# latex / emoji symbol substitution
s = string[slashpos:pos]
latex = get(latex_symbols, s, "")
if !isempty(latex) # complete an exact match
return (true, ([latex], slashpos:pos, true))
end
emoji = get(emoji_symbols, s, "")
if !isempty(emoji)
return (true, ([emoji], slashpos:pos, true))
end
# return possible matches; these cannot be mixed with regular
# Julian completions as only latex / emoji symbols contain the leading \
if startswith(s, "\\:") # emoji
emoji_names = Iterators.filter(k -> startswith(k, s), keys(emoji_symbols))
return (true, (sort!(collect(emoji_names)), slashpos:pos, true))
else # latex
latex_names = Iterators.filter(k -> startswith(k, s), keys(latex_symbols))
return (true, (sort!(collect(latex_names)), slashpos:pos, true))
end
end
return (false, (String[], 0:-1, false))
end
function dict_identifier_key(str,tag)
if tag === :string
str_close = str*"\""
elseif tag === :cmd
str_close = str*"`"
else
str_close = str
end
frange, end_of_indentifier = find_start_brace(str_close, c_start='[', c_end=']')
isempty(frange) && return (nothing, nothing, nothing)
obj = Main
for name in split(str[frange[1]:end_of_indentifier], '.')
Base.isidentifier(name) || return (nothing, nothing, nothing)
sym = Symbol(name)
isdefined(obj, sym) || return (nothing, nothing, nothing)
obj = getfield(obj, sym)
# Avoid `isdefined(::Array, ::Symbol)`
isa(obj, Array) && return (nothing, nothing, nothing)
end
begin_of_key = findnext(x->!in(x,whitespace_chars), str, end_of_indentifier+2)
begin_of_key==0 && return (true, nothing, nothing)
partial_key = str[begin_of_key:end]
(isa(obj, Associative) && length(obj) < 1e6) || return (true, nothing, nothing)
return (obj, partial_key, begin_of_key)
end
function completions(string, pos)
# First parse everything up to the current position
partial = string[1:pos]
inc_tag = Base.syntax_deprecation_warnings(false) do
Base.incomplete_tag(parse(partial, raise=false))
end
# if completing a key in a Dict
identifier, partial_key, loc = dict_identifier_key(partial,inc_tag)
if identifier !== nothing
if partial_key !== nothing
matches = []
for key in keys(identifier)
rkey = repr(key)
startswith(rkey,partial_key) && push!(matches,rkey)
end
length(matches)==1 && (length(string) <= pos || string[pos+1] != ']') && (matches[1]*="]")
length(matches)>0 && return sort(matches), loc:pos, true
else
return String[], 0:-1, false
end
end
# otherwise...
if inc_tag in [:cmd, :string]
m = match(r"[\t\n\r\"'`@\$><=;|&\{]| (?!\\)", reverse(partial))
startpos = nextind(partial, reverseind(partial, m.offset))
r = startpos:pos
paths, r, success = complete_path(replace(string[r], r"\\ ", " "), pos)
if inc_tag == :string &&
length(paths) == 1 && # Only close if there's a single choice,
!isdir(expanduser(replace(string[startpos:start(r)-1] * paths[1], r"\\ ", " "))) && # except if it's a directory
(length(string) <= pos || string[pos+1] != '"') # or there's already a " at the cursor.
paths[1] *= "\""
end
#Latex symbols can be completed for strings
(success || inc_tag==:cmd) && return sort(paths), r, success
end
ok, ret = bslash_completions(string, pos)
ok && return ret
# Make sure that only bslash_completions is working on strings
inc_tag==:string && return String[], 0:-1, false
if inc_tag == :other && should_method_complete(partial)
frange, method_name_end = find_start_brace(partial)
ex = Base.syntax_deprecation_warnings(false) do
parse(partial[frange] * ")", raise=false)
end
if isa(ex, Expr) && ex.head==:call
return complete_methods(ex), start(frange):method_name_end, false
end
elseif inc_tag == :comment
return String[], 0:-1, false
end
dotpos = rsearch(string, '.', pos)
startpos = nextind(string, rsearch(string, non_identifier_chars, pos))
ffunc = (mod,x)->true
suggestions = String[]
comp_keywords = true
if afterusing(string, startpos)
# We're right after using or import. Let's look only for packages
# and modules we can reach from here
# If there's no dot, we're in toplevel, so we should
# also search for packages
s = string[startpos:pos]
if dotpos <= startpos
for dir in [Pkg.dir(); LOAD_PATH; pwd()]
isdir(dir) || continue
for pname in readdir(dir)
if pname[1] != '.' && pname != "METADATA" &&
pname != "REQUIRE" && startswith(pname, s)
# Valid file paths are
# <Mod>.jl
# <Mod>/src/<Mod>.jl
# <Mod>.jl/src/<Mod>.jl
if isfile(joinpath(dir, pname))
endswith(pname, ".jl") && push!(suggestions, pname[1:end-3])
else
mod_name = if endswith(pname, ".jl")
pname[1:end - 3]
else
pname
end
if isfile(joinpath(dir, pname, "src",
"$mod_name.jl"))
push!(suggestions, mod_name)
end
end
end
end
end
end
ffunc = (mod,x)->(isdefined(mod, x) && isa(getfield(mod, x), Module))
comp_keywords = false
end
startpos == 0 && (pos = -1)
dotpos < startpos && (dotpos = startpos - 1)
s = string[startpos:pos]
comp_keywords && append!(suggestions, complete_keyword(s))
# The case where dot and start pos is equal could look like: "(""*"").d","". or CompletionFoo.test_y_array[1].y
# This case can be handled by finding the begining of the expresion. This is done bellow.
if dotpos == startpos
i = prevind(string, startpos)
while 0 < i
c = string[i]
if c in [')', ']']
if c==')'
c_start='('; c_end=')'
elseif c==']'
c_start='['; c_end=']'
end
frange, end_of_indentifier = find_start_brace(string[1:prevind(string, i)], c_start=c_start, c_end=c_end)
startpos = start(frange)
i = prevind(string, startpos)
elseif c in ["\'\"\`"...]
s = "$c$c"*string[startpos:pos]
break
else
break
end
s = string[startpos:pos]
end
end
append!(suggestions, complete_symbol(s, ffunc))
return sort(unique(suggestions)), (dotpos+1):pos, true
end
function shell_completions(string, pos)
# First parse everything up to the current position
scs = string[1:pos]
local args, last_parse
try
args, last_parse = Base.shell_parse(scs, true)
catch
return String[], 0:-1, false
end
# Now look at the last thing we parsed
isempty(args.args[end].args) && return String[], 0:-1, false
arg = args.args[end].args[end]
if all(s -> isa(s, AbstractString), args.args[end].args)
# Treat this as a path
# As Base.shell_parse throws away trailing spaces (unless they are escaped),
# we need to special case here.
# If the last char was a space, but shell_parse ignored it search on "".
ignore_last_word = arg != " " && scs[end] == ' '
prefix = ignore_last_word ? "" : join(args.args[end].args)
# Also try looking into the env path if the user wants to complete the first argument
use_envpath = !ignore_last_word && length(args.args) < 2
return complete_path(prefix, pos, use_envpath=use_envpath)
elseif isexpr(arg, :escape) && (isexpr(arg.args[1], :incomplete) || isexpr(arg.args[1], :error))
r = first(last_parse):prevind(last_parse, last(last_parse))
partial = scs[r]
ret, range = completions(partial, endof(partial))
range += first(r) - 1
return ret, range, true
end
return String[], 0:-1, false
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Terminals
export
TextTerminal,
UnixTerminal,
TerminalBuffer,
TTYTerminal,
cmove,
cmove_col,
cmove_down,
cmove_left,
cmove_line_down,
cmove_line_up,
cmove_right,
cmove_up,
disable_bracketed_paste,
enable_bracketed_paste,
end_keypad_transmit_mode,
getX,
getY,
hascolor,
pos,
raw!
import Base:
check_open, # stream.jl
displaysize,
flush,
pipe_reader,
pipe_writer,
read,
readuntil
## TextTerminal ##
abstract TextTerminal <: Base.AbstractPipe
# INTERFACE
pipe_reader(::TextTerminal) = error("Unimplemented")
pipe_writer(::TextTerminal) = error("Unimplemented")
displaysize(::TextTerminal) = error("Unimplemented")
cmove(t::TextTerminal, x, y) = error("Unimplemented")
getX(t::TextTerminal) = error("Unimplemented")
getY(t::TextTerminal) = error("Unimplemented")
pos(t::TextTerminal) = (getX(t), getY(t))
# Relative moves (Absolute position fallbacks)
cmove_up(t::TextTerminal, n) = cmove(getX(t), max(1, getY(t)-n))
cmove_up(t) = cmove_up(t, 1)
cmove_down(t::TextTerminal, n) = cmove(getX(t), max(height(t), getY(t)+n))
cmove_down(t) = cmove_down(t, 1)
cmove_left(t::TextTerminal, n) = cmove(max(1, getX(t)-n), getY(t))
cmove_left(t) = cmove_left(t, 1)
cmove_right(t::TextTerminal, n) = cmove(max(width(t), getX(t)+n), getY(t))
cmove_right(t) = cmove_right(t, 1)
cmove_line_up(t::TextTerminal, n) = cmove(1, max(1, getY(t)-n))
cmove_line_up(t) = cmove_line_up(t, 1)
cmove_line_down(t::TextTerminal, n) = cmove(1, max(height(t), getY(t)+n))
cmove_line_down(t) = cmove_line_down(t, 1)
cmove_col(t::TextTerminal, c) = cmove(c, getY(t))
# Defaults
hascolor(::TextTerminal) = false
# Utility Functions
width(t::TextTerminal) = displaysize(t)[2]
height(t::TextTerminal) = displaysize(t)[1]
# For terminals with buffers
flush(t::TextTerminal) = nothing
clear(t::TextTerminal) = error("Unimplemented")
clear_line(t::TextTerminal, row) = error("Unimplemented")
clear_line(t::TextTerminal) = error("Unimplemented")
raw!(t::TextTerminal, raw::Bool) = error("Unimplemented")
beep(t::TextTerminal) = nothing
enable_bracketed_paste(t::TextTerminal) = nothing
disable_bracketed_paste(t::TextTerminal) = nothing
## UnixTerminal ##
abstract UnixTerminal <: TextTerminal
pipe_reader(t::UnixTerminal) = t.in_stream
pipe_writer(t::UnixTerminal) = t.out_stream
type TerminalBuffer <: UnixTerminal
out_stream::Base.IO
end
type TTYTerminal <: UnixTerminal
term_type::String
in_stream::Base.TTY
out_stream::Base.TTY
err_stream::Base.TTY
end
const CSI = "\x1b["
cmove_up(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)A")
cmove_down(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)B")
cmove_right(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)C")
cmove_left(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)D")
cmove_line_up(t::UnixTerminal, n) = (cmove_up(t, n); cmove_col(t, 0))
cmove_line_down(t::UnixTerminal, n) = (cmove_down(t, n); cmove_col(t, 0))
cmove_col(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)G")
if is_windows()
function raw!(t::TTYTerminal,raw::Bool)
check_open(t.in_stream)
if Base.ispty(t.in_stream)
run(if raw
`stty raw -echo onlcr -ocrnl opost`
else
`stty sane`
end,t.in_stream,t.out_stream,t.err_stream)
true
else
ccall(:jl_tty_set_mode,
Int32, (Ptr{Void},Int32),
t.in_stream.handle, raw) != -1
end
end
else
function raw!(t::TTYTerminal, raw::Bool)
check_open(t.in_stream)
ccall(:jl_tty_set_mode, Int32, (Ptr{Void},Int32), t.in_stream.handle, raw) != -1
end
end
enable_bracketed_paste(t::UnixTerminal) = write(t.out_stream, "$(CSI)?2004h")
disable_bracketed_paste(t::UnixTerminal) = write(t.out_stream, "$(CSI)?2004l")
end_keypad_transmit_mode(t::UnixTerminal) = # tput rmkx
write(t.out_stream, "$(CSI)?1l\x1b>")
function Base.displaysize(t::UnixTerminal)
return displaysize(t.out_stream)
end
clear(t::UnixTerminal) = write(t.out_stream, "\x1b[H\x1b[2J")
clear_line(t::UnixTerminal) = write(t.out_stream, "\x1b[0G\x1b[0K")
#beep(t::UnixTerminal) = write(t.err_stream,"\x7")
if is_windows()
hascolor(t::TTYTerminal) = true
else
function hascolor(t::TTYTerminal)
startswith(t.term_type, "xterm") && return true
try
return success(`tput setaf 0`)
catch
return false
end
end
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
## Basic functions ##
"""
size(A::AbstractArray, [dim...])
Returns a tuple containing the dimensions of `A`. Optionally you can specify the
dimension(s) you want the length of, and get the length of that dimension, or a tuple of the
lengths of dimensions you asked for.
```jldoctest
julia> A = ones(2,3,4);
julia> size(A, 2)
3
julia> size(A,3,2)
(4,3)
```
"""
size{T,N}(t::AbstractArray{T,N}, d) = d <= N ? size(t)[d] : 1
size{N}(x, d1::Integer, d2::Integer, dx::Vararg{Integer, N}) = (size(x, d1), size(x, d2), ntuple(k->size(x, dx[k]), Val{N})...)
"""
indices(A, d)
Returns the valid range of indices for array `A` along dimension `d`.
```jldoctest
julia> A = ones(5,6,7);
julia> indices(A,2)
Base.OneTo(6)
```
"""
function indices{T,N}(A::AbstractArray{T,N}, d)
@_inline_meta
d <= N ? indices(A)[d] : OneTo(1)
end
"""
indices(A)
Returns the tuple of valid indices for array `A`.
```jldoctest
julia> A = ones(5,6,7);
julia> indices(A)
(Base.OneTo(5),Base.OneTo(6),Base.OneTo(7))
```
"""
function indices(A)
@_inline_meta
map(OneTo, size(A))
end
# Performance optimization: get rid of a branch on `d` in `indices(A,
# d)` for d=1. 1d arrays are heavily used, and the first dimension
# comes up in other applications.
indices1{T}(A::AbstractArray{T,0}) = OneTo(1)
indices1{T}(A::AbstractArray{T}) = (@_inline_meta; indices(A)[1])
indices1(iter) = OneTo(length(iter))
unsafe_indices(A) = indices(A)
unsafe_indices(r::Range) = (OneTo(unsafe_length(r)),) # Ranges use checked_sub for size
"""
linearindices(A)
Returns a `UnitRange` specifying the valid range of indices for `A[i]`
where `i` is an `Int`. For arrays with conventional indexing (indices
start at 1), or any multidimensional array, this is `1:length(A)`;
however, for one-dimensional arrays with unconventional indices, this
is `indices(A, 1)`.
Calling this function is the "safe" way to write algorithms that
exploit linear indexing.
```jldoctest
julia> A = ones(5,6,7);
julia> b = linearindices(A);
julia> extrema(b)
(1,210)
```
"""
linearindices(A) = (@_inline_meta; OneTo(_length(A)))
linearindices(A::AbstractVector) = (@_inline_meta; indices1(A))
eltype{T}(::Type{AbstractArray{T}}) = T
eltype{T,N}(::Type{AbstractArray{T,N}}) = T
elsize{T}(::AbstractArray{T}) = sizeof(T)
"""
ndims(A::AbstractArray) -> Integer
Returns the number of dimensions of `A`.
```jldoctest
julia> A = ones(3,4,5);
julia> ndims(A)
3
```
"""
ndims{T,N}(::AbstractArray{T,N}) = N
ndims{T,N}(::Type{AbstractArray{T,N}}) = N
ndims{T<:AbstractArray}(::Type{T}) = ndims(supertype(T))
"""
length(A::AbstractArray) -> Integer
Returns the number of elements in `A`.
```jldoctest
julia> A = ones(3,4,5);
julia> length(A)
60
```
"""
length(t::AbstractArray) = prod(size(t))
_length(A::AbstractArray) = prod(map(unsafe_length, indices(A))) # circumvent missing size
_length(A) = length(A)
endof(a::AbstractArray) = length(a)
first(a::AbstractArray) = a[first(eachindex(a))]
function first(itr)
state = start(itr)
done(itr, state) && throw(ArgumentError("collection must be non-empty"))
next(itr, state)[1]
end
last(a) = a[end]
"""
stride(A, k::Integer)
Returns the distance in memory (in number of elements) between adjacent elements in dimension `k`.
```jldoctest
julia> A = ones(3,4,5);
julia> stride(A,2)
3
julia> stride(A,3)
12
```
"""
function stride(a::AbstractArray, i::Integer)
if i > ndims(a)
return length(a)
end
s = 1
for n=1:(i-1)
s *= size(a, n)
end
return s
end
strides{T}(A::AbstractArray{T,0}) = ()
"""
strides(A)
Returns a tuple of the memory strides in each dimension.
```jldoctest
julia> A = ones(3,4,5);
julia> strides(A)
(1,3,12)
```
"""
strides(A::AbstractArray) = _strides((1,), A)
_strides{T,N}(out::NTuple{N}, A::AbstractArray{T,N}) = out
function _strides{M,T,N}(out::NTuple{M}, A::AbstractArray{T,N})
@_inline_meta
_strides((out..., out[M]*size(A, M)), A)
end
function isassigned(a::AbstractArray, i::Int...)
try
a[i...]
true
catch e
if isa(e, BoundsError) || isa(e, UndefRefError)
return false
else
rethrow(e)
end
end
end
# used to compute "end" for last index
function trailingsize(A::AbstractArray, n)
s = 1
for i=n:ndims(A)
s *= size(A,i)
end
return s
end
function trailingsize(inds::Indices, n)
s = 1
for i=n:length(inds)
s *= unsafe_length(inds[i])
end
return s
end
# This version is type-stable even if inds is heterogeneous
function trailingsize(inds::Indices)
@_inline_meta
prod(map(unsafe_length, inds))
end
## Traits for array types ##
abstract LinearIndexing
immutable LinearFast <: LinearIndexing end
immutable LinearSlow <: LinearIndexing end
"""
Base.linearindexing(A)
`linearindexing` defines how an AbstractArray most efficiently accesses its elements. If
`Base.linearindexing(A)` returns `Base.LinearFast()`, this means that linear indexing with
only one index is an efficient operation. If it instead returns `Base.LinearSlow()` (by
default), this means that the array intrinsically accesses its elements with indices
specified for every dimension. Since converting a linear index to multiple indexing
subscripts is typically very expensive, this provides a traits-based mechanism to enable
efficient generic code for all array types.
An abstract array subtype `MyArray` that wishes to opt into fast linear indexing behaviors
should define `linearindexing` in the type-domain:
Base.linearindexing{T<:MyArray}(::Type{T}) = Base.LinearFast()
"""
linearindexing(A::AbstractArray) = linearindexing(typeof(A))
linearindexing{T<:AbstractArray}(::Type{T}) = LinearSlow()
linearindexing{T<:Array}(::Type{T}) = LinearFast()
linearindexing{T<:Range}(::Type{T}) = LinearFast()
linearindexing(A::AbstractArray, B::AbstractArray) = linearindexing(linearindexing(A), linearindexing(B))
linearindexing(A::AbstractArray, B::AbstractArray...) = linearindexing(linearindexing(A), linearindexing(B...))
linearindexing(::LinearFast, ::LinearFast) = LinearFast()
linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow()
## Bounds checking ##
# The overall hierarchy is
# `checkbounds(A, I...)` ->
# `checkbounds(Bool, A, I...)` ->
# `checkbounds_indices(Bool, IA, I)`, which recursively calls
# `checkindex` for each dimension
#
# See the "boundscheck" devdocs for more information.
#
# Note this hierarchy has been designed to reduce the likelihood of
# method ambiguities. We try to make `checkbounds` the place to
# specialize on array type, and try to avoid specializations on index
# types; conversely, `checkindex` is intended to be specialized only
# on index type (especially, its last argument).
"""
checkbounds(Bool, A, I...)
Return `true` if the specified indices `I` are in bounds for the given
array `A`. Subtypes of `AbstractArray` should specialize this method
if they need to provide custom bounds checking behaviors; however, in
many cases one can rely on `A`'s indices and [`checkindex`](:func:`checkindex`).
See also [`checkindex`](:func:`checkindex`).
"""
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
@_inline_meta
checkbounds_indices(Bool, indices(A), I)
end
# As a special extension, allow using logical arrays that match the source array exactly
function checkbounds{_,N}(::Type{Bool}, A::AbstractArray{_,N}, I::AbstractArray{Bool,N})
@_inline_meta
indices(A) == indices(I)
end
"""
checkbounds(A, I...)
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
"""
function checkbounds(A::AbstractArray, I...)
@_inline_meta
checkbounds(Bool, A, I...) || throw_boundserror(A, I)
nothing
end
checkbounds(A::AbstractArray) = checkbounds(A, 1) # 0-d case
"""
checkbounds_indices(Bool, IA, I)
Return `true` if the "requested" indices in the tuple `I` fall within
the bounds of the "permitted" indices specified by the tuple
`IA`. This function recursively consumes elements of these tuples,
usually in a 1-for-1 fashion,
checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
checkbounds_indices(Bool, IA, I)
Note that [`checkindex`](:func:`checkindex`) is being used to perform the actual
bounds-check for a single dimension of the array.
There are two important exceptions to the 1-1 rule: linear indexing and
CartesianIndex{N}, both of which may "consume" more than one element
of `IA`.
"""
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
@_inline_meta
checkindex(Bool, IA[1], I[1]) & checkbounds_indices(Bool, tail(IA), tail(I))
end
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple{Any}) = (@_inline_meta; checkindex(Bool, 1:1, I[1]))
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
@_inline_meta
checkindex(Bool, 1:1, I[1]) & checkbounds_indices(Bool, (), tail(I))
end
function checkbounds_indices(::Type{Bool}, IA::Tuple{Any}, I::Tuple{Any})
@_inline_meta
checkindex(Bool, IA[1], I[1])
end
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{Any})
@_inline_meta
checkindex(Bool, OneTo(trailingsize(IA)), I[1]) # linear indexing
end
checkbounds_indices(::Type{Bool}, ::Tuple, ::Tuple{}) = true
throw_boundserror(A, I) = (@_noinline_meta; throw(BoundsError(A, I)))
# check along a single dimension
"""
checkindex(Bool, inds::AbstractUnitRange, index)
Return `true` if the given `index` is within the bounds of
`inds`. Custom types that would like to behave as indices for all
arrays can extend this method in order to provide a specialized bounds
checking implementation.
```jldoctest
julia> checkindex(Bool,1:20,8)
true
julia> checkindex(Bool,1:20,21)
false
```
"""
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::Range)
@_propagate_inbounds_meta
isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
end
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == indices1(I)
# Logical indexing is an exception to the "output dimensionality is the sum of
# the dimensionality of the indices" rule; `A[A.<0]` always returns a vector,
# regardless of the dimensionalities of `A and `A.<0`. This method goes one step
# further and ignores singleton dimensions for logical mask indices. While a
# little strange, it enables idioms like `A[:, sum(A, 1) .< 0]`. Ref #18271.
function checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool})
# Ensure that there's no more than one non-singleton dimension and that it
# matches the source array's index. Note that there's an ambiguity at length
# 1, since we cannot tell which dimension should be the non-singleton one.
@_inline_meta
length(indx) == prod(map(length, indices(I))) && any(x->x==indx, indices(I))
end
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
@_inline_meta
b = true
for i in I
b &= checkindex(Bool, inds, i)
end
b
end
# See also specializations in multidimensional
## Constructors ##
# default arguments to similar()
"""
similar(array, [element_type=eltype(array)], [dims=size(array)])
Create an uninitialized mutable array with the given element type and size, based upon the
given source array. The second and third arguments are both optional, defaulting to the
given array's `eltype` and `size`. The dimensions may be specified either as a single tuple
argument or as a series of integer arguments.
Custom AbstractArray subtypes may choose which specific array type is best-suited to return
for the given element type and dimensionality. If they do not specialize this method, the
default is an `Array{element_type}(dims...)`.
For example, `similar(1:10, 1, 4)` returns an uninitialized `Array{Int,2}` since ranges are
neither mutable nor support 2 dimensions:
julia> similar(1:10, 1, 4)
1×4 Array{Int64,2}:
4419743872 4374413872 4419743888 0
Conversely, `similar(trues(10,10), 2)` returns an uninitialized `BitVector` with two
elements since `BitArray`s are both mutable and can support 1-dimensional arrays:
julia> similar(trues(10,10), 2)
2-element BitArray{1}:
false
false
Since `BitArray`s can only store elements of type `Bool`, however, if you request a
different element type it will create a regular `Array` instead:
julia> similar(falses(10), Float64, 2, 4)
2×4 Array{Float64,2}:
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
"""
similar{T}(a::AbstractArray{T}) = similar(a, T)
similar{T}(a::AbstractArray, ::Type{T}) = similar(a, T, to_shape(indices(a)))
similar{T}(a::AbstractArray{T}, dims::Tuple) = similar(a, T, to_shape(dims))
similar{T}(a::AbstractArray{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims))
similar{T}(a::AbstractArray, ::Type{T}, dims::DimOrInd...) = similar(a, T, to_shape(dims))
similar{T}(a::AbstractArray, ::Type{T}, dims::NeedsShaping) = similar(a, T, to_shape(dims))
# similar creates an Array by default
similar{T,N}(a::AbstractArray, ::Type{T}, dims::Dims{N}) = Array{T,N}(dims)
to_shape(::Tuple{}) = ()
to_shape(dims::Dims) = dims
to_shape(dims::DimsOrInds) = map(to_shape, dims)
# each dimension
to_shape(i::Int) = i
to_shape(i::Integer) = Int(i)
to_shape(r::OneTo) = Int(last(r))
to_shape(r::AbstractUnitRange) = r
"""
similar(storagetype, indices)
Create an uninitialized mutable array analogous to that specified by
`storagetype`, but with `indices` specified by the last
argument. `storagetype` might be a type or a function.
**Examples**:
similar(Array{Int}, indices(A))
creates an array that "acts like" an `Array{Int}` (and might indeed be
backed by one), but which is indexed identically to `A`. If `A` has
conventional indexing, this will be identical to
`Array{Int}(size(A))`, but if `A` has unconventional indexing then the
indices of the result will match `A`.
similar(BitArray, (indices(A, 2),))
would create a 1-dimensional logical array whose indices match those
of the columns of `A`.
similar(dims->zeros(Int, dims), indices(A))
would create an array of `Int`, initialized to zero, matching the
indices of `A`.
"""
similar(f, shape::Tuple) = f(to_shape(shape))
similar(f, dims::DimOrInd...) = similar(f, dims)
## from general iterable to any array
function copy!(dest::AbstractArray, src)
destiter = eachindex(dest)
state = start(destiter)
for x in src
i, state = next(destiter, state)
dest[i] = x
end
return dest
end
function copy!(dest::AbstractArray, dstart::Integer, src)
i = Int(dstart)
for x in src
dest[i] = x
i += 1
end
return dest
end
# copy from an some iterable object into an AbstractArray
function copy!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
if (sstart < 1)
throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
end
st = start(src)
for j = 1:(sstart-1)
if done(src, st)
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",j-1)))
end
_, st = next(src, st)
end
dn = done(src, st)
if dn
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",sstart-1)))
end
i = Int(dstart)
while !dn
val, st = next(src, st)
dest[i] = val
i += 1
dn = done(src, st)
end
return dest
end
# this method must be separate from the above since src might not have a length
function copy!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
n == 0 && return dest
dmax = dstart + n - 1
inds = linearindices(dest)
if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
sstart < 1 && throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
throw(BoundsError(dest, dstart:dmax))
end
st = start(src)
for j = 1:(sstart-1)
if done(src, st)
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",j-1)))
end
_, st = next(src, st)
end
i = Int(dstart)
while i <= dmax && !done(src, st)
val, st = next(src, st)
@inbounds dest[i] = val
i += 1
end
i <= dmax && throw(BoundsError(dest, i))
return dest
end
## copy between abstract arrays - generally more efficient
## since a single index variable can be used.
copy!(dest::AbstractArray, src::AbstractArray) =
copy!(linearindexing(dest), dest, linearindexing(src), src)
function copy!(::LinearIndexing, dest::AbstractArray, ::LinearIndexing, src::AbstractArray)
destinds, srcinds = linearindices(dest), linearindices(src)
isempty(srcinds) || (first(srcinds) ∈ destinds && last(srcinds) ∈ destinds) || throw(BoundsError(dest, srcinds))
@inbounds for i in srcinds
dest[i] = src[i]
end
return dest
end
function copy!(::LinearIndexing, dest::AbstractArray, ::LinearSlow, src::AbstractArray)
destinds, srcinds = linearindices(dest), linearindices(src)
isempty(srcinds) || (first(srcinds) ∈ destinds && last(srcinds) ∈ destinds) || throw(BoundsError(dest, srcinds))
i = 0
@inbounds for a in src
dest[i+=1] = a
end
return dest
end
function copy!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
copy!(dest, dstart, src, first(linearindices(src)), _length(src))
end
function copy!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
srcinds = linearindices(src)
sstart ∈ srcinds || throw(BoundsError(src, sstart))
copy!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
end
function copy!(dest::AbstractArray, dstart::Integer,
src::AbstractArray, sstart::Integer,
n::Integer)
n == 0 && return dest
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
destinds, srcinds = linearindices(dest), linearindices(src)
(dstart ∈ destinds && dstart+n-1 ∈ destinds) || throw(BoundsError(dest, dstart:dstart+n-1))
(sstart ∈ srcinds && sstart+n-1 ∈ srcinds) || throw(BoundsError(src, sstart:sstart+n-1))
@inbounds for i = 0:(n-1)
dest[dstart+i] = src[sstart+i]
end
return dest
end
function copy(a::AbstractArray)
@_propagate_inbounds_meta
copymutable(a)
end
function copy!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_dest::Range{Int},
A::AbstractVecOrMat{S}, ir_src::Range{Int}, jr_src::Range{Int})
if length(ir_dest) != length(ir_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(ir_src)," and ",length(ir_dest),")")))
end
if length(jr_dest) != length(jr_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(jr_src)," and ",length(jr_dest),")")))
end
@boundscheck checkbounds(B, ir_dest, jr_dest)
@boundscheck checkbounds(A, ir_src, jr_src)
jdest = first(jr_dest)
for jsrc in jr_src
idest = first(ir_dest)
for isrc in ir_src
B[idest,jdest] = A[isrc,jsrc]
idest += step(ir_dest)
end
jdest += step(jr_dest)
end
return B
end
function copy_transpose!{R,S}(B::AbstractVecOrMat{R}, ir_dest::Range{Int}, jr_dest::Range{Int},
A::AbstractVecOrMat{S}, ir_src::Range{Int}, jr_src::Range{Int})
if length(ir_dest) != length(jr_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(jr_src)," and ",length(ir_dest),")")))
end
if length(jr_dest) != length(ir_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(ir_src)," and ",length(jr_dest),")")))
end
@boundscheck checkbounds(B, ir_dest, jr_dest)
@boundscheck checkbounds(A, ir_src, jr_src)
idest = first(ir_dest)
for jsrc in jr_src
jdest = first(jr_dest)
for isrc in ir_src
B[idest,jdest] = A[isrc,jsrc]
jdest += step(jr_dest)
end
idest += step(ir_dest)
end
return B
end
"""
copymutable(a)
Make a mutable copy of an array or iterable `a`. For `a::Array`,
this is equivalent to `copy(a)`, but for other array types it may
differ depending on the type of `similar(a)`. For generic iterables
this is equivalent to `collect(a)`.
"""
function copymutable(a::AbstractArray)
@_propagate_inbounds_meta
copy!(similar(a), a)
end
copymutable(itr) = collect(itr)
zero{T}(x::AbstractArray{T}) = fill!(similar(x), zero(T))
## iteration support for arrays by iterating over `eachindex` in the array ##
# Allows fast iteration by default for both LinearFast and LinearSlow arrays
# While the definitions for LinearFast are all simple enough to inline on their
# own, LinearSlow's CartesianRange is more complicated and requires explicit
# inlining.
start(A::AbstractArray) = (@_inline_meta; itr = eachindex(A); (itr, start(itr)))
next(A::AbstractArray,i) = (@_propagate_inbounds_meta; (idx, s) = next(i[1], i[2]); (A[idx], (i[1], s)))
done(A::AbstractArray,i) = (@_propagate_inbounds_meta; done(i[1], i[2]))
# eachindex iterates over all indices. LinearSlow definitions are later.
eachindex(A::AbstractVector) = (@_inline_meta(); indices1(A))
"""
eachindex(A...)
Creates an iterable object for visiting each index of an AbstractArray `A` in an efficient
manner. For array types that have opted into fast linear indexing (like `Array`), this is
simply the range `1:length(A)`. For other array types, this returns a specialized Cartesian
range to efficiently index into the array with indices specified for every dimension. For
other iterables, including strings and dictionaries, this returns an iterator object
supporting arbitrary index types (e.g. unevenly spaced or non-integer indices).
Example for a sparse 2-d array:
```jldoctest
julia> A = sparse([1, 1, 2], [1, 3, 1], [1, 2, -5])
2×3 sparse matrix with 3 Int64 nonzero entries:
[1, 1] = 1
[2, 1] = -5
[1, 3] = 2
julia> for iter in eachindex(A)
@show iter.I[1], iter.I[2]
@show A[iter]
end
(iter.I[1],iter.I[2]) = (1,1)
A[iter] = 1
(iter.I[1],iter.I[2]) = (2,1)
A[iter] = -5
(iter.I[1],iter.I[2]) = (1,2)
A[iter] = 0
(iter.I[1],iter.I[2]) = (2,2)
A[iter] = 0
(iter.I[1],iter.I[2]) = (1,3)
A[iter] = 2
(iter.I[1],iter.I[2]) = (2,3)
A[iter] = 0
```
If you supply more than one `AbstractArray` argument, `eachindex` will create an
iterable object that is fast for all arguments (a [`UnitRange`](:obj:`UnitRange`)
if all inputs have fast linear indexing, a [`CartesianRange`](:obj:`CartesianRange`)
otherwise).
If the arrays have different sizes and/or dimensionalities, `eachindex` returns an
iterable that spans the largest range along each dimension.
"""
eachindex(A::AbstractArray) = (@_inline_meta(); eachindex(linearindexing(A), A))
function eachindex(A::AbstractArray, B::AbstractArray)
@_inline_meta
eachindex(linearindexing(A,B), A, B)
end
function eachindex(A::AbstractArray, B::AbstractArray...)
@_inline_meta
eachindex(linearindexing(A,B...), A, B...)
end
eachindex(::LinearFast, A::AbstractArray) = linearindices(A)
function eachindex(::LinearFast, A::AbstractArray, B::AbstractArray...)
@_inline_meta
1:_maxlength(A, B...)
end
_maxlength(A) = length(A)
function _maxlength(A, B, C...)
@_inline_meta
max(length(A), _maxlength(B, C...))
end
isempty(a::AbstractArray) = (_length(a) == 0)
## Conversions ##
convert{T,N }(::Type{AbstractArray{T,N}}, A::AbstractArray{T,N}) = A
convert{T,S,N}(::Type{AbstractArray{T,N}}, A::AbstractArray{S,N}) = copy!(similar(A,T), A)
convert{T,S,N}(::Type{AbstractArray{T }}, A::AbstractArray{S,N}) = convert(AbstractArray{T,N}, A)
convert{T,N}(::Type{Array}, A::AbstractArray{T,N}) = convert(Array{T,N}, A)
"""
of_indices(x, y)
Represents the array `y` as an array having the same indices type as `x`.
"""
of_indices(x, y) = similar(dims->y, oftype(indices(x), indices(y)))
full(x::AbstractArray) = x
## range conversions ##
map{T<:Real}(::Type{T}, r::StepRange) = T(r.start):T(r.step):T(last(r))
map{T<:Real}(::Type{T}, r::UnitRange) = T(r.start):T(last(r))
map{T<:AbstractFloat}(::Type{T}, r::FloatRange) = FloatRange(T(r.start), T(r.step), r.len, T(r.divisor))
function map{T<:AbstractFloat}(::Type{T}, r::LinSpace)
new_len = T(r.len)
new_len == r.len || error("$r: too long for $T")
LinSpace(T(r.start), T(r.stop), new_len, T(r.divisor))
end
## unsafe/pointer conversions ##
# note: the following type definitions don't mean any AbstractArray is convertible to
# a data Ref. they just map the array element type to the pointer type for
# convenience in cases that work.
pointer{T}(x::AbstractArray{T}) = unsafe_convert(Ptr{T}, x)
pointer{T}(x::AbstractArray{T}, i::Integer) = (@_inline_meta; unsafe_convert(Ptr{T},x) + (i-first(linearindices(x)))*elsize(x))
## Approach:
# We only define one fallback method on getindex for all argument types.
# That dispatches to an (inlined) internal _getindex function, where the goal is
# to transform the indices such that we can call the only getindex method that
# we require the type A{T,N} <: AbstractArray{T,N} to define; either:
# getindex(::A, ::Int) # if linearindexing(A) == LinearFast() OR
# getindex{T,N}(::A{T,N}, ::Vararg{Int, N}) # if LinearSlow()
# If the subtype hasn't defined the required method, it falls back to the
# _getindex function again where an error is thrown to prevent stack overflows.
function getindex(A::AbstractArray, I...)
@_propagate_inbounds_meta
_getindex(linearindexing(A), A, I...)
end
function unsafe_getindex(A::AbstractArray, I...)
@_inline_meta
@inbounds r = getindex(A, I...)
r
end
## Internal definitions
_getindex(::LinearIndexing, A::AbstractArray, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported")
## LinearFast Scalar indexing: canonical method is one Int
_getindex(::LinearFast, A::AbstractVector, ::Int) = error("indexing not defined for ", typeof(A))
_getindex(::LinearFast, A::AbstractArray, ::Int) = error("indexing not defined for ", typeof(A))
_getindex{T}(::LinearFast, A::AbstractArray{T,0}) = A[1]
_getindex(::LinearFast, A::AbstractArray, i::Real) = (@_propagate_inbounds_meta; getindex(A, to_index(i)))
function _getindex{T,N}(::LinearFast, A::AbstractArray{T,N}, I::Vararg{Real,N})
# We must check bounds for sub2ind; so we can then use @inbounds
@_inline_meta
J = to_indexes(I...)
@boundscheck checkbounds(A, J...)
@inbounds r = getindex(A, sub2ind(A, J...))
r
end
function _getindex(::LinearFast, A::AbstractVector, I1::Real, I::Real...)
@_inline_meta
J = to_indexes(I1, I...)
@boundscheck checkbounds(A, J...)
@inbounds r = getindex(A, J[1])
r
end
function _getindex(::LinearFast, A::AbstractArray, I::Real...) # TODO: DEPRECATE FOR #14770
@_inline_meta
J = to_indexes(I...)
@boundscheck checkbounds(A, J...)
@inbounds r = getindex(A, sub2ind(A, J...))
r
end
## LinearSlow Scalar indexing: Canonical method is full dimensionality of Ints
_getindex{T,N}(::LinearSlow, A::AbstractArray{T,N}, ::Vararg{Int, N}) = error("indexing not defined for ", typeof(A))
_getindex{T,N}(::LinearSlow, A::AbstractArray{T,N}, I::Vararg{Real, N}) = (@_propagate_inbounds_meta; getindex(A, to_indexes(I...)...))
function _getindex(::LinearSlow, A::AbstractArray, i::Real)
# ind2sub requires all dimensions to be > 0; may as well just check bounds
@_inline_meta
@boundscheck checkbounds(A, i)
@inbounds r = getindex(A, ind2sub(A, to_index(i))...)
r
end
@generated function _getindex{T,AN}(::LinearSlow, A::AbstractArray{T,AN}, I::Real...) # TODO: DEPRECATE FOR #14770
N = length(I)
if N > AN
# Drop trailing ones
Isplat = Expr[:(I[$d]) for d = 1:AN]
Osplat = Expr[:(to_index(I[$d]) == 1) for d = AN+1:N]
quote
@_propagate_inbounds_meta
@boundscheck (&)($(Osplat...)) || throw_boundserror(A, I)
getindex(A, $(Isplat...))
end
else
# Expand the last index into the appropriate number of indices
Isplat = Expr[:(I[$d]) for d = 1:N-1]
sz = Expr(:tuple)
sz.args = Expr[:(size(A, $d)) for d=max(N,1):AN]
szcheck = Expr[:(size(A, $d) > 0) for d=max(N,1):AN]
last_idx = N > 0 ? :(to_index(I[$N])) : 1
quote
# ind2sub requires all dimensions to be > 0:
@_propagate_inbounds_meta
@boundscheck (&)($(szcheck...)) || throw_boundserror(A, I)
getindex(A, $(Isplat...), ind2sub($sz, $last_idx)...)
end
end
end
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
# function that allows dispatch on array storage
function setindex!(A::AbstractArray, v, I...)
@_propagate_inbounds_meta
_setindex!(linearindexing(A), A, v, I...)
end
function unsafe_setindex!(A::AbstractArray, v, I...)
@_inline_meta
@inbounds r = setindex!(A, v, I...)
r
end
## Internal defitions
_setindex!(::LinearIndexing, A::AbstractArray, v, I...) = error("indexing $(typeof(A)) with types $(typeof(I)) is not supported")
## LinearFast Scalar indexing
_setindex!(::LinearFast, A::AbstractVector, v, ::Int) = error("indexed assignment not defined for ", typeof(A))
_setindex!(::LinearFast, A::AbstractArray, v, ::Int) = error("indexed assignment not defined for ", typeof(A))
_setindex!{T}(::LinearFast, A::AbstractArray{T,0}, v) = (@_propagate_inbounds_meta; setindex!(A, v, 1))
_setindex!(::LinearFast, A::AbstractArray, v, i::Real) = (@_propagate_inbounds_meta; setindex!(A, v, to_index(i)))
function _setindex!{T,N}(::LinearFast, A::AbstractArray{T,N}, v, I::Vararg{Real,N})
# We must check bounds for sub2ind; so we can then use @inbounds
@_inline_meta
J = to_indexes(I...)
@boundscheck checkbounds(A, J...)
@inbounds r = setindex!(A, v, sub2ind(A, J...))
r
end
function _setindex!(::LinearFast, A::AbstractVector, v, I1::Real, I::Real...)
@_inline_meta
J = to_indexes(I1, I...)
@boundscheck checkbounds(A, J...)
@inbounds r = setindex!(A, v, J[1])
r
end
function _setindex!(::LinearFast, A::AbstractArray, v, I::Real...) # TODO: DEPRECATE FOR #14770
@_inline_meta
J = to_indexes(I...)
@boundscheck checkbounds(A, J...)
@inbounds r = setindex!(A, v, sub2ind(A, J...))
r
end
# LinearSlow Scalar indexing
_setindex!{T,N}(::LinearSlow, A::AbstractArray{T,N}, v, ::Vararg{Int, N}) = error("indexed assignment not defined for ", typeof(A))
_setindex!{T,N}(::LinearSlow, A::AbstractArray{T,N}, v, I::Vararg{Real, N}) = (@_propagate_inbounds_meta; setindex!(A, v, to_indexes(I...)...))
function _setindex!(::LinearSlow, A::AbstractArray, v, i::Real)
# ind2sub requires all dimensions to be > 0; may as well just check bounds
@_inline_meta
@boundscheck checkbounds(A, i)
@inbounds r = setindex!(A, v, ind2sub(A, to_index(i))...)
r
end
@generated function _setindex!{T,AN}(::LinearSlow, A::AbstractArray{T,AN}, v, I::Real...) # TODO: DEPRECATE FOR #14770
N = length(I)
if N > AN
# Drop trailing ones
Isplat = Expr[:(I[$d]) for d = 1:AN]
Osplat = Expr[:(to_index(I[$d]) == 1) for d = AN+1:N]
quote
# We only check the trailing ones, so just propagate @inbounds state
@_propagate_inbounds_meta
@boundscheck (&)($(Osplat...)) || throw_boundserror(A, I)
setindex!(A, v, $(Isplat...))
end
else
# Expand the last index into the appropriate number of indices
Isplat = Expr[:(I[$d]) for d = 1:N-1]
sz = Expr(:tuple)
sz.args = Expr[:(size(A, $d)) for d=max(N,1):AN]
szcheck = Expr[:(size(A, $d) > 0) for d=max(N,1):AN]
last_idx = N > 0 ? :(to_index(I[$N])) : 1
quote
# ind2sub requires all dimensions to be > 0:
@_propagate_inbounds_meta
@boundscheck (&)($(szcheck...)) || throw_boundserror(A, I)
setindex!(A, v, $(Isplat...), ind2sub($sz, $last_idx)...)
end
end
end
## get (getindex with a default value) ##
typealias RangeVecIntList{A<:AbstractVector{Int}} Union{Tuple{Vararg{Union{Range, AbstractVector{Int}}}}, AbstractVector{UnitRange{Int}}, AbstractVector{Range{Int}}, AbstractVector{A}}
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
get(A::AbstractArray, I::Tuple{}, default) = similar(A, typeof(default), 0)
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
function get!{T}(X::AbstractVector{T}, A::AbstractVector, I::Union{Range, AbstractVector{Int}}, default::T)
# 1d is not linear indexing
ind = findin(I, indices1(A))
X[ind] = A[I[ind]]
Xind = indices1(X)
X[first(Xind):first(ind)-1] = default
X[last(ind)+1:last(Xind)] = default
X
end
function get!{T}(X::AbstractArray{T}, A::AbstractArray, I::Union{Range, AbstractVector{Int}}, default::T)
# Linear indexing
ind = findin(I, 1:length(A))
X[ind] = A[I[ind]]
X[1:first(ind)-1] = default
X[last(ind)+1:length(X)] = default
X
end
get(A::AbstractArray, I::Range, default) = get!(similar(A, typeof(default), index_shape(A, I)), A, I, default)
# TODO: DEPRECATE FOR #14770 (just the partial linear indexing part)
function get!{T}(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T)
fill!(X, default)
dst, src = indcopy(size(A), I)
X[dst...] = A[src...]
X
end
get(A::AbstractArray, I::RangeVecIntList, default) = get!(similar(A, typeof(default), index_shape(A, I...)), A, I, default)
## structured matrix methods ##
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
## Concatenation ##
promote_eltype() = Bottom
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
#TODO: ERROR CHECK
cat(catdim::Integer) = Array{Any,1}(0)
vcat() = Array{Any,1}(0)
hcat() = Array{Any,1}(0)
typed_vcat{T}(::Type{T}) = Array{T,1}(0)
typed_hcat{T}(::Type{T}) = Array{T,1}(0)
## cat: special cases
vcat{T}(X::T...) = T[ X[i] for i=1:length(X) ]
vcat{T<:Number}(X::T...) = T[ X[i] for i=1:length(X) ]
hcat{T}(X::T...) = T[ X[j] for i=1:1, j=1:length(X) ]
hcat{T<:Number}(X::T...) = T[ X[j] for i=1:1, j=1:length(X) ]
vcat(X::Number...) = hvcat_fill(Array{promote_typeof(X...)}(length(X)), X)
hcat(X::Number...) = hvcat_fill(Array{promote_typeof(X...)}(1,length(X)), X)
typed_vcat{T}(::Type{T}, X::Number...) = hvcat_fill(Array{T,1}(length(X)), X)
typed_hcat{T}(::Type{T}, X::Number...) = hvcat_fill(Array{T,2}(1,length(X)), X)
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
vcat{T}(V::AbstractVector{T}...) = typed_vcat(T, V...)
function typed_vcat{T}(::Type{T}, V::AbstractVector...)
n::Int = 0
for Vk in V
n += length(Vk)
end
a = similar(V[1], T, n)
pos = 1
for k=1:length(V)
Vk = V[k]
p1 = pos+length(Vk)-1
a[pos:p1] = Vk
pos = p1+1
end
a
end
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
hcat{T}(A::AbstractVecOrMat{T}...) = typed_hcat(T, A...)
function typed_hcat{T}(::Type{T}, A::AbstractVecOrMat...)
nargs = length(A)
nrows = size(A[1], 1)
ncols = 0
dense = true
for j = 1:nargs
Aj = A[j]
if size(Aj, 1) != nrows
throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
end
dense &= isa(Aj,Array)
nd = ndims(Aj)
ncols += (nd==2 ? size(Aj,2) : 1)
end
B = similar(A[1], T, nrows, ncols)
pos = 1
if dense
for k=1:nargs
Ak = A[k]
n = length(Ak)
copy!(B, pos, Ak, 1, n)
pos += n
end
else
for k=1:nargs
Ak = A[k]
p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
B[:, pos:p1] = Ak
pos = p1+1
end
end
return B
end
vcat(A::AbstractMatrix...) = typed_vcat(promote_eltype(A...), A...)
vcat{T}(A::AbstractMatrix{T}...) = typed_vcat(T, A...)
function typed_vcat{T}(::Type{T}, A::AbstractMatrix...)
nargs = length(A)
nrows = sum(a->size(a, 1), A)::Int
ncols = size(A[1], 2)
for j = 2:nargs
if size(A[j], 2) != ncols
throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
end
end
B = similar(A[1], T, nrows, ncols)
pos = 1
for k=1:nargs
Ak = A[k]
p1 = pos+size(Ak,1)-1
B[pos:p1, :] = Ak
pos = p1+1
end
return B
end
## cat: general case
function cat(catdims, X...)
T = promote_type(map(x->isa(x,AbstractArray) ? eltype(x) : typeof(x), X)...)
cat_t(catdims, T, X...)
end
function cat_t(catdims, typeC::Type, X...)
catdims = collect(catdims)
nargs = length(X)
ndimsX = Int[isa(a,AbstractArray) ? ndims(a) : 0 for a in X]
ndimsC = max(maximum(ndimsX), maximum(catdims))
catsizes = zeros(Int,(nargs,length(catdims)))
dims2cat = zeros(Int,ndimsC)
for k = 1:length(catdims)
dims2cat[catdims[k]]=k
end
dimsC = Int[d <= ndimsX[1] ? size(X[1],d) : 1 for d=1:ndimsC]
for k = 1:length(catdims)
catsizes[1,k] = dimsC[catdims[k]]
end
for i = 2:nargs
for d = 1:ndimsC
currentdim = (d <= ndimsX[i] ? size(X[i],d) : 1)
if dims2cat[d] != 0
dimsC[d] += currentdim
catsizes[i,dims2cat[d]] = currentdim
elseif dimsC[d] != currentdim
throw(DimensionMismatch(string("mismatch in dimension ",d,
" (expected ",dimsC[d],
" got ",currentdim,")")))
end
end
end
C = similar(isa(X[1],AbstractArray) ? X[1] : [X[1]], typeC, tuple(dimsC...))
if length(catdims)>1
fill!(C,0)
end
offsets = zeros(Int,length(catdims))
for i=1:nargs
cat_one = [ dims2cat[d] == 0 ? (1:dimsC[d]) : (offsets[dims2cat[d]]+(1:catsizes[i,dims2cat[d]]))
for d=1:ndimsC ]
C[cat_one...] = X[i]
for k = 1:length(catdims)
offsets[k] += catsizes[i,k]
end
end
return C
end
"""
vcat(A...)
Concatenate along dimension 1.
```jldoctest
julia> a = [1 2 3 4 5]
1×5 Array{Int64,2}:
1 2 3 4 5
julia> b = [6 7 8 9 10; 11 12 13 14 15]
2×5 Array{Int64,2}:
6 7 8 9 10
11 12 13 14 15
julia> vcat(a,b)
3×5 Array{Int64,2}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
julia> c = ([1 2 3], [4 5 6])
(
[1 2 3],
<BLANKLINE>
[4 5 6])
julia> vcat(c...)
2×3 Array{Int64,2}:
1 2 3
4 5 6
```
"""
vcat(X...) = cat(1, X...)
"""
hcat(A...)
Concatenate along dimension 2.
```jldoctest
julia> a = [1; 2; 3; 4; 5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> b = [6 7; 8 9; 10 11; 12 13; 14 15]
5×2 Array{Int64,2}:
6 7
8 9
10 11
12 13
14 15
julia> hcat(a,b)
5×3 Array{Int64,2}:
1 6 7
2 8 9
3 10 11
4 12 13
5 14 15
julia> c = ([1; 2; 3], [4; 5; 6])
([1,2,3],[4,5,6])
julia> hcat(c...)
3×2 Array{Int64,2}:
1 4
2 5
3 6
```
"""
hcat(X...) = cat(2, X...)
typed_vcat(T::Type, X...) = cat_t(1, T, X...)
typed_hcat(T::Type, X...) = cat_t(2, T, X...)
cat{T}(catdims, A::AbstractArray{T}...) = cat_t(catdims, T, A...)
cat(catdims, A::AbstractArray...) = cat_t(catdims, promote_eltype(A...), A...)
# The specializations for 1 and 2 inputs are important
# especially when running with --inline=no, see #11158
vcat(A::AbstractArray) = cat(1, A)
vcat(A::AbstractArray, B::AbstractArray) = cat(1, A, B)
vcat(A::AbstractArray...) = cat(1, A...)
hcat(A::AbstractArray) = cat(2, A)
hcat(A::AbstractArray, B::AbstractArray) = cat(2, A, B)
hcat(A::AbstractArray...) = cat(2, A...)
typed_vcat(T::Type, A::AbstractArray) = cat_t(1, T, A)
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = cat_t(1, T, A, B)
typed_vcat(T::Type, A::AbstractArray...) = cat_t(1, T, A...)
typed_hcat(T::Type, A::AbstractArray) = cat_t(2, T, A)
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = cat_t(2, T, A, B)
typed_hcat(T::Type, A::AbstractArray...) = cat_t(2, T, A...)
# 2d horizontal and vertical concatenation
function hvcat(nbc::Integer, as...)
# nbc = # of block columns
n = length(as)
mod(n,nbc) != 0 &&
throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
nbr = div(n,nbc)
hvcat(ntuple(i->nbc, nbr), as...)
end
"""
hvcat(rows::Tuple{Vararg{Int}}, values...)
Horizontal and vertical concatenation in one call. This function is called for block matrix
syntax. The first argument specifies the number of arguments to concatenate in each block
row.
```jldoctest
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
(1,2,3,4,5,6)
julia> [a b c; d e f]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> hvcat((3,3), a,b,c,d,e,f)
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> [a b;c d; e f]
3×2 Array{Int64,2}:
1 2
3 4
5 6
julia> hvcat((2,2,2), a,b,c,d,e,f)
3×2 Array{Int64,2}:
1 2
3 4
5 6
```
If the first argument is a single integer `n`, then all block rows are assumed to have `n`
block columns.
"""
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractMatrix...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
hvcat{T}(rows::Tuple{Vararg{Int}}, xs::AbstractMatrix{T}...) = typed_hvcat(T, rows, xs...)
function typed_hvcat{T}(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractMatrix...)
nbr = length(rows) # number of block rows
nc = 0
for i=1:rows[1]
nc += size(as[i],2)
end
nr = 0
a = 1
for i = 1:nbr
nr += size(as[a],1)
a += rows[i]
end
out = similar(as[1], T, nr, nc)
a = 1
r = 1
for i = 1:nbr
c = 1
szi = size(as[a],1)
for j = 1:rows[i]
Aj = as[a+j-1]
szj = size(Aj,2)
if size(Aj,1) != szi
throw(ArgumentError("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
end
if c-1+szj > nc
throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
end
out[r:r-1+szi, c:c-1+szj] = Aj
c += szj
end
if c != nc+1
throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
end
r += szi
a += rows[i]
end
out
end
hvcat(rows::Tuple{Vararg{Int}}) = []
typed_hvcat{T}(::Type{T}, rows::Tuple{Vararg{Int}}) = Array{T,1}(0)
function hvcat{T<:Number}(rows::Tuple{Vararg{Int}}, xs::T...)
nr = length(rows)
nc = rows[1]
a = Array{T,2}(nr, nc)
if length(a) != length(xs)
throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
end
k = 1
@inbounds for i=1:nr
if nc != rows[i]
throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
end
for j=1:nc
a[i,j] = xs[k]
k += 1
end
end
a
end
function hvcat_fill(a::Array, xs::Tuple)
k = 1
nr, nc = size(a,1), size(a,2)
for i=1:nr
@inbounds for j=1:nc
a[i,j] = xs[k]
k += 1
end
end
a
end
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
function typed_hvcat{T}(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...)
nr = length(rows)
nc = rows[1]
for i = 2:nr
if nc != rows[i]
throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
end
end
len = length(xs)
if nr*nc != len
throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
end
hvcat_fill(Array{T,2}(nr, nc), xs)
end
# fallback definition of hvcat in terms of hcat and vcat
function hvcat(rows::Tuple{Vararg{Int}}, as...)
nbr = length(rows) # number of block rows
rs = Array{Any,1}(nbr)
a = 1
for i = 1:nbr
rs[i] = hcat(as[a:a-1+rows[i]]...)
a += rows[i]
end
vcat(rs...)
end
function typed_hvcat{T}(::Type{T}, rows::Tuple{Vararg{Int}}, as...)
nbr = length(rows) # number of block rows
rs = Array{Any,1}(nbr)
a = 1
for i = 1:nbr
rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
a += rows[i]
end
T[rs...;]
end
## Reductions and scans ##
function isequal(A::AbstractArray, B::AbstractArray)
if A === B return true end
if indices(A) != indices(B)
return false
end
if isa(A,Range) != isa(B,Range)
return false
end
for (a, b) in zip(A, B)
if !isequal(a, b)
return false
end
end
return true
end
function lexcmp(A::AbstractArray, B::AbstractArray)
for (a, b) in zip(A, B)
res = lexcmp(a, b)
res == 0 || return res
end
return cmp(length(A), length(B))
end
function (==)(A::AbstractArray, B::AbstractArray)
if indices(A) != indices(B)
return false
end
if isa(A,Range) != isa(B,Range)
return false
end
for (a, b) in zip(A, B)
if !(a == b)
return false
end
end
return true
end
# sub2ind and ind2sub
# fallbacks
function sub2ind(A::AbstractArray, I...)
@_inline_meta
sub2ind(indices(A), I...)
end
"""
ind2sub(a, index) -> subscripts
Returns a tuple of subscripts into array `a` corresponding to the linear index `index`.
```jldoctest
julia> A = ones(5,6,7);
julia> ind2sub(A,35)
(5,1,2)
julia> ind2sub(A,70)
(5,2,3)
```
"""
function ind2sub(A::AbstractArray, ind)
@_inline_meta
ind2sub(indices(A), ind)
end
# 0-dimensional arrays and indexing with []
sub2ind(::Tuple{}) = 1
sub2ind(::DimsInteger) = 1
sub2ind(::Indices) = 1
sub2ind(::Tuple{}, I::Integer...) = (@_inline_meta; _sub2ind((), 1, 1, I...))
# Generic cases
"""
sub2ind(dims, i, j, k...) -> index
The inverse of [`ind2sub`](:func:`ind2sub`), returns the linear index corresponding to the provided subscripts.
```jldoctest
julia> sub2ind((5,6,7),1,2,3)
66
julia> sub2ind((5,6,7),1,6,3)
86
```
"""
sub2ind(dims::DimsInteger, I::Integer...) = (@_inline_meta; _sub2ind(dims, 1, 1, I...))
sub2ind(inds::Indices, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...))
# In 1d, there's a question of whether we're doing cartesian indexing
# or linear indexing. Support only the former.
sub2ind(inds::Indices{1}, I::Integer...) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@_inline_meta; _sub2ind(inds, 1, 1, I...)) # only OneTo is safe
sub2ind(inds::Tuple{OneTo}, i::Integer) = i
_sub2ind(::Any, L, ind) = ind
function _sub2ind(::Tuple{}, L, ind, i::Integer, I::Integer...)
@_inline_meta
_sub2ind((), L, ind+(i-1)*L, I...)
end
function _sub2ind(inds, L, ind, i::Integer, I::Integer...)
@_inline_meta
r1 = inds[1]
_sub2ind(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
end
nextL(L, l::Integer) = L*l
nextL(L, r::AbstractUnitRange) = L*unsafe_length(r)
offsetin(i, l::Integer) = i-1
offsetin(i, r::AbstractUnitRange) = i-first(r)
ind2sub(::Tuple{}, ind::Integer) = (@_inline_meta; ind == 1 ? () : throw(BoundsError()))
"""
ind2sub(dims, index) -> subscripts
Returns a tuple of subscripts into an array with dimensions `dims`,
corresponding to the linear index `index`.
**Example**:
```
i, j, ... = ind2sub(size(A), indmax(A))
```
provides the indices of the maximum element.
```jldoctest
julia> ind2sub((3,4),2)
(2,1)
julia> ind2sub((3,4),3)
(3,1)
julia> ind2sub((3,4),4)
(1,2)
```
"""
ind2sub(dims::DimsInteger, ind::Integer) = (@_inline_meta; _ind2sub(dims, ind-1))
ind2sub(inds::Indices, ind::Integer) = (@_inline_meta; _ind2sub(inds, ind-1))
ind2sub(inds::Indices{1}, ind::Integer) = throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
_ind2sub(::Tuple{}, ind) = (ind+1,)
function _ind2sub(indslast::NTuple{1}, ind)
@_inline_meta
(_lookup(ind, indslast[1]),)
end
function _ind2sub(inds, ind)
@_inline_meta
r1 = inds[1]
indnext, f, l = _div(ind, r1)
(ind-l*indnext+f, _ind2sub(tail(inds), indnext)...)
end
_lookup(ind, d::Integer) = ind+1
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
_div(ind, d::Integer) = div(ind, d), 1, d
_div(ind, r::AbstractUnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d))
# Vectorized forms
function sub2ind{T<:Integer}(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...)
throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
end
sub2ind{T<:Integer}(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) = _sub2ind_vecs(inds, I1, I...)
sub2ind{T<:Integer}(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) = _sub2ind_vecs(inds, I1, I...)
function _sub2ind_vecs(inds, I::AbstractVector...)
I1 = I[1]
Iinds = indices1(I1)
for j = 2:length(I)
indices1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(indices1(I[j])))"))
end
Iout = similar(I1)
_sub2ind!(Iout, inds, Iinds, I)
Iout
end
function _sub2ind!(Iout, inds, Iinds, I)
@_noinline_meta
for i in Iinds
# Iout[i] = sub2ind(inds, map(Ij->Ij[i], I)...)
Iout[i] = sub2ind_vec(inds, i, I)
end
Iout
end
sub2ind_vec(inds, i, I) = (@_inline_meta; _sub2ind_vec(inds, (), i, I...))
_sub2ind_vec(inds, out, i, I1, I...) = (@_inline_meta; _sub2ind_vec(inds, (out..., I1[i]), i, I...))
_sub2ind_vec(inds, out, i) = (@_inline_meta; sub2ind(inds, out...))
function ind2sub{N,T<:Integer}(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{T})
M = length(ind)
t = ntuple(n->similar(ind),Val{N})
for (i,idx) in enumerate(ind) # FIXME: change to eachindexvalue
sub = ind2sub(inds, idx)
for j = 1:N
t[j][i] = sub[j]
end
end
t
end
function ind2sub!{T<:Integer}(sub::Array{T}, dims::Tuple{Vararg{T}}, ind::T)
ndims = length(dims)
for i=1:ndims-1
ind2 = div(ind-1,dims[i])+1
sub[i] = ind - dims[i]*(ind2-1)
ind = ind2
end
sub[ndims] = ind
return sub
end
## iteration utilities ##
"""
foreach(f, c...) -> Void
Call function `f` on each element of iterable `c`.
For multiple iterable arguments, `f` is called elementwise.
`foreach` should be used instead of `map` when the results of `f` are not
needed, for example in `foreach(println, array)`.
```jldoctest
julia> a = 1:3:7;
julia> foreach(x->println(x^2),a)
1
16
49
```
"""
foreach(f) = (f(); nothing)
foreach(f, itr) = (for x in itr; f(x); end; nothing)
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
## map over arrays ##
## transform any set of dimensions
## dims specifies which dimensions will be transformed. for example
## dims==1:2 will call f on all slices A[:,:,...]
"""
mapslices(f, A, dims)
Transform the given dimensions of array `A` using function `f`. `f` is called on each slice
of `A` of the form `A[...,:,...,:,...]`. `dims` is an integer vector specifying where the
colons go in this expression. The results are concatenated along the remaining dimensions.
For example, if `dims` is `[1,2]` and `A` is 4-dimensional, `f` is called on `A[:,:,i,j]`
for all `i` and `j`.
```jldoctest
julia> a = reshape(collect(1:16),(2,2,2,2))
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
<BLANKLINE>
[:, :, 2, 1] =
5 7
6 8
<BLANKLINE>
[:, :, 1, 2] =
9 11
10 12
<BLANKLINE>
[:, :, 2, 2] =
13 15
14 16
julia> mapslices(sum, a, [1,2])
1×1×2×2 Array{Int64,4}:
[:, :, 1, 1] =
10
<BLANKLINE>
[:, :, 2, 1] =
26
<BLANKLINE>
[:, :, 1, 2] =
42
<BLANKLINE>
[:, :, 2, 2] =
58
```
"""
mapslices(f, A::AbstractArray, dims) = mapslices(f, A, [dims...])
function mapslices(f, A::AbstractArray, dims::AbstractVector)
if isempty(dims)
return map(f,A)
end
dimsA = [indices(A)...]
ndimsA = ndims(A)
alldims = [1:ndimsA;]
otherdims = setdiff(alldims, dims)
idx = Any[first(ind) for ind in indices(A)]
itershape = tuple(dimsA[otherdims]...)
for d in dims
idx[d] = Colon()
end
Aslice = A[idx...]
r1 = f(Aslice)
# determine result size and allocate
Rsize = copy(dimsA)
# TODO: maybe support removing dimensions
if !isa(r1, AbstractArray) || ndims(r1) == 0
r1 = [r1]
end
nextra = max(0,length(dims)-ndims(r1))
if eltype(Rsize) == Int
Rsize[dims] = [size(r1)..., ntuple(d->1, nextra)...]
else
Rsize[dims] = [indices(r1)..., ntuple(d->OneTo(1), nextra)...]
end
R = similar(r1, tuple(Rsize...,))
ridx = Any[map(first, indices(R))...]
for d in dims
ridx[d] = indices(R,d)
end
R[ridx...] = r1
isfirst = true
nidx = length(otherdims)
for I in CartesianRange(itershape)
if isfirst
isfirst = false
else
for i in 1:nidx
idx[otherdims[i]] = ridx[otherdims[i]] = I.I[i]
end
_unsafe_getindex!(Aslice, A, idx...)
R[ridx...] = f(Aslice)
end
end
return R
end
# These are needed because map(eltype, As) is not inferrable
promote_eltype_op(::Any) = (@_pure_meta; Any)
promote_eltype_op(op, A) = (@_pure_meta; promote_op(op, eltype(A)))
promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T))
promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; promote_op(op, T, eltype(A)))
promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, eltype(A), T))
promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S))
promote_eltype_op(op, A, B) = (@_pure_meta; promote_op(op, eltype(A), eltype(B)))
promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_eltype_op(op, promote_eltype_op(op, A, B), C, D...))
## 1 argument
"""
map!(function, collection)
In-place version of [`map`](:func:`map`).
"""
map!{F}(f::F, A::AbstractArray) = map!(f, A, A)
function map!{F}(f::F, dest::AbstractArray, A::AbstractArray)
for (i,j) in zip(eachindex(dest),eachindex(A))
dest[i] = f(A[j])
end
return dest
end
# map on collections
map(f, A::Union{AbstractArray,AbstractSet,Associative}) = collect_similar(A, Generator(f,A))
# default to returning an Array for `map` on general iterators
"""
map(f, c...) -> collection
Transform collection `c` by applying `f` to each element. For multiple collection arguments,
apply `f` elementwise.
```jldoctest
julia> map((x) -> x * 2, [1, 2, 3])
3-element Array{Int64,1}:
2
4
6
julia> map(+, [1, 2, 3], [10, 20, 30])
3-element Array{Int64,1}:
11
22
33
```
"""
map(f, A) = collect(Generator(f,A))
## 2 argument
function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray)
for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
dest[i] = f(A[j], B[k])
end
return dest
end
## N argument
ith_all(i, ::Tuple{}) = ()
ith_all(i, as) = (as[1][i], ith_all(i, tail(as))...)
function map_n!{F}(f::F, dest::AbstractArray, As)
for i = linearindices(As[1])
dest[i] = f(ith_all(i, As)...)
end
return dest
end
"""
map!(function, destination, collection...)
Like [`map`](:func:`map`), but stores the result in `destination` rather than a new
collection. `destination` must be at least as large as the first collection.
"""
map!{F}(f::F, dest::AbstractArray, As::AbstractArray...) = map_n!(f, dest, As)
map(f) = f()
map(f, iters...) = collect(Generator(f, iters...))
# multi-item push!, unshift! (built on top of type-specific 1-item version)
# (note: must not cause a dispatch loop when 1-item case is not defined)
push!(A, a, b) = push!(push!(A, a), b)
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
unshift!(A, a, b) = unshift!(unshift!(A, b), a)
unshift!(A, a, b, c...) = unshift!(unshift!(A, c...), a, b)
## hashing collections ##
const hashaa_seed = UInt === UInt64 ? 0x7f53e68ceb575e76 : 0xeb575e76
const hashrle_seed = UInt == UInt64 ? 0x2aab8909bfea414c : 0xbfea414c
function hash(a::AbstractArray, h::UInt)
h += hashaa_seed
h += hash(size(a))
state = start(a)
done(a, state) && return h
x2, state = next(a, state)
done(a, state) && return hash(x2, h)
x1 = x2
while !done(a, state)
x1 = x2
x2, state = next(a, state)
if isequal(x2, x1)
# For repeated elements, use run length encoding
# This allows efficient hashing of sparse arrays
runlength = 2
while !done(a, state)
x2, state = next(a, state)
isequal(x1, x2) || break
runlength += 1
end
h += hashrle_seed
h = hash(runlength, h)
end
h = hash(x1, h)
end
!isequal(x2, x1) && (h = hash(x2, h))
return h
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
## Basic functions ##
isinteger(x::AbstractArray) = all(isinteger,x)
isinteger{T<:Integer,n}(x::AbstractArray{T,n}) = true
isreal(x::AbstractArray) = all(isreal,x)
isreal{T<:Real,n}(x::AbstractArray{T,n}) = true
ctranspose(a::AbstractArray) = error("ctranspose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
transpose(a::AbstractArray) = error("transpose not implemented for $(typeof(a)). Consider adding parentheses, e.g. A*(B*C.') instead of A*B*C' to avoid explicit calculation of the transposed matrix.")
## Constructors ##
"""
vec(a::AbstractArray) -> Vector
Reshape array `a` as a one-dimensional column vector.
```jldoctest
julia> a = [1 2 3; 4 5 6]
2×3 Array{Int64,2}:
1 2 3
4 5 6
julia> vec(a)
6-element Array{Int64,1}:
1
4
2
5
3
6
```
"""
vec(a::AbstractArray) = reshape(a,_length(a))
vec(a::AbstractVector) = a
_sub(::Tuple{}, ::Tuple{}) = ()
_sub(t::Tuple, ::Tuple{}) = t
_sub(t::Tuple, s::Tuple) = _sub(tail(t), tail(s))
"""
squeeze(A, dims)
Remove the dimensions specified by `dims` from array `A`.
Elements of `dims` must be unique and within the range `1:ndims(A)`.
`size(A,i)` must equal 1 for all `i` in `dims`.
```jldoctest
julia> a = reshape(collect(1:4),(2,2,1,1))
2×2×1×1 Array{Int64,4}:
[:, :, 1, 1] =
1 3
2 4
julia> squeeze(a,3)
2×2×1 Array{Int64,3}:
[:, :, 1] =
1 3
2 4
```
"""
function squeeze(A::AbstractArray, dims::Dims)
for i in 1:length(dims)
1 <= dims[i] <= ndims(A) || throw(ArgumentError("squeezed dims must be in range 1:ndims(A)"))
size(A, dims[i]) == 1 || throw(ArgumentError("squeezed dims must all be size 1"))
for j = 1:i-1
dims[j] == dims[i] && throw(ArgumentError("squeezed dims must be unique"))
end
end
d = ()
for i = 1:ndims(A)
if !in(i, dims)
d = tuple(d..., size(A, i))
end
end
reshape(A, d::typeof(_sub(size(A), dims)))
end
squeeze(A::AbstractArray, dim::Integer) = squeeze(A, (Int(dim),))
## Unary operators ##
conj{T<:Real}(x::AbstractArray{T}) = x
conj!{T<:Real}(x::AbstractArray{T}) = x
real{T<:Real}(x::AbstractArray{T}) = x
imag{T<:Real}(x::AbstractArray{T}) = zero(x)
+{T<:Number}(x::AbstractArray{T}) = x
*{T<:Number}(x::AbstractArray{T,2}) = x
## Binary arithmetic operators ##
*(A::Number, B::AbstractArray) = A .* B
*(A::AbstractArray, B::Number) = A .* B
/(A::AbstractArray, B::Number) = A ./ B
\(A::Number, B::AbstractArray) = B ./ A
# index A[:,:,...,i,:,:,...] where "i" is in dimension "d"
"""
slicedim(A, d::Integer, i)
Return all the data of `A` where the index for dimension `d` equals `i`. Equivalent to
`A[:,:,...,i,:,:,...]` where `i` is in position `d`.
```jldoctest
julia> A = [1 2 3 4; 5 6 7 8]
2×4 Array{Int64,2}:
1 2 3 4
5 6 7 8
julia> slicedim(A,2,3)
2-element Array{Int64,1}:
3
7
```
"""
function slicedim(A::AbstractArray, d::Integer, i)
d >= 1 || throw(ArgumentError("dimension must be ≥ 1"))
nd = ndims(A)
d > nd && (i == 1 || throw_boundserror(A, (ntuple(k->Colon(),nd)..., ntuple(k->1,d-1-nd)..., i)))
A[( n==d ? i : indices(A,n) for n in 1:nd )...]
end
function flipdim(A::AbstractVector, d::Integer)
d == 1 || throw(ArgumentError("dimension to flip must be 1"))
reverse(A)
end
"""
flipdim(A, d::Integer)
Reverse `A` in dimension `d`.
```jldoctest
julia> b = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> flipdim(b,2)
2×2 Array{Int64,2}:
2 1
4 3
```
"""
function flipdim(A::AbstractArray, d::Integer)
nd = ndims(A)
1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
if isempty(A)
return copy(A)
end
inds = indices(A)
B = similar(A)
nnd = 0
for i = 1:nd
nnd += Int(length(inds[i])==1 || i==d)
end
indsd = inds[d]
sd = first(indsd)+last(indsd)
if nnd==nd
# flip along the only non-singleton dimension
for i in indsd
B[i] = A[sd-i]
end
return B
end
alli = [ indices(B,n) for n in 1:nd ]
for i in indsd
B[[ n==d ? sd-i : alli[n] for n in 1:nd ]...] = slicedim(A, d, i)
end
return B
end
function circshift(a::AbstractArray, shiftamt::Real)
circshift!(similar(a), a, (Integer(shiftamt),))
end
circshift(a::AbstractArray, shiftamt::DimsInteger) = circshift!(similar(a), a, shiftamt)
"""
circshift(A, shifts)
Circularly shift the data in an array. The second argument is a vector giving the amount to
shift in each dimension.
```jldoctest
julia> b = reshape(collect(1:16), (4,4))
4×4 Array{Int64,2}:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
julia> circshift(b, (0,2))
4×4 Array{Int64,2}:
9 13 1 5
10 14 2 6
11 15 3 7
12 16 4 8
julia> circshift(b, (-1,0))
4×4 Array{Int64,2}:
2 6 10 14
3 7 11 15
4 8 12 16
1 5 9 13
```
See also [`circshift!`](:func:`circshift!`).
"""
function circshift(a::AbstractArray, shiftamt)
circshift!(similar(a), a, map(Integer, (shiftamt...,)))
end
# Uses K-B-N summation
function cumsum_kbn{T<:AbstractFloat}(v::AbstractVector{T})
r = similar(v)
if isempty(v); return r; end
inds = indices(v, 1)
i1 = first(inds)
s = r[i1] = v[i1]
c = zero(T)
for i=i1+1:last(inds)
vi = v[i]
t = s + vi
if abs(s) >= abs(vi)
c += ((s-t) + vi)
else
c += ((vi-t) + s)
end
s = t
r[i] = s+c
end
return r
end
# Uses K-B-N summation
# TODO: Needs a separate LinearSlow method, this is only fast for LinearIndexing
"""
cumsum_kbn(A, [dim::Integer=1])
Cumulative sum along a dimension, using the Kahan-Babuska-Neumaier compensated summation
algorithm for additional accuracy. The dimension defaults to 1.
"""
function cumsum_kbn{T<:AbstractFloat}(A::AbstractArray{T}, axis::Integer=1)
dimsA = size(A)
ndimsA = ndims(A)
axis_size = dimsA[axis]
axis_stride = 1
for i = 1:(axis-1)
axis_stride *= size(A,i)
end
if axis_size <= 1
return A
end
B = similar(A)
C = similar(A)
for i = 1:length(A)
if div(i-1, axis_stride) % axis_size == 0
B[i] = A[i]
C[i] = zero(T)
else
s = B[i-axis_stride]
Ai = A[i]
B[i] = t = s + Ai
if abs(s) >= abs(Ai)
C[i] = C[i-axis_stride] + ((s-t) + Ai)
else
C[i] = C[i-axis_stride] + ((Ai-t) + s)
end
end
end
return B + C
end
## Other array functions ##
"""
repmat(A, m::Int, n::Int=1)
Construct a matrix by repeating the given matrix `m` times in dimension 1 and `n` times in
dimension 2.
```jldoctest
julia> repmat([1, 2, 3], 2)
6-element Array{Int64,1}:
1
2
3
1
2
3
julia> repmat([1, 2, 3], 2, 3)
6×3 Array{Int64,2}:
1 1 1
2 2 2
3 3 3
1 1 1
2 2 2
3 3 3
```
"""
function repmat(a::AbstractVecOrMat, m::Int, n::Int=1)
o, p = size(a,1), size(a,2)
b = similar(a, o*m, p*n)
for j=1:n
d = (j-1)*p+1
R = d:d+p-1
for i=1:m
c = (i-1)*o+1
b[c:c+o-1, R] = a
end
end
return b
end
function repmat(a::AbstractVector, m::Int)
o = length(a)
b = similar(a, o*m)
for i=1:m
c = (i-1)*o+1
b[c:c+o-1] = a
end
return b
end
"""
repeat(A::AbstractArray; inner=ntuple(x->1, ndims(A)), outer=ntuple(x->1, ndims(A)))
Construct an array by repeating the entries of `A`. The i-th element of `inner` specifies
the number of times that the individual entries of the i-th dimension of `A` should be
repeated. The i-th element of `outer` specifies the number of times that a slice along the
i-th dimension of `A` should be repeated. If `inner` or `outer` are omitted, no repetition
is performed.
```jldoctest
julia> repeat(1:2, inner=2)
4-element Array{Int64,1}:
1
1
2
2
julia> repeat(1:2, outer=2)
4-element Array{Int64,1}:
1
2
1
2
julia> repeat([1 2; 3 4], inner=(2, 1), outer=(1, 3))
4×6 Array{Int64,2}:
1 2 1 2 1 2
1 2 1 2 1 2
3 4 3 4 3 4
3 4 3 4 3 4
```
"""
function repeat(A::AbstractArray;
inner=ntuple(x->1, ndims(A)),
outer=ntuple(x->1, ndims(A)))
ndims_in = ndims(A)
length_inner = length(inner)
length_outer = length(outer)
length_inner >= ndims_in || throw(ArgumentError("number of inner repetitions ($(length(inner))) cannot be less than number of dimensions of input ($(ndims(A)))"))
length_outer >= ndims_in || throw(ArgumentError("number of outer repetitions ($(length(outer))) cannot be less than number of dimensions of input ($(ndims(A)))"))
ndims_out = max(ndims_in, length_inner, length_outer)
inner = vcat(collect(inner), ones(Int,ndims_out-length_inner))
outer = vcat(collect(outer), ones(Int,ndims_out-length_outer))
size_in = size(A)
size_out = ntuple(i->inner[i]*size(A,i)*outer[i],ndims_out)::Dims
inner_size_out = ntuple(i->inner[i]*size(A,i),ndims_out)::Dims
indices_in = Vector{Int}(ndims_in)
indices_out = Vector{Int}(ndims_out)
length_out = prod(size_out)
R = similar(A, size_out)
for index_out in 1:length_out
ind2sub!(indices_out, size_out, index_out)
for t in 1:ndims_in
# "Project" outer repetitions into inner repetitions
indices_in[t] = mod1(indices_out[t], inner_size_out[t])
# Find inner repetitions using flooring division
indices_in[t] = fld1(indices_in[t], inner[t])
end
index_in = sub2ind(size_in, indices_in...)
R[index_out] = A[index_in]
end
return R
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
## array.jl: Dense arrays
## Type aliases for convenience ##
typealias AbstractVector{T} AbstractArray{T,1}
typealias AbstractMatrix{T} AbstractArray{T,2}
typealias AbstractVecOrMat{T} Union{AbstractVector{T}, AbstractMatrix{T}}
typealias RangeIndex Union{Int, Range{Int}, AbstractUnitRange{Int}, Colon}
typealias DimOrInd Union{Integer, AbstractUnitRange}
typealias IntOrInd Union{Int, AbstractUnitRange}
typealias DimsOrInds{N} NTuple{N,DimOrInd}
typealias NeedsShaping Union{Tuple{Integer,Vararg{Integer}}, Tuple{OneTo,Vararg{OneTo}}}
typealias Vector{T} Array{T,1}
typealias Matrix{T} Array{T,2}
typealias VecOrMat{T} Union{Vector{T}, Matrix{T}}
typealias DenseVector{T} DenseArray{T,1}
typealias DenseMatrix{T} DenseArray{T,2}
typealias DenseVecOrMat{T} Union{DenseVector{T}, DenseMatrix{T}}
## Basic functions ##
import Core: arraysize, arrayset, arrayref
vect() = Array{Any,1}(0)
vect{T}(X::T...) = T[ X[i] for i=1:length(X) ]
function vect(X...)
T = promote_typeof(X...)
#T[ X[i] for i=1:length(X) ]
# TODO: this is currently much faster. should figure out why. not clear.
return copy!(Array{T,1}(length(X)), X)
end
size(a::Array, d) = arraysize(a, d)
size(a::Vector) = (arraysize(a,1),)
size(a::Matrix) = (arraysize(a,1), arraysize(a,2))
size(a::Array) = (@_inline_meta; _size((), a))
_size{_,N}(out::NTuple{N}, A::Array{_,N}) = out
function _size{_,M,N}(out::NTuple{M}, A::Array{_,N})
@_inline_meta
_size((out..., size(A,M+1)), A)
end
asize_from(a::Array, n) = n > ndims(a) ? () : (arraysize(a,n), asize_from(a, n+1)...)
length(a::Array) = arraylen(a)
elsize{T}(a::Array{T}) = isbits(T) ? sizeof(T) : sizeof(Ptr)
sizeof(a::Array) = elsize(a) * length(a)
function isassigned{T}(a::Array{T}, i::Int...)
ii = sub2ind(size(a), i...)
1 <= ii <= length(a) || return false
ccall(:jl_array_isassigned, Cint, (Any, UInt), a, ii-1) == 1
end
## copy ##
function unsafe_copy!{T}(dest::Ptr{T}, src::Ptr{T}, n)
# Do not use this to copy data between pointer arrays.
# It can't be made safe no matter how carefully you checked.
ccall(:memmove, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
dest, src, n*sizeof(T))
return dest
end
function unsafe_copy!{T}(dest::Array{T}, doffs, src::Array{T}, soffs, n)
if isbits(T)
unsafe_copy!(pointer(dest, doffs), pointer(src, soffs), n)
else
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
dest, pointer(dest, doffs), src, pointer(src, soffs), n)
end
return dest
end
function copy!{T}(dest::Array{T}, doffs::Integer, src::Array{T}, soffs::Integer, n::Integer)
n == 0 && return dest
n > 0 || throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
if soffs < 1 || doffs < 1 || soffs+n-1 > length(src) || doffs+n-1 > length(dest)
throw(BoundsError())
end
unsafe_copy!(dest, doffs, src, soffs, n)
end
copy!{T}(dest::Array{T}, src::Array{T}) = copy!(dest, 1, src, 1, length(src))
copy{T<:Array}(a::T) = ccall(:jl_array_copy, Ref{T}, (Any,), a)
function reinterpret{T,S}(::Type{T}, a::Array{S,1})
nel = Int(div(length(a)*sizeof(S),sizeof(T)))
# TODO: maybe check that remainder is zero?
return reinterpret(T, a, (nel,))
end
function reinterpret{T,S}(::Type{T}, a::Array{S})
if sizeof(S) != sizeof(T)
throw(ArgumentError("result shape not specified"))
end
reinterpret(T, a, size(a))
end
function reinterpret{T,S,N}(::Type{T}, a::Array{S}, dims::NTuple{N,Int})
if !isbits(T)
throw(ArgumentError("cannot reinterpret Array{$(S)} to ::Type{Array{$(T)}}, type $(T) is not a bitstype"))
end
if !isbits(S)
throw(ArgumentError("cannot reinterpret Array{$(S)} to ::Type{Array{$(T)}}, type $(S) is not a bitstype"))
end
nel = div(length(a)*sizeof(S),sizeof(T))
if prod(dims) != nel
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(nel)"))
end
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
end
# reshaping to same # of dimensions
function reshape{T,N}(a::Array{T,N}, dims::NTuple{N,Int})
if prod(dims) != length(a)
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))"))
end
if dims == size(a)
return a
end
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
end
# reshaping to different # of dimensions
function reshape{T,N}(a::Array{T}, dims::NTuple{N,Int})
if prod(dims) != length(a)
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(a))"))
end
ccall(:jl_reshape_array, Array{T,N}, (Any, Any, Any), Array{T,N}, a, dims)
end
## Constructors ##
similar{T}(a::Array{T,1}) = Array{T,1}(size(a,1))
similar{T}(a::Array{T,2}) = Array{T,2}(size(a,1), size(a,2))
similar{T}(a::Array{T,1}, S::Type) = Array{S,1}(size(a,1))
similar{T}(a::Array{T,2}, S::Type) = Array{S,2}(size(a,1), size(a,2))
similar{T}(a::Array{T}, m::Int) = Array{T,1}(m)
similar{N}(a::Array, T::Type, dims::Dims{N}) = Array{T,N}(dims)
similar{T,N}(a::Array{T}, dims::Dims{N}) = Array{T,N}(dims)
# T[x...] constructs Array{T,1}
function getindex{T}(::Type{T}, vals...)
a = Array{T,1}(length(vals))
@inbounds for i = 1:length(vals)
a[i] = vals[i]
end
return a
end
getindex{T}(::Type{T}) = (@_inline_meta; Array{T,1}(0))
getindex{T}(::Type{T}, x) = (@_inline_meta; a = Array{T,1}(1); @inbounds a[1] = x; a)
getindex{T}(::Type{T}, x, y) = (@_inline_meta; a = Array{T,1}(2); @inbounds (a[1] = x; a[2] = y); a)
getindex{T}(::Type{T}, x, y, z) = (@_inline_meta; a = Array{T,1}(3); @inbounds (a[1] = x; a[2] = y; a[3] = z); a)
function getindex(::Type{Any}, vals::ANY...)
a = Array{Any,1}(length(vals))
@inbounds for i = 1:length(vals)
a[i] = vals[i]
end
return a
end
getindex(::Type{Any}) = Array{Any,1}(0)
function fill!(a::Union{Array{UInt8}, Array{Int8}}, x::Integer)
ccall(:memset, Ptr{Void}, (Ptr{Void}, Cint, Csize_t), a, x, length(a))
return a
end
function fill!{T<:Union{Integer,AbstractFloat}}(a::Array{T}, x)
xT = convert(T, x)
for i in eachindex(a)
@inbounds a[i] = xT
end
return a
end
"""
fill(x, dims)
Create an array filled with the value `x`. For example, `fill(1.0, (5,5))` returns a 5×5
array of floats, with each element initialized to `1.0`.
```jldoctest
julia> fill(1.0, (5,5))
5×5 Array{Float64,2}:
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
1.0 1.0 1.0 1.0 1.0
```
If `x` is an object reference, all elements will refer to the same object. `fill(Foo(),
dims)` will return an array filled with the result of evaluating `Foo()` once.
"""
fill(v, dims::Dims) = fill!(Array{typeof(v)}(dims), v)
fill(v, dims::Integer...) = fill!(Array{typeof(v)}(dims...), v)
for (fname, felt) in ((:zeros,:zero), (:ones,:one))
@eval begin
($fname)(T::Type, dims...) = fill!(Array{T}(dims...), ($felt)(T))
($fname)(dims...) = fill!(Array{Float64}(dims...), ($felt)(Float64))
($fname){T}(A::AbstractArray{T}) = fill!(similar(A), ($felt)(T))
end
end
"""
eye([T::Type=Float64,] m::Integer, n::Integer)
`m`-by-`n` identity matrix.
The default element type is `Float64`.
"""
function eye(T::Type, m::Integer, n::Integer)
a = zeros(T,m,n)
for i = 1:min(m,n)
a[i,i] = one(T)
end
return a
end
"""
eye(m, n)
`m`-by-`n` identity matrix.
"""
eye(m::Integer, n::Integer) = eye(Float64, m, n)
eye(T::Type, n::Integer) = eye(T, n, n)
"""
eye([T::Type=Float64,] n::Integer)
`n`-by-`n` identity matrix.
The default element type is `Float64`.
"""
eye(n::Integer) = eye(Float64, n)
"""
eye(A)
Constructs an identity matrix of the same dimensions and type as `A`.
```jldoctest
julia> A = [1 2 3; 4 5 6; 7 8 9]
3×3 Array{Int64,2}:
1 2 3
4 5 6
7 8 9
julia> eye(A)
3×3 Array{Int64,2}:
1 0 0
0 1 0
0 0 1
```
Note the difference from [`ones`](:func:`ones`).
"""
eye{T}(x::AbstractMatrix{T}) = eye(T, size(x, 1), size(x, 2))
function one{T}(x::AbstractMatrix{T})
m,n = size(x)
m==n || throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
eye(T, m)
end
## Conversions ##
convert{T}(::Type{Vector}, x::AbstractVector{T}) = convert(Vector{T}, x)
convert{T}(::Type{Matrix}, x::AbstractMatrix{T}) = convert(Matrix{T}, x)
convert{T,n}(::Type{Array{T}}, x::Array{T,n}) = x
convert{T,n}(::Type{Array{T,n}}, x::Array{T,n}) = x
convert{T,n,S}(::Type{Array{T}}, x::AbstractArray{S, n}) = convert(Array{T, n}, x)
convert{T,n,S}(::Type{Array{T,n}}, x::AbstractArray{S,n}) = copy!(Array{T,n}(size(x)), x)
promote_rule{T,n,S}(::Type{Array{T,n}}, ::Type{Array{S,n}}) = Array{promote_type(T,S),n}
## copying iterators to containers
"""
collect(element_type, collection)
Return an `Array` with the given element type of all items in a collection or iterable.
The result has the same shape and number of dimensions as `collection`.
"""
collect{T}(::Type{T}, itr) = _collect(T, itr, iteratorsize(itr))
_collect{T}(::Type{T}, itr, isz::HasLength) = copy!(Array{T,1}(Int(length(itr)::Integer)), itr)
_collect{T}(::Type{T}, itr, isz::HasShape) = copy!(similar(Array{T}, indices(itr)), itr)
function _collect{T}(::Type{T}, itr, isz::SizeUnknown)
a = Array{T,1}(0)
for x in itr
push!(a,x)
end
return a
end
# make a collection similar to `c` and appropriate for collecting `itr`
_similar_for(c::AbstractArray, T, itr, ::SizeUnknown) = similar(c, T, 0)
_similar_for(c::AbstractArray, T, itr, ::HasLength) = similar(c, T, Int(length(itr)::Integer))
_similar_for(c::AbstractArray, T, itr, ::HasShape) = similar(c, T, indices(itr))
_similar_for(c, T, itr, isz) = similar(c, T)
"""
collect(collection)
Return an `Array` of all items in a collection or iterator. For associative collections, returns
`Pair{KeyType, ValType}`. If the argument is array-like or is an iterator with the `HasShape()`
trait, the result will have the same shape and number of dimensions as the argument.
```jldoctest
julia> collect(1:2:13)
7-element Array{Int64,1}:
1
3
5
7
9
11
13
```
"""
collect(itr) = _collect(1:1 #= Array =#, itr, iteratoreltype(itr), iteratorsize(itr))
collect_similar(cont, itr) = _collect(cont, itr, iteratoreltype(itr), iteratorsize(itr))
_collect(cont, itr, ::HasEltype, isz::Union{HasLength,HasShape}) =
copy!(_similar_for(cont, eltype(itr), itr, isz), itr)
function _collect(cont, itr, ::HasEltype, isz::SizeUnknown)
a = _similar_for(cont, eltype(itr), itr, isz)
for x in itr
push!(a,x)
end
return a
end
if isdefined(Core, :Inference)
_default_eltype(itrt::ANY) = Core.Inference.return_type(first, Tuple{itrt})
else
_default_eltype(itr::ANY) = Any
end
_array_for{T}(::Type{T}, itr, ::HasLength) = Array{T,1}(Int(length(itr)::Integer))
_array_for{T}(::Type{T}, itr, ::HasShape) = similar(Array{T}, indices(itr))
function collect(itr::Generator)
isz = iteratorsize(itr.iter)
et = _default_eltype(typeof(itr))
if isa(isz, SizeUnknown)
return grow_to!(Array{et,1}(0), itr)
else
st = start(itr)
if done(itr,st)
return _array_for(et, itr.iter, isz)
end
v1, st = next(itr, st)
collect_to_with_first!(_array_for(typeof(v1), itr.iter, isz), v1, itr, st)
end
end
_collect(c, itr, ::EltypeUnknown, isz::SizeUnknown) =
grow_to!(_similar_for(c, _default_eltype(typeof(itr)), itr, isz), itr)
function _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape})
st = start(itr)
if done(itr,st)
return _similar_for(c, _default_eltype(typeof(itr)), itr, isz)
end
v1, st = next(itr, st)
collect_to_with_first!(_similar_for(c, typeof(v1), itr, isz), v1, itr, st)
end
function collect_to_with_first!(dest::AbstractArray, v1, itr, st)
i1 = first(linearindices(dest))
dest[i1] = v1
return collect_to!(dest, itr, i1+1, st)
end
function collect_to_with_first!(dest, v1, itr, st)
push!(dest, v1)
return grow_to!(dest, itr, st)
end
function collect_to!{T}(dest::AbstractArray{T}, itr, offs, st)
# collect to dest array, checking the type of each result. if a result does not
# match, widen the result type and re-dispatch.
i = offs
while !done(itr, st)
el, st = next(itr, st)
S = typeof(el)
if S === T || S <: T
@inbounds dest[i] = el::T
i += 1
else
R = typejoin(T, S)
new = similar(dest, R)
copy!(new,1, dest,1, i-1)
@inbounds new[i] = el
return collect_to!(new, itr, i+1, st)
end
end
return dest
end
function grow_to!(dest, itr)
out = grow_to!(similar(dest,Union{}), itr, start(itr))
return isempty(out) ? dest : out
end
function grow_to!(dest, itr, st)
T = eltype(dest)
while !done(itr, st)
el, st = next(itr, st)
S = typeof(el)
if S === T || S <: T
push!(dest, el::T)
else
new = similar(dest, typejoin(T, S))
copy!(new, dest)
push!(new, el)
return grow_to!(new, itr, st)
end
end
return dest
end
## Iteration ##
start(A::Array) = 1
next(a::Array,i) = (@_propagate_inbounds_meta; (a[i],i+1))
done(a::Array,i) = (@_inline_meta; i == length(a)+1)
## Indexing: getindex ##
# This is more complicated than it needs to be in order to get Win64 through bootstrap
getindex(A::Array, i1::Real) = arrayref(A, to_index(i1))
getindex(A::Array, i1::Real, i2::Real, I::Real...) = (@_inline_meta; arrayref(A, to_index(i1), to_index(i2), to_indexes(I...)...)) # TODO: REMOVE FOR #14770
# Faster contiguous indexing using copy! for UnitRange and Colon
function getindex(A::Array, I::UnitRange{Int})
@_inline_meta
@boundscheck checkbounds(A, I)
lI = length(I)
X = similar(A, lI)
if lI > 0
unsafe_copy!(X, 1, A, first(I), lI)
end
return X
end
function getindex(A::Array, c::Colon)
lI = length(A)
X = similar(A, lI)
if lI > 0
unsafe_copy!(X, 1, A, 1, lI)
end
return X
end
# This is redundant with the abstract fallbacks, but needed for bootstrap
function getindex{S,T<:Real}(A::Array{S}, I::Range{T})
return S[ A[to_index(i)] for i in I ]
end
## Indexing: setindex! ##
setindex!{T}(A::Array{T}, x, i1::Real) = arrayset(A, convert(T,x)::T, to_index(i1))
setindex!{T}(A::Array{T}, x, i1::Real, i2::Real, I::Real...) = arrayset(A, convert(T,x)::T, to_index(i1), to_index(i2), to_indexes(I...)...) # TODO: REMOVE FOR #14770
# These are redundant with the abstract fallbacks but needed for bootstrap
function setindex!(A::Array, x, I::AbstractVector{Int})
A === I && (I = copy(I))
for i in I
A[i] = x
end
return A
end
function setindex!(A::Array, X::AbstractArray, I::AbstractVector{Int})
setindex_shape_check(X, length(I))
count = 1
if X === A
X = copy(X)
I===A && (I = X::typeof(I))
elseif I === A
I = copy(I)
end
for i in I
A[i] = X[count]
count += 1
end
return A
end
# Faster contiguous setindex! with copy!
function setindex!{T}(A::Array{T}, X::Array{T}, I::UnitRange{Int})
@_inline_meta
@boundscheck checkbounds(A, I)
lI = length(I)
setindex_shape_check(X, lI)
if lI > 0
unsafe_copy!(A, first(I), X, 1, lI)
end
return A
end
function setindex!{T}(A::Array{T}, X::Array{T}, c::Colon)
lI = length(A)
setindex_shape_check(X, lI)
if lI > 0
unsafe_copy!(A, 1, X, 1, lI)
end
return A
end
setindex!(A::Array, x::Number, ::Colon) = fill!(A, x)
setindex!{T, N}(A::Array{T, N}, x::Number, ::Vararg{Colon, N}) = fill!(A, x)
# efficiently grow an array
_growat!(a::Vector, i::Integer, delta::Integer) =
ccall(:jl_array_grow_at, Void, (Any, Int, UInt), a, i - 1, delta)
# efficiently delete part of an array
_deleteat!(a::Vector, i::Integer, delta::Integer) =
ccall(:jl_array_del_at, Void, (Any, Int, UInt), a, i - 1, delta)
## Dequeue functionality ##
function push!{T}(a::Array{T,1}, item)
# convert first so we don't grow the array if the assignment won't work
itemT = convert(T, item)
ccall(:jl_array_grow_end, Void, (Any, UInt), a, 1)
a[end] = itemT
return a
end
function push!(a::Array{Any,1}, item::ANY)
ccall(:jl_array_grow_end, Void, (Any, UInt), a, 1)
arrayset(a, item, length(a))
return a
end
function append!{T}(a::Array{T,1}, items::AbstractVector)
n = length(items)
ccall(:jl_array_grow_end, Void, (Any, UInt), a, n)
copy!(a, length(a)-n+1, items, 1, n)
return a
end
"""
prepend!(a::Vector, items) -> collection
Insert the elements of `items` to the beginning of `a`.
```jldoctest
julia> prepend!([3],[1,2])
3-element Array{Int64,1}:
1
2
3
```
"""
function prepend!{T}(a::Array{T,1}, items::AbstractVector)
n = length(items)
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, n)
if a === items
copy!(a, 1, items, n+1, n)
else
copy!(a, 1, items, 1, n)
end
return a
end
"""
resize!(a::Vector, n::Integer) -> Vector
Resize `a` to contain `n` elements. If `n` is smaller than the current collection
length, the first `n` elements will be retained. If `n` is larger, the new elements are not
guaranteed to be initialized.
```jldoctest
julia> resize!([6, 5, 4, 3, 2, 1], 3)
3-element Array{Int64,1}:
6
5
4
```
```julia
julia> resize!([6, 5, 4, 3, 2, 1], 8)
8-element Array{Int64,1}:
6
5
4
3
2
1
0
0
```
"""
function resize!(a::Vector, nl::Integer)
l = length(a)
if nl > l
ccall(:jl_array_grow_end, Void, (Any, UInt), a, nl-l)
else
if nl < 0
throw(ArgumentError("new length must be ≥ 0"))
end
ccall(:jl_array_del_end, Void, (Any, UInt), a, l-nl)
end
return a
end
function sizehint!(a::Vector, sz::Integer)
ccall(:jl_array_sizehint, Void, (Any, UInt), a, sz)
a
end
function pop!(a::Vector)
if isempty(a)
throw(ArgumentError("array must be non-empty"))
end
item = a[end]
ccall(:jl_array_del_end, Void, (Any, UInt), a, 1)
return item
end
"""
unshift!(collection, items...) -> collection
Insert one or more `items` at the beginning of `collection`.
```jldoctest
julia> unshift!([1, 2, 3, 4], 5, 6)
6-element Array{Int64,1}:
5
6
1
2
3
4
```
"""
function unshift!{T}(a::Array{T,1}, item)
item = convert(T, item)
ccall(:jl_array_grow_beg, Void, (Any, UInt), a, 1)
a[1] = item
return a
end
function shift!(a::Vector)
if isempty(a)
throw(ArgumentError("array must be non-empty"))
end
item = a[1]
ccall(:jl_array_del_beg, Void, (Any, UInt), a, 1)
return item
end
"""
insert!(a::Vector, index::Integer, item)
Insert an `item` into `a` at the given `index`. `index` is the index of `item` in
the resulting `a`.
```jldoctest
julia> insert!([6, 5, 4, 2, 1], 4, 3)
6-element Array{Int64,1}:
6
5
4
3
2
1
```
"""
function insert!{T}(a::Array{T,1}, i::Integer, item)
# Throw convert error before changing the shape of the array
_item = convert(T, item)
_growat!(a, i, 1)
# _growat! already did bound check
@inbounds a[i] = _item
return a
end
"""
deleteat!(a::Vector, i::Integer)
Remove the item at the given `i` and return the modified `a`. Subsequent items
are shifted to fill the resulting gap.
```jldoctest
julia> deleteat!([6, 5, 4, 3, 2, 1], 2)
5-element Array{Int64,1}:
6
4
3
2
1
```
"""
deleteat!(a::Vector, i::Integer) = (_deleteat!(a, i, 1); a)
function deleteat!{T<:Integer}(a::Vector, r::UnitRange{T})
n = length(a)
isempty(r) || _deleteat!(a, first(r), length(r))
return a
end
"""
deleteat!(a::Vector, inds)
Remove the items at the indices given by `inds`, and return the modified `a`.
Subsequent items are shifted to fill the resulting gap. `inds` must be sorted and unique.
```jldoctest
julia> deleteat!([6, 5, 4, 3, 2, 1], 1:2:5)
3-element Array{Int64,1}:
5
3
1
julia> deleteat!([6, 5, 4, 3, 2, 1], (2, 2))
ERROR: ArgumentError: indices must be unique and sorted
in deleteat!(::Array{Int64,1}, ::Tuple{Int64,Int64}) at ./array.jl:727
...
```
"""
function deleteat!(a::Vector, inds)
n = length(a)
s = start(inds)
done(inds, s) && return a
(p, s) = next(inds, s)
q = p+1
while !done(inds, s)
(i,s) = next(inds, s)
if !(q <= i <= n)
if i < q
throw(ArgumentError("indices must be unique and sorted"))
else
throw(BoundsError())
end
end
while q < i
@inbounds a[p] = a[q]
p += 1; q += 1
end
q = i+1
end
while q <= n
@inbounds a[p] = a[q]
p += 1; q += 1
end
ccall(:jl_array_del_end, Void, (Any, UInt), a, n-p+1)
return a
end
const _default_splice = []
"""
splice!(a::Vector, index::Integer, [replacement]) -> item
Remove the item at the given index, and return the removed item.
Subsequent items are shifted left to fill the resulting gap.
If specified, replacement values from an ordered
collection will be spliced in place of the removed item.
```jldoctest
julia> A = [6, 5, 4, 3, 2, 1]; splice!(A, 5)
2
julia> A
5-element Array{Int64,1}:
6
5
4
3
1
julia> splice!(A, 5, -1)
1
julia> A
5-element Array{Int64,1}:
6
5
4
3
-1
julia> splice!(A, 1, [-1, -2, -3])
6
julia> A
7-element Array{Int64,1}:
-1
-2
-3
5
4
3
-1
```
To insert `replacement` before an index `n` without removing any items, use
`splice!(collection, n:n-1, replacement)`.
"""
function splice!(a::Vector, i::Integer, ins=_default_splice)
v = a[i]
m = length(ins)
if m == 0
_deleteat!(a, i, 1)
elseif m == 1
a[i] = ins[1]
else
_growat!(a, i, m-1)
k = 1
for x in ins
a[i+k-1] = x
k += 1
end
end
return v
end
"""
splice!(a::Vector, range, [replacement]) -> items
Remove items in the specified index range, and return a collection containing
the removed items.
Subsequent items are shifted left to fill the resulting gap.
If specified, replacement values from an ordered collection will be spliced in
place of the removed items.
To insert `replacement` before an index `n` without removing any items, use
`splice!(collection, n:n-1, replacement)`.
```jldoctest
julia> splice!(A, 4:3, 2)
0-element Array{Int64,1}
julia> A
8-element Array{Int64,1}:
-1
-2
-3
2
5
4
3
-1
```
"""
function splice!{T<:Integer}(a::Vector, r::UnitRange{T}, ins=_default_splice)
v = a[r]
m = length(ins)
if m == 0
deleteat!(a, r)
return v
end
n = length(a)
f = first(r)
l = last(r)
d = length(r)
if m < d
delta = d - m
_deleteat!(a, (f - 1 < n - l) ? f : (l - delta + 1), delta)
elseif m > d
_growat!(a, (f - 1 < n - l) ? f : (l + 1), m - d)
end
k = 1
for x in ins
a[f+k-1] = x
k += 1
end
return v
end
function empty!(a::Vector)
ccall(:jl_array_del_end, Void, (Any, UInt), a, length(a))
return a
end
# use memcmp for lexcmp on byte arrays
function lexcmp(a::Array{UInt8,1}, b::Array{UInt8,1})
c = ccall(:memcmp, Int32, (Ptr{UInt8}, Ptr{UInt8}, UInt),
a, b, min(length(a),length(b)))
return c < 0 ? -1 : c > 0 ? +1 : cmp(length(a),length(b))
end
# use memcmp for == on bit integer types
function =={T<:BitInteger,N}(a::Array{T,N}, b::Array{T,N})
size(a) == size(b) && 0 == ccall(
:memcmp, Int32, (Ptr{T}, Ptr{T}, UInt), a, b, sizeof(T) * length(a))
end
# this is ~20% faster than the generic implementation above for very small arrays
function =={T<:BitInteger}(a::Array{T,1}, b::Array{T,1})
len = length(a)
len == length(b) && 0 == ccall(
:memcmp, Int32, (Ptr{T}, Ptr{T}, UInt), a, b, sizeof(T) * len)
end
function reverse(A::AbstractVector, s=1, n=length(A))
B = similar(A)
for i = 1:s-1
B[i] = A[i]
end
for i = s:n
B[i] = A[n+s-i]
end
for i = n+1:length(A)
B[i] = A[i]
end
return B
end
reverseind(a::AbstractVector, i::Integer) = length(a) + 1 - i
function reverse!(v::AbstractVector, s=1, n=length(v))
if n <= s # empty case; ok
elseif !(1 ≤ s ≤ endof(v))
throw(BoundsError(v, s))
elseif !(1 ≤ n ≤ endof(v))
throw(BoundsError(v, n))
end
r = n
@inbounds for i in s:div(s+n-1, 2)
v[i], v[r] = v[r], v[i]
r -= 1
end
return v
end
# concatenations of homogeneous combinations of vectors, horizontal and vertical
function hcat{T}(V::Vector{T}...)
height = length(V[1])
for j = 2:length(V)
if length(V[j]) != height
throw(DimensionMismatch("vectors must have same lengths"))
end
end
return [ V[j][i]::T for i=1:length(V[1]), j=1:length(V) ]
end
function vcat{T}(arrays::Vector{T}...)
n = 0
for a in arrays
n += length(a)
end
arr = Array{T,1}(n)
ptr = pointer(arr)
if isbits(T)
elsz = Core.sizeof(T)
else
elsz = Core.sizeof(Ptr{Void})
end
for a in arrays
na = length(a)
nba = na * elsz
if isbits(T)
ccall(:memcpy, Ptr{Void}, (Ptr{Void}, Ptr{Void}, UInt),
ptr, a, nba)
else
ccall(:jl_array_ptr_copy, Void, (Any, Ptr{Void}, Any, Ptr{Void}, Int),
arr, ptr, a, pointer(a), na)
end
ptr += nba
end
return arr
end
## find ##
"""
findnext(A, i::Integer)
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
```jldoctest
julia> A = [0 0; 1 0]
2×2 Array{Int64,2}:
0 0
1 0
julia> findnext(A,1)
2
julia> findnext(A,3)
0
```
"""
function findnext(A, start::Integer)
for i = start:length(A)
if A[i] != 0
return i
end
end
return 0
end
"""
findfirst(A)
Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`).
Returns `0` if no such value is found.
```jldoctest
julia> A = [0 0; 1 0]
2×2 Array{Int64,2}:
0 0
1 0
julia> findfirst(A)
2
```
"""
findfirst(A) = findnext(A, 1)
"""
findnext(A, v, i::Integer)
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
```jldoctest
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findnext(A,4,4)
0
julia> findnext(A,4,3)
3
```
"""
function findnext(A, v, start::Integer)
for i = start:length(A)
if A[i] == v
return i
end
end
return 0
end
"""
findfirst(A, v)
Return the linear index of the first element equal to `v` in `A`.
Returns `0` if `v` is not found.
```jldoctest
julia> A = [4 6; 2 2]
2×2 Array{Int64,2}:
4 6
2 2
julia> findfirst(A,2)
2
julia> findfirst(A,3)
0
```
"""
findfirst(A, v) = findnext(A, v, 1)
"""
findnext(predicate::Function, A, i::Integer)
Find the next linear index >= `i` of an element of `A` for which `predicate` returns `true`, or `0` if not found.
```jldoctest
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findnext(isodd, A, 1)
1
julia> findnext(isodd, A, 2)
0
```
"""
function findnext(testf::Function, A, start::Integer)
for i = start:length(A)
if testf(A[i])
return i
end
end
return 0
end
"""
findfirst(predicate::Function, A)
Return the linear index of the first element of `A` for which `predicate` returns `true`.
Returns `0` if there is no such element.
```jldoctest
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findfirst(iseven, A)
2
julia> findfirst(x -> x>10, A)
0
```
"""
findfirst(testf::Function, A) = findnext(testf, A, 1)
"""
findprev(A, i::Integer)
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> findprev(A,2)
2
julia> findprev(A,1)
0
```
"""
function findprev(A, start::Integer)
for i = start:-1:1
A[i] != 0 && return i
end
return 0
end
"""
findlast(A)
Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`).
Returns `0` if there is no non-zero value in `A`.
```jldoctest
julia> A = [1 0; 1 0]
2×2 Array{Int64,2}:
1 0
1 0
julia> findlast(A)
2
julia> A = zeros(2,2)
2×2 Array{Float64,2}:
0.0 0.0
0.0 0.0
julia> findlast(A)
0
```
"""
findlast(A) = findprev(A, length(A))
"""
findprev(A, v, i::Integer)
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> findprev(A, 1, 4)
2
julia> findprev(A, 1, 1)
0
```
"""
function findprev(A, v, start::Integer)
for i = start:-1:1
A[i] == v && return i
end
return 0
end
"""
findlast(A, v)
Return the linear index of the last element equal to `v` in `A`.
Returns `0` if there is no element of `A` equal to `v`.
```jldoctest
julia> A = [1 2; 2 1]
2×2 Array{Int64,2}:
1 2
2 1
julia> findlast(A,1)
4
julia> findlast(A,2)
3
julia> findlast(A,3)
0
```
"""
findlast(A, v) = findprev(A, v, length(A))
"""
findprev(predicate::Function, A, i::Integer)
Find the previous linear index <= `i` of an element of `A` for which `predicate` returns `true`, or
`0` if not found.
```jldoctest
julia> A = [4 6; 1 2]
2×2 Array{Int64,2}:
4 6
1 2
julia> findprev(isodd, A, 1)
0
julia> findprev(isodd, A, 3)
2
```
"""
function findprev(testf::Function, A, start::Integer)
for i = start:-1:1
testf(A[i]) && return i
end
return 0
end
"""
findlast(predicate::Function, A)
Return the linear index of the last element of `A` for which `predicate` returns `true`.
Returns `0` if there is no such element.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> findlast(isodd, A)
2
julia> findlast(x -> x > 5, A)
0
```
"""
findlast(testf::Function, A) = findprev(testf, A, length(A))
"""
find(f::Function, A)
Return a vector `I` of the linear indexes of `A` where `f(A[I])` returns `true`.
If there are no such elements of `A`, find returns an empty array.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> find(isodd,A)
2-element Array{Int64,1}:
1
2
```
"""
function find(testf::Function, A)
# use a dynamic-length array to store the indexes, then copy to a non-padded
# array for the return
tmpI = Array{Int,1}(0)
inds = _index_remapper(A)
for (i,a) = enumerate(A)
if testf(a)
push!(tmpI, inds[i])
end
end
I = Array{Int,1}(length(tmpI))
copy!(I, tmpI)
return I
end
_index_remapper(A::AbstractArray) = linearindices(A)
_index_remapper(iter) = Colon() # safe for objects that don't implement length
"""
find(A)
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
common use of this is to convert a boolean array to an array of indexes of the `true`
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
```jldoctest
julia> A = [true false; false true]
2×2 Array{Bool,2}:
true false
false true
julia> find(A)
2-element Array{Int64,1}:
1
4
```
"""
function find(A)
nnzA = countnz(A)
I = Vector{Int}(nnzA)
count = 1
inds = _index_remapper(A)
for (i,a) in enumerate(A)
if a != 0
I[count] = inds[i]
count += 1
end
end
return I
end
find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]
findn(A::AbstractVector) = find(A)
"""
findn(A)
Return a vector of indexes for each dimension giving the locations of the non-zeros in `A`
(determined by `A[i]!=0`).
If there are no non-zero elements of `A`, `findn` returns a 2-tuple of empty arrays.
```jldoctest
julia> A = [1 2 0; 0 0 3; 0 4 0]
3×3 Array{Int64,2}:
1 2 0
0 0 3
0 4 0
julia> findn(A)
([1,1,3,2],[1,2,2,3])
julia> A = zeros(2,2)
2×2 Array{Float64,2}:
0.0 0.0
0.0 0.0
julia> findn(A)
(Int64[],Int64[])
```
"""
function findn(A::AbstractMatrix)
nnzA = countnz(A)
I = similar(A, Int, nnzA)
J = similar(A, Int, nnzA)
count = 1
for j=indices(A,2), i=indices(A,1)
if A[i,j] != 0
I[count] = i
J[count] = j
count += 1
end
end
return (I, J)
end
"""
findnz(A)
Return a tuple `(I, J, V)` where `I` and `J` are the row and column indexes of the non-zero
values in matrix `A`, and `V` is a vector of the non-zero values.
```jldoctest
julia> A = [1 2 0; 0 0 3; 0 4 0]
3×3 Array{Int64,2}:
1 2 0
0 0 3
0 4 0
julia> findnz(A)
([1,1,3,2],[1,2,2,3],[1,2,4,3])
```
"""
function findnz{T}(A::AbstractMatrix{T})
nnzA = countnz(A)
I = zeros(Int, nnzA)
J = zeros(Int, nnzA)
NZs = Array{T,1}(nnzA)
count = 1
if nnzA > 0
for j=indices(A,2), i=indices(A,1)
Aij = A[i,j]
if Aij != 0
I[count] = i
J[count] = j
NZs[count] = Aij
count += 1
end
end
end
return (I, J, NZs)
end
"""
findmax(itr) -> (x, index)
Returns the maximum element of the collection `itr` and its index. If there are multiple
maximal elements, then the first one will be returned. `NaN` values are ignored, unless
all elements are `NaN`.
The collection must not be empty.
```jldoctest
julia> findmax([8,0.1,-9,pi])
(8.0,1)
julia> findmax([1,7,7,6])
(7,2)
julia> findmax([1,7,7,NaN])
(7.0,2)
```
"""
function findmax(a)
if isempty(a)
throw(ArgumentError("collection must be non-empty"))
end
s = start(a)
mi = i = 1
m, s = next(a, s)
while !done(a, s)
ai, s = next(a, s)
i += 1
if ai > m || m!=m
m = ai
mi = i
end
end
return (m, mi)
end
"""
findmin(itr) -> (x, index)
Returns the minimum element of the collection `itr` and its index. If there are multiple
minimal elements, then the first one will be returned. `NaN` values are ignored, unless
all elements are `NaN`.
The collection must not be empty.
```jldoctest
julia> findmin([8,0.1,-9,pi])
(-9.0,3)
julia> findmin([7,1,1,6])
(1,2)
julia> findmin([7,1,1,NaN])
(1.0,2)
```
"""
function findmin(a)
if isempty(a)
throw(ArgumentError("collection must be non-empty"))
end
s = start(a)
mi = i = 1
m, s = next(a, s)
while !done(a, s)
ai, s = next(a, s)
i += 1
if ai < m || m!=m
m = ai
mi = i
end
end
return (m, mi)
end
"""
indmax(itr) -> Integer
Returns the index of the maximum element in a collection. If there are multiple maximal
elements, then the first one will be returned. `NaN` values are ignored, unless all
elements are `NaN`.
The collection must not be empty.
```jldoctest
julia> indmax([8,0.1,-9,pi])
1
julia> indmax([1,7,7,6])
2
julia> indmax([1,7,7,NaN])
2
```
"""
indmax(a) = findmax(a)[2]
"""
indmin(itr) -> Integer
Returns the index of the minimum element in a collection. If there are multiple minimal
elements, then the first one will be returned. `NaN` values are ignored, unless all
elements are `NaN`.
The collection must not be empty.
```jldoctest
julia> indmin([8,0.1,-9,pi])
3
julia> indmin([7,1,1,6])
2
julia> indmin([7,1,1,NaN])
2
```
"""
indmin(a) = findmin(a)[2]
# similar to Matlab's ismember
"""
indexin(a, b)
Returns a vector containing the highest index in `b` for
each value in `a` that is a member of `b` . The output
vector contains 0 wherever `a` is not a member of `b`.
```jldoctest
julia> a = ['a', 'b', 'c', 'b', 'd', 'a'];
julia> b = ['a','b','c'];
julia> indexin(a,b)
6-element Array{Int64,1}:
1
2
3
2
0
1
julia> indexin(b,a)
3-element Array{Int64,1}:
6
4
3
```
"""
function indexin(a::AbstractArray, b::AbstractArray)
bdict = Dict(zip(b, 1:length(b)))
[get(bdict, i, 0) for i in a]
end
"""
findin(a, b)
Returns the indices of elements in collection `a` that appear in collection `b`.
```jldoctest
julia> a = collect(1:3:15)
5-element Array{Int64,1}:
1
4
7
10
13
julia> b = collect(2:4:10)
3-element Array{Int64,1}:
2
6
10
julia> findin(a,b) # 10 is the only common element
1-element Array{Int64,1}:
4
```
"""
function findin(a, b)
ind = Array{Int,1}(0)
bset = Set(b)
@inbounds for (i,ai) in enumerate(a)
ai in bset && push!(ind, i)
end
ind
end
# Copying subregions
# TODO: DEPRECATE FOR #14770
function indcopy(sz::Dims, I::Vector)
n = length(I)
s = sz[n]
for i = n+1:length(sz)
s *= sz[i]
end
dst = eltype(I)[findin(I[i], i < n ? (1:sz[i]) : (1:s)) for i = 1:n]
src = eltype(I)[I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))] for i = 1:n]
dst, src
end
function indcopy(sz::Dims, I::Tuple{Vararg{RangeIndex}})
n = length(I)
s = sz[n]
for i = n+1:length(sz)
s *= sz[i]
end
dst::typeof(I) = ntuple(i-> findin(I[i], i < n ? (1:sz[i]) : (1:s)), n)::typeof(I)
src::typeof(I) = ntuple(i-> I[i][findin(I[i], i < n ? (1:sz[i]) : (1:s))], n)::typeof(I)
dst, src
end
## Filter ##
"""
filter(function, collection)
Return a copy of `collection`, removing elements for which `function` is `false`. For
associative collections, the function is passed two arguments (key and value).
```jldocttest
julia> a = 1:10
1:10
julia> filter(isodd, a)
5-element Array{Int64,1}:
1
3
5
7
9
```
"""
filter(f, As::AbstractArray) = As[map(f, As)::AbstractArray{Bool}]
function filter!(f, a::Vector)
insrt = 1
for acurr in a
if f(acurr)
a[insrt] = acurr
insrt += 1
end
end
deleteat!(a, insrt:length(a))
return a
end
function filter(f, a::Vector)
r = Array{eltype(a)}(0)
for ai in a
if f(ai)
push!(r, ai)
end
end
return r
end
# set-like operators for vectors
# These are moderately efficient, preserve order, and remove dupes.
function intersect(v1, vs...)
ret = Array{promote_eltype(v1, vs...)}(0)
for v_elem in v1
inall = true
for vsi in vs
if !in(v_elem, vsi)
inall=false; break
end
end
if inall
push!(ret, v_elem)
end
end
ret
end
function union(vs...)
ret = Array{promote_eltype(vs...)}(0)
seen = Set()
for v in vs
for v_elem in v
if !in(v_elem, seen)
push!(ret, v_elem)
push!(seen, v_elem)
end
end
end
ret
end
# setdiff only accepts two args
"""
setdiff(a, b)
Construct the set of elements in `a` but not `b`. Maintains order with arrays. Note that
both arguments must be collections, and both will be iterated over. In particular,
`setdiff(set,element)` where `element` is a potential member of `set`, will not work in
general.
```jldoctest
julia> setdiff([1,2,3],[3,4,5])
2-element Array{Int64,1}:
1
2
```
"""
function setdiff(a, b)
args_type = promote_type(eltype(a), eltype(b))
bset = Set(b)
ret = Array{args_type,1}(0)
seen = Set{eltype(a)}()
for a_elem in a
if !in(a_elem, seen) && !in(a_elem, bset)
push!(ret, a_elem)
push!(seen, a_elem)
end
end
ret
end
# symdiff is associative, so a relatively clean
# way to implement this is by using setdiff and union, and
# recursing. Has the advantage of keeping order, too, but
# not as fast as other methods that make a single pass and
# store counts with a Dict.
symdiff(a) = a
symdiff(a, b) = union(setdiff(a,b), setdiff(b,a))
"""
symdiff(a, b, rest...)
Construct the symmetric difference of elements in the passed in sets or arrays.
Maintains order with arrays.
```jldoctest
julia> symdiff([1,2,3],[3,4,5],[4,5,6])
3-element Array{Int64,1}:
1
2
6
```
"""
symdiff(a, b, rest...) = symdiff(a, symdiff(b, rest...))
# This file is a part of Julia. License is MIT: http://julialang.org/license
## Unary operators ##
"""
conj!(A)
Transform an array to its complex conjugate in-place.
See also [`conj`](:func:`conj`).
"""
function conj!{T<:Number}(A::AbstractArray{T})
for i in eachindex(A)
A[i] = conj(A[i])
end
return A
end
for f in (:-, :~, :conj, :sign)
@eval begin
function ($f)(A::AbstractArray)
F = similar(A)
RF, RA = eachindex(F), eachindex(A)
if RF == RA
for i in RA
F[i] = ($f)(A[i])
end
else
for (iF, iA) in zip(RF, RA)
F[iF] = ($f)(A[iA])
end
end
return F
end
end
end
(-)(A::AbstractArray{Bool}) = reshape([ -A[i] for i in eachindex(A) ], size(A))
real(A::AbstractArray) = reshape([ real(x) for x in A ], size(A))
imag(A::AbstractArray) = reshape([ imag(x) for x in A ], size(A))
function !(A::AbstractArray{Bool})
F = similar(A)
RF, RA = eachindex(F), eachindex(A)
if RF == RA
for i in RA
F[i] = !A[i]
end
else
for (iF, iA) in zip(RF, RA)
F[iF] = !A[iA]
end
end
return F
end
## Binary arithmetic operators ##
promote_array_type(F, ::Type, ::Type, T::Type) = T
promote_array_type{S<:Real, A<:AbstractFloat}(F, ::Type{S}, ::Type{A}, ::Type) = A
promote_array_type{S<:Integer, A<:Integer}(F, ::Type{S}, ::Type{A}, ::Type) = A
promote_array_type{S<:Integer, A<:Integer}(::typeof(./), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer, A<:Integer}(::typeof(.\), ::Type{S}, ::Type{A}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(./), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer}(::typeof(.\), ::Type{S}, ::Type{Bool}, T::Type) = T
promote_array_type{S<:Integer}(F, ::Type{S}, ::Type{Bool}, T::Type) = T
for f in (:+, :-, :div, :mod, :&, :|, :$)
@eval ($f)(A::AbstractArray, B::AbstractArray) =
_elementwise($f, promote_eltype_op($f, A, B), A, B)
end
function _elementwise(op, ::Type{Any}, A::AbstractArray, B::AbstractArray)
promote_shape(A, B) # check size compatibility
return broadcast(op, A, B)
end
function _elementwise{T}(op, ::Type{T}, A::AbstractArray, B::AbstractArray)
F = similar(A, T, promote_shape(A, B))
RF, RA, RB = eachindex(F), eachindex(A), eachindex(B)
if RF == RA == RB
for i in RA
@inbounds F[i] = op(A[i], B[i])
end
else
for (iF, iA, iB) in zip(RF, RA, RB)
@inbounds F[iF] = op(A[iA], B[iB])
end
end
return F
end
for f in (:.+, :.-, :.*, :./, :.\, :.^, :.÷, :.%, :.<<, :.>>, :div, :mod, :rem, :&, :|, :$)
@eval begin
function ($f){T}(A::Number, B::AbstractArray{T})
R = promote_op($f, typeof(A), T)
S = promote_array_type($f, typeof(A), T, R)
S === Any && return [($f)(A, b) for b in B]
F = similar(B, S)
RF, RB = eachindex(F), eachindex(B)
if RF == RB
for i in RB
@inbounds F[i] = ($f)(A, B[i])
end
else
for (iF, iB) in zip(RF, RB)
@inbounds F[iF] = ($f)(A, B[iB])
end
end
return F
end
function ($f){T}(A::AbstractArray{T}, B::Number)
R = promote_op($f, T, typeof(B))
S = promote_array_type($f, typeof(B), T, R)
S === Any && return [($f)(a, B) for a in A]
F = similar(A, S)
RF, RA = eachindex(F), eachindex(A)
if RF == RA
for i in RA
@inbounds F[i] = ($f)(A[i], B)
end
else
for (iF, iA) in zip(RF, RA)
@inbounds F[iF] = ($f)(A[iA], B)
end
end
return F
end
end
end
# familiar aliases for broadcasting operations of array ± scalar (#7226):
(+)(A::AbstractArray{Bool},x::Bool) = A .+ x
(+)(x::Bool,A::AbstractArray{Bool}) = x .+ A
(-)(A::AbstractArray{Bool},x::Bool) = A .- x
(-)(x::Bool,A::AbstractArray{Bool}) = x .- A
(+)(A::AbstractArray,x::Number) = A .+ x
(+)(x::Number,A::AbstractArray) = x .+ A
(-)(A::AbstractArray,x::Number) = A .- x
(-)(x::Number,A::AbstractArray) = x .- A
## data movement ##
function flipdim{T}(A::Array{T}, d::Integer)
nd = ndims(A)
1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
sd = size(A, d)
if sd == 1 || isempty(A)
return copy(A)
end
B = similar(A)
nnd = 0
for i = 1:nd
nnd += Int(size(A,i)==1 || i==d)
end
if nnd==nd
# flip along the only non-singleton dimension
for i = 1:sd
B[i] = A[sd+1-i]
end
return B
end
d_in = size(A)
leading = d_in[1:(d-1)]
M = prod(leading)
N = length(A)
stride = M * sd
if M==1
for j = 0:stride:(N-stride)
for i = 1:sd
ri = sd+1-i
B[j + ri] = A[j + i]
end
end
else
if isbits(T) && M>200
for i = 1:sd
ri = sd+1-i
for j=0:stride:(N-stride)
offs = j + 1 + (i-1)*M
boffs = j + 1 + (ri-1)*M
copy!(B, boffs, A, offs, M)
end
end
else
for i = 1:sd
ri = sd+1-i
for j=0:stride:(N-stride)
offs = j + 1 + (i-1)*M
boffs = j + 1 + (ri-1)*M
for k=0:(M-1)
B[boffs + k] = A[offs + k]
end
end
end
end
end
return B
end
"""
rotl90(A)
Rotate matrix `A` left 90 degrees.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotl90(a)
2×2 Array{Int64,2}:
2 4
1 3
```
"""
function rotl90(A::AbstractMatrix)
ind1, ind2 = indices(A)
B = similar(A, (ind2,ind1))
n = first(ind2)+last(ind2)
for i=indices(A,1), j=ind2
B[n-j,i] = A[i,j]
end
return B
end
"""
rotr90(A)
Rotate matrix `A` right 90 degrees.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotr90(a)
2×2 Array{Int64,2}:
3 1
4 2
```
"""
function rotr90(A::AbstractMatrix)
ind1, ind2 = indices(A)
B = similar(A, (ind2,ind1))
m = first(ind1)+last(ind1)
for i=ind1, j=indices(A,2)
B[j,m-i] = A[i,j]
end
return B
end
"""
rot180(A)
Rotate matrix `A` 180 degrees.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rot180(a)
2×2 Array{Int64,2}:
4 3
2 1
```
"""
function rot180(A::AbstractMatrix)
B = similar(A)
ind1, ind2 = indices(A,1), indices(A,2)
m, n = first(ind1)+last(ind1), first(ind2)+last(ind2)
for j=ind2, i=ind1
B[m-i,n-j] = A[i,j]
end
return B
end
"""
rotl90(A, k)
Rotate matrix `A` left 90 degrees an integer `k` number of times.
If `k` is zero or a multiple of four, this is equivalent to a `copy`.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotl90(a,1)
2×2 Array{Int64,2}:
2 4
1 3
julia> rotl90(a,2)
2×2 Array{Int64,2}:
4 3
2 1
julia> rotl90(a,3)
2×2 Array{Int64,2}:
3 1
4 2
julia> rotl90(a,4)
2×2 Array{Int64,2}:
1 2
3 4
```
"""
function rotl90(A::AbstractMatrix, k::Integer)
k = mod(k, 4)
k == 1 ? rotl90(A) :
k == 2 ? rot180(A) :
k == 3 ? rotr90(A) : copy(A)
end
"""
rotr90(A, k)
Rotate matrix `A` right 90 degrees an integer `k` number of times. If `k` is zero or a
multiple of four, this is equivalent to a `copy`.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rotr90(a,1)
2×2 Array{Int64,2}:
3 1
4 2
julia> rotr90(a,2)
2×2 Array{Int64,2}:
4 3
2 1
julia> rotr90(a,3)
2×2 Array{Int64,2}:
2 4
1 3
julia> rotr90(a,4)
2×2 Array{Int64,2}:
1 2
3 4
```
"""
rotr90(A::AbstractMatrix, k::Integer) = rotl90(A,-k)
"""
rot180(A, k)
Rotate matrix `A` 180 degrees an integer `k` number of times.
If `k` is even, this is equivalent to a `copy`.
```jldoctest
julia> a = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> rot180(a,1)
2×2 Array{Int64,2}:
4 3
2 1
julia> rot180(a,2)
2×2 Array{Int64,2}:
1 2
3 4
```
"""
rot180(A::AbstractMatrix, k::Integer) = mod(k, 2) == 1 ? rot180(A) : copy(A)
## Transpose ##
"""
transpose!(dest,src)
Transpose array `src` and store the result in the preallocated array `dest`, which should
have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition is
supported and unexpected results will happen if `src` and `dest` have overlapping memory
regions.
"""
transpose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(transpose, B, A)
"""
ctranspose!(dest,src)
Conjugate transpose array `src` and store the result in the preallocated array `dest`, which
should have a size corresponding to `(size(src,2),size(src,1))`. No in-place transposition
is supported and unexpected results will happen if `src` and `dest` have overlapping memory
regions.
"""
ctranspose!(B::AbstractMatrix, A::AbstractMatrix) = transpose_f!(ctranspose, B, A)
function transpose!(B::AbstractVector, A::AbstractMatrix)
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
copy!(B, A)
end
function transpose!(B::AbstractMatrix, A::AbstractVector)
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
copy!(B, A)
end
function ctranspose!(B::AbstractVector, A::AbstractMatrix)
indices(B,1) == indices(A,2) && indices(A,1) == 1:1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end
function ctranspose!(B::AbstractMatrix, A::AbstractVector)
indices(B,2) == indices(A,1) && indices(B,1) == 1:1 || throw(DimensionMismatch("transpose"))
ccopy!(B, A)
end
const transposebaselength=64
function transpose_f!(f,B::AbstractMatrix,A::AbstractMatrix)
inds = indices(A)
indices(B,1) == inds[2] && indices(B,2) == inds[1] || throw(DimensionMismatch(string(f)))
m, n = length(inds[1]), length(inds[2])
if m*n<=4*transposebaselength
@inbounds begin
for j = inds[2]
for i = inds[1]
B[j,i] = f(A[i,j])
end
end
end
else
transposeblock!(f,B,A,m,n,first(inds[1])-1,first(inds[2])-1)
end
return B
end
function transposeblock!(f,B::AbstractMatrix,A::AbstractMatrix,m::Int,n::Int,offseti::Int,offsetj::Int)
if m*n<=transposebaselength
@inbounds begin
for j = offsetj+(1:n)
for i = offseti+(1:m)
B[j,i] = f(A[i,j])
end
end
end
elseif m>n
newm=m>>1
transposeblock!(f,B,A,newm,n,offseti,offsetj)
transposeblock!(f,B,A,m-newm,n,offseti+newm,offsetj)
else
newn=n>>1
transposeblock!(f,B,A,m,newn,offseti,offsetj)
transposeblock!(f,B,A,m,n-newn,offseti,offsetj+newn)
end
return B
end
function ccopy!(B, A)
RB, RA = eachindex(B), eachindex(A)
if RB == RA
for i = RB
B[i] = ctranspose(A[i])
end
else
for (i,j) = zip(RB, RA)
B[i] = ctranspose(A[j])
end
end
end
"""
transpose(A)
The transposition operator (`.'`).
"""
function transpose(A::AbstractMatrix)
ind1, ind2 = indices(A)
B = similar(A, (ind2, ind1))
transpose!(B, A)
end
function ctranspose(A::AbstractMatrix)
ind1, ind2 = indices(A)
B = similar(A, (ind2, ind1))
ctranspose!(B, A)
end
ctranspose{T<:Real}(A::AbstractVecOrMat{T}) = transpose(A)
transpose(x::AbstractVector) = [ transpose(v) for i=of_indices(x, OneTo(1)), v in x ]
ctranspose{T}(x::AbstractVector{T}) = T[ ctranspose(v) for i=of_indices(x, OneTo(1)), v in x ]
# see discussion in #18364 ... we try not to widen type of the resulting array
# from cumsum or cumprod, but in some cases (+, Bool) we may not have a choice.
rcum_promote_type{T<:Number}(op, ::Type{T}) = promote_op(op, T)
rcum_promote_type{T}(op, ::Type{T}) = T
# handle sums of Vector{Bool} and similar. it would be nice to handle
# any AbstractArray here, but it's not clear how that would be possible
rcum_promote_type{T,N}(op, ::Type{Array{T,N}}) = Array{rcum_promote_type(op,T), N}
for (f, f!, fp, op) = ((:cumsum, :cumsum!, :cumsum_pairwise!, :+),
(:cumprod, :cumprod!, :cumprod_pairwise!, :*) )
# in-place cumsum of c = s+v[range(i1,n)], using pairwise summation
@eval function ($fp){T}(v::AbstractVector, c::AbstractVector{T}, s, i1, n)
local s_::T # for sum(v[range(i1,n)]), i.e. sum without s
if n < 128
@inbounds s_ = v[i1]
@inbounds c[i1] = ($op)(s, s_)
for i = i1+1:i1+n-1
@inbounds s_ = $(op)(s_, v[i])
@inbounds c[i] = $(op)(s, s_)
end
else
n2 = n >> 1
s_ = ($fp)(v, c, s, i1, n2)
s_ = $(op)(s_, ($fp)(v, c, ($op)(s, s_), i1+n2, n-n2))
end
return s_
end
@eval function ($f!)(result::AbstractVector, v::AbstractVector)
li = linearindices(v)
li != linearindices(result) && throw(DimensionMismatch("input and output array sizes and indices must match"))
n = length(li)
if n == 0; return result; end
i1 = first(li)
@inbounds result[i1] = v1 = v[i1]
n == 1 && return result
($fp)(v, result, v1, i1+1, n-1)
return result
end
@eval function ($f){T}(v::AbstractVector{T})
return ($f!)(similar(v, rcum_promote_type($op, T)), v)
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# generic operations on associative collections
const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__
haskey(d::Associative, k) = in(k,keys(d))
function in(p::Pair, a::Associative, valcmp=(==))
v = get(a,p[1],secret_table_token)
if v !== secret_table_token
valcmp(v, p[2]) && return true
end
return false
end
function in(p, a::Associative)
error("""Associative collections only contain Pairs;
Either look for e.g. A=>B instead, or use the `keys` or `values`
function if you are looking for a key or value respectively.""")
end
function summary(t::Associative)
n = length(t)
return string(typeof(t), " with ", n, (n==1 ? " entry" : " entries"))
end
immutable KeyIterator{T<:Associative}
dict::T
end
immutable ValueIterator{T<:Associative}
dict::T
end
summary{T<:Union{KeyIterator,ValueIterator}}(iter::T) =
string(T.name, " for a ", summary(iter.dict))
show(io::IO, iter::Union{KeyIterator,ValueIterator}) = show(io, collect(iter))
length(v::Union{KeyIterator,ValueIterator}) = length(v.dict)
isempty(v::Union{KeyIterator,ValueIterator}) = isempty(v.dict)
_tt1{A,B}(::Type{Pair{A,B}}) = A
_tt2{A,B}(::Type{Pair{A,B}}) = B
eltype{D}(::Type{KeyIterator{D}}) = _tt1(eltype(D))
eltype{D}(::Type{ValueIterator{D}}) = _tt2(eltype(D))
start(v::Union{KeyIterator,ValueIterator}) = start(v.dict)
done(v::Union{KeyIterator,ValueIterator}, state) = done(v.dict, state)
function next(v::KeyIterator, state)
n = next(v.dict, state)
n[1][1], n[2]
end
function next(v::ValueIterator, state)
n = next(v.dict, state)
n[1][2], n[2]
end
in(k, v::KeyIterator) = get(v.dict, k, secret_table_token) !== secret_table_token
"""
keys(a::Associative)
Return an iterator over all keys in a collection.
`collect(keys(d))` returns an array of keys.
Since the keys are stored internally in a hash table,
the order in which they are returned may vary.
```jldoctest
julia> a = Dict('a'=>2, 'b'=>3)
Dict{Char,Int64} with 2 entries:
'b' => 3
'a' => 2
julia> collect(keys(a))
2-element Array{Char,1}:
'b'
'a'
```
"""
keys(a::Associative) = KeyIterator(a)
eachindex(a::Associative) = KeyIterator(a)
"""
values(a::Associative)
Return an iterator over all values in a collection.
`collect(values(d))` returns an array of values.
```jldoctest
julia> a = Dict('a'=>2, 'b'=>3)
Dict{Char,Int64} with 2 entries:
'b' => 3
'a' => 2
julia> collect(values(a))
2-element Array{Int64,1}:
3
2
```
"""
values(a::Associative) = ValueIterator(a)
function copy(a::Associative)
b = similar(a)
for (k,v) in a
b[k] = v
end
return b
end
"""
merge!(d::Associative, others::Associative...)
Update collection with pairs from the other collections.
See also [`merge`](:func:`merge`).
"""
function merge!(d::Associative, others::Associative...)
for other in others
for (k,v) in other
d[k] = v
end
end
return d
end
# very similar to `merge!`, but accepts any iterable and extends code
# that would otherwise only use `copy!` with arrays.
function copy!(dest::Union{Associative,AbstractSet}, src)
for x in src
push!(dest, x)
end
return dest
end
"""
keytype(type)
Get the key type of an associative collection type. Behaves similarly to [`eltype`](:func:`eltype`).
"""
keytype{K,V}(::Type{Associative{K,V}}) = K
keytype(a::Associative) = keytype(typeof(a))
keytype{A<:Associative}(::Type{A}) = keytype(supertype(A))
"""
valtype(type)
Get the value type of an associative collection type. Behaves similarly to [`eltype`](:func:`eltype`).
"""
valtype{K,V}(::Type{Associative{K,V}}) = V
valtype{A<:Associative}(::Type{A}) = valtype(supertype(A))
valtype(a::Associative) = valtype(typeof(a))
"""
merge(d::Associative, others::Associative...)
Construct a merged collection from the given collections. If necessary, the
types of the resulting collection will be promoted to accommodate the types of
the merged collections. If the same key is present in another collection, the
value for that key will be the value it has in the last collection listed.
```jldoctest
julia> a = Dict("foo" => 0.0, "bar" => 42.0)
Dict{String,Float64} with 2 entries:
"bar" => 42.0
"foo" => 0.0
julia> b = Dict("baz" => 17, "bar" => 4711)
Dict{String,Int64} with 2 entries:
"bar" => 4711
"baz" => 17
julia> merge(a, b)
Dict{String,Float64} with 3 entries:
"bar" => 4711.0
"baz" => 17.0
"foo" => 0.0
julia> merge(b, a)
Dict{String,Float64} with 3 entries:
"bar" => 42.0
"baz" => 17.0
"foo" => 0.0
```
"""
function merge(d::Associative, others::Associative...)
K, V = keytype(d), valtype(d)
for other in others
K = promote_type(K, keytype(other))
V = promote_type(V, valtype(other))
end
merge!(Dict{K,V}(), d, others...)
end
function filter!(f, d::Associative)
badkeys = Array{keytype(d)}(0)
for (k,v) in d
# don't delete!(d, k) here, since associative types
# may not support mutation during iteration
f(k,v) || push!(badkeys, k)
end
for k in badkeys
delete!(d, k)
end
return d
end
function filter(f, d::Associative)
# don't just do filter!(f, copy(d)): avoid making a whole copy of d
df = similar(d)
for (k,v) in d
if f(k,v)
df[k] = v
end
end
return df
end
eltype{K,V}(::Type{Associative{K,V}}) = Pair{K,V}
function isequal(l::Associative, r::Associative)
l === r && return true
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
return false
end
if length(l) != length(r) return false end
for pair in l
if !in(pair, r, isequal)
return false
end
end
true
end
function ==(l::Associative, r::Associative)
l === r && return true
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
return false
end
if length(l) != length(r) return false end
for pair in l
if !in(pair, r, ==)
return false
end
end
true
end
const hasha_seed = UInt === UInt64 ? 0x6d35bb51952d5539 : 0x952d5539
function hash(a::Associative, h::UInt)
h = hash(hasha_seed, h)
for (k,v) in a
h $= hash(k, hash(v))
end
return h
end
function getindex(t::Associative, key)
v = get(t, key, secret_table_token)
if v === secret_table_token
throw(KeyError(key))
end
return v
end
# t[k1,k2,ks...] is syntactic sugar for t[(k1,k2,ks...)]. (Note
# that we need to avoid dispatch loops if setindex!(t,v,k) is not defined.)
getindex(t::Associative, k1, k2, ks...) = getindex(t, tuple(k1,k2,ks...))
setindex!(t::Associative, v, k1, k2, ks...) = setindex!(t, v, tuple(k1,k2,ks...))
push!(t::Associative, p::Pair) = setindex!(t, p.second, p.first)
push!(t::Associative, p::Pair, q::Pair) = push!(push!(t, p), q)
push!(t::Associative, p::Pair, q::Pair, r::Pair...) = push!(push!(push!(t, p), q), r...)
# hashing objects by identity
type ObjectIdDict <: Associative{Any,Any}
ht::Vector{Any}
ndel::Int
ObjectIdDict() = new(Vector{Any}(32), 0)
function ObjectIdDict(itr)
d = ObjectIdDict()
for (k,v) in itr; d[k] = v; end
d
end
function ObjectIdDict(pairs::Pair...)
d = ObjectIdDict()
for (k,v) in pairs; d[k] = v; end
d
end
ObjectIdDict(o::ObjectIdDict) = new(copy(o.ht))
end
similar(d::ObjectIdDict) = ObjectIdDict()
function rehash!(t::ObjectIdDict, newsz = length(t.ht))
t.ht = ccall(:jl_idtable_rehash, Any, (Any, Csize_t), t.ht, newsz)
t
end
function setindex!(t::ObjectIdDict, v::ANY, k::ANY)
if t.ndel >= ((3*length(t.ht))>>2)
rehash!(t, max(length(t.ht)>>1, 32))
t.ndel = 0
end
t.ht = ccall(:jl_eqtable_put, Array{Any,1}, (Any, Any, Any), t.ht, k, v)
return t
end
get(t::ObjectIdDict, key::ANY, default::ANY) =
ccall(:jl_eqtable_get, Any, (Any, Any, Any), t.ht, key, default)
function pop!(t::ObjectIdDict, key::ANY, default::ANY)
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any), t.ht, key, default)
# TODO: this can underestimate `ndel`
val === default || (t.ndel += 1)
return val
end
function pop!(t::ObjectIdDict, key::ANY)
val = pop!(t, key, secret_table_token)
val !== secret_table_token ? val : throw(KeyError(key))
end
function delete!(t::ObjectIdDict, key::ANY)
pop!(t, key, secret_table_token)
t
end
empty!(t::ObjectIdDict) = (t.ht = Vector{Any}(length(t.ht)); t.ndel = 0; t)
_oidd_nextind(a, i) = reinterpret(Int,ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i))
start(t::ObjectIdDict) = _oidd_nextind(t.ht, 0)
done(t::ObjectIdDict, i) = (i == -1)
next(t::ObjectIdDict, i) = (Pair{Any,Any}(t.ht[i+1],t.ht[i+2]), _oidd_nextind(t.ht, i+2))
function length(d::ObjectIdDict)
n = 0
for pair in d
n+=1
end
n
end
copy(o::ObjectIdDict) = ObjectIdDict(o)
get!(o::ObjectIdDict, key, default) = (o[key] = get(o, key, default))
# This file is a part of Julia. License is MIT: http://julialang.org/license
using Base.Iterators.Enumerate
"""
AsyncCollector(f, results, c...; ntasks=0) -> iterator
Apply `f` to each element of `c` using at most `ntasks` asynchronous
tasks.
If `ntasks` is unspecified, uses `max(100, nworkers())` tasks.
For multiple collection arguments, apply `f` elementwise.
Output is collected into `results`.
Note: `next(::AsyncCollector, state) -> (nothing, state)`
Note: `for task in AsyncCollector(f, results, c...) end` is equivalent to
`map!(f, results, c...)`.
"""
type AsyncCollector
f
results
enumerator::Enumerate
max_tasks::Function
task_chnl::Channel{Tuple{Int, Any}} # to communicate with the tasks
AsyncCollector(f, r, en::Enumerate, mt::Function, c::Channel) = new(f, r, en, mt, c)
end
function AsyncCollector(f, results, c...; ntasks=0)
if ntasks == 0
ntasks = max(nworkers(), 100)
max_tasks = ()->ntasks
elseif isa(ntasks, Integer)
max_tasks = ()->ntasks
elseif isa(ntasks, Function)
max_tasks = ntasks
else
throw(ArgumentError("ntasks must be an Integer or a zero-arg function returning the maximum number of tasks allowed."))
end
AsyncCollector(f, results, enumerate(zip(c...)), max_tasks, Channel{Tuple{Int, Any}}(typemax(Int)))
end
type AsyncCollectorState
enum_state
active_count::Int
item_done::Condition
done::Bool
in_error::Bool
nfree::Int # number of free tasks
end
isbusy(itr::AsyncCollector, state::AsyncCollectorState) = (state.nfree == 0)
# Wait for @async task to end.
wait(state::AsyncCollectorState) = wait(state.item_done)
function start_collector_task(itr::AsyncCollector, state::AsyncCollectorState)
t = @async begin
try
for (i, args) in itr.task_chnl
state.nfree -= 1
itr.results[i] = itr.f(args...)
notify(state.item_done, nothing)
state.nfree += 1
end
catch e
# The in_error flag causes done() to end the iteration early and call sync_end().
# sync_end() then re-throws "e" in the main task.
state.in_error = true
clear_collector_channel(itr)
notify(state.item_done, nothing)
rethrow(e)
end
end
state.active_count += 1
t
end
function clear_collector_channel(itr::AsyncCollector)
try
# empty out the channel and close it, ignore any errors in doing this
while isready(itr.task_chnl)
take!(itr.task_chnl)
end
close(itr.task_chnl)
catch
end
nothing
end
# Open a @sync block and initialise iterator state.
function start(itr::AsyncCollector)
sync_begin()
state = AsyncCollectorState(start(itr.enumerator), 0, Condition(), false, false, 0)
for _ in 1:itr.max_tasks()
start_collector_task(itr, state)
state.nfree += 1
end
state
end
# Close @sync block when iterator is done.
function done(itr::AsyncCollector, state::AsyncCollectorState)
if state.in_error
@assert !isopen(itr.task_chnl) # Channel should have been cleared and closed in the async task.
sync_end()
# state.in_error is only being set in the @async block (and an error thrown),
# which in turn should have been caught and thrown by the sync_end() call above.
# Control should not come here.
@assert false "Error should have been captured and thrown previously."
end
if !state.done && done(itr.enumerator, state.enum_state)
state.done = true
close(itr.task_chnl)
sync_end()
end
return state.done
end
function next(itr::AsyncCollector, state::AsyncCollectorState)
# start a task if required.
# Note: Shouldn't need to check on every iteration. Do this at a periodic interval?
if state.active_count < itr.max_tasks()
start_collector_task(itr, state)
end
while isbusy(itr, state)
wait(state)
if state.in_error
# Stop processing immediately on error.
return (nothing, state)
end
end
# Get index and mapped function arguments from enumeration iterator.
(i, args), state.enum_state = next(itr.enumerator, state.enum_state)
put!(itr.task_chnl, (i, args))
return (nothing, state)
end
"""
AsyncGenerator(f, c...; ntasks=0) -> iterator
Apply `f` to each element of `c` using at most `ntasks` asynchronous tasks.
If `ntasks` is unspecified, uses `max(100, nworkers())` tasks.
For multiple collection arguments, apply f elementwise.
Results are returned by the iterator as they become available.
Note: `collect(AsyncGenerator(f, c...; ntasks=1))` is equivalent to
`map(f, c...)`.
"""
type AsyncGenerator
collector::AsyncCollector
end
function AsyncGenerator(f, c...; ntasks=0)
AsyncGenerator(AsyncCollector(f, Dict{Int,Any}(), c...; ntasks=ntasks))
end
type AsyncGeneratorState
i::Int
async_state::AsyncCollectorState
end
start(itr::AsyncGenerator) = AsyncGeneratorState(0, start(itr.collector))
# Done when source async collector is done and all results have been consumed.
function done(itr::AsyncGenerator, state::AsyncGeneratorState)
done(itr.collector, state.async_state) && isempty(itr.collector.results)
end
# Pump the source async collector if it is not already busy.
function pump_source(itr::AsyncGenerator, state::AsyncGeneratorState)
if !isbusy(itr.collector, state.async_state) &&
!done(itr.collector, state.async_state)
ignored, state.async_state = next(itr.collector, state.async_state)
return true
else
return false
end
end
function next(itr::AsyncGenerator, state::AsyncGeneratorState)
state.i += 1
results = itr.collector.results
while !haskey(results, state.i)
# Wait for results to become available.
if !pump_source(itr,state) && !haskey(results, state.i)
wait(state.async_state)
end
end
r = results[state.i]
delete!(results, state.i)
return (r, state)
end
# pass-through iterator traits to the iterable
# on which the mapping function is being applied
iteratorsize(itr::AsyncGenerator) = iteratorsize(itr.collector.enumerator)
size(itr::AsyncGenerator) = size(itr.collector.enumerator)
length(itr::AsyncGenerator) = length(itr.collector.enumerator)
"""
asyncmap(f, c...) -> collection
Transform collection `c` by applying `@async f` to each element.
For multiple collection arguments, apply f elementwise.
"""
asyncmap(f, c...) = collect(AsyncGenerator(f, c...))
"""
asyncmap!(f, c)
In-place version of `asyncmap()`.
"""
asyncmap!(f, c) = (for x in AsyncCollector(f, c, c) end; c)
"""
asyncmap!(f, results, c...)
Like `asyncmap()`, but stores output in `results` rather returning a collection.
"""
asyncmap!(f, r, c1, c...) = (for x in AsyncCollector(f, r, c1, c...) end; r)
# This file is a part of Julia. License is MIT: http://julialang.org/license
using Core.Intrinsics: llvmcall
import Base: setindex!, getindex, unsafe_convert
import Base.Sys: ARCH, WORD_SIZE
export
Atomic,
atomic_cas!,
atomic_xchg!,
atomic_add!, atomic_sub!,
atomic_and!, atomic_nand!, atomic_or!, atomic_xor!,
atomic_max!, atomic_min!,
atomic_fence
# Disable 128-bit types on 32-bit Intel sytems due to LLVM problems;
# see <https://github.com/JuliaLang/julia/issues/14818> (fixed on LLVM 3.9)
# 128-bit atomics do not exist on AArch32.
if (VersionNumber(Base.libllvm_version) < v"3.9-" && ARCH === :i686) ||
startswith(string(ARCH), "arm")
const inttypes = (Int8, Int16, Int32, Int64,
UInt8, UInt16, UInt32, UInt64)
else
const inttypes = (Int8, Int16, Int32, Int64, Int128,
UInt8, UInt16, UInt32, UInt64, UInt128)
end
const floattypes = (Float16, Float32, Float64)
# TODO: Support Bool, Ptr
const atomictypes = (inttypes..., floattypes...)
typealias IntTypes Union{inttypes...}
typealias FloatTypes Union{floattypes...}
typealias AtomicTypes Union{atomictypes...}
"""
Threads.Atomic{T}
Holds a reference to an object of type `T`, ensuring that it is only
accessed atomically, i.e. in a thread-safe manner.
Only certain "simple" types can be used atomically, namely the
bitstypes integer and float-point types. These are `Int8`...`Int128`,
`UInt8`...`UInt128`, and `Float16`...`Float64`.
New atomic objects can be created from a non-atomic values; if none is
specified, the atomic object is initialized with zero.
Atomic objects can be accessed using the `[]` notation:
```Julia
x::Atomic{Int}
x[] = 1
val = x[]
```
Atomic operations use an `atomic_` prefix, such as `atomic_add!`,
`atomic_xchg!`, etc.
"""
type Atomic{T<:AtomicTypes}
value::T
Atomic() = new(zero(T))
Atomic(value) = new(value)
end
Atomic() = Atomic{Int}()
"""
Threads.atomic_cas!{T}(x::Atomic{T}, cmp::T, newval::T)
Atomically compare-and-set `x`
Atomically compares the value in `x` with `cmp`. If equal, write
`newval` to `x`. Otherwise, leaves `x` unmodified. Returns the old
value in `x`. By comparing the returned value to `cmp` (via `===`) one
knows whether `x` was modified and now holds the new value `newval`.
For further details, see LLVM's `cmpxchg` instruction.
This function can be used to implement transactional semantics. Before
the transaction, one records the value in `x`. After the transaction,
the new value is stored only if `x` has not been modified in the mean
time.
"""
function atomic_cas! end
"""
Threads.atomic_xchg!{T}(x::Atomic{T}, newval::T)
Atomically exchange the value in `x`
Atomically exchanges the value in `x` with `newval`. Returns the old
value.
For further details, see LLVM's `atomicrmw xchg` instruction.
"""
function atomic_xchg! end
"""
Threads.atomic_add!{T}(x::Atomic{T}, val::T)
Atomically add `val` to `x`
Performs `x[] += val` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw add` instruction.
"""
function atomic_add! end
"""
Threads.atomic_sub!{T}(x::Atomic{T}, val::T)
Atomically subtract `val` from `x`
Performs `x[] -= val` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw sub` instruction.
"""
function atomic_sub! end
"""
Threads.atomic_and!{T}(x::Atomic{T}, val::T)
Atomically bitwise-and `x` with `val`
Performs `x[] &= val` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw and` instruction.
"""
function atomic_and! end
"""
Threads.atomic_nand!{T}(x::Atomic{T}, val::T)
Atomically bitwise-nand (not-and) `x` with `val`
Performs `x[] = ~(x[] & val)` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw nand` instruction.
"""
function atomic_nand! end
"""
Threads.atomic_or!{T}(x::Atomic{T}, val::T)
Atomically bitwise-or `x` with `val`
Performs `x[] |= val` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw or` instruction.
"""
function atomic_or! end
"""
Threads.atomic_xor!{T}(x::Atomic{T}, val::T)
Atomically bitwise-xor (exclusive-or) `x` with `val`
Performs `x[] \$= val` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw xor` instruction.
"""
function atomic_xor! end
"""
Threads.atomic_max!{T}(x::Atomic{T}, val::T)
Atomically store the maximum of `x` and `val` in `x`
Performs `x[] = max(x[], val)` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw min` instruction.
"""
function atomic_max! end
"""
Threads.atomic_min!{T}(x::Atomic{T}, val::T)
Atomically store the minimum of `x` and `val` in `x`
Performs `x[] = min(x[], val)` atomically. Returns the old (!) value.
For further details, see LLVM's `atomicrmw max` instruction.
"""
function atomic_min! end
unsafe_convert{T}(::Type{Ptr{T}}, x::Atomic{T}) = convert(Ptr{T}, pointer_from_objref(x))
setindex!{T}(x::Atomic{T}, v) = setindex!(x, convert(T, v))
const llvmtypes = Dict(
Bool => "i1",
Int8 => "i8", UInt8 => "i8",
Int16 => "i16", UInt16 => "i16",
Int32 => "i32", UInt32 => "i32",
Int64 => "i64", UInt64 => "i64",
Int128 => "i128", UInt128 => "i128",
Float16 => "i16", # half
Float32 => "float",
Float64 => "double",
)
inttype{T<:Integer}(::Type{T}) = T
inttype(::Type{Float16}) = Int16
inttype(::Type{Float32}) = Int32
inttype(::Type{Float64}) = Int64
# All atomic operations have acquire and/or release semantics, depending on
# whether the load or store values. Most of the time, this is what one wants
# anyway, and it's only moderately expensive on most hardware.
for typ in atomictypes
lt = llvmtypes[typ]
ilt = llvmtypes[inttype(typ)]
rt = VersionNumber(Base.libllvm_version) >= v"3.6" ? "$lt, $lt*" : "$lt*"
irt = VersionNumber(Base.libllvm_version) >= v"3.6" ? "$ilt, $ilt*" : "$ilt*"
if VersionNumber(Base.libllvm_version) >= v"3.8"
@eval getindex(x::Atomic{$typ}) =
llvmcall($"""
%rv = load atomic $rt %0 acquire, align $(WORD_SIZE ÷ 8)
ret $lt %rv
""", $typ, Tuple{Ptr{$typ}}, unsafe_convert(Ptr{$typ}, x))
@eval setindex!(x::Atomic{$typ}, v::$typ) =
llvmcall($"""
store atomic $lt %1, $lt* %0 release, align $(WORD_SIZE ÷ 8)
ret void
""", Void, Tuple{Ptr{$typ},$typ}, unsafe_convert(Ptr{$typ}, x), v)
else
if typ <: Integer
@eval getindex(x::Atomic{$typ}) =
llvmcall($"""
%rv = load atomic $rt %0 acquire, align $(WORD_SIZE ÷ 8)
ret $lt %rv
""", $typ, Tuple{Ptr{$typ}}, unsafe_convert(Ptr{$typ}, x))
@eval setindex!(x::Atomic{$typ}, v::$typ) =
llvmcall($"""
store atomic $lt %1, $lt* %0 release, align $(WORD_SIZE ÷ 8)
ret void
""", Void, Tuple{Ptr{$typ},$typ}, unsafe_convert(Ptr{$typ}, x), v)
else
@eval getindex(x::Atomic{$typ}) =
llvmcall($"""
%iptr = bitcast $lt* %0 to $ilt*
%irv = load atomic $irt %iptr acquire, align $(WORD_SIZE ÷ 8)
%rv = bitcast $ilt %irv to $lt
ret $lt %rv
""", $typ, Tuple{Ptr{$typ}}, unsafe_convert(Ptr{$typ}, x))
@eval setindex!(x::Atomic{$typ}, v::$typ) =
llvmcall($"""
%iptr = bitcast $lt* %0 to $ilt*
%ival = bitcast $lt %1 to $ilt
store atomic $ilt %ival, $ilt* %iptr release, align $(WORD_SIZE ÷ 8)
ret void
""", Void, Tuple{Ptr{$typ},$typ}, unsafe_convert(Ptr{$typ}, x), v)
end
end
# Note: atomic_cas! succeeded (i.e. it stored "new") if and only if the result is "cmp"
if VersionNumber(Base.libllvm_version) >= v"3.5"
if typ <: Integer
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
llvmcall($"""
%rs = cmpxchg $lt* %0, $lt %1, $lt %2 acq_rel acquire
%rv = extractvalue { $lt, i1 } %rs, 0
ret $lt %rv
""", $typ, Tuple{Ptr{$typ},$typ,$typ},
unsafe_convert(Ptr{$typ}, x), cmp, new)
else
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
llvmcall($"""
%iptr = bitcast $lt* %0 to $ilt*
%icmp = bitcast $lt %1 to $ilt
%inew = bitcast $lt %2 to $ilt
%irs = cmpxchg $ilt* %iptr, $ilt %icmp, $ilt %inew acq_rel acquire
%irv = extractvalue { $ilt, i1 } %irs, 0
%rv = bitcast $ilt %irv to $lt
ret $lt %rv
""", $typ, Tuple{Ptr{$typ},$typ,$typ},
unsafe_convert(Ptr{$typ}, x), cmp, new)
end
else
if typ <: Integer
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
llvmcall($"""
%rv = cmpxchg $lt* %0, $lt %1, $lt %2 acq_rel
ret $lt %rv
""", $typ, Tuple{Ptr{$typ},$typ,$typ},
unsafe_convert(Ptr{$typ}, x), cmp, new)
else
@eval atomic_cas!(x::Atomic{$typ}, cmp::$typ, new::$typ) =
llvmcall($"""
%iptr = bitcast $lt* %0 to $ilt*
%icmp = bitcast $lt %1 to $ilt
%inew = bitcast $lt %2 to $ilt
%irv = cmpxchg $ilt* %iptr, $ilt %icmp, $ilt %inew acq_rel
%rv = bitcast $ilt %irv to $lt
ret $lt %rv
""", $typ, Tuple{Ptr{$typ},$typ,$typ},
unsafe_convert(Ptr{$typ}, x), cmp, new)
end
end
for rmwop in [:xchg, :add, :sub, :and, :nand, :or, :xor, :max, :min]
rmw = string(rmwop)
fn = Symbol("atomic_", rmw, "!")
if (rmw == "max" || rmw == "min") && typ <: Unsigned
# LLVM distinguishes signedness in the operation, not the integer type.
rmw = "u" * rmw
end
if typ <: Integer
@eval $fn(x::Atomic{$typ}, v::$typ) =
llvmcall($"""
%rv = atomicrmw $rmw $lt* %0, $lt %1 acq_rel
ret $lt %rv
""", $typ, Tuple{Ptr{$typ}, $typ}, unsafe_convert(Ptr{$typ}, x), v)
else
rmwop == :xchg || continue
@eval $fn(x::Atomic{$typ}, v::$typ) =
llvmcall($"""
%iptr = bitcast $lt* %0 to $ilt*
%ival = bitcast $lt %1 to $ilt
%irv = atomicrmw $rmw $ilt* %iptr, $ilt %ival acq_rel
%rv = bitcast $ilt %irv to $lt
ret $lt %rv
""", $typ, Tuple{Ptr{$typ}, $typ}, unsafe_convert(Ptr{$typ}, x), v)
end
end
end
# Provide atomic floating-point operations via atomic_cas!
const opnames = Dict{Symbol, Symbol}(:+ => :add, :- => :sub)
for op in [:+, :-, :max, :min]
opname = get(opnames, op, op)
@eval function $(Symbol("atomic_", opname, "!")){T<:FloatTypes}(var::Atomic{T}, val::T)
IT = inttype(T)
old = var[]
while true
new = $op(old, val)
cmp = old
old = atomic_cas!(var, cmp, new)
reinterpret(IT, old) == reinterpret(IT, cmp) && return new
# Temporary solution before we have gc transition support in codegen.
ccall(:jl_gc_safepoint, Void, ())
end
end
end
"""
Threads.atomic_fence()
Insert a sequential-consistency memory fence
Inserts a memory fence with sequentially-consistent ordering
semantics. There are algorithms where this is needed, i.e. where an
acquire/release ordering is insufficient.
This is likely a very expensive operation. Given that all other atomic
operations in Julia already have acquire/release semantics, explicit
fences should not be necessary in most cases.
For further details, see LLVM's `fence` instruction.
"""
atomic_fence() = llvmcall("""
fence seq_cst
ret void
""", Void, Tuple{})
# This file is a part of Julia. License is MIT: http://julialang.org/license
"""
SystemError(prefix::AbstractString, [errno::Int32])
A system call failed with an error code (in the `errno` global variable).
"""
type SystemError <: Exception
prefix::AbstractString
errnum::Int32
extrainfo
SystemError(p::AbstractString, e::Integer, extrainfo) = new(p, e, extrainfo)
SystemError(p::AbstractString, e::Integer) = new(p, e, nothing)
SystemError(p::AbstractString) = new(p, Libc.errno())
end
"""
ParseError(msg)
The expression passed to the `parse` function could not be interpreted as a valid Julia
expression.
"""
type ParseError <: Exception
msg::AbstractString
end
"""
ArgumentError(msg)
The parameters to a function call do not match a valid signature. Argument `msg` is a
descriptive error string.
"""
type ArgumentError <: Exception
msg::AbstractString
end
#type UnboundError <: Exception
# var::Symbol
#end
"""
KeyError(key)
An indexing operation into an `Associative` (`Dict`) or `Set` like object tried to access or
delete a non-existent element.
"""
type KeyError <: Exception
key
end
"""
MethodError(f, args)
A method with the required type signature does not exist in the given generic function.
Alternatively, there is no unique most-specific method.
"""
type MethodError <: Exception
f
args
end
"""
EOFError()
No more data was available to read from a file or stream.
"""
type EOFError <: Exception end
"""
DimensionMismatch([msg])
The objects called do not have matching dimensionality. Optional argument `msg` is a
descriptive error string.
"""
type DimensionMismatch <: Exception
msg::AbstractString
end
DimensionMismatch() = DimensionMismatch("")
"""
AssertionError([msg])
The asserted condition did not evaluate to `true`.
Optional argument `msg` is a descriptive error string.
"""
type AssertionError <: Exception
msg::AbstractString
AssertionError() = new("")
AssertionError(msg) = new(msg)
end
#Generic wrapping of arbitrary exceptions
#Subtypes should put the exception in an 'error' field
abstract WrappedException <: Exception
"""
LoadError(file::AbstractString, line::Int, error)
An error occurred while `include`ing, `require`ing, or `using` a file. The error specifics
should be available in the `.error` field.
"""
type LoadError <: WrappedException
file::AbstractString
line::Int
error
end
"""
InitError(mod::Symbol, error)
An error occurred when running a module's `__init__` function. The actual error thrown is
available in the `.error` field.
"""
type InitError <: WrappedException
mod::Symbol
error
end
ccall(:jl_get_system_hooks, Void, ())
==(w::WeakRef, v::WeakRef) = isequal(w.value, v.value)
==(w::WeakRef, v) = isequal(w.value, v)
==(w, v::WeakRef) = isequal(w, v.value)
function finalizer(o::ANY, f::ANY)
if isimmutable(o)
error("objects of type ", typeof(o), " cannot be finalized")
end
ccall(:jl_gc_add_finalizer_th, Void, (Ptr{Void}, Any, Any),
Core.getptls(), o, f)
end
function finalizer{T}(o::T, f::Ptr{Void})
@_inline_meta
if isimmutable(T)
error("objects of type ", T, " cannot be finalized")
end
ccall(:jl_gc_add_ptr_finalizer, Void, (Ptr{Void}, Any, Ptr{Void}),
Core.getptls(), o, f)
end
finalize(o::ANY) = ccall(:jl_finalize_th, Void, (Ptr{Void}, Any,),
Core.getptls(), o)
gc(full::Bool=true) = ccall(:jl_gc_collect, Void, (Cint,), full)
gc_enable(on::Bool) = ccall(:jl_gc_enable, Cint, (Cint,), on)!=0
immutable Nullable{T}
hasvalue::Bool
value::T
Nullable() = new(false)
Nullable(value::T, hasvalue::Bool=true) = new(hasvalue, value)
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Base64
import Base: read, write, close, eof, empty!
export Base64EncodePipe, Base64DecodePipe, base64encode, base64decode
# Base64EncodePipe is a pipe-like IO object, which converts into base64 data sent
# to a stream. (You must close the pipe to complete the encode, separate from
# closing the target stream). We also have a function base64encode(f,
# args...) which works like sprint except that it produces
# base64-encoded data, along with base64encode(args...) which is equivalent
# to base64encode(write, args...), to return base64 strings.
# A Base64DecodePipe object can be used to decode base64-encoded data read from a stream
# , while function base64decode is useful for decoding strings
#############################################################################
"""
Base64EncodePipe(ostream)
Returns a new write-only I/O stream, which converts any bytes written to it into
base64-encoded ASCII bytes written to `ostream`. Calling `close` on the `Base64EncodePipe` stream
is necessary to complete the encoding (but does not close `ostream`).
"""
type Base64EncodePipe <: IO
io::IO
# writing works in groups of 3, so we need to cache last two bytes written
b0::UInt8
b1::UInt8
nb::UInt8 # number of bytes in cache: 0, 1, or 2
function Base64EncodePipe(io::IO)
b = new(io,0,0,0)
finalizer(b, close)
return b
end
end
#############################################################################
# Based on code by Stefan Karpinski from https://github.com/hackerschool/WebSockets.jl (distributed under the same MIT license as Julia)
const b64chars = ['A':'Z';'a':'z';'0':'9';'+';'/']
const base64_pad = UInt8('=')
function b64(x::UInt8, y::UInt8, z::UInt8)
n = Int(x)<<16 | Int(y)<<8 | Int(z)
b64chars[(n >> 18) + 1],
b64chars[(n >> 12) & 0b111111 + 1],
b64chars[(n >> 6) & 0b111111 + 1],
b64chars[(n ) & 0b111111 + 1]
end
function b64(x::UInt8, y::UInt8)
a, b, c = b64(x, y, 0x0)
a, b, c, base64_pad
end
function b64(x::UInt8)
a, b = b64(x, 0x0, 0x0)
a, b, base64_pad, base64_pad
end
const sentinel = typemax(UInt8)
const revb64chars = fill(sentinel, 256)
# Fill revb64chars
for (val, ch) in enumerate(b64chars)
revb64chars[UInt8(ch)] = UInt8(val - 1)
end
# Decode a block of at least 2 and at most 4 bytes, received in encvec
# Returns the first decoded byte and stores up to two more in cache
function b64decode!(encvec::Vector{UInt8}, cache::Vector{UInt8})
if length(encvec) < 2
throw(ArgumentError("incorrect base64 format, block must be at least 2 and at most 4 bytes"))
end
@inbounds u = revb64chars[encvec[1]]
@inbounds v = revb64chars[encvec[2]]
empty!(cache)
res = (u << 2) | (v >> 4)
if length(encvec) > 2
@inbounds w = revb64chars[encvec[3]]
push!(cache, (v << 4) | (w >> 2))
end
if length(encvec) > 3
@inbounds z = revb64chars[encvec[4]]
push!(cache, (w << 6) | z)
end
res
end
#############################################################################
function unsafe_write(b::Base64EncodePipe, x::Ptr{UInt8}, n::UInt)
s = 1 # starting index
# finish any cached data to write:
if b.nb == 1
if n >= 2
write(b.io, b64(b.b0, unsafe_load(x, 1), unsafe_load(x, 2))...)
s = 3
elseif n == 1
b.b1 = unsafe_load(x, 1)
b.nb = 2
return
else
return
end
elseif b.nb == 2
if n >= 1
write(b.io, b64(b.b0, b.b1, unsafe_load(x, 1))...)
s = 2
else
return
end
end
# write all groups of three bytes:
while s + 2 <= n
write(b.io, b64(unsafe_load(x, s), unsafe_load(x, s + 1), unsafe_load(x, s + 2))...)
s += 3
end
# cache any leftover bytes:
if s + 1 == n
b.b0 = unsafe_load(x, s)
b.b1 = unsafe_load(x, s + 1)
b.nb = 2
elseif s == n
b.b0 = unsafe_load(x, s)
b.nb = 1
else
b.nb = 0
end
n
end
function write(b::Base64EncodePipe, x::UInt8)
if b.nb == 0
b.b0 = x
b.nb = 1
elseif b.nb == 1
b.b1 = x
b.nb = 2
else
write(b.io, b64(b.b0,b.b1,x)...)
b.nb = 0
end
1
end
function close(b::Base64EncodePipe)
if b.nb > 0
# write leftover bytes + padding
if b.nb == 1
write(b.io, b64(b.b0)...)
else # b.nb == 2
write(b.io, b64(b.b0, b.b1)...)
end
b.nb = 0
end
nothing
end
# like sprint, but returns base64 string
"""
base64encode(writefunc, args...)
base64encode(args...)
Given a `write`-like function `writefunc`, which takes an I/O stream as its first argument,
`base64encode(writefunc, args...)` calls `writefunc` to write `args...` to a base64-encoded
string, and returns the string. `base64encode(args...)` is equivalent to `base64encode(write, args...)`:
it converts its arguments into bytes using the standard `write` functions and returns the
base64-encoded string.
"""
function base64encode(f::Function, args...)
s = IOBuffer()
b = Base64EncodePipe(s)
f(b, args...)
close(b)
takebuf_string(s)
end
base64encode(x...) = base64encode(write, x...)
#############################################################################
"""
Base64DecodePipe(istream)
Returns a new read-only I/O stream, which decodes base64-encoded data read from `istream`.
"""
type Base64DecodePipe <: IO
io::IO
# reading works in blocks of 4 characters that are decoded into 3 bytes and 2 of them cached
cache::Vector{UInt8}
encvec::Vector{UInt8}
function Base64DecodePipe(io::IO)
b = new(io,[],[])
finalizer(b, close)
return b
end
end
function read(b::Base64DecodePipe, t::Type{UInt8})
if !isempty(b.cache)
return shift!(b.cache)
else
empty!(b.encvec)
while !eof(b.io) && length(b.encvec) < 4
c::UInt8 = read(b.io, t)
@inbounds if revb64chars[c] != sentinel
push!(b.encvec, c)
end
end
return b64decode!(b.encvec,b.cache)
end
end
eof(b::Base64DecodePipe) = isempty(b.cache) && eof(b.io)
close(b::Base64DecodePipe) = nothing
# Decodes a base64-encoded string
"""
base64decode(string)
Decodes the base64-encoded `string` and returns a `Vector{UInt8}` of the decoded bytes.
"""
function base64decode(s)
b = IOBuffer(s)
try
return read(Base64DecodePipe(b))
finally
close(b)
end
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
## BitArray
# notes: bits are stored in contiguous chunks
# unused bits must always be set to 0
type BitArray{N} <: DenseArray{Bool, N}
chunks::Vector{UInt64}
len::Int
dims::NTuple{N,Int}
function BitArray(dims::Vararg{Int,N})
n = 1
i = 1
for d in dims
d >= 0 || throw(ArgumentError("dimension size must be ≥ 0, got $d for dimension $i"))
n *= d
i += 1
end
nc = num_bit_chunks(n)
chunks = Array{UInt64}(nc)
nc > 0 && (chunks[end] = UInt64(0))
b = new(chunks, n)
N != 1 && (b.dims = dims)
return b
end
end
# note: the docs for the two signatures are unified, but only
# the first one is recognized by the help system; it would be nice
# to fix this.
"""
BitArray(dims::Integer...)
BitArray{N}(dims::NTuple{N,Int})
Construct an uninitialized `BitArray` with the given dimensions.
Behaves identically to the [`Array`](:func:`Array`) constructor.
"""
BitArray(dims::Integer...) = BitArray(map(Int,dims))
BitArray{N}(dims::NTuple{N,Int}) = BitArray{N}(dims...)
typealias BitVector BitArray{1}
typealias BitMatrix BitArray{2}
BitVector() = BitArray{1}(0)
## utility functions ##
length(B::BitArray) = B.len
size(B::BitVector) = (B.len,)
size(B::BitArray) = B.dims
@inline function size(B::BitVector, d)
d < 1 && throw_boundserror(size(B), d)
ifelse(d == 1, B.len, 1)
end
isassigned{N}(B::BitArray{N}, i::Int) = 1 <= i <= length(B)
linearindexing{A<:BitArray}(::Type{A}) = LinearFast()
## aux functions ##
const _msk64 = ~UInt64(0)
@inline _div64(l) = l >>> 6
@inline _mod64(l) = l & 63
@inline _msk_end(l::Integer) = _msk64 >>> _mod64(-l)
@inline _msk_end(B::BitArray) = _msk_end(length(B))
num_bit_chunks(n::Int) = _div64(n+63)
function _check_bitarray_consistency{N}(B::BitArray{N})
n = length(B)
if N ≠ 1
all(d ≥ 0 for d in B.dims) || (warn("negative d in dims: $(B.dims)"); return false)
prod(B.dims) ≠ n && (warn("inconsistent dims/len: prod(dims)=$(prod(B.dims)) len=$n"); return false)
end
Bc = B.chunks
nc = length(Bc)
nc == num_bit_chunks(n) || (warn("incorrect chunks length for length $n: expected=$(num_bit_chunks(n)) actual=$nc"); return false)
n == 0 && return true
Bc[end] & _msk_end(n) == Bc[end] || (warn("nonzero bits in chunk after BitArray end"); return false)
return true
end
@inline get_chunks_id(i::Integer) = _div64(Int(i)-1)+1, _mod64(Int(i)-1)
function glue_src_bitchunks(src::Vector{UInt64}, k::Int, ks1::Int, msk_s0::UInt64, ls0::Int)
@inbounds begin
chunk = ((src[k] & msk_s0) >>> ls0)
if ks1 > k && ls0 > 0
chunk_n = (src[k + 1] & ~msk_s0)
chunk |= (chunk_n << (64 - ls0))
end
end
return chunk
end
function copy_chunks!(dest::Vector{UInt64}, pos_d::Integer, src::Vector{UInt64}, pos_s::Integer, numbits::Integer)
numbits == 0 && return
if dest === src && pos_d > pos_s
return copy_chunks_rtol!(dest, pos_d, pos_s, numbits)
end
kd0, ld0 = get_chunks_id(pos_d)
kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
ks0, ls0 = get_chunks_id(pos_s)
ks1, ls1 = get_chunks_id(pos_s + numbits - 1)
delta_kd = kd1 - kd0
delta_ks = ks1 - ks0
u = _msk64
if delta_kd == 0
msk_d0 = ~(u << ld0) | (u << (ld1+1))
else
msk_d0 = ~(u << ld0)
msk_d1 = (u << (ld1+1))
end
if delta_ks == 0
msk_s0 = (u << ls0) & ~(u << (ls1+1))
else
msk_s0 = (u << ls0)
end
chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0)
dest[kd0] = (dest[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
delta_kd == 0 && return
for i = 1 : kd1 - kd0 - 1
chunk_s1 = glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0)
chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
dest[kd0 + i] = chunk_s
chunk_s0 = chunk_s1
end
if ks1 >= ks0 + delta_kd
chunk_s1 = glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0)
else
chunk_s1 = UInt64(0)
end
chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
dest[kd1] = (dest[kd1] & msk_d1) | (chunk_s & ~msk_d1)
return
end
function copy_chunks_rtol!(chunks::Vector{UInt64}, pos_d::Integer, pos_s::Integer, numbits::Integer)
pos_d == pos_s && return
pos_d < pos_s && return copy_chunks!(chunks, pos_d, chunks, pos_s, numbits)
left = numbits
s = min(left, 64)
b = left - s
ps = pos_s + b
pd = pos_d + b
u = _msk64
while left > 0
kd0, ld0 = get_chunks_id(pd)
kd1, ld1 = get_chunks_id(pd + s - 1)
ks0, ls0 = get_chunks_id(ps)
ks1, ls1 = get_chunks_id(ps + s - 1)
delta_kd = kd1 - kd0
delta_ks = ks1 - ks0
if delta_kd == 0
msk_d0 = ~(u << ld0) | (u << (ld1+1))
else
msk_d0 = ~(u << ld0)
msk_d1 = (u << (ld1+1))
end
if delta_ks == 0
msk_s0 = (u << ls0) & ~(u << (ls1+1))
else
msk_s0 = (u << ls0)
end
chunk_s0 = glue_src_bitchunks(chunks, ks0, ks1, msk_s0, ls0) & ~(u << s)
chunks[kd0] = (chunks[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
if delta_kd != 0
chunk_s = (chunk_s0 >>> (64 - ld0))
chunks[kd1] = (chunks[kd1] & msk_d1) | (chunk_s & ~msk_d1)
end
left -= s
s = min(left, 64)
b = left - s
ps = pos_s + b
pd = pos_d + b
end
end
function fill_chunks!(Bc::Array{UInt64}, x::Bool, pos::Integer, numbits::Integer)
numbits <= 0 && return
k0, l0 = get_chunks_id(pos)
k1, l1 = get_chunks_id(pos+numbits-1)
u = _msk64
if k1 == k0
msk0 = (u << l0) & ~(u << (l1+1))
else
msk0 = (u << l0)
msk1 = ~(u << (l1+1))
end
@inbounds if x
Bc[k0] |= msk0
for k = k0+1:k1-1
Bc[k] = u
end
k1 > k0 && (Bc[k1] |= msk1)
else
Bc[k0] &= ~msk0
for k = k0+1:k1-1
Bc[k] = 0
end
k1 > k0 && (Bc[k1] &= ~msk1)
end
end
copy_to_bitarray_chunks!(dest::Vector{UInt64}, pos_d::Integer, src::BitArray, pos_s::Integer, numbits::Integer) =
copy_chunks!(dest, pos_d, src.chunks, pos_s, numbits)
# pack 8 Bools encoded as one contiguous UIn64 into a single byte, e.g.:
# 0000001:0000001:00000000:00000000:00000001:00000000:00000000:00000001 → 11001001 → 0xc9
function pack8bools(z::UInt64)
z |= z >>> 7
z |= z >>> 14
z |= z >>> 28
z &= 0xFF
return z
end
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::Array{Bool}, pos_s::Int, numbits::Int)
kd0, ld0 = get_chunks_id(pos_d)
kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
delta_kd = kd1 - kd0
u = _msk64
if delta_kd == 0
msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
lt0 = ld1
else
msk_d0 = ~(u << ld0)
msk_d1 = (u << (ld1+1))
lt0 = 63
end
bind = kd0
ind = pos_s
@inbounds if ld0 > 0
c = UInt64(0)
for j = ld0:lt0
c |= (UInt64(C[ind]) << j)
ind += 1
end
Bc[kd0] = (Bc[kd0] & msk_d0) | (c & ~msk_d0)
bind += 1
end
nc = _div64(numbits - ind + pos_s)
nc8 = (nc >>> 3) << 3
if nc8 > 0
ind8 = 1
C8 = reinterpret(UInt64, unsafe_wrap(Array, pointer(C, ind), nc8 << 6))
@inbounds for i = 1:nc8
c = UInt64(0)
for j = 0:7
c |= (pack8bools(C8[ind8]) << (j<<3))
ind8 += 1
end
Bc[bind] = c
bind += 1
end
ind += (ind8-1) << 3
end
@inbounds for i = (nc8+1):nc
c = UInt64(0)
for j = 0:63
c |= (UInt64(C[ind]) << j)
ind += 1
end
Bc[bind] = c
bind += 1
end
@inbounds if bind ≤ kd1
@assert bind == kd1
c = UInt64(0)
for j = 0:ld1
c |= (UInt64(C[ind]) << j)
ind += 1
end
Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
end
end
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::Array, pos_s::Int, numbits::Int)
bind = pos_d
cind = pos_s
lastind = pos_d + numbits - 1
@inbounds while bind ≤ lastind
unsafe_bitsetindex!(Bc, Bool(C[cind]), bind)
bind += 1
cind += 1
end
end
# Note: the next two functions rely on the following definition of the conversion to Bool:
# convert(::Type{Bool}, x::Real) = x==0 ? false : x==1 ? true : throw(InexactError())
# they're used to pre-emptively check in bulk when possible, which is much faster.
# Also, the functions can be overloaded for custom types T<:Real :
# a) in the unlikely eventuality that they use a different logic for Bool conversion
# b) to skip the check if not necessary
@inline try_bool_conversion(x::Real) = x == 0 || x == 1 || throw(InexactError())
@inline unchecked_bool_convert(x::Real) = x == 1
function copy_to_bitarray_chunks!{T<:Real}(Bc::Vector{UInt64}, pos_d::Int, C::Array{T}, pos_s::Int, numbits::Int)
@inbounds for i = (1:numbits) + pos_s - 1
try_bool_conversion(C[i])
end
kd0, ld0 = get_chunks_id(pos_d)
kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
delta_kd = kd1 - kd0
u = _msk64
if delta_kd == 0
msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
lt0 = ld1
else
msk_d0 = ~(u << ld0)
msk_d1 = (u << (ld1+1))
lt0 = 63
end
bind = kd0
ind = pos_s
@inbounds if ld0 > 0
c = UInt64(0)
for j = ld0:lt0
c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
ind += 1
end
Bc[kd0] = (Bc[kd0] & msk_d0) | (c & ~msk_d0)
bind += 1
end
nc = _div64(numbits - ind + pos_s)
@inbounds for i = 1:nc
c = UInt64(0)
for j = 0:63
c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
ind += 1
end
Bc[bind] = c
bind += 1
end
@inbounds if bind ≤ kd1
@assert bind == kd1
c = UInt64(0)
for j = 0:ld1
c |= (UInt64(unchecked_bool_convert(C[ind])) << j)
ind += 1
end
Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
end
end
# auxiliary definitions used when filling a BitArray via a Vector{Bool} cache
# (e.g. when constructing from an iterable, or in broadcast!)
const bitcache_chunks = 64 # this can be changed
const bitcache_size = 64 * bitcache_chunks # do not change this
dumpbitcache(Bc::Vector{UInt64}, bind::Int, C::Vector{Bool}) =
copy_to_bitarray_chunks!(Bc, ((bind - 1) << 6) + 1, C, 1, min(bitcache_size, (length(Bc)-bind+1) << 6))
## custom iterator ##
start(B::BitArray) = 0
next(B::BitArray, i::Int) = (B.chunks[_div64(i)+1] & (UInt64(1)<<_mod64(i)) != 0, i+1)
done(B::BitArray, i::Int) = i >= length(B)
## similar, fill!, copy! etc ##
similar(B::BitArray) = BitArray(size(B))
similar(B::BitArray, dims::Int...) = BitArray(dims)
similar(B::BitArray, dims::Dims) = BitArray(dims...)
similar(B::BitArray, T::Type{Bool}, dims::Dims) = BitArray(dims)
# changing type to a non-Bool returns an Array
# (this triggers conversions like float(bitvector) etc.)
similar(B::BitArray, T::Type, dims::Dims) = Array{T}(dims)
function fill!(B::BitArray, x)
y = convert(Bool, x)
isempty(B) && return B
Bc = B.chunks
if !y
fill!(Bc, 0)
else
fill!(Bc, _msk64)
Bc[end] &= _msk_end(B)
end
return B
end
"""
falses(dims)
Create a `BitArray` with all values set to `false`.
```jldoctest
julia> falses(2,3)
2×3 BitArray{2}:
false false false
false false false
```
"""
falses(dims::Dims) = fill!(BitArray(dims), false)
falses(dims::Integer...) = falses(map(Int,dims))
"""
falses(A)
Create a `BitArray` with all values set to `false` of the same shape as `A`.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> falses(A)
2×2 BitArray{2}:
false false
false false
```
"""
falses(A::AbstractArray) = falses(size(A))
"""
trues(dims)
Create a `BitArray` with all values set to `true`.
```jldoctest
julia> trues(2,3)
2×3 BitArray{2}:
true true true
true true true
```
"""
trues(dims::Dims) = fill!(BitArray(dims), true)
trues(dims::Integer...) = trues(map(Int,dims))
"""
trues(A)
Create a `BitArray` with all values set to `true` of the same shape as `A`.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> trues(A)
2×2 BitArray{2}:
true true
true true
```
"""
trues(A::AbstractArray) = trues(size(A))
function one(x::BitMatrix)
m, n = size(x)
m == n || throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
a = falses(n, n)
for i = 1:n
a[i,i] = true
end
return a
end
function copy!(dest::BitArray, src::BitArray)
length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
destc = dest.chunks; srcc = src.chunks
nc = min(length(destc), length(srcc))
nc == 0 && return dest
@inbounds begin
for i = 1 : nc - 1
destc[i] = srcc[i]
end
if length(src) == length(dest)
destc[nc] = srcc[nc]
else
msk_s = _msk_end(src)
msk_d = ~msk_s
destc[nc] = (msk_d & destc[nc]) | (msk_s & srcc[nc])
end
end
return dest
end
function unsafe_copy!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer)
copy_to_bitarray_chunks!(dest.chunks, doffs, src, soffs, n)
return dest
end
function copy!(dest::BitArray, doffs::Integer, src::Array, soffs::Integer, n::Integer)
n == 0 && return dest
soffs < 1 && throw(BoundsError(src, soffs))
doffs < 1 && throw(BoundsError(dest, doffs))
soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))
doffs+n-1 > length(dest) && throw(BoundsError(dest, length(dest)+1))
return unsafe_copy!(dest, doffs, src, soffs, n)
end
function copy!(dest::BitArray, src::Array)
length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
length(src) == 0 && return det
return unsafe_copy!(dest, 1, src, 1, length(src))
end
function reshape{N}(B::BitArray, dims::NTuple{N,Int})
prod(dims) == length(B) ||
throw(DimensionMismatch("new dimensions $(dims) must be consistent with array size $(length(B))"))
dims == size(B) && return B
Br = BitArray{N}(ntuple(i->0,N)...)
Br.chunks = B.chunks
Br.len = prod(dims)
N != 1 && (Br.dims = dims)
return Br
end
## Conversions ##
convert{T,N}(::Type{Array{T}}, B::BitArray{N}) = convert(Array{T,N}, B)
convert{T,N}(::Type{Array{T,N}}, B::BitArray{N}) = _convert(Array{T,N}, B) # see #15801
function _convert{T,N}(::Type{Array{T,N}}, B::BitArray{N})
A = Array{T}(size(B))
Bc = B.chunks
@inbounds for i = 1:length(A)
A[i] = unsafe_bitgetindex(Bc, i)
end
return A
end
convert{T,N}(::Type{BitArray}, A::AbstractArray{T,N}) = convert(BitArray{N}, A)
function convert{T,N}(::Type{BitArray{N}}, A::AbstractArray{T,N})
B = BitArray(size(A))
Bc = B.chunks
l = length(B)
l == 0 && return B
ind = 1
@inbounds begin
for i = 1:length(Bc)-1
c = UInt64(0)
for j = 0:63
c |= (UInt64(A[ind] != 0) << j)
ind += 1
end
Bc[i] = c
end
c = UInt64(0)
for j = 0:_mod64(l-1)
c |= (UInt64(A[ind] != 0) << j)
ind += 1
end
Bc[end] = c
end
return B
end
function convert{N}(::Type{BitArray{N}}, A::Array{Bool,N})
B = BitArray(size(A))
Bc = B.chunks
l = length(B)
l == 0 && return B
copy_to_bitarray_chunks!(Bc, 1, A, 1, l)
return B
end
convert{N}(::Type{BitArray{N}}, B::BitArray{N}) = B
convert{T,N}(::Type{AbstractArray{T,N}}, B::BitArray{N}) = convert(Array{T,N}, B)
reinterpret{N}(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) = reinterpret(B, dims)
reinterpret{N}(B::BitArray, dims::NTuple{N,Int}) = reshape(B, dims)
## Constructors from generic iterables ##
BitArray{T,N}(A::AbstractArray{T,N}) = convert(BitArray{N}, A)
"""
BitArray(itr)
Construct a `BitArray` generated by the given iterable object. The shape is inferred from
the `itr` object.
```jldoctest
julia> BitArray([1 0; 0 1])
2×2 BitArray{2}:
true false
false true
julia> BitArray(x+y == 3 for x = 1:2, y = 1:3)
2×3 BitArray{2}:
false true false
true false false
julia> BitArray(x+y == 3 for x = 1:2 for y = 1:3)
6-element BitArray{1}:
false
true
false
true
false
false
```
"""
BitArray(itr) = gen_bitarray(iteratorsize(itr), itr)
# generic constructor from an iterable without compile-time info
# (we pass start(itr) explicitly to avoid a type-instability with filters)
gen_bitarray(isz::IteratorSize, itr) = gen_bitarray_from_itr(itr, start(itr))
# generic iterable with known shape
function gen_bitarray(::HasShape, itr)
B = BitArray(size(itr))
for (I,x) in zip(CartesianRange(indices(itr)), itr)
B[I] = x
end
return B
end
# generator with known shape or length
function gen_bitarray(::HasShape, itr::Generator)
B = BitArray(size(itr))
return fill_bitarray_from_itr!(B, itr, start(itr))
end
function gen_bitarray(::HasLength, itr)
n = length(itr)
B = BitArray(n)
return fill_bitarray_from_itr!(B, itr, start(itr))
end
gen_bitarray(::IsInfinite, itr) = throw(ArgumentError("infinite-size iterable used in BitArray constructor"))
# The aux functions gen_bitarray_from_itr and fill_bitarray_from_itr! both
# use a Vector{Bool} cache for performance reasons
function gen_bitarray_from_itr(itr, st)
B = empty!(BitArray(bitcache_size))
C = Vector{Bool}(bitcache_size)
Bc = B.chunks
ind = 1
cind = 1
while !done(itr, st)
x, st = next(itr, st)
@inbounds C[ind] = x
ind += 1
if ind > bitcache_size
resize!(B, length(B) + bitcache_size)
dumpbitcache(Bc, cind, C)
cind += bitcache_chunks
ind = 1
end
end
if ind > 1
@inbounds C[ind:bitcache_size] = false
resize!(B, length(B) + ind - 1)
dumpbitcache(Bc, cind, C)
end
return B
end
function fill_bitarray_from_itr!(B::BitArray, itr, st)
n = length(B)
C = Vector{Bool}(bitcache_size)
Bc = B.chunks
ind = 1
cind = 1
while !done(itr, st)
x, st = next(itr, st)
@inbounds C[ind] = x
ind += 1
if ind > bitcache_size
dumpbitcache(Bc, cind, C)
cind += bitcache_chunks
ind = 1
end
end
if ind > 1
@inbounds C[ind:bitcache_size] = false
dumpbitcache(Bc, cind, C)
end
return B
end
## Indexing: getindex ##
@inline function unsafe_bitgetindex(Bc::Vector{UInt64}, i::Int)
i1, i2 = get_chunks_id(i)
u = UInt64(1) << i2
@inbounds r = (Bc[i1] & u) != 0
return r
end
@inline function getindex(B::BitArray, i::Int)
@boundscheck checkbounds(B, i)
unsafe_bitgetindex(B.chunks, i)
end
## Indexing: setindex! ##
@inline function unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i::Int)
i1, i2 = get_chunks_id(i)
u = UInt64(1) << i2
@inbounds begin
c = Bc[i1]
Bc[i1] = ifelse(x, c | u, c & ~u)
end
end
@inline function setindex!(B::BitArray, x, i::Int)
@boundscheck checkbounds(B, i)
unsafe_bitsetindex!(B.chunks, convert(Bool, x), i)
return B
end
# logical indexing
# When indexing with a BitArray, we can operate whole chunks at a time for a ~100x gain
@inline function setindex!(B::BitArray, x, I::BitArray)
@boundscheck checkbounds(B, I)
_unsafe_setindex!(B, x, I)
end
function _unsafe_setindex!(B::BitArray, x, I::BitArray)
y = convert(Bool, x)
Bc = B.chunks
Ic = I.chunks
length(Bc) == length(Ic) || throw_boundserror(B, I)
@inbounds if y
for i = 1:length(Bc)
Bc[i] |= Ic[i]
end
else
for i = 1:length(Bc)
Bc[i] &= ~Ic[i]
end
end
return B
end
# Assigning an array of bools is more complicated, but we can still do some
# work on chunks by combining X and I 64 bits at a time to improve perf by ~40%
@inline function setindex!(B::BitArray, X::AbstractArray, I::BitArray)
@boundscheck checkbounds(B, I)
_unsafe_setindex!(B, X, I)
end
function _unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray)
Bc = B.chunks
Ic = I.chunks
length(Bc) == length(Ic) || throw_boundserror(B, I)
lc = length(Bc)
lx = length(X)
last_chunk_len = _mod64(length(B)-1)+1
c = 1
for i = 1:lc
@inbounds Imsk = Ic[i]
@inbounds C = Bc[i]
u = UInt64(1)
for j = 1:(i < lc ? 64 : last_chunk_len)
if Imsk & u != 0
lx < c && throw_setindex_mismatch(X, c)
@inbounds x = convert(Bool, X[c])
C = ifelse(x, C | u, C & ~u)
c += 1
end
u <<= 1
end
@inbounds Bc[i] = C
end
if length(X) != c-1
throw_setindex_mismatch(X, c-1)
end
return B
end
## Dequeue functionality ##
function push!(B::BitVector, item)
# convert first so we don't grow the bitarray if the assignment won't work
item = convert(Bool, item)
Bc = B.chunks
l = _mod64(length(B))
if l == 0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, 1)
Bc[end] = UInt64(0)
end
B.len += 1
if item
B[end] = true
end
return B
end
function append!(B::BitVector, items::BitVector)
n0 = length(B)
n1 = length(items)
n1 == 0 && return B
Bc = B.chunks
k0 = length(Bc)
k1 = num_bit_chunks(n0 + n1)
if k1 > k0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, k1 - k0)
Bc[end] = UInt64(0)
end
B.len += n1
copy_chunks!(Bc, n0+1, items.chunks, 1, n1)
return B
end
append!(B::BitVector, items::AbstractVector{Bool}) = append!(B, BitArray(items))
append!(A::Vector{Bool}, items::BitVector) = append!(A, Array(items))
function prepend!(B::BitVector, items::BitVector)
n0 = length(B)
n1 = length(items)
n1 == 0 && return B
Bc = B.chunks
k0 = length(Bc)
k1 = num_bit_chunks(n0 + n1)
if k1 > k0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, k1 - k0)
Bc[end] = UInt64(0)
end
B.len += n1
copy_chunks!(Bc, 1 + n1, Bc, 1, n0)
copy_chunks!(Bc, 1, items.chunks, 1, n1)
return B
end
prepend!(B::BitVector, items::AbstractVector{Bool}) = prepend!(B, BitArray(items))
prepend!(A::Vector{Bool}, items::BitVector) = prepend!(A, Array(items))
function sizehint!(B::BitVector, sz::Integer)
ccall(:jl_array_sizehint, Void, (Any, UInt), B.chunks, num_bit_chunks(sz))
return B
end
function resize!(B::BitVector, n::Integer)
n0 = length(B)
n == n0 && return B
n >= 0 || throw(BoundsError(B, n))
if n < n0
deleteat!(B, n+1:n0)
return B
end
Bc = B.chunks
k0 = length(Bc)
k1 = num_bit_chunks(Int(n))
if k1 > k0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, k1 - k0)
Bc[end] = UInt64(0)
end
B.len = n
return B
end
function pop!(B::BitVector)
isempty(B) && throw(ArgumentError("argument must not be empty"))
item = B[end]
B[end] = false
l = _mod64(length(B))
l == 1 && ccall(:jl_array_del_end, Void, (Any, UInt), B.chunks, 1)
B.len -= 1
return item
end
function unshift!(B::BitVector, item)
item = convert(Bool, item)
Bc = B.chunks
l = _mod64(length(B))
if l == 0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, 1)
Bc[end] = UInt64(0)
end
B.len += 1
if B.len == 1
Bc[1] = item
return B
end
for i = length(Bc) : -1 : 2
Bc[i] = (Bc[i] << 1) | (Bc[i-1] >>> 63)
end
Bc[1] = UInt64(item) | (Bc[1] << 1)
return B
end
function shift!(B::BitVector)
isempty(B) && throw(ArgumentError("argument must not be empty"))
@inbounds begin
item = B[1]
Bc = B.chunks
for i = 1 : length(Bc) - 1
Bc[i] = (Bc[i] >>> 1) | (Bc[i+1] << 63)
end
l = _mod64(length(B))
if l == 1
ccall(:jl_array_del_end, Void, (Any, UInt), Bc, 1)
else
Bc[end] >>>= 1
end
B.len -= 1
end
return item
end
function insert!(B::BitVector, i::Integer, item)
n = length(B)
1 <= i <= n+1 || throw(BoundsError(B, i))
item = convert(Bool, item)
Bc = B.chunks
k, j = get_chunks_id(i)
l = _mod64(length(B))
if l == 0
ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, 1)
Bc[end] = UInt64(0)
end
B.len += 1
for t = length(Bc) : -1 : k + 1
Bc[t] = (Bc[t] << 1) | (Bc[t - 1] >>> 63)
end
msk_aft = (_msk64 << j)
msk_bef = ~msk_aft
Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) << 1)
B[i] = item
B
end
function _deleteat!(B::BitVector, i::Integer)
k, j = get_chunks_id(i)
msk_bef = _msk64 >>> (63 - j)
msk_aft = ~msk_bef
msk_bef >>>= 1
Bc = B.chunks
@inbounds begin
Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) >> 1)
if length(Bc) > k
Bc[k] |= (Bc[k + 1] << 63)
end
for t = k + 1 : length(Bc) - 1
Bc[t] = (Bc[t] >>> 1) | (Bc[t + 1] << 63)
end
l = _mod64(length(B))
if l == 1
ccall(:jl_array_del_end, Void, (Any, UInt), Bc, 1)
elseif length(Bc) > k
Bc[end] >>>= 1
end
end
B.len -= 1
return B
end
function deleteat!(B::BitVector, i::Integer)
n = length(B)
1 <= i <= n || throw(BoundsError(B, i))
return _deleteat!(B, i)
end
function deleteat!(B::BitVector, r::UnitRange{Int})
n = length(B)
i_f = first(r)
i_l = last(r)
1 <= i_f || throw(BoundsError(B, i_f))
i_l <= n || throw(BoundsError(B, n+1))
Bc = B.chunks
new_l = length(B) - length(r)
delta_k = num_bit_chunks(new_l) - length(Bc)
copy_chunks!(Bc, i_f, Bc, i_l+1, n-i_l)
delta_k < 0 && ccall(:jl_array_del_end, Void, (Any, UInt), Bc, -delta_k)
B.len = new_l
if new_l > 0
Bc[end] &= _msk_end(new_l)
end
return B
end
function deleteat!(B::BitVector, inds)
n = new_l = length(B)
s = start(inds)
done(inds, s) && return B
Bc = B.chunks
(p, s) = next(inds, s)
q = p+1
new_l -= 1
while !done(inds, s)
(i,s) = next(inds, s)
if !(q <= i <= n)
i < q && throw(ArgumentError("indices must be unique and sorted"))
throw(BoundsError(B, i))
end
new_l -= 1
if i > q
copy_chunks!(Bc, p, Bc, q, i-q)
p += i-q
end
q = i+1
end
q <= n && copy_chunks!(Bc, p, Bc, q, n-q+1)
delta_k = num_bit_chunks(new_l) - length(Bc)
delta_k < 0 && ccall(:jl_array_del_end, Void, (Any, UInt), Bc, -delta_k)
B.len = new_l
if new_l > 0
Bc[end] &= _msk_end(new_l)
end
return B
end
function splice!(B::BitVector, i::Integer)
n = length(B)
1 <= i <= n || throw(BoundsError(B, i))
v = B[i] # TODO: change to a copy if/when subscripting becomes an ArrayView
_deleteat!(B, i)
return v
end
const _default_bit_splice = BitVector(0)
function splice!(B::BitVector, r::Union{UnitRange{Int}, Integer}, ins::AbstractArray = _default_bit_splice)
n = length(B)
i_f = first(r)
i_l = last(r)
1 <= i_f <= n+1 || throw(BoundsError(B, i_f))
i_l <= n || throw(BoundsError(B, n+1))
Bins = convert(BitArray, ins)
if (i_f > n)
append!(B, Bins)
return BitVector(0)
end
v = B[r] # TODO: change to a copy if/when subscripting becomes an ArrayView
Bc = B.chunks
lins = length(Bins)
ldel = length(r)
new_l = length(B) + lins - ldel
delta_k = num_bit_chunks(new_l) - length(Bc)
delta_k > 0 && ccall(:jl_array_grow_end, Void, (Any, UInt), Bc, delta_k)
copy_chunks!(Bc, i_f+lins, Bc, i_l+1, n-i_l)
copy_chunks!(Bc, i_f, Bins.chunks, 1, lins)
delta_k < 0 && ccall(:jl_array_del_end, Void, (Any, UInt), Bc, -delta_k)
B.len = new_l
if new_l > 0
Bc[end] &= _msk_end(new_l)
end
return v
end
function splice!(B::BitVector, r::Union{UnitRange{Int}, Integer}, ins)
Bins = BitArray(length(ins))
i = 1
for x in ins
Bins[i] = Bool(x)
i += 1
end
return splice!(B, r, Bins)
end
function empty!(B::BitVector)
ccall(:jl_array_del_end, Void, (Any, UInt), B.chunks, length(B.chunks))
B.len = 0
return B
end
## Misc functions
broadcast(::typeof(abs), B::BitArray) = copy(B)
## Unary operators ##
function (-)(B::BitArray)
A = zeros(Int, size(B))
l = length(B)
l == 0 && return A
Bc = B.chunks
ind = 1
for i = 1:length(Bc)-1
u = UInt64(1)
c = Bc[i]
for j = 1:64
if c & u != 0
A[ind] = -1
end
ind += 1
u <<= 1
end
end
u = UInt64(1)
c = Bc[end]
for j = 0:_mod64(l-1)
if c & u != 0
A[ind] = -1
end
ind += 1
u <<= 1
end
return A
end
sign(B::BitArray) = copy(B)
function (~)(B::BitArray)
C = similar(B)
Bc = B.chunks
if !isempty(Bc)
Cc = C.chunks
for i = 1:length(Bc)
Cc[i] = ~Bc[i]
end
Cc[end] &= _msk_end(B)
end
return C
end
"""
flipbits!(B::BitArray{N}) -> BitArray{N}
Performs a bitwise not operation on `B`. See [`~`](:ref:`~ operator <~>`).
```jldoctest
julia> A = trues(2,2)
2×2 BitArray{2}:
true true
true true
julia> flipbits!(A)
2×2 BitArray{2}:
false false
false false
```
"""
function flipbits!(B::BitArray)
Bc = B.chunks
@inbounds if !isempty(Bc)
for i = 1:length(Bc)
Bc[i] = ~Bc[i]
end
Bc[end] &= _msk_end(B)
end
return B
end
!(B::BitArray) = ~B
## Binary arithmetic operators ##
for f in (:+, :-)
@eval function ($f)(A::BitArray, B::BitArray)
r = Array{Int}(promote_shape(size(A), size(B)))
ai = start(A)
bi = start(B)
ri = 1
while !done(A, ai)
a, ai = next(A, ai)
b, bi = next(B, bi)
@inbounds r[ri] = ($f)(a, b)
ri += 1
end
return r
end
end
for (f) in (:.+, :.-)
for (arg1, arg2, T, t) in ((:(B::BitArray), :(x::Bool) , Int , (:b, :x)),
(:(B::BitArray), :(x::Number) , :(Bool, typeof(x)), (:b, :x)),
(:(x::Bool) , :(B::BitArray), Int , (:x, :b)),
(:(x::Number) , :(B::BitArray), :(typeof(x), Bool), (:x, :b)))
@eval function ($f)($arg1, $arg2)
$(if T === Int
quote
r = Array{Int}(size(B))
end
else
quote
T = promote_op($f, $(T.args[1]), $(T.args[2]))
T === Any && return [($f)($(t[1]), $(t[2])) for b in B]
r = Array{T}(size(B))
end
end)
bi = start(B)
ri = 1
while !done(B, bi)
b, bi = next(B, bi)
@inbounds r[ri] = ($f)($(t[1]), $(t[2]))
ri += 1
end
return r
end
end
end
for f in (:/, :\)
@eval begin
($f)(A::BitArray, B::BitArray) = ($f)(Array(A), Array(B))
end
end
(/)(B::BitArray, x::Number) = (/)(Array(B), x)
(/)(x::Number, B::BitArray) = (/)(x, Array(B))
function div(A::BitArray, B::BitArray)
shp = promote_shape(size(A), size(B))
all(B) || throw(DivideError())
return reshape(copy(A), shp)
end
div(A::BitArray, B::Array{Bool}) = div(A, BitArray(B))
div(A::Array{Bool}, B::BitArray) = div(BitArray(A), B)
function div(B::BitArray, x::Bool)
return x ? copy(B) : throw(DivideError())
end
function div(x::Bool, B::BitArray)
all(B) || throw(DivideError())
return x ? trues(size(B)) : falses(size(B))
end
function div(x::Number, B::BitArray)
all(B) || throw(DivideError())
y = div(x, true)
return fill(y, size(B))
end
function mod(A::BitArray, B::BitArray)
shp = promote_shape(size(A), size(B))
all(B) || throw(DivideError())
return falses(shp)
end
mod(A::BitArray, B::Array{Bool}) = mod(A, BitArray(B))
mod(A::Array{Bool}, B::BitArray) = mod(BitArray(A), B)
function mod(B::BitArray, x::Bool)
return x ? falses(size(B)) : throw(DivideError())
end
function mod(x::Bool, B::BitArray)
all(B) || throw(DivideError())
return falses(size(B))
end
function mod(x::Number, B::BitArray)
all(B) || throw(DivideError())
y = mod(x, true)
return fill(y, size(B))
end
for f in (:div, :mod)
@eval begin
function ($f)(B::BitArray, x::Number)
T = promote_op($f, Bool, typeof(x))
T === Any && return [($f)(b, x) for b in B]
F = Array{T}(size(B))
for i = 1:length(F)
F[i] = ($f)(B[i], x)
end
return F
end
end
end
function (&)(B::BitArray, x::Bool)
x ? copy(B) : falses(size(B))
end
(&)(x::Bool, B::BitArray) = B & x
function (|)(B::BitArray, x::Bool)
x ? trues(size(B)) : copy(B)
end
(|)(x::Bool, B::BitArray) = B | x
function ($)(B::BitArray, x::Bool)
x ? ~B : copy(B)
end
($)(x::Bool, B::BitArray) = B $ x
for f in (:&, :|, :$)
@eval begin
function ($f)(A::BitArray, B::BitArray)
F = BitArray(promote_shape(size(A),size(B))...)
Fc = F.chunks
Ac = A.chunks
Bc = B.chunks
(isempty(Ac) || isempty(Bc)) && return F
for i = 1:length(Fc)
Fc[i] = ($f)(Ac[i], Bc[i])
end
Fc[end] &= _msk_end(F)
return F
end
($f)(A::DenseArray{Bool}, B::BitArray) = ($f)(BitArray(A), B)
($f)(B::BitArray, A::DenseArray{Bool}) = ($f)(B, BitArray(A))
($f)(x::Number, B::BitArray) = ($f)(x, Array(B))
($f)(B::BitArray, x::Number) = ($f)(Array(B), x)
end
end
function (.^)(B::BitArray, x::Bool)
x ? copy(B) : trues(size(B))
end
function (.^)(x::Bool, B::BitArray)
x ? trues(size(B)) : ~B
end
function (.^)(x::Number, B::BitArray)
z = x ^ false
u = x ^ true
reshape([ B[i] ? u : z for i = 1:length(B) ], size(B))
end
function (.^)(B::BitArray, x::Integer)
x == 0 && return trues(size(B))
x < 0 && throw(DomainError())
return copy(B)
end
function (.^){T<:Number}(B::BitArray, x::T)
x == 0 && return ones(typeof(true ^ x), size(B))
T <: Real && x > 0 && return convert(Array{T}, B)
z = nothing
u = nothing
zerr = nothing
uerr = nothing
try
z = false^x
catch err
zerr = err
end
try
u = true^x
catch err
uerr = err
end
if zerr === nothing && uerr === nothing
t = promote_type(typeof(z), typeof(u))
elseif zerr === nothing
t = typeof(z)
else
t = typeof(u)
end
F = Array{t}(size(B))
for i = 1:length(B)
if B[i]
if uerr === nothing
F[i] = u
else
throw(uerr)
end
else
if zerr === nothing
F[i] = z
else
throw(zerr)
end
end
end
return F
end
(.*)(x::Bool, B::BitArray) = x & B
(.*)(B::BitArray, x::Bool) = B & x
(.*)(x::Number, B::BitArray) = x .* Array(B)
(.*)(B::BitArray, x::Number) = Array(B) .* x
## promotion to complex ##
# TODO?
## comparison operators ##
function (==)(A::BitArray, B::BitArray)
size(A) != size(B) && return false
return A.chunks == B.chunks
end
## Data movement ##
# TODO some of this could be optimized
function slicedim(A::BitArray, d::Integer, i::Integer)
d_in = size(A)
leading = d_in[1:(d-1)]
d_out = tuple(leading..., d_in[(d+1):end]...)
M = prod(leading)
N = length(A)
stride = M * d_in[d]
B = BitArray(d_out)
index_offset = 1 + (i-1)*M
l = 1
if M == 1
for j = 0:stride:(N-stride)
B[l] = A[j + index_offset]
l += 1
end
else
for j = 0:stride:(N-stride)
offs = j + index_offset
for k = 0:(M-1)
B[l] = A[offs + k]
l += 1
end
end
end
return B
end
function flipdim(A::BitArray, d::Integer)
nd = ndims(A)
1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
sd = size(A, d)
sd == 1 && return copy(A)
B = similar(A)
nnd = 0
for i = 1:nd
nnd += Int(size(A,i)==1 || i==d)
end
if nnd == nd
# flip along the only non-singleton dimension
for i = 1:sd
B[i] = A[sd+1-i]
end
return B
end
d_in = size(A)
leading = d_in[1:(d-1)]
M = prod(leading)
N = length(A)
stride = M * sd
if M == 1
for j = 0:stride:(N-stride)
for i = 1:sd
ri = sd+1-i
B[j + ri] = A[j + i]
end
end
else
for i = 1:sd
ri = sd+1-i
for j=0:stride:(N-stride)
offs = j + 1 + (i-1)*M
boffs = j + 1 + (ri-1)*M
copy_chunks!(B.chunks, boffs, A.chunks, offs, M)
end
end
end
return B
end
function reverse_bits(src::UInt64)
z = src
z = ((z >>> 1) & 0x5555555555555555) | ((z << 1) & 0xaaaaaaaaaaaaaaaa)
z = ((z >>> 2) & 0x3333333333333333) | ((z << 2) & 0xcccccccccccccccc)
z = ((z >>> 4) & 0x0f0f0f0f0f0f0f0f) | ((z << 4) & 0xf0f0f0f0f0f0f0f0)
z = ((z >>> 8) & 0x00ff00ff00ff00ff) | ((z << 8) & 0xff00ff00ff00ff00)
z = ((z >>> 16) & 0x0000ffff0000ffff) | ((z << 16) & 0xffff0000ffff0000)
return ((z >>> 32) & 0x00000000ffffffff) | ((z << 32) & 0xffffffff00000000)
end
function reverse!(B::BitVector)
# Basic idea: each chunk is divided into two blocks of size k = n % 64, and
# h = 64 - k. Walk from either end (with indexes i and j) reversing chunks
# and separately ORing their two blocks into place.
#
# chunk 3 chunk 2 chunk 1
# ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
# │000000000000000│ E ││ D │ C ││ B │ A │
# └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
# k h k h k
# yielding;
# ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
# │000000000000000│ A' ││ B' │ C' ││ D' │ E' │
# └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
n = length(B)
n == 0 && return B
k = _mod64(n+63) + 1
h = 64 - k
i, j = 0, length(B.chunks)
u = UInt64(0)
v = reverse_bits(B.chunks[j])
B.chunks[j] = 0
@inbounds while true
i += 1
if i == j
break
end
u = reverse_bits(B.chunks[i])
B.chunks[i] = 0
B.chunks[j] |= u >>> h
B.chunks[i] |= v >>> h
j -= 1
if i == j
break
end
v = reverse_bits(B.chunks[j])
B.chunks[j] = 0
B.chunks[i] |= v << k
B.chunks[j] |= u << k
end
if isodd(length(B.chunks))
B.chunks[i] |= v >>> h
else
B.chunks[i] |= u << k
end
return B
end
reverse(v::BitVector) = reverse!(copy(v))
function (<<)(B::BitVector, i::Int)
n = length(B)
i == 0 && return copy(B)
A = falses(n)
i < n && copy_chunks!(A.chunks, 1, B.chunks, i+1, n-i)
return A
end
function (>>>)(B::BitVector, i::Int)
n = length(B)
i == 0 && return copy(B)
A = falses(n)
i < n && copy_chunks!(A.chunks, i+1, B.chunks, 1, n-i)
return A
end
(>>)(B::BitVector, i::Int) = B >>> i
"""
rol!(dest::BitVector, src::BitVector, i::Integer) -> BitVector
Performs a left rotation operation on `src` and puts the result into `dest`.
`i` controls how far to rotate the bits.
"""
function rol!(dest::BitVector, src::BitVector, i::Integer)
length(dest) == length(src) || throw(ArgumentError("destination and source should be of same size"))
n = length(dest)
i %= n
i == 0 && return (src === dest ? src : copy!(dest, src))
i < 0 && return ror!(dest, src, -i)
Bc = (src === dest ? copy(src.chunks) : src.chunks)
copy_chunks!(dest.chunks, 1, Bc, i+1, n-i)
copy_chunks!(dest.chunks, n-i+1, Bc, 1, i)
return dest
end
"""
rol!(B::BitVector, i::Integer) -> BitVector
Performs a left rotation operation in-place on `B`.
`i` controls how far to rotate the bits.
"""
rol!(B::BitVector, i::Integer) = rol!(B, B, i)
"""
rol(B::BitVector, i::Integer) -> BitVector
Performs a left rotation operation, returning a new `BitVector`.
`i` controls how far to rotate the bits.
See also [`rol!`](:func:`rol!`).
```jldoctest
julia> A = BitArray([true, true, false, false, true])
5-element BitArray{1}:
true
true
false
false
true
julia> rol(A,1)
5-element BitArray{1}:
true
false
false
true
true
julia> rol(A,2)
5-element BitArray{1}:
false
false
true
true
true
julia> rol(A,5)
5-element BitArray{1}:
true
true
false
false
true
```
"""
rol(B::BitVector, i::Integer) = rol!(similar(B), B, i)
"""
ror!(dest::BitVector, src::BitVector, i::Integer) -> BitVector
Performs a right rotation operation on `src` and puts the result into `dest`.
`i` controls how far to rotate the bits.
"""
function ror!(dest::BitVector, src::BitVector, i::Integer)
length(dest) == length(src) || throw(ArgumentError("destination and source should be of same size"))
n = length(dest)
i %= n
i == 0 && return (src === dest ? src : copy!(dest, src))
i < 0 && return rol!(dest, src, -i)
Bc = (src === dest ? copy(src.chunks) : src.chunks)
copy_chunks!(dest.chunks, i+1, Bc, 1, n-i)
copy_chunks!(dest.chunks, 1, Bc, n-i+1, i)
return dest
end
"""
ror!(B::BitVector, i::Integer) -> BitVector
Performs a right rotation operation in-place on `B`.
`i` controls how far to rotate the bits.
"""
ror!(B::BitVector, i::Integer) = ror!(B, B, i)
"""
ror(B::BitVector, i::Integer) -> BitVector
Performs a right rotation operation on `B`, returning a new `BitVector`.
`i` controls how far to rotate the bits.
See also [`ror!`](:func:`ror!`).
```jldoctest
julia> A = BitArray([true, true, false, false, true])
5-element BitArray{1}:
true
true
false
false
true
julia> ror(A,1)
5-element BitArray{1}:
true
true
true
false
false
julia> ror(A,2)
5-element BitArray{1}:
false
true
true
true
false
julia> ror(A,5)
5-element BitArray{1}:
true
true
false
false
true
```
"""
ror(B::BitVector, i::Integer) = ror!(similar(B), B, i)
## countnz & find ##
function countnz(B::BitArray)
n = 0
Bc = B.chunks
@inbounds for i = 1:length(Bc)
n += count_ones(Bc[i])
end
return n
end
# returns the index of the next non-zero element, or 0 if all zeros
function findnext(B::BitArray, start::Integer)
start > 0 || throw(BoundsError(B, start))
start > length(B) && return 0
Bc = B.chunks
chunk_start = _div64(start-1)+1
within_chunk_start = _mod64(start-1)
mask = _msk64 << within_chunk_start
@inbounds begin
if Bc[chunk_start] & mask != 0
return (chunk_start-1) << 6 + trailing_zeros(Bc[chunk_start] & mask) + 1
end
for i = chunk_start+1:length(Bc)
if Bc[i] != 0
return (i-1) << 6 + trailing_zeros(Bc[i]) + 1
end
end
end
return 0
end
#findfirst(B::BitArray) = findnext(B, 1) ## defined in array.jl
# aux function: same as findnext(~B, start), but performed without temporaries
function findnextnot(B::BitArray, start::Integer)
start > 0 || throw(BoundsError(B, start))
start > length(B) && return 0
Bc = B.chunks
l = length(Bc)
l == 0 && return 0
chunk_start = _div64(start-1)+1
within_chunk_start = _mod64(start-1)
mask = ~(_msk64 << within_chunk_start)
@inbounds if chunk_start < l
if Bc[chunk_start] | mask != _msk64
return (chunk_start-1) << 6 + trailing_ones(Bc[chunk_start] | mask) + 1
end
for i = chunk_start+1:l-1
if Bc[i] != _msk64
return (i-1) << 6 + trailing_ones(Bc[i]) + 1
end
end
if Bc[l] != _msk_end(B)
return (l-1) << 6 + trailing_ones(Bc[l]) + 1
end
elseif Bc[l] | mask != _msk_end(B)
return (l-1) << 6 + trailing_ones(Bc[l] | mask) + 1
end
return 0
end
findfirstnot(B::BitArray) = findnextnot(B,1)
# returns the index of the first matching element
function findnext(B::BitArray, v, start::Integer)
v == false && return findnextnot(B, start)
v == true && return findnext(B, start)
return 0
end
#findfirst(B::BitArray, v) = findnext(B, 1, v) ## defined in array.jl
# returns the index of the first element for which the function returns true
function findnext(testf::Function, B::BitArray, start::Integer)
f0::Bool = testf(false)
f1::Bool = testf(true)
!f0 && f1 && return findnext(B, start)
f0 && !f1 && return findnextnot(B, start)
start > 0 || throw(BoundsError(B, start))
start > length(B) && return 0
f0 && f1 && return Int(start)
return 0 # last case: !f0 && !f1
end
#findfirst(testf::Function, B::BitArray) = findnext(testf, B, 1) ## defined in array.jl
# returns the index of the previous non-zero element, or 0 if all zeros
function findprev(B::BitArray, start::Integer)
start > 0 || return 0
start > length(B) && throw(BoundsError(B, start))
Bc = B.chunks
chunk_start = _div64(start-1)+1
mask = _msk_end(start)
@inbounds begin
if Bc[chunk_start] & mask != 0
return (chunk_start-1) << 6 + (64 - leading_zeros(Bc[chunk_start] & mask))
end
for i = (chunk_start-1):-1:1
if Bc[i] != 0
return (i-1) << 6 + (64 - leading_zeros(Bc[i]))
end
end
end
return 0
end
function findprevnot(B::BitArray, start::Integer)
start > 0 || return 0
start > length(B) && throw(BoundsError(B, start))
Bc = B.chunks
chunk_start = _div64(start-1)+1
mask = ~_msk_end(start)
@inbounds begin
if Bc[chunk_start] | mask != _msk64
return (chunk_start-1) << 6 + (64 - leading_ones(Bc[chunk_start] | mask))
end
for i = chunk_start-1:-1:1
if Bc[i] != _msk64
return (i-1) << 6 + (64 - leading_ones(Bc[i]))
end
end
end
return 0
end
findlastnot(B::BitArray) = findprevnot(B, length(B))
# returns the index of the previous matching element
function findprev(B::BitArray, v, start::Integer)
v == false && return findprevnot(B, start)
v == true && return findprev(B, start)
return 0
end
#findlast(B::BitArray, v) = findprev(B, 1, v) ## defined in array.jl
# returns the index of the previous element for which the function returns true
function findprev(testf::Function, B::BitArray, start::Integer)
f0::Bool = testf(false)
f1::Bool = testf(true)
!f0 && f1 && return findprev(B, start)
f0 && !f1 && return findprevnot(B, start)
start > 0 || return 0
start > length(B) && throw(BoundsError(B, start))
f0 && f1 && return Int(start)
return 0 # last case: !f0 && !f1
end
#findlast(testf::Function, B::BitArray) = findprev(testf, B, 1) ## defined in array.jl
function find(B::BitArray)
l = length(B)
nnzB = countnz(B)
I = Array{Int}(nnzB)
nnzB == 0 && return I
Bc = B.chunks
Bcount = 1
Icount = 1
for i = 1:length(Bc)-1
u = UInt64(1)
c = Bc[i]
for j = 1:64
if c & u != 0
I[Icount] = Bcount
Icount += 1
end
Bcount += 1
u <<= 1
end
end
u = UInt64(1)
c = Bc[end]
for j = 0:_mod64(l-1)
if c & u != 0
I[Icount] = Bcount
Icount += 1
end
Bcount += 1
u <<= 1
end
return I
end
findn(B::BitVector) = find(B)
function findn(B::BitMatrix)
nnzB = countnz(B)
I = Array{Int}(nnzB)
J = Array{Int}(nnzB)
count = 1
for j = 1:size(B,2), i = 1:size(B,1)
if B[i,j]
I[count] = i
J[count] = j
count += 1
end
end
return I, J
end
function findnz(B::BitMatrix)
I, J = findn(B)
return I, J, trues(length(I))
end
## Reductions ##
sum(A::BitArray, region) = reducedim(+, A, region)
sum(B::BitArray) = countnz(B)
function all(B::BitArray)
isempty(B) && return true
Bc = B.chunks
@inbounds begin
for i = 1:length(Bc)-1
Bc[i] == _msk64 || return false
end
Bc[end] == _msk_end(B) || return false
end
return true
end
function any(B::BitArray)
isempty(B) && return false
Bc = B.chunks
@inbounds begin
for i = 1:length(Bc)
Bc[i] == 0 || return true
end
end
return false
end
minimum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : all(B)
maximum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : any(B)
## map over bitarrays ##
# Specializing map is even more important for bitarrays than it is for generic
# arrays since there can be a 64x speedup by working at the level of Int64
# instead of looping bit-by-bit.
map(f::Function, A::BitArray) = map!(f, similar(A), A)
map(f::Function, A::BitArray, B::BitArray) = map!(f, similar(A), A, B)
map!(f, A::BitArray) = map!(f, A, A)
map!(f::typeof(!), dest::BitArray, A::BitArray) = map!(~, dest, A)
map!(f::typeof(zero), dest::BitArray, A::BitArray) = fill!(dest, false)
map!(f::typeof(one), dest::BitArray, A::BitArray) = fill!(dest, true)
immutable BitChunkFunctor{F<:Function}
f::F
end
(f::BitChunkFunctor)(x, y) = f.f(x,y)
map!(f::Union{typeof(*), typeof(min)}, dest::BitArray, A::BitArray, B::BitArray) = map!(&, dest, A, B)
map!(f::typeof(max), dest::BitArray, A::BitArray, B::BitArray) = map!(|, dest, A, B)
map!(f::typeof(!=), dest::BitArray, A::BitArray, B::BitArray) = map!($, dest, A, B)
map!(f::Union{typeof(>=), typeof(^)}, dest::BitArray, A::BitArray, B::BitArray) = map!(BitChunkFunctor((p, q) -> p | ~q), dest, A, B)
map!(f::typeof(<=), dest::BitArray, A::BitArray, B::BitArray) = map!(BitChunkFunctor((p, q) -> ~p | q), dest, A, B)
map!(f::typeof(==), dest::BitArray, A::BitArray, B::BitArray) = map!(BitChunkFunctor((p, q) -> ~(p $ q)), dest, A, B)
map!(f::typeof(<), dest::BitArray, A::BitArray, B::BitArray) = map!(BitChunkFunctor((p, q) -> ~p & q), dest, A, B)
map!(f::typeof(>), dest::BitArray, A::BitArray, B::BitArray) = map!(BitChunkFunctor((p, q) -> p & ~q), dest, A, B)
# If we were able to specialize the function to a known bitwise operation,
# map across the chunks. Otherwise, fall-back to the AbstractArray method that
# iterates bit-by-bit.
function map!(f::Union{typeof(identity), typeof(~)}, dest::BitArray, A::BitArray)
size(A) == size(dest) || throw(DimensionMismatch("sizes of dest and A must match"))
isempty(A) && return dest
destc = dest.chunks
Ac = A.chunks
for i = 1:(length(Ac)-1)
destc[i] = f(Ac[i])
end
destc[end] = f(Ac[end]) & _msk_end(A)
dest
end
function map!(f::Union{BitChunkFunctor, typeof(&), typeof(|), typeof($)}, dest::BitArray, A::BitArray, B::BitArray)
size(A) == size(B) == size(dest) || throw(DimensionMismatch("sizes of dest, A, and B must all match"))
isempty(A) && return dest
destc = dest.chunks
Ac = A.chunks
Bc = B.chunks
for i = 1:(length(Ac)-1)
destc[i] = f(Ac[i], Bc[i])
end
destc[end] = f(Ac[end], Bc[end]) & _msk_end(A)
dest
end
## Filter ##
function filter(f, Bs::BitArray)
boolmap::Array{Bool} = map(f, Bs)
Bs[boolmap]
end
## Transpose ##
transpose(B::BitVector) = reshape(copy(B), 1, length(B))
# fast 8x8 bit transpose from Henry S. Warrens's "Hacker's Delight"
# http://www.hackersdelight.org/hdcodetxt/transpose8.c.txt
function transpose8x8(x::UInt64)
y = x
t = (y $ (y >>> 7)) & 0x00aa00aa00aa00aa
y = y $ t $ (t << 7)
t = (y $ (y >>> 14)) & 0x0000cccc0000cccc
y = y $ t $ (t << 14)
t = (y $ (y >>> 28)) & 0x00000000f0f0f0f0
return y $ t $ (t << 28)
end
function form_8x8_chunk(Bc::Vector{UInt64}, i1::Int, i2::Int, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::UInt64)
x = UInt64(0)
k, l = get_chunks_id(i1 + (i2 - 1) * m)
r = 0
for j = 1:8
k > nc && break
x |= ((Bc[k] >>> l) & msk8) << r
if l + 8 >= 64 && nc > k
r0 = 8 - _mod64(l + 8)
x |= (Bc[k + 1] & (msk8 >>> r0)) << (r + r0)
end
k += cgap + (l + cinc >= 64 ? 1 : 0)
l = _mod64(l + cinc)
r += 8
end
return x
end
# note: assumes B is filled with 0's
function put_8x8_chunk(Bc::Vector{UInt64}, i1::Int, i2::Int, x::UInt64, m::Int, cgap::Int, cinc::Int, nc::Int, msk8::UInt64)
k, l = get_chunks_id(i1 + (i2 - 1) * m)
r = 0
for j = 1:8
k > nc && break
Bc[k] |= ((x >>> r) & msk8) << l
if l + 8 >= 64 && nc > k
r0 = 8 - _mod64(l + 8)
Bc[k + 1] |= ((x >>> (r + r0)) & (msk8 >>> r0))
end
k += cgap + (l + cinc >= 64 ? 1 : 0)
l = _mod64(l + cinc)
r += 8
end
return
end
function transpose(B::BitMatrix)
l1 = size(B, 1)
l2 = size(B, 2)
Bt = falses(l2, l1)
cgap1, cinc1 = _div64(l1), _mod64(l1)
cgap2, cinc2 = _div64(l2), _mod64(l2)
Bc = B.chunks
Btc = Bt.chunks
nc = length(Bc)
for i = 1:8:l1
msk8_1 = UInt64(0xff)
if (l1 < i + 7)
msk8_1 >>>= i + 7 - l1
end
for j = 1:8:l2
x = form_8x8_chunk(Bc, i, j, l1, cgap1, cinc1, nc, msk8_1)
x = transpose8x8(x)
msk8_2 = UInt64(0xff)
if (l2 < j + 7)
msk8_2 >>>= j + 7 - l2
end
put_8x8_chunk(Btc, j, i, x, l2, cgap2, cinc2, nc, msk8_2)
end
end
return Bt
end
ctranspose(B::BitArray) = transpose(B)
## Concatenation ##
function hcat(B::BitVector...)
height = length(B[1])
for j = 2:length(B)
length(B[j]) == height ||
throw(DimensionMismatch("dimensions must match"))
end
M = BitArray(height, length(B))
for j = 1:length(B)
copy_chunks!(M.chunks, (height*(j-1))+1, B[j].chunks, 1, height)
end
return M
end
function vcat(V::BitVector...)
n = 0
for Vk in V
n += length(Vk)
end
B = BitArray(n)
j = 1
for Vk in V
copy_chunks!(B.chunks, j, Vk.chunks, 1, length(Vk))
j += length(Vk)
end
return B
end
function hcat(A::Union{BitMatrix,BitVector}...)
nargs = length(A)
nrows = size(A[1], 1)
ncols = 0
dense = true
for j = 1:nargs
Aj = A[j]
nd = ndims(Aj)
ncols += (nd==2 ? size(Aj,2) : 1)
size(Aj, 1) == nrows ||
throw(DimensionMismatch("row lengths must match"))
end
B = BitArray(nrows, ncols)
pos = 1
for k = 1:nargs
Ak = A[k]
n = length(Ak)
copy_chunks!(B.chunks, pos, Ak.chunks, 1, n)
pos += n
end
return B
end
function vcat(A::BitMatrix...)
nargs = length(A)
nrows = sum(a->size(a, 1), A)::Int
ncols = size(A[1], 2)
for j = 2:nargs
size(A[j], 2) == ncols ||
throw(DimensionMismatch("column lengths must match"))
end
B = BitArray(nrows, ncols)
Bc = B.chunks
nrowsA = [size(a, 1) for a in A]
Ac = [a.chunks for a in A]
pos_d = 1
pos_s = ones(Int, nargs)
for j = 1:ncols, k = 1:nargs
copy_chunks!(Bc, pos_d, Ac[k], pos_s[k], nrowsA[k])
pos_s[k] += nrowsA[k]
pos_d += nrowsA[k]
end
return B
end
function cat(catdim::Integer, X::Integer...)
reshape([X...], (ones(Int,catdim-1)..., length(X)))
end
# general case, specialized for BitArrays and Integers
function cat(catdim::Integer, X::Union{BitArray, Integer}...)
nargs = length(X)
# using integers results in conversion to Array{Int}
# (except in the all-Bool case)
has_integer = false
for a in X
if isa(a, Integer)
has_integer = true; break
end
end
dimsX = map((a->isa(a,BitArray) ? size(a) : (1,)), X)
ndimsX = map((a->isa(a,BitArray) ? ndims(a) : 1), X)
d_max = maximum(ndimsX)
if catdim > d_max + 1
for i = 1:nargs
dimsX[1] == dimsX[i] ||
throw(DimensionMismatch("all inputs must have same dimensions when concatenating along a higher dimension"))
end
elseif nargs >= 2
for d = 1:d_max
d == catdim && continue
len = d <= ndimsX[1] ? dimsX[1][d] : 1
for i = 2:nargs
len == (d <= ndimsX[i] ? dimsX[i][d] : 1) || throw(DimensionMismatch("mismatch in dimension $d"))
end
end
end
cat_ranges = ntuple(i->(catdim <= ndimsX[i] ? dimsX[i][catdim] : 1), nargs)
function compute_dims(d)
if d == catdim
catdim <= d_max && return sum(cat_ranges)
return nargs
else
d <= ndimsX[1] && return dimsX[1][d]
return 1
end
end
ndimsC = max(catdim, d_max)
dimsC = ntuple(compute_dims, ndimsC)::Tuple{Vararg{Int}}
typeC = promote_type(map(x->isa(x,BitArray) ? eltype(x) : typeof(x), X)...)
if !has_integer || typeC == Bool
C = BitArray(dimsC)
else
C = Array{typeC}(dimsC)
end
range = 1
for k = 1:nargs
nextrange = range + cat_ranges[k]
cat_one = ntuple(i->(i != catdim ? (1:dimsC[i]) : (range:nextrange-1)),
ndimsC)
# note: when C and X are BitArrays, this calls
# the special assign with ranges
C[cat_one...] = X[k]
range = nextrange
end
return C
end
# hvcat -> use fallbacks in abstractarray.jl
# BitArray I/O
write(s::IO, B::BitArray) = write(s, B.chunks)
function read!(s::IO, B::BitArray)
n = length(B)
Bc = B.chunks
nc = length(read!(s, Bc))
if length(Bc) > 0 && Bc[end] & _msk_end(n) ≠ Bc[end]
Bc[end] &= _msk_end(n) # ensure that the BitArray is not broken
throw(DimensionMismatch("read mismatch, found non-zero bits after BitArray length"))
end
return B
end
sizeof(B::BitArray) = sizeof(B.chunks)
# This file is a part of Julia. License is MIT: http://julialang.org/license
## boolean conversions ##
convert(::Type{Bool}, x::Bool) = x
convert(::Type{Bool}, x::Float16) = x==0 ? false : x==1 ? true : throw(InexactError())
convert(::Type{Bool}, x::Real) = x==0 ? false : x==1 ? true : throw(InexactError())
# promote Bool to any other numeric type
promote_rule{T<:Number}(::Type{Bool}, ::Type{T}) = T
typemin(::Type{Bool}) = false
typemax(::Type{Bool}) = true
## boolean operations ##
function !(x::Bool)
## We need a better heuristic to detect this automatically
@_pure_meta
return box(Bool,not_int(unbox(Bool,x)))
end
(~)(x::Bool) = !x
(&)(x::Bool, y::Bool) = box(Bool,and_int(unbox(Bool,x),unbox(Bool,y)))
(|)(x::Bool, y::Bool) = box(Bool,or_int(unbox(Bool,x),unbox(Bool,y)))
($)(x::Bool, y::Bool) = (x!=y)
>>(x::Bool, c::Unsigned) = Int(x) >> c
<<(x::Bool, c::Unsigned) = Int(x) << c
>>>(x::Bool, c::Unsigned) = Int(x) >>> c
>>(x::Bool, c::Int) = Int(x) >> c
<<(x::Bool, c::Int) = Int(x) << c
>>>(x::Bool, c::Int) = Int(x) >>> c
>>(x::Bool, c::Integer) = Int(x) >> c
<<(x::Bool, c::Integer) = Int(x) << c
>>>(x::Bool, c::Integer) = Int(x) >>> c
signbit(x::Bool) = false
sign(x::Bool) = x
abs(x::Bool) = x
abs2(x::Bool) = x
<(x::Bool, y::Bool) = y&!x
<=(x::Bool, y::Bool) = y|!x
## do arithmetic as Int ##
+(x::Bool) = Int(x)
-(x::Bool) = -Int(x)
+(x::Bool, y::Bool) = Int(x) + Int(y)
-(x::Bool, y::Bool) = Int(x) - Int(y)
*(x::Bool, y::Bool) = x & y
^(x::Bool, y::Bool) = x | !y
^(x::Integer, y::Bool) = ifelse(y, x, one(x))
function +{T<:AbstractFloat}(x::Bool, y::T)::promote_type(Bool,T)
return ifelse(x, one(y) + y, y)
end
+(y::AbstractFloat, x::Bool) = x + y
function *{T<:Number}(x::Bool, y::T)::promote_type(Bool,T)
return ifelse(x, y, copysign(zero(y), y))
end
function *{T<:Unsigned}(x::Bool, y::T)::promote_type(Bool,T)
return ifelse(x, y, zero(y))
end
*(y::Number, x::Bool) = x * y
div(x::Bool, y::Bool) = y ? x : throw(DivideError())
fld(x::Bool, y::Bool) = div(x,y)
cld(x::Bool, y::Bool) = div(x,y)
rem(x::Bool, y::Bool) = y ? false : throw(DivideError())
mod(x::Bool, y::Bool) = rem(x,y)
# This file is a part of Julia. License is MIT: http://julialang.org/license
# commented-out definitions are implemented in C
#abstract Any <: Any
#abstract Type{T}
#abstract Vararg{T}
#Tuple = (Any...)
#type Symbol
# #opaque
#end
#type TypeName
# name::Symbol
#end
#type DataType <: Type
# name::TypeName
# super::Type
# parameters::Tuple
# names::Tuple
# types::Tuple
# ctor
# instance
# size::Int32
# abstract::Bool
# mutable::Bool
# pointerfree::Bool
#end
#type Union <: Type
# types::Tuple
#end
#type TypeVar
# name::Symbol
# lb::Type
# ub::Type
#end
#type TypeConstructor
# parameters::Tuple
# body
#end
#immutable Void
#end
#const nothing = Void()
#abstract AbstractArray{T,N}
#abstract DenseArray{T,N} <: AbstractArray{T,N}
#type Array{T,N} <: DenseArray{T,N}
#end
#type Module
# name::Symbol
#end
#type Method
#end
#type MethodInstance
#end
#type CodeInfo
#end
#type TypeMapLevel
#end
#type TypeMapEntry
#end
#abstract Ref{T}
#bitstype {32|64} Ptr{T} <: Ref{T}
# types for the front end
#type Expr
# head::Symbol
# args::Array{Any,1}
# typ::Any
#end
#immutable LineNumberNode
# line::Int
#end
#immutable LabelNode
# label::Int
#end
#immutable GotoNode
# label::Int
#end
#immutable QuoteNode
# value
#end
#immutable GlobalRef
# mod::Module
# name::Symbol
#end
# type Task
# parent::Task
# storage::Any
# consumers
# started::Bool
# done::Bool
# runnable::Bool
# end
import Core.Intrinsics.ccall
export
# key types
Any, DataType, Vararg, ANY, NTuple,
Tuple, Type, TypeConstructor, TypeName, TypeVar, Union, Void,
SimpleVector, AbstractArray, DenseArray,
# special objects
Function, CodeInfo, Method, MethodTable, TypeMapEntry, TypeMapLevel,
Module, Symbol, Task, Array, WeakRef, VecElement,
# numeric types
Number, Real, Integer, Bool, Ref, Ptr,
AbstractFloat, Float16, Float32, Float64,
Signed, Int, Int8, Int16, Int32, Int64, Int128,
Unsigned, UInt, UInt8, UInt16, UInt32, UInt64, UInt128,
# string types
Char, DirectIndexString, AbstractString, String, IO,
# errors
ErrorException, BoundsError, DivideError, DomainError, Exception, InexactError,
InterruptException, OutOfMemoryError, ReadOnlyMemoryError, OverflowError,
StackOverflowError, SegmentationFault, UndefRefError, UndefVarError, TypeError,
# AST representation
Expr, GotoNode, LabelNode, LineNumberNode, QuoteNode,
GlobalRef, NewvarNode, SSAValue, Slot, SlotNumber, TypedSlot,
# object model functions
fieldtype, getfield, setfield!, nfields, throw, tuple, ===, isdefined, eval,
# sizeof # not exported, to avoid conflicting with Base.sizeof
# type reflection
issubtype, typeof, isa, typeassert,
# method reflection
applicable, invoke,
# constants
nothing, Main
typealias AnyVector Array{Any,1}
abstract Number
abstract Real <: Number
abstract AbstractFloat <: Real
abstract Integer <: Real
abstract Signed <: Integer
abstract Unsigned <: Integer
bitstype 16 Float16 <: AbstractFloat
bitstype 32 Float32 <: AbstractFloat
bitstype 64 Float64 <: AbstractFloat
bitstype 8 Bool <: Integer
bitstype 32 Char
bitstype 8 Int8 <: Signed
bitstype 8 UInt8 <: Unsigned
bitstype 16 Int16 <: Signed
bitstype 16 UInt16 <: Unsigned
bitstype 32 Int32 <: Signed
bitstype 32 UInt32 <: Unsigned
bitstype 64 Int64 <: Signed
bitstype 64 UInt64 <: Unsigned
bitstype 128 Int128 <: Signed
bitstype 128 UInt128 <: Unsigned
if Int === Int64
typealias UInt UInt64
else
typealias UInt UInt32
end
abstract AbstractString
function Typeof end
(f::typeof(Typeof))(x::ANY) = isa(x,Type) ? Type{x} : typeof(x)
abstract Exception
type ErrorException <: Exception
msg::AbstractString
ErrorException(msg::AbstractString) = new(msg)
end
immutable BoundsError <: Exception
a::Any
i::Any
BoundsError() = new()
BoundsError(a::ANY) = new(a)
BoundsError(a::ANY, i::ANY) = new(a,i)
end
immutable DivideError <: Exception end
immutable DomainError <: Exception end
immutable OverflowError <: Exception end
immutable InexactError <: Exception end
immutable OutOfMemoryError <: Exception end
immutable ReadOnlyMemoryError<: Exception end
immutable SegmentationFault <: Exception end
immutable StackOverflowError <: Exception end
immutable UndefRefError <: Exception end
immutable UndefVarError <: Exception
var::Symbol
end
immutable InterruptException <: Exception end
type TypeError <: Exception
func::Symbol
context::AbstractString
expected::Type
got
end
abstract DirectIndexString <: AbstractString
immutable String <: AbstractString
data::Array{UInt8,1}
# required to make String("foo") work (#15120):
String(d::Array{UInt8,1}) = new(d)
end
# This should always be inlined
getptls() = ccall(:jl_get_ptls_states, Ptr{Void}, ())
include(fname::String) = ccall(:jl_load_, Any, (Any,), fname)
eval(e::ANY) = eval(Main, e)
eval(m::Module, e::ANY) = ccall(:jl_toplevel_eval_in, Any, (Any, Any), m, e)
kwfunc(f::ANY) = ccall(:jl_get_keyword_sorter, Any, (Any,), f)
kwftype(t::ANY) = typeof(ccall(:jl_get_kwsorter, Any, (Any,), t.name))
type Box
contents::Any
Box(x::ANY) = new(x)
Box() = new()
end
# constructors for built-in types
type WeakRef
value
WeakRef() = WeakRef(nothing)
WeakRef(v::ANY) = ccall(:jl_gc_new_weakref_th, Ref{WeakRef},
(Ptr{Void}, Any), getptls(), v)
end
TypeVar(n::Symbol) =
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, Union{}, Any)
TypeVar(n::Symbol, ub::ANY) =
(isa(ub,Bool) ?
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, Union{}, Any, ub) :
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, Union{}, ub::Type))
TypeVar(n::Symbol, lb::ANY, ub::ANY) =
(isa(ub,Bool) ?
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, Union{}, lb::Type, ub) :
ccall(:jl_new_typevar, Ref{TypeVar}, (Any, Any, Any), n, lb::Type, ub::Type))
TypeVar(n::Symbol, lb::ANY, ub::ANY, b::Bool) =
ccall(:jl_new_typevar_, Ref{TypeVar}, (Any, Any, Any, Any), n, lb::Type, ub::Type, b)
TypeConstructor(p::ANY, t::ANY) =
ccall(:jl_new_type_constructor, Ref{TypeConstructor}, (Any, Any), p::SimpleVector, t::Type)
Void() = nothing
immutable VecElement{T}
value::T
VecElement(value::T) = new(value) # disable converting constructor in Core
end
VecElement{T}(arg::T) = VecElement{T}(arg)
Expr(args::ANY...) = _expr(args...)
# used by lowering of splicing unquote
splicedexpr(hd::Symbol, args::Array{Any,1}) = (e=Expr(hd); e.args=args; e)
_new(typ::Symbol, argty::Symbol) = eval(:((::Type{$typ})(n::$argty) = $(Expr(:new, typ, :n))))
_new(:LabelNode, :Int)
_new(:GotoNode, :Int)
_new(:NewvarNode, :SlotNumber)
_new(:QuoteNode, :ANY)
_new(:SSAValue, :Int)
eval(:((::Type{LineNumberNode})(l::Int) = $(Expr(:new, :LineNumberNode, :l))))
eval(:((::Type{GlobalRef})(m::Module, s::Symbol) = $(Expr(:new, :GlobalRef, :m, :s))))
eval(:((::Type{SlotNumber})(n::Int) = $(Expr(:new, :SlotNumber, :n))))
eval(:((::Type{TypedSlot})(n::Int, t::ANY) = $(Expr(:new, :TypedSlot, :n, :t))))
Module(name::Symbol=:anonymous, std_imports::Bool=true) = ccall(:jl_f_new_module, Ref{Module}, (Any, Bool), name, std_imports)
Task(f::ANY) = ccall(:jl_new_task, Ref{Task}, (Any, Int), f, 0)
# simple convert for use by constructors of types in Core
# note that there is no actual conversion defined here,
# so the methods and ccall's in Core aren't permitted to use convert
convert(::Type{Any}, x::ANY) = x
convert{T}(::Type{T}, x::T) = x
cconvert{T}(::Type{T}, x) = convert(T, x)
unsafe_convert{T}(::Type{T}, x::T) = x
typealias NTuple{N,T} Tuple{Vararg{T,N}}
# primitive array constructors
(::Type{Array{T,N}}){T,N}(d::NTuple{N,Int}) =
ccall(:jl_new_array, Array{T,N}, (Any,Any), Array{T,N}, d)
(::Type{Array{T,1}}){T}(d::NTuple{1,Int}) = Array{T,1}(getfield(d,1))
(::Type{Array{T,2}}){T}(d::NTuple{2,Int}) = Array{T,2}(getfield(d,1), getfield(d,2))
(::Type{Array{T,3}}){T}(d::NTuple{3,Int}) = Array{T,3}(getfield(d,1), getfield(d,2), getfield(d,3))
(::Type{Array{T,N}}){T,N}(d::Vararg{Int, N}) = ccall(:jl_new_array, Array{T,N}, (Any,Any), Array{T,N}, d)
(::Type{Array{T,1}}){T}(m::Int) =
ccall(:jl_alloc_array_1d, Array{T,1}, (Any,Int), Array{T,1}, m)
(::Type{Array{T,2}}){T}(m::Int, n::Int) =
ccall(:jl_alloc_array_2d, Array{T,2}, (Any,Int,Int), Array{T,2}, m, n)
(::Type{Array{T,3}}){T}(m::Int, n::Int, o::Int) =
ccall(:jl_alloc_array_3d, Array{T,3}, (Any,Int,Int,Int), Array{T,3}, m, n, o)
(::Type{Array{T}}){T,N}(d::NTuple{N,Int}) = Array{T,N}(d)
(::Type{Array{T}}){T}(m::Int) = Array{T,1}(m)
(::Type{Array{T}}){T}(m::Int, n::Int) = Array{T,2}(m, n)
(::Type{Array{T}}){T}(m::Int, n::Int, o::Int) = Array{T,3}(m, n, o)
(::Type{Array{T,1}}){T}() = Array{T,1}(0)
(::Type{Array{T,2}}){T}() = Array{T,2}(0, 0)
# TODO: possibly turn these into deprecations
Array{T,N}(::Type{T}, d::NTuple{N,Int}) = Array{T,N}(d)
Array{T}(::Type{T}, d::Int...) = Array(T, d)
Array{T}(::Type{T}, m::Int) = Array{T,1}(m)
Array{T}(::Type{T}, m::Int,n::Int) = Array{T,2}(m,n)
Array{T}(::Type{T}, m::Int,n::Int,o::Int) = Array{T,3}(m,n,o)
# docsystem basics
macro doc(x...)
atdoc(x...)
end
macro __doc__(x)
Expr(:escape, Expr(:block, Expr(:meta, :doc), x))
end
macro doc_str(s)
Expr(:escape, s)
end
atdoc = (str, expr) -> Expr(:escape, expr)
atdoc!(λ) = global atdoc = λ
# simple stand-alone print definitions for debugging
abstract IO
type CoreSTDOUT <: IO end
type CoreSTDERR <: IO end
const STDOUT = CoreSTDOUT()
const STDERR = CoreSTDERR()
io_pointer(::CoreSTDOUT) = Intrinsics.pointerref(Intrinsics.cglobal(:jl_uv_stdout, Ptr{Void}), 1, 1)
io_pointer(::CoreSTDERR) = Intrinsics.pointerref(Intrinsics.cglobal(:jl_uv_stderr, Ptr{Void}), 1, 1)
unsafe_write(io::IO, x::Ptr{UInt8}, nb::UInt) =
(ccall(:jl_uv_puts, Void, (Ptr{Void}, Ptr{UInt8}, UInt), io_pointer(io), x, nb); nb)
unsafe_write(io::IO, x::Ptr{UInt8}, nb::Int) =
(ccall(:jl_uv_puts, Void, (Ptr{Void}, Ptr{UInt8}, Int), io_pointer(io), x, nb); nb)
write(io::IO, x::UInt8) =
(ccall(:jl_uv_putb, Void, (Ptr{Void}, UInt8), io_pointer(io), x); 1)
function write(io::IO, x::String)
nb = sizeof(x.data)
unsafe_write(io, ccall(:jl_array_ptr, Ptr{UInt8}, (Any,), x.data), nb)
return nb
end
show(io::IO, x::ANY) = ccall(:jl_static_show, Void, (Ptr{Void}, Any), io_pointer(io), x)
print(io::IO, x::Char) = ccall(:jl_uv_putc, Void, (Ptr{Void}, Char), io_pointer(io), x)
print(io::IO, x::String) = write(io, x)
print(io::IO, x::ANY) = show(io, x)
print(io::IO, x::ANY, a::ANY...) = (print(io, x); print(io, a...))
println(io::IO) = write(io, 0x0a) # 0x0a = '\n'
println(io::IO, x::ANY...) = (print(io, x...); println(io))
show(a::ANY) = show(STDOUT, a)
print(a::ANY...) = print(STDOUT, a...)
println(a::ANY...) = println(STDOUT, a...)
ccall(:jl_set_istopmod, Void, (Bool,), true)
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Broadcast
using Base.Cartesian
using Base: promote_eltype_op, linearindices, tail, OneTo, to_shape,
_msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache
import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, .÷, .%, .<<, .>>, .^
import Base: broadcast
export broadcast!, bitbroadcast, dotview
export broadcast_getindex, broadcast_setindex!
## Broadcasting utilities ##
# fallback for broadcasting with zero arguments and some special cases
broadcast(f) = f()
@inline broadcast(f, x::Number...) = f(x...)
@inline broadcast{N}(f, t::NTuple{N}, ts::Vararg{NTuple{N}}) = map(f, t, ts...)
@inline broadcast(f, As::AbstractArray...) = broadcast_t(f, promote_eltype_op(f, As...), As...)
# special cases for "X .= ..." (broadcast!) assignments
broadcast!(::typeof(identity), X::AbstractArray, x::Number) = fill!(X, x)
broadcast!(f, X::AbstractArray) = fill!(X, f())
broadcast!(f, X::AbstractArray, x::Number...) = fill!(X, f(x...))
function broadcast!{T,S,N}(::typeof(identity), x::AbstractArray{T,N}, y::AbstractArray{S,N})
check_broadcast_shape(broadcast_indices(x), broadcast_indices(y))
copy!(x, y)
end
# logic for deciding the resulting container type
containertype(x) = containertype(typeof(x))
containertype(::Type) = Any
containertype{T<:Tuple}(::Type{T}) = Tuple
containertype{T<:AbstractArray}(::Type{T}) = Array
containertype(ct1, ct2) = promote_containertype(containertype(ct1), containertype(ct2))
@inline containertype(ct1, ct2, cts...) = promote_containertype(containertype(ct1), containertype(ct2, cts...))
promote_containertype(::Type{Array}, ::Type{Array}) = Array
promote_containertype(::Type{Array}, ct) = Array
promote_containertype(ct, ::Type{Array}) = Array
promote_containertype(::Type{Tuple}, ::Type{Any}) = Tuple
promote_containertype(::Type{Any}, ::Type{Tuple}) = Tuple
promote_containertype{T}(::Type{T}, ::Type{T}) = T
## Calculate the broadcast indices of the arguments, or error if incompatible
# array inputs
broadcast_indices() = ()
broadcast_indices(A) = broadcast_indices(containertype(A), A)
broadcast_indices(::Type{Any}, A) = ()
broadcast_indices(::Type{Tuple}, A) = (OneTo(length(A)),)
broadcast_indices(::Type{Array}, A) = indices(A)
@inline broadcast_indices(A, B...) = broadcast_shape((), broadcast_indices(A), map(broadcast_indices, B)...)
# shape (i.e., tuple-of-indices) inputs
broadcast_shape(shape::Tuple) = shape
@inline broadcast_shape(shape::Tuple, shape1::Tuple, shapes::Tuple...) = broadcast_shape(_bcs((), shape, shape1), shapes...)
# _bcs consolidates two shapes into a single output shape
_bcs(out, ::Tuple{}, ::Tuple{}) = out
@inline _bcs(out, ::Tuple{}, newshape) = _bcs((out..., newshape[1]), (), tail(newshape))
@inline _bcs(out, shape, ::Tuple{}) = _bcs((out..., shape[1]), tail(shape), ())
@inline function _bcs(out, shape, newshape)
newout = _bcs1(shape[1], newshape[1])
_bcs((out..., newout), tail(shape), tail(newshape))
end
# _bcs1 handles the logic for a single dimension
_bcs1(a::Integer, b::Integer) = a == 1 ? b : (b == 1 ? a : (a == b ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size"))))
_bcs1(a::Integer, b) = a == 1 ? b : (first(b) == 1 && last(b) == a ? b : throw(DimensionMismatch("arrays could not be broadcast to a common size")))
_bcs1(a, b::Integer) = _bcs1(b, a)
_bcs1(a, b) = _bcsm(b, a) ? b : (_bcsm(a, b) ? a : throw(DimensionMismatch("arrays could not be broadcast to a common size")))
# _bcsm tests whether the second index is consistent with the first
_bcsm(a, b) = a == b || length(b) == 1
_bcsm(a, b::Number) = b == 1
_bcsm(a::Number, b::Number) = a == b || b == 1
## Check that all arguments are broadcast compatible with shape
# comparing one input against a shape
check_broadcast_shape(shp) = nothing
check_broadcast_shape(shp, ::Tuple{}) = nothing
check_broadcast_shape(::Tuple{}, ::Tuple{}) = nothing
check_broadcast_shape(::Tuple{}, Ashp::Tuple) = throw(DimensionMismatch("cannot broadcast array to have fewer dimensions"))
function check_broadcast_shape(shp, Ashp::Tuple)
_bcsm(shp[1], Ashp[1]) || throw(DimensionMismatch("array could not be broadcast to match destination"))
check_broadcast_shape(tail(shp), tail(Ashp))
end
check_broadcast_indices(shp, A) = check_broadcast_shape(shp, broadcast_indices(A))
# comparing many inputs
@inline function check_broadcast_indices(shp, A, As...)
check_broadcast_indices(shp, A)
check_broadcast_indices(shp, As...)
end
## Indexing manipulations
# newindex(I, keep, Idefault) replaces a CartesianIndex `I` with something that
# is appropriate for a particular broadcast array/scalar. `keep` is a
# NTuple{N,Bool}, where keep[d] == true means that one should preserve
# I[d]; if false, replace it with Idefault[d].
@inline newindex(I::CartesianIndex, keep, Idefault) = CartesianIndex(_newindex(I.I, keep, Idefault))
@inline _newindex(I, keep, Idefault) =
(ifelse(keep[1], I[1], Idefault[1]), _newindex(tail(I), tail(keep), tail(Idefault))...)
@inline _newindex(I, keep::Tuple{}, Idefault) = () # truncate if keep is shorter than I
# newindexer(shape, A) generates `keep` and `Idefault` (for use by
# `newindex` above) for a particular array `A`, given the
# broadcast_indices `shape`
# `keep` is equivalent to map(==, indices(A), shape) (but see #17126)
@inline newindexer(shape, A) = shapeindexer(shape, broadcast_indices(A))
@inline shapeindexer(shape, indsA::Tuple{}) = (), ()
@inline function shapeindexer(shape, indsA::Tuple)
ind1 = indsA[1]
keep, Idefault = shapeindexer(tail(shape), tail(indsA))
(shape[1] == ind1, keep...), (first(ind1), Idefault...)
end
# Equivalent to map(x->newindexer(shape, x), As) (but see #17126)
map_newindexer(shape, ::Tuple{}) = (), ()
@inline function map_newindexer(shape, As)
A1 = As[1]
keeps, Idefaults = map_newindexer(shape, tail(As))
keep, Idefault = newindexer(shape, A1)
(keep, keeps...), (Idefault, Idefaults...)
end
@inline _broadcast_getindex(A, I) = _broadcast_getindex(containertype(A), A, I)
@inline _broadcast_getindex(::Type{Any}, A, I) = A
@inline _broadcast_getindex(::Any, A, I) = A[I]
## Broadcasting core
# nargs encodes the number of As arguments (which matches the number
# of keeps). The first two type parameters are to ensure specialization.
@generated function _broadcast!{K,ID,AT,nargs}(f, B::AbstractArray, keeps::K, Idefaults::ID, As::AT, ::Type{Val{nargs}})
quote
$(Expr(:meta, :noinline))
# destructure the keeps and As tuples
@nexprs $nargs i->(A_i = As[i])
@nexprs $nargs i->(keep_i = keeps[i])
@nexprs $nargs i->(Idefault_i = Idefaults[i])
@simd for I in CartesianRange(indices(B))
# reverse-broadcast the indices
@nexprs $nargs i->(I_i = newindex(I, keep_i, Idefault_i))
# extract array values
@nexprs $nargs i->(@inbounds val_i = _broadcast_getindex(A_i, I_i))
# call the function and store the result
@inbounds B[I] = @ncall $nargs f val
end
end
end
# For BitArray outputs, we cache the result in a "small" Vector{Bool},
# and then copy in chunks into the output
@generated function _broadcast!{K,ID,AT,nargs}(f, B::BitArray, keeps::K, Idefaults::ID, As::AT, ::Type{Val{nargs}})
quote
$(Expr(:meta, :noinline))
# destructure the keeps and As tuples
@nexprs $nargs i->(A_i = As[i])
@nexprs $nargs i->(keep_i = keeps[i])
@nexprs $nargs i->(Idefault_i = Idefaults[i])
C = Vector{Bool}(bitcache_size)
Bc = B.chunks
ind = 1
cind = 1
@simd for I in CartesianRange(indices(B))
# reverse-broadcast the indices
@nexprs $nargs i->(I_i = newindex(I, keep_i, Idefault_i))
# extract array values
@nexprs $nargs i->(@inbounds val_i = _broadcast_getindex(A_i, I_i))
# call the function and store the result
@inbounds C[ind] = @ncall $nargs f val
ind += 1
if ind > bitcache_size
dumpbitcache(Bc, cind, C)
cind += bitcache_chunks
ind = 1
end
end
if ind > 1
@inbounds C[ind:bitcache_size] = false
dumpbitcache(Bc, cind, C)
end
end
end
"""
broadcast!(f, dest, As...)
Like [`broadcast`](:func:`broadcast`), but store the result of
`broadcast(f, As...)` in the `dest` array.
Note that `dest` is only used to store the result, and does not supply
arguments to `f` unless it is also listed in the `As`,
as in `broadcast!(f, A, A, B)` to perform `A[:] = broadcast(f, A, B)`.
"""
@inline function broadcast!{nargs}(f, B::AbstractArray, As::Vararg{Any,nargs})
shape = indices(B)
check_broadcast_indices(shape, As...)
keeps, Idefaults = map_newindexer(shape, As)
_broadcast!(f, B, keeps, Idefaults, As, Val{nargs})
B
end
# broadcast with computed element type
@generated function _broadcast!{K,ID,AT,nargs}(f, B::AbstractArray, keeps::K, Idefaults::ID, As::AT, ::Type{Val{nargs}}, iter, st, count)
quote
$(Expr(:meta, :noinline))
# destructure the keeps and As tuples
@nexprs $nargs i->(A_i = As[i])
@nexprs $nargs i->(keep_i = keeps[i])
@nexprs $nargs i->(Idefault_i = Idefaults[i])
while !done(iter, st)
I, st = next(iter, st)
# reverse-broadcast the indices
@nexprs $nargs i->(I_i = newindex(I, keep_i, Idefault_i))
# extract array values
@nexprs $nargs i->(@inbounds val_i = _broadcast_getindex(A_i, I_i))
# call the function
V = @ncall $nargs f val
S = typeof(V)
# store the result
if S <: eltype(B)
@inbounds B[I] = V
else
R = typejoin(eltype(B), S)
new = similar(B, R)
for II in Iterators.take(iter, count)
new[II] = B[II]
end
new[I] = V
return _broadcast!(f, new, keeps, Idefaults, As, Val{nargs}, iter, st, count+1)
end
count += 1
end
return B
end
end
function broadcast_t(f, ::Type{Any}, As...)
shape = broadcast_indices(As...)
iter = CartesianRange(shape)
if isempty(iter)
return similar(Array{Any}, shape)
end
nargs = length(As)
keeps, Idefaults = map_newindexer(shape, As)
st = start(iter)
I, st = next(iter, st)
val = f([ _broadcast_getindex(As[i], newindex(I, keeps[i], Idefaults[i])) for i=1:nargs ]...)
B = similar(Array{typeof(val)}, shape)
B[I] = val
return _broadcast!(f, B, keeps, Idefaults, As, Val{nargs}, iter, st, 1)
end
@inline broadcast_t(f, T, As...) = broadcast!(f, similar(Array{T}, broadcast_indices(As...)), As...)
function broadcast_c(f, ::Type{Tuple}, As...)
shape = broadcast_indices(As...)
check_broadcast_indices(shape, As...)
n = length(shape[1])
return ntuple(k->f((_broadcast_getindex(A, k) for A in As)...), n)
end
@inline broadcast_c(f, ::Type{Any}, a...) = f(a...)
@inline broadcast_c(f, ::Type{Array}, As...) = broadcast_t(f, promote_eltype_op(f, As...), As...)
"""
broadcast(f, As...)
Broadcasts the arrays, tuples and/or scalars `As` to a container of the
appropriate type and dimensions. In this context, anything that is not a
subtype of `AbstractArray` or `Tuple` is considered a scalar. The resulting
container is established by the following rules:
- If all the arguments are scalars, it returns a scalar.
- If the arguments are tuples and zero or more scalars, it returns a tuple.
- If there is at least an array in the arguments, it returns an array
(and treats tuples as 1-dimensional arrays) expanding singleton dimensions.
A special syntax exists for broadcasting: `f.(args...)` is equivalent to
`broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
single broadcast loop.
```jldoctest
julia> A = [1, 2, 3, 4, 5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> B = [1 2; 3 4; 5 6; 7 8; 9 10]
5×2 Array{Int64,2}:
1 2
3 4
5 6
7 8
9 10
julia> broadcast(+, A, B)
5×2 Array{Int64,2}:
2 3
5 6
8 9
11 12
14 15
julia> parse.(Int, ["1", "2"])
2-element Array{Int64,1}:
1
2
julia> abs.((1, -2))
(1,2)
julia> broadcast(+, 1.0, (0, -2.0))
(1.0,-1.0)
julia> broadcast(+, 1.0, (0, -2.0), [1])
2-element Array{Float64,1}:
2.0
0.0
julia> string.(("one","two","three","four"), ": ", 1:4)
4-element Array{String,1}:
"one: 1"
"two: 2"
"three: 3"
"four: 4"
```
"""
@inline broadcast(f, As...) = broadcast_c(f, containertype(As...), As...)
"""
bitbroadcast(f, As...)
Like [`broadcast`](:func:`broadcast`), but allocates a `BitArray` to store the
result, rather then an `Array`.
```jldoctest
julia> bitbroadcast(isodd,[1,2,3,4,5])
5-element BitArray{1}:
true
false
true
false
true
```
"""
@inline bitbroadcast(f, As...) = broadcast!(f, similar(BitArray, broadcast_indices(As...)), As...)
"""
broadcast_getindex(A, inds...)
Broadcasts the `inds` arrays to a common size like [`broadcast`](:func:`broadcast`)
and returns an array of the results `A[ks...]`,
where `ks` goes over the positions in the broadcast result `A`.
```jldoctest
julia> A = [1, 2, 3, 4, 5]
5-element Array{Int64,1}:
1
2
3
4
5
julia> B = [1 2; 3 4; 5 6; 7 8; 9 10]
5×2 Array{Int64,2}:
1 2
3 4
5 6
7 8
9 10
julia> C = broadcast(+,A,B)
5×2 Array{Int64,2}:
2 3
5 6
8 9
11 12
14 15
julia> broadcast_getindex(C,[1,2,10])
3-element Array{Int64,1}:
2
5
15
```
"""
broadcast_getindex(src::AbstractArray, I::AbstractArray...) = broadcast_getindex!(similar(Array{eltype(src)}, broadcast_indices(I...)), src, I...)
@generated function broadcast_getindex!(dest::AbstractArray, src::AbstractArray, I::AbstractArray...)
N = length(I)
Isplat = Expr[:(I[$d]) for d = 1:N]
quote
@nexprs $N d->(I_d = I[d])
check_broadcast_indices(indices(dest), $(Isplat...)) # unnecessary if this function is never called directly
checkbounds(src, $(Isplat...))
@nexprs $N d->(@nexprs $N k->(Ibcast_d_k = indices(I_k, d) == OneTo(1)))
@nloops $N i dest d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k)
@inbounds (@nref $N dest i) = (@nref $N src J)
end
dest
end
end
"""
broadcast_setindex!(A, X, inds...)
Broadcasts the `X` and `inds` arrays to a common size and stores the value from each
position in `X` at the indices in `A` given by the same positions in `inds`.
"""
@generated function broadcast_setindex!(A::AbstractArray, x, I::AbstractArray...)
N = length(I)
Isplat = Expr[:(I[$d]) for d = 1:N]
quote
@nexprs $N d->(I_d = I[d])
checkbounds(A, $(Isplat...))
shape = broadcast_indices($(Isplat...))
@nextract $N shape d->(length(shape) < d ? OneTo(1) : shape[d])
@nexprs $N d->(@nexprs $N k->(Ibcast_d_k = indices(I_k, d) == 1:1))
if !isa(x, AbstractArray)
xA = convert(eltype(A), x)
@nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(@inbounds J_k = @nref $N I_k d->j_d_k)
@inbounds (@nref $N A J) = xA
end
else
X = x
@nexprs $N d->(shapelen_d = length(shape_d))
@ncall $N Base.setindex_shape_check X shapelen
Xstate = start(X)
@inbounds @nloops $N i d->shape_d d->(@nexprs $N k->(j_d_k = Ibcast_d_k ? 1 : i_d)) begin
@nexprs $N k->(J_k = @nref $N I_k d->j_d_k)
x_el, Xstate = next(X, Xstate)
(@nref $N A J) = x_el
end
end
A
end
end
## elementwise operators ##
for op in (:÷, :%, :<<, :>>, :-, :/, :\, ://, :^)
@eval $(Symbol(:., op))(A::AbstractArray, B::AbstractArray) = broadcast($op, A, B)
end
.+(As::AbstractArray...) = broadcast(+, As...)
.*(As::AbstractArray...) = broadcast(*, As...)
# ## element-wise comparison operators returning BitArray ##
.==(A::AbstractArray, B::AbstractArray) = bitbroadcast(==, A, B)
.<(A::AbstractArray, B::AbstractArray) = bitbroadcast(<, A, B)
.!=(A::AbstractArray, B::AbstractArray) = bitbroadcast(!=, A, B)
.<=(A::AbstractArray, B::AbstractArray) = bitbroadcast(<=, A, B)
function broadcast_bitarrays(scalarf, bitf, A::AbstractArray{Bool}, B::AbstractArray{Bool})
local shape
try
shape = promote_shape(indices(A), indices(B))
catch
return bitbroadcast(scalarf, A, B)
end
F = BitArray(to_shape(shape))
Fc = F.chunks
Ac = BitArray(A).chunks
Bc = BitArray(B).chunks
if !isempty(Ac) && !isempty(Bc)
for i = 1:length(Fc) - 1
Fc[i] = (bitf)(Ac[i], Bc[i])
end
Fc[end] = (bitf)(Ac[end], Bc[end]) & _msk_end(F)
end
return F
end
biteq(a::UInt64, b::UInt64) = ~a $ b
bitlt(a::UInt64, b::UInt64) = ~a & b
bitneq(a::UInt64, b::UInt64) = a $ b
bitle(a::UInt64, b::UInt64) = ~a | b
.==(A::AbstractArray{Bool}, B::AbstractArray{Bool}) = broadcast_bitarrays(==, biteq, A, B)
.<(A::AbstractArray{Bool}, B::AbstractArray{Bool}) = broadcast_bitarrays(<, bitlt, A, B)
.!=(A::AbstractArray{Bool}, B::AbstractArray{Bool}) = broadcast_bitarrays(!=, bitneq, A, B)
.<=(A::AbstractArray{Bool}, B::AbstractArray{Bool}) = broadcast_bitarrays(<=, bitle, A, B)
function bitcache(op, A, B, refA, refB, l::Int, ind::Int, C::Vector{Bool})
left = l - ind + 1
@inbounds begin
for j = 1:min(bitcache_size, left)
C[j] = (op)(refA(A, ind), refB(B, ind))
ind += 1
end
C[left+1:bitcache_size] = false
end
return ind
end
# note: the following are not broadcasting, but need to be defined here to avoid
# ambiguity warnings
for (f, scalarf) in ((:.==, :(==)),
(:.< , :< ),
(:.!=, :!= ),
(:.<=, :<= ))
for (sigA, sigB, active, refA, refB) in ((:Any, :AbstractArray, :B,
:((A,ind)->A), :((B,ind)->B[ind])),
(:AbstractArray, :Any, :A,
:((A,ind)->A[ind]), :((B,ind)->B)))
shape = :(indices($active))
@eval begin
function ($f)(A::$sigA, B::$sigB)
P = similar(BitArray, $shape)
F = parent(P)
l = length(F)
l == 0 && return F
Fc = F.chunks
C = Array{Bool}(bitcache_size)
ind = first(linearindices($active))
cind = 1
for i = 1:div(l + bitcache_size - 1, bitcache_size)
ind = bitcache($scalarf, A, B, $refA, $refB, l, ind, C)
dumpbitcache(Fc, cind, C)
cind += bitcache_chunks
end
return P
end
end
end
end
## specialized element-wise operators for BitArray
(.^)(A::BitArray, B::AbstractArray{Bool}) = (B .<= A)
(.^)(A::AbstractArray{Bool}, B::AbstractArray{Bool}) = (B .<= A)
function bitcache_pow{T}(Ac::Vector{UInt64}, B::Array{T}, l::Int, ind::Int, C::Vector{Bool})
left = l - ind + 1
@inbounds begin
for j = 1:min(bitcache_size, left)
C[j] = unsafe_bitgetindex(Ac, ind) ^ B[ind]
ind += 1
end
C[left+1:bitcache_size] = false
end
return ind
end
function (.^){T<:Integer}(A::BitArray, B::Array{T})
local shape
try
shape = promote_shape(indices(A), indices(B))
catch
return bitbroadcast(^, A, B)
end
F = BitArray(to_shape(shape))
l = length(F)
l == 0 && return F
Ac = A.chunks
Fc = F.chunks
C = Array{Bool}(bitcache_size)
ind = 1
cind = 1
for i = 1:div(l + bitcache_size - 1, bitcache_size)
ind = bitcache_pow(Ac, B, l, ind, C)
dumpbitcache(Fc, cind, C)
cind += bitcache_chunks
end
return F
end
for (sigA, sigB) in ((BitArray, BitArray),
(AbstractArray{Bool}, BitArray),
(BitArray, AbstractArray{Bool}))
@eval function (.*)(A::$sigA, B::$sigB)
try
return BitArray(A) & BitArray(B)
catch
return bitbroadcast(&, A, B)
end
end
end
############################################################
# x[...] .= f.(y...) ---> broadcast!(f, dotview(x, ...), y...).
# The dotview function defaults to getindex, but we override it in
# a few cases to get the expected in-place behavior without affecting
# explicit calls to view. (All of this can go away if slices
# are changed to generate views by default.)
dotview(args...) = getindex(args...)
dotview(A::AbstractArray, args...) = view(A, args...)
dotview{T<:AbstractArray}(A::AbstractArray{T}, args...) = getindex(A, args...)
# avoid splatting penalty in common cases:
for nargs = 0:5
args = Symbol[Symbol("x",i) for i = 1:nargs]
eval(Expr(:(=), Expr(:call, :dotview, args...),
Expr(:call, :getindex, args...)))
eval(Expr(:(=), Expr(:call, :dotview, :(A::AbstractArray), args...),
Expr(:call, :view, :A, args...)))
end
end # module
# This file is automatically generated in base/Makefile
const MACHINE = "x86_64-apple-darwin16.0.0"
const libm_name = "libopenlibm"
const libblas_name = "libopenblas64_"
const liblapack_name = "libopenblas64_"
const USE_BLAS64 = true
const USE_GPL_LIBS = true
const libfftw_name = "libfftw3_threads"
const libfftwf_name = "libfftw3f_threads"
const libllvm_version = "3.7.1"
const VERSION_STRING = "0.6.0-dev"
const TAGGED_RELEASE_BANNER = ""
const SYSCONFDIR = "../etc"
const DATAROOTDIR = "../share"
const DOCDIR = "../share/doc/julia"
const LIBDIR = "../lib"
const INCLUDEDIR = "../include"
# This file is a part of Julia. License is MIT: http://julialang.org/license
# definitions related to C interface
import Core.Intrinsics: cglobal, box
cfunction(f::Function, r, a) = ccall(:jl_function_ptr, Ptr{Void}, (Any, Any, Any), f, r, a)
if ccall(:jl_is_char_signed, Ref{Bool}, ())
typealias Cchar Int8
else
typealias Cchar UInt8
end
"""
Cchar
Equivalent to the native `char` c-type.
"""
Cchar
if is_windows()
typealias Clong Int32
typealias Culong UInt32
typealias Cwchar_t UInt16
else
typealias Clong Int
typealias Culong UInt
typealias Cwchar_t Int32
end
"""
Clong
Equivalent to the native `signed long` c-type.
"""
Clong
"""
Culong
Equivalent to the native `unsigned long` c-type.
"""
Culong
"""
Cwchar_t
Equivalent to the native `wchar_t` c-type (`Int32`).
"""
Cwchar_t
if !is_windows()
const sizeof_mode_t = ccall(:jl_sizeof_mode_t, Cint, ())
if sizeof_mode_t == 2
typealias Cmode_t Int16
elseif sizeof_mode_t == 4
typealias Cmode_t Int32
elseif sizeof_mode_t == 8
typealias Cmode_t Int64
end
end
# construction from typed pointers
convert{T<:Union{Int8,UInt8}}(::Type{Cstring}, p::Ptr{T}) = box(Cstring, p)
convert(::Type{Cwstring}, p::Ptr{Cwchar_t}) = box(Cwstring, p)
convert{T<:Union{Int8,UInt8}}(::Type{Ptr{T}}, p::Cstring) = box(Ptr{T}, p)
convert(::Type{Ptr{Cwchar_t}}, p::Cwstring) = box(Ptr{Cwchar_t}, p)
# construction from untyped pointers
convert{T<:Union{Cstring,Cwstring}}(::Type{T}, p::Ptr{Void}) = box(T, p)
pointer(p::Cstring) = convert(Ptr{UInt8}, p)
pointer(p::Cwstring) = convert(Ptr{Cwchar_t}, p)
# comparisons against pointers (mainly to support `cstr==C_NULL`)
==(x::Union{Cstring,Cwstring}, y::Ptr) = pointer(x) == y
==(x::Ptr, y::Union{Cstring,Cwstring}) = x == pointer(y)
# here, not in pointer.jl, to avoid bootstrapping problems in coreimg.jl
unsafe_wrap(::Type{String}, p::Cstring, own::Bool=false) = unsafe_wrap(String, convert(Ptr{UInt8}, p), own)
unsafe_wrap(::Type{String}, p::Cstring, len::Integer, own::Bool=false) =
unsafe_wrap(String, convert(Ptr{UInt8}, p), len, own)
unsafe_string(s::Cstring) = unsafe_string(convert(Ptr{UInt8}, s))
# convert strings to String etc. to pass as pointers
cconvert(::Type{Cstring}, s::String) =
ccall(:jl_array_cconvert_cstring, Ref{Vector{UInt8}},
(Vector{UInt8},), s.data)
cconvert(::Type{Cstring}, s::AbstractString) =
cconvert(Cstring, String(s)::String)
function cconvert(::Type{Cwstring}, s::AbstractString)
v = transcode(Cwchar_t, String(s).data)
!isempty(v) && v[end] == 0 || push!(v, 0)
return v
end
eltype(::Type{Cstring}) = UInt8
eltype(::Type{Cwstring}) = Cwchar_t
containsnul(p::Ptr, len) =
C_NULL != ccall(:memchr, Ptr{Cchar}, (Ptr{Cchar}, Cint, Csize_t), p, 0, len)
containsnul(s::String) = containsnul(unsafe_convert(Ptr{Cchar}, s), sizeof(s))
containsnul(s::AbstractString) = '\0' in s
function unsafe_convert(::Type{Cstring}, s::Vector{UInt8})
p = unsafe_convert(Ptr{Cchar}, s)
containsnul(p, sizeof(s)) &&
throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))"))
return Cstring(p)
end
function unsafe_convert(::Type{Cwstring}, v::Vector{Cwchar_t})
for i = 1:length(v)-1
v[i] == 0 &&
throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(v))"))
end
v[end] == 0 ||
throw(ArgumentError("C string data must be NUL terminated: $(repr(v))"))
p = unsafe_convert(Ptr{Cwchar_t}, v)
return Cwstring(p)
end
# symbols are guaranteed not to contain embedded NUL
convert(::Type{Cstring}, s::Symbol) = Cstring(unsafe_convert(Ptr{Cchar}, s))
if is_windows()
"""
Base.cwstring(s)
Converts a string `s` to a NUL-terminated `Vector{Cwchar_t}`, suitable for passing to C
functions expecting a `Ptr{Cwchar_t}`. The main advantage of using this over the implicit
conversion provided by `Cwstring` is if the function is called multiple times with the
same argument.
This is only available on Windows.
"""
function cwstring(s::AbstractString)
bytes = String(s).data
0 in bytes && throw(ArgumentError("embedded NULs are not allowed in C strings: $(repr(s))"))
return push!(transcode(UInt16, bytes), 0)
end
end
# transcoding between data in UTF-8 and UTF-16 for Windows APIs,
# and also UTF-32 for APIs using Cwchar_t on other platforms.
"""
transcode(T, src)
Convert string data between Unicode encodings. `src` is either a
`String` or a `Vector{UIntXX}` of UTF-XX code units, where
`XX` is 8, 16, or 32. `T` indicates the encoding of the return value:
`String` to return a (UTF-8 encoded) `String` or `UIntXX`
to return a `Vector{UIntXX}` of UTF-`XX` data. (The alias `Cwchar_t`
can also be used as the integer type, for converting `wchar_t*` strings
used by external C libraries.)
The `transcode` function succeeds as long as the input data can be
reasonably represented in the target encoding; it always succeeds for
conversions between UTF-XX encodings, even for invalid Unicode data.
Only conversion to/from UTF-8 is currently supported.
"""
function transcode end
transcode{T<:Union{UInt8,UInt16,UInt32,Int32}}(::Type{T}, src::Vector{T}) = src
transcode{T<:Union{Int32,UInt32}}(::Type{T}, src::String) = T[T(c) for c in src]
transcode{T<:Union{Int32,UInt32}}(::Type{T}, src::Vector{UInt8}) = transcode(T, String(src))
function transcode{S<:Union{Int32,UInt32}}(::Type{UInt8}, src::Vector{S})
buf = IOBuffer()
for c in src; print(buf, Char(c)); end
takebuf_array(buf)
end
transcode(::Type{String}, src::String) = src
transcode(T, src::String) = transcode(T, src.data)
transcode(::Type{String}, src) = String(transcode(UInt8, src))
function transcode(::Type{UInt16}, src::Vector{UInt8})
dst = UInt16[]
i, n = 1, length(src)
n > 0 || return dst
sizehint!(dst, 2n)
a = src[1]
while true
if i < n && -64 <= a % Int8 <= -12 # multi-byte character
b = src[i += 1]
if -64 <= (b % Int8) || a == 0xf4 && 0x8f < b
# invalid UTF-8 (non-continuation or too-high code point)
push!(dst, a)
a = b; continue
elseif a < 0xe0 # 2-byte UTF-8
push!(dst, 0x3080 $ (UInt16(a) << 6) $ b)
elseif i < n # 3/4-byte character
c = src[i += 1]
if -64 <= (c % Int8) # invalid UTF-8 (non-continuation)
push!(dst, a, b)
a = c; continue
elseif a < 0xf0 # 3-byte UTF-8
push!(dst, 0x2080 $ (UInt16(a) << 12) $ (UInt16(b) << 6) $ c)
elseif i < n
d = src[i += 1]
if -64 <= (d % Int8) # invalid UTF-8 (non-continuation)
push!(dst, a, b, c)
a = d; continue
elseif a == 0xf0 && b < 0x90 # overlong encoding
push!(dst, 0x2080 $ (UInt16(b) << 12) $ (UInt16(c) << 6) $ d)
else # 4-byte UTF-8
push!(dst, 0xe5b8 + (UInt16(a) << 8) + (UInt16(b) << 2) + (c >> 4),
0xdc80 $ (UInt16(c & 0xf) << 6) $ d)
end
else # too short
push!(dst, a, b, c)
break
end
else # too short
push!(dst, a, b)
break
end
else # ASCII or invalid UTF-8 (continuation byte or too-high code point)
push!(dst, a)
end
i < n || break
a = src[i += 1]
end
return dst
end
function transcode(::Type{UInt8}, src::Vector{UInt16})
n = length(src)
n == 0 && return UInt8[]
# Precompute m = sizeof(dst). This involves annoying duplication
# of the loop over the src array. However, this is not just an
# optimization: it is problematic for security reasons to grow
# dst dynamically, because Base.winprompt uses this function to
# convert passwords to UTF-8 and we don't want to make unintentional
# copies of the password data.
a = src[1]
i, m = 1, 0
while true
if a < 0x80
m += 1
elseif a < 0x800 # 2-byte UTF-8
m += 2
elseif a & 0xfc00 == 0xd800 && i < length(src)
b = src[i += 1]
if (b & 0xfc00) == 0xdc00 # 2-unit UTF-16 sequence => 4-byte UTF-8
m += 4
else
m += 3
a = b; continue
end
else
# 1-unit high UTF-16 or unpaired high surrogate
# either way, encode as 3-byte UTF-8 code point
m += 3
end
i < n || break
a = src[i += 1]
end
dst = Array{UInt8}(m)
a = src[1]
i, j = 1, 0
while true
if a < 0x80 # ASCII
dst[j += 1] = a % UInt8
elseif a < 0x800 # 2-byte UTF-8
dst[j += 1] = 0xc0 | ((a >> 6) % UInt8)
dst[j += 1] = 0x80 | ((a % UInt8) & 0x3f)
elseif a & 0xfc00 == 0xd800 && i < n
b = src[i += 1]
if (b & 0xfc00) == 0xdc00
# 2-unit UTF-16 sequence => 4-byte UTF-8
a += 0x2840
dst[j += 1] = 0xf0 | ((a >> 8) % UInt8)
dst[j += 1] = 0x80 | ((a % UInt8) >> 2)
dst[j += 1] = 0xf0 $ ((((a % UInt8) << 4) & 0x3f) $ (b >> 6) % UInt8)
dst[j += 1] = 0x80 | ((b % UInt8) & 0x3f)
else
dst[j += 1] = 0xe0 | ((a >> 12) % UInt8)
dst[j += 1] = 0x80 | (((a >> 6) % UInt8) & 0x3f)
dst[j += 1] = 0x80 | ((a % UInt8) & 0x3f)
a = b; continue
end
else
# 1-unit high UTF-16 or unpaired high surrogate
# either way, encode as 3-byte UTF-8 code point
dst[j += 1] = 0xe0 | ((a >> 12) % UInt8)
dst[j += 1] = 0x80 | (((a >> 6) % UInt8) & 0x3f)
dst[j += 1] = 0x80 | ((a % UInt8) & 0x3f)
end
i < n || break
a = src[i += 1]
end
return dst
end
# deferring (or un-deferring) ctrl-c handler for external C code that
# is not interrupt safe (see also issue #2622). The sigatomic_begin/end
# functions should always be called in matched pairs, ideally via:
# disable_sigint() do .. end
# reennable_sigint is provided so that immediate ctrl-c handling is
# re-enabled within a sigatomic region, e.g. inside a Julia callback function
# within a long-running C routine.
sigatomic_begin() = ccall(:jl_sigatomic_begin, Void, ())
sigatomic_end() = ccall(:jl_sigatomic_end, Void, ())
"""
disable_sigint(f::Function)
Disable Ctrl-C handler during execution of a function on the current task,
for calling external code that may call julia code that is not interrupt safe.
Intended to be called using `do` block syntax as follows:
disable_sigint() do
# interrupt-unsafe code
...
end
This is not needed on worker threads (`Threads.threadid() != 1`) since the
`InterruptException` will only be delivered to the master thread.
External functions that do not call julia code or julia runtime
automatically disable sigint during their execution.
"""
function disable_sigint(f::Function)
sigatomic_begin()
res = f()
# Exception unwind sigatomic automatically
sigatomic_end()
res
end
"""
reenable_sigint(f::Function)
Re-enable Ctrl-C handler during execution of a function.
Temporarily reverses the effect of `disable_sigint`.
"""
function reenable_sigint(f::Function)
sigatomic_end()
res = f()
# Exception unwind sigatomic automatically
sigatomic_begin()
res
end
function ccallable(f::Function, rt::Type, argt::Type, name::Union{AbstractString,Symbol}=string(f))
ccall(:jl_extern_c, Void, (Any, Any, Any, Cstring), f, rt, argt, name)
end
macro ccallable(rt, def)
if isa(def,Expr) && (def.head === :(=) || def.head === :function)
sig = def.args[1]
if sig.head === :call
name = sig.args[1]
at = map(sig.args[2:end]) do a
if isa(a,Expr) && a.head === :(::)
a.args[2]
else
:Any
end
end
return quote
$(esc(def))
ccallable($(esc(name)), $(esc(rt)), $(Expr(:curly, :Tuple, map(esc, at)...)), $(string(name)))
end
end
end
error("expected method definition in @ccallable")
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Cartesian
export @nloops, @nref, @ncall, @nexprs, @nextract, @nall, @nany, @ntuple, @nif
### Cartesian-specific macros
"""
@nloops N itersym rangeexpr bodyexpr
@nloops N itersym rangeexpr preexpr bodyexpr
@nloops N itersym rangeexpr preexpr postexpr bodyexpr
Generate `N` nested loops, using `itersym` as the prefix for the iteration variables.
`rangeexpr` may be an anonymous-function expression, or a simple symbol `var` in which case
the range is `1:size(var,d)` for dimension `d`.
Optionally, you can provide "pre" and "post" expressions. These get executed first and last,
respectively, in the body of each loop. For example:
@nloops 2 i A d->j_d=min(i_d,5) begin
s += @nref 2 A j
end
would generate:
for i_2 = 1:size(A, 2)
j_2 = min(i_2, 5)
for i_1 = 1:size(A, 1)
j_1 = min(i_1, 5)
s += A[j_1,j_2]
end
end
If you want just a post-expression, supply `nothing` for the pre-expression. Using
parentheses and semicolons, you can supply multi-statement expressions.
"""
macro nloops(N, itersym, rangeexpr, args...)
_nloops(N, itersym, rangeexpr, args...)
end
function _nloops(N::Int, itersym::Symbol, arraysym::Symbol, args::Expr...)
@gensym d
_nloops(N, itersym, :($d->indices($arraysym, $d)), args...)
end
function _nloops(N::Int, itersym::Symbol, rangeexpr::Expr, args::Expr...)
if rangeexpr.head != :->
throw(ArgumentError("second argument must be an anonymous function expression to compute the range"))
end
if !(1 <= length(args) <= 3)
throw(ArgumentError("number of arguments must be 1 ≤ length(args) ≤ 3, got $nargs"))
end
body = args[end]
ex = Expr(:escape, body)
for dim = 1:N
itervar = inlineanonymous(itersym, dim)
rng = inlineanonymous(rangeexpr, dim)
preexpr = length(args) > 1 ? inlineanonymous(args[1], dim) : (:(nothing))
postexpr = length(args) > 2 ? inlineanonymous(args[2], dim) : (:(nothing))
ex = quote
for $(esc(itervar)) = $(esc(rng))
$(esc(preexpr))
$ex
$(esc(postexpr))
end
end
end
ex
end
"""
@nref N A indexexpr
Generate expressions like `A[i_1,i_2,...]`. `indexexpr` can either be an iteration-symbol
prefix, or an anonymous-function expression.
"""
macro nref(N, A, sym)
_nref(N, A, sym)
end
function _nref(N::Int, A::Symbol, ex)
vars = [ inlineanonymous(ex,i) for i = 1:N ]
Expr(:escape, Expr(:ref, A, vars...))
end
"""
@ncall N f sym...
Generate a function call expression. `sym` represents any number of function arguments, the
last of which may be an anonymous-function expression and is expanded into `N` arguments.
For example `@ncall 3 func a` generates
func(a_1, a_2, a_3)
while `@ncall 2 func a b i->c[i]` yields
func(a, b, c[1], c[2])
"""
macro ncall(N, f, sym...)
_ncall(N, f, sym...)
end
function _ncall(N::Int, f, args...)
pre = args[1:end-1]
ex = args[end]
vars = [ inlineanonymous(ex,i) for i = 1:N ]
Expr(:escape, Expr(:call, f, pre..., vars...))
end
"""
@nexprs N expr
Generate `N` expressions. `expr` should be an anonymous-function expression.
"""
macro nexprs(N, ex)
_nexprs(N, ex)
end
function _nexprs(N::Int, ex::Expr)
exs = [ inlineanonymous(ex,i) for i = 1:N ]
Expr(:escape, Expr(:block, exs...))
end
"""
@nextract N esym isym
Generate `N` variables `esym_1`, `esym_2`, ..., `esym_N` to extract values from `isym`.
`isym` can be either a `Symbol` or anonymous-function expression.
`@nextract 2 x y` would generate
x_1 = y[1]
x_2 = y[2]
while `@nextract 3 x d->y[2d-1]` yields
x_1 = y[1]
x_2 = y[3]
x_3 = y[5]
"""
macro nextract(N, esym, isym)
_nextract(N, esym, isym)
end
function _nextract(N::Int, esym::Symbol, isym::Symbol)
aexprs = [Expr(:escape, Expr(:(=), inlineanonymous(esym, i), :(($isym)[$i]))) for i = 1:N]
Expr(:block, aexprs...)
end
function _nextract(N::Int, esym::Symbol, ex::Expr)
aexprs = [Expr(:escape, Expr(:(=), inlineanonymous(esym, i), inlineanonymous(ex,i))) for i = 1:N]
Expr(:block, aexprs...)
end
"""
@nall N expr
Check whether all of the expressions generated by the anonymous-function expression `expr`
evaluate to `true`.
`@nall 3 d->(i_d > 1)` would generate the expression `(i_1 > 1 && i_2 > 1 && i_3 > 1)`. This
can be convenient for bounds-checking.
"""
macro nall(N, criterion)
_nall(N, criterion)
end
function _nall(N::Int, criterion::Expr)
if criterion.head != :->
throw(ArgumentError("second argument must be an anonymous function expression yielding the criterion"))
end
conds = [Expr(:escape, inlineanonymous(criterion, i)) for i = 1:N]
Expr(:&&, conds...)
end
"""
@nany N expr
Check whether any of the expressions generated by the anonymous-function expression `expr`
evaluate to `true`.
`@nany 3 d->(i_d > 1)` would generate the expression `(i_1 > 1 || i_2 > 1 || i_3 > 1)`.
"""
macro nany(N, criterion)
_nany(N, criterion)
end
function _nany(N::Int, criterion::Expr)
if criterion.head != :->
error("Second argument must be an anonymous function expression yielding the criterion")
end
conds = [Expr(:escape, inlineanonymous(criterion, i)) for i = 1:N]
Expr(:||, conds...)
end
"""
@ntuple N expr
Generates an `N`-tuple. `@ntuple 2 i` would generate `(i_1, i_2)`, and `@ntuple 2 k->k+1`
would generate `(2,3)`.
"""
macro ntuple(N, ex)
_ntuple(N, ex)
end
function _ntuple(N::Int, ex)
vars = [ inlineanonymous(ex,i) for i = 1:N ]
Expr(:escape, Expr(:tuple, vars...))
end
"""
@nif N conditionexpr expr
@nif N conditionexpr expr elseexpr
Generates a sequence of `if ... elseif ... else ... end` statements. For example:
@nif 3 d->(i_d >= size(A,d)) d->(error("Dimension ", d, " too big")) d->println("All OK")
would generate:
if i_1 > size(A, 1)
error("Dimension ", 1, " too big")
elseif i_2 > size(A, 2)
error("Dimension ", 2, " too big")
else
println("All OK")
end
"""
macro nif(N, condition, operation...)
# Handle the final "else"
ex = esc(inlineanonymous(length(operation) > 1 ? operation[2] : operation[1], N))
# Make the nested if statements
for i = N-1:-1:1
ex = Expr(:if, esc(inlineanonymous(condition,i)), esc(inlineanonymous(operation[1],i)), ex)
end
ex
end
## Utilities
# Simplify expressions like :(d->3:size(A,d)-3) given an explicit value for d
function inlineanonymous(ex::Expr, val)
if ex.head != :->
throw(ArgumentError("not an anonymous function"))
end
if !isa(ex.args[1], Symbol)
throw(ArgumentError("not a single-argument anonymous function"))
end
sym = ex.args[1]
ex = ex.args[2]
exout = lreplace(ex, sym, val)
exout = poplinenum(exout)
exprresolve(exout)
end
# Given :i and 3, this generates :i_3
inlineanonymous(base::Symbol, ext) = Symbol(base,'_',ext)
# Replace a symbol by a value or a "coded" symbol
# E.g., for d = 3,
# lreplace(:d, :d, 3) -> 3
# lreplace(:i_d, :d, 3) -> :i_3
# lreplace(:i_{d-1}, :d, 3) -> :i_2
# This follows LaTeX notation.
immutable LReplace{S<:AbstractString}
pat_sym::Symbol
pat_str::S
val::Int
end
LReplace(sym::Symbol, val::Integer) = LReplace(sym, string(sym), val)
lreplace(ex, sym::Symbol, val) = lreplace!(copy(ex), LReplace(sym, val))
function lreplace!(sym::Symbol, r::LReplace)
sym == r.pat_sym && return r.val
Symbol(lreplace!(string(sym), r))
end
function lreplace!(str::AbstractString, r::LReplace)
i = start(str)
pat = r.pat_str
j = start(pat)
matching = false
while !done(str, i)
cstr, i = next(str, i)
if !matching
if cstr != '_' || done(str, i)
continue
end
istart = i
cstr, i = next(str, i)
end
if !done(pat, j)
cr, j = next(pat, j)
if cstr == cr
matching = true
else
matching = false
j = start(pat)
i = istart
continue
end
end
if matching && done(pat, j)
if done(str, i) || next(str, i)[1] == '_'
# We have a match
return string(str[1:prevind(str, istart)], r.val, lreplace!(str[i:end], r))
end
matching = false
j = start(pat)
i = istart
end
end
str
end
function lreplace!(ex::Expr, r::LReplace)
# Curly-brace notation, which acts like parentheses
if ex.head == :curly && length(ex.args) == 2 && isa(ex.args[1], Symbol) && endswith(string(ex.args[1]), "_")
excurly = exprresolve(lreplace!(ex.args[2], r))
if isa(excurly, Number)
return Symbol(ex.args[1],excurly)
else
ex.args[2] = excurly
return ex
end
end
for i in 1:length(ex.args)
ex.args[i] = lreplace!(ex.args[i], r)
end
ex
end
lreplace!(arg, r::LReplace) = arg
poplinenum(arg) = arg
function poplinenum(ex::Expr)
if ex.head == :block
if length(ex.args) == 1
return ex.args[1]
elseif length(ex.args) == 2 && isa(ex.args[1], LineNumberNode)
return ex.args[2]
elseif (length(ex.args) == 2 && isa(ex.args[1], Expr) && ex.args[1].head == :line)
return ex.args[2]
end
end
ex
end
## Resolve expressions at parsing time ##
const exprresolve_arith_dict = Dict{Symbol,Function}(:+ => +,
:- => -, :* => *, :/ => /, :^ => ^, :div => div)
const exprresolve_cond_dict = Dict{Symbol,Function}(:(==) => ==,
:(<) => <, :(>) => >, :(<=) => <=, :(>=) => >=)
function exprresolve_arith(ex::Expr)
if ex.head == :call && haskey(exprresolve_arith_dict, ex.args[1]) && all([isa(ex.args[i], Number) for i = 2:length(ex.args)])
return true, exprresolve_arith_dict[ex.args[1]](ex.args[2:end]...)
end
false, 0
end
exprresolve_arith(arg) = false, 0
exprresolve_conditional(b::Bool) = true, b
function exprresolve_conditional(ex::Expr)
if ex.head == :call && ex.args[1] ∈ keys(exprresolve_cond_dict) && isa(ex.args[2], Number) && isa(ex.args[3], Number)
return true, exprresolve_cond_dict[ex.args[1]](ex.args[2], ex.args[3])
end
false, false
end
exprresolve_conditional(arg) = false, false
exprresolve(arg) = arg
function exprresolve(ex::Expr)
for i = 1:length(ex.args)
ex.args[i] = exprresolve(ex.args[i])
end
# Handle simple arithmetic
can_eval, result = exprresolve_arith(ex)
if can_eval
return result
elseif ex.head == :call && (ex.args[1] == :+ || ex.args[1] == :-) && length(ex.args) == 3 && ex.args[3] == 0
# simplify x+0 and x-0
return ex.args[2]
end
# Resolve array references
if ex.head == :ref && isa(ex.args[1], Array)
for i = 2:length(ex.args)
if !isa(ex.args[i], Real)
return ex
end
end
return ex.args[1][ex.args[2:end]...]
end
# Resolve conditionals
if ex.head == :if
can_eval, tf = exprresolve_conditional(ex.args[1])
if can_eval
ex = tf?ex.args[2]:ex.args[3]
end
end
ex
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
abstract AbstractChannel
type Channel{T} <: AbstractChannel
cond_take::Condition # waiting for data to become available
cond_put::Condition # waiting for a writeable slot
state::Symbol
data::Array{T,1}
sz_max::Int # maximum size of channel
# Used when sz_max == 0, i.e., an unbuffered channel.
takers::Array{Condition}
function Channel(sz::Float64)
if sz == Inf
Channel{T}(typemax(Int))
else
Channel{T}(convert(Int, sz))
end
end
function Channel(sz::Integer)
if sz < 0
throw(ArgumentError("Channel size must be either 0, a positive integer or Inf"))
end
new(Condition(), Condition(), :open, Array{T}(0), sz, Array{Condition}(0))
end
# deprecated empty constructor
function Channel()
depwarn(string("The empty constructor Channel() is deprecated. ",
"The channel size needs to be specified explictly. ",
"Defaulting to Channel{$T}(32)."), :Channel)
Channel(32)
end
end
Channel(sz) = Channel{Any}(sz)
# deprecated empty constructor
Channel() = Channel{Any}()
closed_exception() = InvalidStateException("Channel is closed.", :closed)
isbuffered(c::Channel) = c.sz_max==0 ? false : true
"""
close(c::Channel)
Closes a channel. An exception is thrown by:
* `put!` on a closed channel.
* `take!` and `fetch` on an empty, closed channel.
"""
function close(c::Channel)
c.state = :closed
notify_error(c::Channel, closed_exception())
nothing
end
isopen(c::Channel) = (c.state == :open)
type InvalidStateException <: Exception
msg::AbstractString
state::Symbol
end
"""
put!(c::Channel, v)
Appends an item `v` to the channel `c`. Blocks if the channel is full.
For unbuffered channels, blocks until a `take!` is performed by a different
task.
"""
function put!(c::Channel, v)
!isopen(c) && throw(closed_exception())
isbuffered(c) ? put_buffered(c,v) : put_unbuffered(c,v)
end
function put_buffered(c::Channel, v)
while length(c.data) == c.sz_max
wait(c.cond_put)
end
push!(c.data, v)
notify(c.cond_take, nothing, true, false) # notify all, since some of the waiters may be on a "fetch" call.
v
end
function put_unbuffered(c::Channel, v)
while length(c.takers) == 0
notify(c.cond_take, nothing, true, false) # Required to handle wait() on 0-sized channels
wait(c.cond_put)
end
cond_taker = shift!(c.takers)
notify(cond_taker, v, false, false)
v
end
push!(c::Channel, v) = put!(c, v)
"""
fetch(c::Channel)
Waits for and gets the first available item from the channel. Does not
remove the item. `fetch` is unsupported on an unbuffered (0-size) channel.
"""
fetch(c::Channel) = isbuffered(c) ? fetch_buffered(c) : fetch_unbuffered(c)
function fetch_buffered(c::Channel)
wait(c)
c.data[1]
end
fetch_unbuffered(c::Channel) = throw(ErrorException("`fetch` is not supported on an unbuffered Channel."))
"""
take!(c::Channel)
Removes and returns a value from a `Channel`. Blocks until data is available.
For unbuffered channels, blocks until a `put!` is performed by a different
task.
"""
take!(c::Channel) = isbuffered(c) ? take_buffered(c) : take_unbuffered(c)
function take_buffered(c::Channel)
wait(c)
v = shift!(c.data)
notify(c.cond_put, nothing, false, false) # notify only one, since only one slot has become available for a put!.
v
end
shift!(c::Channel) = take!(c)
# 0-size channel
function take_unbuffered(c::Channel)
!isopen(c) && throw(closed_exception())
cond_taker = Condition()
push!(c.takers, cond_taker)
notify(c.cond_put, nothing, false, false)
try
return wait(cond_taker)
catch e
if isa(e, InterruptException)
# remove self from the list of takers
filter!(x -> x != cond_taker, c.takers)
else
rethrow(e)
end
end
end
"""
isready(c::Channel)
Determine whether a `Channel` has a value stored to it. Returns
immediately, does not block.
For unbuffered channels returns `true` if there are tasks waiting
on a `put!`.
"""
isready(c::Channel) = n_avail(c) > 0
n_avail(c::Channel) = isbuffered(c) ? length(c.data) : n_waiters(c.cond_put)
function wait(c::Channel)
while !isready(c)
!isopen(c) && throw(closed_exception())
wait(c.cond_take)
end
nothing
end
function notify_error(c::Channel, err)
notify_error(c.cond_take, err)
notify_error(c.cond_put, err)
foreach(x->notify_error(x, err), c.takers)
end
eltype{T}(::Type{Channel{T}}) = T
show(io::IO, c::Channel) = print(io, "$(typeof(c))(sz_max:$(c.sz_max),sz_curr:$(n_avail(c)))")
type ChannelState{T}
hasval::Bool
val::T
ChannelState(x) = new(x)
end
start{T}(c::Channel{T}) = ChannelState{T}(false)
function done(c::Channel, state::ChannelState)
try
# we are waiting either for more data or channel to be closed
state.hasval && return false
state.val = take!(c)
state.hasval = true
return false
catch e
if isa(e, InvalidStateException) && e.state==:closed
return true
else
rethrow(e)
end
end
end
next{T}(c::Channel{T}, state) = (v=state.val; state.hasval=false; (v, state))
iteratorsize{C<:Channel}(::Type{C}) = SizeUnknown()
# This file is a part of Julia. License is MIT: http://julialang.org/license
convert(::Type{Char}, x::UInt32) = reinterpret(Char, x)
convert(::Type{Char}, x::Number) = Char(UInt32(x))
convert(::Type{UInt32}, x::Char) = reinterpret(UInt32, x)
convert{T<:Number}(::Type{T}, x::Char) = convert(T, UInt32(x))
rem{T<:Number}(x::Char, ::Type{T}) = rem(UInt32(x), T)
typemax(::Type{Char}) = reinterpret(Char, typemax(UInt32))
typemin(::Type{Char}) = reinterpret(Char, typemin(UInt32))
size(c::Char) = ()
size(c::Char,d) = convert(Int, d) < 1 ? throw(BoundsError()) : 1
ndims(c::Char) = 0
ndims(::Type{Char}) = 0
length(c::Char) = 1
endof(c::Char) = 1
getindex(c::Char) = c
getindex(c::Char, i::Integer) = i == 1 ? c : throw(BoundsError())
getindex(c::Char, I::Integer...) = all(Predicate(x -> x == 1), I) ? c : throw(BoundsError())
first(c::Char) = c
last(c::Char) = c
eltype(::Type{Char}) = Char
start(c::Char) = false
next(c::Char, state) = (c, true)
done(c::Char, state) = state
isempty(c::Char) = false
in(x::Char, y::Char) = x == y
==(x::Char, y::Char) = UInt32(x) == UInt32(y)
isless(x::Char, y::Char) = UInt32(x) < UInt32(y)
const hashchar_seed = 0xd4d64234
hash(x::Char, h::UInt) = hash_uint64(((UInt64(x)+hashchar_seed)<<32) $ UInt64(h))
-(x::Char, y::Char) = Int(x) - Int(y)
-(x::Char, y::Integer) = Char(Int32(x) - Int32(y))
+(x::Char, y::Integer) = Char(Int32(x) + Int32(y))
+(x::Integer, y::Char) = y + x
bswap(x::Char) = Char(bswap(UInt32(x)))
print(io::IO, c::Char) = (write(io, c); nothing)
const hex_chars = UInt8['0':'9';'a':'z']
function show(io::IO, c::Char)
if c <= '\\'
b = c == '\0' ? 0x30 :
c == '\a' ? 0x61 :
c == '\b' ? 0x62 :
c == '\t' ? 0x74 :
c == '\n' ? 0x6e :
c == '\v' ? 0x76 :
c == '\f' ? 0x66 :
c == '\r' ? 0x72 :
c == '\e' ? 0x65 :
c == '\'' ? 0x27 :
c == '\\' ? 0x5c : 0xff
if b != 0xff
write(io, 0x27, 0x5c, b, 0x27)
return
end
end
if isprint(c)
write(io, 0x27, c, 0x27)
else
u = UInt32(c)
write(io, 0x27, 0x5c, c <= '\x7f' ? 0x78 : c <= '\uffff' ? 0x75 : 0x55)
d = max(2, 8 - (leading_zeros(u) >> 2))
while 0 < d
write(io, hex_chars[((u >> ((d -= 1) << 2)) & 0xf) + 1])
end
write(io, 0x27)
end
return
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Support for checked integer arithmetic
module Checked
export checked_neg, checked_abs, checked_add, checked_sub, checked_mul,
checked_div, checked_rem, checked_fld, checked_mod, checked_cld,
add_with_overflow, sub_with_overflow, mul_with_overflow
import Core.Intrinsics: box, unbox,
checked_sadd_int, checked_ssub_int, checked_smul_int, checked_sdiv_int,
checked_srem_int,
checked_uadd_int, checked_usub_int, checked_umul_int, checked_udiv_int,
checked_urem_int
import Base: no_op_err, @_inline_meta
# define promotion behavior for checked operations
checked_add(x::Integer, y::Integer) = checked_add(promote(x,y)...)
checked_sub(x::Integer, y::Integer) = checked_sub(promote(x,y)...)
checked_mul(x::Integer, y::Integer) = checked_mul(promote(x,y)...)
checked_div(x::Integer, y::Integer) = checked_div(promote(x,y)...)
checked_rem(x::Integer, y::Integer) = checked_rem(promote(x,y)...)
checked_fld(x::Integer, y::Integer) = checked_fld(promote(x,y)...)
checked_mod(x::Integer, y::Integer) = checked_mod(promote(x,y)...)
checked_cld(x::Integer, y::Integer) = checked_cld(promote(x,y)...)
# fallback catchall rules to prevent infinite recursion if promotion succeeds,
# but no method exists to handle those types
checked_abs{T<:Integer}(x::T) = no_op_err("checked_abs", T)
typealias SignedInt Union{Int8,Int16,Int32,Int64,Int128}
typealias UnsignedInt Union{UInt8,UInt16,UInt32,UInt64,UInt128}
# LLVM has several code generation bugs for checked integer arithmetic (see e.g.
# #4905). We thus distinguish between operations that can be implemented via
# intrinsics, and operations for which we have to provide work-arounds.
# Note: As far as this code has been tested, most checked_* functions are
# working fine in LLVM. (Note that division is still handled via `base/int.jl`,
# which always checks for overflow, and which provides its own sets of
# work-arounds for LLVM codegen bugs.) However, the comments in `base/int.jl`
# and in issue #4905 are more pessimistic. For the time being, we thus retain
# the ability to handle codegen bugs in LLVM, until the code here has been
# tested on more systems and architectures. It also seems that things depend on
# which compiler that was used to build LLVM (i.e. either gcc or clang).
# These unions are used for most checked functions:
# BrokenSignedInt
# BrokenUnsignedInt
# These unions are used for checked_{mul,div,rem}:
# BrokenSignedIntMul
# BrokenUnsignedIntMul
# This code runs early during bootstrap, and we can't use Julia's version
# strings yet
const llvm_version = Int(ccall(:jl_get_LLVM_VERSION, UInt32, ()))
brokenSignedInt = Union{}
brokenUnsignedInt = Union{}
brokenSignedIntMul = Int128
brokenUnsignedIntMul = UInt128
if Core.sizeof(Ptr{Void}) == 4
brokenSignedIntMul = Union{brokenSignedIntMul, Int64}
brokenUnsignedIntMul = Union{brokenUnsignedIntMul, UInt64}
end
if llvm_version < 30500
brokenSignedIntMul = Union{brokenSignedIntMul, Int8}
brokenUnsignedIntMul = Union{brokenUnsignedIntMul, UInt8}
end
typealias BrokenSignedInt brokenSignedInt
typealias BrokenUnsignedInt brokenUnsignedInt
typealias BrokenSignedIntMul brokenSignedIntMul
typealias BrokenUnsignedIntMul brokenUnsignedIntMul
# Use these definitions to test the non-LLVM implementations
# typealias BrokenSignedInt SignedInt
# typealias BrokenUnsignedInt UnsignedInt
# typealias BrokenSignedIntMul SignedInt
# typealias BrokenUnsignedIntMul UnsignedInt
"""
Base.checked_neg(x)
Calculates `-x`, checking for overflow errors where applicable. For
example, standard two's complement signed integers (e.g. `Int`) cannot
represent `-typemin(Int)`, thus leading to an overflow.
The overflow protection may impose a perceptible performance penalty.
"""
function checked_neg{T<:Integer}(x::T)
checked_sub(T(0), x)
end
if BrokenSignedInt != Union{}
function checked_neg{T<:BrokenSignedInt}(x::T)
r = -x
(x<0) & (r<0) && throw(OverflowError())
r
end
end
if BrokenUnsignedInt != Union{}
function checked_neg{T<:BrokenUnsignedInt}(x::T)
x != 0 && throw(OverflowError())
T(0)
end
end
"""
Base.checked_abs(x)
Calculates `abs(x)`, checking for overflow errors where applicable.
For example, standard two's complement signed integers (e.g. `Int`)
cannot represent `abs(typemin(Int))`, thus leading to an overflow.
The overflow protection may impose a perceptible performance penalty.
"""
function checked_abs end
function checked_abs(x::SignedInt)
r = ifelse(x<0, -x, x)
r<0 && throw(OverflowError())
r
end
checked_abs(x::UnsignedInt) = x
checked_abs(x::Bool) = x
"""
Base.add_with_overflow(x, y) -> (r, f)
Calculates `r = x+y`, with the flag `f` indicating whether overflow has occurred.
"""
function add_with_overflow end
add_with_overflow{T<:SignedInt}(x::T, y::T) = checked_sadd_int(x, y)
add_with_overflow{T<:UnsignedInt}(x::T, y::T) = checked_uadd_int(x, y)
add_with_overflow(x::Bool, y::Bool) = x+y, false
if BrokenSignedInt != Union{}
function add_with_overflow{T<:BrokenSignedInt}(x::T, y::T)
r = x + y
# x and y have the same sign, and the result has a different sign
f = (x<0) == (y<0) != (r<0)
r, f
end
end
if BrokenUnsignedInt != Union{}
function add_with_overflow{T<:BrokenUnsignedInt}(x::T, y::T)
# x + y > typemax(T)
# Note: ~y == -y-1
x + y, x > ~y
end
end
"""
Base.checked_add(x, y)
Calculates `x+y`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
function checked_add{T<:Integer}(x::T, y::T)
@_inline_meta
z, b = add_with_overflow(x, y)
b && throw(OverflowError())
z
end
# Handle multiple arguments
checked_add(x) = x
checked_add(x::Bool) = +x
checked_add{T}(x1::T, x2::T, x3::T) =
checked_add(checked_add(x1, x2), x3)
checked_add{T}(x1::T, x2::T, x3::T, x4::T) =
checked_add(checked_add(x1, x2), x3, x4)
checked_add{T}(x1::T, x2::T, x3::T, x4::T, x5::T) =
checked_add(checked_add(x1, x2), x3, x4, x5)
checked_add{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T) =
checked_add(checked_add(x1, x2), x3, x4, x5, x6)
checked_add{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T, x7::T) =
checked_add(checked_add(x1, x2), x3, x4, x5, x6, x7)
checked_add{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T, x7::T, x8::T) =
checked_add(checked_add(x1, x2), x3, x4, x5, x6, x7, x8)
"""
Base.sub_with_overflow(x, y) -> (r, f)
Calculates `r = x-y`, with the flag `f` indicating whether overflow has occurred.
"""
function sub_with_overflow end
sub_with_overflow{T<:SignedInt}(x::T, y::T) = checked_ssub_int(x, y)
sub_with_overflow{T<:UnsignedInt}(x::T, y::T) = checked_usub_int(x, y)
sub_with_overflow(x::Bool, y::Bool) = x-y, false
if BrokenSignedInt != Union{}
function sub_with_overflow{T<:BrokenSignedInt}(x::T, y::T)
r = x - y
# x and y have different signs, and the result has a different sign than x
f = (x<0) != (y<0) == (r<0)
r, f
end
end
if BrokenUnsignedInt != Union{}
function sub_with_overflow{T<:BrokenUnsignedInt}(x::T, y::T)
# x - y < 0
x - y, x < y
end
end
"""
Base.checked_sub(x, y)
Calculates `x-y`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
function checked_sub{T<:Integer}(x::T, y::T)
@_inline_meta
z, b = sub_with_overflow(x, y)
b && throw(OverflowError())
z
end
"""
Base.mul_with_overflow(x, y) -> (r, f)
Calculates `r = x*y`, with the flag `f` indicating whether overflow has occurred.
"""
function mul_with_overflow end
mul_with_overflow{T<:SignedInt}(x::T, y::T) = checked_smul_int(x, y)
mul_with_overflow{T<:UnsignedInt}(x::T, y::T) = checked_umul_int(x, y)
mul_with_overflow(x::Bool, y::Bool) = x*y, false
if BrokenSignedIntMul != Union{} && BrokenSignedIntMul != Int128
function mul_with_overflow{T<:BrokenSignedIntMul}(x::T, y::T)
r = widemul(x, y)
f = r % T != r
r % T, f
end
end
if BrokenUnsignedIntMul != Union{} && BrokenUnsignedIntMul != UInt128
function mul_with_overflow{T<:BrokenUnsignedIntMul}(x::T, y::T)
r = widemul(x, y)
f = r % T != r
r % T, f
end
end
if Int128 <: BrokenSignedIntMul
# Avoid BigInt
function mul_with_overflow{T<:Int128}(x::T, y::T)
f = if y > 0
# x * y > typemax(T)
# x * y < typemin(T)
x > fld(typemax(T), y) || x < cld(typemin(T), y)
elseif y < 0
# x * y > typemax(T)
# x * y < typemin(T)
# y == -1 can overflow fld
x < cld(typemax(T), y) || y != -1 && x > fld(typemin(T), y)
else
false
end
x*y, f
end
end
if UInt128 <: BrokenUnsignedIntMul
# Avoid BigInt
function mul_with_overflow{T<:UInt128}(x::T, y::T)
# x * y > typemax(T)
x * y, y > 0 && x > fld(typemax(T), y)
end
end
"""
Base.checked_mul(x, y)
Calculates `x*y`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
function checked_mul{T<:Integer}(x::T, y::T)
@_inline_meta
z, b = mul_with_overflow(x, y)
b && throw(OverflowError())
z
end
# Handle multiple arguments
checked_mul(x) = x
checked_mul{T}(x1::T, x2::T, x3::T) =
checked_mul(checked_mul(x1, x2), x3)
checked_mul{T}(x1::T, x2::T, x3::T, x4::T) =
checked_mul(checked_mul(x1, x2), x3, x4)
checked_mul{T}(x1::T, x2::T, x3::T, x4::T, x5::T) =
checked_mul(checked_mul(x1, x2), x3, x4, x5)
checked_mul{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T) =
checked_mul(checked_mul(x1, x2), x3, x4, x5, x6)
checked_mul{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T, x7::T) =
checked_mul(checked_mul(x1, x2), x3, x4, x5, x6, x7)
checked_mul{T}(x1::T, x2::T, x3::T, x4::T, x5::T, x6::T, x7::T, x8::T) =
checked_mul(checked_mul(x1, x2), x3, x4, x5, x6, x7, x8)
"""
Base.checked_div(x, y)
Calculates `div(x,y)`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
checked_div{T<:Integer}(x::T, y::T) = div(x, y) # Base.div already checks
"""
Base.checked_rem(x, y)
Calculates `x%y`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
checked_rem{T<:Integer}(x::T, y::T) = rem(x, y) # Base.rem already checks
"""
Base.checked_fld(x, y)
Calculates `fld(x,y)`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
checked_fld{T<:Integer}(x::T, y::T) = fld(x, y) # Base.fld already checks
"""
Base.checked_mod(x, y)
Calculates `mod(x,y)`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
checked_mod{T<:Integer}(x::T, y::T) = mod(x, y) # Base.mod already checks
"""
Base.checked_cld(x, y)
Calculates `cld(x,y)`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
"""
checked_cld{T<:Integer}(x::T, y::T) = cld(x, y) # Base.cld already checks
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
## client.jl - frontend handling command line options, environment setup,
## and REPL
const text_colors = AnyDict(
:black => "\033[1m\033[30m",
:red => "\033[1m\033[31m",
:green => "\033[1m\033[32m",
:yellow => "\033[1m\033[33m",
:blue => "\033[1m\033[34m",
:magenta => "\033[1m\033[35m",
:cyan => "\033[1m\033[36m",
:white => "\033[1m\033[37m",
:normal => "\033[0m",
:bold => "\033[1m",
)
for i in 0:255
text_colors[i] = "\033[1m\033[38;5;$(i)m"
end
# Create a docstring with an automatically generated list
# of colors.
const possible_formatting_symbols = [:normal, :bold]
available_text_colors = collect(Iterators.filter(x -> !isa(x, Integer), keys(text_colors)))
available_text_colors = cat(1,
sort(intersect(available_text_colors, possible_formatting_symbols), rev=true),
sort(setdiff( available_text_colors, possible_formatting_symbols)))
const available_text_colors_docstring =
string(join([string("`:", key,"`")
for key in available_text_colors], ",\n", ", or \n"))
"""Dictionary of color codes for the terminal.
Available colors are: $available_text_colors_docstring as well as the integers 0 to 255 inclusive.
"""
text_colors
have_color = false
default_color_warn = :red
default_color_info = :cyan
if is_windows()
default_color_input = :normal
default_color_answer = :normal
else
default_color_input = :bold
default_color_answer = :bold
end
color_normal = text_colors[:normal]
function repl_color(key, default)
env_str = get(ENV, key, "")
c = tryparse(Int, env_str)
c_conv = isnull(c) ? Symbol(env_str) : get(c)
haskey(text_colors, c_conv) ? c_conv : default
end
warn_color() = repl_color("JULIA_WARN_COLOR", default_color_warn)
info_color() = repl_color("JULIA_INFO_COLOR", default_color_info)
input_color() = text_colors[repl_color("JULIA_INPUT_COLOR", default_color_input)]
answer_color() = text_colors[repl_color("JULIA_ANSWER_COLOR", default_color_answer)]
function repl_cmd(cmd, out)
shell = shell_split(get(ENV,"JULIA_SHELL",get(ENV,"SHELL","/bin/sh")))
# Note that we can't support the fish shell due to its lack of subshells
# See this for details: https://github.com/JuliaLang/julia/issues/4918
if Base.basename(shell[1]) == "fish"
warn_once("cannot use the fish shell, defaulting to /bin/sh\
set the JULIA_SHELL environment variable to silence this warning")
shell = "/bin/sh"
end
if isempty(cmd.exec)
throw(ArgumentError("no cmd to execute"))
elseif cmd.exec[1] == "cd"
new_oldpwd = pwd()
if length(cmd.exec) > 2
throw(ArgumentError("cd method only takes one argument"))
elseif length(cmd.exec) == 2
dir = cmd.exec[2]
if dir == "-"
if !haskey(ENV, "OLDPWD")
error("cd: OLDPWD not set")
end
cd(ENV["OLDPWD"])
else
cd(@static is_windows() ? dir : readchomp(`$shell -c "echo $(shell_escape(dir))"`))
end
else
cd()
end
ENV["OLDPWD"] = new_oldpwd
println(out, pwd())
else
run(ignorestatus(@static is_windows() ? cmd : (isa(STDIN, TTY) ? `$shell -i -c "($(shell_escape(cmd))) && true"` : `$shell -c "($(shell_escape(cmd))) && true"`)))
end
nothing
end
display_error(er) = display_error(er, [])
function display_error(er, bt)
with_output_color(:red, STDERR) do io
print(io, "ERROR: ")
showerror(io, er, bt)
println(io)
end
end
function eval_user_input(ast::ANY, show_value)
errcount, lasterr, bt = 0, (), nothing
while true
try
if have_color
print(color_normal)
end
if errcount > 0
display_error(lasterr,bt)
errcount, lasterr = 0, ()
else
ast = expand(ast)
value = eval(Main, ast)
eval(Main, Expr(:(=), :ans, Expr(:call, ()->value)))
if value!==nothing && show_value
if have_color
print(answer_color())
end
try display(value)
catch err
println(STDERR, "Evaluation succeeded, but an error occurred while showing value of type ", typeof(value), ":")
rethrow(err)
end
println()
end
end
break
catch err
if errcount > 0
println(STDERR, "SYSTEM: show(lasterr) caused an error")
end
errcount, lasterr = errcount+1, err
if errcount > 2
println(STDERR, "WARNING: it is likely that something important is broken, and Julia will not be able to continue normally")
break
end
bt = catch_backtrace()
end
end
isa(STDIN,TTY) && println()
end
syntax_deprecation_warnings(warn::Bool) =
ccall(:jl_parse_depwarn, Cint, (Cint,), warn) == 1
function syntax_deprecation_warnings(f::Function, warn::Bool)
prev = syntax_deprecation_warnings(warn)
try
f()
finally
syntax_deprecation_warnings(prev)
end
end
function parse_input_line(s::String; filename::String="none")
# (expr, pos) = parse(s, 1)
# (ex, pos) = ccall(:jl_parse_string, Any,
# (Ptr{UInt8},Csize_t,Int32,Int32),
# s, sizeof(s), pos-1, 1)
# if ex!==()
# throw(ParseError("extra input after end of expression"))
# end
# expr
ccall(:jl_parse_input_line, Any, (Ptr{UInt8}, Csize_t, Ptr{UInt8}, Csize_t),
s, sizeof(s), filename, sizeof(filename))
end
parse_input_line(s::AbstractString) = parse_input_line(String(s))
function parse_input_line(io::IO)
s = ""
while !eof(io)
s = s*readline(io)
e = parse_input_line(s)
if !(isa(e,Expr) && e.head === :incomplete)
return e
end
end
end
# detect the reason which caused an :incomplete expression
# from the error message
# NOTE: the error messages are defined in src/julia-parser.scm
incomplete_tag(ex) = :none
function incomplete_tag(ex::Expr)
Meta.isexpr(ex, :incomplete) || return :none
msg = ex.args[1]
contains(msg, "string") && return :string
contains(msg, "comment") && return :comment
contains(msg, "requires end") && return :block
contains(msg, "\"`\"") && return :cmd
contains(msg, "character") && return :char
return :other
end
# try to include() a file, ignoring if not found
try_include(path::AbstractString) = isfile(path) && include(path)
function process_options(opts::JLOptions)
if !isempty(ARGS)
idxs = find(x -> x == "--", ARGS)
length(idxs) > 0 && deleteat!(ARGS, idxs[1])
end
repl = true
startup = (opts.startupfile != 2)
history_file = (opts.historyfile != 0)
quiet = (opts.quiet != 0)
color_set = (opts.color != 0)
global have_color = (opts.color == 1)
global is_interactive = (opts.isinteractive != 0)
while true
# startup worker.
# opts.startupfile, opts.load, etc should should not be processed for workers.
if opts.worker != C_NULL
start_worker(unsafe_string(opts.worker)) # does not return
end
# add processors
if opts.nprocs > 0
addprocs(opts.nprocs)
end
# load processes from machine file
if opts.machinefile != C_NULL
addprocs(load_machine_file(unsafe_string(opts.machinefile)))
end
# load ~/.juliarc file
startup && load_juliarc()
# load file immediately on all processors
if opts.load != C_NULL
@sync for p in procs()
@async remotecall_fetch(include, p, unsafe_string(opts.load))
end
end
# eval expression
if opts.eval != C_NULL
repl = false
eval(Main, parse_input_line(unsafe_string(opts.eval)))
break
end
# eval expression and show result
if opts.print != C_NULL
repl = false
show(eval(Main, parse_input_line(unsafe_string(opts.print))))
println()
break
end
# eval expression but don't disable interactive mode
if opts.postboot != C_NULL
eval(Main, parse_input_line(unsafe_string(opts.postboot)))
end
# load file
if !isempty(ARGS) && !isempty(ARGS[1])
# program
repl = false
# remove filename from ARGS
global PROGRAM_FILE = shift!(ARGS)
if !is_interactive
ccall(:jl_exit_on_sigint, Void, (Cint,), 1)
end
include(PROGRAM_FILE)
end
break
end
repl |= is_interactive
return (quiet,repl,startup,color_set,history_file)
end
function load_juliarc()
# If the user built us with a specific Base.SYSCONFDIR, check that location first for a juliarc.jl file
# If it is not found, then continue on to the relative path based on JULIA_HOME
if !isempty(Base.SYSCONFDIR) && isfile(joinpath(JULIA_HOME,Base.SYSCONFDIR,"julia","juliarc.jl"))
include(abspath(JULIA_HOME,Base.SYSCONFDIR,"julia","juliarc.jl"))
else
try_include(abspath(JULIA_HOME,"..","etc","julia","juliarc.jl"))
end
try_include(abspath(homedir(),".juliarc.jl"))
end
function load_machine_file(path::AbstractString)
machines = []
for line in split(readstring(path),'\n'; keep=false)
s = map!(strip, split(line,'*'; keep=false))
if length(s) > 1
cnt = isnumber(s[1]) ? parse(Int,s[1]) : Symbol(s[1])
push!(machines,(s[2], cnt))
else
push!(machines,line)
end
end
return machines
end
import .Terminals
import .REPL
const repl_hooks = []
"""
atreplinit(f)
Register a one-argument function to be called before the REPL interface is initialized in
interactive sessions; this is useful to customize the interface. The argument of `f` is the
REPL object. This function should be called from within the `.juliarc.jl` initialization
file.
"""
atreplinit(f::Function) = (unshift!(repl_hooks, f); nothing)
function _atreplinit(repl)
for f in repl_hooks
try
f(repl)
catch err
show(STDERR, err)
println(STDERR)
end
end
end
function _start()
empty!(ARGS)
append!(ARGS, Core.ARGS)
opts = JLOptions()
try
(quiet,repl,startup,color_set,history_file) = process_options(opts)
local term
global active_repl
global active_repl_backend
if repl
if !isa(STDIN,TTY)
global is_interactive |= !isa(STDIN, Union{File, IOStream})
color_set || (global have_color = false)
else
term = Terminals.TTYTerminal(get(ENV, "TERM", @static is_windows() ? "" : "dumb"), STDIN, STDOUT, STDERR)
global is_interactive = true
color_set || (global have_color = Terminals.hascolor(term))
quiet || REPL.banner(term,term)
if term.term_type == "dumb"
active_repl = REPL.BasicREPL(term)
quiet || warn("Terminal not fully functional")
else
active_repl = REPL.LineEditREPL(term, true)
active_repl.history_file = history_file
active_repl.hascolor = have_color
end
# Make sure any displays pushed in .juliarc.jl ends up above the
# REPLDisplay
pushdisplay(REPL.REPLDisplay(active_repl))
end
end
if repl
if !isa(STDIN,TTY)
# note: currently IOStream is used for file STDIN
if isa(STDIN,File) || isa(STDIN,IOStream)
# reading from a file, behave like include
eval(Main,parse_input_line(readstring(STDIN)))
else
# otherwise behave repl-like
while !eof(STDIN)
eval_user_input(parse_input_line(STDIN), true)
end
end
else
_atreplinit(active_repl)
REPL.run_repl(active_repl, backend->(global active_repl_backend = backend))
end
end
catch err
display_error(err,catch_backtrace())
exit(1)
end
if is_interactive && have_color
print(color_normal)
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
import .Serializer: known_object_data, object_number, serialize_cycle, deserialize_cycle, writetag,
__deserialized_types__, serialize_typename, deserialize_typename,
TYPENAME_TAG, object_numbers
type ClusterSerializer{I<:IO} <: AbstractSerializer
io::I
counter::Int
table::ObjectIdDict
sent_objects::Set{UInt64} # used by serialize (track objects sent)
ClusterSerializer(io::I) = new(io, 0, ObjectIdDict(), Set{UInt64}())
end
ClusterSerializer(io::IO) = ClusterSerializer{typeof(io)}(io)
function deserialize(s::ClusterSerializer, ::Type{TypeName})
full_body_sent = deserialize(s)
number = read(s.io, UInt64)
if !full_body_sent
tn = get(known_object_data, number, nothing)::TypeName
if !haskey(object_numbers, tn)
# set up reverse mapping for serialize
object_numbers[tn] = number
end
deserialize_cycle(s, tn)
else
tn = deserialize_typename(s, number)
end
return tn
end
function serialize(s::ClusterSerializer, t::TypeName)
serialize_cycle(s, t) && return
writetag(s.io, TYPENAME_TAG)
identifier = object_number(t)
send_whole = !(identifier in s.sent_objects)
serialize(s, send_whole)
write(s.io, identifier)
if send_whole
serialize_typename(s, t)
push!(s.sent_objects, identifier)
end
# println(t.module, ":", t.name, ", id:", identifier, send_whole ? " sent" : " NOT sent")
nothing
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Collections
import Base: setindex!, done, get, hash, haskey, isempty, length, next, getindex, start, copymutable
import ..Order: Forward, Ordering, lt
export
PriorityQueue,
dequeue!,
enqueue!,
heapify!,
heapify,
heappop!,
heappush!,
isheap,
peek
# Some algorithms that can be defined only after infrastructure is in place
Base.append!(a::Vector, iter) = _append!(a, Base.iteratorsize(iter), iter)
function _append!(a, ::Base.HasLength, iter)
n = length(a)
resize!(a, n+length(iter))
@inbounds for (i,item) in zip(n+1:length(a), iter)
a[i] = item
end
a
end
function _append!(a, ::Base.IteratorSize, iter)
for item in iter
push!(a, item)
end
a
end
# Heap operations on flat arrays
# ------------------------------
# Binary heap indexing
heapleft(i::Integer) = 2i
heapright(i::Integer) = 2i + 1
heapparent(i::Integer) = div(i, 2)
# Binary min-heap percolate down.
function percolate_down!(xs::AbstractArray, i::Integer, x=xs[i], o::Ordering=Forward, len::Integer=length(xs))
@inbounds while (l = heapleft(i)) <= len
r = heapright(i)
j = r > len || lt(o, xs[l], xs[r]) ? l : r
if lt(o, xs[j], x)
xs[i] = xs[j]
i = j
else
break
end
end
xs[i] = x
end
percolate_down!(xs::AbstractArray, i::Integer, o::Ordering, len::Integer=length(xs)) = percolate_down!(xs, i, xs[i], o, len)
# Binary min-heap percolate up.
function percolate_up!(xs::AbstractArray, i::Integer, x=xs[i], o::Ordering=Forward)
@inbounds while (j = heapparent(i)) >= 1
if lt(o, x, xs[j])
xs[i] = xs[j]
i = j
else
break
end
end
xs[i] = x
end
percolate_up!{T}(xs::AbstractArray{T}, i::Integer, o::Ordering) = percolate_up!(xs, i, xs[i], o)
"""
heappop!(v, [ord])
Given a binary heap-ordered array, remove and return the lowest ordered element.
For efficiency, this function does not check that the array is indeed heap-ordered.
"""
function heappop!(xs::AbstractArray, o::Ordering=Forward)
x = xs[1]
y = pop!(xs)
if !isempty(xs)
percolate_down!(xs, 1, y, o)
end
x
end
"""
heappush!(v, x, [ord])
Given a binary heap-ordered array, push a new element `x`, preserving the heap property.
For efficiency, this function does not check that the array is indeed heap-ordered.
"""
function heappush!(xs::AbstractArray, x, o::Ordering=Forward)
push!(xs, x)
percolate_up!(xs, length(xs), x, o)
xs
end
# Turn an arbitrary array into a binary min-heap in linear time.
"""
heapify!(v, ord::Ordering=Forward)
In-place [`heapify`](:func:`heapify`).
"""
function heapify!(xs::AbstractArray, o::Ordering=Forward)
for i in heapparent(length(xs)):-1:1
percolate_down!(xs, i, o)
end
xs
end
"""
heapify(v, ord::Ordering=Forward)
Returns a new vector in binary heap order, optionally using the given ordering.
```jldoctest
julia> a = [1,3,4,5,2];
julia> Base.Collections.heapify(a)
5-element Array{Int64,1}:
1
2
4
5
3
julia> Base.Collections.heapify(a, Base.Order.Reverse)
5-element Array{Int64,1}:
5
3
4
1
2
```
"""
heapify(xs::AbstractArray, o::Ordering=Forward) = heapify!(copymutable(xs), o)
"""
isheap(v, ord::Ordering=Forward)
Return `true` if an array is heap-ordered according to the given order.
```jldoctest
julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> Base.Collections.isheap(a,Base.Order.Forward)
true
julia> Base.Collections.isheap(a,Base.Order.Reverse)
false
```
"""
function isheap(xs::AbstractArray, o::Ordering=Forward)
for i in 1:div(length(xs), 2)
if lt(o, xs[heapleft(i)], xs[i]) ||
(heapright(i) <= length(xs) && lt(o, xs[heapright(i)], xs[i]))
return false
end
end
true
end
# PriorityQueue
# -------------
"""
PriorityQueue(K, V, [ord])
Construct a new [`PriorityQueue`](:obj:`PriorityQueue`), with keys of type
`K` and values/priorites of type `V`.
If an order is not given, the priority queue is min-ordered using
the default comparison for `V`.
A `PriorityQueue` acts like a `Dict`, mapping values to their
priorities, with the addition of a `dequeue!` function to remove the
lowest priority element.
```jldoctest
julia> a = Base.Collections.PriorityQueue(["a","b","c"],[2,3,1],Base.Order.Forward)
Base.Collections.PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries:
"c" => 1
"b" => 3
"a" => 2
```
"""
type PriorityQueue{K,V,O<:Ordering} <: Associative{K,V}
# Binary heap of (element, priority) pairs.
xs::Array{Pair{K,V}, 1}
o::O
# Map elements to their index in xs
index::Dict{K, Int}
function PriorityQueue(o::O)
new(Array{Pair{K,V}}(0), o, Dict{K, Int}())
end
PriorityQueue() = PriorityQueue{K,V,O}(Forward)
function PriorityQueue(ks::AbstractArray{K}, vs::AbstractArray{V},
o::O)
# TODO: maybe deprecate
if length(ks) != length(vs)
throw(ArgumentError("key and value arrays must have equal lengths"))
end
PriorityQueue{K,V,O}(zip(ks, vs), o)
end
function PriorityQueue(itr, o::O)
xs = Array{Pair{K,V}}(length(itr))
index = Dict{K, Int}()
for (i, (k, v)) in enumerate(itr)
xs[i] = Pair{K,V}(k, v)
if haskey(index, k)
throw(ArgumentError("PriorityQueue keys must be unique"))
end
index[k] = i
end
pq = new(xs, o, index)
# heapify
for i in heapparent(length(pq.xs)):-1:1
percolate_down!(pq, i)
end
pq
end
end
PriorityQueue(o::Ordering=Forward) = PriorityQueue{Any,Any,typeof(o)}(o)
PriorityQueue{K,V}(::Type{K}, ::Type{V}, o::Ordering=Forward) = PriorityQueue{K,V,typeof(o)}(o)
# TODO: maybe deprecate
PriorityQueue{K,V}(ks::AbstractArray{K}, vs::AbstractArray{V},
o::Ordering=Forward) = PriorityQueue{K,V,typeof(o)}(ks, vs, o)
PriorityQueue{K,V}(kvs::Associative{K,V}, o::Ordering=Forward) = PriorityQueue{K,V,typeof(o)}(kvs, o)
PriorityQueue{K,V}(a::AbstractArray{Tuple{K,V}}, o::Ordering=Forward) = PriorityQueue{K,V,typeof(o)}(a, o)
length(pq::PriorityQueue) = length(pq.xs)
isempty(pq::PriorityQueue) = isempty(pq.xs)
haskey(pq::PriorityQueue, key) = haskey(pq.index, key)
"""
peek(pq)
Return the lowest priority key from a priority queue without removing that
key from the queue.
"""
peek(pq::PriorityQueue) = pq.xs[1]
function percolate_down!(pq::PriorityQueue, i::Integer)
x = pq.xs[i]
@inbounds while (l = heapleft(i)) <= length(pq)
r = heapright(i)
j = r > length(pq) || lt(pq.o, pq.xs[l].second, pq.xs[r].second) ? l : r
if lt(pq.o, pq.xs[j].second, x.second)
pq.index[pq.xs[j].first] = i
pq.xs[i] = pq.xs[j]
i = j
else
break
end
end
pq.index[x.first] = i
pq.xs[i] = x
end
function percolate_up!(pq::PriorityQueue, i::Integer)
x = pq.xs[i]
@inbounds while i > 1
j = heapparent(i)
if lt(pq.o, x.second, pq.xs[j].second)
pq.index[pq.xs[j].first] = i
pq.xs[i] = pq.xs[j]
i = j
else
break
end
end
pq.index[x.first] = i
pq.xs[i] = x
end
# Equivalent to percolate_up! with an element having lower priority than any other
function force_up!(pq::PriorityQueue, i::Integer)
x = pq.xs[i]
@inbounds while i > 1
j = heapparent(i)
pq.index[pq.xs[j].first] = i
pq.xs[i] = pq.xs[j]
i = j
end
pq.index[x.first] = i
pq.xs[i] = x
end
function getindex{K,V}(pq::PriorityQueue{K,V}, key)
pq.xs[pq.index[key]].second
end
function get{K,V}(pq::PriorityQueue{K,V}, key, deflt)
i = get(pq.index, key, 0)
i == 0 ? deflt : pq.xs[i].second
end
# Change the priority of an existing element, or equeue it if it isn't present.
function setindex!{K,V}(pq::PriorityQueue{K, V}, value, key)
if haskey(pq, key)
i = pq.index[key]
oldvalue = pq.xs[i].second
pq.xs[i] = Pair{K,V}(key, value)
if lt(pq.o, oldvalue, value)
percolate_down!(pq, i)
else
percolate_up!(pq, i)
end
else
enqueue!(pq, key, value)
end
value
end
"""
enqueue!(pq, k, v)
Insert the a key `k` into a priority queue `pq` with priority `v`.
```jldoctest
julia> a = Base.Collections.PriorityQueue(["a","b","c"],[2,3,1],Base.Order.Forward)
Base.Collections.PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries:
"c" => 1
"b" => 3
"a" => 2
julia> Base.Collections.enqueue!(a, "d", 4)
Base.Collections.PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 4 entries:
"c" => 1
"b" => 3
"a" => 2
"d" => 4
```
"""
function enqueue!{K,V}(pq::PriorityQueue{K,V}, key, value)
if haskey(pq, key)
throw(ArgumentError("PriorityQueue keys must be unique"))
end
push!(pq.xs, Pair{K,V}(key, value))
pq.index[key] = length(pq)
percolate_up!(pq, length(pq))
pq
end
"""
dequeue!(pq)
Remove and return the lowest priority key from a priority queue.
```jldoctest
julia> a = Base.Collections.PriorityQueue(["a","b","c"],[2,3,1],Base.Order.Forward)
Base.Collections.PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 3 entries:
"c" => 1
"b" => 3
"a" => 2
julia> Base.Collections.dequeue!(a)
"c"
julia> a
Base.Collections.PriorityQueue{String,Int64,Base.Order.ForwardOrdering} with 2 entries:
"b" => 3
"a" => 2
```
"""
function dequeue!(pq::PriorityQueue)
x = pq.xs[1]
y = pop!(pq.xs)
if !isempty(pq)
pq.xs[1] = y
pq.index[y.first] = 1
percolate_down!(pq, 1)
end
delete!(pq.index, x.first)
x.first
end
function dequeue!(pq::PriorityQueue, key)
idx = pq.index[key]
force_up!(pq, idx)
dequeue!(pq)
key
end
# Unordered iteration through key value pairs in a PriorityQueue
start(pq::PriorityQueue) = start(pq.index)
done(pq::PriorityQueue, i) = done(pq.index, i)
function next{K,V}(pq::PriorityQueue{K,V}, i)
(k, idx), i = next(pq.index, i)
return (pq.xs[idx], i)
end
end # module Collections
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Factorials
const _fact_table64 =
Int64[1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,
87178291200,1307674368000,20922789888000,355687428096000,6402373705728000,
121645100408832000,2432902008176640000]
const _fact_table128 =
UInt128[0x00000000000000000000000000000001, 0x00000000000000000000000000000002,
0x00000000000000000000000000000006, 0x00000000000000000000000000000018,
0x00000000000000000000000000000078, 0x000000000000000000000000000002d0,
0x000000000000000000000000000013b0, 0x00000000000000000000000000009d80,
0x00000000000000000000000000058980, 0x00000000000000000000000000375f00,
0x00000000000000000000000002611500, 0x0000000000000000000000001c8cfc00,
0x0000000000000000000000017328cc00, 0x0000000000000000000000144c3b2800,
0x00000000000000000000013077775800, 0x00000000000000000000130777758000,
0x00000000000000000001437eeecd8000, 0x00000000000000000016beecca730000,
0x000000000000000001b02b9306890000, 0x000000000000000021c3677c82b40000,
0x0000000000000002c5077d36b8c40000, 0x000000000000003ceea4c2b3e0d80000,
0x000000000000057970cd7e2933680000, 0x00000000000083629343d3dcd1c00000,
0x00000000000cd4a0619fb0907bc00000, 0x00000000014d9849ea37eeac91800000,
0x00000000232f0fcbb3e62c3358800000, 0x00000003d925ba47ad2cd59dae000000,
0x0000006f99461a1e9e1432dcb6000000, 0x00000d13f6370f96865df5dd54000000,
0x0001956ad0aae33a4560c5cd2c000000, 0x0032ad5a155c6748ac18b9a580000000,
0x0688589cc0e9505e2f2fee5580000000, 0xde1bc4d19efcac82445da75b00000000]
function factorial_lookup(n::Integer, table, lim)
n < 0 && throw(DomainError())
n > lim && throw(OverflowError())
n == 0 && return one(n)
@inbounds f = table[n]
return oftype(n, f)
end
factorial(n::Int128) = factorial_lookup(n, _fact_table128, 33)
factorial(n::UInt128) = factorial_lookup(n, _fact_table128, 34)
factorial(n::Union{Int64,UInt64}) = factorial_lookup(n, _fact_table64, 20)
if Int === Int32
factorial(n::Union{Int8,UInt8,Int16,UInt16}) = factorial(Int32(n))
factorial(n::Union{Int32,UInt32}) = factorial_lookup(n, _fact_table64, 12)
else
factorial(n::Union{Int8,UInt8,Int16,UInt16,Int32,UInt32}) = factorial(Int64(n))
end
function gamma(n::Union{Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64})
n < 0 && throw(DomainError())
n == 0 && return Inf
n <= 2 && return 1.0
n > 20 && return gamma(Float64(n))
@inbounds return Float64(_fact_table64[n-1])
end
# Basic functions for working with permutations
"""
isperm(v) -> Bool
Returns `true` if `v` is a valid permutation.
```jldoctest
julia> isperm([1; 2])
true
julia> isperm([1; 3])
false
```
"""
function isperm(A)
n = length(A)
used = falses(n)
for a in A
(0 < a <= n) && (used[a] $= true) || return false
end
true
end
isperm(p::Tuple{}) = true
isperm(p::Tuple{Int}) = p[1] == 1
isperm(p::Tuple{Int,Int}) = ((p[1] == 1) & (p[2] == 2)) | ((p[1] == 2) & (p[2] == 1))
function permute!!{T<:Integer}(a, p::AbstractVector{T})
count = 0
start = 0
while count < length(a)
ptr = start = findnext(p, start+1)
temp = a[start]
next = p[start]
count += 1
while next != start
a[ptr] = a[next]
p[ptr] = 0
ptr = next
next = p[next]
count += 1
end
a[ptr] = temp
p[ptr] = 0
end
a
end
"""
permute!(v, p)
Permute vector `v` in-place, according to permutation `p`. No checking is done
to verify that `p` is a permutation.
To return a new permutation, use `v[p]`. Note that this is generally faster than
`permute!(v,p)` for large vectors.
"""
permute!(a, p::AbstractVector) = permute!!(a, copymutable(p))
function ipermute!!{T<:Integer}(a, p::AbstractVector{T})
count = 0
start = 0
while count < length(a)
start = findnext(p, start+1)
temp = a[start]
next = p[start]
count += 1
while next != start
temp_next = a[next]
a[next] = temp
temp = temp_next
ptr = p[next]
p[next] = 0
next = ptr
count += 1
end
a[next] = temp
p[next] = 0
end
a
end
"""
ipermute!(v, p)
Like `permute!`, but the inverse of the given permutation is applied.
"""
ipermute!(a, p::AbstractVector) = ipermute!!(a, copymutable(p))
"""
invperm(v)
Return the inverse permutation of `v`.
If `B = A[v]`, then `A == B[invperm(v)]`.
```jldoctest
julia> v = [2; 4; 3; 1];
julia> invperm(v)
4-element Array{Int64,1}:
4
1
3
2
julia> A = ['a','b','c','d'];
julia> B = A[v]
4-element Array{Char,1}:
'b'
'd'
'c'
'a'
julia> B[invperm(v)]
4-element Array{Char,1}:
'a'
'b'
'c'
'd'
```
"""
function invperm(a::AbstractVector)
b = zero(a) # similar vector of zeros
n = length(a)
@inbounds for (i, j) in enumerate(a)
((1 <= j <= n) && b[j] == 0) ||
throw(ArgumentError("argument is not a permutation"))
b[j] = i
end
b
end
function invperm(p::Union{Tuple{},Tuple{Int},Tuple{Int,Int}})
isperm(p) || throw(ArgumentError("argument is not a permutation"))
p # in dimensions 0-2, every permutation is its own inverse
end
invperm(a::Tuple) = (invperm([a...])...,)
#XXX This function should be moved to Combinatorics.jl but is currently used by Base.DSP.
"""
nextprod([k_1,k_2,...], n)
Next integer not less than `n` that can be written as ``\\prod k_i^{p_i}`` for integers
``p_1``, ``p_2``, etc.
"""
function nextprod(a::Vector{Int}, x)
if x > typemax(Int)
throw(ArgumentError("unsafe for x > typemax(Int), got $x"))
end
k = length(a)
v = ones(Int, k) # current value of each counter
mx = [nextpow(ai,x) for ai in a] # maximum value of each counter
v[1] = mx[1] # start at first case that is >= x
p::widen(Int) = mx[1] # initial value of product in this case
best = p
icarry = 1
while v[end] < mx[end]
if p >= x
best = p < best ? p : best # keep the best found yet
carrytest = true
while carrytest
p = div(p, v[icarry])
v[icarry] = 1
icarry += 1
p *= a[icarry]
v[icarry] *= a[icarry]
carrytest = v[icarry] > mx[icarry] && icarry < k
end
if p < x
icarry = 1
end
else
while p < x
p *= a[1]
v[1] *= a[1]
end
end
end
# might overflow, but want predictable return type
return mx[end] < best ? Int(mx[end]) : Int(best)
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
immutable Complex{T<:Real} <: Number
re::T
im::T
end
Complex(x::Real, y::Real) = Complex(promote(x,y)...)
Complex(x::Real) = Complex(x, zero(x))
"""
im
The imaginary unit.
"""
const im = Complex(false,true)
typealias Complex128 Complex{Float64}
typealias Complex64 Complex{Float32}
typealias Complex32 Complex{Float16}
convert{T<:Real}(::Type{Complex{T}}, x::Real) = Complex{T}(x,0)
convert{T<:Real}(::Type{Complex{T}}, z::Complex) = Complex{T}(real(z),imag(z))
convert{T<:Real}(::Type{T}, z::Complex) =
isreal(z) ? convert(T,real(z)) : throw(InexactError())
convert(::Type{Complex}, z::Complex) = z
convert(::Type{Complex}, x::Real) = Complex(x)
promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{S}) =
Complex{promote_type(T,S)}
promote_rule{T<:Real,S<:Real}(::Type{Complex{T}}, ::Type{Complex{S}}) =
Complex{promote_type(T,S)}
widen{T}(::Type{Complex{T}}) = Complex{widen(T)}
"""
real(z)
Return the real part of the complex number `z`.
"""
real(z::Complex) = z.re
"""
imag(z)
Return the imaginary part of the complex number `z`.
"""
imag(z::Complex) = z.im
real(x::Real) = x
imag(x::Real) = zero(x)
"""
reim(z)
Return both the real and imaginary parts of the complex number `z`.
"""
reim(z) = (real(z), imag(z))
real{T<:Real}(::Type{T}) = T
real{T<:Real}(::Type{Complex{T}}) = T
complex{T<:Real}(::Type{T}) = Complex{T}
complex{T<:Real}(::Type{Complex{T}}) = Complex{T}
isreal(x::Real) = true
isreal(z::Complex) = imag(z) == 0
"""
isimag(z) -> Bool
Test whether `z` is purely imaginary, i.e. has a real part equal to 0.
"""
isimag(z::Number) = real(z) == 0
isinteger(z::Complex) = isreal(z) & isinteger(real(z))
isfinite(z::Complex) = isfinite(real(z)) & isfinite(imag(z))
isnan(z::Complex) = isnan(real(z)) | isnan(imag(z))
isinf(z::Complex) = isinf(real(z)) | isinf(imag(z))
complex(x::Real, y::Real) = Complex(x, y)
complex(x::Real) = Complex(x)
complex(z::Complex) = z
flipsign(x::Complex, y::Real) = ifelse(signbit(y), -x, x)
function show(io::IO, z::Complex)
r, i = reim(z)
compact = get(io, :compact, false)
show(io, r)
if signbit(i) && !isnan(i)
i = -i
print(io, compact ? "-" : " - ")
else
print(io, compact ? "+" : " + ")
end
show(io, i)
if !(isa(i,Integer) && !isa(i,Bool) || isa(i,AbstractFloat) && isfinite(i))
print(io, "*")
end
print(io, "im")
end
show(io::IO, z::Complex{Bool}) =
print(io, z == im ? "im" : "Complex($(z.re),$(z.im))")
function read{T<:Real}(s::IO, ::Type{Complex{T}})
r = read(s,T)
i = read(s,T)
Complex{T}(r,i)
end
function write(s::IO, z::Complex)
write(s,real(z),imag(z))
end
## equality and hashing of complex numbers ##
==(z::Complex, w::Complex) = (real(z) == real(w)) & (imag(z) == imag(w))
==(z::Complex, x::Real) = isreal(z) && real(z) == x
==(x::Real, z::Complex) = isreal(z) && real(z) == x
isequal(z::Complex, w::Complex) = isequal(real(z),real(w)) & isequal(imag(z),imag(w))
if UInt === UInt64
const h_imag = 0x32a7a07f3e7cd1f9
else
const h_imag = 0x3e7cd1f9
end
const hash_0_imag = hash(0, h_imag)
function hash(z::Complex, h::UInt)
# TODO: with default argument specialization, this would be better:
# hash(real(z), h $ hash(imag(z), h $ h_imag) $ hash(0, h $ h_imag))
hash(real(z), h $ hash(imag(z), h_imag) $ hash_0_imag)
end
## generic functions of complex numbers ##
"""
conj(z)
Compute the complex conjugate of a complex number `z`.
"""
conj(z::Complex) = Complex(real(z),-imag(z))
abs(z::Complex) = hypot(real(z), imag(z))
abs2(z::Complex) = real(z)*real(z) + imag(z)*imag(z)
inv(z::Complex) = conj(z)/abs2(z)
inv{T<:Integer}(z::Complex{T}) = inv(float(z))
-(z::Complex) = Complex(-real(z), -imag(z))
+(z::Complex, w::Complex) = Complex(real(z) + real(w), imag(z) + imag(w))
-(z::Complex, w::Complex) = Complex(real(z) - real(w), imag(z) - imag(w))
*(z::Complex, w::Complex) = Complex(real(z) * real(w) - imag(z) * imag(w),
real(z) * imag(w) + imag(z) * real(w))
muladd(z::Complex, w::Complex, x::Complex) =
Complex(muladd(real(z), real(w), real(x)) - imag(z)*imag(w), # TODO: use mulsub given #15985
muladd(real(z), imag(w), muladd(imag(z), real(w), imag(x))))
# handle Bool and Complex{Bool}
# avoid type signature ambiguity warnings
+(x::Bool, z::Complex{Bool}) = Complex(x + real(z), imag(z))
+(z::Complex{Bool}, x::Bool) = Complex(real(z) + x, imag(z))
-(x::Bool, z::Complex{Bool}) = Complex(x - real(z), - imag(z))
-(z::Complex{Bool}, x::Bool) = Complex(real(z) - x, imag(z))
*(x::Bool, z::Complex{Bool}) = Complex(x * real(z), x * imag(z))
*(z::Complex{Bool}, x::Bool) = Complex(real(z) * x, imag(z) * x)
+(x::Bool, z::Complex) = Complex(x + real(z), imag(z))
+(z::Complex, x::Bool) = Complex(real(z) + x, imag(z))
-(x::Bool, z::Complex) = Complex(x - real(z), - imag(z))
-(z::Complex, x::Bool) = Complex(real(z) - x, imag(z))
*(x::Bool, z::Complex) = Complex(x * real(z), x * imag(z))
*(z::Complex, x::Bool) = Complex(real(z) * x, imag(z) * x)
+(x::Real, z::Complex{Bool}) = Complex(x + real(z), imag(z))
+(z::Complex{Bool}, x::Real) = Complex(real(z) + x, imag(z))
function -(x::Real, z::Complex{Bool})
# we don't want the default type for -(Bool)
re = x-real(z)
Complex(re, - oftype(re, imag(z)))
end
-(z::Complex{Bool}, x::Real) = Complex(real(z) - x, imag(z))
*(x::Real, z::Complex{Bool}) = Complex(x * real(z), x * imag(z))
*(z::Complex{Bool}, x::Real) = Complex(real(z) * x, imag(z) * x)
# adding or multiplying real & complex is common
+(x::Real, z::Complex) = Complex(x + real(z), imag(z))
+(z::Complex, x::Real) = Complex(x + real(z), imag(z))
function -(x::Real, z::Complex)
# we don't want the default type for -(Bool)
re = x - real(z)
Complex(re, - oftype(re, imag(z)))
end
-(z::Complex, x::Real) = Complex(real(z) - x, imag(z))
*(x::Real, z::Complex) = Complex(x * real(z), x * imag(z))
*(z::Complex, x::Real) = Complex(x * real(z), x * imag(z))
muladd(x::Real, z::Complex, y::Number) = muladd(z, x, y)
muladd(z::Complex, x::Real, y::Real) = Complex(muladd(real(z),x,y), imag(z)*x)
muladd(z::Complex, x::Real, w::Complex) =
Complex(muladd(real(z),x,real(w)), muladd(imag(z),x,imag(w)))
muladd(x::Real, y::Real, z::Complex) = Complex(muladd(x,y,real(z)), imag(z))
muladd(z::Complex, w::Complex, x::Real) =
Complex(muladd(real(z), real(w), x) - imag(z)*imag(w), # TODO: use mulsub given #15985
muladd(real(z), imag(w), imag(z) * real(w)))
/(a::Real, z::Complex) = a*inv(z)
/(z::Complex, x::Real) = Complex(real(z)/x, imag(z)/x)
function /{T<:Real}(a::Complex{T}, b::Complex{T})
are = real(a); aim = imag(a); bre = real(b); bim = imag(b)
if abs(bre) <= abs(bim)
if isinf(bre) && isinf(bim)
r = sign(bre)/sign(bim)
else
r = bre / bim
end
den = bim + r*bre
Complex((are*r + aim)/den, (aim*r - are)/den)
else
if isinf(bre) && isinf(bim)
r = sign(bim)/sign(bre)
else
r = bim / bre
end
den = bre + r*bim
Complex((are + aim*r)/den, (aim - are*r)/den)
end
end
inv{T<:Union{Float16,Float32}}(z::Complex{T}) =
oftype(z, conj(widen(z))/abs2(widen(z)))
/{T<:Union{Float16,Float32}}(z::Complex{T}, w::Complex{T}) =
oftype(z, widen(z)*inv(widen(w)))
# robust complex division for double precision
# the first step is to scale variables if appropriate ,then do calculations
# in a way that avoids over/underflow (subfuncs 1 and 2), then undo the scaling.
# scaling variable s and other techniques
# based on arxiv.1210.4539
# a + i*b
# p + i*q = ---------
# c + i*d
function /(z::Complex128, w::Complex128)
a, b = reim(z); c, d = reim(w)
half = 0.5
two = 2.0
ab = max(abs(a), abs(b))
cd = max(abs(c), abs(d))
ov = realmax(a)
un = realmin(a)
ϵ = eps(Float64)
bs = two/(ϵ*ϵ)
s = 1.0
ab >= half*ov && (a=half*a; b=half*b; s=two*s ) # scale down a,b
cd >= half*ov && (c=half*c; d=half*d; s=s*half) # scale down c,d
ab <= un*two/ϵ && (a=a*bs; b=b*bs; s=s/bs ) # scale up a,b
cd <= un*two/ϵ && (c=c*bs; d=d*bs; s=s*bs ) # scale up c,d
abs(d)<=abs(c) ? ((p,q)=robust_cdiv1(a,b,c,d) ) : ((p,q)=robust_cdiv1(b,a,d,c); q=-q)
return Complex128(p*s,q*s) # undo scaling
end
function robust_cdiv1(a::Float64, b::Float64, c::Float64, d::Float64)
r = d/c
t = 1.0/(c+d*r)
p = robust_cdiv2(a,b,c,d,r,t)
q = robust_cdiv2(b,-a,c,d,r,t)
return p,q
end
function robust_cdiv2(a::Float64, b::Float64, c::Float64, d::Float64, r::Float64, t::Float64)
if r != 0
br = b*r
return (br != 0 ? (a+br)*t : a*t + (b*t)*r)
else
return (a + d*(b/c)) * t
end
end
function inv(w::Complex128)
c, d = reim(w)
half = 0.5
two = 2.0
cd = max(abs(c), abs(d))
ov = realmax(c)
un = realmin(c)
ϵ = eps(Float64)
bs = two/(ϵ*ϵ)
s = 1.0
cd >= half*ov && (c=half*c; d=half*d; s=s*half) # scale down c,d
cd <= un*two/ϵ && (c=c*bs; d=d*bs; s=s*bs ) # scale up c,d
if abs(d)<=abs(c)
r = d/c
t = 1.0/(c+d*r)
p = t
q = -r * t
else
c, d = d, c
r = d/c
t = 1.0/(c+d*r)
p = r * t
q = -t
end
return Complex128(p*s,q*s) # undo scaling
end
function ssqs{T<:AbstractFloat}(x::T, y::T)
k::Int = 0
ρ = x*x + y*y
if !isfinite(ρ) && (isinf(x) || isinf(y))
ρ = convert(T, Inf)
elseif isinf(ρ) || (ρ==0 && (x!=0 || y!=0)) || ρ<nextfloat(zero(T))/(2*eps(T)^2)
m::T = max(abs(x), abs(y))
k = m==0 ? m : exponent(m)
xk, yk = ldexp(x,-k), ldexp(y,-k)
ρ = xk*xk + yk*yk
end
ρ, k
end
function sqrt{T<:AbstractFloat}(z::Complex{T})
x, y = reim(z)
if x==y==0
return Complex(zero(x),y)
end
ρ, k::Int = ssqs(x, y)
if isfinite(x) ρ=ldexp(abs(x),-k)+sqrt(ρ) end
if isodd(k)
k = div(k-1,2)
else
k = div(k,2)-1
ρ += ρ
end
ρ = ldexp(sqrt(ρ),k) #sqrt((abs(z)+abs(x))/2) without over/underflow
ξ = ρ
η = y
if ρ != 0
if isfinite(η) η=(η/ρ)/2 end
if x<0
ξ = abs(η)
η = copysign(ρ,y)
end
end
Complex(ξ,η)
end
sqrt(z::Complex) = sqrt(float(z))
# function sqrt(z::Complex)
# rz = float(real(z))
# iz = float(imag(z))
# r = sqrt((hypot(rz,iz)+abs(rz))/2)
# if r == 0
# return Complex(zero(iz), iz)
# end
# if rz >= 0
# return Complex(r, iz/r/2)
# end
# return Complex(abs(iz)/r/2, copysign(r,iz))
# end
# compute exp(im*theta)
cis(theta::Real) = Complex(cos(theta),sin(theta))
"""
cis(z)
Return ``\\exp(iz)``.
"""
function cis(z::Complex)
v = exp(-imag(z))
Complex(v*cos(real(z)), v*sin(real(z)))
end
"""
angle(z)
Compute the phase angle in radians of a complex number `z`.
"""
angle(z::Complex) = atan2(imag(z), real(z))
function log{T<:AbstractFloat}(z::Complex{T})
const T1::T = 1.25
const T2::T = 3
const ln2::T = log(convert(T,2)) #0.6931471805599453
x, y = reim(z)
ρ, k = ssqs(x,y)
ax = abs(x)
ay = abs(y)
if ax < ay
θ, β = ax, ay
else
θ, β = ay, ax
end
if k==0 && (0.5 < β*β) && (β <= T1 || ρ < T2)
ρρ = log1p((β-1)*(β+1)+θ*θ)/2
else
ρρ = log(ρ)/2 + k*ln2
end
Complex(ρρ, angle(z))
end
log(z::Complex) = log(float(z))
# function log(z::Complex)
# ar = abs(real(z))
# ai = abs(imag(z))
# if ar < ai
# r = ar/ai
# re = log(ai) + log1p(r*r)/2
# else
# if ar == 0
# re = isnan(ai) ? ai : -inv(ar)
# elseif isinf(ai)
# re = oftype(ar,Inf)
# else
# r = ai/ar
# re = log(ar) + log1p(r*r)/2
# end
# end
# Complex(re, angle(z))
# end
function log10(z::Complex)
a = log(z)
a/log(oftype(real(a),10))
end
function log2(z::Complex)
a = log(z)
a/log(oftype(real(a),2))
end
function exp(z::Complex)
zr, zi = reim(z)
if isnan(zr)
Complex(zr, zi==0 ? zi : zr)
elseif !isfinite(zi)
if zr == Inf
Complex(-zr, oftype(zr,NaN))
elseif zr == -Inf
Complex(-zero(zr), copysign(zero(zi), zi))
else
Complex(oftype(zr,NaN), oftype(zi,NaN))
end
else
er = exp(zr)
if zi == zero(zi)
Complex(er, zi)
else
Complex(er*cos(zi), er*sin(zi))
end
end
end
function expm1(z::Complex)
zr,zi = reim(z)
if isnan(zr)
Complex(zr, zi==0 ? zi : zr)
elseif !isfinite(zi)
if zr == Inf
Complex(-zr, oftype(zr,NaN))
elseif zr == -Inf
Complex(-one(zr), copysign(zero(zi), zi))
else
Complex(oftype(zr,NaN), oftype(zi,NaN))
end
else
erm1 = expm1(zr)
if zi == 0
Complex(erm1, zi)
else
er = erm1+one(erm1)
wr = isfinite(er) ? erm1 - 2.0*er*(sin(0.5*zi))^2 : er*cos(zi)
Complex(wr, er*sin(zi))
end
end
end
function log1p{T}(z::Complex{T})
zr,zi = reim(z)
if isfinite(zr)
isinf(zi) && return log(z)
# This is based on a well-known trick for log1p of real z,
# allegedly due to Kahan, only modified to handle real(u) <= 0
# differently to avoid inaccuracy near z==-2 and for correct branch cut
u = float(one(T)) + z
u == 1 ? convert(typeof(u), z) : real(u) <= 0 ? log(u) : log(u)*z/(u-1)
elseif isnan(zr)
Complex(zr, zr)
elseif isfinite(zi)
Complex(T(Inf), copysign(zr > 0 ? zero(T) : convert(T, pi), zi))
else
Complex(T(Inf), T(NaN))
end
end
function ^{T<:AbstractFloat}(z::Complex{T}, p::Complex{T})::Complex{T}
if p == 2 #square
zr, zi = reim(z)
x = (zr-zi)*(zr+zi)
y = 2*zr*zi
if isnan(x)
if isinf(y)
x = copysign(zero(T),zr)
elseif isinf(zi)
x = convert(T,-Inf)
elseif isinf(zr)
x = convert(T,Inf)
end
elseif isnan(y) && isinf(x)
y = copysign(zero(T), y)
end
Complex(x,y)
elseif z!=0
if p!=0 && isinteger(p)
rp = real(p)
if rp < 0
return power_by_squaring(inv(z), convert(Integer, -rp))
else
return power_by_squaring(z, convert(Integer, rp))
end
end
exp(p*log(z))
elseif p!=0 #0^p
zero(z) #CHECK SIGNS
else #0^0
zer = copysign(zero(T),real(p))*copysign(zero(T),imag(z))
Complex(one(T), zer)
end
end
function exp2{T}(z::Complex{T})
er = exp2(real(z))
theta = imag(z) * log(convert(T, 2))
Complex(er*cos(theta), er*sin(theta))
end
function exp10{T}(z::Complex{T})
er = exp10(real(z))
theta = imag(z) * log(convert(T, 10))
Complex(er*cos(theta), er*sin(theta))
end
function ^{T<:Complex}(z::T, p::T)
if isinteger(p)
rp = real(p)
if rp < 0
return power_by_squaring(inv(float(z)), convert(Integer, -rp))
else
return power_by_squaring(float(z), convert(Integer, rp))
end
end
pr, pim = reim(p)
zr, zi = reim(z)
r = abs(z)
rp = r^pr
theta = atan2(zi, zr)
ntheta = pr*theta
if pim != 0 && r != 0
rp = rp*exp(-pim*theta)
ntheta = ntheta + pim*log(r)
end
cosntheta = cos(ntheta)
sinntheta = sin(ntheta)
re, im = rp*cosntheta, rp*sinntheta
if isinf(rp)
if isnan(re)
re = copysign(zero(re), cosntheta)
end
if isnan(im)
im = copysign(zero(im), sinntheta)
end
end
# apply some corrections to force known zeros
if pim == 0
if isinteger(pr)
if zi == 0
im = copysign(zero(im), im)
elseif zr == 0
if isinteger(0.5*pr) # pr is even
im = copysign(zero(im), im)
else
re = copysign(zero(re), re)
end
end
else
dr = pr*2
if isinteger(dr) && zi == 0
if zr < 0
re = copysign(zero(re), re)
else
im = copysign(zero(im), im)
end
end
end
end
Complex(re, im)
end
^(z::Complex, n::Bool) = n ? z : one(z)
^(z::Complex, n::Integer) = z^Complex(n)
^{T<:AbstractFloat}(z::Complex{T}, n::Bool) = n ? z : one(z) # to resolve ambiguity
^{T<:Integer}(z::Complex{T}, n::Bool) = n ? z : one(z) # to resolve ambiguity
^{T<:AbstractFloat}(z::Complex{T}, n::Integer) =
n>=0 ? power_by_squaring(z,n) : power_by_squaring(inv(z),-n)
^{T<:Integer}(z::Complex{T}, n::Integer) = power_by_squaring(z,n) # DomainError for n<0
function sin{T}(z::Complex{T})
F = float(T)
zr, zi = reim(z)
if zr == 0
Complex(F(zr), sinh(zi))
elseif !isfinite(zr)
if zi == 0 || isinf(zi)
Complex(F(NaN), F(zi))
else
Complex(F(NaN), F(NaN))
end
else
Complex(sin(zr)*cosh(zi), cos(zr)*sinh(zi))
end
end
function cos{T}(z::Complex{T})
F = float(T)
zr, zi = reim(z)
if zr == 0
Complex(cosh(zi), isnan(zi) ? F(zr) : -flipsign(F(zr),zi))
elseif !isfinite(zr)
if zi == 0
Complex(F(NaN), isnan(zr) ? zero(F) : -flipsign(F(zi),zr))
elseif isinf(zi)
Complex(F(Inf), F(NaN))
else
Complex(F(NaN), F(NaN))
end
else
Complex(cos(zr)*cosh(zi), -sin(zr)*sinh(zi))
end
end
function tan(z::Complex)
zr, zi = reim(z)
w = tanh(Complex(-zi, zr))
Complex(imag(w), -real(w))
end
function asin(z::Complex)
zr, zi = reim(z)
if isinf(zr) && isinf(zi)
return Complex(copysign(oftype(zr,pi)/4, zr),zi)
elseif isnan(zi) && isinf(zr)
return Complex(zi, oftype(zr, Inf))
end
ξ = zr == 0 ? zr :
!isfinite(zr) ? oftype(zr,pi)/2 * sign(zr) :
atan2(zr, real(sqrt(1-z)*sqrt(1+z)))
η = asinh(copysign(imag(sqrt(conj(1-z))*sqrt(1+z)), imag(z)))
Complex(ξ,η)
end
function acos{T<:AbstractFloat}(z::Complex{T})
zr, zi = reim(z)
if isnan(zr)
if isinf(zi) return Complex(zr, -zi)
else return Complex(zr, zr) end
elseif isnan(zi)
if isinf(zr) return Complex(zi, abs(zr))
elseif zr==0 return Complex(oftype(zr,pi)/2, zi)
else return Complex(zi, zi) end
elseif zr==zi==0
return Complex(oftype(zr,pi)/2, -zi)
elseif zr==Inf && zi===0.0
return Complex(zi, -zr)
elseif zr==-Inf && zi===-0.0
return Complex(oftype(zi,pi), -zr)
end
ξ = 2*atan2(real(sqrt(1-z)), real(sqrt(1+z)))
η = asinh(imag(sqrt(conj(1+z))*sqrt(1-z)))
if isinf(zr) && isinf(zi) ξ -= oftype(η,pi)/4 * sign(zr) end
Complex(ξ,η)
end
acos(z::Complex) = acos(float(z))
function atan(z::Complex)
w = atanh(Complex(-imag(z),real(z)))
Complex(imag(w),-real(w))
end
function sinh(z::Complex)
zr, zi = reim(z)
w = sin(Complex(zi, zr))
Complex(imag(w),real(w))
end
function cosh(z::Complex)
zr, zi = reim(z)
cos(Complex(zi,-zr))
end
function tanh{T<:AbstractFloat}(z::Complex{T})
const Ω = prevfloat(typemax(T))
ξ, η = reim(z)
if isnan(ξ) && η==0 return Complex(ξ, η) end
if 4*abs(ξ) > asinh(Ω) #Overflow?
Complex(copysign(one(T),ξ),
copysign(zero(T),η*(isfinite(η) ? sin(2*abs(η)) : one(η))))
else
t = tan(η)
β = 1+t*t #sec(η)^2
s = sinh(ξ)
ρ = sqrt(1 + s*s) #cosh(ξ)
if isinf(t)
Complex(ρ/s,1/t)
else
Complex(β*ρ*s,t)/(1+β*s*s)
end
end
end
tanh(z::Complex) = tanh(float(z))
function asinh(z::Complex)
w = asin(Complex(-imag(z),real(z)))
Complex(imag(w),-real(w))
end
function acosh(z::Complex)
zr, zi = reim(z)
if isnan(zr) || isnan(zi)
if isinf(zr) || isinf(zi)
return Complex(oftype(zr, Inf), oftype(zi, NaN))
else
return Complex(oftype(zr, NaN), oftype(zi, NaN))
end
elseif zr==-Inf && zi===-0.0 #Edge case is wrong - WHY?
return Complex(oftype(zr,Inf), oftype(zi, -pi))
end
ξ = asinh(real(sqrt(conj(z-1))*sqrt(z+1)))
η = 2atan2(imag(sqrt(z-1)),real(sqrt(z+1)))
if isinf(zr) && isinf(zi)
η -= oftype(η,pi)/4 * sign(zi) * sign(zr)
end
Complex(ξ, η)
end
function atanh{T<:AbstractFloat}(z::Complex{T})
const Ω = prevfloat(typemax(T))
const θ = sqrt(Ω)/4
const ρ = 1/θ
x, y = reim(z)
ax = abs(x)
ay = abs(y)
if ax > θ || ay > θ #Prevent overflow
if isnan(y)
if isinf(x)
return Complex(copysign(zero(x),x), y)
else
return Complex(real(1/z), y)
end
end
if isinf(y)
return Complex(copysign(zero(x),x), copysign(oftype(y,pi)/2, y))
end
return Complex(real(1/z), copysign(oftype(y,pi)/2, y))
elseif ax==1
if y == 0
ξ = copysign(oftype(x,Inf),x)
η = zero(y)
else
ym = ay+ρ
ξ = log(sqrt(sqrt(4+y*y))/sqrt(ym))
η = copysign(oftype(y,pi)/2 + atan(ym/2), y)/2
end
else #Normal case
ysq = (ay+ρ)^2
if x == 0
ξ = x
else
ξ = log1p(4x/((1-x)^2 + ysq))/4
end
η = angle(Complex((1-x)*(1+x)-ysq, 2y))/2
end
Complex(ξ, η)
end
atanh(z::Complex) = atanh(float(z))
function lexcmp(a::Complex, b::Complex)
c = cmp(real(a), real(b))
c == 0 || return c
cmp(imag(a), imag(b))
end
#Rounding complex numbers
#Requires two different RoundingModes for the real and imaginary components
"""
round(z, RoundingModeReal, RoundingModeImaginary)
Returns the nearest integral value of the same type as the complex-valued `z` to `z`,
breaking ties using the specified [`RoundingMode`](:obj:`RoundingMode`)s. The first
[`RoundingMode`](:obj:`RoundingMode`) is used for rounding the real components while the
second is used for rounding the imaginary components.
"""
function round{T<:AbstractFloat, MR, MI}(z::Complex{T}, ::RoundingMode{MR}, ::RoundingMode{MI})
Complex(round(real(z), RoundingMode{MR}()),
round(imag(z), RoundingMode{MI}()))
end
round(z::Complex) = Complex(round(real(z)), round(imag(z)))
function round(z::Complex, digits::Integer, base::Integer=10)
Complex(round(real(z), digits, base),
round(imag(z), digits, base))
end
float{T<:AbstractFloat}(z::Complex{T}) = z
float(z::Complex) = Complex(float(real(z)), float(imag(z)))
big{T<:AbstractFloat}(z::Complex{T}) = Complex{BigFloat}(z)
big{T<:Integer}(z::Complex{T}) = Complex{BigInt}(z)
## Array operations on complex numbers ##
complex{T<:Complex}(A::AbstractArray{T}) = A
function complex{T}(A::AbstractArray{T})
if !isleaftype(T)
error("`complex` not defined on abstractly-typed arrays; please convert to a more specific type")
end
convert(AbstractArray{typeof(complex(zero(T)))}, A)
end
big{T<:Integer,N}(A::AbstractArray{Complex{T},N}) = convert(AbstractArray{Complex{BigInt},N}, A)
big{T<:AbstractFloat,N}(A::AbstractArray{Complex{T},N}) = convert(AbstractArray{Complex{BigFloat},N}, A)
## promotion to complex ##
_default_type(T::Type{Complex}) = Complex{Int}
promote_array_type{S<:Union{Complex, Real}, T<:AbstractFloat}(F, ::Type{S}, ::Type{Complex{T}}, ::Type) = Complex{T}
function complex{S<:Real,T<:Real}(A::AbstractArray{S}, B::AbstractArray{T})
if size(A) != size(B); throw(DimensionMismatch()); end
F = similar(A, typeof(complex(zero(S),zero(T))))
RF, RA, RB = eachindex(F), eachindex(A), eachindex(B)
if RF == RA == RB
for i in RA
@inbounds F[i] = complex(A[i], B[i])
end
else
for (iF, iA, iB) in zip(RF, RA, RB)
@inbounds F[iF] = complex(A[iA], B[iB])
end
end
return F
end
function complex{T<:Real}(A::Real, B::AbstractArray{T})
F = similar(B, typeof(complex(A,zero(T))))
RF, RB = eachindex(F), eachindex(B)
if RF == RB
for i in RB
@inbounds F[i] = complex(A, B[i])
end
else
for (iF, iB) in zip(RF, RB)
@inbounds F[iF] = complex(A, B[iB])
end
end
return F
end
function complex{T<:Real}(A::AbstractArray{T}, B::Real)
F = similar(A, typeof(complex(zero(T),B)))
RF, RA = eachindex(F), eachindex(A)
if RF == RA
for i in RA
@inbounds F[i] = complex(A[i], B)
end
else
for (iF, iA) in zip(RF, RA)
@inbounds F[iF] = complex(A[iA], B)
end
end
return F
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
Main.Core.eval(Main.Core, :(baremodule Inference
using Core.Intrinsics
import Core: print, println, show, write, unsafe_write, STDOUT, STDERR
ccall(:jl_set_istopmod, Void, (Bool,), false)
eval(x) = Core.eval(Inference,x)
eval(m,x) = Core.eval(m,x)
include = Core.include
## Load essential files and libraries
include("ctypes.jl")
include("essentials.jl")
include("generator.jl")
include("reflection.jl")
include("options.jl")
# core operations & types
include("promotion.jl")
include("tuple.jl")
include("range.jl")
include("expr.jl")
include("error.jl")
# core numeric operations & types
include("bool.jl")
include("number.jl")
include("int.jl")
include("operators.jl")
include("pointer.jl")
const checked_add = +
const checked_sub = -
if !isdefined(Main, :Base)
# conditional to allow redefining Core.Inference after base exists
(::Type{T}){T}(arg) = convert(T, arg)::T
end
# Symbol constructors
Symbol(s::String) = Symbol(s.data)
Symbol(a::Array{UInt8,1}) =
ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int32), a, length(a))
# core array operations
include("array.jl")
include("abstractarray.jl")
include("hashing.jl")
include("nofloat_hashing.jl")
# map-reduce operators
macro simd(forloop)
esc(forloop)
end
include("reduce.jl")
## core structures
include("intset.jl")
include("associative.jl")
# core docsystem
include("docs/core.jl")
# compiler
include("inference.jl")
ccall(:jl_set_typeinf_func, Void, (Any,), typeinf_ext)
end # baremodule Inference
))
# This file is a part of Julia. License is MIT: http://julialang.org/license
show(x) = show(STDOUT::IO, x)
print(xs...) = print(STDOUT::IO, xs...)
println(xs...) = println(STDOUT::IO, xs...)
println(io::IO) = print(io, '\n')
immutable DevNullStream <: IO end
const DevNull = DevNullStream()
isreadable(::DevNullStream) = false
iswritable(::DevNullStream) = true
isopen(::DevNullStream) = true
read(::DevNullStream, ::Type{UInt8}) = throw(EOFError())
write(::DevNullStream, ::UInt8) = 1
close(::DevNullStream) = nothing
flush(::DevNullStream) = nothing
wait_connected(::DevNullStream) = nothing
wait_readnb(::DevNullStream) = wait()
wait_readbyte(::DevNullStream) = wait()
wait_close(::DevNullStream) = wait()
eof(::DevNullStream) = true
let CoreIO = Union{Core.CoreSTDOUT, Core.CoreSTDERR}
global write, unsafe_write
write(io::CoreIO, x::UInt8) = Core.write(io, x)
unsafe_write(io::CoreIO, x::Ptr{UInt8}, nb::UInt) = Core.unsafe_write(io, x, nb)
end
STDIN = DevNull
STDOUT = Core.STDOUT
STDERR = Core.STDERR
# This file is a part of Julia. License is MIT: http://julialang.org/license
# essential type definitions for interacting with C code
# (platform- or OS-dependent types are defined in c.jl)
"""
Cuchar
Equivalent to the native `unsigned char` c-type (`UInt8`).
"""
typealias Cuchar UInt8
"""
Cshort
Equivalent to the native `signed short` c-type (`Int16`).
"""
typealias Cshort Int16
"""
Cushort
Equivalent to the native `unsigned short` c-type (`UInt16`).
"""
typealias Cushort UInt16
"""
Cint
Equivalent to the native `signed int` c-type (`Int32`).
"""
typealias Cint Int32
"""
Cuint
Equivalent to the native `unsigned int` c-type (`UInt32`).
"""
typealias Cuint UInt32
"""
Cptrdiff_t
Equivalent to the native `ptrdiff_t` c-type (`Int`).
"""
typealias Cptrdiff_t Int
"""
Csize_t
Equivalent to the native `size_t` c-type (`UInt`).
"""
typealias Csize_t UInt
"""
Cssize_t
Equivalent to the native `ssize_t` c-type.
"""
typealias Cssize_t Int
"""
Cintmax_t
Equivalent to the native `intmax_t` c-type (`Int64`).
"""
typealias Cintmax_t Int64
"""
Cuintmax_t
Equivalent to the native `uintmax_t` c-type (`UInt64`).
"""
typealias Cuintmax_t UInt64
"""
Clonglong
Equivalent to the native `signed long long` c-type (`Int64`).
"""
typealias Clonglong Int64
"""
Culonglong
Equivalent to the native `unsigned long long` c-type (`UInt64`).
"""
typealias Culonglong UInt64
"""
Cfloat
Equivalent to the native `float` c-type (`Float32`).
"""
typealias Cfloat Float32
"""
Cdouble
Equivalent to the native `double` c-type (`Float64`).
"""
typealias Cdouble Float64
# This file is a part of Julia. License is MIT: http://julialang.org/license
module dSFMT
import Base: copy, copy!, ==
export DSFMT_state, dsfmt_get_min_array_size, dsfmt_get_idstring,
dsfmt_init_gen_rand, dsfmt_init_by_array, dsfmt_gv_init_by_array,
dsfmt_fill_array_close_open!, dsfmt_fill_array_close1_open2!,
win32_SystemFunction036!
"Mersenne Exponent"
const MEXP = 19937
"DSFMT internal state array size of N 128-bit integers."
const N = floor(Int, ((MEXP - 128) / 104 + 1))
"""Julia DSFMT state representation size counted in 32-bit integers.
Size: (DSFMT state array of Int128 + 1)*4 + Int32 index + Int32 padding
"""
const JN32 = (N+1)*4+1+1
"Jump polynomial for 10^20 steps for dSFMT with exponent 19937"
const JPOLY1e21 = "e172e20c5d2de26b567c0cace9e7c6cc4407bd5ffcd22ca59d37b73d54fdbd937cd3abc6f502e8c186dbd4f1a06b9e2b894f31be77424f94dddfd5a45888a84ca66eeeb242eefe6764ed859dafccae7a6a635b3a63fe9dfbbd5f2d3f2610d39388f53060e84edae75be4f4f2272c0f1f26d1231836ad040ab091550f8a3a5423fb3ab83e068fe2684057f15691c4dc757a3aee4bca8595bf1ad03500d9620a5dbe3b2d64380694895d2f379ca928238293ea267ce14236d5be816a61f018fe4f6bc3c9865f5d4d4186e320ab653d1f3c035ae83e2ad725648a67d3480331e763a1dcdfb5711b56796170b124f5febd723a664a2deefbfa9999d922a108b0e683582ae8d3baacb5bb56683405ea9e6e0d71ddb24b2229c72bb9d07061f2d1fa097ade823b607a2029d6e121ae09d93de01a154199e8e6a6e77c970bda72ba8079b2b3a15dd494a3188b1d94a25ae108a8a5bd0b050e6ce64a365a21420e07fdeebecae02eb68a4304b59283055d22c27d680ea35952834d828c9b9b9dd1a886b4f7fe82fe8f2a962e1e5390e563dc281c799aee2a441b7a813facb6ff5e94c059710dcfe7e6b1635e21ae0dc878dd5f7cc0e1101a74452495a67d23a2672c939f32c81d4a2611073990e92a084cc3a62fd42ee566f29d963a9cc5100ccd0a200f49ce0a74fa891efa1b974d342b7fedf9269e40d9b34e3c59c3d37201aecd5a04f4ae3d0c9a68c7ab78c662390e4cf36cb63ea3539c442efd0bf4aace4b8c8bde93c3d84b4d6290adfae1c5e3fcd457b6f3159e501f17b72ff6bc13d6bf61fbdafabefd16ac1dae0bca667e4e16a2b800732f1d0a9274c8a4c6cccd2db62fc275dc308c31c11cd6fda78de2f81f0e542b76b42b2cc09ed8f965d94c714c9918064f53af5379cfbbc31edf9cbce694f63a75f122048de6e57b094908f749661456813a908027f5d8397ab7962bf75ac779a3e1b7ae3fbc93397a67b486bb849befff1de6162ef2819715a88f41881e366ace692a900796a2806393898dd1750ac2b4ca3d34ca48942322fb6375f0c9a00c9701048ee8d7d7a17e11739177a7ad5027556e85835daf8594d84a97fe6621c0fce1495ae6ab8676cdc992d247acf5a4e5ec8c4755fde28117228d2c3ecf89edb91e93d949e2174924572265e36d176d082ed1be884e51d885ba3cda175c51edcee5042eaf519d292aa05aa4185b03858d710a9d0880b3d4e5111f858a52fe352cbe0a24f06a3d977ae2eb85e2a03a68131d0ab91dac4941067cf90ecd0fce156bcd40b8968cd4aa11e0b4353b14508d79d13ac00af4a4d452496b7f2393699889aa1e508427dbf0be3db91d955feb51e559af57640c6b3f9d5f95609852c28f9462a9869dd93acbdb1aafb2381ebb886a0b3fcec278f8bb0f62c23e157e49b89245b0881268ce594acbddd3605b9eaa77c9ff513e0dbad514914136d96fe2843fe2b4e886a0b718a9b8d1132132110618d0d3595da284cd2a4c9d09386199e4f4d7723983d3a374b51cf20dac5cabb4ff7e7197c2ebd9318463409baa583d6a6115c1b768282ff37b0fe152c97671e400d5ccba7d6875df0bf95c5d91257fedb124de393f31908d0e36251326aa29dd5be86291c80b4bf78f419ec151eeaeff643a58b48ab35ad2cd2c0b77b1965966ef3db6b6373cb2c4b590cef2f16f4d6f62f13a6cbf1a481565b5935edd4e76f7b6a8fd0d74bc336b40a803aec38125c006c877dfdcdb9ba2b7aecab5cafe6076e024c73e3567adf97f607a71d180402c22a20a8388f517484cc4198f97c2fe4f3407e0dc577e61f0f71354aa601cf4e3e42e1edd8722d50f5af3441f68caa568cc1c3a19956c1233f265bb47236afab24ee42b27b0042b90693d77c1923147360ae6503f6ba6abbc9dd52a7b4c36a3b6b55f6a80cfa7f101dd9f1bfc7d7eaf09a5d636b510228f245bfb37b4625025d2c911435cdf6f878113753e0804ab8ecab870ad733b9728d7636b17578b41239393e7de47cbce871137d2b61729dda67b2b84cd3363aad64c5dd5bd172f1f091305b1ff78982abe7dab1588036d097cf497e300e6c78a926048febd1b9462c07f5868928357b74297c87f503056b89f786d22a538b6702e290bca04639a0f1d0939b67f409e5e58e472a6a07fa543e2531c2567ec73c41f6769b6ba94c5aa0a030d006f5b6b1c5fb218b86a8f63a48bc867466f20f699859e87956f48a182d26ed451861dd21201ecc7239037ada67319bdf0849c387c73a110af798b4c5f9018bc97993e060ea2a2937fa2eb095d65ec07009fc407a350f1d6fb3c98a0a5f204be985b0cb6962f0eb7844a179c4598a92ea32d2d706c800034d2e960ded5b476d77073316b933fb3e6ba2f4f24a3b73a1e4d8ed1491d757ecf56fd72465dac0000736744d28d29073091587c8bccad302f7054e8a32bb8724974d9f3e449fc70b2a41f0008b548f717ac0a2c3a6580bfb50774933a578ad6acdcb89940bb406ea540893f097d8a88d1609ed605f25499de939083a0c8a7c6db462df5dfa06c298dd233e249433a54267d5cdc22e5524705b7d6b16b96bb2cb83e00cef62e21d91528a74cf95bfd1d391590c93f4058e9bb02656fd087a5b63d738d1c3b5cf533fd59c81cf9136bfcd3e955c19daf9906ef175791fde6a1d98155d7881e241c3522551cf9fcae42e1e46929ea39fd00943446823f9755085ccc8456a3090b73a3031a201d9c704a4ad4868dd9b6d06205560013973f60d637de2f18354bf4523d9d81dc2a7e78cd42c586364bbe0ed86fde0f081f801c1a4abb830839b7796d9a01f141bec8bd93144104c6dc59170162c0a5a639eb63a0a164970de50eb2e04f027394b26ed48d341f7851994df79d7cd663672a556f25e5e16a3adbe1003d631de938fabfed234df12b5ff3027f4a2da823834cb098e0f977a4eb9614579d5c7a1d400a1a933a657aef8ea1a66743d73b0cf37a7d64e9a63e4c7b09945f0db750b311b39783fb5ea216616751967d480a630d3da7c89d1c7beae20369137e96734a4cfedca56a7887f076fe4fe97534ad3e4f74d1a81750581a5ea214b440c7f30331ab86c257534c71175d1e731303a48b01c589fda4fb0d4368b4dd63d91204cb6fc389b2202aa94391907bfb72902a4031f5589ed5f391c2ce92aa998c200ba3c77d8bd747b9d0a29fa85cda3949a6d2bd0c3402e68f98fd451aa27b6c2dfd170e004577cbdb25e3a1b9852e9f66a370789c47bfce722446dade1b32ceae71ee0e1d96edf7ed08a93e3690056f46c3d8e63f88e53673ee71d72cfedbeba493ee91333120e09e9ce9f9c9a7a400f814ea618b1de48f9805e092f4e20f301fbb65caa83735a2a5c89befe4bce4116dca3688e1e14c6f09a945671dedbb5c0ba526842b6cae31d8b5ff978bae928a17a75c134630dd9de988f6ad3d89a071b33775a9660a40b48ec61ad3f93ac81cb1c65d8b0bab5c214786abd13cc10a8ea2e2a370e86e2fa1a372d83c9697b5e37b281e51507685f714fdaebe49ffc93a5582e1936eaee8e4140a4b72"
type DSFMT_state
val::Vector{Int32}
DSFMT_state(val::Vector{Int32} = zeros(Int32, JN32)) =
new(length(val) == JN32 ? val : throw(DomainError()))
end
copy!(dst::DSFMT_state, src::DSFMT_state) = (copy!(dst.val, src.val); dst)
copy(src::DSFMT_state) = DSFMT_state(copy(src.val))
==(s1::DSFMT_state, s2::DSFMT_state) = s1.val == s2.val
function dsfmt_get_idstring()
idstring = ccall((:dsfmt_get_idstring,:libdSFMT),
Ptr{UInt8},
())
return unsafe_string(idstring)
end
function dsfmt_get_min_array_size()
min_array_size = ccall((:dsfmt_get_min_array_size,:libdSFMT),
Int32,
())
end
const dsfmt_min_array_size = dsfmt_get_min_array_size()
function dsfmt_init_gen_rand(s::DSFMT_state, seed::UInt32)
ccall((:dsfmt_init_gen_rand,:libdSFMT),
Void,
(Ptr{Void}, UInt32,),
s.val, seed)
end
function dsfmt_init_by_array(s::DSFMT_state, seed::Vector{UInt32})
ccall((:dsfmt_init_by_array,:libdSFMT),
Void,
(Ptr{Void}, Ptr{UInt32}, Int32),
s.val, seed, length(seed))
end
function dsfmt_gv_init_by_array(seed::Vector{UInt32})
ccall((:dsfmt_gv_init_by_array,:libdSFMT),
Void,
(Ptr{UInt32}, Int32),
seed, length(seed))
end
function dsfmt_fill_array_close1_open2!(s::DSFMT_state, A::Ptr{Float64}, n::Int)
@assert Csize_t(A) % 16 == 0 # the underlying C array must be 16-byte aligned
@assert dsfmt_min_array_size <= n && iseven(n)
ccall((:dsfmt_fill_array_close1_open2,:libdSFMT),
Void,
(Ptr{Void}, Ptr{Float64}, Int),
s.val, A, n)
end
function dsfmt_fill_array_close_open!(s::DSFMT_state, A::Ptr{Float64}, n::Int)
@assert Csize_t(A) % 16 == 0 # the underlying C array must be 16-byte aligned
@assert dsfmt_min_array_size <= n && iseven(n)
ccall((:dsfmt_fill_array_close_open,:libdSFMT),
Void,
(Ptr{Void}, Ptr{Float64}, Int),
s.val, A, n)
end
# dSFMT jump
function dsfmt_jump(s::DSFMT_state, jp::AbstractString)
index = s.val[end-1]
work = zeros(UInt64, JN32>>1)
dsfmt = reinterpret(UInt64, copy(s.val))
dsfmt[end] = UInt64(N*2)
for c in jp
bits = parse(UInt8,c,16)
for j in 1:4
(bits & 0x01) != 0x00 && dsfmt_jump_add!(work, dsfmt)
bits = bits >> 0x01
dsfmt_jump_next_state!(dsfmt)
end
end
work[end] = index
return DSFMT_state(reinterpret(Int32, work))
end
function dsfmt_jump_add!(dest::Vector{UInt64}, src::Vector{UInt64})
dp = dest[end] >> 1
sp = src[end] >> 1
diff = ((sp - dp + N) % N)
i = 1
while i <= N-diff
j = i*2-1
p = j + diff*2
dest[j] $= src[p]
dest[j+1] $= src[p+1]
i += 1
end
while i <= N
j = i*2-1
p = j + (diff - N)*2
dest[j] $= src[p]
dest[j+1] $= src[p+1]
i += 1
end
dest[N*2+1] $= src[N*2+1]
dest[N*2+2] $= src[N*2+2]
return dest
end
function dsfmt_jump_next_state!(mts::Vector{UInt64})
POS1 = 117
SL1 = 19
SR = 12
MSK1 = 0x000ffafffffffb3f
MSK2 = 0x000ffdfffc90fffd
idx = (mts[end] >> 1) % N
a = idx*2+1
b = ((idx + POS1) % N)*2+1
u = N*2+1
t0 = mts[a]
t1 = mts[a+1]
L0 = mts[u]
L1 = mts[u+1]
mts[u] = (t0 << SL1) $ (L1 >> 32) $ (L1 << 32) $ mts[b]
mts[u+1] = (t1 << SL1) $ (L0 >> 32) $ (L0 << 32) $ mts[b+1]
mts[a] = (mts[u] >> SR) $ (mts[u] & MSK1) $ t0
mts[a+1] = (mts[u+1] >> SR) $ (mts[u+1] & MSK2) $ t1
mts[end] = (mts[end] + 2) % (N*2)
return mts
end
## Windows entropy
if is_windows()
function win32_SystemFunction036!{T}(a::Array{T})
ccall((:SystemFunction036, :Advapi32), stdcall, UInt8, (Ptr{Void}, UInt32), a, sizeof(a))
end
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
## file formats ##
module DataFmt
import Base: _default_delims, tryparse_internal, show
export countlines, readdlm, readcsv, writedlm, writecsv
invalid_dlm(::Type{Char}) = reinterpret(Char, 0xfffffffe)
invalid_dlm(::Type{UInt8}) = 0xfe
invalid_dlm(::Type{UInt16}) = 0xfffe
invalid_dlm(::Type{UInt32}) = 0xfffffffe
const offs_chunk_size = 5000
countlines(f::AbstractString, eol::Char='\n') = open(io->countlines(io,eol), f)::Int
function countlines(io::IO, eol::Char='\n')
isascii(eol) || throw(ArgumentError("only ASCII line terminators are supported"))
aeol = UInt8(eol)
a = Array{UInt8}(8192)
nl = 0
while !eof(io)
nb = readbytes!(io, a)
@simd for i=1:nb
@inbounds nl += a[i] == aeol
end
end
nl
end
"""
readdlm(source, T::Type; options...)
The columns are assumed to be separated by one or more whitespaces. The end of line
delimiter is taken as `\\n`.
"""
readdlm(input, T::Type; opts...) = readdlm(input, invalid_dlm(Char), T, '\n'; opts...)
"""
readdlm(source, delim::Char, T::Type; options...)
The end of line delimiter is taken as `\\n`.
"""
readdlm(input, dlm::Char, T::Type; opts...) = readdlm(input, dlm, T, '\n'; opts...)
"""
readdlm(source; options...)
The columns are assumed to be separated by one or more whitespaces. The end of line
delimiter is taken as `\\n`. If all data is numeric, the result will be a numeric array. If
some elements cannot be parsed as numbers, a heterogeneous array of numbers and strings
is returned.
"""
readdlm(input; opts...) = readdlm(input, invalid_dlm(Char), '\n'; opts...)
"""
readdlm(source, delim::Char; options...)
The end of line delimiter is taken as `\\n`. If all data is numeric, the result will be a
numeric array. If some elements cannot be parsed as numbers, a heterogeneous array of
numbers and strings is returned.
"""
readdlm(input, dlm::Char; opts...) = readdlm(input, dlm, '\n'; opts...)
"""
readdlm(source, delim::Char, eol::Char; options...)
If all data is numeric, the result will be a numeric array. If some elements cannot be
parsed as numbers, a heterogeneous array of numbers and strings is returned.
"""
readdlm(input, dlm::Char, eol::Char; opts...) =
readdlm_auto(input, dlm, Float64, eol, true; opts...)
"""
readdlm(source, delim::Char, T::Type, eol::Char; header=false, skipstart=0, skipblanks=true, use_mmap, quotes=true, dims, comments=true, comment_char='#')
Read a matrix from the source where each line (separated by `eol`) gives one row, with
elements separated by the given delimiter. The source can be a text file, stream or byte
array. Memory mapped files can be used by passing the byte array representation of the
mapped segment as source.
If `T` is a numeric type, the result is an array of that type, with any non-numeric elements
as `NaN` for floating-point types, or zero. Other useful values of `T` include
`String`, `AbstractString`, and `Any`.
If `header` is `true`, the first row of data will be read as header and the tuple
`(data_cells, header_cells)` is returned instead of only `data_cells`.
Specifying `skipstart` will ignore the corresponding number of initial lines from the input.
If `skipblanks` is `true`, blank lines in the input will be ignored.
If `use_mmap` is `true`, the file specified by `source` is memory mapped for potential
speedups. Default is `true` except on Windows. On Windows, you may want to specify `true` if
the file is large, and is only read once and not written to.
If `quotes` is `true`, columns enclosed within double-quote (\") characters are allowed to
contain new lines and column delimiters. Double-quote characters within a quoted field must
be escaped with another double-quote. Specifying `dims` as a tuple of the expected rows and
columns (including header, if any) may speed up reading of large files. If `comments` is
`true`, lines beginning with `comment_char` and text following `comment_char` in any line
are ignored.
"""
readdlm(input, dlm::Char, T::Type, eol::Char; opts...) =
readdlm_auto(input, dlm, T, eol, false; opts...)
readdlm_auto(input::Vector{UInt8}, dlm::Char, T::Type, eol::Char, auto::Bool; opts...) =
readdlm_string(String(input), dlm, T, eol, auto, val_opts(opts))
readdlm_auto(input::IO, dlm::Char, T::Type, eol::Char, auto::Bool; opts...) =
readdlm_string(readstring(input), dlm, T, eol, auto, val_opts(opts))
function readdlm_auto(input::AbstractString, dlm::Char, T::Type, eol::Char, auto::Bool; opts...)
optsd = val_opts(opts)
use_mmap = get(optsd, :use_mmap, is_windows() ? false : true)
fsz = filesize(input)
if use_mmap && fsz > 0 && fsz < typemax(Int)
a = Mmap.mmap(input, Vector{UInt8}, (Int(fsz),))
# TODO: It would be nicer to use String(a) without making a copy,
# but because the mmap'ed array is not NUL-terminated this causes
# jl_try_substrtod to segfault below.
return readdlm_string(String(copy(a)), dlm, T, eol, auto, optsd)
else
return readdlm_string(readstring(input), dlm, T, eol, auto, optsd)
end
end
#
# Handlers act on events generated by the parser.
# Parser calls store_cell on the handler to pass events.
#
# DLMOffsets: Keep offsets (when result dimensions are not known)
# DLMStore: Store values directly into a result store (when result dimensions are known)
abstract DLMHandler
type DLMOffsets <: DLMHandler
oarr::Vector{Vector{Int}}
offidx::Int
thresh::Int
bufflen::Int
function DLMOffsets(sbuff::String)
offsets = Array{Array{Int,1}}(1)
offsets[1] = Array{Int}(offs_chunk_size)
thresh = ceil(min(typemax(UInt), Base.Sys.total_memory()) / sizeof(Int) / 5)
new(offsets, 1, thresh, length(sbuff.data))
end
end
function store_cell(dlmoffsets::DLMOffsets, row::Int, col::Int,
quoted::Bool, startpos::Int, endpos::Int)
offidx = dlmoffsets.offidx
(offidx == 0) && return # offset collection stopped to avoid choking on memory
oarr = dlmoffsets.oarr
offsets = oarr[end]
if length(offsets) < offidx
offlen = offs_chunk_size * length(oarr)
if (offlen + offs_chunk_size) > dlmoffsets.thresh
est_tot = round(Int, offlen * dlmoffsets.bufflen / endpos)
if (est_tot - offlen) > offs_chunk_size # allow another chunk
# abandon offset collection
dlmoffsets.oarr = Vector{Int}[]
dlmoffsets.offidx = 0
return
end
end
offsets = Array{Int}(offs_chunk_size)
push!(oarr, offsets)
offidx = 1
end
offsets[offidx] = row
offsets[offidx+1] = col
offsets[offidx+2] = Int(quoted)
offsets[offidx+3] = startpos
offsets[offidx+4] = endpos
dlmoffsets.offidx = offidx + 5
nothing
end
function result(dlmoffsets::DLMOffsets)
trimsz = (dlmoffsets.offidx-1) % offs_chunk_size
((trimsz > 0) || (dlmoffsets.offidx == 1)) && resize!(dlmoffsets.oarr[end], trimsz)
dlmoffsets.oarr
end
type DLMStore{T} <: DLMHandler
hdr::Array{AbstractString, 2}
data::Array{T, 2}
nrows::Int
ncols::Int
lastrow::Int
lastcol::Int
hdr_offset::Int
sbuff::String
auto::Bool
eol::Char
end
function DLMStore{T}(::Type{T}, dims::NTuple{2,Integer},
has_header::Bool, sbuff::String, auto::Bool, eol::Char)
(nrows,ncols) = dims
nrows <= 0 && throw(ArgumentError("number of rows in dims must be > 0, got $nrows"))
ncols <= 0 && throw(ArgumentError("number of columns in dims must be > 0, got $ncols"))
hdr_offset = has_header ? 1 : 0
DLMStore{T}(fill(SubString(sbuff,1,0), 1, ncols), Array{T}(nrows-hdr_offset, ncols),
nrows, ncols, 0, 0, hdr_offset, sbuff, auto, eol)
end
_chrinstr(sbuff::String, chr::UInt8, startpos::Int, endpos::Int) =
(endpos >= startpos) && (C_NULL != ccall(:memchr, Ptr{UInt8},
(Ptr{UInt8}, Int32, Csize_t), pointer(sbuff.data)+startpos-1, chr, endpos-startpos+1))
function store_cell{T}(dlmstore::DLMStore{T}, row::Int, col::Int,
quoted::Bool, startpos::Int, endpos::Int)
drow = row - dlmstore.hdr_offset
ncols = dlmstore.ncols
lastcol = dlmstore.lastcol
lastrow = dlmstore.lastrow
cells::Array{T,2} = dlmstore.data
sbuff = dlmstore.sbuff
endpos = prevind(sbuff, nextind(sbuff,endpos))
if (endpos > 0) && ('\n' == dlmstore.eol) && ('\r' == Char(sbuff[endpos]))
endpos = prevind(sbuff, endpos)
end
if quoted
startpos += 1
endpos -= 1
end
if drow > 0
# fill missing elements
while ((drow - lastrow) > 1) || ((drow > lastrow > 0) && (lastcol < ncols))
if (lastcol == ncols) || (lastrow == 0)
lastcol = 0
lastrow += 1
end
for cidx in (lastcol+1):ncols
if (T <: AbstractString) || (T == Any)
cells[lastrow, cidx] = SubString(sbuff, 1, 0)
elseif ((T <: Number) || (T <: Char)) && dlmstore.auto
throw(TypeError(:store_cell, "", Any, T))
else
error("missing value at row $lastrow column $cidx")
end
end
lastcol = ncols
end
# fill data
if quoted && _chrinstr(sbuff, UInt8('"'), startpos, endpos)
unescaped = replace(SubString(sbuff, startpos, endpos), r"\"\"", "\"")
fail = colval(unescaped, 1, length(unescaped), cells, drow, col)
else
fail = colval(sbuff, startpos, endpos, cells, drow, col)
end
if fail
sval = SubString(sbuff, startpos, endpos)
if (T <: Number) && dlmstore.auto
throw(TypeError(:store_cell, "", Any, T))
else
error("file entry \"$(sval)\" cannot be converted to $T")
end
end
dlmstore.lastrow = drow
dlmstore.lastcol = col
else
# fill header
if quoted && _chrinstr(sbuff, UInt8('"'), startpos, endpos)
unescaped = replace(SubString(sbuff, startpos, endpos), r"\"\"", "\"")
colval(unescaped, 1, length(unescaped), dlmstore.hdr, 1, col)
else
colval(sbuff, startpos, endpos, dlmstore.hdr, 1, col)
end
end
nothing
end
function result{T}(dlmstore::DLMStore{T})
nrows = dlmstore.nrows - dlmstore.hdr_offset
ncols = dlmstore.ncols
lastcol = dlmstore.lastcol
lastrow = dlmstore.lastrow
cells = dlmstore.data
sbuff = dlmstore.sbuff
if (nrows > 0) && ((lastcol < ncols) || (lastrow < nrows))
while lastrow <= nrows
(lastcol == ncols) && (lastcol = 0; lastrow += 1)
for cidx in (lastcol+1):ncols
if (T <: AbstractString) || (T == Any)
cells[lastrow, cidx] = SubString(sbuff, 1, 0)
elseif ((T <: Number) || (T <: Char)) && dlmstore.auto
throw(TypeError(:store_cell, "", Any, T))
else
error("missing value at row $lastrow column $cidx")
end
end
lastcol = ncols
(lastrow == nrows) && break
end
dlmstore.lastrow = lastrow
dlmstore.lastcol = ncols
end
(dlmstore.hdr_offset > 0) ? (dlmstore.data, dlmstore.hdr) : dlmstore.data
end
function readdlm_string(sbuff::String, dlm::Char, T::Type, eol::Char, auto::Bool, optsd::Dict)
ign_empty = (dlm == invalid_dlm(Char))
quotes = get(optsd, :quotes, true)
comments = get(optsd, :comments, true)
comment_char = get(optsd, :comment_char, '#')
dims = get(optsd, :dims, nothing)
has_header = get(optsd, :header, get(optsd, :has_header, false))
haskey(optsd, :has_header) && (optsd[:has_header] != has_header) && throw(ArgumentError("conflicting values for header and has_header"))
skipstart = get(optsd, :skipstart, 0)
(skipstart >= 0) || throw(ArgumentError("skipstart must be ≥ 0, got $skipstart"))
skipblanks = get(optsd, :skipblanks, true)
offset_handler = (dims === nothing) ? DLMOffsets(sbuff) : DLMStore(T, dims, has_header, sbuff, auto, eol)
for retry in 1:2
try
dims = dlm_parse(sbuff, eol, dlm, '"', comment_char, ign_empty, quotes, comments, skipstart, skipblanks, offset_handler)
break
catch ex
if isa(ex, TypeError) && (ex.func == :store_cell)
T = ex.expected
else
rethrow(ex)
end
offset_handler = (dims === nothing) ? DLMOffsets(sbuff) : DLMStore(T, dims, has_header, sbuff, auto, eol)
end
end
isa(offset_handler, DLMStore) && (return result(offset_handler))
offsets = result(offset_handler)
!isempty(offsets) && (return dlm_fill(T, offsets, dims, has_header, sbuff, auto, eol))
optsd[:dims] = dims
return readdlm_string(sbuff, dlm, T, eol, auto, optsd)
end
const valid_opts = [:header, :has_header, :use_mmap, :quotes, :comments, :dims, :comment_char, :skipstart, :skipblanks]
const valid_opt_types = [Bool, Bool, Bool, Bool, Bool, NTuple{2,Integer}, Char, Integer, Bool]
const deprecated_opts = Dict(:has_header => :header)
function val_opts(opts)
d = Dict{Symbol,Union{Bool,NTuple{2,Integer},Char,Integer}}()
for (opt_name, opt_val) in opts
if opt_name == :ignore_invalid_chars
Base.depwarn("the ignore_invalid_chars option is no longer supported and will be ignored", :val_opts)
continue
end
in(opt_name, valid_opts) ||
throw(ArgumentError("unknown option $opt_name"))
opt_typ = valid_opt_types[findfirst(valid_opts, opt_name)]
isa(opt_val, opt_typ) ||
throw(ArgumentError("$opt_name should be of type $opt_typ, got $(typeof(opt_val))"))
d[opt_name] = opt_val
haskey(deprecated_opts, opt_name) &&
Base.depwarn("$opt_name is deprecated, use $(deprecated_opts[opt_name]) instead", :val_opts)
end
return d
end
function dlm_fill(T::DataType, offarr::Vector{Vector{Int}}, dims::NTuple{2,Integer}, has_header::Bool, sbuff::String, auto::Bool, eol::Char)
idx = 1
offidx = 1
offsets = offarr[1]
row = 0
col = 0
try
dh = DLMStore(T, dims, has_header, sbuff, auto, eol)
while idx <= length(offsets)
row = offsets[idx]
col = offsets[idx+1]
quoted = offsets[idx+2] != 0
startpos = offsets[idx+3]
endpos = offsets[idx+4]
((idx += 5) > offs_chunk_size) && (offidx < length(offarr)) && (idx = 1; offsets = offarr[offidx += 1])
store_cell(dh, row, col, quoted, startpos, endpos)
end
return result(dh)
catch ex
isa(ex, TypeError) && (ex.func == :store_cell) && (return dlm_fill(ex.expected, offarr, dims, has_header, sbuff, auto, eol))
error("at row $row, column $col : $ex")
end
end
function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{Bool,2}, row::Int, col::Int)
n = tryparse_internal(Bool, sbuff, startpos, endpos, 0, false)
isnull(n) || (cells[row, col] = get(n))
isnull(n)
end
function colval{T<:Integer}(sbuff::String, startpos::Int, endpos::Int, cells::Array{T,2}, row::Int, col::Int)
n = tryparse_internal(T, sbuff, startpos, endpos, 0, false)
isnull(n) || (cells[row, col] = get(n))
isnull(n)
end
function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{Float64,2}, row::Int, col::Int)
n = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8},Csize_t,Csize_t), sbuff, startpos-1, endpos-startpos+1)
isnull(n) || (cells[row, col] = get(n))
isnull(n)
end
function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{Float32,2}, row::Int, col::Int)
n = ccall(:jl_try_substrtof, Nullable{Float32}, (Ptr{UInt8}, Csize_t, Csize_t), sbuff, startpos-1, endpos-startpos+1)
isnull(n) || (cells[row, col] = get(n))
isnull(n)
end
function colval{T<:AbstractString}(sbuff::String, startpos::Int, endpos::Int, cells::Array{T,2}, row::Int, col::Int)
cells[row, col] = SubString(sbuff, startpos, endpos)
return false
end
function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{Any,2}, row::Int, col::Int)
# if array is of Any type, attempt parsing only the most common types: Int, Bool, Float64 and fallback to SubString
len = endpos-startpos+1
if len > 0
# check Inteter
ni64 = tryparse_internal(Int, sbuff, startpos, endpos, 0, false)
isnull(ni64) || (cells[row, col] = get(ni64); return false)
# check Bool
nb = tryparse_internal(Bool, sbuff, startpos, endpos, 0, false)
isnull(nb) || (cells[row, col] = get(nb); return false)
# check float64
nf64 = ccall(:jl_try_substrtod, Nullable{Float64}, (Ptr{UInt8}, Csize_t, Csize_t), sbuff, startpos-1, endpos-startpos+1)
isnull(nf64) || (cells[row, col] = get(nf64); return false)
end
cells[row, col] = SubString(sbuff, startpos, endpos)
false
end
function colval{T<:Char}(sbuff::String, startpos::Int, endpos::Int, cells::Array{T,2}, row::Int, col::Int)
if startpos == endpos
cells[row, col] = next(sbuff, startpos)[1]
return false
else
return true
end
end
colval(sbuff::String, startpos::Int, endpos::Int, cells::Array, row::Int, col::Int) = true
function dlm_parse{T,D}(dbuff::T, eol::D, dlm::D, qchar::D, cchar::D,
ign_adj_dlm::Bool, allow_quote::Bool, allow_comments::Bool,
skipstart::Int, skipblanks::Bool, dh::DLMHandler)
all_ascii = (D <: UInt8) || (isascii(eol) &&
isascii(dlm) &&
(!allow_quote || isascii(qchar)) &&
(!allow_comments || isascii(cchar)))
if T === String && all_ascii
return dlm_parse(dbuff.data, eol % UInt8, dlm % UInt8, qchar % UInt8, cchar % UInt8,
ign_adj_dlm, allow_quote, allow_comments, skipstart, skipblanks, dh)
end
ncols = nrows = col = 0
is_default_dlm = (dlm == invalid_dlm(D))
error_str = ""
# 0: begin field, 1: quoted field, 2: unquoted field,
# 3: second quote (could either be end of field or escape character),
# 4: comment, 5: skipstart
state = (skipstart > 0) ? 5 : 0
is_eol = is_dlm = is_cr = is_quote = is_comment = expct_col = false
idx = 1
try
slen = sizeof(dbuff)
col_start_idx = 1
was_cr = false
while idx <= slen
val,idx = next(dbuff, idx)
if (is_eol = (Char(val) == Char(eol)))
is_dlm = is_comment = is_cr = is_quote = false
elseif (is_dlm = (is_default_dlm ? in(Char(val), _default_delims) : (Char(val) == Char(dlm))))
is_comment = is_cr = is_quote = false
elseif (is_quote = (Char(val) == Char(qchar)))
is_comment = is_cr = false
elseif (is_comment = (Char(val) == Char(cchar)))
is_cr = false
else
is_cr = (Char(eol) == '\n') && (Char(val) == '\r')
end
if 2 == state # unquoted field
if is_dlm
state = 0
col += 1
store_cell(dh, nrows+1, col, false, col_start_idx, idx-2)
col_start_idx = idx
!ign_adj_dlm && (expct_col = true)
elseif is_eol
nrows += 1
col += 1
store_cell(dh, nrows, col, false, col_start_idx, idx - (was_cr ? 3 : 2))
col_start_idx = idx
ncols = max(ncols, col)
col = 0
state = 0
elseif (is_comment && allow_comments)
nrows += 1
col += 1
store_cell(dh, nrows, col, false, col_start_idx, idx - 2)
ncols = max(ncols, col)
col = 0
state = 4
end
elseif 1 == state # quoted field
is_quote && (state = 3)
elseif 4 == state # comment line
if is_eol
col_start_idx = idx
state = 0
end
elseif 0 == state # begin field
if is_quote
state = (allow_quote && !was_cr) ? 1 : 2
expct_col = false
elseif is_dlm
if !ign_adj_dlm
expct_col = true
col += 1
store_cell(dh, nrows+1, col, false, col_start_idx, idx-2)
end
col_start_idx = idx
elseif is_eol
if (col > 0) || !skipblanks
nrows += 1
if expct_col
col += 1
store_cell(dh, nrows, col, false, col_start_idx, idx - (was_cr ? 3 : 2))
end
ncols = max(ncols, col)
col = 0
end
col_start_idx = idx
expct_col = false
elseif is_comment && allow_comments
if col > 0
nrows += 1
if expct_col
col += 1
store_cell(dh, nrows, col, false, col_start_idx, idx - 2)
end
ncols = max(ncols, col)
col = 0
end
expct_col = false
state = 4
elseif !is_cr
state = 2
expct_col = false
end
elseif 3 == state # second quote
if is_quote && !was_cr
state = 1
elseif is_dlm && !was_cr
state = 0
col += 1
store_cell(dh, nrows+1, col, true, col_start_idx, idx-2)
col_start_idx = idx
!ign_adj_dlm && (expct_col = true)
elseif is_eol
nrows += 1
col += 1
store_cell(dh, nrows, col, true, col_start_idx, idx - (was_cr ? 3 : 2))
col_start_idx = idx
ncols = max(ncols, col)
col = 0
state = 0
elseif is_comment && allow_comments && !was_cr
nrows += 1
col += 1
store_cell(dh, nrows, col, true, col_start_idx, idx - 2)
ncols = max(ncols, col)
col = 0
state = 4
elseif (is_cr && was_cr) || !is_cr
error_str = escape_string("unexpected character '$(Char(val))' after quoted field at row $(nrows+1) column $(col+1)")
break
end
elseif 5 == state # skip start
if is_eol
col_start_idx = idx
skipstart -= 1
(0 == skipstart) && (state = 0)
end
end
was_cr = is_cr
end
if isempty(error_str)
if 1 == state # quoted field
error_str = "truncated column at row $(nrows+1) column $(col+1)"
elseif (2 == state) || (3 == state) || ((0 == state) && is_dlm) # unquoted field, second quote, or begin field with last character as delimiter
col += 1
nrows += 1
store_cell(dh, nrows, col, (3 == state), col_start_idx, idx-1)
ncols = max(ncols, col)
end
end
catch ex
if isa(ex, TypeError) && (ex.func == :store_cell)
rethrow(ex)
else
error("at row $(nrows+1), column $col : $ex)")
end
end
!isempty(error_str) && error(error_str)
return (nrows, ncols)
end
readcsv(io; opts...) = readdlm(io, ','; opts...)
readcsv(io, T::Type; opts...) = readdlm(io, ',', T; opts...)
# todo: keyword argument for # of digits to print
writedlm_cell(io::IO, elt::AbstractFloat, dlm, quotes) = print_shortest(io, elt)
function writedlm_cell{T}(io::IO, elt::AbstractString, dlm::T, quotes::Bool)
if quotes && !isempty(elt) && (('"' in elt) || ('\n' in elt) || ((T <: Char) ? (dlm in elt) : contains(elt, dlm)))
print(io, '"', replace(elt, r"\"", "\"\""), '"')
else
print(io, elt)
end
end
writedlm_cell(io::IO, elt, dlm, quotes) = print(io, elt)
function writedlm(io::IO, a::AbstractMatrix, dlm; opts...)
optsd = val_opts(opts)
quotes = get(optsd, :quotes, true)
pb = PipeBuffer()
lastc = last(indices(a, 2))
for i = indices(a, 1)
for j = indices(a, 2)
writedlm_cell(pb, a[i, j], dlm, quotes)
j == lastc ? write(pb,'\n') : print(pb,dlm)
end
(nb_available(pb) > (16*1024)) && write(io, takebuf_array(pb))
end
write(io, takebuf_array(pb))
nothing
end
writedlm{T}(io::IO, a::AbstractArray{T,0}, dlm; opts...) = writedlm(io, reshape(a,1), dlm; opts...)
# write an iterable row as dlm-separated items
function writedlm_row(io::IO, row, dlm, quotes)
state = start(row)
while !done(row, state)
(x, state) = next(row, state)
writedlm_cell(io, x, dlm, quotes)
done(row, state) ? write(io,'\n') : print(io,dlm)
end
end
# If the row is a single string, write it as a string rather than
# iterating over characters. Also, include the common case of
# a Number (handled correctly by the generic writedlm_row above)
# purely as an optimization.
function writedlm_row(io::IO, row::Union{Number,AbstractString}, dlm, quotes)
writedlm_cell(io, row, dlm, quotes)
write(io, '\n')
end
# write an iterable collection of iterable rows
function writedlm(io::IO, itr, dlm; opts...)
optsd = val_opts(opts)
quotes = get(optsd, :quotes, true)
pb = PipeBuffer()
for row in itr
writedlm_row(pb, row, dlm, quotes)
(nb_available(pb) > (16*1024)) && write(io, takebuf_array(pb))
end
write(io, takebuf_array(pb))
nothing
end
function writedlm(fname::AbstractString, a, dlm; opts...)
open(fname, "w") do io
writedlm(io, a, dlm; opts...)
end
end
"""
writedlm(f, A, delim='\\t'; opts)
Write `A` (a vector, matrix, or an iterable collection of iterable rows) as text to `f`
(either a filename string or an [`IO`](:class:`IO`) stream) using the given delimiter
`delim` (which defaults to tab, but can be any printable Julia object, typically a `Char` or
`AbstractString`).
For example, two vectors `x` and `y` of the same length can be written as two columns of
tab-delimited text to `f` by either `writedlm(f, [x y])` or by `writedlm(f, zip(x, y))`.
"""
writedlm(io, a; opts...) = writedlm(io, a, '\t'; opts...)
"""
writecsv(filename, A; opts)
Equivalent to [`writedlm`](:func:`writedlm`) with `delim` set to comma.
"""
writecsv(io, a; opts...) = writedlm(io, a, ','; opts...)
show(io::IO, ::MIME"text/csv", a) = writedlm(io, a, ',')
show(io::IO, ::MIME"text/tab-separated-values", a) = writedlm(io, a, '\t')
end # module DataFmt
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Convert # of Rata Die days to proleptic Gregorian calendar y,m,d,w
# Reference: http://mysite.verizon.net/aesir_research/date/date0.htm
function yearmonthday(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
d = c - div(153m-457,5); return m > 12 ? (y+1,m-12,d) : (y,m,d)
end
function year(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
return m > 12 ? y+1 : y
end
function yearmonth(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
return m > 12 ? (y+1,m-12) : (y,m)
end
function month(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
return m > 12 ? m-12 : m
end
function monthday(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
d = c - div(153m-457,5); return m > 12 ? (m-12,d) : (m,d)
end
function day(days)
z = days + 306; h = 100z - 25; a = fld(h,3652425); b = a - fld(a,4)
y = fld(100b+h,36525); c = b + z - 365y - fld(y,4); m = div(5c+456,153)
return c - div(153m-457,5)
end
# https://en.wikipedia.org/wiki/Talk:ISO_week_date#Algorithms
function week(days)
w = div(abs(days-1),7) % 20871
c,w = divrem((w + (w >= 10435)),5218)
w = (w*28+[15,23,3,11][c+1]) % 1461
return div(w,28) + 1
end
# Accessor functions
value(dt::TimeType) = dt.instant.periods.value
days(dt::Date) = value(dt)
days(dt::DateTime) = fld(value(dt),86400000)
year(dt::TimeType) = year(days(dt))
month(dt::TimeType) = month(days(dt))
week(dt::TimeType) = week(days(dt))
day(dt::TimeType) = day(days(dt))
hour(dt::DateTime) = mod(fld(value(dt),3600000),24)
minute(dt::DateTime) = mod(fld(value(dt),60000),60)
second(dt::DateTime) = mod(fld(value(dt),1000),60)
millisecond(dt::DateTime) = mod(value(dt),1000)
dayofmonth(dt::TimeType) = day(dt)
yearmonth(dt::TimeType) = yearmonth(days(dt))
monthday(dt::TimeType) = monthday(days(dt))
yearmonthday(dt::TimeType) = yearmonthday(days(dt))
# Documentation for exported accessors
for func in (:year, :month)
name = string(func)
@eval begin
@doc """
$($name)(dt::TimeType) -> Int64
The $($name) of a `Date` or `DateTime` as an `Int64`.
""" $func(dt::TimeType)
end
end
"""
week(dt::TimeType) -> Int64
Return the [ISO week date](https://en.wikipedia.org/wiki/ISO_week_date) of a `Date` or
`DateTime` as an `Int64`. Note that the first week of a year is the week that contains the
first Thursday of the year which can result in dates prior to January 4th being in the last
week of the previous year. For example `week(Date(2005,1,1))` is the 53rd week of 2004.
"""
week(dt::TimeType)
for func in (:day, :dayofmonth)
name = string(func)
@eval begin
@doc """
$($name)(dt::TimeType) -> Int64
The day of month of a `Date` or `DateTime` as an `Int64`.
""" $func(dt::TimeType)
end
end
"""
hour(dt::DateTime) -> Int64
The hour of day of a `DateTime` as an `Int64`.
"""
hour(dt::DateTime)
for func in (:minute, :second, :millisecond)
name = string(func)
@eval begin
@doc """
$($name)(dt::DateTime) -> Int64
The $($name) of a `DateTime` as an `Int64`.
""" $func(dt::DateTime)
end
end
for parts in (["year", "month"], ["month", "day"], ["year", "month", "day"])
name = join(parts)
func = Symbol(name)
@eval begin
@doc """
$($name)(dt::TimeType) -> ($(join(repeated(Int64, length($parts)), ", ")))
Simultaneously return the $(join($parts, ", ", " and ")) parts of a `Date` or
`DateTime`.
""" $func(dt::TimeType)
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
### truncation
Base.trunc(dt::Date, p::Type{Year}) = Date(UTD(totaldays(year(dt), 1, 1)))
Base.trunc(dt::Date, p::Type{Month}) = firstdayofmonth(dt)
Base.trunc(dt::Date, p::Type{Day}) = dt
Base.trunc(dt::DateTime, p::Type{Year}) = DateTime(trunc(Date(dt), Year))
Base.trunc(dt::DateTime, p::Type{Month}) = DateTime(trunc(Date(dt), Month))
Base.trunc(dt::DateTime, p::Type{Day}) = DateTime(Date(dt))
Base.trunc(dt::DateTime, p::Type{Hour}) = dt - Minute(dt) - Second(dt) - Millisecond(dt)
Base.trunc(dt::DateTime, p::Type{Minute}) = dt - Second(dt) - Millisecond(dt)
Base.trunc(dt::DateTime, p::Type{Second}) = dt - Millisecond(dt)
Base.trunc(dt::DateTime, p::Type{Millisecond}) = dt
"""
trunc(dt::TimeType, ::Type{Period}) -> TimeType
Truncates the value of `dt` according to the provided `Period` type. E.g. if `dt` is
`1996-01-01T12:30:00`, then `trunc(dt,Day) == 1996-01-01T00:00:00`.
"""
Dates.trunc(::Dates.TimeType, ::Type{Dates.Period})
# Adjusters
"""
firstdayofweek(dt::TimeType) -> TimeType
Adjusts `dt` to the Monday of its week.
"""
function firstdayofweek end
firstdayofweek(dt::Date) = Date(UTD(value(dt) - dayofweek(dt) + 1))
firstdayofweek(dt::DateTime) = DateTime(firstdayofweek(Date(dt)))
"""
lastdayofweek(dt::TimeType) -> TimeType
Adjusts `dt` to the Sunday of its week.
"""
function lastdayofweek end
lastdayofweek(dt::Date) = Date(UTD(value(dt) + (7 - dayofweek(dt))))
lastdayofweek(dt::DateTime) = DateTime(lastdayofweek(Date(dt)))
"""
firstdayofmonth(dt::TimeType) -> TimeType
Adjusts `dt` to the first day of its month.
"""
function firstdayofmonth end
firstdayofmonth(dt::Date) = Date(UTD(value(dt) - day(dt) + 1))
firstdayofmonth(dt::DateTime) = DateTime(firstdayofmonth(Date(dt)))
"""
lastdayofmonth(dt::TimeType) -> TimeType
Adjusts `dt` to the last day of its month.
"""
function lastdayofmonth end
function lastdayofmonth(dt::Date)
y, m, d = yearmonthday(dt)
return Date(UTD(value(dt) + daysinmonth(y, m) - d))
end
lastdayofmonth(dt::DateTime) = DateTime(lastdayofmonth(Date(dt)))
"""
firstdayofyear(dt::TimeType) -> TimeType
Adjusts `dt` to the first day of its year.
"""
function firstdayofyear end
firstdayofyear(dt::Date) = Date(UTD(value(dt) - dayofyear(dt) + 1))
firstdayofyear(dt::DateTime) = DateTime(firstdayofyear(Date(dt)))
"""
lastdayofyear(dt::TimeType) -> TimeType
Adjusts `dt` to the last day of its year.
"""
function lastdayofyear end
function lastdayofyear(dt::Date)
y, m, d = yearmonthday(dt)
return Date(UTD(value(dt) + daysinyear(y) - dayofyear(y, m, d)))
end
lastdayofyear(dt::DateTime) = DateTime(lastdayofyear(Date(dt)))
"""
firstdayofquarter(dt::TimeType) -> TimeType
Adjusts `dt` to the first day of its quarter.
"""
function firstdayofquarter end
function firstdayofquarter(dt::Date)
y,m = yearmonth(dt)
mm = m < 4 ? 1 : m < 7 ? 4 : m < 10 ? 7 : 10
return Date(y, mm, 1)
end
firstdayofquarter(dt::DateTime) = DateTime(firstdayofquarter(Date(dt)))
"""
lastdayofquarter(dt::TimeType) -> TimeType
Adjusts `dt` to the last day of its quarter.
"""
function lastdayofquarter end
function lastdayofquarter(dt::Date)
y,m = yearmonth(dt)
mm, d = m < 4 ? (3, 31) : m < 7 ? (6, 30) : m < 10 ? (9, 30) : (12, 31)
return Date(y, mm, d)
end
lastdayofquarter(dt::DateTime) = DateTime(lastdayofquarter(Date(dt)))
# Temporal Adjusters
immutable DateFunction
f::Function
# validate boolean, single-arg inner constructor
function DateFunction(f::ANY, negate::Bool, dt::TimeType)
isa(f(dt), Bool) || throw(ArgumentError("Provided function must take a single TimeType argument and return true or false"))
return new(negate ? x -> !f(x)::Bool : f)
end
end
Base.show(io::IO, df::DateFunction) = println(io, df.f)
# Core adjuster
function adjust(df::DateFunction, start, step, limit)
for i = 1:limit
df.f(start) && return start
start += step
end
throw(ArgumentError("Adjustment limit reached: $limit iterations"))
end
function adjust(func::Function, start; step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, start), start, step, limit)
end
# Constructors using DateFunctions
"""
Date(f::Function, y[, m, d]; step=Day(1), negate=false, limit=10000) -> Date
Create a `Date` through the adjuster API. The starting point will be constructed from the
provided `y, m, d` arguments, and will be adjusted until `f::Function` returns `true`. The
step size in adjusting can be provided manually through the `step` keyword. If
`negate=true`, then the adjusting will stop when `f::Function` returns `false` instead of
`true`. `limit` provides a limit to the max number of iterations the adjustment API will
pursue before throwing an error (given that `f::Function` is never satisfied).
"""
function Date(func::Function, y, m=1, d=1;step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, Date(y, m, d)), Date(y, m, d), step, limit)
end
"""
DateTime(f::Function, y[, m, d, h, mi, s]; step=Day(1), negate=false, limit=10000) -> DateTime
Create a `DateTime` through the adjuster API. The starting point will be constructed from
the provided `y, m, d...` arguments, and will be adjusted until `f::Function` returns
`true`. The step size in adjusting can be provided manually through the `step` keyword. If
`negate=true`, then the adjusting will stop when `f::Function` returns `false` instead of
`true`. `limit` provides a limit to the max number of iterations the adjustment API will
pursue before throwing an error (in the case that `f::Function` is never satisfied).
"""
DateTime(::Function, args...)
function DateTime(func::Function, y, m=1; step::Period=Day(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y, m)), DateTime(y, m), step, limit)
end
function DateTime(func::Function, y, m, d; step::Period=Hour(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d), step, limit)
end
function DateTime(func::Function, y, m, d, h; step::Period=Minute(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h), step, limit)
end
function DateTime(func::Function, y, m, d, h, mi; step::Period=Second(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h, mi), step, limit)
end
function DateTime(func::Function, y, m, d, h, mi, s; step::Period=Millisecond(1), negate::Bool=false, limit::Int=10000)
return adjust(DateFunction(func, negate, DateTime(y)), DateTime(y, m, d, h, mi, s), step, limit)
end
# Return the next TimeType that falls on dow
ISDAYOFWEEK = Dict(Mon => DateFunction(ismonday, false, Date(0)),
Tue => DateFunction(istuesday, false, Date(0)),
Wed => DateFunction(iswednesday, false, Date(0)),
Thu => DateFunction(isthursday, false, Date(0)),
Fri => DateFunction(isfriday, false, Date(0)),
Sat => DateFunction(issaturday, false, Date(0)),
Sun => DateFunction(issunday, false, Date(0)))
# "same" indicates whether the current date can be considered or not
"""
tonext(dt::TimeType,dow::Int;same::Bool=false) -> TimeType
Adjusts `dt` to the next day of week corresponding to `dow` with `1 = Monday, 2 = Tuesday,
etc`. Setting `same=true` allows the current `dt` to be considered as the next `dow`,
allowing for no adjustment to occur.
"""
tonext(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same ? dt : dt+Day(1), Day(1), 7)
# Return the next TimeType where func evals true using step in incrementing
"""
tonext(func::Function,dt::TimeType;step=Day(1),negate=false,limit=10000,same=false) -> TimeType
Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func`
returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same`
allows `dt` to be considered in satisfying `func`. `negate` will make the adjustment process
terminate when `func` returns `false` instead of `true`.
"""
function tonext(func::Function, dt::TimeType;step::Period=Day(1), negate::Bool=false, limit::Int=10000, same::Bool=false)
return adjust(DateFunction(func, negate, dt), same ? dt : dt+step, step, limit)
end
"""
toprev(dt::TimeType,dow::Int;same::Bool=false) -> TimeType
Adjusts `dt` to the previous day of week corresponding to `dow` with `1 = Monday, 2 =
Tuesday, etc`. Setting `same=true` allows the current `dt` to be considered as the previous
`dow`, allowing for no adjustment to occur.
"""
toprev(dt::TimeType, dow::Int; same::Bool=false) = adjust(ISDAYOFWEEK[dow], same ? dt : dt+Day(-1), Day(-1), 7)
"""
toprev(func::Function,dt::TimeType;step=Day(-1),negate=false,limit=10000,same=false) -> TimeType
Adjusts `dt` by iterating at most `limit` iterations by `step` increments until `func`
returns `true`. `func` must take a single `TimeType` argument and return a `Bool`. `same`
allows `dt` to be considered in satisfying `func`. `negate` will make the adjustment process
terminate when `func` returns `false` instead of `true`.
"""
function toprev(func::Function, dt::TimeType; step::Period=Day(-1), negate::Bool=false, limit::Int=10000, same::Bool=false)
return adjust(DateFunction(func, negate, dt), same ? dt : dt+step, step, limit)
end
# Return the first TimeType that falls on dow in the Month or Year
"""
tofirst(dt::TimeType,dow::Int;of=Month) -> TimeType
Adjusts `dt` to the first `dow` of its month. Alternatively, `of=Year` will adjust to the
first `dow` of the year.
"""
function tofirst(dt::TimeType, dow::Int; of::Union{Type{Year}, Type{Month}}=Month)
dt = of <: Month ? firstdayofmonth(dt) : firstdayofyear(dt)
return adjust(ISDAYOFWEEK[dow], dt, Day(1), 366)
end
# Return the last TimeType that falls on dow in the Month or Year
"""
tolast(dt::TimeType,dow::Int;of=Month) -> TimeType
Adjusts `dt` to the last `dow` of its month. Alternatively, `of=Year` will adjust to the
last `dow` of the year.
"""
function tolast(dt::TimeType, dow::Int; of::Union{Type{Year}, Type{Month}}=Month)
dt = of <: Month ? lastdayofmonth(dt) : lastdayofyear(dt)
return adjust(ISDAYOFWEEK[dow], dt, Day(-1), 366)
end
function recur{T<:TimeType}(fun::Function, start::T, stop::T; step::Period=Day(1), negate::Bool=false, limit::Int=10000)
((start != stop) & ((step > zero(step)) != (stop > start))) && return T[]
a = T[]
check = start <= stop ? 1 : -1
df = Dates.DateFunction(fun, negate, start)
while true
next = Dates.adjust(df, start, step, limit)
cmp(next, stop) == check && break
push!(a, next)
start = next + step
end
return a
end
"""
recur{T<:TimeType}(func::Function,dr::StepRange{T};negate=false,limit=10000) -> Vector{T}
`func` takes a single TimeType argument and returns a `Bool` indicating whether the input
should be "included" in the final set. `recur` applies `func` over each element in the range
of `dr`, including those elements for which `func` returns `true` in the resulting Array,
unless `negate=true`, then only elements where `func` returns `false` are included.
"""
function recur{T<:TimeType}(fun::Function, dr::StepRange{T};negate::Bool=false, limit::Int=10000)
return recur(fun, first(dr), last(dr); step=step(dr), negate=negate, limit=limit)
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Instant arithmetic
(+)(x::Instant) = x
(-){T<:Instant}(x::T,y::T) = x.periods - y.periods
# TimeType arithmetic
(+)(x::TimeType) = x
(-){T<:TimeType}(x::T,y::T) = x.instant - y.instant
# TimeType-Year arithmetic
function (+)(dt::DateTime,y::Year)
oy,m,d = yearmonthday(dt); ny = oy+value(y); ld = daysinmonth(ny,m)
return DateTime(ny,m,d <= ld ? d : ld,hour(dt),minute(dt),second(dt),millisecond(dt))
end
function (+)(dt::Date,y::Year)
oy,m,d = yearmonthday(dt); ny = oy+value(y); ld = daysinmonth(ny,m)
return Date(ny,m,d <= ld ? d : ld)
end
function (-)(dt::DateTime,y::Year)
oy,m,d = yearmonthday(dt); ny = oy-value(y); ld = daysinmonth(ny,m)
return DateTime(ny,m,d <= ld ? d : ld,hour(dt),minute(dt),second(dt),millisecond(dt))
end
function (-)(dt::Date,y::Year)
oy,m,d = yearmonthday(dt); ny = oy-value(y); ld = daysinmonth(ny,m)
return Date(ny,m,d <= ld ? d : ld)
end
# TimeType-Month arithmetic
# monthwrap adds two months with wraparound behavior (i.e. 12 + 1 == 1)
monthwrap(m1,m2) = (v = mod1(m1+m2,12); return v < 0 ? 12 + v : v)
# yearwrap takes a starting year/month and a month to add and returns
# the resulting year with wraparound behavior (i.e. 2000-12 + 1 == 2001)
yearwrap(y,m1,m2) = y + fld(m1 + m2 - 1,12)
function (+)(dt::DateTime,z::Month)
y,m,d = yearmonthday(dt)
ny = yearwrap(y,m,value(z))
mm = monthwrap(m,value(z)); ld = daysinmonth(ny,mm)
return DateTime(ny,mm,d <= ld ? d : ld,hour(dt),minute(dt),second(dt),millisecond(dt))
end
function (+)(dt::Date,z::Month)
y,m,d = yearmonthday(dt)
ny = yearwrap(y,m,value(z))
mm = monthwrap(m,value(z)); ld = daysinmonth(ny,mm)
return Date(ny,mm,d <= ld ? d : ld)
end
function (-)(dt::DateTime,z::Month)
y,m,d = yearmonthday(dt)
ny = yearwrap(y,m,-value(z))
mm = monthwrap(m,-value(z)); ld = daysinmonth(ny,mm)
return DateTime(ny,mm,d <= ld ? d : ld,hour(dt),minute(dt),second(dt),millisecond(dt))
end
function (-)(dt::Date,z::Month)
y,m,d = yearmonthday(dt)
ny = yearwrap(y,m,-value(z))
mm = monthwrap(m,-value(z)); ld = daysinmonth(ny,mm)
return Date(ny,mm,d <= ld ? d : ld)
end
(+)(x::Date,y::Week) = return Date(UTD(value(x) + 7*value(y)))
(-)(x::Date,y::Week) = return Date(UTD(value(x) - 7*value(y)))
(+)(x::Date,y::Day) = return Date(UTD(value(x) + value(y)))
(-)(x::Date,y::Day) = return Date(UTD(value(x) - value(y)))
(+)(x::DateTime,y::Period) = return DateTime(UTM(value(x)+toms(y)))
(-)(x::DateTime,y::Period) = return DateTime(UTM(value(x)-toms(y)))
(+)(y::Period,x::TimeType) = x + y
(-)(y::Period,x::TimeType) = x - y
for op in (:.+, :.-)
op_ = Symbol(string(op)[2:end])
@eval begin
# GeneralPeriod, AbstractArray{TimeType}
($op){T<:TimeType}(x::AbstractArray{T}, y::GeneralPeriod) =
reshape(T[($op_)(i,y) for i in x], size(x))
($op){T<:TimeType}(y::GeneralPeriod, x::AbstractArray{T}) = ($op)(x,y)
($op_){T<:TimeType}(x::AbstractArray{T}, y::GeneralPeriod) = ($op)(x,y)
($op_){T<:TimeType}(y::GeneralPeriod, x::AbstractArray{T}) = ($op)(x,y)
# TimeType, StridedArray{GeneralPeriod}
($op){T<:TimeType,P<:GeneralPeriod}(x::StridedArray{P}, y::T) =
reshape(T[($op_)(i,y) for i in x], size(x))
($op){P<:GeneralPeriod}(y::TimeType, x::StridedArray{P}) = ($op)(x,y)
($op_){T<:TimeType,P<:GeneralPeriod}(x::StridedArray{P}, y::T) = ($op)(x,y)
($op_){P<:GeneralPeriod}(y::TimeType, x::StridedArray{P}) = ($op)(x,y)
end
end
# TimeType, AbstractArray{TimeType}
(.-){T<:TimeType}(x::AbstractArray{T}, y::T) = reshape(Period[i - y for i in x], size(x))
(.-){T<:TimeType}(y::T, x::AbstractArray{T}) = -(x .- y)
(-){T<:TimeType}(x::AbstractArray{T}, y::T) = x .- y
(-){T<:TimeType}(y::T, x::AbstractArray{T}) = -(x .- y)
# AbstractArray{TimeType}, AbstractArray{TimeType}
(-){T<:TimeType}(x::OrdinalRange{T}, y::OrdinalRange{T}) = collect(x) - collect(y)
(-){T<:TimeType}(x::Range{T}, y::Range{T}) = collect(x) - collect(y)
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Conversion/Promotion
"""
Date(dt::DateTime) -> Date
Converts a `DateTime` to a `Date`. The hour, minute, second, and millisecond parts of
the `DateTime` are truncated, so only the year, month and day parts are used in
construction.
"""
Date(dt::TimeType) = convert(Date,dt)
"""
DateTime(dt::Date) -> DateTime
Converts a `Date` to a `DateTime`. The hour, minute, second, and millisecond parts of
the new `DateTime` are assumed to be zero.
"""
DateTime(dt::TimeType) = convert(DateTime,dt)
Base.convert(::Type{DateTime},dt::Date) = DateTime(UTM(value(dt)*86400000))
Base.convert(::Type{Date},dt::DateTime) = Date(UTD(days(dt)))
"""
convert{T<:Real}(::Type{T}, dt::DateTime) -> T
Converts a DateTime value `dt` to a number of type `T`. The returned value corresponds to the number of Rata Die milliseconds since epoch.
See `convert(DateTime, x::Real)` for inverse.
"""
Base.convert{R<:Real}(::Type{R},x::DateTime) = convert(R,value(x))
"""
convert{T<:Real}(::Type{T}, dt::Date) -> T
Converts a Date value `dt` to a number of type `T`. The returned value corresponds to the number of Rata Die days since epoch.
See `convert(Date, x::Real)` for inverse.
"""
Base.convert{R<:Real}(::Type{R},x::Date) = convert(R,value(x))
"""
convert{T<:Real}(::Type{DateTime}, x::T) -> DateTime
Converts a number of type `T` to a DateTime. `x` should be the number of Rata Die milliseconds since epoch.
See `convert(Int64,dt::DateTime)` for inverse.
"""
Base.convert{R<:Real}(::Type{DateTime}, x::R) = DateTime(UTM(x))
"""
convert{T<:Real}(::Type{Date}, x::T) -> Date
Converts a number of type `T` to a Date. `x` should be the number of Rata Die days since epoch.
See `convert(Int64,dt::Date)` for inverse.
"""
Base.convert{R<:Real}(::Type{Date}, x::R) = Date(UTD(x))
### External Conversions
const UNIXEPOCH = value(DateTime(1970)) #Rata Die milliseconds for 1970-01-01T00:00:00
"""
unix2datetime(x) -> DateTime
Takes the number of seconds since unix epoch `1970-01-01T00:00:00` and converts to the
corresponding `DateTime`.
"""
function unix2datetime(x)
rata = UNIXEPOCH + round(Int64, Int64(1000) * x)
return DateTime(UTM(rata))
end
"""
datetime2unix(dt::DateTime) -> Float64
Takes the given `DateTime` and returns the number of seconds
since the unix epoch `1970-01-01T00:00:00` as a `Float64`.
"""
datetime2unix(dt::DateTime) = (value(dt) - UNIXEPOCH)/1000.0
"""
now() -> DateTime
Returns a `DateTime` corresponding to the user's system time including the system timezone
locale.
"""
function now()
tv = Libc.TimeVal()
tm = Libc.TmStruct(tv.sec)
return DateTime(tm.year+1900,tm.month+1,tm.mday,tm.hour,tm.min,tm.sec,div(tv.usec,1000))
end
"""
today() -> Date
Returns the date portion of `now()`.
"""
today() = Date(now())
"""
now(::Type{UTC}) -> DateTime
Returns a `DateTime` corresponding to the user's system time as UTC/GMT.
"""
now(::Type{UTC}) = unix2datetime(time())
"""
rata2datetime(days) -> DateTime
Takes the number of Rata Die days since epoch `0000-12-31T00:00:00` and returns the
corresponding `DateTime`.
"""
rata2datetime(days) = DateTime(yearmonthday(days)...)
"""
datetime2rata(dt::TimeType) -> Int64
Returns the number of Rata Die days since epoch from the given `Date` or `DateTime`.
"""
datetime2rata(dt::TimeType) = days(dt)
# Julian conversions
const JULIANEPOCH = value(DateTime(-4713,11,24,12))
"""
julian2datetime(julian_days) -> DateTime
Takes the number of Julian calendar days since epoch `-4713-11-24T12:00:00` and returns the
corresponding `DateTime`.
"""
function julian2datetime(f)
rata = JULIANEPOCH + round(Int64, Int64(86400000) * f)
return DateTime(UTM(rata))
end
"""
datetime2julian(dt::DateTime) -> Float64
Takes the given `DateTime` and returns the number of Julian calendar days since the julian
epoch `-4713-11-24T12:00:00` as a `Float64`.
"""
datetime2julian(dt::DateTime) = (value(dt) - JULIANEPOCH)/86400000.0
# This file is a part of Julia. License is MIT: http://julialang.org/license
module Dates
importall ..Base.Operators
using Base.Iterators
include("types.jl")
include("periods.jl")
include("accessors.jl")
include("query.jl")
include("arithmetic.jl")
include("conversions.jl")
include("ranges.jl")
include("adjusters.jl")
include("rounding.jl")
include("io.jl")
export Period, DatePeriod, TimePeriod,
Year, Month, Week, Day, Hour, Minute, Second, Millisecond,
TimeZone, UTC, TimeType, DateTime, Date,
# accessors.jl
yearmonthday, yearmonth, monthday, year, month, week, day,
hour, minute, second, millisecond, dayofmonth,
# query.jl
dayofweek, isleapyear, daysinmonth, daysinyear, dayofyear, dayname, dayabbr,
dayofweekofmonth, daysofweekinmonth, monthname, monthabbr,
quarterofyear, dayofquarter,
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
Mon, Tue, Wed, Thu, Fri, Sat, Sun,
January, February, March, April, May, June,
July, August, September, October, November, December,
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec,
# conversions.jl
unix2datetime, datetime2unix, now, today,
rata2datetime, datetime2rata, julian2datetime, datetime2julian,
# adjusters.jl
firstdayofweek, lastdayofweek,
firstdayofmonth, lastdayofmonth,
firstdayofyear, lastdayofyear,
firstdayofquarter, lastdayofquarter,
adjust, tonext, toprev, tofirst, tolast, recur,
# io.jl
ISODateTimeFormat, ISODateFormat, DateFormat, RFC1123Format
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
# TODO: optimize this
function Base.string(dt::DateTime)
y,m,d = yearmonthday(days(dt))
h,mi,s = hour(dt),minute(dt),second(dt)
yy = y < 0 ? @sprintf("%05i",y) : lpad(y,4,"0")
mm = lpad(m,2,"0")
dd = lpad(d,2,"0")
hh = lpad(h,2,"0")
mii = lpad(mi,2,"0")
ss = lpad(s,2,"0")
ms = millisecond(dt) == 0 ? "" : string(millisecond(dt)/1000.0)[2:end]
return "$yy-$mm-$(dd)T$hh:$mii:$ss$(ms)"
end
Base.show(io::IO,x::DateTime) = print(io,string(x))
function Base.string(dt::Date)
y,m,d = yearmonthday(value(dt))
yy = y < 0 ? @sprintf("%05i",y) : lpad(y,4,"0")
mm = lpad(m,2,"0")
dd = lpad(d,2,"0")
return "$yy-$mm-$dd"
end
Base.show(io::IO,x::Date) = print(io,string(x))
### Parsing
const english = Dict{String,Int}("january"=>1,"february"=>2,"march"=>3,"april"=>4,
"may"=>5,"june"=>6,"july"=>7,"august"=>8,"september"=>9,
"october"=>10,"november"=>11,"december"=>12)
const abbrenglish = Dict{String,Int}("jan"=>1,"feb"=>2,"mar"=>3,"apr"=>4,
"may"=>5,"jun"=>6,"jul"=>7,"aug"=>8,"sep"=>9,
"oct"=>10,"nov"=>11,"dec"=>12)
const MONTHTOVALUE = Dict{String,Dict{String,Int}}("english"=>english)
const MONTHTOVALUEABBR = Dict{String,Dict{String,Int}}("english"=>abbrenglish)
# Date/DateTime Parsing
abstract Slot{T<:Any}
immutable DelimitedSlot{T<:Any} <: Slot{T}
parser::Type{T}
letter::Char
width::Int
transition::Union{Regex,AbstractString}
end
immutable FixedWidthSlot{T<:Any} <: Slot{T}
parser::Type{T}
letter::Char
width::Int
end
immutable DateFormat
slots::Array{Slot,1}
prefix::AbstractString # optional transition from the start of a string to the 1st slot
locale::AbstractString
end
abstract DayOfWeekSlot
# Slot rules translate letters into types. Note that
# list of rules can be extended.
immutable SlotRule
rules::Array{Type}
end
const SLOT_RULE = SlotRule(Array{Type}(256))
getindex(collection::SlotRule, key::Char) = collection.rules[Int(key)]
setindex!(collection::SlotRule, value::Type, key::Char) = collection.rules[Int(key)] = value
keys(c::SlotRule) = map(Char, filter(el -> isassigned(c.rules, el) && c.rules[el] != Void, eachindex(c.rules)))
SLOT_RULE['y'] = Year
SLOT_RULE['Y'] = Year
SLOT_RULE['m'] = Month
SLOT_RULE['u'] = Month
SLOT_RULE['U'] = Month
SLOT_RULE['e'] = DayOfWeekSlot
SLOT_RULE['E'] = DayOfWeekSlot
SLOT_RULE['d'] = Day
SLOT_RULE['H'] = Hour
SLOT_RULE['M'] = Minute
SLOT_RULE['S'] = Second
SLOT_RULE['s'] = Millisecond
duplicates(slots) = any(map(x->count(y->x.parser==y.parser,slots),slots) .> 1)
"""
DateFormat(format::AbstractString, locale::AbstractString="english") -> DateFormat
Construct a date formatting object that can be used for parsing date strings or
formatting a date object as a string. For details on the syntax for `format` see
[`DateTime(::AbstractString, ::AbstractString)`](:ref:`parsing <man-date-parsing>`) and
[`format`](:ref:`formatting <man-date-formatting>`).
"""
function DateFormat(f::AbstractString, locale::AbstractString="english")
slots = Slot[]
prefix = ""
params = ()
last_offset = 1
letters = join(keys(SLOT_RULE), "")
for m in eachmatch(Regex("(?<!\\\\)([\\Q$letters\\E])\\1*"), f)
letter = f[m.offset]
typ = SLOT_RULE[letter]
width = length(m.match)
tran = replace(f[last_offset:m.offset-1], r"\\(.)", s"\1")
if isempty(params)
prefix = tran
else
slot = tran == "" ? FixedWidthSlot(params...) : DelimitedSlot(params..., tran)
push!(slots,slot)
end
params = (typ,letter,width)
last_offset = m.offset + width
end
if !isempty(params)
if last_offset > endof(f)
slot = DelimitedSlot(params..., r"(?=\s|$)")
else
tran = replace(f[last_offset:end], r"\\(.)", s"\1")
if tran == ""
slot = FixedWidthSlot(params...)
else
slot = DelimitedSlot(params..., tran)
end
end
push!(slots,slot)
end
duplicates(slots) && throw(ArgumentError("Two separate periods of the same type detected"))
return DateFormat(slots,prefix,locale)
end
const SLOTERROR = ArgumentError("Non-digit character encountered")
slotparse(slot,x,locale) = !ismatch(r"[^0-9\s]",x) ? slot.parser(x) : throw(SLOTERROR)
function slotparse(slot::Slot{Month},x,locale)
if slot.letter == 'm'
ismatch(r"[^0-9\s]",x) ? throw(SLOTERROR) : return Month(x)
elseif slot.letter == 'u'
return Month(MONTHTOVALUEABBR[locale][lowercase(x)])
else
return Month(MONTHTOVALUE[locale][lowercase(x)])
end
end
slotparse(slot::Slot{Millisecond},x,locale) = !ismatch(r"[^0-9\s]",x) ? slot.parser(Base.parse(Float64,"."*x)*1000.0) : throw(SLOTERROR)
slotparse(slot::Slot{DayOfWeekSlot},x,locale) = nothing
function getslot(x,slot::DelimitedSlot,locale,cursor)
endind = first(search(x,slot.transition,nextind(x,cursor)))
if endind == 0 # we didn't find the next delimiter
s = x[cursor:end]
index = endof(x)+1
else
s = x[cursor:(endind-1)]
index = nextind(x,endind)
end
return index, slotparse(slot,s,locale)
end
getslot(x,slot,locale,cursor) = (cursor+slot.width, slotparse(slot,x[cursor:(cursor+slot.width-1)], locale))
function parse(x::AbstractString,df::DateFormat)
x = strip(x)
startswith(x, df.prefix) && (x = replace(x, df.prefix, "", 1))
isempty(x) && throw(ArgumentError("Cannot parse empty format string"))
if isa(df.slots[1], DelimitedSlot) && first(search(x,df.slots[1].transition)) == 0
throw(ArgumentError("Delimiter mismatch. Couldn't find first delimiter, \"$(df.slots[1].transition)\", in date string"))
end
periods = Period[]
extra = Any[] # Supports custom slot types such as TimeZone
cursor = 1
for slot in df.slots
cursor, pe = getslot(x,slot,df.locale,cursor)
pe !== nothing && (isa(pe,Period) ? push!(periods,pe) : push!(extra,pe))
cursor > endof(x) && break
end
sort!(periods,rev=true,lt=periodisless)
if isempty(extra)
return periods
else
return vcat(periods, extra)
end
end
slotformat(slot,dt,locale) = lpad(string(value(slot.parser(dt))),slot.width,"0")
function slotformat(slot::Slot{Year},dt,locale)
s = lpad(string(value(slot.parser(dt))),slot.width,"0")
if slot.letter == 'y'
return s[(end-slot.width+1):end] # Truncate the year
else # == 'Y'
return s
end
end
function slotformat(slot::Slot{Month},dt,locale)
if slot.letter == 'm'
return lpad(month(dt),slot.width,"0")
elseif slot.letter == 'u'
return VALUETOMONTHABBR[locale][month(dt)]
else
return VALUETOMONTH[locale][month(dt)]
end
end
function slotformat(slot::Slot{DayOfWeekSlot},dt,locale)
if slot.letter == 'e'
return VALUETODAYOFWEEKABBR[locale][dayofweek(dt)]
else # == 'E'
return VALUETODAYOFWEEK[locale][dayofweek(dt)]
end
end
slotformat(slot::Slot{Millisecond},dt,locale) = rpad(string(millisecond(dt)/1000.0)[3:end], slot.width, "0")
function format(dt::TimeType,df::DateFormat)
f = df.prefix
for slot in df.slots
f *= slotformat(slot,dt,df.locale)
if isa(slot, DelimitedSlot)
f *= isa(slot.transition, AbstractString) ? slot.transition : ""
end
end
return f
end
# UI
const ISODateTimeFormat = DateFormat("yyyy-mm-dd\\THH:MM:SS.s")
const ISODateFormat = DateFormat("yyyy-mm-dd")
const RFC1123Format = DateFormat("e, dd u yyyy HH:MM:SS")
"""
DateTime(dt::AbstractString, format::AbstractString; locale="english") -> DateTime
Construct a `DateTime` by parsing the `dt` date string following the pattern given in
the `format` string. The following character codes can be used to construct the `format`
string:
| Code | Matches | Comment |
|:-----------|:----------|:-------------------------------------------------------------|
| `y` | 1996, 96 | Returns year of 1996, 0096 |
| `Y` | 1996, 96 | Returns year of 1996, 0096. Equivalent to `y` |
| `m` | 1, 01 | Matches 1 or 2-digit months |
| `u` | Jan | Matches abbreviated months according to the `locale` keyword |
| `U` | January | Matches full month names according to the `locale` keyword |
| `d` | 1, 01 | Matches 1 or 2-digit days |
| `H` | 00 | Matches hours |
| `M` | 00 | Matches minutes |
| `S` | 00 | Matches seconds |
| `s` | .500 | Matches milliseconds |
| `e` | Mon, Tues | Matches abbreviated days of the week |
| `E` | Monday | Matches full name days of the week |
| `yyyymmdd` | 19960101 | Matches fixed-width year, month, and day |
Characters not listed above are normally treated as delimiters between date and time slots.
For example a `dt` string of "1996-01-15T00:00:00.0" would have a `format` string like
"y-m-dTH:M:S.s". If you need to use a code character as a delimiter you can escape it using
backslash. The date "1995y01m" would have the format "y\\ym\\m".
"""
DateTime(dt::AbstractString,format::AbstractString;locale::AbstractString="english") = DateTime(dt,DateFormat(format,locale))
"""
DateTime(dt::AbstractString, df::DateFormat) -> DateTime
Construct a `DateTime` by parsing the `dt` date string following the pattern given in
the [`DateFormat`](:func:`Dates.DateFormat`) object. Similar to
`DateTime(::AbstractString, ::AbstractString)` but more efficient when repeatedly parsing
similarly formatted date strings with a pre-created `DateFormat` object.
"""
DateTime(dt::AbstractString,df::DateFormat=ISODateTimeFormat) = DateTime(parse(dt,df)...)
"""
Date(dt::AbstractString, format::AbstractString; locale="english") -> Date
Construct a `Date` object by parsing a `dt` date string following the pattern given in the
`format` string. Follows the same conventions as
`DateTime(::AbstractString, ::AbstractString)`.
"""
Date(dt::AbstractString,format::AbstractString;locale::AbstractString="english") = Date(dt,DateFormat(format,locale))
"""
Date(dt::AbstractString, df::DateFormat) -> Date
Parse a date from a date string `dt` using a `DateFormat` object `df`.
"""
Date(dt::AbstractString,df::DateFormat=ISODateFormat) = Date(parse(dt,df)...)
"""
format(dt::TimeType, format::AbstractString; locale="english") -> AbstractString
Construct a string by using a `TimeType` object and applying the provided `format`. The
following character codes can be used to construct the `format` string:
| Code | Examples | Comment |
|:-----------|:----------|:-------------------------------------------------------------|
| `y` | 6 | Numeric year with a fixed width |
| `Y` | 1996 | Numeric year with a minimum width |
| `m` | 1, 12 | Numeric month with a minimum width |
| `u` | Jan | Month name shortened to 3-chars according to the `locale` |
| `U` | January | Full month name according to the `locale` keyword |
| `d` | 1, 31 | Day of the month with a minimum width |
| `H` | 0, 23 | Hour (24-hour clock) with a minimum width |
| `M` | 0, 59 | Minute with a minimum width |
| `S` | 0, 59 | Second with a minimum width |
| `s` | 000, 500 | Millisecond with a minimum width of 3 |
| `e` | Mon, Tue | Abbreviated days of the week |
| `E` | Monday | Full day of week name |
The number of sequential code characters indicate the width of the code. A format of
`yyyy-mm` specifies that the code `y` should have a width of four while `m` a width of two.
Codes that yield numeric digits have an associated mode: fixed-width or minimum-width.
The fixed-width mode left-pads the value with zeros when it is shorter than the specified
width and truncates the value when longer. Minimum-width mode works the same as fixed-width
except that it does not truncate values longer than the width.
When creating a `format` you can use any non-code characters as a separator. For example to
generate the string "1996-01-15T00:00:00" you could use `format`: "yyyy-mm-ddTHH:MM:SS".
Note that if you need to use a code character as a literal you can use the escape character
backslash. The string "1996y01m" can be produced with the format "yyyy\\ymm\\m".
"""
format(dt::TimeType,f::AbstractString;locale::AbstractString="english") = format(dt,DateFormat(f,locale))
# vectorized
DateTime{T<:AbstractString}(Y::AbstractArray{T},format::AbstractString;locale::AbstractString="english") = DateTime(Y,DateFormat(format,locale))
function DateTime{T<:AbstractString}(Y::AbstractArray{T},df::DateFormat=ISODateTimeFormat)
return reshape(DateTime[DateTime(parse(y,df)...) for y in Y], size(Y))
end
Date{T<:AbstractString}(Y::AbstractArray{T},format::AbstractString;locale::AbstractString="english") = Date(Y,DateFormat(format,locale))
function Date{T<:AbstractString}(Y::AbstractArray{T},df::DateFormat=ISODateFormat)
return reshape(Date[Date(parse(y,df)...) for y in Y], size(Y))
end
format{T<:TimeType}(Y::AbstractArray{T},format::AbstractString;locale::AbstractString="english") = Dates.format(Y,DateFormat(format,locale))
function format(Y::AbstractArray{Date},df::DateFormat=ISODateFormat)
return reshape([Dates.format(y,df) for y in Y], size(Y))
end
function format(Y::AbstractArray{DateTime},df::DateFormat=ISODateTimeFormat)
return reshape([Dates.format(y,df) for y in Y], size(Y))
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
#Period types
value(x::Period) = x.value
# The default constructors for Periods work well in almost all cases
# P(x) = new((convert(Int64,x))
# The following definitions are for Period-specific safety
for period in (:Year, :Month, :Week, :Day, :Hour, :Minute, :Second, :Millisecond)
period_str = string(period)
accessor_str = lowercase(period_str)
# Convenience method for show()
@eval _units(x::$period) = " " * $accessor_str * (abs(value(x)) == 1 ? "" : "s")
# periodisless
@eval periodisless(x::$period,y::$period) = value(x) < value(y)
# AbstractString parsing (mainly for IO code)
@eval $period(x::AbstractString) = $period(Base.parse(Int64,x))
# Period accessors
typ_str = period in (:Hour, :Minute, :Second, :Millisecond) ? "DateTime" : "TimeType"
description = typ_str == "TimeType" ? "`Date` or `DateTime`" : "`$typ_str`"
reference = period == :Week ? " For details see [`$accessor_str(::$typ_str)`](:func:`$accessor_str`)." : ""
@eval begin
@doc """
$($period_str)(dt::$($typ_str)) -> $($period_str)
The $($accessor_str) part of a $($description) as a `$($period_str)`.$($reference)
""" ->
$period(dt::$(Symbol(typ_str))) = $period($(Symbol(accessor_str))(dt))
@doc """
$($period_str)(v)
Construct a `$($period_str)` object with the given `v` value. Input must be
losslessly convertible to an `Int64`.
""" $period(v)
end
end
# Now we're safe to define Period-Number conversions
# Anything an Int64 can convert to, a Period can convert to
Base.convert{T<:Number}(::Type{T},x::Period) = convert(T,value(x))
Base.convert{T<:Period}(::Type{T},x::Real) = T(x)
#Print/show/traits
Base.string{P<:Period}(x::P) = string(value(x),_units(x))
Base.show(io::IO,x::Period) = print(io,string(x))
Base.zero{P<:Period}(::Union{Type{P},P}) = P(0)
Base.one{P<:Period}(::Union{Type{P},P}) = P(1)
Base.typemin{P<:Period}(::Type{P}) = P(typemin(Int64))
Base.typemax{P<:Period}(::Type{P}) = P(typemax(Int64))
# Default values (as used by TimeTypes)
"""
default(p::Period) -> Period
Returns a sensible "default" value for the input Period by returning `one(p)` for Year,
Month, and Day, and `zero(p)` for Hour, Minute, Second, and Millisecond.
"""
function default end
default{T<:DatePeriod}(p::Union{T,Type{T}}) = one(p)
default{T<:TimePeriod}(p::Union{T,Type{T}}) = zero(p)
(-){P<:Period}(x::P) = P(-value(x))
Base.isless{P<:Period}(x::P,y::P) = isless(value(x),value(y))
=={P<:Period}(x::P,y::P) = value(x) == value(y)
# Period Arithmetic, grouped by dimensionality:
import Base: div, fld, mod, rem, gcd, lcm, +, -, *, /, %, .+, .-, .*, .%
for op in (:+,:-,:lcm,:gcd)
@eval ($op){P<:Period}(x::P,y::P) = P(($op)(value(x),value(y)))
end
for op in (:/,:div,:fld)
@eval begin
($op){P<:Period}(x::P,y::P) = ($op)(value(x),value(y))
($op){P<:Period}(x::P,y::Real) = P(($op)(value(x),Int64(y)))
end
end
for op in (:rem,:mod)
@eval begin
($op){P<:Period}(x::P,y::P) = P(($op)(value(x),value(y)))
($op){P<:Period}(x::P,y::Real) = P(($op)(value(x),Int64(y)))
end
end
/{P<:Period}(X::StridedArray{P}, y::P) = X ./ y
%{P<:Period}(X::StridedArray{P}, y::P) = X .% y
*{P<:Period}(x::P,y::Real) = P(value(x) * Int64(y))
*(y::Real,x::Period) = x * y
.*{P<:Period}(y::Real, X::StridedArray{P}) = X .* y
for (op,Ty,Tz) in ((:.*,Real,:P),
(:./,:P,Float64), (:./,Real,:P),
(:div,:P,Int64), (:div,Integer,:P),
(:.%,:P,:P),
(:mod,:P,:P))
sop = string(op)
op_ = sop[1] == '.' ? Symbol(sop[2:end]) : op
@eval begin
function ($op){P<:Period}(X::StridedArray{P},y::$Ty)
Z = similar(X, $Tz)
for (Idst, Isrc) in zip(eachindex(Z), eachindex(X))
@inbounds Z[Idst] = ($op_)(X[Isrc],y)
end
return Z
end
end
end
# intfuncs
Base.gcdx{T<:Period}(a::T,b::T) = ((g,x,y)=gcdx(value(a),value(b)); return T(g),x,y)
Base.abs{T<:Period}(a::T) = T(abs(value(a)))
periodisless(::Period,::Year) = true
periodisless(::Period,::Month) = true
periodisless(::Year,::Month) = false
periodisless(::Period,::Week) = true
periodisless(::Year,::Week) = false
periodisless(::Month,::Week) = false
periodisless(::Period,::Day) = true
periodisless(::Year,::Day) = false
periodisless(::Month,::Day) = false
periodisless(::Week,::Day) = false
periodisless(::Period,::Hour) = false
periodisless(::Minute,::Hour) = true
periodisless(::Second,::Hour) = true
periodisless(::Millisecond,::Hour) = true
periodisless(::Period,::Minute) = false
periodisless(::Second,::Minute) = true
periodisless(::Millisecond,::Minute) = true
periodisless(::Period,::Second) = false
periodisless(::Millisecond,::Second) = true
periodisless(::Period,::Millisecond) = false
# return (next coarser period, conversion factor):
coarserperiod{P<:Period}(::Type{P}) = (P,1)
coarserperiod(::Type{Millisecond}) = (Second,1000)
coarserperiod(::Type{Second}) = (Minute,60)
coarserperiod(::Type{Minute}) = (Hour,60)
coarserperiod(::Type{Hour}) = (Day,24)
coarserperiod(::Type{Day}) = (Week,7)
coarserperiod(::Type{Month}) = (Year,12)
# Stores multiple periods in greatest to least order by type, not values,
# canonicalized to eliminate zero periods, merge equal period types,
# and convert more-precise periods to less-precise periods when possible
"""
CompoundPeriod
A `CompoundPeriod` is useful for expressing time periods that are not a fixed multiple of
smaller periods. For example, \"a year and a day\" is not a fixed number of days, but can
be expressed using a `CompoundPeriod`. In fact, a `CompoundPeriod` is automatically
generated by addition of different period types, e.g. `Year(1) + Day(1)` produces a
`CompoundPeriod` result.
"""
type CompoundPeriod <: AbstractTime
periods::Array{Period,1}
function CompoundPeriod(p::Vector{Period})
n = length(p)
if n > 1
sort!(p, rev=true, lt=periodisless)
# canonicalize p by merging equal period types and removing zeros
i = j = 1
while j <= n
k = j+1
while k <= n
if typeof(p[j]) == typeof(p[k])
p[j] += p[k]
k += 1
else
break
end
end
if p[j] != zero(p[j])
p[i] = p[j]
i += 1
end
j = k
end
n = i - 1 # new length
elseif n == 1 && value(p[1]) == 0
p = Period[]
n = 0
end
# canonicalize Periods by pushing "overflow" into a coarser period.
if n > 0
pc = sizehint!(Period[], n)
P = typeof(p[n])
v = value(p[n])
i = n - 1
while true
Pc, f = coarserperiod(P)
if i > 0 && typeof(p[i]) == P
v += value(p[i])
i -= 1
end
v0 = f == 1 ? v : rem(v, f)
v0 != 0 && push!(pc, P(v0))
if v != v0
P = Pc
v = div(v - v0, f)
elseif i > 0
P = typeof(p[i])
v = value(p[i])
i -= 1
else
break
end
end
p = reverse!(pc)
n = length(p)
else
return new(resize!(p, n))
end
# reduce the amount of mixed positive/negative Periods.
if n > 0
pc = sizehint!(Period[], n)
i = n
while i > 0
j = i
# Determine sign of the largest period in this group which
# can be converted into via coarserperiod.
last = Union{}
current = typeof(p[i])
while i > 0 && current != last
if typeof(p[i]) == current
i -= 1
end
last, current = current, coarserperiod(current)[1]
end
s = sign(value(p[i + 1]))
# Adjust all the periods in the group based upon the
# largest period sign.
P = typeof(p[j])
v = 0
while j > i
Pc, f = coarserperiod(P)
if j > 0 && typeof(p[j]) == P
v += value(p[j])
j -= 1
end
v0 = f == 1 ? v : mod(v, f * s)
v0 != 0 && push!(pc, P(v0))
if v != v0
P = Pc
v = div(v - v0, f)
elseif j > 0
P = typeof(p[j])
v = 0
else
break
end
end
end
p = reverse!(pc)
end
return new(p)
end
end
"""
CompoundPeriod(periods) -> CompoundPeriod
Construct a `CompoundPeriod` from a `Vector` of `Period`s. The constructor will
automatically simplify the periods into a canonical form according to the following rules:
* All `Period`s of the same type will be added together
* Any `Period` large enough be partially representable by a coarser `Period` will be broken
into multiple `Period`s (eg. `Hour(30)` becomes `Day(1) + Hour(6)`)
* `Period`s with opposite signs will be combined when possible
(eg. `Hour(1) - Day(1)` becomes `-Hour(23)`)
Due to the canonicalization, `CompoundPeriod` is also useful for converting time periods
into more human-comprehensible forms.
# Examples
```julia
julia> Dates.CompoundPeriod([Dates.Hour(12), Dates.Hour(13)])
1 day, 1 hour
julia> Dates.CompoundPeriod([Dates.Hour(-1), Dates.Minute(1)])
-59 minutes
julia> Dates.CompoundPeriod([Dates.Month(1), Dates.Week(-2)])
1 month, -2 weeks
julia> Dates.CompoundPeriod(Dates.Minute(50000)))
4 weeks, 6 days, 17 hours, 20 minutes
```
"""
CompoundPeriod{P<:Period}(p::Vector{P}) = CompoundPeriod(Array{Period}(p))
Base.convert(::Type{CompoundPeriod}, x::Period) = CompoundPeriod(Period[x])
function Base.string(x::CompoundPeriod)
if isempty(x.periods)
return "empty period"
else
s = ""
for p in x.periods
s *= ", " * string(p)
end
return s[3:end]
end
end
Base.show(io::IO,x::CompoundPeriod) = print(io,string(x))
# E.g. Year(1) + Day(1)
(+)(x::Period,y::Period) = CompoundPeriod(Period[x,y])
(+)(x::CompoundPeriod,y::Period) = CompoundPeriod(vcat(x.periods,y))
(+)(y::Period,x::CompoundPeriod) = x + y
(+)(x::CompoundPeriod,y::CompoundPeriod) = CompoundPeriod(vcat(x.periods,y.periods))
# E.g. Year(1) - Month(1)
(-)(x::Period,y::Period) = CompoundPeriod(Period[x,-y])
(-)(x::CompoundPeriod,y::Period) = CompoundPeriod(vcat(x.periods,-y))
(-)(x::CompoundPeriod) = CompoundPeriod(-x.periods)
(-)(y::Union{Period,CompoundPeriod},x::CompoundPeriod) = (-x) + y
GeneralPeriod = Union{Period,CompoundPeriod}
(+)(x::GeneralPeriod) = x
(+){P<:GeneralPeriod}(x::StridedArray{P}) = x
for op in (:.+, :.-)
op_ = Symbol(string(op)[2:end])
@eval begin
function ($op){P<:GeneralPeriod}(X::StridedArray{P},y::GeneralPeriod)
Z = similar(X, CompoundPeriod)
for (Idst, Isrc) in zip(eachindex(Z), eachindex(X))
@inbounds Z[Idst] = ($op_)(X[Isrc],y)
end
return Z
end
($op){P<:GeneralPeriod}(x::GeneralPeriod,Y::StridedArray{P}) = ($op)(Y,x) |> ($op_)
($op_){P<:GeneralPeriod}(x::GeneralPeriod,Y::StridedArray{P}) = ($op)(Y,x) |> ($op_)
($op_){P<:GeneralPeriod}(Y::StridedArray{P},x::GeneralPeriod) = ($op)(Y,x)
($op_){P<:GeneralPeriod, Q<:GeneralPeriod}(X::StridedArray{P}, Y::StridedArray{Q}) =
reshape(CompoundPeriod[($op_)(x,y) for (x,y) in zip(X, Y)], promote_shape(size(X),size(Y)))
end
end
(==)(x::CompoundPeriod, y::Period) = x == CompoundPeriod(y)
(==)(y::Period, x::CompoundPeriod) = x == y
(==)(x::CompoundPeriod, y::CompoundPeriod) = x.periods == y.periods
# Capture TimeType+-Period methods
(+)(a::TimeType,b::Period,c::Period) = (+)(a,b+c)
(-)(a::TimeType,b::Period,c::Period) = (-)(a,b-c)
(+)(a::TimeType,b::Period,c::Period,d::Period...) = (+)((+)(a,b+c),d...)
(-)(a::TimeType,b::Period,c::Period,d::Period...) = (-)((-)(a,b-c),d...)
function (+)(x::TimeType,y::CompoundPeriod)
for p in y.periods
x += p
end
return x
end
(+)(x::CompoundPeriod,y::TimeType) = y + x
function (-)(x::TimeType,y::CompoundPeriod)
for p in y.periods
x -= p
end
return x
end
(-)(x::CompoundPeriod,y::TimeType) = y - x
# Fixed-value Periods (periods corresponding to a well-defined time interval,
# as opposed to variable calendar intervals like Year).
typealias FixedPeriod Union{Week,Day,Hour,Minute,Second,Millisecond}
# like div but throw an error if remainder is nonzero
function divexact(x,y)
q,r = divrem(x, y)
r == 0 || throw(InexactError())
return q
end
# FixedPeriod conversions and promotion rules
const fixedperiod_conversions = [(Week,7),(Day,24),(Hour,60),(Minute,60),(Second,1000),(Millisecond,1)]
for i = 1:length(fixedperiod_conversions)
(T,n) = fixedperiod_conversions[i]
N = 1
for j = i-1:-1:1 # less-precise periods
(Tc,nc) = fixedperiod_conversions[j]
N *= nc
vmax = typemax(Int64) ÷ N
vmin = typemin(Int64) ÷ N
@eval function Base.convert(::Type{$T}, x::$Tc)
$vmin ≤ value(x) ≤ $vmax || throw(InexactError())
return $T(value(x)*$N)
end
end
N = n
for j = i+1:length(fixedperiod_conversions) # more-precise periods
(Tc,nc) = fixedperiod_conversions[j]
@eval Base.convert(::Type{$T}, x::$Tc) = $T(divexact(value(x), $N))
@eval Base.promote_rule(::Type{$T},::Type{$Tc}) = $Tc
N *= nc
end
end
# have to declare thusly so that diagonal dispatch above takes precedence:
(==){T<:FixedPeriod,S<:FixedPeriod}(x::T,y::S) = (==)(promote(x,y)...)
Base.isless{T<:FixedPeriod,S<:FixedPeriod}(x::T,y::S) = isless(promote(x,y)...)
# other periods with fixed conversions but which aren't fixed time periods
typealias OtherPeriod Union{Month,Year}
let vmax = typemax(Int64) ÷ 12, vmin = typemin(Int64) ÷ 12
@eval function Base.convert(::Type{Month}, x::Year)
$vmin ≤ value(x) ≤ $vmax || throw(InexactError())
Month(value(x)*12)
end
end
Base.convert(::Type{Year}, x::Month) = Year(divexact(value(x),12))
Base.promote_rule(::Type{Year}, ::Type{Month}) = Month
(==){T<:OtherPeriod,S<:OtherPeriod}(x::T,y::S) = (==)(promote(x,y)...)
Base.isless{T<:OtherPeriod,S<:OtherPeriod}(x::T,y::S) = isless(promote(x,y)...)
# truncating conversions to milliseconds and days:
toms(c::Millisecond) = value(c)
toms(c::Second) = 1000*value(c)
toms(c::Minute) = 60000*value(c)
toms(c::Hour) = 3600000*value(c)
toms(c::Day) = 86400000*value(c)
toms(c::Week) = 604800000*value(c)
toms(c::Month) = 86400000.0*30.436875*value(c)
toms(c::Year) = 86400000.0*365.2425*value(c)
toms(c::CompoundPeriod) = isempty(c.periods)?0.0 : Float64(sum(toms,c.periods))
days(c::Millisecond) = div(value(c),86400000)
days(c::Second) = div(value(c),86400)
days(c::Minute) = div(value(c),1440)
days(c::Hour) = div(value(c),24)
days(c::Day) = value(c)
days(c::Week) = 7*value(c)
days(c::Year) = 365.2425*value(c)
days(c::Month) = 30.436875*value(c)
days(c::CompoundPeriod) = isempty(c.periods)?0.0 : Float64(sum(days,c.periods))
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Date functions
### Core query functions
# Monday = 1....Sunday = 7
dayofweek(days) = mod1(days,7)
# Number of days in year
"""
daysinyear(dt::TimeType) -> Int
Returns 366 if the year of `dt` is a leap year, otherwise returns 365.
"""
daysinyear(y) = 365 + isleapyear(y)
# Day of the year
const MONTHDAYS = [0,31,59,90,120,151,181,212,243,273,304,334]
dayofyear(y,m,d) = MONTHDAYS[m] + d + (m > 2 && isleapyear(y))
### Days of the Week
"""
dayofweek(dt::TimeType) -> Int64
Returns the day of the week as an `Int64` with `1 = Monday, 2 = Tuesday, etc.`.
"""
dayofweek(dt::TimeType) = dayofweek(days(dt))
const Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday = 1,2,3,4,5,6,7
const Mon,Tue,Wed,Thu,Fri,Sat,Sun = 1,2,3,4,5,6,7
const english_daysofweek = Dict(1=>"Monday",2=>"Tuesday",3=>"Wednesday",
4=>"Thursday",5=>"Friday",6=>"Saturday",7=>"Sunday")
const VALUETODAYOFWEEK = Dict{String,Dict{Int,String}}("english"=>english_daysofweek)
const english_daysofweekabbr = Dict(1=>"Mon",2=>"Tue",3=>"Wed",
4=>"Thu",5=>"Fri",6=>"Sat",7=>"Sun")
const VALUETODAYOFWEEKABBR = Dict{String,Dict{Int,String}}("english"=>english_daysofweekabbr)
dayname(dt::Integer;locale::AbstractString="english") = VALUETODAYOFWEEK[locale][dt]
"""
dayabbr(dt::TimeType; locale="english") -> AbstractString
Return the abbreviated name corresponding to the day of the week of the `Date` or `DateTime`
in the given `locale`.
"""
dayabbr(dt::Integer;locale::AbstractString="english") = VALUETODAYOFWEEKABBR[locale][dt]
"""
dayname(dt::TimeType; locale="english") -> AbstractString
Return the full day name corresponding to the day of the week of the `Date` or `DateTime` in
the given `locale`.
"""
dayname(dt::TimeType;locale::AbstractString="english") = VALUETODAYOFWEEK[locale][dayofweek(dt)]
dayabbr(dt::TimeType;locale::AbstractString="english") = VALUETODAYOFWEEKABBR[locale][dayofweek(dt)]
# Convenience methods for each day
ismonday(dt::TimeType) = dayofweek(dt) == Mon
istuesday(dt::TimeType) = dayofweek(dt) == Tue
iswednesday(dt::TimeType) = dayofweek(dt) == Wed
isthursday(dt::TimeType) = dayofweek(dt) == Thu
isfriday(dt::TimeType) = dayofweek(dt) == Fri
issaturday(dt::TimeType) = dayofweek(dt) == Sat
issunday(dt::TimeType) = dayofweek(dt) == Sun
# i.e. 1st Monday? 2nd Monday? 3rd Wednesday? 5th Sunday?
"""
dayofweekofmonth(dt::TimeType) -> Int
For the day of week of `dt`, returns which number it is in `dt`'s month. So if the day of
the week of `dt` is Monday, then `1 = First Monday of the month, 2 = Second Monday of the
month, etc.` In the range 1:5.
"""
dayofweekofmonth(dt::TimeType) = (d = day(dt); return d < 8 ? 1 :
d < 15 ? 2 : d < 22 ? 3 : d < 29 ? 4 : 5)
# Total number of a day of week in the month
# e.g. are there 4 or 5 Mondays in this month?
const TWENTYNINE = IntSet([1,8,15,22,29])
const THIRTY = IntSet([1,2,8,9,15,16,22,23,29,30])
const THIRTYONE = IntSet([1,2,3,8,9,10,15,16,17,22,23,24,29,30,31])
"""
daysofweekinmonth(dt::TimeType) -> Int
For the day of week of `dt`, returns the total number of that day of the week in `dt`'s
month. Returns 4 or 5. Useful in temporal expressions for specifying the last day of a week
in a month by including `dayofweekofmonth(dt) == daysofweekinmonth(dt)` in the adjuster
function.
"""
function daysofweekinmonth(dt::TimeType)
y,m,d = yearmonthday(dt)
ld = daysinmonth(y,m)
return ld == 28 ? 4 : ld == 29 ? ((d in TWENTYNINE) ? 5 : 4) :
ld == 30 ? ((d in THIRTY) ? 5 : 4) :
(d in THIRTYONE) ? 5 : 4
end
### Months
const January,February,March,April,May,June = 1,2,3,4,5,6
const July,August,September,October,November,December = 7,8,9,10,11,12
const Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec = 1,2,3,4,5,6,7,8,9,10,11,12
const english_months = Dict(1=>"January",2=>"February",3=>"March",4=>"April",
5=>"May",6=>"June",7=>"July",8=>"August",9=>"September",
10=>"October",11=>"November",12=>"December")
const VALUETOMONTH = Dict{String,Dict{Int,String}}("english"=>english_months)
const englishabbr_months = Dict(1=>"Jan",2=>"Feb",3=>"Mar",4=>"Apr",
5=>"May",6=>"Jun",7=>"Jul",8=>"Aug",9=>"Sep",
10=>"Oct",11=>"Nov",12=>"Dec")
const VALUETOMONTHABBR = Dict{String,Dict{Int,String}}("english"=>englishabbr_months)
monthname(dt::Integer;locale::AbstractString="english") = VALUETOMONTH[locale][dt]
monthabbr(dt::Integer;locale::AbstractString="english") = VALUETOMONTHABBR[locale][dt]
"""
monthname(dt::TimeType; locale="english") -> AbstractString
Return the full name of the month of the `Date` or `DateTime` in the given `locale`.
"""
monthname(dt::TimeType;locale::AbstractString="english") = VALUETOMONTH[locale][month(dt)]
"""
monthabbr(dt::TimeType; locale="english") -> AbstractString
Return the abbreviated month name of the `Date` or `DateTime` in the given `locale`.
"""
monthabbr(dt::TimeType;locale::AbstractString="english") = VALUETOMONTHABBR[locale][month(dt)]
"""
daysinmonth(dt::TimeType) -> Int
Returns the number of days in the month of `dt`. Value will be 28, 29, 30, or 31.
"""
daysinmonth(dt::TimeType) = ((y,m) = yearmonth(dt); return daysinmonth(y,m))
### Years
"""
isleapyear(dt::TimeType) -> Bool
Returns `true` if the year of `dt` is a leap year.
"""
isleapyear(dt::TimeType) = isleapyear(year(dt))
"""
dayofyear(dt::TimeType) -> Int
Returns the day of the year for `dt` with January 1st being day 1.
"""
dayofyear(dt::TimeType) = ((y,m,d) = yearmonthday(dt); return dayofyear(y,m,d))
daysinyear(dt::TimeType) = 365 + isleapyear(dt)
### Quarters
"""
quarterofyear(dt::TimeType) -> Int
Returns the quarter that `dt` resides in. Range of value is 1:4.
"""
function quarterofyear(dt::TimeType)
m = month(dt)
return m < 4 ? 1 : m < 7 ? 2 : m < 10 ? 3 : 4
end
const QUARTERDAYS = [0,90,181,273]
"""
dayofquarter(dt::TimeType) -> Int
Returns the day of the current quarter of `dt`. Range of value is 1:92.
"""
dayofquarter(dt::TimeType) = dayofyear(dt) - QUARTERDAYS[quarterofyear(dt)]
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Date/DateTime Ranges
# Override default step; otherwise it would be Millisecond(1)
Base.colon{T<:DateTime}(start::T, stop::T) = StepRange(start, Day(1), stop)
# Given a start and end date, how many steps/periods are in between
guess(a::DateTime,b::DateTime,c) = floor(Int64,(Int128(b) - Int128(a))/toms(c))
guess(a::Date,b::Date,c) = Int64(div(Int64(b - a),days(c)))
function len(a,b,c)
lo, hi, st = min(a,b), max(a,b), abs(c)
i = guess(a,b,c)-1
while lo+st*i <= hi
i += 1
end
return i-1
end
Base.length{T<:TimeType}(r::StepRange{T}) = isempty(r) ? 0 : len(r.start,r.stop,r.step) + 1
# Period ranges hook into Int64 overflow detection
Base.length{P<:Period}(r::StepRange{P}) = length(StepRange(value(r.start),value(r.step),value(r.stop)))
# Used to calculate the last valid date in the range given the start, stop, and step
# last = stop - steprem(start,stop,step)
Base.steprem{T<:TimeType}(a::T,b::T,c) = b - (a + c*len(a,b,c))
import Base.in
function in{T<:TimeType}(x::T, r::StepRange{T})
n = len(first(r),x,step(r)) + 1
n >= 1 && n <= length(r) && r[n] == x
end
Base.start{T<:TimeType}(r::StepRange{T}) = 0
Base.next{T<:TimeType}(r::StepRange{T}, i::Int) = (r.start+r.step*i,i+1)
Base.done{T<:TimeType,S<:Period}(r::StepRange{T,S}, i::Integer) = length(r) <= i
.+{T<:TimeType}(x::Period, r::Range{T}) = (x+first(r)):step(r):(x+last(r))
.+{T<:TimeType}(r::Range{T},x::Period) = x .+ r
+{T<:TimeType}(r::Range{T},x::Period) = x .+ r
+{T<:TimeType}(x::Period,r::Range{T}) = x .+ r
.-{T<:TimeType}(r::Range{T},x::Period) = (first(r)-x):step(r):(last(r)-x)
-{T<:TimeType}(r::Range{T},x::Period) = r .- x
# This file is a part of Julia. License is MIT: http://julialang.org/license
# The epochs used for date rounding are based ISO 8601's "year zero" notation
const DATEEPOCH = value(Date(0))
const DATETIMEEPOCH = value(DateTime(0))
# According to ISO 8601, the first day of the first week of year 0000 is 0000-01-03
const WEEKEPOCH = value(Date(0, 1, 3))
"""
epochdays2date(days) -> Date
Takes the number of days since the rounding epoch (`0000-01-01T00:00:00`) and returns the
corresponding `Date`.
"""
epochdays2date(i) = Date(UTD(DATEEPOCH + Int64(i)))
"""
epochms2datetime(milliseconds) -> DateTime
Takes the number of milliseconds since the rounding epoch (`0000-01-01T00:00:00`) and
returns the corresponding `DateTime`.
"""
epochms2datetime(i) = DateTime(UTM(DATETIMEEPOCH + Int64(i)))
"""
date2epochdays(dt::Date) -> Int64
Takes the given `Date` and returns the number of days since the rounding epoch
(`0000-01-01T00:00:00`) as an `Int64`.
"""
date2epochdays(dt::Date) = value(dt) - DATEEPOCH
"""
datetime2epochms(dt::DateTime) -> Int64
Takes the given `DateTime` and returns the number of milliseconds since the rounding epoch
(`0000-01-01T00:00:00`) as an `Int64`.
"""
datetime2epochms(dt::DateTime) = value(dt) - DATETIMEEPOCH
function Base.floor(dt::Date, p::Year)
value(p) < 1 && throw(DomainError())
years = year(dt)
return Date(years - mod(years, value(p)))
end
function Base.floor(dt::Date, p::Month)
value(p) < 1 && throw(DomainError())
y, m = yearmonth(dt)
months_since_epoch = y * 12 + m - 1
month_offset = months_since_epoch - mod(months_since_epoch, value(p))
target_month = mod(month_offset, 12) + 1
target_year = div(month_offset, 12) - (month_offset < 0 && target_month != 1)
return Date(target_year, target_month)
end
function Base.floor(dt::Date, p::Week)
value(p) < 1 && throw(DomainError())
days = value(dt) - WEEKEPOCH
days = days - mod(days, value(Day(p)))
return Date(UTD(WEEKEPOCH + Int64(days)))
end
function Base.floor(dt::Date, p::Day)
value(p) < 1 && throw(DomainError())
days = date2epochdays(dt)
return epochdays2date(days - mod(days, value(p)))
end
Base.floor(dt::DateTime, p::DatePeriod) = DateTime(Base.floor(Date(dt), p))
function Base.floor(dt::DateTime, p::TimePeriod)
value(p) < 1 && throw(DomainError())
milliseconds = datetime2epochms(dt)
return epochms2datetime(milliseconds - mod(milliseconds, value(Millisecond(p))))
end
"""
floor(dt::TimeType, p::Period) -> TimeType
Returns the nearest `Date` or `DateTime` less than or equal to `dt` at resolution `p`.
For convenience, `p` may be a type instead of a value: `floor(dt, Dates.Hour)` is a shortcut
for `floor(dt, Dates.Hour(1))`.
```jldoctest
julia> floor(Date(1985, 8, 16), Dates.Month)
1985-08-01
julia> floor(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15))
2013-02-13T00:30:00
julia> floor(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day)
2016-08-06T00:00:00
```
"""
Base.floor(::Dates.TimeType, ::Dates.Period)
"""
ceil(dt::TimeType, p::Period) -> TimeType
Returns the nearest `Date` or `DateTime` greater than or equal to `dt` at resolution `p`.
For convenience, `p` may be a type instead of a value: `ceil(dt, Dates.Hour)` is a shortcut
for `ceil(dt, Dates.Hour(1))`.
```jldoctest
julia> ceil(Date(1985, 8, 16), Dates.Month)
1985-09-01
julia> ceil(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15))
2013-02-13T00:45:00
julia> ceil(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day)
2016-08-07T00:00:00
```
"""
function Base.ceil(dt::TimeType, p::Period)
f = floor(dt, p)
return (dt == f) ? f : f + p
end
"""
floorceil(dt::TimeType, p::Period) -> (TimeType, TimeType)
Simultaneously return the `floor` and `ceil` of a `Date` or `DateTime` at resolution `p`.
More efficient than calling both `floor` and `ceil` individually.
"""
function floorceil(dt::TimeType, p::Period)
f = floor(dt, p)
return f, (dt == f) ? f : f + p
end
"""
round(dt::TimeType, p::Period, [r::RoundingMode]) -> TimeType
Returns the `Date` or `DateTime` nearest to `dt` at resolution `p`. By default
(`RoundNearestTiesUp`), ties (e.g., rounding 9:30 to the nearest hour) will be rounded up.
For convenience, `p` may be a type instead of a value: `round(dt, Dates.Hour)` is a shortcut
for `round(dt, Dates.Hour(1))`.
```jldoctest
julia> round(Date(1985, 8, 16), Dates.Month)
1985-08-01
julia> round(DateTime(2013, 2, 13, 0, 31, 20), Dates.Minute(15))
2013-02-13T00:30:00
julia> round(DateTime(2016, 8, 6, 12, 0, 0), Dates.Day)
2016-08-07T00:00:00
```
Valid rounding modes for `round(::TimeType, ::Period, ::RoundingMode)` are
`RoundNearestTiesUp` (default), `RoundDown` (`floor`), and `RoundUp` (`ceil`).
"""
function Base.round(dt::TimeType, p::Period, r::RoundingMode{:NearestTiesUp})
f, c = floorceil(dt, p)
return (dt - f) < (c - dt) ? f : c
end
Base.round(dt::TimeType, p::Period, r::RoundingMode{:Down}) = Base.floor(dt, p)
Base.round(dt::TimeType, p::Period, r::RoundingMode{:Up}) = Base.ceil(dt, p)
# No implementation of other `RoundingMode`s: rounding to nearest "even" is skipped because
# "even" is not defined for Period; rounding toward/away from zero is skipped because ISO
# 8601's year 0000 is not really "zero".
Base.round(::TimeType, ::Period, ::RoundingMode) = throw(DomainError())
# Default to RoundNearestTiesUp.
Base.round(dt::TimeType, p::Period) = Base.round(dt, p, RoundNearestTiesUp)
# Make rounding functions callable using Period types in addition to values.
Base.floor{T <: Period}(dt::TimeType, p::Type{T}) = Base.floor(dt, p(1))
Base.ceil{T <: Period}(dt::TimeType, p::Type{T}) = Base.ceil(dt, p(1))
function Base.round{T<:Period}(dt::TimeType, p::Type{T}, r::RoundingMode=RoundNearestTiesUp)
return Base.round(dt, p(1), r)
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
abstract AbstractTime
"""
Period
Year
Month
Week
Day
Hour
Minute
Second
Millisecond
`Period` types represent discrete, human representations of time.
"""
abstract Period <: AbstractTime
abstract DatePeriod <: Period
abstract TimePeriod <: Period
for T in (:Year,:Month,:Week,:Day)
@eval immutable $T <: DatePeriod
value::Int64
$T(v::Number) = new(v)
end
end
for T in (:Hour,:Minute,:Second,:Millisecond)
@eval immutable $T <: TimePeriod
value::Int64
$T(v::Number) = new(v)
end
end
"""
Year(v)
Month(v)
Week(v)
Day(v)
Hour(v)
Minute(v)
Second(v)
Millisecond(v)
Construct a `Period` type with the given `v` value. Input must be losslessly convertible
to an `Int64`.
"""
Period(v)
"""
Instant
`Instant` types represent integer-based, machine representations of time as continuous
timelines starting from an epoch.
"""
abstract Instant <: AbstractTime
"""
UTInstant{T}
The `UTInstant` represents a machine timeline based on UT time (1 day = one revolution of
the earth). The `T` is a `Period` parameter that indicates the resolution or precision of
the instant.
"""
immutable UTInstant{P<:Period} <: Instant
periods::P
end
# Convenience default constructors
UTM(x) = UTInstant(Millisecond(x))
UTD(x) = UTInstant(Day(x))
# Calendar types provide rules for interpretating instant
# timelines in human-readable form.
abstract Calendar <: AbstractTime
# ISOCalendar implements the ISO 8601 standard (en.wikipedia.org/wiki/ISO_8601)
# Notably based on the proleptic Gregorian calendar
# ISOCalendar provides interpretation rules for UTInstants to civil date and time parts
immutable ISOCalendar <: Calendar end
abstract TimeZone
immutable UTC <: TimeZone end
"""
TimeType
`TimeType` types wrap `Instant` machine instances to provide human representations of the
machine instant. Both `DateTime` and `Date` are subtypes of `TimeType`.
"""
abstract TimeType <: AbstractTime
"""
DateTime
`DateTime` wraps a `UTInstant{Millisecond}` and interprets it according to the proleptic
Gregorian calendar.
"""
immutable DateTime <: TimeType
instant::UTInstant{Millisecond}
DateTime(instant::UTInstant{Millisecond}) = new(instant)
end
"""
Date
`Date` wraps a `UTInstant{Day}` and interprets it according to the proleptic Gregorian calendar.
"""
immutable Date <: TimeType
instant::UTInstant{Day}
Date(instant::UTInstant{Day}) = new(instant)
end
# Fallback constructors
_c(x) = convert(Int64,x)
DateTime(y,m=1,d=1,h=0,mi=0,s=0,ms=0) = DateTime(_c(y),_c(m),_c(d),_c(h),_c(mi),_c(s),_c(ms))
Date(y,m=1,d=1) = Date(_c(y),_c(m),_c(d))
# Convert y,m,d to # of Rata Die days
# Works by shifting the beginning of the year to March 1,
# so a leap day is the very last day of the year
const SHIFTEDMONTHDAYS = [306,337,0,31,61,92,122,153,184,214,245,275]
function totaldays(y,m,d)
# If we're in Jan/Feb, shift the given year back one
z = m < 3 ? y - 1 : y
mdays = SHIFTEDMONTHDAYS[m]
# days + month_days + year_days
return d + mdays + 365z + fld(z,4) - fld(z,100) + fld(z,400) - 306
end
# If the year is divisible by 4, except for every 100 years, except for every 400 years
isleapyear(y) = ((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)
# Number of days in month
const DAYSINMONTH = [31,28,31,30,31,30,31,31,30,31,30,31]
daysinmonth(y,m) = DAYSINMONTH[m] + (m == 2 && isleapyear(y))
### CONSTRUCTORS ###
# Core constructors
"""
DateTime(y, [m, d, h, mi, s, ms]) -> DateTime
Construct a `DateTime` type by parts. Arguments must be convertible to `Int64`.
"""
function DateTime(y::Int64,m::Int64=1,d::Int64=1,
h::Int64=0,mi::Int64=0,s::Int64=0,ms::Int64=0)
0 < m < 13 || throw(ArgumentError("Month: $m out of range (1:12)"))
0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$(daysinmonth(y,m)))"))
-1 < h < 24 || throw(ArgumentError("Hour: $h out of range (0:23)"))
-1 < mi < 60 || throw(ArgumentError("Minute: $mi out of range (0:59)"))
-1 < s < 60 || throw(ArgumentError("Second: $s out of range (0:59)"))
-1 < ms < 1000 || throw(ArgumentError("Millisecond: $ms out of range (0:999)"))
rata = ms + 1000*(s + 60mi + 3600h + 86400*totaldays(y,m,d))
return DateTime(UTM(rata))
end
"""
Date(y, [m, d]) -> Date
Construct a `Date` type by parts. Arguments must be convertible to `Int64`.
"""
function Date(y::Int64,m::Int64=1,d::Int64=1)
0 < m < 13 || throw(ArgumentError("Month: $m out of range (1:12)"))
0 < d < daysinmonth(y,m)+1 || throw(ArgumentError("Day: $d out of range (1:$(daysinmonth(y,m)))"))
return Date(UTD(totaldays(y,m,d)))
end
# Convenience constructors from Periods
function DateTime(y::Year,m::Month=Month(1),d::Day=Day(1),
h::Hour=Hour(0),mi::Minute=Minute(0),
s::Second=Second(0),ms::Millisecond=Millisecond(0))
return DateTime(value(y),value(m),value(d),
value(h),value(mi),value(s),value(ms))
end
Date(y::Year,m::Month=Month(1),d::Day=Day(1)) = Date(value(y),value(m),value(d))
# To allow any order/combination of Periods
"""
DateTime(periods::Period...) -> DateTime
Construct a `DateTime` type by `Period` type parts. Arguments may be in any order. DateTime
parts not provided will default to the value of `Dates.default(period)`.
"""
function DateTime(periods::Period...)
y = Year(1); m = Month(1); d = Day(1)
h = Hour(0); mi = Minute(0); s = Second(0); ms = Millisecond(0)
for p in periods
isa(p, Year) && (y = p::Year)
isa(p, Month) && (m = p::Month)
isa(p, Day) && (d = p::Day)
isa(p, Hour) && (h = p::Hour)
isa(p, Minute) && (mi = p::Minute)
isa(p, Second) && (s = p::Second)
isa(p, Millisecond) && (ms = p::Millisecond)
end
return DateTime(y,m,d,h,mi,s,ms)
end
"""
Date(period::Period...) -> Date
Construct a `Date` type by `Period` type parts. Arguments may be in any order. `Date` parts
not provided will default to the value of `Dates.default(period)`.
"""
function Date(periods::Period...)
y = Year(1); m = Month(1); d = Day(1)
for p in periods
isa(p, Year) && (y = p::Year)
isa(p, Month) && (m = p::Month)
isa(p, Day) && (d = p::Day)
end
return Date(y,m,d)
end
# Traits, Equality
Base.isfinite{T<:TimeType}(::Union{Type{T},T}) = true
calendar(dt::DateTime) = ISOCalendar
calendar(dt::Date) = ISOCalendar
"""
eps(::DateTime) -> Millisecond
eps(::Date) -> Day
Returns `Millisecond(1)` for `DateTime` values and `Day(1)` for `Date` values.
"""
Base.eps
Base.eps(dt::DateTime) = Millisecond(1)
Base.eps(dt::Date) = Day(1)
Base.typemax(::Union{DateTime,Type{DateTime}}) = DateTime(146138512,12,31,23,59,59)
Base.typemin(::Union{DateTime,Type{DateTime}}) = DateTime(-146138511,1,1,0,0,0)
Base.typemax(::Union{Date,Type{Date}}) = Date(252522163911149,12,31)
Base.typemin(::Union{Date,Type{Date}}) = Date(-252522163911150,1,1)
# Date-DateTime promotion, isless, ==
Base.promote_rule(::Type{Date},x::Type{DateTime}) = DateTime
Base.isless(x::Date,y::Date) = isless(value(x),value(y))
Base.isless(x::DateTime,y::DateTime) = isless(value(x),value(y))
Base.isless(x::TimeType,y::TimeType) = isless(promote(x,y)...)
==(x::TimeType,y::TimeType) = ===(promote(x,y)...)
# This file is a part of Julia. License is MIT: http://julialang.org/license
# deep copying
# Note: deepcopy_internal(::Any, ::ObjectIdDict) is
# only exposed for specialization by libraries
deepcopy(x) = deepcopy_internal(x, ObjectIdDict())::typeof(x)
deepcopy_internal(x::Union{Symbol,Core.MethodInstance,Method,GlobalRef,DataType,Union,Task},
stackdict::ObjectIdDict) = x
deepcopy_internal(x::Tuple, stackdict::ObjectIdDict) =
ntuple(i->deepcopy_internal(x[i], stackdict), length(x))
deepcopy_internal(x::Module, stackdict::ObjectIdDict) = error("deepcopy of Modules not supported")
function deepcopy_internal(x::SimpleVector, stackdict::ObjectIdDict)
if haskey(stackdict, x)
return stackdict[x]
end
y = Core.svec(Any[deepcopy_internal(x[i], stackdict) for i = 1:length(x)]...)
stackdict[x] = y
return y
end
function deepcopy_internal(x::ANY, stackdict::ObjectIdDict)
T = typeof(x)::DataType
nf = nfields(T)
(isbits(T) || nf == 0) && return x
if haskey(stackdict, x)
return stackdict[x]
end
y = ccall(:jl_new_struct_uninit, Any, (Any,), T)
if T.mutable
stackdict[x] = y
end
for i in 1:nf
if isdefined(x,i)
ccall(:jl_set_nth_field, Void, (Any, Csize_t, Any), y, i-1,
deepcopy_internal(getfield(x,i), stackdict))
end
end
return y::T
end
function deepcopy_internal(x::Array, stackdict::ObjectIdDict)
if haskey(stackdict, x)
return stackdict[x]
end
_deepcopy_array_t(x, eltype(x), stackdict)
end
function _deepcopy_array_t(x::ANY, T, stackdict::ObjectIdDict)
if isbits(T)
return (stackdict[x]=copy(x))
end
dest = similar(x)
stackdict[x] = dest
for i = 1:(length(x)::Int)
if ccall(:jl_array_isassigned, Cint, (Any, Csize_t), x, i-1) != 0
xi = ccall(:jl_arrayref, Any, (Any, Csize_t), x, i-1)
if !isbits(typeof(xi))
xi = deepcopy_internal(xi, stackdict)
end
ccall(:jl_arrayset, Void, (Any, Any, Csize_t), dest, xi, i-1)
end
end
return dest
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Deprecated functions and objects
#
# Please add new deprecations at the bottom of the file.
# A function deprecated in a release will be removed in the next one.
# Please also add a reference to the pull request which introduced the
# deprecation.
#
# For simple cases where a direct replacement is available, use @deprecate:
# the first argument is the signature of the deprecated method, the second one
# is the call which replaces it. Remove the definition of the deprecated method
# and unexport it, as @deprecate takes care of calling the replacement
# and of exporting the function.
#
# For more complex cases, move the body of the deprecated method in this file,
# and call depwarn() directly from inside it. The symbol depwarn() expects is
# the name of the function, which is used to ensure that the deprecation warning
# is only printed the first time for each call place.
macro deprecate(old,new)
meta = Expr(:meta, :noinline)
if isa(old,Symbol)
oldname = Expr(:quote,old)
newname = Expr(:quote,new)
Expr(:toplevel,
Expr(:export,esc(old)),
:(function $(esc(old))(args...)
$meta
depwarn(string($oldname," is deprecated, use ",$newname," instead."),
$oldname)
$(esc(new))(args...)
end))
elseif isa(old,Expr) && old.head == :call
remove_linenums!(new)
oldcall = sprint(io->show_unquoted(io,old))
newcall = sprint(io->show_unquoted(io,new))
oldsym = if isa(old.args[1],Symbol)
old.args[1]
elseif isa(old.args[1],Expr) && old.args[1].head == :curly
old.args[1].args[1]
else
error("invalid usage of @deprecate")
end
oldname = Expr(:quote, oldsym)
Expr(:toplevel,
Expr(:export,esc(oldsym)),
:($(esc(old)) = begin
$meta
depwarn(string($oldcall," is deprecated, use ",$newcall," instead."),
$oldname)
$(esc(new))
end))
else
error("invalid usage of @deprecate")
end
end
function depwarn(msg, funcsym)
opts = JLOptions()
if opts.depwarn > 0
ln = Int(unsafe_load(cglobal(:jl_lineno, Cint)))
fn = unsafe_string(unsafe_load(cglobal(:jl_filename, Ptr{Cchar})))
bt = backtrace()
caller = firstcaller(bt, funcsym)
if opts.depwarn == 1 # raise a warning
warn(msg, once=(caller != C_NULL), key=caller, bt=bt,
filename=fn, lineno=ln)
elseif opts.depwarn == 2 # raise an error
throw(ErrorException(msg))
end
end
end
function firstcaller(bt::Array{Ptr{Void},1}, funcsym::Symbol)
# Identify the calling line
i = 1
while i <= length(bt)
lkups = StackTraces.lookup(bt[i])
i += 1
for lkup in lkups
if lkup === StackTraces.UNKNOWN
continue
end
if lkup.func == funcsym
@goto found
end
end
end
@label found
if i <= length(bt)
return bt[i]
end
return C_NULL
end
deprecate(s::Symbol) = deprecate(current_module(), s)
deprecate(m::Module, s::Symbol) = ccall(:jl_deprecate_binding, Void, (Any, Any), m, s)
macro deprecate_binding(old, new)
Expr(:toplevel,
Expr(:export, esc(old)),
Expr(:const, Expr(:(=), esc(old), esc(new))),
Expr(:call, :deprecate, Expr(:quote, old)))
end
# 0.5 deprecations
for f in (:remotecall, :remotecall_fetch, :remotecall_wait)
@eval begin
@deprecate ($f)(w::LocalProcess, f::Function, args...) ($f)(f, w::LocalProcess, args...)
@deprecate ($f)(w::Worker, f::Function, args...) ($f)(f, w::Worker, args...)
@deprecate ($f)(id::Integer, f::Function, args...) ($f)(f, id::Integer, args...)
end
end
# 13232
@deprecate with_bigfloat_precision setprecision
@deprecate set_bigfloat_precision(prec) setprecision(prec)
@deprecate get_bigfloat_precision() precision(BigFloat)
@deprecate set_rounding setrounding
@deprecate with_rounding setrounding
@deprecate get_rounding rounding
#13465
@deprecate cov(x::AbstractVector; corrected=true, mean=Base.mean(x)) Base.covm(x, mean, corrected)
@deprecate cov(X::AbstractMatrix; vardim=1, corrected=true, mean=Base.mean(X, vardim)) Base.covm(X, mean, vardim, corrected)
@deprecate cov(x::AbstractVector, y::AbstractVector; corrected=true, mean=(Base.mean(x), Base.mean(y))) Base.covm(x, mean[1], y, mean[2], corrected)
@deprecate cov(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, corrected=true, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.covm(X, mean[1], Y, mean[2], vardim, corrected)
@deprecate cor(x::AbstractVector; mean=Base.mean(x)) Base.corm(x, mean)
@deprecate cor(X::AbstractMatrix; vardim=1, mean=Base.mean(X, vardim)) Base.corm(X, mean, vardim)
@deprecate cor(x::AbstractVector, y::AbstractVector; mean=(Base.mean(x), Base.mean(y))) Base.corm(x, mean[1], y, mean[2])
@deprecate cor(X::AbstractVecOrMat, Y::AbstractVecOrMat; vardim=1, mean=(Base.mean(X, vardim), Base.mean(Y, vardim))) Base.corm(X, mean[1], Y, mean[2], vardim)
@deprecate_binding SparseMatrix SparseArrays
#13496
@deprecate A_ldiv_B!(A::SparseMatrixCSC, B::StridedVecOrMat) A_ldiv_B!(factorize(A), B)
@deprecate chol(A::Number, ::Type{Val{:U}}) chol(A)
@deprecate chol(A::AbstractMatrix, ::Type{Val{:U}}) chol(A)
@deprecate chol(A::Number, ::Type{Val{:L}}) ctranspose(chol(A))
@deprecate chol(A::AbstractMatrix, ::Type{Val{:L}}) ctranspose(chol(A))
# Number updates
# rem1 is inconsistent for x==0: The result should both have the same
# sign as x, and should be non-zero.
function rem1{T<:Real}(x::T, y::T)
depwarn("`rem1(x,y)` is discontinued, as it cannot be defined consistently for `x==0`. Rewrite the expression using `mod1` instead.", :rem1)
rem(x-1,y)+1
end
rem1(x::Real, y::Real) = rem1(promote(x,y)...)
export rem1
# Filesystem module updates
@deprecate_binding FS Filesystem
isreadable(path...) = isreadable(stat(path...))
iswritable(path...) = iswritable(stat(path...))
isexecutable(path...) = isexecutable(stat(path...))
function isreadable(st::Filesystem.StatStruct)
depwarn("isreadable is deprecated as it implied that the file would actually be readable by the user; consider using `isfile` instead. see also the system man page for `access`", :isreadable)
return (st.mode & 0o444) > 0
end
function iswritable(st::Filesystem.StatStruct)
depwarn("iswritable is deprecated as it implied that the file would actually be writable by the user; consider using `isfile` instead. see also the system man page for `access`", :iswritable)
return (st.mode & 0o222) > 0
end
function isexecutable(st::Filesystem.StatStruct)
depwarn("isexecutable is deprecated as it implied that the file would actually be executable by the user; consider using `isfile` instead. see also the system man page for `access`", :isexecutable)
return (st.mode & 0o111) > 0
end
export isreadable, iswritable, isexecutable
@deprecate RemoteRef RemoteChannel
function tty_size()
depwarn("tty_size is deprecated. use `displaysize(io)` as a replacement", :tty_size)
if isdefined(Base, :active_repl)
os = REPL.outstream(Base.active_repl)
if isa(os, Terminals.TTYTerminal)
return displaysize(os)
end
end
if isdefined(Base, :STDOUT)
return displaysize(STDOUT)
end
return displaysize()
end
# Combinatorics functions that have been moved out of base (#13897)
# Note: only the two-argument form of factorial has been moved
for deprecatedfunc in [:combinations, :factorial, :prevprod, :levicivita,
:nthperm!, :nthperm, :parity, :partitions, :permutations]
@eval begin
$deprecatedfunc(args...) = error(string($deprecatedfunc, args,
" has been moved to the package Combinatorics.jl.\n",
"Run Pkg.add(\"Combinatorics\") to install Combinatorics on Julia v0.5-"))
export $deprecatedfunc
end
end
# Primes functions that have been moved out of base (#16481)
for deprecatedfunc in [:isprime, :primes, :primesmask, :factor]
@eval begin
$deprecatedfunc(args...) = error(string($deprecatedfunc, args,
" has been moved to the package Primes.jl.\n",
"Run Pkg.add(\"Primes\") to install Primes on Julia v0.5-"))
export $deprecatedfunc
end
end
#14335
@deprecate super(T::DataType) supertype(T)
function with_output_limit(thk, lim::Bool=true) # thk is usually show()
depwarn("with_output_limit is deprecated. use `io = IOContext(io, :limit => lim)` as a replacement", :with_output_limit)
global _limit_output
last = _limit_output
_limit_output = lim
try
thk()
finally
_limit_output = last
end
end
#14555
@deprecate_binding Coff_t Int64
@deprecate_binding FileOffset Int64
#14474
macro boundscheck(yesno,blk)
depwarn("The meaning of `@boundscheck` has changed. It now indicates that the provided code block performs bounds checking, and may be elided when inbounds.", Symbol("@boundscheck"))
if yesno === true
:(@inbounds $(esc(blk)))
end
end
@deprecate parseip(str::AbstractString) parse(IPAddr, str)
#https://github.com/JuliaLang/julia/issues/14608
@deprecate readall readstring
@deprecate readbytes read
@deprecate field_offset(x::DataType, idx) fieldoffset(x, idx+1)
@noinline function fieldoffsets(x::DataType)
depwarn("fieldoffsets is deprecated. use `map(idx->fieldoffset(x, idx), 1:nfields(x))` instead", :fieldoffsets)
nf = nfields(x)
offsets = Array{Int}(nf)
for i = 1:nf
offsets[i] = fieldoffset(x, i)
end
return offsets
end
export fieldoffsets
# 14766
@deprecate write(io::IO, p::Ptr, nb::Integer) unsafe_write(io, p, nb)
@deprecate isgeneric(f) isa(f,Function)
# need to do this manually since the front end deprecates method defs of `call`
const call = @eval function(f, args...; kw...)
$(Expr(:meta, :noinline))
depwarn("call(f,args...) is deprecated, use f(args...) instead.", :call)
f(args...; kw...)
end
export call
# Changed issym to issymmetric. #15192
@deprecate issym issymmetric
# 15258
@deprecate scale(α::Number, A::AbstractArray) α*A
@deprecate scale(A::AbstractArray, α::Number) A*α
@deprecate scale(A::AbstractMatrix, x::AbstractVector) A*Diagonal(x)
@deprecate scale(x::AbstractVector, A::AbstractMatrix) Diagonal(x)*A
# 1933
@deprecate_binding SingleAsyncWork AsyncCondition
# #12872
@deprecate istext istextmime
#15409
# Deprecated definition of pmap with keyword arguments.
# deprecation warnings are in pmap.jl
# 15692
typealias Func{N} Function
deprecate(:Func)
for (Fun, func) in [(:IdFun, :identity),
(:AbsFun, :abs),
(:Abs2Fun, :abs2),
(:ExpFun, :exp),
(:LogFun, :log),
(:ConjFun, :conj),
(:AndFun, :&),
(:OrFun, :|),
(:XorFun, :$),
(:AddFun, :+),
(:DotAddFun, :.+),
(:SubFun, :-),
(:DotSubFun, :.-),
(:MulFun, :*),
(:DotMulFun, :.*),
(:RDivFun, :/),
(:DotRDivFun, :./),
(:LDivFun, :\),
(:IDivFun, :div),
(:DotIDivFun, :.÷),
(:ModFun, :mod),
(:RemFun, :rem),
(:DotRemFun, :.%),
(:PowFun, :^),
(:MaxFun, :scalarmax),
(:MinFun, :scalarmin),
(:LessFun, :<),
(:MoreFun, :>),
(:DotLSFun, :.<<),
(:DotRSFun, :.>>),
(:ElementwiseMaxFun, :max),
(:ElementwiseMinFun, :min),
(:ComplexFun, :complex),
(:DotFun, :dot),
]
@eval begin
@deprecate_binding $(Fun) typeof($(func))
(::Type{typeof($(func))})() = $(func)
end
end
@deprecate_binding CentralizedAbs2Fun typeof(centralizedabs2fun(0)).name.primary
(::Type{typeof(centralizedabs2fun(0)).name.primary})(m::Number) = centralizedabs2fun(m)
@deprecate specialized_unary(f::Function) f
@deprecate specialized_binary(f::Function) f
@deprecate specialized_bitwise_unary(f::Function) f
@deprecate specialized_bitwise_binary(f::Function) f
@deprecate bitunpack(B::BitArray) Array(B)
@deprecate bitpack(A::AbstractArray) BitArray(A)
# #4163
@deprecate xdump dump
@deprecate copy(x::AbstractString) identity(x)
@deprecate copy(x::Tuple) identity(x)
@deprecate sprandbool(m::Integer, n::Integer, density::AbstractFloat) sprand(Bool, m, n, density)
@deprecate sprandbool(r::AbstractRNG, m::Integer, n::Integer, density::AbstractFloat) sprand(r, Bool, m, n, density)
@deprecate sprandbool(n::Integer, density::AbstractFloat) sprand(Bool, n, density)
@deprecate sprandbool(r::AbstractRNG, n::Integer, density::AbstractFloat) sprand(r, Bool, n, density)
@deprecate sprand{T}(n::Integer, density::AbstractFloat, ::Type{T}) sprand(T, n, density)
@deprecate sprand{T}(r::AbstractRNG, n::Integer, density::AbstractFloat, ::Type{T}) sprand(r, T, n, density)
#15995
@deprecate symbol Symbol
#15032: Expressions like Base.(:+) now call broadcast. Since calls
# to broadcast(x, ::Symbol) are unheard of, and broadcast(x, ::Integer)
# are unlikely, we can treat these as deprecated getfield calls.
# (See julia-syntax.scm for the Base.(:+)(...) = ... deprecation.)
function broadcast(x::Any, i::Union{Integer,Symbol})
depwarn("x.(i) is deprecated; use getfield(x, i) instead.", :broadcast)
getfield(x, i)
end
# clearer to be more explicit in the warning for the Module case
function broadcast(m::Module, s::Symbol)
S = repr(s) # 16295
depwarn("$m.($S) is deprecated; use $m.$S or getfield($m, $S) instead.", :broadcast)
getfield(m, s)
end
# expressions like f.(3) should still call broadcast for f::Function,
# and in general broadcast should work for scalar arguments, while
# getfield is certainly not intended for the case of f::Function.
broadcast(f::Function, i::Integer) = f(i)
#16167
macro ccallable(def)
depwarn("@ccallable requires a return type", Symbol("@ccallable"))
if isa(def,Expr) && (def.head === :(=) || def.head === :function)
sig = def.args[1]
if sig.head === :call
name = sig.args[1]
at = map(sig.args[2:end]) do a
if isa(a,Expr) && a.head === :(::)
a.args[2]
else
:Any
end
end
return quote
$(esc(def))
let name = $(esc(name)), tt = $(Expr(:curly, :Tuple, map(esc, at)...))
rt = return_types(name, tt)
length(rt) == 1 || error("function not ccallable")
ccallable(name, rt[1], tt)
end
end
end
end
error("expected method definition in @ccallable")
end
@deprecate_binding ASCIIString String
@deprecate_binding UTF8String String
@deprecate_binding ByteString String
@deprecate utf8(p::Ptr{UInt8}, len::Integer) unsafe_string(p, len)
@deprecate utf8(p::Ptr{UInt8}) unsafe_string(p)
@deprecate utf8(v::Vector{UInt8}) String(v)
@deprecate utf8(s::AbstractString) String(s)
@deprecate utf8(x) convert(String, x)
@deprecate ascii(p::Ptr{UInt8}, len::Integer) ascii(unsafe_string(p, len))
@deprecate ascii(p::Ptr{UInt8}) ascii(unsafe_string(p))
@deprecate ascii(v::Vector{UInt8}) ascii(String(v))
@deprecate ascii(x) ascii(convert(String, x))
@deprecate bytestring(s::Cstring) unsafe_string(s)
@deprecate bytestring(v::Vector{UInt8}) String(copy(v))
@deprecate bytestring(io::Base.AbstractIOBuffer) String(io)
@deprecate bytestring(p::Union{Ptr{Int8},Ptr{UInt8}}) unsafe_string(p)
@deprecate bytestring(p::Union{Ptr{Int8},Ptr{UInt8}}, len::Integer) unsafe_string(p,len)
@deprecate bytestring(s::AbstractString...) string(s...)
@deprecate String(s::Cstring) unsafe_string(s)
@deprecate String(p::Union{Ptr{Int8},Ptr{UInt8}}) unsafe_string(p)
@deprecate String(p::Union{Ptr{Int8},Ptr{UInt8}}, len::Integer) unsafe_string(p,len)
@deprecate(
convert(::Type{String}, a::Vector{UInt8}, invalids_as::AbstractString),
let a = a, invalids_as = invalids_as
l = length(a)
idx = 1
iscopy = false
while idx <= l
if !is_valid_continuation(a[idx])
nextidx = idx+1+utf8_trailing[a[idx]+1]
(nextidx <= (l+1)) && (idx = nextidx; continue)
end
!iscopy && (a = copy(a); iscopy = true)
endn = idx
while endn <= l
!is_valid_continuation(a[endn]) && break
endn += 1
end
(endn > idx) && (endn -= 1)
splice!(a, idx:endn, invalids_as.data)
l = length(a)
end
String(a)
end
)
@deprecate ==(x::Char, y::Integer) UInt32(x) == y
@deprecate ==(x::Integer, y::Char) x == UInt32(y)
# Note: when these deprecations are deleted, the specialized definitions isequal(x::Char, y::Integer)
# and isequal(x::Integer, y::Char) in operators.jl can be deleted, too
@deprecate isless(x::Char, y::Integer) UInt32(x) < y
@deprecate isless(x::Integer, y::Char) x < UInt32(y)
#6674 and #4233
macro windows(qm,ex)
depwarn("`@windows` is deprecated, use `@static is_windows()` instead", Symbol("@windows"))
return @static is_windows() ? esc(ex.args[1]) : esc(ex.args[2])
end
macro unix(qm,ex)
depwarn("`@unix` is deprecated, use `@static is_unix()` instead", Symbol("@unix"))
return @static is_unix() ? esc(ex.args[1]) : esc(ex.args[2])
end
macro osx(qm,ex)
depwarn("`@osx` is deprecated, use `@static is_apple()` instead", Symbol("@osx"))
return @static is_apple() ? esc(ex.args[1]) : esc(ex.args[2])
end
macro linux(qm,ex)
depwarn("`@linux` is deprecated, use `@static is_linux()` instead", Symbol("@linux"))
return @static is_linux() ? esc(ex.args[1]) : esc(ex.args[2])
end
macro windows_only(ex)
depwarn("`@windows_only` is deprecated, use `@static if is_windows()` instead", Symbol("@windows_only"))
return @static if is_windows() esc(ex) end
end
macro unix_only(ex)
depwarn("`@unix_only` is deprecated, use `@static if is_unix()` instead", Symbol("@unix_only"))
return @static if is_unix() esc(ex) end
end
macro osx_only(ex)
depwarn("`@osx_only` is deprecated, use `@static if is_apple()` instead", Symbol("@osx_only"))
return @static if is_apple() esc(ex) end
end
macro linux_only(ex)
depwarn("`@linux_only` is deprecated, use `@static if is_linux()` instead", Symbol("@linux_only"))
return @static if is_linux() esc(ex) end
end
export
@windows,
@unix,
@osx,
@linux,
@windows_only,
@unix_only,
@osx_only,
@linux_only
export OS_NAME
const OS_NAME =
if Sys.KERNEL === :NT
:Windows
else
Sys.KERNEL
end
deprecate(:OS_NAME) # use Sys.KERNEL now
export CPU_CORES
function _set_CPU_CORES()
global const CPU_CORES = Sys.CPU_CORES
deprecate(Base, :CPU_CORES)
end
module Init_CPU_CORES
const __init__ = Base._set_CPU_CORES
end
@deprecate_binding WORD_SIZE Sys.WORD_SIZE
@deprecate showcompact_lim show
@deprecate_binding writemime show
@deprecate blas_set_num_threads BLAS.set_num_threads
@deprecate print_escaped escape_string
@deprecate print_unescaped unescape_string
@deprecate print_joined join
@deprecate broadcast!_function(f) (B, As...) -> broadcast!(f, B, As...)
@deprecate broadcast_function(f) (As...) -> broadcast(f, As...)
##### histogram #####
## nice-valued ranges for histograms
export hist, hist!, hist2d, hist2d!, histrange
function histrange{T<:AbstractFloat,N}(v::AbstractArray{T,N}, n::Integer)
depwarn("histrange(...) is deprecated, use StatsBase.histrange(...) instead",:histrange)
nv = length(v)
if nv == 0 && n < 0
throw(ArgumentError("number of bins must be ≥ 0 for an empty array, got $n"))
elseif nv > 0 && n < 1
throw(ArgumentError("number of bins must be ≥ 1 for a non-empty array, got $n"))
end
if nv == 0
return 0.0:1.0:0.0
end
lo, hi = extrema(v)
if hi == lo
step = 1.0
else
bw = (hi - lo) / n
e = 10.0^floor(log10(bw))
r = bw / e
if r <= 2
step = 2*e
elseif r <= 5
step = 5*e
else
step = 10*e
end
end
start = step*(ceil(lo/step)-1)
nm1 = ceil(Int,(hi - start)/step)
start:step:(start + nm1*step)
end
function histrange{T<:Integer,N}(v::AbstractArray{T,N}, n::Integer)
depwarn("histrange(...) is deprecated, use StatsBase.histrange(...) instead",:histrange)
nv = length(v)
if nv == 0 && n < 0
throw(ArgumentError("number of bins must be ≥ 0 for an empty array, got $n"))
elseif nv > 0 && n < 1
throw(ArgumentError("number of bins must be ≥ 1 for a non-empty array, got $n"))
end
if nv == 0
return 0:1:0
end
if n <= 0
throw(ArgumentError("number of bins n=$n must be positive"))
end
lo, hi = extrema(v)
if hi == lo
step = 1
else
bw = (Float64(hi) - Float64(lo)) / n
e = 10.0^max(0,floor(log10(bw)))
r = bw / e
if r <= 1
step = e
elseif r <= 2
step = 2*e
elseif r <= 5
step = 5*e
else
step = 10*e
end
end
start = step*(ceil(lo/step)-1)
nm1 = ceil(Int,(hi - start)/step)
start:step:(start + nm1*step)
end
## midpoints of intervals
midpoints(r::Range) = r[1:length(r)-1] + 0.5*step(r)
midpoints(v::AbstractVector) = [0.5*(v[i] + v[i+1]) for i in 1:length(v)-1]
## hist ##
function sturges(n) # Sturges' formula
depwarn("sturges(n) is deprecated, use StatsBase.sturges(n) instead.",:sturges)
n==0 && return one(n)
ceil(Int,log2(n))+1
end
function hist!{HT}(h::AbstractArray{HT}, v::AbstractVector, edg::AbstractVector; init::Bool=true)
depwarn("hist(...) and hist!(...) are deprecated. Use fit(Histogram,...) in StatsBase.jl instead.",:hist!)
n = length(edg) - 1
length(h) == n || throw(DimensionMismatch("length(histogram) must equal length(edges) - 1"))
if init
fill!(h, zero(HT))
end
for x in v
i = searchsortedfirst(edg, x)-1
if 1 <= i <= n
h[i] += 1
end
end
edg, h
end
hist(v::AbstractVector, edg::AbstractVector) = hist!(Array{Int,1}(length(edg)-1), v, edg)
hist(v::AbstractVector, n::Integer) = hist(v,histrange(v,n))
hist(v::AbstractVector) = hist(v,sturges(length(v)))
function hist!{HT}(H::AbstractArray{HT,2}, A::AbstractMatrix, edg::AbstractVector; init::Bool=true)
depwarn("hist(...) and hist!(...) are deprecated. Use fit(Histogram,...) in StatsBase.jl instead.",:hist!)
m, n = size(A)
sH = size(H)
sE = (length(edg)-1,n)
sH == sE || throw(DimensionMismatch("incorrect size of histogram"))
if init
fill!(H, zero(HT))
end
for j = 1:n
hist!(sub(H, :, j), sub(A, :, j), edg)
end
edg, H
end
hist(A::AbstractMatrix, edg::AbstractVector) = hist!(Array{Int,2}(length(edg)-1, size(A,2)), A, edg)
hist(A::AbstractMatrix, n::Integer) = hist(A,histrange(A,n))
hist(A::AbstractMatrix) = hist(A,sturges(size(A,1)))
## hist2d
function hist2d!{HT}(H::AbstractArray{HT,2}, v::AbstractMatrix,
edg1::AbstractVector, edg2::AbstractVector; init::Bool=true)
depwarn("hist2d!(...) and hist2d(...) are deprecated. Use fit(Histogram,...) in StatsBase.jl instead.",:hist2d!)
size(v,2) == 2 || throw(DimensionMismatch("hist2d requires an Nx2 matrix"))
n = length(edg1) - 1
m = length(edg2) - 1
size(H) == (n, m) || throw(DimensionMismatch("incorrect size of histogram"))
if init
fill!(H, zero(HT))
end
for i = indices(v,1)
x = searchsortedfirst(edg1, v[i,1]) - 1
y = searchsortedfirst(edg2, v[i,2]) - 1
if 1 <= x <= n && 1 <= y <= m
@inbounds H[x,y] += 1
end
end
edg1, edg2, H
end
hist2d(v::AbstractMatrix, edg1::AbstractVector, edg2::AbstractVector) =
hist2d!(Array{Int,2}(length(edg1)-1, length(edg2)-1), v, edg1, edg2)
hist2d(v::AbstractMatrix, edg::AbstractVector) = hist2d(v, edg, edg)
hist2d(v::AbstractMatrix, n1::Integer, n2::Integer) =
hist2d(v, histrange(sub(v,:,1),n1), histrange(sub(v,:,2),n2))
hist2d(v::AbstractMatrix, n::Integer) = hist2d(v, n, n)
hist2d(v::AbstractMatrix) = hist2d(v, sturges(size(v,1)))
@deprecate cell(dims::Integer...) Array{Any}(dims...)
@deprecate cell(dims::Tuple{Vararg{Integer}}) Array{Any}(dims)
@deprecate(pointer_to_array{T}(p::Ptr{T}, d::Union{Integer, Tuple{Vararg{Integer}}}, own::Bool=false),
unsafe_wrap(Array, p, d, own))
@deprecate(pointer_to_string(p::Ptr{UInt8}, len::Integer, own::Bool=false),
unsafe_wrap(String, p, len, own))
@deprecate(pointer_to_string(p::Ptr{UInt8}, own::Bool=false),
unsafe_wrap(String, p, own))
function checkbounds(::Type{Bool}, sz::Integer, i)
depwarn("checkbounds(Bool, size(A, d), i) is deprecated, use checkindex(Bool, indices(A, d), i).", :checkbounds)
checkbounds(Bool, 1:sz, i)
end
immutable FakeArray{T,N} <: AbstractArray{T,N}
dims::NTuple{N,Int}
end
size(A::FakeArray) = A.dims
function checkbounds{N,T}(::Type{Bool}, sz::NTuple{N,Integer}, I1::T, I...)
depwarn("checkbounds(Bool, size(A), I...) is deprecated, use checkbounds(Bool, A, I...).", :checkbounds)
checkbounds(Bool, FakeArray(sz), I1, I...)
end
function first(::Colon)
depwarn("first(:) is deprecated, see http://docs.julialang.org/en/latest/devdocs/offset-arrays/", :first)
1
end
function _first(i, A, d)
depwarn("_first is deprecated, see http://docs.julialang.org/en/latest/devdocs/offset-arrays/", :_first)
__first(i, A, d)
end
__first(::Colon, P, ::Colon) = first(linearindices(P))
__first(i, P, ::Colon) = first(i)
__first(::Colon, P, d) = first(indices(P, d))
__first(i, P, d) = first(i)
# Not exported, but deprecation may be useful just in case
function Broadcast.check_broadcast_shape(sz::Dims, As::Union{AbstractArray,Number}...)
depwarn("check_broadcast_shape(size(A), B...) should be replaced with check_broadcast_shape(indices(A), B...)", :check_broadcast_shape)
Broadcast.check_broadcast_shape(map(OneTo, sz), As...)
end
@deprecate trailingsize{n}(A::AbstractArray, ::Type{Val{n}}) trailingsize(A, n)
@deprecate slice view
@deprecate sub view
# Point users to SuiteSparse
function ereach{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, k::Integer, parent::Vector{Ti})
error(string("ereach(A, k, parent) now lives in package SuiteSparse.jl. Run",
"Pkg.add(\"SuiteSparse\") to install SuiteSparse on Julia v0.5."))
end
export etree
function etree{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, postorder::Bool)
error(string("etree(A[, post]) now lives in package SuiteSparse.jl. Run",
"Pkg.add(\"SuiteSparse\") to install SuiteSparse on Julia v0.5."))
end
etree(A::SparseMatrixCSC) = etree(A, false)
function csc_permute{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, pinv::Vector{Ti}, q::Vector{Ti})
error(string("csc_permute(A, pinv, q) now lives in package SuiteSparse.jl. Run",
"Pkg.add(\"SuiteSparse\") to install SuiteSparse on Julia v0.5."))
end
function symperm{Tv,Ti}(A::SparseMatrixCSC{Tv,Ti}, pinv::Vector{Ti})
error(string("symperm(A, pinv) now lives in package SuiteSparse.jl. Run,",
"Pkg.add(\"SuiteSparse\") to install SuiteSparse on Julia v0.5."))
end
# Deprecate no-op transpose fallback. Please see #13171 and #17075.
function transpose(x)
depwarn(string("the no-op `transpose` fallback is deprecated, and no more specific ",
"`transpose` method for $(typeof(x)) exists. Consider `permutedims(x, [2, 1])` ",
"or writing a specific `transpose(x::$(typeof(x)))` method if appropriate."),
:transpose)
return x
end
@deprecate cholfact!(A::Base.LinAlg.HermOrSym, uplo::Symbol, ::Type{Val{false}}) cholfact!(A, Val{false})
@deprecate cholfact!(A::Base.LinAlg.HermOrSym, uplo::Symbol = :U) cholfact!(A)
# During the 0.5 development cycle, do not add any deprecations below this line
# To be deprecated in 0.6
const _oldstyle_array_vcat_ = false
@deprecate write(x) write(STDOUT::IO, x)
function delete!(::EnvHash, k::AbstractString, def)
depwarn("`delete!(ENV, k, def)` should be replaced with `pop!(ENV, k, def)`. Be aware that `pop!` returns `k` or `def`, while `delete!` returns `ENV` or `def`.", :delete!)
haskey(ENV,k) ? delete!(ENV,k) : def
end
@deprecate (+)(J::UniformScaling, x::Number) J.λ + x
@deprecate (+)(x::Number, J::UniformScaling) x + J.λ
@deprecate (-)(J::UniformScaling, x::Number) J.λ - x
@deprecate (-)(x::Number, J::UniformScaling) x - J.λ
# Deprecate methods that convert Diagonal and Bidiagonal to <:AbstractTriangular.
function convert(::Type{UpperTriangular}, A::Diagonal)
depwarn(string("`convert(::Type{UpperTriangular}, A::Diagonal)` and other methods ",
"that convert `Diagonal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `UpperTriangular` constructor directly ",
"(`UpperTriangular(A)`) instead."), :convert)
UpperTriangular(A)
end
function convert(::Type{LowerTriangular}, A::Diagonal)
depwarn(string("`convert(::Type{LowerTriangular}, A::Diagonal)` and other methods ",
"that convert `Diagonal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `LowerTriangular` constructor directly ",
"(`LowerTriangular(A)`) instead."), :convert)
LowerTriangular(A)
end
function convert(::Type{Base.LinAlg.UnitUpperTriangular}, A::Diagonal)
depwarn(string("`convert(::Type{UnitUpperTriangular}, A::Diagonal)` and other methods ",
"that convert `Diagonal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `UnitUpperTriangular` constructor directly ",
"(`Base.LinAlg.UnitUpperTriangular(A)`) instead."), :convert)
if !all(A.diag .== one(eltype(A)))
throw(ArgumentError("matrix cannot be represented as UnitUpperTriangular"))
end
Base.LinAlg.UnitUpperTriangular(Array(A))
end
function convert(::Type{Base.LinAlg.UnitLowerTriangular}, A::Diagonal)
depwarn(string("`convert(::Type{UnitLowerTriangular}, A::Diagonal)` and other methods ",
"that convert `Diagonal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `UnitLowerTriangular` constructor directly ",
"(`Base.LinAlg.UnitLowerTriangular(A)`) instead."), :convert)
if !all(A.diag .== one(eltype(A)))
throw(ArgumentError("matrix cannot be represented as UnitLowerTriangular"))
end
Base.LinAlg.UnitLowerTriangular(Array(A))
end
function convert(::Type{LowerTriangular}, A::Bidiagonal)
depwarn(string("`convert(::Type{LowerTriangular}, A::Bidiagonal)` and other methods ",
"that convert `Diagonal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `LowerTriangular` constructor directly (`LowerTriangular(A)`) ",
"instead."), :convert)
if !A.isupper
LowerTriangular(Array(A))
else
throw(ArgumentError("Bidiagonal matrix must have lower off diagonal to be converted to LowerTriangular"))
end
end
function convert(::Type{UpperTriangular}, A::Bidiagonal)
depwarn(string("`convert(::Type{UpperTriangular}, A::Bidiagonal)` and other methods ",
"that convert `Diagoinal`/`Bidiagonal` to `<:AbstractTriangular` are deprecated. ",
"Consider calling the `UpperTriangular` constructor directly (`UpperTriangular(A)`) ",
"instead."), :convert)
if A.isupper
UpperTriangular(Array(A))
else
throw(ArgumentError("Bidiagonal matrix must have upper off diagonal to be converted to UpperTriangular"))
end
end
# Deprecate vectorized unary functions over sparse matrices in favor of compact broadcast syntax (#17265).
for f in (:sin, :sinh, :sind, :asin, :asinh, :asind,
:tan, :tanh, :tand, :atan, :atanh, :atand,
:sinpi, :cosc, :ceil, :floor, :trunc, :round, :real, :imag,
:log1p, :expm1, :abs, :abs2, :conj,
:log, :log2, :log10, :exp, :exp2, :exp10, :sinc, :cospi,
:cos, :cosh, :cosd, :acos, :acosd,
:cot, :coth, :cotd, :acot, :acotd,
:sec, :sech, :secd, :asech,
:csc, :csch, :cscd, :acsch)
@eval @deprecate $f(A::SparseMatrixCSC) $f.(A)
end
# For deprecating vectorized functions in favor of compact broadcast syntax
macro dep_vectorize_1arg(S, f)
S = esc(S)
f = esc(f)
T = esc(:T)
x = esc(:x)
AbsArr = esc(:AbstractArray)
:( @deprecate $f{$T<:$S}($x::$AbsArr{$T}) $f.($x) )
end
macro dep_vectorize_2arg(S, f)
S = esc(S)
f = esc(f)
T1 = esc(:T1)
T2 = esc(:T2)
x = esc(:x)
y = esc(:y)
AbsArr = esc(:AbstractArray)
quote
@deprecate $f{$T1<:$S}($x::$S, $y::$AbsArr{$T1}) $f.($x,$y)
@deprecate $f{$T1<:$S}($x::$AbsArr{$T1}, $y::$S) $f.($x,$y)
@deprecate $f{$T1<:$S,$T2<:$S}($x::$AbsArr{$T1}, $y::$AbsArr{$T2}) $f.($x,$y)
end
end
# Deprecate @vectorize_1arg-vectorized functions from...
for f in (
# base/special/trig.jl
:sinpi, :cospi, :sinc, :cosc,
# base/special/log.jl
:log, :log1p,
# base/special/gamma.jl
:gamma, :lfact, :digamma, :trigamma, :zeta, :eta,
# base/special/erf.jl
:erfcx, :erfi, :dawson,
# base/special/bessel.jl
:airyprime, :airyai, :airyaiprime, :airybi, :airybiprime,
:airy, :airyx, :besselj0, :besselj1, :bessely0, :bessely1,
# base/math.jl
:cbrt, :sinh, :cosh, :tanh, :atan, :asinh, :exp, :erf, :erfc, :exp2,
:expm1, :exp10, :sin, :cos, :tan, :asin, :acos, :acosh, :atanh,
#=:log,=# :log2, :log10, :lgamma, #=:log1p,=# :sqrt,
# base/floatfuncs.jl
:abs, :abs2, :angle, :isnan, :isinf, :isfinite,
# base/complex.jl
:cis,
)
@eval @dep_vectorize_1arg Number $f
end
# base/fastmath.jl
for f in ( :acos_fast, :acosh_fast, :angle_fast, :asin_fast, :asinh_fast,
:atan_fast, :atanh_fast, :cbrt_fast, :cis_fast, :cos_fast,
:cosh_fast, :exp10_fast, :exp2_fast, :exp_fast, :expm1_fast,
:lgamma_fast, :log10_fast, :log1p_fast, :log2_fast, :log_fast,
:sin_fast, :sinh_fast, :sqrt_fast, :tan_fast, :tanh_fast )
eval(FastMath, :(Base.@dep_vectorize_1arg Number $f))
end
for f in (
:invdigamma, # base/special/gamma.jl
:erfinc, :erfcinv, # base/special/erf.jl
:trunc, :floor, :ceil, :round, # base/floatfuncs.jl
:rad2deg, :deg2rad, :exponent, :significand, # base/math.jl
:sind, :cosd, :tand, :asind, :acosd, :atand, :asecd, :acscd, :acotd, # base/special/trig.jl
)
@eval @dep_vectorize_1arg Real $f
end
# base/complex.jl
@dep_vectorize_1arg Complex round
@dep_vectorize_1arg Complex float
# base/dates/*.jl
for f in (:unix2datetime, :rata2datetime, :julian2datetime) # base/dates/conversions.jl
eval(Dates, :(Base.@dep_vectorize_1arg Real $f))
end
for f in (
# base/dates/accessors.jl
:year, :month, :day, :week, :dayofmonth, :yearmonth, :monthday, :yearmonthday,
# base/dates/adjusters.jl
:firstdayofweek, :lastdayofweek, :firstdayofmonth,
:lastdayofmonth, :firstdayofyear, :lastdayofyear,
:firstdayofquarter, :lastdayofquarter,
# base/dates/query.jl
:dayname, :dayabbr, :dayofweek, :dayofweekofmonth,
:daysofweekinmonth, :monthname, :monthabbr, :daysinmonth,
:isleapyear, :dayofyear, :daysinyear, :quarterofyear, :dayofquarter,
)
eval(Dates, :(Base.@dep_vectorize_1arg Dates.TimeType $f))
end
for f in (
:hour, :minute, :second, :millisecond, # base/dates/accessors.jl
:Date, :datetime2unix, :datetime2rata, :datetime2julian, # base/dates/conversions.jl
)
eval(Dates, :(Base.@dep_vectorize_1arg Dates.DateTime $f))
end
eval(Dates, :(Base.@dep_vectorize_1arg Dates.Date Datetime)) # base/dates/conversions.jl
# Deprecate @vectorize_2arg-vectorized functions from...
for f in (
# base/special/gamma.jl
:polygamma, :zeta, :beta, :lbeta,
# base/special/bessel.jl
:airy, :airyx, :besseli, :besselix, :besselj, :besseljx,
:besselk, :besselkx, :bessely, :besselyx, :besselh,
:besselhx, :hankelh1, :hankelh2, :hankelh1x, :hankelh2x,
# base/math.jl
:log, :hypot, :atan2,
)
@eval @dep_vectorize_2arg Number $f
end
# base/fastmath.jl
for f in (:pow_fast, :atan2_fast, :hypot_fast, :max_fast, :min_fast, :minmax_fast)
eval(FastMath, :(Base.@dep_vectorize_2arg Number $f))
end
for f in (
:max, :min, # base/math.jl
:copysign, :flipsign, # base/floatfuncs.jl
)
@eval @dep_vectorize_2arg Real $f
end
# Deprecate @vectorize_1arg and @vectorize_2arg themselves
macro vectorize_1arg(S,f)
depwarn(string("`@vectorize_1arg` is deprecated in favor of compact broadcast syntax. ",
"Instead of `@vectorize_1arg`'ing function `f` and calling `f(arg)`, call `f.(arg)`."),
:vectorize_1arg)
quote
@dep_vectorize_1arg($(esc(S)),$(esc(f)))
end
end
macro vectorize_2arg(S,f)
depwarn(string("`@vectorize_2arg` is deprecated in favor of compact broadcast syntax. ",
"Instead of `@vectorize_2arg`'ing function `f` and calling `f(arg1, arg2)`, call ",
"`f.(arg1,arg2)`. "), :vectorize_2arg)
quote
@dep_vectorize_2arg($(esc(S)),$(esc(f)))
end
end
export @vectorize_1arg, @vectorize_2arg
# Devectorize manually vectorized abs methods in favor of compact broadcast syntax
@deprecate abs(f::Base.Pkg.Resolve.MaxSum.Field) abs.(f)
@deprecate abs(B::BitArray) abs.(B)
@deprecate abs(M::Bidiagonal) abs.(M)
@deprecate abs(D::Diagonal) abs.(D)
@deprecate abs(M::Tridiagonal) abs.(M)
@deprecate abs(M::SymTridiagonal) abs.(M)
@deprecate abs(x::AbstractSparseVector) abs.(x)
# Deprecate @textmime into the Multimedia module, #18441
eval(Multimedia, :(macro textmime(mime)
Base.depwarn(string("`@textmime \"mime\"` is deprecated; use ",
"`Base.Multimedia.istextmime(::MIME\"mime\") = true` instead"
), :textmime)
quote
Base.Multimedia.istextmime(::MIME{$(Meta.quot(Symbol(mime)))}) = true
end
end))
@deprecate ipermutedims(A::AbstractArray,p) permutedims(A, invperm(p))
@deprecate is (===)
@deprecate_binding Filter Iterators.Filter
@deprecate_binding Zip Iterators.Zip
@deprecate filter(flt, itr) Iterators.filter(flt, itr)
@deprecate_binding rest Iterators.rest
@deprecate_binding countfrom Iterators.countfrom
@deprecate_binding take Iterators.take
@deprecate_binding drop Iterators.drop
@deprecate_binding cycle Iterators.cycle
@deprecate_binding repeated Iterators.repeated
# NOTE: Deprecation of Channel{T}() is implemented in channels.jl.
# To be removed from there when 0.6 deprecations are removed.
# Not exported, but probably better to have deprecations anyway
function reduced_dims(::Tuple{}, d::Int)
d < 1 && throw(ArgumentError("dimension must be ≥ 1, got $d"))
()
end
reduced_dims(::Tuple{}, region) = ()
function reduced_dims(dims::Dims, region)
Base.depwarn("`reduced_dims` is deprecated for Dims-tuples; pass `indices` instead", :reduced_dims)
map(last, reduced_dims(map(n->OneTo(n), dims), region))
end
function reduced_dims0(::Tuple{}, d::Int)
d < 1 && throw(ArgumentError("dimension must be ≥ 1, got $d"))
()
end
reduced_dims0(::Tuple{}, region) = ()
function reduced_dims0(dims::Dims, region)
Base.depwarn("`reduced_dims0` is deprecated for Dims-tuples; pass `indices` instead", :reduced_dims0)
map(last, reduced_dims0(map(n->OneTo(n), dims), region))
end
# #18218
eval(Base.LinAlg, quote
function arithtype(T)
depwarn(string("arithtype is now deprecated. If you were using it inside a ",
"promote_op call, use promote_op(LinAlg.matprod, Ts...) instead. Otherwise, ",
"if you need its functionality, consider defining it locally."),
:arithtype)
T
end
function arithtype(::Type{Bool})
depwarn(string("arithtype is now deprecated. If you were using it inside a ",
"promote_op call, use promote_op(LinAlg.matprod, Ts...) instead. Otherwise, ",
"if you need its functionality, consider defining it locally."),
:arithtype)
Int
end
end)
# End deprecations scheduled for 0.6
# This file is a part of Julia. License is MIT: http://julialang.org/license
module DFT
# DFT plan where the inputs are an array of eltype T
abstract Plan{T}
import Base: show, summary, size, ndims, length, eltype,
*, A_mul_B!, inv, \, A_ldiv_B!
eltype{T}(::Type{Plan{T}}) = T
# size(p) should return the size of the input array for p
size(p::Plan, d) = size(p)[d]
ndims(p::Plan) = length(size(p))
length(p::Plan) = prod(size(p))::Int
##############################################################################
export fft, ifft, bfft, fft!, ifft!, bfft!,
plan_fft, plan_ifft, plan_bfft, plan_fft!, plan_ifft!, plan_bfft!,
rfft, irfft, brfft, plan_rfft, plan_irfft, plan_brfft
typealias FFTWFloat Union{Float32,Float64}
fftwfloat(x) = _fftwfloat(float(x))
_fftwfloat{T<:FFTWFloat}(::Type{T}) = T
_fftwfloat(::Type{Float16}) = Float32
_fftwfloat{T}(::Type{Complex{T}}) = Complex{_fftwfloat(T)}
_fftwfloat{T}(::Type{T}) = error("type $T not supported")
_fftwfloat{T}(x::T) = _fftwfloat(T)(x)
complexfloat{T<:FFTWFloat}(x::StridedArray{Complex{T}}) = x
realfloat{T<:FFTWFloat}(x::StridedArray{T}) = x
# return an Array, rather than similar(x), to avoid an extra copy for FFTW
# (which only works on StridedArray types).
complexfloat{T<:Complex}(x::AbstractArray{T}) = copy1(typeof(fftwfloat(one(T))), x)
complexfloat{T<:Real}(x::AbstractArray{T}) = copy1(typeof(complex(fftwfloat(one(T)))), x)
realfloat{T<:Real}(x::AbstractArray{T}) = copy1(typeof(fftwfloat(one(T))), x)
# copy to a 1-based array, using circular permutation
function copy1{T}(::Type{T}, x)
y = Array{T}(map(length, indices(x)))
Base.circcopy!(y, x)
end
to1(x::AbstractArray) = _to1(indices(x), x)
_to1(::Tuple{Base.OneTo,Vararg{Base.OneTo}}, x) = x
_to1(::Tuple, x) = copy1(eltype(x), x)
# implementations only need to provide plan_X(x, region)
# for X in (:fft, :bfft, ...):
for f in (:fft, :bfft, :ifft, :fft!, :bfft!, :ifft!, :rfft)
pf = Symbol("plan_", f)
@eval begin
$f(x::AbstractArray) = (y = to1(x); $pf(y) * y)
$f(x::AbstractArray, region) = (y = to1(x); $pf(y, region) * y)
$pf(x::AbstractArray; kws...) = (y = to1(x); $pf(y, 1:ndims(y); kws...))
end
end
"""
plan_ifft(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Same as [`plan_fft`](:func:`plan_fft`), but produces a plan that performs inverse transforms
[`ifft`](:func:`ifft`).
"""
plan_ifft
"""
plan_ifft!(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Same as [`plan_ifft`](:func:`plan_ifft`), but operates in-place on `A`.
"""
plan_ifft!
"""
plan_bfft!(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Same as [`plan_bfft`](:func:`plan_bfft`), but operates in-place on `A`.
"""
plan_bfft!
"""
plan_bfft(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Same as [`plan_fft`](:func:`plan_fft`), but produces a plan that performs an unnormalized
backwards transform [`bfft`](:func:`bfft`).
"""
plan_bfft
"""
plan_fft(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Pre-plan an optimized FFT along given dimensions (`dims`) of arrays matching the shape and
type of `A`. (The first two arguments have the same meaning as for [`fft`](:func:`fft`).)
Returns an object `P` which represents the linear operator computed by the FFT, and which
contains all of the information needed to compute `fft(A, dims)` quickly.
To apply `P` to an array `A`, use `P * A`; in general, the syntax for applying plans is much
like that of matrices. (A plan can only be applied to arrays of the same size as the `A`
for which the plan was created.) You can also apply a plan with a preallocated output array `Â`
by calling `A_mul_B!(Â, plan, A)`. (For `A_mul_B!`, however, the input array `A` must
be a complex floating-point array like the output `Â`.) You can compute the inverse-transform plan by `inv(P)`
and apply the inverse plan with `P \\ Â` (the inverse plan is cached and reused for
subsequent calls to `inv` or `\\`), and apply the inverse plan to a pre-allocated output
array `A` with `A_ldiv_B!(A, P, Â)`.
The `flags` argument is a bitwise-or of FFTW planner flags, defaulting to `FFTW.ESTIMATE`.
e.g. passing `FFTW.MEASURE` or `FFTW.PATIENT` will instead spend several seconds (or more)
benchmarking different possible FFT algorithms and picking the fastest one; see the FFTW
manual for more information on planner flags. The optional `timelimit` argument specifies a
rough upper bound on the allowed planning time, in seconds. Passing `FFTW.MEASURE` or
`FFTW.PATIENT` may cause the input array `A` to be overwritten with zeros during plan
creation.
[`plan_fft!`](:func:`plan_fft!`) is the same as [`plan_fft`](:func:`plan_fft`) but creates a
plan that operates in-place on its argument (which must be an array of complex
floating-point numbers). [`plan_ifft`](:func:`plan_ifft`) and so on are similar but produce
plans that perform the equivalent of the inverse transforms [`ifft`](:func:`ifft`) and so on.
"""
plan_fft
"""
plan_fft!(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Same as [`plan_fft`](:func:`plan_fft`), but operates in-place on `A`.
"""
plan_fft!
"""
rfft(A [, dims])
Multidimensional FFT of a real array `A`, exploiting the fact that the transform has
conjugate symmetry in order to save roughly half the computational time and storage costs
compared with [`fft`](:func:`fft`). If `A` has size `(n_1, ..., n_d)`, the result has size
`(div(n_1,2)+1, ..., n_d)`.
The optional `dims` argument specifies an iterable subset of one or more dimensions of `A`
to transform, similar to [`fft`](:func:`fft`). Instead of (roughly) halving the first
dimension of `A` in the result, the `dims[1]` dimension is (roughly) halved in the same way.
"""
rfft
"""
ifft!(A [, dims])
Same as [`ifft`](:func:`ifft`), but operates in-place on `A`.
"""
ifft!
"""
ifft(A [, dims])
Multidimensional inverse FFT.
A one-dimensional inverse FFT computes
```math
\\operatorname{IDFT}(A)[k] = \\frac{1}{\\operatorname{length}(A)}
\\sum_{n=1}^{\\operatorname{length}(A)} \\exp\\left(+i\\frac{2\\pi (n-1)(k-1)}
{\\operatorname{length}(A)} \\right) A[n].
```
A multidimensional inverse FFT simply performs this operation along each transformed dimension of `A`.
"""
ifft
"""
fft!(A [, dims])
Same as [`fft`](:func:`fft`), but operates in-place on `A`, which must be an array of
complex floating-point numbers.
"""
fft!
"""
bfft(A [, dims])
Similar to [`ifft`](:func:`ifft`), but computes an unnormalized inverse (backward)
transform, which must be divided by the product of the sizes of the transformed dimensions
in order to obtain the inverse. (This is slightly more efficient than [`ifft`](:func:`ifft`)
because it omits a scaling step, which in some applications can be combined with other
computational steps elsewhere.)
```math
\\operatorname{BDFT}(A)[k] = \\operatorname{length}(A) \\operatorname{IDFT}(A)[k]
```
"""
bfft
"""
bfft!(A [, dims])
Same as [`bfft`](:func:`bfft`), but operates in-place on `A`.
"""
bfft!
# promote to a complex floating-point type (out-of-place only),
# so implementations only need Complex{Float} methods
for f in (:fft, :bfft, :ifft)
pf = Symbol("plan_", f)
@eval begin
$f{T<:Real}(x::AbstractArray{T}, region=1:ndims(x)) = $f(complexfloat(x), region)
$pf{T<:Real}(x::AbstractArray{T}, region; kws...) = $pf(complexfloat(x), region; kws...)
$f{T<:Union{Integer,Rational}}(x::AbstractArray{Complex{T}}, region=1:ndims(x)) = $f(complexfloat(x), region)
$pf{T<:Union{Integer,Rational}}(x::AbstractArray{Complex{T}}, region; kws...) = $pf(complexfloat(x), region; kws...)
end
end
rfft{T<:Union{Integer,Rational}}(x::AbstractArray{T}, region=1:ndims(x)) = rfft(realfloat(x), region)
plan_rfft(x::AbstractArray, region; kws...) = plan_rfft(realfloat(x), region; kws...)
# only require implementation to provide *(::Plan{T}, ::Array{T})
*{T}(p::Plan{T}, x::AbstractArray) = p * copy1(T, x)
# Implementations should also implement A_mul_B!(Y, plan, X) so as to support
# pre-allocated output arrays. We don't define * in terms of A_mul_B!
# generically here, however, because of subtleties for in-place and rfft plans.
##############################################################################
# To support inv, \, and A_ldiv_B!(y, p, x), we require Plan subtypes
# to have a pinv::Plan field, which caches the inverse plan, and which
# should be initially undefined. They should also implement
# plan_inv(p) to construct the inverse of a plan p.
# hack from @simonster (in #6193) to compute the return type of plan_inv
# without actually calling it or even constructing the empty arrays.
_pinv_type(p::Plan) = typeof([plan_inv(x) for x in typeof(p)[]])
pinv_type(p::Plan) = eltype(_pinv_type(p))
inv(p::Plan) =
isdefined(p, :pinv) ? p.pinv::pinv_type(p) : (p.pinv = plan_inv(p))
\(p::Plan, x::AbstractArray) = inv(p) * x
A_ldiv_B!(y::AbstractArray, p::Plan, x::AbstractArray) = A_mul_B!(y, inv(p), x)
##############################################################################
# implementations only need to provide the unnormalized backwards FFT,
# similar to FFTW, and we do the scaling generically to get the ifft:
type ScaledPlan{T,P,N} <: Plan{T}
p::P
scale::N # not T, to avoid unnecessary promotion to Complex
pinv::Plan
ScaledPlan(p, scale) = new(p, scale)
end
(::Type{ScaledPlan{T}}){T,P,N}(p::P, scale::N) = ScaledPlan{T,P,N}(p, scale)
ScaledPlan{T}(p::Plan{T}, scale::Number) = ScaledPlan{T}(p, scale)
ScaledPlan(p::ScaledPlan, α::Number) = ScaledPlan(p.p, p.scale * α)
size(p::ScaledPlan) = size(p.p)
show(io::IO, p::ScaledPlan) = print(io, p.scale, " * ", p.p)
summary(p::ScaledPlan) = string(p.scale, " * ", summary(p.p))
*(p::ScaledPlan, x::AbstractArray) = scale!(p.p * x, p.scale)
*(α::Number, p::Plan) = ScaledPlan(p, α)
*(p::Plan, α::Number) = ScaledPlan(p, α)
*(I::UniformScaling, p::ScaledPlan) = ScaledPlan(p, I.λ)
*(p::ScaledPlan, I::UniformScaling) = ScaledPlan(p, I.λ)
*(I::UniformScaling, p::Plan) = ScaledPlan(p, I.λ)
*(p::Plan, I::UniformScaling) = ScaledPlan(p, I.λ)
# Normalization for ifft, given unscaled bfft, is 1/prod(dimensions)
normalization(T, sz, region) = (one(T) / prod([sz...][[region...]]))::T
normalization(X, region) = normalization(real(eltype(X)), size(X), region)
plan_ifft(x::AbstractArray, region; kws...) =
ScaledPlan(plan_bfft(x, region; kws...), normalization(x, region))
plan_ifft!(x::AbstractArray, region; kws...) =
ScaledPlan(plan_bfft!(x, region; kws...), normalization(x, region))
plan_inv(p::ScaledPlan) = ScaledPlan(plan_inv(p.p), inv(p.scale))
A_mul_B!(y::AbstractArray, p::ScaledPlan, x::AbstractArray) =
scale!(p.scale, A_mul_B!(y, p.p, x))
##############################################################################
# Real-input DFTs are annoying because the output has a different size
# than the input if we want to gain the full factor-of-two(ish) savings
# For backward real-data transforms, we must specify the original length
# of the first dimension, since there is no reliable way to detect this
# from the data (we can't detect whether the dimension was originally even
# or odd).
for f in (:brfft, :irfft)
pf = Symbol("plan_", f)
@eval begin
$f(x::AbstractArray, d::Integer) = $pf(x, d) * x
$f(x::AbstractArray, d::Integer, region) = $pf(x, d, region) * x
$pf(x::AbstractArray, d::Integer;kws...) = $pf(x, d, 1:ndims(x);kws...)
end
end
for f in (:brfft, :irfft)
@eval begin
$f{T<:Real}(x::AbstractArray{T}, d::Integer, region=1:ndims(x)) = $f(complexfloat(x), d, region)
$f{T<:Union{Integer,Rational}}(x::AbstractArray{Complex{T}}, d::Integer, region=1:ndims(x)) = $f(complexfloat(x), d, region)
end
end
"""
irfft(A, d [, dims])
Inverse of [`rfft`](:func:`rfft`): for a complex array `A`, gives the corresponding real
array whose FFT yields `A` in the first half. As for [`rfft`](:func:`rfft`), `dims` is an
optional subset of dimensions to transform, defaulting to `1:ndims(A)`.
`d` is the length of the transformed real array along the `dims[1]` dimension, which must
satisfy `div(d,2)+1 == size(A,dims[1])`. (This parameter cannot be inferred from `size(A)`
since both `2*size(A,dims[1])-2` as well as `2*size(A,dims[1])-1` are valid sizes for the
transformed real array.)
"""
irfft
"""
brfft(A, d [, dims])
Similar to [`irfft`](:func:`irfft`) but computes an unnormalized inverse transform (similar
to [`bfft`](:func:`bfft`)), which must be divided by the product of the sizes of the
transformed dimensions (of the real output array) in order to obtain the inverse transform.
"""
brfft
function rfft_output_size(x::AbstractArray, region)
d1 = first(region)
osize = [size(x)...]
osize[d1] = osize[d1]>>1 + 1
return osize
end
function brfft_output_size(x::AbstractArray, d::Integer, region)
d1 = first(region)
osize = [size(x)...]
@assert osize[d1] == d>>1 + 1
osize[d1] = d
return osize
end
plan_irfft{T}(x::AbstractArray{Complex{T}}, d::Integer, region; kws...) =
ScaledPlan(plan_brfft(x, d, region; kws...),
normalization(T, brfft_output_size(x, d, region), region))
"""
plan_irfft(A, d [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Pre-plan an optimized inverse real-input FFT, similar to [`plan_rfft`](:func:`plan_rfft`)
except for [`irfft`](:func:`irfft`) and [`brfft`](:func:`brfft`), respectively. The first
three arguments have the same meaning as for [`irfft`](:func:`irfft`).
"""
plan_irfft
##############################################################################
export fftshift, ifftshift
fftshift(x) = circshift(x, div([size(x)...],2))
"""
fftshift(x)
Swap the first and second halves of each dimension of `x`.
"""
fftshift(x)
function fftshift(x,dim)
s = zeros(Int,ndims(x))
s[dim] = div(size(x,dim),2)
circshift(x, s)
end
"""
fftshift(x,dim)
Swap the first and second halves of the given dimension of array `x`.
"""
fftshift(x,dim)
ifftshift(x) = circshift(x, div([size(x)...],-2))
"""
ifftshift(x, [dim])
Undoes the effect of `fftshift`.
"""
ifftshift
function ifftshift(x,dim)
s = zeros(Int,ndims(x))
s[dim] = -div(size(x,dim),2)
circshift(x, s)
end
##############################################################################
# FFTW module (may move to an external package at some point):
if Base.USE_GPL_LIBS
@doc """
fft(A [, dims])
Performs a multidimensional FFT of the array `A`. The optional `dims` argument specifies an
iterable subset of dimensions (e.g. an integer, range, tuple, or array) to transform along.
Most efficient if the size of `A` along the transformed dimensions is a product of small
primes; see `nextprod()`. See also `plan_fft()` for even greater efficiency.
A one-dimensional FFT computes the one-dimensional discrete Fourier transform (DFT) as
defined by
```math
\\operatorname{DFT}(A)[k] =
\\sum_{n=1}^{\\operatorname{length}(A)}
\\exp\\left(-i\\frac{2\\pi
(n-1)(k-1)}{\\operatorname{length}(A)} \\right) A[n].
```
A multidimensional FFT simply performs this operation along each transformed dimension of `A`.
!!! note
* Julia starts FFTW up with 1 thread by default. Higher performance is usually possible by
increasing number of threads. Use `FFTW.set_num_threads(Sys.CPU_CORES)` to use as many
threads as cores on your system.
* This performs a multidimensional FFT by default. FFT libraries in other languages such as
Python and Octave perform a one-dimensional FFT along the first non-singleton dimension
of the array. This is worth noting while performing comparisons. For more details,
refer to the ["Noteworthy Differences from other Languages"](:ref:`man-noteworthy-differences`)
section of the manual.
""" ->
fft
include("fft/FFTW.jl")
importall .FFTW
export FFTW, dct, idct, dct!, idct!, plan_dct, plan_idct, plan_dct!, plan_idct!
end
##############################################################################
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
function _truncate_at_width_or_chars(str, width, chars="", truncmark="…")
truncwidth = strwidth(truncmark)
(width <= 0 || width < truncwidth) && return ""
wid = truncidx = lastidx = 0
idx = start(str)
while !done(str, idx)
lastidx = idx
c, idx = next(str, idx)
wid += charwidth(c)
wid >= width - truncwidth && truncidx == 0 && (truncidx = lastidx)
(wid >= width || c in chars) && break
end
lastidx != 0 && str[lastidx] in chars && (lastidx = prevind(str, lastidx))
truncidx == 0 && (truncidx = lastidx)
if lastidx < endof(str)
return String(SubString(str, 1, truncidx) * truncmark)
else
return String(str)
end
end
function show{K,V}(io::IO, t::Associative{K,V})
recur_io = IOContext(io, :SHOWN_SET => t)
limit::Bool = get(io, :limit, false)
if !haskey(io, :compact)
recur_io = IOContext(recur_io, :compact => true)
end
# show in a Julia-syntax-like form: Dict(k=>v, ...)
if isempty(t)
print(io, typeof(t), "()")
else
if isleaftype(K) && isleaftype(V)
print(io, typeof(t).name)
else
print(io, typeof(t))
end
print(io, '(')
if !show_circular(io, t)
first = true
n = 0
for pair in t
first || print(io, ',')
first = false
show(recur_io, pair)
n+=1
limit && n >= 10 && (print(io, "…"); break)
end
end
print(io, ')')
end
end
abstract AbstractSerializer
# Dict
# These can be changed, to trade off better performance for space
const global maxallowedprobe = 16
const global maxprobeshift = 6
_tablesz(x::Integer) = x < 16 ? 16 : one(x)<<((sizeof(x)<<3)-leading_zeros(x-1))
"""
Dict([itr])
`Dict{K,V}()` constructs a hash table with keys of type `K` and values of type `V`.
Given a single iterable argument, constructs a [`Dict`](:obj:`Dict`) whose key-value pairs
are taken from 2-tuples `(key,value)` generated by the argument.
```jldoctest
julia> Dict([("A", 1), ("B", 2)])
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
```
Alternatively, a sequence of pair arguments may be passed.
```jldoctest
julia> Dict("A"=>1, "B"=>2)
Dict{String,Int64} with 2 entries:
"B" => 2
"A" => 1
```
"""
type Dict{K,V} <: Associative{K,V}
slots::Array{UInt8,1}
keys::Array{K,1}
vals::Array{V,1}
ndel::Int
count::Int
age::UInt
idxfloor::Int # an index <= the indexes of all used slots
maxprobe::Int
function Dict()
n = 16
new(zeros(UInt8,n), Array{K,1}(n), Array{V,1}(n), 0, 0, 0, 1, 0)
end
function Dict(kv)
h = Dict{K,V}()
for (k,v) in kv
h[k] = v
end
return h
end
Dict(p::Pair) = setindex!(Dict{K,V}(), p.second, p.first)
function Dict(ps::Pair...)
h = Dict{K,V}()
sizehint!(h, length(ps))
for p in ps
h[p.first] = p.second
end
return h
end
function Dict(d::Dict{K,V})
if d.ndel > 0
rehash!(d)
end
@assert d.ndel == 0
new(copy(d.slots), copy(d.keys), copy(d.vals), 0, d.count, d.age, d.idxfloor,
d.maxprobe)
end
end
Dict() = Dict{Any,Any}()
Dict(kv::Tuple{}) = Dict()
copy(d::Dict) = Dict(d)
const AnyDict = Dict{Any,Any}
Dict{K,V}(ps::Pair{K,V}...) = Dict{K,V}(ps)
Dict{K }(ps::Pair{K}...,) = Dict{K,Any}(ps)
Dict{V }(ps::Pair{TypeVar(:K),V}...,) = Dict{Any,V}(ps)
Dict( ps::Pair...) = Dict{Any,Any}(ps)
function Dict(kv)
try
Base.dict_with_eltype(kv, eltype(kv))
catch e
if any(x->isempty(methods(x, (typeof(kv),))), [start, next, done]) ||
!all(x->isa(x,Union{Tuple,Pair}),kv)
throw(ArgumentError("Dict(kv): kv needs to be an iterator of tuples or pairs"))
else
rethrow(e)
end
end
end
dict_with_eltype{K,V}(kv, ::Type{Tuple{K,V}}) = Dict{K,V}(kv)
dict_with_eltype{K,V}(kv, ::Type{Pair{K,V}}) = Dict{K,V}(kv)
dict_with_eltype{K,V}(::Type{Pair{K,V}}) = Dict{K,V}()
dict_with_eltype(::Type) = Dict()
dict_with_eltype(kv, t) = grow_to!(dict_with_eltype(_default_eltype(typeof(kv))), kv)
# this is a special case due to (1) allowing both Pairs and Tuples as elements,
# and (2) Pair being invariant. a bit annoying.
function grow_to!(dest::Associative, itr)
out = grow_to!(similar(dest, Pair{Union{},Union{}}), itr, start(itr))
return isempty(out) ? dest : out
end
function grow_to!{K,V}(dest::Associative{K,V}, itr, st)
while !done(itr, st)
(k,v), st = next(itr, st)
if isa(k,K) && isa(v,V)
dest[k] = v
else
new = similar(dest, Pair{typejoin(K,typeof(k)), typejoin(V,typeof(v))})
copy!(new, dest)
new[k] = v
return grow_to!(new, itr, st)
end
end
return dest
end
similar{K,V}(d::Dict{K,V}) = Dict{K,V}()
similar{K,V}(d::Dict, ::Type{Pair{K,V}}) = Dict{K,V}()
# conversion between Dict types
function convert{K,V}(::Type{Dict{K,V}},d::Associative)
h = Dict{K,V}()
for (k,v) in d
ck = convert(K,k)
if !haskey(h,ck)
h[ck] = convert(V,v)
else
error("key collision during dictionary conversion")
end
end
return h
end
convert{K,V}(::Type{Dict{K,V}},d::Dict{K,V}) = d
hashindex(key, sz) = (((hash(key)%Int) & (sz-1)) + 1)::Int
isslotempty(h::Dict, i::Int) = h.slots[i] == 0x0
isslotfilled(h::Dict, i::Int) = h.slots[i] == 0x1
isslotmissing(h::Dict, i::Int) = h.slots[i] == 0x2
function rehash!{K,V}(h::Dict{K,V}, newsz = length(h.keys))
olds = h.slots
oldk = h.keys
oldv = h.vals
sz = length(olds)
newsz = _tablesz(newsz)
h.age += 1
h.idxfloor = 1
if h.count == 0
resize!(h.slots, newsz)
fill!(h.slots, 0)
resize!(h.keys, newsz)
resize!(h.vals, newsz)
h.ndel = 0
return h
end
slots = zeros(UInt8,newsz)
keys = Array{K,1}(newsz)
vals = Array{V,1}(newsz)
age0 = h.age
count = 0
maxprobe = h.maxprobe
for i = 1:sz
if olds[i] == 0x1
k = oldk[i]
v = oldv[i]
index0 = index = hashindex(k, newsz)
while slots[index] != 0
index = (index & (newsz-1)) + 1
end
probe = (index - index0) & (newsz-1)
probe > maxprobe && (maxprobe = probe)
slots[index] = 0x1
keys[index] = k
vals[index] = v
count += 1
if h.age != age0
# if `h` is changed by a finalizer, retry
return rehash!(h, newsz)
end
end
end
h.slots = slots
h.keys = keys
h.vals = vals
h.count = count
h.ndel = 0
h.maxprobe = maxprobe
@assert h.age == age0
return h
end
function sizehint!(d::Dict, newsz)
oldsz = length(d.slots)
if newsz <= oldsz
# todo: shrink
# be careful: rehash!() assumes everything fits. it was only designed
# for growing.
return d
end
# grow at least 25%
newsz = max(newsz, (oldsz*5)>>2)
rehash!(d, newsz)
end
function empty!{K,V}(h::Dict{K,V})
fill!(h.slots, 0x0)
sz = length(h.slots)
empty!(h.keys)
empty!(h.vals)
resize!(h.keys, sz)
resize!(h.vals, sz)
h.ndel = 0
h.count = 0
h.age += 1
h.idxfloor = 1
return h
end
# get the index where a key is stored, or -1 if not present
function ht_keyindex{K,V}(h::Dict{K,V}, key)
sz = length(h.keys)
iter = 0
maxprobe = h.maxprobe
index = hashindex(key, sz)
keys = h.keys
while true
if isslotempty(h,index)
break
end
if !isslotmissing(h,index) && (key === keys[index] || isequal(key,keys[index]))
return index
end
index = (index & (sz-1)) + 1
iter += 1
iter > maxprobe && break
end
return -1
end
# get the index where a key is stored, or -pos if not present
# and the key would be inserted at pos
# This version is for use by setindex! and get!
function ht_keyindex2{K,V}(h::Dict{K,V}, key)
age0 = h.age
sz = length(h.keys)
iter = 0
maxprobe = h.maxprobe
index = hashindex(key, sz)
avail = 0
keys = h.keys
while true
if isslotempty(h,index)
if avail < 0
return avail
end
return -index
end
if isslotmissing(h,index)
if avail == 0
# found an available slot, but need to keep scanning
# in case "key" already exists in a later collided slot.
avail = -index
end
elseif key === keys[index] || isequal(key, keys[index])
return index
end
index = (index & (sz-1)) + 1
iter += 1
iter > maxprobe && break
end
avail < 0 && return avail
maxallowed = max(maxallowedprobe, sz>>maxprobeshift)
# Check if key is not present, may need to keep searching to find slot
while iter < maxallowed
if !isslotfilled(h,index)
h.maxprobe = iter
return -index
end
index = (index & (sz-1)) + 1
iter += 1
end
rehash!(h, h.count > 64000 ? sz*2 : sz*4)
return ht_keyindex2(h, key)
end
function _setindex!(h::Dict, v, key, index)
h.slots[index] = 0x1
h.keys[index] = key
h.vals[index] = v
h.count += 1
h.age += 1
if index < h.idxfloor
h.idxfloor = index
end
sz = length(h.keys)
# Rehash now if necessary
if h.ndel >= ((3*sz)>>2) || h.count*3 > sz*2
# > 3/4 deleted or > 2/3 full
rehash!(h, h.count > 64000 ? h.count*2 : h.count*4)
end
end
function setindex!{K,V}(h::Dict{K,V}, v0, key0)
key = convert(K, key0)
if !isequal(key, key0)
throw(ArgumentError("$key0 is not a valid key for type $K"))
end
setindex!(h, v0, key)
end
function setindex!{K,V}(h::Dict{K,V}, v0, key::K)
v = convert(V, v0)
index = ht_keyindex2(h, key)
if index > 0
h.age += 1
h.keys[index] = key
h.vals[index] = v
else
_setindex!(h, v, key, -index)
end
return h
end
get!{K,V}(h::Dict{K,V}, key0, default) = get!(()->default, h, key0)
function get!{K,V}(default::Callable, h::Dict{K,V}, key0)
key = convert(K, key0)
if !isequal(key, key0)
throw(ArgumentError("$key0 is not a valid key for type $K"))
end
return get!(default, h, key)
end
function get!{K,V}(default::Callable, h::Dict{K,V}, key::K)
index = ht_keyindex2(h, key)
index > 0 && return h.vals[index]
age0 = h.age
v = convert(V, default())
if h.age != age0
index = ht_keyindex2(h, key)
end
if index > 0
h.age += 1
h.keys[index] = key
h.vals[index] = v
else
_setindex!(h, v, key, -index)
end
return v
end
# NOTE: this macro is trivial, and should
# therefore not be exported as-is: it's for internal use only.
macro get!(h, key0, default)
return quote
get!(()->$(esc(default)), $(esc(h)), $(esc(key0)))
end
end
function getindex{K,V}(h::Dict{K,V}, key)
index = ht_keyindex(h, key)
return (index < 0) ? throw(KeyError(key)) : h.vals[index]::V
end
function get{K,V}(h::Dict{K,V}, key, default)
index = ht_keyindex(h, key)
return (index < 0) ? default : h.vals[index]::V
end
function get{K,V}(default::Callable, h::Dict{K,V}, key)
index = ht_keyindex(h, key)
return (index < 0) ? default() : h.vals[index]::V
end
"""
haskey(collection, key) -> Bool
Determine whether a collection has a mapping for a given key.
```jldoctest
julia> a = Dict('a'=>2, 'b'=>3)
Dict{Char,Int64} with 2 entries:
'b' => 3
'a' => 2
julia> haskey(a,'a')
true
julia> haskey(a,'c')
false
```
"""
haskey(h::Dict, key) = (ht_keyindex(h, key) >= 0)
in{T<:Dict}(key, v::KeyIterator{T}) = (ht_keyindex(v.dict, key) >= 0)
"""
getkey(collection, key, default)
Return the key matching argument `key` if one exists in `collection`, otherwise return `default`.
```jldoctest
julia> a = Dict('a'=>2, 'b'=>3)
Dict{Char,Int64} with 2 entries:
'b' => 3
'a' => 2
julia> getkey(a,'a',1)
'a'
julia> getkey(a,'d','a')
'a'
```
"""
function getkey{K,V}(h::Dict{K,V}, key, default)
index = ht_keyindex(h, key)
return (index<0) ? default : h.keys[index]::K
end
function _pop!(h::Dict, index)
val = h.vals[index]
_delete!(h, index)
return val
end
function pop!(h::Dict, key)
index = ht_keyindex(h, key)
return index > 0 ? _pop!(h, index) : throw(KeyError(key))
end
function pop!(h::Dict, key, default)
index = ht_keyindex(h, key)
return index > 0 ? _pop!(h, index) : default
end
function _delete!(h::Dict, index)
h.slots[index] = 0x2
ccall(:jl_arrayunset, Void, (Any, UInt), h.keys, index-1)
ccall(:jl_arrayunset, Void, (Any, UInt), h.vals, index-1)
h.ndel += 1
h.count -= 1
h.age += 1
return h
end
function delete!(h::Dict, key)
index = ht_keyindex(h, key)
if index > 0
_delete!(h, index)
end
return h
end
function skip_deleted(h::Dict, i)
L = length(h.slots)
while i<=L && !isslotfilled(h,i)
i += 1
end
return i
end
function start(t::Dict)
i = skip_deleted(t, t.idxfloor)
t.idxfloor = i
return i
end
done(t::Dict, i) = i > length(t.vals)
next{K,V}(t::Dict{K,V}, i) = (Pair{K,V}(t.keys[i],t.vals[i]), skip_deleted(t,i+1))
isempty(t::Dict) = (t.count == 0)
length(t::Dict) = t.count
next{T<:Dict}(v::KeyIterator{T}, i) = (v.dict.keys[i], skip_deleted(v.dict,i+1))
next{T<:Dict}(v::ValueIterator{T}, i) = (v.dict.vals[i], skip_deleted(v.dict,i+1))
# For these Associative types, it is safe to implement filter!
# by deleting keys during iteration.
function filter!(f, d::Union{ObjectIdDict,Dict})
for (k,v) in d
if !f(k,v)
delete!(d,k)
end
end
return d
end
immutable ImmutableDict{K, V} <: Associative{K,V}
parent::ImmutableDict{K, V}
key::K
value::V
ImmutableDict() = new() # represents an empty dictionary
ImmutableDict(key, value) = (empty = new(); new(empty, key, value))
ImmutableDict(parent::ImmutableDict, key, value) = new(parent, key, value)
end
"""
ImmutableDict
ImmutableDict is a Dictionary implemented as an immutable linked list,
which is optimal for small dictionaries that are constructed over many individual insertions
Note that it is not possible to remove a value, although it can be partially overridden and hidden
by inserting a new value with the same key
ImmutableDict(KV::Pair)
Create a new entry in the Immutable Dictionary for the key => value pair
- use `(key => value) in dict` to see if this particular combination is in the properties set
- use `get(dict, key, default)` to retrieve the most recent value for a particular key
"""
ImmutableDict
ImmutableDict{K,V}(KV::Pair{K,V}) = ImmutableDict{K,V}(KV[1], KV[2])
ImmutableDict{K,V}(t::ImmutableDict{K,V}, KV::Pair) = ImmutableDict{K,V}(t, KV[1], KV[2])
function in(key_value::Pair, dict::ImmutableDict, valcmp=(==))
key, value = key_value
while isdefined(dict, :parent)
if dict.key == key
valcmp(value, dict.value) && return true
end
dict = dict.parent
end
return false
end
function haskey(dict::ImmutableDict, key)
while isdefined(dict, :parent)
dict.key == key && return true
dict = dict.parent
end
return false
end
function getindex(dict::ImmutableDict, key)
while isdefined(dict, :parent)
dict.key == key && return dict.value
dict = dict.parent
end
throw(KeyError(key))
end
function get(dict::ImmutableDict, key, default)
while isdefined(dict, :parent)
dict.key == key && return dict.value
dict = dict.parent
end
return default
end
# this actually defines reverse iteration (e.g. it should not be used for merge/copy/filter type operations)
start(t::ImmutableDict) = t
next{K,V}(::ImmutableDict{K,V}, t) = (Pair{K,V}(t.key, t.value), t.parent)
done(::ImmutableDict, t) = !isdefined(t, :parent)
length(t::ImmutableDict) = count(x->1, t)
isempty(t::ImmutableDict) = done(t, start(t))
function similar(t::ImmutableDict)
while isdefined(t, :parent)
t = t.parent
end
return t
end
_similar_for{P<:Pair}(c::Dict, ::Type{P}, itr, isz) = similar(c, P)
_similar_for(c::Associative, T, itr, isz) = throw(ArgumentError("for Associatives, similar requires an element type of Pair;\n if calling map, consider a comprehension instead"))
# This file is a part of Julia. License is MIT: http://julialang.org/license
module BaseDocs
immutable Keyword
name :: Symbol
end
macro kw_str(text) Keyword(Symbol(text)) end
"Hello, Human."
kw"hello", kw"hi"
"""
**Welcome to Julia $(string(VERSION)).** The full manual is available at
http://docs.julialang.org/
as well many great tutorials and learning resources:
http://julialang.org/learning/
For help on a specific function or macro, type `?` followed
by its name, e.g. `?fft`, or `?@time`, and press enter.
"""
kw"help", kw"?", kw"julia"
"""
`using` will load the given module or package and make some of its names available for
use (see also `export`). For example:
using Gadfly
loads the plotting package, Gadfly, so that the `plot` function can be used.
Names can be used via dot syntax, whether they are exported or not:
Gadfly.plot(...)
If you don't want to use the packages exports directly, see also `import`. If you're not
sure, `using` is almost definitely what you want.
"""
kw"using"
"""
import Gadfly
`import`, like `using`, will load modules and packages for use. Unlike `using`, however,
it will *not* make any `export`ed names available for use. To use Gadfly's `plot`
function after importing it, for example, you have to write:
Gadfly.plot(...)
Import can also be used with specific names, for example
import Gadfly: plot, render
This syntax is used when you want to extend the modules functions with new methods.
"""
kw"import"
"""
`export` is used within modules and packages to tell Julia which functions should be
made available to the user. For example:
module Test
export foo # foo is exported, but bar isn't
foo(x) = x
bar(y) = y
end
using Test
foo(1) # 1
bar(1) # Error: bar not defined
Test.bar(1) # 1
"""
kw"export"
"""
`abstract` declares a type that cannot be instantiated, and serves only as a node in the
type graph, thereby describing sets of related concrete types: those concrete types
which are their descendants. Abstract types form the conceptual hierarchy which makes
Julia’s type system more than just a collection of object implementations. For example:
abstract Number
abstract Real <: Number
`abstract Number` has no supertype, whereas `abstract Real` is an abstract subtype of `Number`.
"""
kw"abstract"
"""
`module` declares a Module, which is a separate global variable workspace. Within a
module, you can control which names from other modules are visible (via importing), and
specify which of your names are intended to be public (via exporting). For example:
module
import Base.show
export MyType, foo
type MyType
x
end
bar(x) = 2x
foo(a::MyType) = bar(a.x) + 1
show(io, a::MyType) = print(io, "MyType \$(a.x)")
end
Modules allow you to create top-level definitions without worrying about name conflicts
when your code is used together with somebody else’s.
"""
kw"module"
"""
`baremodule` declares a module that does not contain `using Base`
or a definition of `eval`. It does still import `Core`.
"""
kw"baremodule"
"""
`bitstype` declares a concrete type whose data consists of plain old bits. Classic
examples of bits types are integers and floating-point values. Some example built-in
bits type declarations:
bitstype 32 Char
bitstype 8 Bool <: Integer
The first parameter indicates how many bits of storage the type requires. Currently,
only sizes that are multiples of 8 bits are supported. The second parameter gives the
name of the type. The `Bool` declaration shows how a bits type can be optionally
declared to be a subtype of some supertype.
"""
kw"bitstype"
"""
`macro` defines a method to include generated code in the final body of a program. A
macro maps a tuple of arguments to a returned expression, and the resulting expression
is compiled directly rather than requiring a runtime `eval()` call. Macro arguments may
include expressions, literal values, and symbols. For example:
macro sayhello(name)
return :( println("Hello, ", \$name) )
end
This macro takes one argument: `name`. When `@sayhello` is encountered, the quoted
expression is expanded to interpolate the value of the argument into the final
expression.
"""
kw"macro"
"""
`importall` imports all names exported by the specified module, as if `import` were used
individually on all of them. For example:
importall Distributions
As with `import`, functions imported by `importall` can be extended.
"""
kw"importall"
"""
`local` introduces a new local variable. For example:
function foo(n)
x = 0
for i = 1:n
local x
x = i
end
x
end
julia> foo(10)
0
Here `local x` introduces a separate `x` inside the loop, so the function returns `0`.
"""
kw"local"
"""
`global x` makes `x` in the current scope and its inner scopes refer to the global
variable of that name. In the example below, `global` is needed so the function can
modify the global variable `z`:
z=3
function foo()
global z=6
end
julia> foo()
6
julia> z
6
Without the `global` declaration in `foo()`, a new local variable would have been
created inside foo(), and the `z` in the global scope would have remained equal to `3`.
"""
kw"global"
"""
`let` statements allocate new variable bindings each time they run. Whereas an
assignment modifies an existing value location, `let` creates new locations. This
difference is only detectable in the case of variables that outlive their scope via
closures. The `let` syntax accepts a comma-separated series of assignments and variable
names:
let var1 = value1, var2, var3 = value3
code
end
The assignments are evaluated in order, with each right-hand side evaluated in the scope
before the new variable on the left-hand side has been introduced. Therefore it makes
sense to write something like `let x = x`, since the two `x` variables are distinct and
have separate storage.
"""
kw"let"
"""
`quote` creates multiple expression objects in a block without using the explicit `Expr`
constructor. For example:
ex = quote
x = 1
y = 2
x + y
end
Unlike the other means of quoting, `:( ... )`, this form introduces `QuoteNode` elements
to the expression tree, which must be considered when directly manipulating the tree.
For other purposes, `:( ... )` and `quote .. end` blocks are treated identically.
"""
kw"quote"
"""
`'` is the conjugate transposition operator:
julia> A = reshape(1:4, 2,2)
2×2 Array{Int64,2}:
1 3
2 4
julia> A'
2×2 Array{Int64,2}:
1 2
3 4
julia> B = A + im
2×2 Array{Complex{Int64},2}:
1+1im 3+1im
2+1im 4+1im
julia> B'
2×2 Array{Complex{Int64},2}:
1-1im 2-1im
3-1im 4-1im
"""
kw"'"
"""
`.'` is the transposition operator:
julia> A = reshape(1:4, 2,2)
2×2 Array{Int64,2}:
1 3
2 4
julia> A.'
2×2 Array{Int64,2}:
1 2
3 4
julia> B = A + im
2×2 Array{Complex{Int64},2}:
1+1im 3+1im
2+1im 4+1im
julia> B.'
2×2 Array{Complex{Int64},2}:
1+1im 2+1im
3+1im 4+1im
"""
kw".'"
"""
`const` is used to declare global variables which are also constant. In almost all code
(and particularly performance sensitive code) global variables should be declared
constant in this way.
const x = 5
Note that "constant-ness" is not enforced inside containers, so if `x` is an array or
dictionary (for example) you can still add and remove elements.
Technically, you can even redefine `const` variables, although this will generate a
warning from the compiler. The only strict requirement is that the *type* of the
variable does not change, which is why `const` variables are much faster than regular
globals.
"""
kw"const"
"""
Functions are defined with the `function` keyword:
function add(a, b)
return a + b
end
Or the short form notation:
add(a, b) = a + b
The use of the `return` keyword is exactly the same as in other languages, but is often
optional. When it's not used, the last expression in the function body will be returned
by default:
function compare(a, b)
a == b && return "equal to"
a < b ? "less than" : "greater than"
end
"""
kw"function"
"""
`return` can be used function bodies to exit early and return a given value, e.g.
function compare(a, b)
a == b && return "equal to"
a < b ? "less than" : "greater than"
end
In general you can place a `return` statement anywhere within a function body, including
within deeply nested loops or conditionals, but be careful with `do` blocks. For
example:
function test1(xs)
for x in xs
iseven(x) && return 2x
end
end
function test2(xs)
map(xs) do x
iseven(x) && return 2x
x
end
end
In the first example, the return breaks out of its enclosing function as soon as it hits
an even number, so `test1([5,6,7])` returns `12`.
You might expect the second example to behave the same way, but in fact the `return`
there only breaks out of the *inner* function (inside the `do` block) and gives a value
back to `map`. `test2([5,6,7])` then returns `[5,12,7]`.
"""
kw"return"
"""
`if`-`elseif`-`else` performs conditional evaluation, which allows portions of code to
be evaluated or not evaluated depending on the value of a boolean expression. Here is
the anatomy of the `if`-`elseif`-`else` conditional syntax:
if x < y
println("x is less than y")
elseif x > y
println("x is greater than y")
else
println("x is equal to y")
end
If the condition expression `x < y` is true, then the corresponding block is evaluated;
otherwise the condition expression `x > y` is evaluated, and if it is true, the
corresponding block is evaluated; if neither expression is true, the `else` block is
evaluated. The `elseif` and `else` blocks are optional, and as many `elseif` blocks as
desired can be used.
"""
kw"if", kw"elseif", kw"else"
"""
`for` loops repeatedly evaluate the body of the loop by iterating over a sequence of
values. For example:
for i in [1,4,0]
println(i)
end
"""
kw"for"
"""
`while` loops repeatedly evaluate a conditional expression, and continues evaluating the
body of the while loop so long as the expression remains `true`. If the condition
expression is false when the while loop is first reached, the body is never evaluated.
For example:
while i <= 5
println(i)
i += 1
end
"""
kw"while"
"""
`end` marks the conclusion of a block of expressions. In the example below, `end` marks
the conclusion of a `function`.
function foo()
println("hello, world")
end
`end` marks the conclusion of all kinds of expression blocks: `module`, `type`, `begin`,
`let`, `for`, etc.
In addition, `end` may be used when indexing into an array to represent the last index
of each dimension:
x[1:end, 2:end-1]
"""
kw"end"
"""
A `try/catch` statement allows for `Exception`s to be tested for. For example, a
customized square root function can be written to automatically call either the real or
complex square root method on demand using `Exception`s:
f(x) = try
sqrt(x)
catch
sqrt(complex(x, 0))
end
`try/catch` statements also allow the `Exception` to be saved in a variable, e.g. `catch y`.
The `catch` clause is not strictly necessary; when omitted, the default return value is
`nothing`. The power of the `try/catch` construct lies in the ability to unwind a deeply
nested computation immediately to a much higher level in the stack of calling functions.
"""
kw"try", kw"catch"
"""
`finally` provides a way to run some code when a given block of code exits, regardless
of how it exits. For example, here is how we can guarantee that an opened file is
closed:
f = open("file")
try
operate_on_file(f)
finally
close(f)
end
When control leaves the `try` block (for example due to a `return`, or just finishing
normally), `close(f)` will be executed. If the `try` block exits due to an exception,
the exception will continue propagating. A `catch` block may be combined with `try` and
`finally` as well. In this case the `finally` block will run after `catch` has handled
the error.
"""
kw"finally"
"""
`break` breaks out of a loop immediately. For example
i = 0
while true
i += 1
i > 10 && break
println(i)
end
prints the numbers 1 to 10.
"""
kw"break"
"""
`continue` skips the rest of the current loop, then carries on looping. For example
for i = 1:10
iseven(i) && continue
println(i)
end
prints the numbers 1, 3, 5..., skipping the even numbers.
"""
kw"continue"
"""
The `do` keyword creates an anonymous function. For example
map(1:10) do x
2x
end
is equivalent to `map(x->2x, 1:10)`.
Use multiple arguments like so:
map(1:10, 11:20) do x, y
x + y
end
"""
kw"do"
"""
The "splat" operator, `...`, represents a sequence of arguments. For example
add(xs...) = reduce(+, xs)
can take any number of arguments:
add(1, 2, 3, 4, 5)
`...` can also be used to apply a function to a sequence of arguments like so:
add([1, 2, 3]...) # 6
add(7, 1:100..., 1000:1100...) # 111107
"""
kw"..."
"""
`;` has a similar role in Julia as in many C-like languages, and is used to delimit the
end of the previous statement. `;` is not necessary after new lines, but can be used to
separate statements on a single line or to join statements into a single expression:
function foo()
println("Hello, "); println("World!")
return true
end
foo() = (println("Hello, World!"); true)
`;` is also used to suppress output in the REPL and similar interfaces.
"""
kw";"
"""
x && y
Short-circuiting boolean AND.
"""
kw"&&"
"""
x || y
Short-circuiting boolean OR.
"""
kw"||"
"""
ccall((symbol, library) or function_pointer, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
Call function in C-exported shared library, specified by `(function name, library)`
tuple, where each component is a string or symbol.
Note that the argument type tuple must be a literal tuple, and not a tuple-valued
variable or expression. Alternatively, `ccall` may also be used to call a function
pointer, such as one returned by `dlsym`.
Each `ArgumentValue` to the `ccall` will be converted to the corresponding
`ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType,
cconvert(ArgumentType, ArgumentValue))`. (See also the documentation for each of these
functions for further details.) In most cases, this simply results in a call to
`convert(ArgumentType, ArgumentValue)`.
"""
kw"ccall"
"""
llvmcall(IR::String, ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
llvmcall((declarations::String, IR::String), ReturnType, (ArgumentType1, ...), ArgumentValue1, ...)
Call LLVM IR string in the first argument. Similar to an LLVM function `define` block,
arguments are available as consecutive unnamed SSA variables (%0, %1, etc.).
The optional declarations string contains external functions declarations that are
necessary for llvm to compile the IR string. Multiple declarations can be passed in by
separating them with line breaks.
Note that the argument type tuple must be a literal tuple, and not a tuple-valued
variable or expression.
Each `ArgumentValue` to `llvmcall` will be converted to the corresponding
`ArgumentType`, by automatic insertion of calls to `unsafe_convert(ArgumentType,
cconvert(ArgumentType, ArgumentValue))`. (see also the documentation for each of these
functions for further details). In most cases, this simply results in a call to
`convert(ArgumentType, ArgumentValue)`.
See `test/llvmcall.jl` for usage examples.
"""
Core.Intrinsics.llvmcall
"""
`begin...end` denotes a block of code.
begin
println("Hello, ")
println("World!")
end
Usually `begin` will not be necessary, since keywords such as `function` and `let`
implicitly begin blocks of code. See also `;`.
"""
kw"begin"
"""
At their most basic, Julia types are specified as a name and a set of fields.
type Point
x
y
end
Fields can have type restrictions, which may be parametrised:
type Point{X}
x::X
y::Float64
end
Type can also declare an abstract super type via `<:` syntax:
type Point <: AbstractPoint
...
See the manual for more details, such as information on inner constructors.
"""
kw"type"
"""
Introduce a new name for an already expressible type. For example, in `base/boot.jl`,
`UInt` is type aliased to either `UInt64` or `UInt32` as appropriate for the size of
pointers on the system:
if Int === Int64
typealias UInt UInt64
else
typealias UInt UInt32
end
For parametric types, `typealias` can be convenient for providing names in cases where
some parameter choices are fixed. In `base` for example:
typealias Vector{T} Array{T,1}
"""
kw"typealias"
"""
`immutable` acts in the same way as `type`, but declares that the fields of the type may
not be set after construction. See `type` and the manual for more information.
"""
kw"immutable"
"""
@__LINE__ -> Int
`@__LINE__` expands to the line number of the call-site.
"""
kw"@__LINE__"
"""
ans
A variable referring to the last computed value, automatically set at the interactive prompt.
"""
kw"ans"
"""
nothing
The singleton instance of type `Void`, used by convention when there is no value to return
(as in a C `void` function). Can be converted to an empty `Nullable` value.
"""
nothing
"""
ANY
Equivalent to `Any` for dispatch purposes, but signals the compiler to skip code
generation specialization for that field.
"""
ANY
"""
DevNull
Used in a stream redirect to discard all data written to it. Essentially equivalent to
/dev/null on Unix or NUL on Windows. Usage:
```julia
run(pipeline(`cat test.txt`, DevNull))
```
"""
DevNull
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
export @var
immutable Binding
mod::Module
var::Symbol
function Binding(m::Module, v::Symbol)
# Normalise the binding module for module symbols so that:
# Binding(Base, :Base) === Binding(Main, :Base)
m = module_name(m) === v ? module_parent(m) : m
new(Base.binding_module(m, v), v)
end
end
bindingexpr(x) = Expr(:call, Binding, splitexpr(x)...)
defined(b::Binding) = isdefined(b.mod, b.var)
resolve(b::Binding) = getfield(b.mod, b.var)
function splitexpr(x::Expr)
isexpr(x, :macrocall) ? splitexpr(x.args[1]) :
isexpr(x, :.) ? (x.args[1], x.args[2]) :
error("Invalid @var syntax `$x`.")
end
splitexpr(s::Symbol) = Expr(:call, current_module), quot(s)
splitexpr(other) = error("Invalid @var syntax `$other`.")
macro var(x)
esc(bindingexpr(x))
end
function Base.show(io::IO, b::Binding)
if b.mod === Main
print(io, b.var)
else
print(io, b.mod, '.', Base.isoperator(b.var) ? ":" : "", b.var)
end
end
aliasof(b::Binding) = defined(b) ? (a = aliasof(resolve(b), b); defined(a) ? a : b) : b
aliasof(d::DataType, b) = Binding(d.name.module, d.name.name)
aliasof(λ::Function, b) = (m = typeof(λ).name.mt; Binding(m.module, m.name))
aliasof(m::Module, b) = Binding(m, module_name(m))
aliasof(other, b) = b
# This file is a part of Julia. License is MIT: http://julialang.org/license
module CoreDocs
import ..esc, ..push!, ..getindex, ..current_module, ..unsafe_load, ..Csize_t
function doc!(str, ex)
ptr = unsafe_load(Core.Intrinsics.cglobal(:jl_filename, Ptr{UInt8}))
len = ccall(:strlen, Csize_t, (Ptr{UInt8},), ptr)
file = ccall(:jl_symbol_n, Any, (Ptr{UInt8}, Int32), ptr, len)
line = unsafe_load(Core.Intrinsics.cglobal(:jl_lineno, Int32)) # Cint
push!(DOCS, (current_module(), ex, str, file, line))
end
const DOCS = Array{Any, 1}()
isexpr(x, h) = isa(x, Expr) && x.head === h
lazy_iterpolate(s::AbstractString) = Expr(:call, Core.svec, s)
lazy_iterpolate(x) = isexpr(x, :string) ? Expr(:call, Core.svec, x.args...) : x
function docm(str, x)
out = esc(Expr(:call, doc!, lazy_iterpolate(str), Expr(:quote, x)))
isexpr(x, :module) ? Expr(:toplevel, out, esc(x)) :
isexpr(x, :call) ? out : Expr(:block, esc(x), out)
end
docm(x) = isexpr(x, :->) ? docm(x.args[1], x.args[2].args[2]) : error("invalid '@doc'.")
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
"""
The Docs module provides the `@doc` macro which can be used to set and retrieve
documentation metadata for Julia objects. Please see docs for the `@doc` macro for more
information.
"""
module Docs
"""
# Documentation
Functions, methods and types can be documented by placing a string before the definition:
\"""
# The Foo Function
`foo(x)`: Foo the living hell out of `x`.
\"""
foo(x) = ...
The `@doc` macro can be used directly to both set and retrieve documentation / metadata. By
default, documentation is written as Markdown, but any object can be placed before the
arrow. For example:
@doc "blah" ->
function foo() ...
The `->` is not required if the object is on the same line, e.g.
@doc "foo" foo
## Documenting objects after they are defined
You can document an object after its definition by
@doc "foo" function_to_doc
@doc "bar" TypeToDoc
For macros, the syntax is `@doc "macro doc" :(@Module.macro)` or `@doc "macro doc"
:(string_macro"")` for string macros. Without the quote `:()` the expansion of the macro
will be documented.
## Retrieving Documentation
You can retrieve docs for functions, macros and other objects as follows:
@doc foo
@doc @time
@doc md""
## Functions & Methods
Placing documentation before a method definition (e.g. `function foo() ...` or `foo() = ...`)
will cause that specific method to be documented, as opposed to the whole function. Method
docs are concatenated together in the order they were defined to provide docs for the
function.
"""
:(Core.@doc)
include("bindings.jl")
import Base.Markdown: @doc_str, MD
import Base.Meta: quot, isexpr
import Base: Callable
import ..CoreDocs: lazy_iterpolate
export doc
# Basic API / Storage
const modules = Module[]
const META = gensym(:meta)
meta(m::Module = current_module()) = isdefined(m, META) ? getfield(m, META) : ObjectIdDict()
function initmeta(m::Module = current_module())
if !isdefined(m, META)
eval(m, :(const $META = $(ObjectIdDict())))
push!(modules, m)
end
nothing
end
function signature(expr::Expr)
if isexpr(expr, [:call, :macrocall])
sig = :(Union{Tuple{}})
for arg in expr.args[2:end]
isexpr(arg, :parameters) && continue
if isexpr(arg, :kw) # optional arg
push!(sig.args, :(Tuple{$(sig.args[end].args[2:end]...)}))
end
push!(sig.args[end].args, argtype(arg))
end
Expr(:let, Expr(:block, sig), typevars(expr)...)
else
signature(expr.args[1])
end
end
signature(other) = :(Union{})
function argtype(expr::Expr)
isexpr(expr, :(::)) && return expr.args[end]
isexpr(expr, :(...)) && return :(Vararg{$(argtype(expr.args[1]))})
argtype(expr.args[1])
end
argtype(other) = :Any
function typevars(expr::Expr)
isexpr(expr, :curly) && return [tvar(x) for x in expr.args[2:end]]
typevars(expr.args[1])
end
typevars(::Symbol) = []
tvar(x::Expr) = :($(x.args[1]) = TypeVar($(quot(x.args[1])), $(x.args[2]), true))
tvar(s::Symbol) = :($(s) = TypeVar($(quot(s)), Any, true))
# Docsystem types.
# ================
"""
Docs.DocStr
Stores the contents of a single docstring as well as related metadata.
Both the raw text, `.text`, and the parsed markdown, `.object`, are tracked by this type.
Parsing of the raw text is done lazily when a request is made to render the docstring,
which helps to reduce total precompiled image size.
The `.data` fields stores several values related to the docstring, such as: path,
linenumber, source code, and fielddocs.
"""
type DocStr
text :: Core.SimpleVector
object :: Nullable
data :: Dict{Symbol, Any}
end
function docstr(binding::Binding, typesig::ANY = Union{})
for m in modules
dict = meta(m)
if haskey(dict, binding)
docs = dict[binding].docs
if haskey(docs, typesig)
return docs[typesig]
end
end
end
error("could not find matching docstring for '$binding :: $typesig'.")
end
docstr(object, data = Dict()) = _docstr(object, data)
_docstr(vec::Core.SimpleVector, data) = DocStr(vec, Nullable(), data)
_docstr(str::AbstractString, data) = DocStr(Core.svec(str), Nullable(), data)
_docstr(object, data) = DocStr(Core.svec(), Nullable(object), data)
_docstr(doc::DocStr, data) = (doc.data = merge(data, doc.data); doc)
macro ref(x)
binding = bindingexpr(namify(x))
typesig = signature(x)
esc(docexpr(binding, typesig))
end
docexpr(args...) = Expr(:call, docstr, args...)
function formatdoc(d::DocStr)
buffer = IOBuffer()
for part in d.text
formatdoc(buffer, d, part)
end
Markdown.parse(seekstart(buffer))
end
@noinline formatdoc(buffer, d, part) = print(buffer, part)
function parsedoc(d::DocStr)
if isnull(d.object)
md = formatdoc(d)
md.meta[:module] = d.data[:module]
md.meta[:path] = d.data[:path]
d.object = Nullable(md)
end
get(d.object)
end
"""
MultiDoc
Stores a collection of docstrings for related objects, ie. a `Function`/`DataType` and
associated `Method` objects.
Each documented object in a `MultiDoc` is referred to by it's signature which is represented
by a `Union` of `Tuple` types. For example the following `Method` definition
f(x, y) = ...
is stored as `Tuple{Any, Any}` in the `MultiDoc` while
f{T}(x::T, y = ?) = ...
is stored as `Union{Tuple{T}, Tuple{T, Any}}`.
Note: The `Function`/`DataType` object's signature is always `Union{}`.
"""
type MultiDoc
"Ordered (via definition order) vector of object signatures."
order::Vector{Type}
"Documentation for each object. Keys are signatures."
docs::ObjectIdDict
MultiDoc() = new(Type[], ObjectIdDict())
end
# Docstring registration.
# =======================
"""
Docs.doc!(binding, str, sig)
Adds a new docstring `str` to the docsystem for `binding` and signature `sig`.
"""
function doc!(b::Binding, str::DocStr, sig::ANY = Union{})
initmeta()
m = get!(meta(), b, MultiDoc())
if haskey(m.docs, sig)
# We allow for docstrings to be updated, but print a warning since it is possible
# that over-writing a docstring *may* have been accidental.
s = "replacing docs for '$b :: $sig' in module '$(current_module())'."
isdefined(Base, :STDERR) ? warn(s) : ccall(:jl_, Void, (Any,), "WARNING: $s")
else
# The ordering of docstrings for each Binding is defined by the order in which they
# are initially added. Replacing a specific docstring does not change it's ordering.
push!(m.order, sig)
end
m.docs[sig] = str
str.data[:binding] = b
str.data[:typesig] = sig
return b
end
# Docstring lookup.
# =================
"""
Docs.doc(binding, sig)
Returns all documentation that matches both `binding` and `sig`.
"""
function doc(binding::Binding, sig::Type = Union{})
results, groups = DocStr[], MultiDoc[]
# Lookup `binding` and `sig` for matches in all modules of the docsystem.
for mod in modules
dict = meta(mod)
if haskey(dict, binding)
multidoc = dict[binding]
push!(groups, multidoc)
for msig in multidoc.order
sig <: msig && push!(results, multidoc.docs[msig])
end
end
end
if isempty(groups)
# When no `MultiDoc`s are found that match `binding` then we check whether `binding`
# is an alias of some other `Binding`. When it is we then re-run `doc` with that
# `Binding`, otherwise if it's not an alias then we generate a summary for the
# `binding` and display that to the user instead.
alias = aliasof(binding)
alias == binding ? summarize(alias, sig) : doc(alias, sig)
else
# There was at least one match for `binding` while searching. If there weren't any
# matches for `sig` then we concatenate *all* the docs from the matching `Binding`s.
if isempty(results)
for group in groups, each in group.order
push!(results, group.docs[each])
end
end
# Get parsed docs and concatenate them.
md = catdoc(map(parsedoc, results)...)
# Save metadata in the generated markdown.
if isa(md, Markdown.MD)
md.meta[:results] = results
md.meta[:binding] = binding
md.meta[:typesig] = sig
end
return md
end
end
# Some additional convenience `doc` methods that take objects rather than `Binding`s.
doc(object, sig::Type = Union{}) = doc(aliasof(object, typeof(object)), sig)
doc(object, sig...) = doc(object, Tuple{sig...})
"""
Docs.fielddoc(binding, field)
Returns documentation for a particular `field` of a type if it exists.
"""
function fielddoc(binding::Binding, field::Symbol)
for mod in modules
dict = meta(mod)
if haskey(dict, binding)
multidoc = dict[binding]
if haskey(multidoc.docs, Union{})
fields = multidoc.docs[Union{}].data[:fields]
if haskey(fields, field)
doc = fields[field]
return isa(doc, Markdown.MD) ? doc : Markdown.parse(doc)
end
end
end
end
fields = join(["`$f`" for f in fieldnames(resolve(binding))], ", ", ", and ")
fields = isempty(fields) ? "no fields" : "fields $fields"
Markdown.parse("`$(resolve(binding))` has $fields.")
end
# As with the additional `doc` methods, this converts an object to a `Binding` first.
fielddoc(object, field::Symbol) = fielddoc(aliasof(object, typeof(object)), field)
# Object Summaries.
# =================
function summarize(binding::Binding, sig)
io = IOBuffer()
println(io, "No documentation found.\n")
if defined(binding)
summarize(io, resolve(binding), binding)
else
println(io, "Binding `", binding, "` does not exist.")
end
md = Markdown.parse(seekstart(io))
# Save metadata in the generated markdown.
md.meta[:results] = DocStr[]
md.meta[:binding] = binding
md.meta[:typesig] = sig
return md
end
function summarize(io::IO, λ::Function, binding)
kind = startswith(string(binding.var), '@') ? "macro" : "`Function`"
println(io, "`", binding, "` is a ", kind, ".")
println(io, "```\n", methods(λ), "\n```")
end
function summarize(io::IO, T::DataType, binding)
println(io, "**Summary:**")
println(io, "```")
println(io,
T.abstract ? "abstract" : T.mutable ? "type" : "immutable",
" ", T, " <: ", supertype(T)
)
println(io, "```")
if !isempty(fieldnames(T))
println(io, "**Fields:**")
println(io, "```")
pad = maximum(length(string(f)) for f in fieldnames(T))
for (f, t) in zip(fieldnames(T), T.types)
println(io, rpad(f, pad), " :: ", t)
end
println(io, "```")
end
if !isempty(subtypes(T))
println(io, "**Subtypes:**")
println(io, "```")
for t in subtypes(T)
println(io, t)
end
println(io, "```")
end
end
function summarize(io::IO, m::Module, binding)
readme = Pkg.dir(string(m), "README.md")
if isfile(readme)
println(io, "Displaying the `README.md` for the module instead.\n")
println(io, "---\n")
println(io, readstring(readme))
else
println(io, "No `README.md` found for module `", m, "`.\n")
end
end
function summarize{T}(io::IO, ::T, binding)
println(io, "`", binding, "` is of type `", T, "`.\n")
summarize(io, T, binding)
end
# Utilities.
# ==========
"""
`catdoc(xs...)`: Combine the documentation metadata `xs` into a single meta object.
"""
catdoc() = nothing
catdoc(xs...) = vcat(xs...)
const keywords = Dict{Symbol, DocStr}()
isdoc(s::AbstractString) = true
isdoc(x) = isexpr(x, :string) ||
(isexpr(x, :macrocall) && x.args[1] === Symbol("@doc_str")) ||
(isexpr(x, :call) && x.args[1] === Base.Markdown.doc_str)
function unblock(ex)
isexpr(ex, :block) || return ex
exs = filter(ex -> !(isa(ex, LineNumberNode) || isexpr(ex, :line)), ex.args)
length(exs) == 1 || return ex
return unblock(exs[1])
end
uncurly(ex) = isexpr(ex, :curly) ? ex.args[1] : ex
namify(x) = nameof(x, isexpr(x, :macro))
function nameof(x::Expr, ismacro)
if isexpr(x, :.)
ismacro ? macroname(x) : x
else
n = isexpr(x, [:module, :type, :bitstype]) ? 2 : 1
nameof(x.args[n], ismacro)
end
end
nameof(q::QuoteNode, ismacro) = nameof(q.value, ismacro)
nameof(s::Symbol, ismacro) = ismacro ? macroname(s) : s
nameof(other, ismacro) = other
macroname(s::Symbol) = Symbol('@', s)
macroname(x::Expr) = Expr(x.head, x.args[1], macroname(x.args[end].value))
isfield(x) = isexpr(x, :.) &&
(isa(x.args[1], Symbol) || isfield(x.args[1])) &&
(isa(x.args[2], QuoteNode) || isexpr(x.args[2], :quote))
# @doc expression builders.
# =========================
"""
Docs.metadata(expr)
Build a `Dict` expression containing metadata captured from the expression `expr`.
Fields that may be included in the returned `Dict`:
- `:path`: String representing the file where `expr` is defined.
- `:linenumber`: Linenumber where `expr` is defined.
- `:module`: Module where the docstring is defined.
- `:fields`: `Dict` of all field docs found in `expr`. Only for concrete types.
"""
function metadata(expr)
args = []
# Filename and linenumber of the docstring.
push!(args, :($(Pair)(:path, $(Base).@__FILE__)))
push!(args, :($(Pair)(:linenumber, $(unsafe_load(cglobal(:jl_lineno, Cint))))))
# Module in which the docstring is defined.
push!(args, :($(Pair)(:module, $(current_module)())))
# Field docs for concrete types.
if isexpr(expr, :type)
fields = []
tmp = nothing
for each in expr.args[3].args
if isdoc(each)
tmp = each
elseif tmp !== nothing && (isa(each, Symbol) || isexpr(each, :(::)))
push!(fields, (namify(each), tmp))
tmp = nothing
end
end
dict = :($(Dict)($([:($(Pair)($(quot(f)), $d)) for (f, d) in fields]...)))
push!(args, :($(Pair)(:fields, $dict)))
end
:($(Dict)($(args...)))
end
function keyworddoc(str, def)
docstr = esc(docexpr(lazy_iterpolate(str), metadata(def)))
:($(keywords)[$(esc(quot(def.name)))] = $docstr)
end
function objectdoc(str, def, expr, sig = :(Union{}))
binding = esc(bindingexpr(namify(expr)))
docstr = esc(docexpr(lazy_iterpolate(str), metadata(expr)))
quote
$(esc(def))
$(doc!)($binding, $docstr, $(esc(sig)))
end
end
function calldoc(str, def)
args = def.args[2:end]
if isempty(args) || all(validcall, args)
objectdoc(str, nothing, def, signature(def))
else
docerror(def)
end
end
validcall(x) = isa(x, Symbol) || isexpr(x, [:(::), :..., :kw, :parameters])
function moduledoc(meta, def, def′)
name = namify(def′)
docex = Expr(:call, doc!, bindingexpr(name),
docexpr(lazy_iterpolate(meta), metadata(name))
)
if def === nothing
esc(:(eval($name, $(quot(docex)))))
else
def = unblock(def)
block = def.args[3].args
if !def.args[1]
isempty(block) && error("empty baremodules are not documentable.")
insert!(block, 2, :(import Base: @doc))
end
push!(block, docex)
esc(Expr(:toplevel, def))
end
end
# Shares a single doc, `meta`, between several expressions from the tuple expression `ex`.
function multidoc(meta, ex, define)
out = Expr(:toplevel)
str = docexpr(lazy_iterpolate(meta), metadata(ex))
ref = Ref{DocStr}()
for (n, arg) in enumerate(ex.args)
# The first `arg` to be documented needs to also create the docstring for the group.
# Subsequent `arg`s just need `ref` to be able to find the docstring without having
# to create an entirely new one each.
docstr = n === 1 ? :($(ref)[] = $str) : :($(ref)[])
push!(out.args, :(@doc($docstr, $arg, $define)))
end
esc(out)
end
"""
@__doc__(ex)
Low-level macro used to mark expressions returned by a macro that should be documented. If
more than one expression is marked then the same docstring is applied to each expression.
macro example(f)
quote
\$(f)() = 0
@__doc__ \$(f)(x) = 1
\$(f)(x, y) = 2
end |> esc
end
`@__doc__` has no effect when a macro that uses it is not documented.
"""
:(Core.@__doc__)
function __doc__!(meta, def, define)
# Two cases must be handled here to avoid redefining all definitions contained in `def`:
if define
# `def` has not been defined yet (this is the common case, i.e. when not generating
# the Base image). We just need to convert each `@__doc__` marker to an `@doc`.
finddoc(def) do each
each.head = :macrocall
each.args = [Symbol("@doc"), meta, each.args[end], define]
end
else
# `def` has already been defined during Base image gen so we just need to find and
# document any subexpressions marked with `@__doc__`.
docs = []
found = finddoc(def) do each
push!(docs, :(@doc($meta, $(each.args[end]), $define)))
end
# If any subexpressions have been documented then replace the entire expression with
# just those documented subexpressions to avoid redefining any definitions.
if found
def.head = :toplevel
def.args = docs
end
found
end
end
# Walk expression tree `def` and call `λ` when any `@__doc__` markers are found. Returns
# `true` to signify that at least one `@__doc__` has been found, and `false` otherwise.
function finddoc(λ, def::Expr)
if isexpr(def, :block, 2) && isexpr(def.args[1], :meta, 1) && def.args[1].args[1] === :doc
# Found the macroexpansion of an `@__doc__` expression.
λ(def)
true
else
found = false
for each in def.args
found |= finddoc(λ, each)
end
found
end
end
finddoc(λ, def) = false
# Predicates and helpers for `docm` expression selection:
const FUNC_HEADS = [:function, :stagedfunction, :macro, :(=)]
const BINDING_HEADS = [:typealias, :const, :global, :(=)]
# For the special `:@mac` / `:(Base.@mac)` syntax for documenting a macro after definition.
isquotedmacrocall(x) =
isexpr(x, :copyast, 1) &&
isa(x.args[1], QuoteNode) &&
isexpr(x.args[1].value, :macrocall, 1)
# Simple expressions / atoms the may be documented.
isbasicdoc(x) = isexpr(x, :.) || isa(x, Union{QuoteNode, Symbol})
is_signature(x) = isexpr(x, :call) || (isexpr(x, :(::), 2) && isexpr(x.args[1], :call))
function docm(meta, ex, define = true)
# Some documented expressions may be decorated with macro calls which obscure the actual
# expression. Expand the macro calls and remove extra blocks.
x = unblock(macroexpand(ex))
# Don't try to redefine expressions. This is only needed for `Base` img gen since
# otherwise calling `loaddocs` would redefine all documented functions and types.
def = define ? x : nothing
# Keywords using the `@kw_str` macro in `base/docs/basedocs.jl`.
#
# "..."
# kw"if", kw"else"
#
isa(x, Base.BaseDocs.Keyword) ? keyworddoc(meta, x) :
# Method / macro definitions and "call" syntax.
#
# function f(...) ... end
# f(...) = ...
# macro m(...) end
# function f end
# f(...)
#
isexpr(x, FUNC_HEADS) && is_signature(x.args[1]) ? objectdoc(meta, def, x, signature(x)) :
isexpr(x, :function) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) :
isexpr(x, :call) ? calldoc(meta, x) :
# Type definitions.
#
# type T ... end
# abstract T
# bitstype N T
#
isexpr(x, [:type, :abstract, :bitstype]) ? objectdoc(meta, def, x) :
# "Bindings". Names that resolve to objects with different names, ie.
#
# typealias T S
# const T = S
# T = S
# global T = S
#
isexpr(x, BINDING_HEADS) && !isexpr(x.args[1], :call) ? objectdoc(meta, def, x) :
# Quoted macrocall syntax. `:@time` / `:(Base.@time)`.
isquotedmacrocall(x) ? objectdoc(meta, def, x) :
# Modules and baremodules.
isexpr(x, :module) ? moduledoc(meta, def, x) :
# Document several expressions with the same docstring. `a, b, c`.
isexpr(x, :tuple) ? multidoc(meta, x, define) :
# Errors generated by calling `macroexpand` are passed back to the call site.
isexpr(x, :error) ? esc(x) :
# When documenting macro-generated code we look for embedded `@__doc__` calls.
__doc__!(meta, x, define) ? esc(x) :
# Any "basic" expression such as a bare function or module name or numeric literal.
isbasicdoc(x) ? objectdoc(meta, nothing, x) :
# All other expressions are undocumentable and should be handled on a case-by-case basis
# with `@__doc__`. Unbound string literals are also undocumentable since they cannot be
# retrieved from the module's metadata `ObjectIdDict` without a reference to the string.
docerror(ex)
end
function docerror(ex)
txt = """
cannot document the following expression:
$(isa(ex, AbstractString) ? repr(ex) : ex)"""
if isexpr(ex, :macrocall)
txt *= "\n\n'$(ex.args[1])' not documentable. See 'Base.@__doc__' docs for details."
end
:($(error)($txt, "\n"))
end
function docm(ex)
if isexpr(ex, :->)
docm(ex.args...)
elseif haskey(keywords, ex)
parsedoc(keywords[ex])
elseif isa(ex, Union{Expr, Symbol})
binding = esc(bindingexpr(namify(ex)))
if isexpr(ex, [:call, :macrocall])
sig = esc(signature(ex))
:($(doc)($binding, $sig))
else
:($(doc)($binding))
end
else
:($(doc)($(typeof)($(esc(ex)))))
end
end
# MD support
catdoc(md::MD...) = MD(md...)
include("utils.jl")
# Swap out the bootstrap macro with the real one.
Core.atdoc!(docm)
function loaddocs(docs)
for (mod, ex, str, file, line) in docs
data = Dict(:path => string(file), :linenumber => line)
doc = docstr(str, data)
eval(mod, :(@doc($doc, $ex, false)))
end
empty!(docs)
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Base
"""
systemerror(sysfunc, iftrue)
Raises a `SystemError` for `errno` with the descriptive string `sysfunc` if `iftrue` is `true`
"""
systemerror
"""
fill!(A, x)
Fill array `A` with the value `x`. If `x` is an object reference, all elements will refer to
the same object. `fill!(A, Foo())` will return `A` filled with the result of evaluating
`Foo()` once.
"""
fill!
"""
read!(stream::IO, array::Union{Array, BitArray})
read!(filename::AbstractString, array::Union{Array, BitArray})
Read binary data from an I/O stream or file, filling in `array`.
"""
read!
"""
empty!(collection) -> collection
Remove all elements from a `collection`.
```jldoctest
julia> A = Dict("a" => 1, "b" => 2)
Dict{String,Int64} with 2 entries:
"b" => 2
"a" => 1
julia> empty!(A);
julia> A
Dict{String,Int64} with 0 entries
```
"""
empty!
"""
asin(x)
Compute the inverse sine of `x`, where the output is in radians.
"""
asin
"""
takebuf_array(b::IOBuffer)
Obtain the contents of an `IOBuffer` as an array, without copying. Afterwards, the
`IOBuffer` is reset to its initial state.
"""
takebuf_array
"""
pointer(array [, index])
Get the native address of an array or string element. Be careful to ensure that a Julia
reference to `a` exists as long as this pointer will be used. This function is "unsafe" like
`unsafe_convert`.
Calling `Ref(array[, index])` is generally preferable to this function.
"""
pointer
"""
//(num, den)
Divide two integers or rational numbers, giving a `Rational` result.
"""
Base.:(//)
"""
isinteger(x) -> Bool
Test whether `x` or all its elements are numerically equal to some integer.
```jldoctest
julia> isinteger(4.0)
true
julia> isinteger([1; 2; 5.5])
false
```
"""
isinteger
"""
./(x, y)
Element-wise right division operator.
```jldoctest
julia> [1 2 3] ./ [1 2 3]
1×3 Array{Float64,2}:
1.0 1.0 1.0
```
"""
Base.:(./)
"""
prod!(r, A)
Multiply elements of `A` over the singleton dimensions of `r`, and write results to `r`.
"""
prod!
"""
cummin(A, [dim])
Cumulative minimum along a dimension. The dimension defaults to 1.
"""
cummin
"""
minabs!(r, A)
Compute the minimum absolute values over the singleton dimensions of `r`, and write values to `r`.
"""
minabs!
"""
eigfact!(A, [B])
Same as [`eigfact`](:func:`eigfact`), but saves space by overwriting the input `A` (and
`B`), instead of creating a copy.
"""
eigfact!
"""
cosh(x)
Compute hyperbolic cosine of `x`.
"""
cosh
"""
precision(num::AbstractFloat)
Get the precision of a floating point number, as defined by the effective number of bits in
the mantissa.
"""
precision
"""
promote_type(type1, type2)
Determine a type big enough to hold values of each argument type without loss, whenever
possible. In some cases, where no type exists to which both types can be promoted
losslessly, some loss is tolerated; for example, `promote_type(Int64,Float64)` returns
`Float64` even though strictly, not all `Int64` values can be represented exactly as
`Float64` values.
"""
promote_type
"""
```
.*(x, y)
```
Element-wise multiplication operator.
```jldoctest
julia> [1 2 3] .* [1 2 3]
1×3 Array{Int64,2}:
1 4 9
```
"""
Base.:(.*)
"""
backtrace()
Get a backtrace object for the current program point.
"""
backtrace
"""
-(x)
Unary minus operator.
"""
-(x)
"""
-(x, y)
Subtraction operator.
"""
-(x, y)
"""
bits(n)
A string giving the literal bit representation of a number.
```jldoctest
julia> bits(4)
"0000000000000000000000000000000000000000000000000000000000000100"
julia> bits(2.2)
"0100000000000001100110011001100110011001100110011001100110011010"
```
"""
bits
"""
getindex(type[, elements...])
Construct a 1-d array of the specified type. This is usually called with the syntax
`Type[]`. Element values can be specified using `Type[a,b,c,...]`.
"""
getindex(::Type, elements...)
"""
getindex(A, inds...)
Returns a subset of array `A` as specified by `inds`, where each `ind` may be an
`Int`, a `Range`, or a `Vector`. See the manual section on
[array indexing](:ref:`array indexing <man-array-indexing>`) for details.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> getindex(A, 1)
1
julia> getindex(A, [2, 1])
2-element Array{Int64,1}:
3
1
julia> getindex(A, 2:4)
3-element Array{Int64,1}:
3
2
4
```
"""
getindex(::AbstractArray, inds...)
"""
getindex(collection, key...)
Retrieve the value(s) stored at the given key or index within a collection. The syntax
`a[i,j,...]` is converted by the compiler to `getindex(a, i, j, ...)`.
```jldoctest
julia> A = Dict("a" => 1, "b" => 2)
Dict{String,Int64} with 2 entries:
"b" => 2
"a" => 1
julia> getindex(A, "a")
1
```
"""
getindex(collection, key...)
"""
cconvert(T,x)
Convert `x` to a value of type `T`, typically by calling `convert(T,x)`
In cases where `x` cannot be safely converted to `T`, unlike [`convert`](:func:`convert`), `cconvert` may
return an object of a type different from `T`, which however is suitable for
[`unsafe_convert`](:func:`unsafe_convert`) to handle.
Neither `convert` nor `cconvert` should take a Julia object and turn it into a `Ptr`.
"""
cconvert
"""
assert(cond)
Throw an [`AssertionError`](:obj:`AssertionError`) if `cond` is `false`.
Also available as the macro `@assert expr`.
"""
assert
"""
sech(x)
Compute the hyperbolic secant of `x`
"""
sech
"""
acos(x)
Compute the inverse cosine of `x`, where the output is in radians
"""
acos
"""
unsafe_copy!(dest::Ptr{T}, src::Ptr{T}, N)
Copy `N` elements from a source pointer to a destination, with no checking. The size of an
element is determined by the type of the pointers.
The `unsafe` prefix on this function indicates that no validation is performed on the
pointers `dest` and `src` to ensure that they are valid. Incorrect usage may corrupt or
segfault your program, in the same manner as C.
"""
unsafe_copy!{T}(dest::Ptr{T}, src::Ptr{T}, N)
"""
unsafe_copy!(dest::Array, do, src::Array, so, N)
Copy `N` elements from a source array to a destination, starting at offset `so` in the
source and `do` in the destination (1-indexed).
The `unsafe` prefix on this function indicates that no validation is performed to ensure
that N is inbounds on either array. Incorrect usage may corrupt or segfault your program, in
the same manner as C.
"""
unsafe_copy!(dest::Array, d, src::Array, so, N)
"""
.^(x, y)
Element-wise exponentiation operator.
```jldoctest
julia> [1 2 3] .^ [1 2 3]
1×3 Array{Int64,2}:
1 4 27
```
"""
Base.:(.^)
"""
Float32(x [, mode::RoundingMode])
Create a Float32 from `x`. If `x` is not exactly representable then `mode` determines how
`x` is rounded.
```jldoctest
julia> Float32(1/3, RoundDown)
0.3333333f0
julia> Float32(1/3, RoundUp)
0.33333334f0
```
See [`RoundingMode`](:obj:`RoundingMode`) for available rounding modes.
"""
Float32
"""
Mmap.mmap(io::Union{IOStream,AbstractString,Mmap.AnonymousMmap}[, type::Type{Array{T,N}}, dims, offset]; grow::Bool=true, shared::Bool=true)
Mmap.mmap(type::Type{Array{T,N}}, dims)
Create an `Array` whose values are linked to a file, using memory-mapping. This provides a
convenient way of working with data too large to fit in the computer's memory.
The type is an `Array{T,N}` with a bits-type element of `T` and dimension `N` that
determines how the bytes of the array are interpreted. Note that the file must be stored in
binary format, and no format conversions are possible (this is a limitation of operating
systems, not Julia).
`dims` is a tuple or single `Integer` specifying the size or length of the array.
The file is passed via the stream argument, either as an open `IOStream` or filename string.
When you initialize the stream, use `"r"` for a "read-only" array, and `"w+"` to create a
new array used to write values to disk.
If no `type` argument is specified, the default is `Vector{UInt8}`.
Optionally, you can specify an offset (in bytes) if, for example, you want to skip over a
header in the file. The default value for the offset is the current stream position for an
`IOStream`.
The `grow` keyword argument specifies whether the disk file should be grown to accommodate
the requested size of array (if the total file size is < requested array size). Write
privileges are required to grow the file.
The `shared` keyword argument specifies whether the resulting `Array` and changes made to it
will be visible to other processes mapping the same file.
For example, the following code
```julia
# Create a file for mmapping
# (you could alternatively use mmap to do this step, too)
A = rand(1:20, 5, 30)
s = open("/tmp/mmap.bin", "w+")
# We'll write the dimensions of the array as the first two Ints in the file
write(s, size(A,1))
write(s, size(A,2))
# Now write the data
write(s, A)
close(s)
# Test by reading it back in
s = open("/tmp/mmap.bin") # default is read-only
m = read(s, Int)
n = read(s, Int)
A2 = Mmap.mmap(s, Matrix{Int}, (m,n))
```
creates a `m`-by-`n` `Matrix{Int}`, linked to the file associated with stream `s`.
A more portable file would need to encode the word size -- 32 bit or 64 bit -- and endianness
information in the header. In practice, consider encoding binary data using standard formats
like HDF5 (which can be used with memory-mapping).
"""
Mmap.mmap(io, ::Type, dims, offset)
"""
Mmap.mmap(io, BitArray, [dims, offset])
Create a `BitArray` whose values are linked to a file, using memory-mapping; it has the same
purpose, works in the same way, and has the same arguments, as [`mmap`](:func:`mmap`), but
the byte representation is different.
**Example**: `B = Mmap.mmap(s, BitArray, (25,30000))`
This would create a 25-by-30000 `BitArray`, linked to the file associated with stream `s`.
"""
Mmap.mmap(io, ::BitArray, dims = ?, offset = ?)
"""
bessely0(x)
Bessel function of the second kind of order 0, ``Y_0(x)``.
"""
bessely0
"""
any!(r, A)
Test whether any values in `A` along the singleton dimensions of `r` are `true`, and write
results to `r`.
"""
any!
"""
filter!(function, collection)
Update `collection`, removing elements for which `function` is `false`.
For associative collections, the function is passed two arguments (key and value).
```jldoctest
julia> filter!(isodd, collect(1:10))
5-element Array{Int64,1}:
1
3
5
7
9
```
"""
filter!
"""
sizeof(T)
Size, in bytes, of the canonical binary representation of the given DataType `T`, if any.
```jldoctest
julia> sizeof(Float32)
4
julia> sizeof(Complex128)
16
```
If `T` is not a bitstype, an error is thrown.
```jldoctest
julia> sizeof(Base.LinAlg.LU)
ERROR: argument is an abstract type; size is indeterminate
in sizeof(::Type{T}) at ./essentials.jl:89
...
```
"""
sizeof(::Type)
"""
ReadOnlyMemoryError()
An operation tried to write to memory that is read-only.
"""
ReadOnlyMemoryError
"""
last(coll)
Get the last element of an ordered collection, if it can be computed in O(1) time. This is
accomplished by calling [`endof`](:func:`endof`) to get the last index. Returns the end
point of a [`Range`](:obj:`Range`) even if it is empty.
```jldoctest
julia> last(1:2:10)
9
julia> last([1; 2; 3; 4])
4
```
"""
last
"""
sinh(x)
Compute hyperbolic sine of `x`.
"""
sinh
"""
ceil([T,] x, [digits, [base]])
`ceil(x)` returns the nearest integral value of the same type as `x` that is greater than or
equal to `x`.
`ceil(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is not
representable.
`digits` and `base` work as for [`round`](:func:`round`).
"""
ceil
"""
oftype(x, y)
Convert `y` to the type of `x` (`convert(typeof(x), y)`).
"""
oftype
"""
maxabs!(r, A)
Compute the maximum absolute values over the singleton dimensions of `r`, and write values to `r`.
"""
maxabs!
"""
isfinite(f) -> Bool
Test whether a number is finite.
```jldoctest
julia> isfinite(5)
true
julia> isfinite(NaN32)
false
```
"""
isfinite
"""
push!(collection, items...) -> collection
Insert one or more `items` at the end of `collection`.
```jldoctest
julia> push!([1, 2, 3], 4, 5, 6)
6-element Array{Int64,1}:
1
2
3
4
5
6
```
Use [`append!`](:func:`append!`) to add all the elements of another collection to
`collection`. The result of the preceding example is equivalent to `append!([1, 2, 3], [4,
5, 6])`.
"""
push!
"""
prevpow(a, x)
The largest `a^n` not greater than `x`, where `n` is a non-negative integer.
`a` must be greater than 1, and `x` must not be less than 1.
"""
prevpow
"""
promote(xs...)
Convert all arguments to their common promotion type (if any), and return them all (as a tuple).
"""
promote
"""
tan(x)
Compute tangent of `x`, where `x` is in radians.
"""
tan
"""
fd(stream)
Returns the file descriptor backing the stream or file. Note that this function only applies
to synchronous `File`'s and `IOStream`'s not to any of the asynchronous streams.
"""
fd
"""
ones(type, dims)
Create an array of all ones of specified type. The type defaults to `Float64` if not specified.
```jldoctest
julia> ones(Complex128, 2, 3)
2×3 Array{Complex{Float64},2}:
1.0+0.0im 1.0+0.0im 1.0+0.0im
1.0+0.0im 1.0+0.0im 1.0+0.0im
```
"""
ones(t,dims)
"""
ones(A)
Create an array of all ones with the same element type and shape as `A`.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> ones(A)
2×2 Array{Int64,2}:
1 1
1 1
```
"""
ones(A)
"""
reshape(A, dims)
Create an array with the same data as the given array, but with different dimensions.
```jldoctest
julia> A = collect(1:16)
16-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
julia> reshape(A, (2, 8))
2×8 Array{Int64,2}:
1 3 5 7 9 11 13 15
2 4 6 8 10 12 14 16
```
"""
reshape
"""
randsubseq!(S, A, p)
Like [`randsubseq`](:func:`randsubseq`), but the results are stored in `S`
(which is resized as needed).
"""
randsubseq!
"""
maximum(A, dims)
Compute the maximum value of an array over the given dimensions. See also the
[`max(a,b)`](:func:`max`) function to take the maximum of two or more arguments,
which can be applied elementwise to arrays via `max.(a,b)`.
"""
maximum(A,dims)
"""
redisplay(x)
redisplay(d::Display, x)
redisplay(mime, x)
redisplay(d::Display, mime, x)
By default, the `redisplay` functions simply call [`display`](:func:`display`).
However, some display backends may override `redisplay` to modify an existing
display of `x` (if any).
Using `redisplay` is also a hint to the backend that `x` may be redisplayed
several times, and the backend may choose to defer the display until
(for example) the next interactive prompt.
"""
redisplay
"""
searchsorted(a, x, [by=<transform>,] [lt=<comparison>,] [rev=false])
Returns the range of indices of `a` which compare as equal to `x` according to the order
specified by the `by`, `lt` and `rev` keywords, assuming that `a` is already sorted in that
order. Returns an empty range located at the insertion point if `a` does not contain values
equal to `x`.
"""
searchsorted
"""
/(x, y)
Right division operator: multiplication of `x` by the inverse of `y` on the right. Gives
floating-point results for integer arguments.
"""
Base.:(/)
"""
dump(x)
Show every part of the representation of a value.
"""
dump
"""
sumabs(A, dims)
Sum absolute values of elements of an array over the given dimensions.
"""
sumabs(A, dims)
"""
consume(task, values...)
Receive the next value passed to `produce` by the specified task. Additional arguments may
be passed, to be returned from the last `produce` call in the producer.
"""
consume
"""
cummax(A, [dim])
Cumulative maximum along a dimension. The dimension defaults to 1.
"""
cummax
"""
isinteractive() -> Bool
Determine whether Julia is running an interactive session.
"""
isinteractive
"""
sum!(r, A)
Sum elements of `A` over the singleton dimensions of `r`, and write results to `r`.
"""
sum!
"""
parentindexes(A)
From an array view `A`, returns the corresponding indexes in the parent.
"""
parentindexes
"""
display(x)
display(d::Display, x)
display(mime, x)
display(d::Display, mime, x)
Display `x` using the topmost applicable display in the display stack, typically using the
richest supported multimedia output for `x`, with plain-text [`STDOUT`](:obj:`STDOUT`) output as a fallback.
The `display(d, x)` variant attempts to display `x` on the given display `d` only, throwing
a `MethodError` if `d` cannot display objects of this type.
There are also two variants with a `mime` argument (a MIME type string, such as
`"image/png"`), which attempt to display `x` using the requested MIME type *only*, throwing
a `MethodError` if this type is not supported by either the display(s) or by `x`. With these
variants, one can also supply the "raw" data in the requested MIME type by passing
`x::AbstractString` (for MIME types with text-based storage, such as text/html or
application/postscript) or `x::Vector{UInt8}` (for binary MIME types).
"""
display
"""
@spawnat
Accepts two arguments, `p` and an expression. A closure is created around the expression and
run asynchronously on process `p`. Returns a [`Future`](:obj:`Future`) to the result.
"""
:@spawnat
"""
print_shortest(io, x)
Print the shortest possible representation, with the minimum number of consecutive non-zero
digits, of number `x`, ensuring that it would parse to the exact same number.
"""
print_shortest
"""
tuple(xs...)
Construct a tuple of the given objects.
"""
tuple
"""
eachmatch(r::Regex, s::AbstractString[, overlap::Bool=false])
Search for all matches of a the regular expression `r` in `s` and return a iterator over the
matches. If overlap is `true`, the matching sequences are allowed to overlap indices in the
original string, otherwise they must be from distinct character ranges.
"""
eachmatch
"""
log10(x)
Compute the logarithm of `x` to base 10.
Throws [`DomainError`](:obj:`DomainError`) for negative `Real` arguments.
```jldoctest
julia> log10(100)
2.0
julia> log10(2)
0.3010299956639812
```
"""
log10
"""
num2hex(f)
Get a hexadecimal string of the binary representation of a floating point number.
```jldoctest
julia> num2hex(2.2)
"400199999999999a"
```
"""
num2hex
"""
displayable(mime) -> Bool
displayable(d::Display, mime) -> Bool
Returns a boolean value indicating whether the given `mime` type (string) is displayable by
any of the displays in the current display stack, or specifically by the display `d` in the
second variant.
"""
displayable
"""
truncate(file,n)
Resize the file or buffer given by the first argument to exactly `n` bytes, filling
previously unallocated space with '\\0' if the file or buffer is grown.
"""
truncate
"""
exp10(x)
Compute ``10^x``.
```jldoctest
julia> exp10(2)
100.0
julia> exp10(0.2)
1.5848931924611136
```
"""
exp10
"""
&(x, y)
Bitwise and.
```jldoctest
julia> 4 & 10
0
julia> 4 & 12
4
```
"""
&
"""
cumsum!(B, A, [dim])
Cumulative sum of `A` along a dimension, storing the result in `B`. The dimension defaults
to 1.
"""
cumsum!
"""
select(v, k, [by=<transform>,] [lt=<comparison>,] [rev=false])
Variant of `select!` which copies `v` before partially sorting it, thereby returning the
same thing as `select!` but leaving `v` unmodified.
"""
select
"""
accept(server[,client])
Accepts a connection on the given server and returns a connection to the client. An
uninitialized client stream may be provided, in which case it will be used instead of
creating a new stream.
"""
accept
"""
readstring(stream::IO)
readstring(filename::AbstractString)
Read the entire contents of an I/O stream or a file as a string.
The text is assumed to be encoded in UTF-8.
"""
readstring
"""
eachline(stream::IO)
eachline(filename::AbstractString)
Create an iterable object that will yield each line from an I/O stream or a file.
The text is assumed to be encoded in UTF-8.
"""
eachline
"""
complex(r, [i])
Convert real numbers or arrays to complex. `i` defaults to zero.
"""
complex
"""
Mmap.Anonymous(name, readonly, create)
Create an `IO`-like object for creating zeroed-out mmapped-memory that is not tied to a file
for use in `Mmap.mmap`. Used by `SharedArray` for creating shared memory arrays.
"""
Mmap.Anonymous
"""
erfi(x)
Compute the imaginary error function of `x`, defined by ``-i \\operatorname{erf}(ix)``.
"""
erfi
"""
floor([T,] x, [digits, [base]])
`floor(x)` returns the nearest integral value of the same type as `x` that is less than or
equal to `x`.
`floor(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is
not representable.
`digits` and `base` work as for [`round`](:func:`round`).
"""
floor
"""
ErrorException(msg)
Generic error type. The error message, in the `.msg` field, may provide more specific details.
"""
ErrorException
"""
reverse(v [, start=1 [, stop=length(v) ]] )
Return a copy of `v` reversed from start to stop.
"""
reverse
"""
reverse!(v [, start=1 [, stop=length(v) ]]) -> v
In-place version of [`reverse`](:func:`reverse`).
"""
reverse!
"""
num(x)
Numerator of the rational representation of `x`.
"""
num
"""
.<(x, y)
Element-wise less-than comparison operator.
```jldoctest
julia> [1; 2; 3] .< [2; 1; 4]
3-element BitArray{1}:
true
false
true
```
"""
Base.:(.<)
"""
UndefRefError()
The item or field is not defined for the given object.
"""
UndefRefError
"""
bessely1(x)
Bessel function of the second kind of order 1, ``Y_1(x)``.
"""
bessely1
"""
append!(collection, collection2) -> collection.
Add the elements of `collection2` to the end of `collection`.
```jldoctest
julia> append!([1],[2,3])
3-element Array{Int64,1}:
1
2
3
```
```jldoctest
julia> append!([1, 2, 3], [4, 5, 6])
6-element Array{Int64,1}:
1
2
3
4
5
6
```
Use [`push!`](:func:`push!`) to add individual items to `collection` which are not already
themselves in another collection. The result is of the preceding example is equivalent to
`push!([1, 2, 3], 4, 5, 6)`.
"""
append!
"""
skip(s, offset)
Seek a stream relative to the current position.
"""
skip
"""
setdiff!(s, iterable)
Remove each element of `iterable` from set `s` in-place.
"""
setdiff!
"""
copysign(x, y) -> z
Return `z` which has the magnitude of `x` and the same sign as `y`.
```jldoctest
julia> copysign(1, -2)
-1
julia> copysign(-1, 2)
1
```
"""
copysign
"""
@show
Show an expression and result, returning the result.
"""
:@show
"""
showcompact(x)
Show a compact representation of a value.
This is used for printing array elements without repeating type information (which would
be redundant with that printed once for the whole array), and without line breaks inside
the representation of an element.
To offer a compact representation different from its standard one, a custom type should
test `get(io, :compact, false)` in its normal `show` method.
"""
showcompact
"""
erfc(x)
Compute the complementary error function of `x`, defined by ``1 - \\operatorname{erf}(x)``.
"""
erfc
"""
getfield(value, name::Symbol)
Extract a named field from a `value` of composite type. The syntax `a.b` calls
`getfield(a, :b)`.
"""
getfield
"""
besselj1(x)
Bessel function of the first kind of order 1, ``J_1(x)``.
"""
besselj1
"""
select!(v, k, [by=<transform>,] [lt=<comparison>,] [rev=false])
Partially sort the vector `v` in place, according to the order specified by `by`, `lt` and
`rev` so that the value at index `k` (or range of adjacent values if `k` is a range) occurs
at the position where it would appear if the array were fully sorted via a non-stable
algorithm. If `k` is a single index, that value is returned; if `k` is a range, an array of
values at those indices is returned. Note that `select!` does not fully sort the input
array.
"""
select!
"""
maximum!(r, A)
Compute the maximum value of `A` over the singleton dimensions of `r`, and write results to `r`.
"""
maximum!
"""
prod(A, dims)
Multiply elements of an array over the given dimensions.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> prod(A, 1)
1×2 Array{Int64,2}:
3 8
julia> prod(A, 2)
2×1 Array{Int64,2}:
2
12
```
"""
prod(A, dims)
"""
log1p(x)
Accurate natural logarithm of `1+x`. Throws `DomainError` for `Real` arguments less than -1.
There is an experimental variant in the `Base.Math.JuliaLibm` module, which is typically
faster and more accurate.
"""
log1p
"""
flipsign(x, y)
Return `x` with its sign flipped if `y` is negative. For example `abs(x) = flipsign(x,x)`.
"""
flipsign
"""
randstring([rng,] len=8)
Create a random ASCII string of length `len`, consisting of upper- and
lower-case letters and the digits 0-9. The optional `rng` argument
specifies a random number generator, see [Random Numbers](:ref:`Random Numbers <random-numbers>`).
"""
randstring
"""
Float64(x [, mode::RoundingMode])
Create a Float64 from `x`. If `x` is not exactly representable then `mode` determines how
`x` is rounded.
```jldoctest
julia> Float64(pi, RoundDown)
3.141592653589793
julia> Float64(pi, RoundUp)
3.1415926535897936
```
See [`RoundingMode`](:obj:`RoundingMode`) for available rounding modes.
"""
Float64
"""
union(s1,s2...)
∪(s1,s2...)
Construct the union of two or more sets. Maintains order with arrays.
"""
union
"""
realmax(T)
The highest finite value representable by the given floating-point DataType `T`.
"""
realmax
"""
serialize(stream, value)
Write an arbitrary value to a stream in an opaque format, such that it can be read back by
[`deserialize`](:func:`deserialize`). The read-back value will be as identical as possible to the original. In
general, this process will not work if the reading and writing are done by different
versions of Julia, or an instance of Julia with a different system image. `Ptr` values are
serialized as all-zero bit patterns (`NULL`).
"""
serialize
"""
sum(A, dims)
Sum elements of an array over the given dimensions.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> sum(A, 1)
1×2 Array{Int64,2}:
4 6
julia> sum(A, 2)
2×1 Array{Int64,2}:
3
7
```
"""
sum(A, dims)
"""
typemin(T)
The lowest value representable by the given (real) numeric DataType `T`.
"""
typemin
"""
typeof(x)
Get the concrete type of `x`.
"""
typeof
"""
log(x)
Compute the natural logarithm of `x`. Throws `DomainError` for negative `Real` arguments.
Use complex negative arguments to obtain complex results.
There is an experimental variant in the `Base.Math.JuliaLibm` module, which is typically
faster and more accurate.
"""
log(x)
"""
trunc([T,] x, [digits, [base]])
`trunc(x)` returns the nearest integral value of the same type as `x` whose absolute value
is less than or equal to `x`.
`trunc(T, x)` converts the result to type `T`, throwing an `InexactError` if the value is
not representable.
`digits` and `base` work as for [`round`](:func:`round`).
"""
trunc
"""
unsafe_convert(T,x)
Convert `x` to a value of type `T`
In cases where [`convert`](:func:`convert`) would need to take a Julia object
and turn it into a `Ptr`, this function should be used to define and perform
that conversion.
Be careful to ensure that a Julia reference to `x` exists as long as the result of this
function will be used. Accordingly, the argument `x` to this function should never be an
expression, only a variable name or field reference. For example, `x=a.b.c` is acceptable,
but `x=[a,b,c]` is not.
The `unsafe` prefix on this function indicates that using the result of this function after
the `x` argument to this function is no longer accessible to the program may cause undefined
behavior, including program corruption or segfaults, at any later time.
"""
unsafe_convert
"""
erfinv(x)
Compute the inverse error function of a real `x`, defined by ``\\operatorname{erf}(\\operatorname{erfinv}(x)) = x``.
"""
erfinv
"""
seek(s, pos)
Seek a stream to the given position.
"""
seek
"""
besselj0(x)
Bessel function of the first kind of order 0, ``J_0(x)``.
"""
besselj0
"""
erfcinv(x)
Compute the inverse error complementary function of a real `x`, defined by
``\\operatorname{erfc}(\\operatorname{erfcinv}(x)) = x``.
"""
erfcinv
"""
minabs(A, dims)
Compute the minimum absolute values over given dimensions.
"""
minabs(A, dims)
"""
popdisplay()
popdisplay(d::Display)
Pop the topmost backend off of the display-backend stack, or the topmost copy of `d` in the
second variant.
"""
popdisplay
"""
cglobal((symbol, library) [, type=Void])
Obtain a pointer to a global variable in a C-exported shared library, specified exactly as
in [`ccall`](:func:`ccall`).
Returns a `Ptr{Type}`, defaulting to `Ptr{Void}` if no `Type` argument is
supplied.
The values can be read or written by [`unsafe_load`](:func:`unsafe_load`) or [`unsafe_store!`](:func:`unsafe_store!`),
respectively.
"""
cglobal
"""
one(x)
Get the multiplicative identity element for the type of `x` (`x` can also specify the type
itself). For matrices, returns an identity matrix of the appropriate size and type.
"""
one
"""
endof(collection) -> Integer
Returns the last index of the collection.
```jldoctest
julia> endof([1,2,4])
3
```
"""
endof
"""
Channel{T}(sz::Int)
Constructs a `Channel` with an internal buffer that can hold a maximum of `sz` objects
of type `T`. `put!` calls on a full channel block until an object is removed with `take!`.
`Channel(0)` constructs an unbuffered channel. `put!` blocks until a matching `take!` is called.
And vice-versa.
Other constructors:
- `Channel(Inf)` - equivalent to `Channel{Any}(typemax(Int))`
- `Channel(sz)` equivalent to `Channel{Any}(sz)`
"""
Channel
"""
next(iter, state) -> item, state
For a given iterable object and iteration state, return the current item and the next iteration state.
"""
next
"""
log2(x)
Compute the logarithm of `x` to base 2. Throws `DomainError` for negative `Real` arguments.
```jldoctest
julia> log2(4)
2.0
julia> log2(10)
3.321928094887362
```
"""
log2
"""
abs2(x)
Squared absolute value of `x`.
"""
abs2
"""
sizehint!(s, n)
Suggest that collection `s` reserve capacity for at least `n` elements. This can improve performance.
"""
sizehint!
"""
OutOfMemoryError()
An operation allocated too much memory for either the system or the garbage collector to
handle properly.
"""
OutOfMemoryError
"""
finalize(x)
Immediately run finalizers registered for object `x`.
"""
finalize
"""
BoundsError([a],[i])
An indexing operation into an array, `a`, tried to access an out-of-bounds element, `i`.
"""
BoundsError
"""
invoke(f, (types...), args...)
Invoke a method for the given generic function matching the specified types (as a tuple), on
the specified arguments. The arguments must be compatible with the specified types. This
allows invoking a method other than the most specific matching method, which is useful when
the behavior of a more general definition is explicitly needed (often as part of the
implementation of a more specific method of the same function).
"""
invoke
"""
parse(str, start; greedy=true, raise=true)
Parse the expression string and return an expression (which could later be passed to eval
for execution). `start` is the index of the first character to start parsing. If `greedy` is
`true` (default), `parse` will try to consume as much input as it can; otherwise, it will
stop as soon as it has parsed a valid expression. Incomplete but otherwise syntactically
valid expressions will return `Expr(:incomplete, "(error message)")`. If `raise` is `true`
(default), syntax errors other than incomplete expressions will raise an error. If `raise`
is `false`, `parse` will return an expression that will raise an error upon evaluation.
"""
parse(str, start)
"""
parse(str; raise=true)
Parse the expression string greedily, returning a single expression. An error is thrown if
there are additional characters after the first expression. If `raise` is `true` (default),
syntax errors will raise an error; otherwise, `parse` will return an expression that will
raise an error upon evaluation.
"""
parse(str)
"""
parse(type, str, [base])
Parse a string as a number. If the type is an integer type, then a base can be specified
(the default is 10). If the type is a floating point type, the string is parsed as a decimal
floating point number. If the string does not contain a valid number, an error is raised.
"""
parse(T::Type, str, base=Int)
"""
^(x, y)
Exponentiation operator.
"""
Base.:(^)(x, y)
"""
position(s)
Get the current position of a stream.
"""
position
"""
selectperm(v, k, [alg=<algorithm>,] [by=<transform>,] [lt=<comparison>,] [rev=false])
Return a partial permutation of the vector `v`, according to the order specified by
`by`, `lt` and `rev`, so that `v[output]` returns the first `k` (or range of adjacent values
if `k` is a range) values of a fully sorted version of `v`. If `k` is a single index
(Integer), an array of the first `k` indices is returned; if `k` is a range, an array of
those indices is returned. Note that the handling of integer values for `k` is different
from `select` in that it returns a vector of `k` elements instead of just the `k` th
element. Also note that this is equivalent to, but more efficient than, calling
`sortperm(...)[k]`
"""
selectperm
"""
reinterpret(type, A)
Change the type-interpretation of a block of memory.
For arrays, this constructs an array with the same binary data as the given
array, but with the specified element type.
For example,
`reinterpret(Float32, UInt32(7))` interprets the 4 bytes corresponding to `UInt32(7)` as a
`Float32`.
```jldoctest
julia> reinterpret(Float32, UInt32(7))
1.0f-44
julia> reinterpret(Float32, UInt32[1 2 3 4 5])
1×5 Array{Float32,2}:
1.4013f-45 2.8026f-45 4.2039f-45 5.60519f-45 7.00649f-45
```
"""
reinterpret
"""
~(x)
Bitwise not.
```jldoctest
julia> ~4
-5
julia> ~10
-11
julia> ~true
false
```
"""
~
"""
bswap(n)
Byte-swap an integer.
"""
bswap
"""
sumabs2!(r, A)
Sum squared absolute values of elements of `A` over the singleton dimensions of `r`, and
write results to `r`.
"""
sumabs2!
"""
tanh(x)
Compute hyperbolic tangent of `x`.
"""
tanh
"""
maxintfloat(T)
The largest integer losslessly representable by the given floating-point DataType `T`.
"""
maxintfloat
"""
delete!(collection, key)
Delete the mapping for the given key in a collection, and return the collection.
"""
delete!
"""
eps(T)
The distance between 1.0 and the next larger representable floating-point value of
`DataType` `T`. Only floating-point types are sensible arguments.
"""
eps(::Union{Type{BigFloat},Type{Float64},Type{Float32},Type{Float16}})
"""
eps()
The distance between 1.0 and the next larger representable floating-point value of `Float64`.
"""
eps()
"""
eps(x)
The distance between `x` and the next larger representable floating-point value of the same
`DataType` as `x`.
"""
eps(::AbstractFloat)
"""
searchsortedfirst(a, x, [by=<transform>,] [lt=<comparison>,] [rev=false])
Returns the index of the first value in `a` greater than or equal to `x`, according to the
specified order. Returns `length(a)+1` if `x` is greater than all values in `a`.
"""
searchsortedfirst
"""
big(x)
Convert a number to a maximum precision representation (typically `BigInt` or `BigFloat`).
See [`BigFloat`](:obj:`BigFloat`) for information about some pitfalls with floating-point numbers.
"""
big
"""
quit()
Quit the program indicating that the processes completed successfully. This function calls
`exit(0)` (see [`exit`](:func:`exit`)).
"""
quit
"""
typejoin(T, S)
Compute a type that contains both `T` and `S`.
"""
typejoin
"""
sin(x)
Compute sine of `x`, where `x` is in radians.
"""
sin
"""
selectperm!(ix, v, k, [alg=<algorithm>,] [by=<transform>,] [lt=<comparison>,] [rev=false,] [initialized=false])
Like `selectperm`, but accepts a preallocated index vector `ix`. If `initialized` is `false`
(the default), ix is initialized to contain the values `1:length(ix)`.
"""
selectperm!
"""
precompile(f,args::Tuple{Vararg{Any}})
Compile the given function `f` for the argument tuple (of types) `args`, but do not execute it.
"""
precompile
"""
asinh(x)
Compute the inverse hyperbolic sine of `x`.
"""
asinh
"""
minimum(A, dims)
Compute the minimum value of an array over the given dimensions. See also the
[`min(a,b)`](:func:`min`) function to take the minimum of two or more arguments,
which can be applied elementwise to arrays via `min.(a,b)`.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> minimum(A, 1)
1×2 Array{Int64,2}:
1 2
julia> minimum(A, 2)
2×1 Array{Int64,2}:
1
3
```
"""
minimum(A,dims)
"""
view(A, inds...)
Like [`getindex`](:func:`getindex`), but returns a view into the parent array `A` with the
given indices instead of making a copy. Calling [`getindex`](:func:`getindex`) or
[`setindex!`](:func:`setindex!`) on the returned [`SubArray`](:obj:`SubArray`) computes the
indices to the parent array on the fly without checking bounds.
"""
view
"""
cot(x)
Compute the cotangent of `x`, where `x` is in radians.
"""
cot
"""
get(collection, key, default)
Return the value stored for the given key, or the given default value if no mapping for the
key is present.
"""
get(collection,key,default)
"""
get(f::Function, collection, key)
Return the value stored for the given key, or if no mapping for the key is present, return
`f()`. Use [`get!`](:func:`get!`) to also store the default value in the dictionary.
This is intended to be called using `do` block syntax
```julia
get(dict, key) do
# default value calculated here
time()
end
```
"""
get
"""
Mmap.sync!(array)
Forces synchronization between the in-memory version of a memory-mapped `Array` or
`BitArray` and the on-disk version.
"""
Mmap.sync!
"""
csc(x)
Compute the cosecant of `x`, where `x` is in radians.
"""
csc
"""
hash(x[, h::UInt])
Compute an integer hash code such that `isequal(x,y)` implies `hash(x)==hash(y)`. The
optional second argument `h` is a hash code to be mixed with the result.
New types should implement the 2-argument form, typically by calling the 2-argument `hash`
method recursively in order to mix hashes of the contents with each other (and with `h`).
Typically, any type that implements `hash` should also implement its own `==` (hence
`isequal`) to guarantee the property mentioned above.
"""
hash
"""
atanh(x)
Compute the inverse hyperbolic tangent of `x`.
"""
atanh
"""
read(stream::IO, T)
Read a single value of type `T` from `stream`, in canonical binary representation.
"""
read(stream, t)
"""
shift!(collection) -> item
Remove the first `item` from `collection`.
```jldoctest
julia> A = [1, 2, 3, 4, 5, 6]
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> shift!(A)
1
julia> A
5-element Array{Int64,1}:
2
3
4
5
6
```
"""
shift!
"""
spawn(command)
Run a command object asynchronously, returning the resulting [`Process`](:obj:`Process`) object.
"""
spawn
"""
isdefined([m::Module,] s::Symbol)
isdefined(object, s::Symbol)
isdefined(object, index::Int)
Tests whether an assignable location is defined. The arguments can be a module and a symbol
or a composite object and field name (as a symbol) or index. With a single symbol argument,
tests whether a global variable with that name is defined in `current_module()`.
"""
isdefined
"""
cotd(x)
Compute the cotangent of `x`, where `x` is in degrees.
"""
cotd
"""
wait([x])
Block the current task until some event occurs, depending on the type of the argument:
* [`RemoteChannel`](:obj:`RemoteChannel`) : Wait for a value to become available on the specified remote channel.
* [`Future`](:obj:`Future`) : Wait for a value to become available for the specified future.
* [`Channel`](:obj:`Channel`): Wait for a value to be appended to the channel.
* [`Condition`](:obj:`Condition`): Wait for [`notify`](:func:`notify`) on a condition.
* [`Process`](:obj:`Process`): Wait for a process or process chain to exit. The `exitcode` field of a process
can be used to determine success or failure.
* [`Task`](:obj:`Task`): Wait for a `Task` to finish, returning its result value. If the task fails with an
exception, the exception is propagated (re-thrown in the task that called `wait`).
* [`RawFD`](:obj:`RawFD`): Wait for changes on a file descriptor (see [`poll_fd`](:func:`poll_fd`) for keyword arguments and return code)
If no argument is passed, the task blocks for an undefined period. A task can only be
restarted by an explicit call to `schedule` or `yieldto`.
Often `wait` is called within a `while` loop to ensure a waited-for condition is met before proceeding.
"""
wait
"""
atexit(f)
Register a zero-argument function `f()` to be called at process exit. `atexit()` hooks are
called in last in first out (LIFO) order and run before object finalizers.
"""
atexit
"""
copy(x)
Create a shallow copy of `x`: the outer structure is copied, but not all internal values.
For example, copying an array produces a new array with identically-same elements as the
original.
"""
copy
"""
isempty(collection) -> Bool
Determine whether a collection is empty (has no elements).
```jldoctest
julia> isempty([])
true
julia> isempty([1 2 3])
false
```
"""
isempty
"""
sumabs!(r, A)
Sum absolute values of elements of `A` over the singleton dimensions of `r`, and write
results to `r`.
"""
sumabs!
"""
hex2num(str)
Convert a hexadecimal string to the floating point number it represents.
"""
hex2num
"""
InexactError()
Type conversion cannot be done exactly.
"""
InexactError
"""
typemax(T)
The highest value representable by the given (real) numeric `DataType`.
"""
typemax
"""
all(A, dims)
Test whether all values along the given dimensions of an array are `true`.
```jldoctest
julia> A = [true false; true true]
2×2 Array{Bool,2}:
true false
true true
julia> all(A, 1)
1×2 Array{Bool,2}:
true false
julia> all(A, 2)
2×1 Array{Bool,2}:
false
true
```
"""
all(A::AbstractArray, dims)
"""
DomainError()
The arguments to a function or constructor are outside the valid domain.
"""
DomainError
"""
acosh(x)
Compute the inverse hyperbolic cosine of `x`.
"""
acosh
"""
IntSet([itr])
Construct a sorted set of positive `Int`s generated by the given iterable object, or an
empty set. Implemented as a bit string, and therefore designed for dense integer sets. Only
`Int`s greater than 0 can be stored. If the set will be sparse (for example holding a few
very large integers), use [`Set`](:obj:`Set`) instead.
"""
IntSet
"""
Task(func)
Create a `Task` (i.e. coroutine) to execute the given function (which must be
callable with no arguments). The task exits when this function returns.
"""
Task
"""
pushdisplay(d::Display)
Pushes a new display `d` on top of the global display-backend stack. Calling `display(x)` or
`display(mime, x)` will display `x` on the topmost compatible backend in the stack (i.e.,
the topmost backend that does not throw a `MethodError`).
"""
pushdisplay
"""
produce(value)
Send the given value to the last `consume` call, switching to the consumer task. If the next
`consume` call passes any values, they are returned by `produce`.
"""
produce
"""
StackOverflowError()
The function call grew beyond the size of the call stack. This usually happens when a call
recurses infinitely.
"""
StackOverflowError
"""
BigInt(x)
Create an arbitrary precision integer. `x` may be an `Int` (or anything that can be
converted to an `Int`). The usual mathematical operators are defined for this type, and
results are promoted to a `BigInt`.
Instances can be constructed from strings via [`parse`](:func:`parse`), or using the `big`
string literal.
"""
BigInt
"""
==(x, y)
Generic equality operator, giving a single `Bool` result. Falls back to `===`. Should be
implemented for all types with a notion of equality, based on the abstract value that an
instance represents. For example, all numeric types are compared by numeric value, ignoring
type. Strings are compared as sequences of characters, ignoring encoding.
Follows IEEE semantics for floating-point numbers.
Collections should generally implement `==` by calling `==` recursively on all contents.
New numeric types should implement this function for two arguments of the new type, and
handle comparison to other types via promotion rules where possible.
"""
Base.:(==)
"""
seekstart(s)
Seek a stream to its beginning.
"""
seekstart
"""
nfields(x::DataType) -> Int
Get the number of fields of a `DataType`.
"""
nfields
"""
show(stream, mime, x)
The `display` functions ultimately call `show` in order to write an object `x` as a
given `mime` type to a given I/O `stream` (usually a memory buffer), if possible. In order
to provide a rich multimedia representation of a user-defined type `T`, it is only necessary
to define a new `show` method for `T`, via: `show(stream, ::MIME"mime", x::T) = ...`,
where `mime` is a MIME-type string and the function body calls `write` (or similar) to write
that representation of `x` to `stream`. (Note that the `MIME""` notation only supports
literal strings; to construct `MIME` types in a more flexible manner use
`MIME{Symbol("")}`.)
For example, if you define a `MyImage` type and know how to write it to a PNG file, you
could define a function `show(stream, ::MIME"image/png", x::MyImage) = ...` to allow
your images to be displayed on any PNG-capable `Display` (such as IJulia). As usual, be sure
to `import Base.show` in order to add new methods to the built-in Julia function
`show`.
The default MIME type is `MIME"text/plain"`. There is a fallback definition for `text/plain`
output that calls `show` with 2 arguments. Therefore, this case should be handled by
defining a 2-argument `show(stream::IO, x::MyType)` method.
Technically, the `MIME"mime"` macro defines a singleton type for the given `mime` string,
which allows us to exploit Julia's dispatch mechanisms in determining how to display objects
of any given type.
The first argument to `show` can be an [`IOContext`](:obj:`IOContext`) specifying output format properties.
See [`IOContext`](:obj:`IOContext`) for details.
"""
show(stream, mime, x)
"""
mean!(r, v)
Compute the mean of `v` over the singleton dimensions of `r`, and write results to `r`.
"""
mean!
"""
isless(x, y)
Test whether `x` is less than `y`, according to a canonical total order. Values that are
normally unordered, such as `NaN`, are ordered in an arbitrary but consistent fashion. This
is the default comparison used by `sort`. Non-numeric types with a canonical total order
should implement this function. Numeric types only need to implement it if they have special
values such as `NaN`.
"""
isless
"""
expm1(x)
Accurately compute ``e^x-1``.
"""
expm1
"""
showerror(io, e)
Show a descriptive representation of an exception object.
"""
showerror
"""
error(message::AbstractString)
Raise an `ErrorException` with the given message.
"""
error
"""
sqrtm(A)
If `A` has no negative real eigenvalues, compute the principal matrix square root of `A`,
that is the unique matrix ``X`` with eigenvalues having positive real part such that
``X^2 = A``. Otherwise, a nonprincipal square root is returned.
If `A` is symmetric or Hermitian, its eigendecomposition ([`eigfact`](:func:`eigfact`)) is
used to compute the square root. Otherwise, the square root is determined by means of the
Björck-Hammarling method, which computes the complex Schur form ([`schur`](:func:`schur`))
and then the complex square root of the triangular factor.
[^BH83]: Åke Björck and Sven Hammarling, "A Schur method for the square root of a matrix", Linear Algebra and its Applications, 52-53, 1983, 127-140. [doi:10.1016/0024-3795(83)80010-X](http://dx.doi.org/10.1016/0024-3795(83)80010-X)
"""
sqrtm
"""
unsafe_store!(p::Ptr{T}, x, [i::Integer=1])
Store a value of type `T` to the address of the ith element (1-indexed) starting at `p`.
This is equivalent to the C expression `p[i-1] = x`.
The `unsafe` prefix on this function indicates that no validation is performed on the
pointer `p` to ensure that it is valid. Incorrect usage may corrupt or segfault your
program, in the same manner as C.
"""
unsafe_store!
"""
readcsv(source, [T::Type]; options...)
Equivalent to `readdlm` with `delim` set to comma, and type optionally defined by `T`.
"""
readcsv
"""
erfcx(x)
Compute the scaled complementary error function of `x`, defined by ``e^{x^2} \\operatorname{erfc}(x)``.
Note also that ``\\operatorname{erfcx}(-ix)`` computes the Faddeeva function ``w(x)``.
"""
erfcx
"""
UndefVarError(var::Symbol)
A symbol in the current scope is not defined.
"""
UndefVarError
"""
gc()
Perform garbage collection. This should not generally be used.
"""
gc
"""
minimum!(r, A)
Compute the minimum value of `A` over the singleton dimensions of `r`, and write results to `r`.
"""
minimum!
"""
.-(x, y)
Element-wise subtraction operator.
```jldoctest
julia> [4; 5; 6] .- [1; 2; 4]
3-element Array{Int64,1}:
3
3
2
```
"""
Base.:(.-)
"""
unsafe_trunc(T, x)
`unsafe_trunc(T, x)` returns the nearest integral value of type `T` whose absolute value is
less than or equal to `x`. If the value is not representable by `T`, an arbitrary value will
be returned.
"""
unsafe_trunc
"""
parent(A)
Returns the "parent array" of an array view type (e.g., `SubArray`), or the array itself if
it is not a view.
"""
parent
"""
nextpow(a, x)
The smallest `a^n` not less than `x`, where `n` is a non-negative integer. `a` must be
greater than 1, and `x` must be greater than 0.
"""
nextpow
"""
gc_enable(on::Bool)
Control whether garbage collection is enabled using a boolean argument (`true` for enabled,
`false` for disabled). Returns previous GC state. Disabling garbage collection should be
used only with extreme caution, as it can cause memory use to grow without bound.
"""
gc_enable
"""
atan(x)
Compute the inverse tangent of `x`, where the output is in radians.
"""
atan
"""
isinf(f) -> Bool
Test whether a number is infinite.
"""
isinf
"""
secd(x)
Compute the secant of `x`, where `x` is in degrees.
"""
secd
"""
OverflowError()
The result of an expression is too large for the specified type and will cause a wraparound.
"""
OverflowError
"""
object_id(x)
Get a hash value for `x` based on object identity. `object_id(x)==object_id(y)` if `x === y`.
"""
object_id
"""
cat(dims, A...)
Concatenate the input arrays along the specified dimensions in the iterable `dims`. For
dimensions not in `dims`, all input arrays should have the same size, which will also be the
size of the output array along that dimension. For dimensions in `dims`, the size of the
output array is the sum of the sizes of the input arrays along that dimension. If `dims` is
a single number, the different arrays are tightly stacked along that dimension. If `dims` is
an iterable containing several dimensions, this allows one to construct block diagonal
matrices and their higher-dimensional analogues by simultaneously increasing several
dimensions for every new input array and putting zero blocks elsewhere. For example,
`cat([1,2], matrices...)` builds a block diagonal matrix, i.e. a block matrix with
`matrices[1]`, `matrices[2]`, ... as diagonal blocks and matching zero blocks away from the
diagonal.
"""
cat
"""
show(x)
Write an informative text representation of a value to the current output stream. New types
should overload `show(io, x)` where the first argument is a stream. The representation used
by `show` generally includes Julia-specific formatting and type information.
"""
show(x)
"""
Array(dims)
`Array{T}(dims)` constructs an uninitialized dense array with element type `T`. `dims` may
be a tuple or a series of integer arguments. The syntax `Array(T, dims)` is also available,
but deprecated.
"""
Array
"""
isreal(x) -> Bool
Test whether `x` or all its elements are numerically equal to some real number.
```jldoctest
julia> isreal(5.)
true
julia> isreal([4.; complex(0,1)])
false
```
"""
isreal
"""
issubtype(type1, type2)
Return `true` if and only if all values of `type1` are also of `type2`. Can also be written
using the `<:` infix operator as `type1 <: type2`.
```jldoctest
julia> issubtype(Int8, Int32)
false
julia> Int8 <: Integer
true
```
"""
issubtype(type1, type2)
"""
finalizer(x, function)
Register a function `f(x)` to be called when there are no program-accessible references to
`x`. The behavior of this function is unpredictable if `x` is of a bits type.
"""
finalizer
"""
csch(x)
Compute the hyperbolic cosecant of `x`.
"""
csch
"""
sec(x)
Compute the secant of `x`, where `x` is in radians.
"""
sec
"""
TypeError(func::Symbol, context::AbstractString, expected::Type, got)
A type assertion failure, or calling an intrinsic function with an incorrect argument type.
"""
TypeError
"""
setfield!(value, name::Symbol, x)
Assign `x` to a named field in `value` of composite type. The syntax `a.b = c` calls
`setfield!(a, :b, c)`.
"""
setfield!
"""
countlines(io,[eol::Char])
Read `io` until the end of the stream/file and count the number of lines. To specify a file
pass the filename as the first argument. EOL markers other than '\\n' are supported by
passing them as the second argument.
"""
countlines
"""
.\\(x, y)
Element-wise left division operator.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> A .\\ [1 2]
2×2 Array{Float64,2}:
1.0 1.0
0.333333 0.5
```
```jldoctest
julia> A = [1 0; 0 -1];
julia> B = [0 1; 1 0];
julia> C = [A, B]
2-element Array{Array{Int64,2},1}:
[1 0; 0 -1]
[0 1; 1 0]
julia> x = [1; 0];
julia> y = [0; 1];
julia> D = [x, y]
2-element Array{Array{Int64,1},1}:
[1,0]
[0,1]
julia> C .\\ D
2-element Array{Array{Float64,1},1}:
[1.0,-0.0]
[1.0,0.0]
```
See also [`broadcast`](:func:`broadcast`).
"""
Base.:(.\)(x,y)
"""
```
*(x, y...)
```
Multiplication operator. `x*y*z*...` calls this function with all arguments, i.e. `*(x, y, z, ...)`.
"""
Base.:(*)(x, y...)
"""
time()
Get the system time in seconds since the epoch, with fairly high (typically, microsecond) resolution.
"""
time()
"""
TextDisplay(stream)
Returns a `TextDisplay <: Display`, which can display any object as the text/plain MIME type
(only), writing the text representation to the given I/O stream. (The text representation is
the same as the way an object is printed in the Julia REPL.)
"""
TextDisplay
"""
ismatch(r::Regex, s::AbstractString) -> Bool
Test whether a string contains a match of the given regular expression.
"""
ismatch
"""
exp(x)
Compute ``e^x``.
"""
exp
"""
matchall(r::Regex, s::AbstractString[, overlap::Bool=false]) -> Vector{AbstractString}
Return a vector of the matching substrings from [`eachmatch`](:func:`eachmatch`).
"""
matchall
"""
get!(collection, key, default)
Return the value stored for the given key, or if no mapping for the key is present, store
`key => default`, and return `default`.
"""
get!(collection,key,default)
"""
get!(f::Function, collection, key)
Return the value stored for the given key, or if no mapping for the key is present, store
`key => f()`, and return `f()`.
This is intended to be called using `do` block syntax:
get!(dict, key) do
# default value calculated here
time()
end
"""
get!(f::Function,collection,key)
"""
@assert cond [text]
Throw an `AssertionError` if `cond` is `false`. Preferred syntax for writing assertions.
Message `text` is optionally displayed upon assertion failure.
"""
:@assert
"""
deserialize(stream)
Read a value written by [`serialize`](:func:`serialize`). `deserialize` assumes the binary data read from
`stream` is correct and has been serialized by a compatible implementation of [`serialize`](:func:`serialize`).
It has been designed with simplicity and performance as a goal and does not validate
the data read. Malformed data can result in process termination. The caller has to ensure
the integrity and correctness of data read from `stream`.
"""
deserialize
"""
first(coll)
Get the first element of an iterable collection. Returns the start point of a
[`Range`](:obj:`Range`) even if it is empty.
```jldoctest
julia> first(2:2:10)
2
julia> first([1; 2; 3; 4])
1
```
"""
first
"""
median!(v)
Like [`median`](:func:`median`), but may overwrite the input vector.
"""
median!
"""
cumprod!(B, A, [dim])
Cumulative product of `A` along a dimension, storing the result in `B`. The dimension defaults to 1.
"""
cumprod!
"""
rethrow([e])
Throw an object without changing the current exception backtrace. The default argument is
the current exception (if called within a `catch` block).
"""
rethrow
"""
!(x)
Boolean not.
```jldoctest
julia> !true
false
julia> !false
true
julia> ![true false true]
1×3 Array{Bool,2}:
false true false
```
"""
Base.:(!)
"""
length(collection) -> Integer
For ordered, indexable collections, returns the maximum index `i` for which `getindex(collection, i)`
is valid.
For unordered collections, returns the number of elements.
```jldoctest
julia> length(1:5)
5
julia> length([1; 2; 3; 4])
4
```
"""
length(collection)
"""
searchsortedlast(a, x, [by=<transform>,] [lt=<comparison>,] [rev=false])
Returns the index of the last value in `a` less than or equal to `x`, according to the
specified order. Returns `0` if `x` is less than all values in `a`.
"""
searchsortedlast
"""
InterruptException()
The process was stopped by a terminal interrupt (CTRL+C).
"""
InterruptException
"""
den(x)
Denominator of the rational representation of `x`.
"""
den
"""
issubnormal(f) -> Bool
Test whether a floating point number is subnormal.
"""
issubnormal
"""
NullException()
An attempted access to a [`Nullable`](:obj:`Nullable`) with no defined value.
"""
NullException
"""
.==(x, y)
Element-wise equality comparison operator.
```jldoctest
julia> [1 2 3] .== [1 2 4]
1×3 BitArray{2}:
true true false
```
"""
Base.:(.==)
"""
cfunction(function::Function, ReturnType::Type, (ArgumentTypes...))
Generate C-callable function pointer from Julia function. Type annotation of the return
value in the callback function is a must for situations where Julia cannot infer the return
type automatically.
For example:
function foo()
# body
retval::Float64
end
bar = cfunction(foo, Float64, ())
"""
cfunction
"""
intersect(s1,s2...)
∩(s1,s2)
Construct the intersection of two or more sets.
Maintains order and multiplicity of the first argument for arrays and ranges.
"""
intersect
"""
@spawn
Creates a closure around an expression and runs it on an automatically-chosen process,
returning a [`Future`](:obj:`Future`) to the result.
"""
:@spawn
"""
promote_rule(type1, type2)
Specifies what type should be used by [`promote`](:func:`promote`) when given values of types `type1` and
`type2`. This function should not be called directly, but should have definitions added to
it for new types as appropriate.
"""
promote_rule
"""
sumabs2(A, dims)
Sum squared absolute values of elements of an array over the given dimensions.
"""
sumabs2(A,dims)
"""
showall(x)
Similar to [`show`](:func:`show`), except shows all elements of arrays.
"""
showall
"""
mimewritable(mime, x)
Returns a boolean value indicating whether or not the object `x` can be written as the given
`mime` type. (By default, this is determined automatically by the existence of the
corresponding [`show`](:func:`show`) function for `typeof(x)`.)
"""
mimewritable
"""
match(r::Regex, s::AbstractString[, idx::Integer[, addopts]])
Search for the first match of the regular expression `r` in `s` and return a `RegexMatch`
object containing the match, or nothing if the match failed. The matching substring can be
retrieved by accessing `m.match` and the captured sequences can be retrieved by accessing
`m.captures` The optional `idx` argument specifies an index at which to start the search.
"""
match
"""
coth(x)
Compute the hyperbolic cotangent of `x`.
"""
coth
"""
start(iter) -> state
Get initial iteration state for an iterable object.
"""
start
"""
readavailable(stream)
Read all available data on the stream, blocking the task only if no data is available. The
result is a `Vector{UInt8,1}`.
"""
readavailable
"""
isa(x, type) -> Bool
Determine whether `x` is of the given `type`.
"""
isa
"""
unsafe_load(p::Ptr{T}, [i::Integer=1])
Load a value of type `T` from the address of the ith element (1-indexed) starting at `p`.
This is equivalent to the C expression `p[i-1]`.
The `unsafe` prefix on this function indicates that no validation is performed on the
pointer `p` to ensure that it is valid. Incorrect usage may segfault your program or return
garbage answers, in the same manner as C.
"""
unsafe_load
"""
catch_backtrace()
Get the backtrace of the current exception, for use within `catch` blocks.
"""
catch_backtrace
"""
cos(x)
Compute cosine of `x`, where `x` is in radians.
"""
cos
"""
maxabs(A, dims)
Compute the maximum absolute values over given dimensions.
"""
maxabs(A,dims)
"""
done(iter, state) -> Bool
Test whether we are done iterating.
"""
done
"""
convert(T, x)
Convert `x` to a value of type `T`.
If `T` is an `Integer` type, an [`InexactError`](:exc:`InexactError`) will be raised if `x`
is not representable by `T`, for example if `x` is not integer-valued, or is outside the
range supported by `T`.
```jldoctest
julia> convert(Int, 3.0)
3
julia> convert(Int, 3.5)
ERROR: InexactError()
in convert(::Type{Int64}, ::Float64) at ./int.jl:330
...
```
If `T` is a [`AbstractFloat`](:obj:`AbstractFloat`) or [`Rational`](:obj:`Rational`) type,
then it will return the closest value to `x` representable by `T`.
```jldoctest
julia> x = 1/3
0.3333333333333333
julia> convert(Float32, x)
0.33333334f0
julia> convert(Rational{Int32}, x)
1//3
julia> convert(Rational{Int64}, x)
6004799503160661//18014398509481984
```
If `T` is a collection type and `x` a collection, the result of `convert(T, x)` may alias
`x`.
```jldoctest
julia> x = Int[1,2,3];
julia> y = convert(Vector{Int}, x);
julia> y === x
true
```
Similarly, if `T` is a composite type and `x` a related instance, the result of
`convert(T, x)` may alias part or all of `x`.
```jldoctest
julia> x = speye(5);
julia> typeof(x)
SparseMatrixCSC{Float64,Int64}
julia> y = convert(SparseMatrixCSC{Float64,Int64}, x);
julia> z = convert(SparseMatrixCSC{Float32,Int64}, y);
julia> y === x
true
julia> z === x
false
julia> z.colptr === x.colptr
true
```
"""
convert
"""
applicable(f, args...) -> Bool
Determine whether the given generic function has a method applicable to the given arguments.
```jldoctest
julia> function f(x, y)
x + y
end;
julia> applicable(f, 1)
false
julia> applicable(f, 1, 2)
true
```
"""
applicable
"""
fma(x, y, z)
Computes `x*y+z` without rounding the intermediate result `x*y`. On some systems this is
significantly more expensive than `x*y+z`. `fma` is used to improve accuracy in certain
algorithms. See [`muladd`](:func:`muladd`).
"""
fma
"""
eigvals(A,[irange,][vl,][vu]) -> values
Returns the eigenvalues of `A`. If `A` is `Symmetric`, `Hermitian` or `SymTridiagonal`,
it is possible to calculate only a subset of the eigenvalues by specifying either a
`UnitRange` `irange` covering indices of the sorted eigenvalues, or a pair `vl` and `vu`
for the lower and upper boundaries of the eigenvalues.
For general non-symmetric matrices it is possible to specify how the matrix is balanced
before the eigenvector calculation. The option `permute=true` permutes the matrix to
become closer to upper triangular, and `scale=true` scales the matrix by its diagonal
elements to make rows and columns moreequal in norm. The default is `true` for both
options.
"""
eigvals
"""
pointer_from_objref(object_instance)
Get the memory address of a Julia object as a `Ptr`. The existence of the resulting `Ptr`
will not protect the object from garbage collection, so you must ensure that the object
remains referenced for the whole time that the `Ptr` will be used.
"""
pointer_from_objref
"""
copy!(dest, src)
Copy all elements from collection `src` to array `dest`. Returns `dest`.
"""
copy!(dest,src)
"""
copy!(dest, do, src, so, N)
Copy `N` elements from collection `src` starting at offset `so`, to array `dest` starting at
offset `do`. Returns `dest`.
"""
copy!(dest,d,src,so,N)
"""
+(x, y...)
Addition operator. `x+y+z+...` calls this function with all arguments, i.e. `+(x, y, z, ...)`.
"""
+
"""
setindex!(A, X, inds...)
Store values from array `X` within some subset of `A` as specified by `inds`.
"""
setindex!(A::AbstractArray,X,inds...)
"""
setindex!(collection, value, key...)
Store the given value at the given key or index within a collection. The syntax `a[i,j,...] =
x` is converted by the compiler to `(setindex!(a, x, i, j, ...); x)`.
"""
setindex!(collection,value,key...)
"""
signif(x, digits, [base])
Rounds (in the sense of [`round`](:func:`round`)) `x` so that there are `digits` significant digits, under a
base `base` representation, default 10. E.g., `signif(123.456, 2)` is `120.0`, and
`signif(357.913, 4, 2)` is `352.0`.
"""
signif
"""
full(F)
Reconstruct the matrix `A` from the factorization `F=factorize(A)`.
"""
full(F)
"""
throw(e)
Throw an object as an exception.
"""
throw
"""
issubset(a, b)
⊆(a,b) -> Bool
⊈(a,b) -> Bool
⊊(a,b) -> Bool
Determine whether every element of `a` is also in `b`, using [`in`](:func:`in`).
"""
issubset(a,b)
"""
issubset(A, S) -> Bool
⊆(A,S) -> Bool
Return `true` if `A` is a subset of or equal to `S`.
"""
issubset
"""
zero(x)
Get the additive identity element for the type of `x` (`x` can also specify the type itself).
"""
zero
"""
any(A, dims)
Test whether any values along the given dimensions of an array are `true`.
"""
any(::AbstractArray,dims)
"""
zeros(type, dims)
Create an array of all zeros of specified type.
The type defaults to `Float64` if not specified.
```jldoctest
julia> zeros(Int8, 2, 3)
2×3 Array{Int8,2}:
0 0 0
0 0 0
```
"""
zeros(t,dims)
"""
zeros(A)
Create an array of all zeros with the same element type and shape as `A`.
```jldoctest
julia> A = [1 2; 3 4]
2×2 Array{Int64,2}:
1 2
3 4
julia> zeros(A)
2×2 Array{Int64,2}:
0 0
0 0
```
"""
zeros(A)
"""
Symbol(x...) -> Symbol
Create a `Symbol` by concatenating the string representations of the arguments together.
"""
Symbol
"""
isvalid(value) -> Bool
Returns `true` if the given value is valid for its type, which currently can be either
`Char` or `String`.
"""
isvalid(value)
"""
isvalid(T, value) -> Bool
Returns `true` if the given value is valid for that type. Types currently can
be either `Char` or `String`. Values for `Char` can be of type `Char` or `UInt32`.
Values for `String` can be of that type, or `Vector{UInt8}`.
"""
isvalid(T,value)
"""
unsigned(x) -> Unsigned
Convert a number to an unsigned integer. If the argument is signed, it is reinterpreted as
unsigned without checking for negative values.
"""
unsigned
"""
midpoints(e)
Compute the midpoints of the bins with edges `e`. The result is a vector/range of length
`length(e) - 1`. Note: Julia does not ignore `NaN` values in the computation.
"""
midpoints
"""
.+(x, y)
Element-wise addition operator.
```jldoctest
julia> A = [1 2; 3 4];
julia> B = [5 6; 7 8];
julia> C = [A, B]
2-element Array{Array{Int64,2},1}:
[1 2; 3 4]
[5 6; 7 8]
julia> C .+ [[1; 2] [3; 4]]
2×2 Array{Array{Int64,2},2}:
[2 3; 4 5] [4 5; 6 7]
[7 8; 9 10] [9 10; 11 12]
```
See also [`broadcast`](:func:`broadcast`).
"""
Base.:(.+)
"""
reverseind(v, i)
Given an index `i` in `reverse(v)`, return the corresponding index in `v` so that
`v[reverseind(v,i)] == reverse(v)[i]`. (This can be nontrivial in the case where `v` is a
Unicode string.)
"""
reverseind
"""
float(x)
Convert a number, array, or string to a `AbstractFloat` data type. For numeric data, the
smallest suitable `AbstractFloat` type is used. Converts strings to `Float64`.
"""
float
"""
signbit(x)
Returns `true` if the value of the sign of `x` is negative, otherwise `false`.
```jldoctest
julia> signbit(-4)
true
julia> signbit(5)
false
julia> signbit(5.5)
false
julia> signbit(-4.1)
true
```
"""
signbit
"""
cscd(x)
Compute the cosecant of `x`, where `x` is in degrees.
"""
cscd
"""
tryparse(type, str, [base])
Like [`parse`](:func:`parse`), but returns a [`Nullable`](:obj:`Nullable`) of the requested type. The result will be null if the
string does not contain a valid number.
"""
tryparse
"""
all!(r, A)
Test whether all values in `A` along the singleton dimensions of `r` are `true`, and write results to `r`.
"""
all!
"""
exit([code])
Quit (or control-D at the prompt). The default exit code is zero, indicating that the
processes completed successfully.
"""
exit
"""
skipchars(stream, predicate; linecomment::Char)
Advance the stream until before the first character for which `predicate` returns `false`.
For example `skipchars(stream, isspace)` will skip all whitespace. If keyword argument
`linecomment` is specified, characters from that character through the end of a line will
also be skipped.
"""
skipchars
"""
realmin(T)
The smallest in absolute value non-subnormal value representable by the given floating-point DataType `T`.
"""
realmin
"""
union!(s, iterable)
Union each element of `iterable` into set `s` in-place.
"""
union!
"""
deepcopy(x)
Create a deep copy of `x`: everything is copied recursively, resulting in a fully
independent object. For example, deep-copying an array produces a new array whose elements
are deep copies of the original elements. Calling `deepcopy` on an object should generally
have the same effect as serializing and then deserializing it.
As a special case, functions can only be actually deep-copied if they are anonymous,
otherwise they are just copied. The difference is only relevant in the case of closures,
i.e. functions which may contain hidden internal references.
While it isn't normally necessary, user-defined types can override the default `deepcopy`
behavior by defining a specialized version of the function `deepcopy_internal(x::T, dict::ObjectIdDict)`
(which shouldn't otherwise be used), where `T` is the type to be specialized for, and `dict`
keeps track of objects copied so far within the recursion. Within the definition,
`deepcopy_internal` should be used in place of `deepcopy`, and the `dict` variable should be
updated as appropriate before returning.
"""
deepcopy
"""
widen(x)
If `x` is a type, return a "larger" type (for numeric types, this will be
a type with at least as much range and precision as the argument, and usually more).
Otherwise `x` is converted to `widen(typeof(x))`.
```jldoctest
julia> widen(Int32)
Int64
julia> widen(1.5f0)
1.5
```
"""
widen
"""
Set([itr])
Construct a [`Set`](:obj:`Set`) of the values generated by the given iterable object, or an
empty set. Should be used instead of [`IntSet`](:obj:`IntSet`) for sparse integer sets, or
for sets of arbitrary objects.
"""
Set
"""
erf(x)
Compute the error function of `x`, defined by ``\\frac{2}{\\sqrt{\\pi}} \\int_0^x e^{-t^2} dt``
for arbitrary complex `x`.
"""
erf
"""
signed(x)
Convert a number to a signed integer. If the argument is unsigned, it is reinterpreted as
signed without checking for overflow.
"""
signed
"""
Val{c}
Create a "value type" out of `c`, which must be an `isbits` value. The intent of this
construct is to be able to dispatch on constants, e.g., `f(Val{false})` allows you to
dispatch directly (at compile-time) to an implementation `f(::Type{Val{false}})`, without
having to test the boolean value at runtime.
"""
Val
"""
|(x, y)
Bitwise or.
```jldoctest
julia> 4 | 10
14
julia> 4 | 1
5
```
"""
Base.:(|)
"""
pop!(collection, key[, default])
Delete and return the mapping for `key` if it exists in `collection`, otherwise return
`default`, or throw an error if default is not specified.
"""
pop!(collection,key,?)
"""
pop!(collection) -> item
Remove the last item in `collection` and return it.
```jldoctest
julia> A=[1, 2, 3, 4, 5, 6]
6-element Array{Int64,1}:
1
2
3
4
5
6
julia> pop!(A)
6
julia> A
5-element Array{Int64,1}:
1
2
3
4
5
```
"""
pop!(collection)
"""
seekend(s)
Seek a stream to its end.
"""
seekend
"""
DivideError()
Integer division was attempted with a denominator value of 0.
"""
DivideError
"""
unsafe_pointer_to_objref(p::Ptr)
Convert a `Ptr` to an object reference. Assumes the pointer refers to a valid heap-allocated
Julia object. If this is not the case, undefined behavior results, hence this function is
considered "unsafe" and should be used with care.
"""
unsafe_pointer_to_objref
"""
dawson(x)
Compute the Dawson function (scaled imaginary error function) of `x`, defined by
``\\frac{\\sqrt{\\pi}}{2} e^{-x^2} \\operatorname{erfi}(x)``.
"""
dawson
"""
\$(x, y)
Bitwise exclusive or.
"""
Base.:$(x, y)
# This file is a part of Julia. License is MIT: http://julialang.org/license
include("helpdb/Base.jl")
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Text / HTML objects
import Base: print, show
export HTML, @html_str
export HTML, Text, apropos
"""
`HTML(s)`: Create an object that renders `s` as html.
HTML("<div>foo</div>")
You can also use a stream for large amounts of data:
HTML() do io
println(io, "<div>foo</div>")
end
"""
type HTML{T}
content::T
end
function HTML(xs...)
HTML() do io
for x in xs
show(io, MIME"text/html"(), x)
end
end
end
show(io::IO, ::MIME"text/html", h::HTML) = print(io, h.content)
show{F <: Function}(io::IO, ::MIME"text/html", h::HTML{F}) = h.content(io)
"""
@html_str -> Docs.HTML
Create an `HTML` object from a literal string.
"""
macro html_str(s)
:(HTML($s))
end
function catdoc(xs::HTML...)
HTML() do io
for x in xs
show(io, MIME"text/html"(), x)
end
end
end
export Text, @text_str
"""
`Text(s)`: Create an object that renders `s` as plain text.
Text("foo")
You can also use a stream for large amounts of data:
Text() do io
println(io, "foo")
end
"""
type Text{T}
content::T
end
print(io::IO, t::Text) = print(io, t.content)
print{F <: Function}(io::IO, t::Text{F}) = t.content(io)
show(io::IO, t::Text) = print(io, t)
"""
@text_str -> Docs.Text
Create a `Text` object from a literal string.
"""
macro text_str(s)
:(Text($s))
end
function catdoc(xs::Text...)
Text() do io
for x in xs
show(io, MIME"text/plain"(), x)
end
end
end
# REPL help
function helpmode(line::AbstractString)
line = strip(line)
expr =
if haskey(keywords, Symbol(line))
# Docs for keywords must be treated separately since trying to parse a single
# keyword such as `function` would throw a parse error due to the missing `end`.
Symbol(line)
else
x = Base.syntax_deprecation_warnings(false) do
parse(line, raise = false)
end
# Retrieving docs for macros requires us to make a distinction between the text
# `@macroname` and `@macroname()`. These both parse the same, but are used by
# the docsystem to return different results. The first returns all documentation
# for `@macroname`, while the second returns *only* the docs for the 0-arg
# definition if it exists.
(isexpr(x, :macrocall, 1) && !endswith(line, "()")) ? quot(x) : x
end
:(Base.Docs.@repl $expr)
end
function repl_search(io::IO, s)
pre = "search:"
print(io, pre)
printmatches(io, s, completions(s), cols = displaysize(io)[2] - length(pre))
println(io, "\n")
end
repl_search(s) = repl_search(STDOUT, s)
function repl_corrections(io::IO, s)
print(io, "Couldn't find ")
Markdown.with_output_format(:cyan, io) do io
println(io, s)
end
print_correction(io, s)
end
repl_corrections(s) = repl_corrections(STDOUT, s)
macro repl(ex) repl(ex) end
function repl(s::Symbol)
quote
repl_search($(string(s)))
($(isdefined(s) || haskey(keywords, s))) || repl_corrections($(string(s)))
$(_repl(s))
end
end
isregex(x) = isexpr(x, :macrocall, 2) && x.args[1] === Symbol("@r_str") && !isempty(x.args[2])
repl(ex::Expr) = isregex(ex) ? :(apropos($ex)) : _repl(ex)
repl(str::AbstractString) = :(apropos($str))
repl(other) = :(@doc $(esc(other)))
function _repl(x)
docs = (isexpr(x, :call) && !any(isexpr(x, :(::)) for x in x.args)) ?
Base.gen_call_with_extracted_types(doc, x) : :(@doc $(esc(x)))
if isfield(x)
quote
if isa($(esc(x.args[1])), DataType)
fielddoc($(esc(x.args[1])), $(esc(x.args[2])))
else
$docs
end
end
else
docs
end
end
# Search & Rescue
# Utilities for correcting user mistakes and (eventually)
# doing full documentation searches from the repl.
# Fuzzy Search Algorithm
function matchinds(needle, haystack; acronym = false)
chars = collect(needle)
is = Int[]
lastc = '\0'
for (i, char) in enumerate(haystack)
isempty(chars) && break
while chars[1] == ' ' shift!(chars) end # skip spaces
if lowercase(char) == lowercase(chars[1]) && (!acronym || !isalpha(lastc))
push!(is, i)
shift!(chars)
end
lastc = char
end
return is
end
longer(x, y) = length(x) ≥ length(y) ? (x, true) : (y, false)
bestmatch(needle, haystack) =
longer(matchinds(needle, haystack, acronym = true),
matchinds(needle, haystack))
avgdistance(xs) =
isempty(xs) ? 0 :
(xs[end] - xs[1] - length(xs)+1)/length(xs)
function fuzzyscore(needle, haystack)
score = 0.
is, acro = bestmatch(needle, haystack)
score += (acro?2:1)*length(is) # Matched characters
score -= 2(length(needle)-length(is)) # Missing characters
!acro && (score -= avgdistance(is)/10) # Contiguous
!isempty(is) && (score -= mean(is)/100) # Closer to beginning
return score
end
function fuzzysort(search, candidates)
scores = map(cand -> (fuzzyscore(search, cand), -levenshtein(search, cand)), candidates)
candidates[sortperm(scores)] |> reverse
end
# Levenshtein Distance
function levenshtein(s1, s2)
a, b = collect(s1), collect(s2)
m = length(a)
n = length(b)
d = Array{Int}(m+1, n+1)
d[1:m+1, 1] = 0:m
d[1, 1:n+1] = 0:n
for i = 1:m, j = 1:n
d[i+1,j+1] = min(d[i , j+1] + 1,
d[i+1, j ] + 1,
d[i , j ] + (a[i] != b[j]))
end
return d[m+1, n+1]
end
function levsort(search, candidates)
scores = map(cand -> (levenshtein(search, cand), -fuzzyscore(search, cand)), candidates)
candidates = candidates[sortperm(scores)]
i = 0
for i = 1:length(candidates)
levenshtein(search, candidates[i]) > 3 && break
end
return candidates[1:i]
end
# Result printing
function printmatch(io::IO, word, match)
is, _ = bestmatch(word, match)
Markdown.with_output_format(:fade, io) do io
for (i, char) = enumerate(match)
if i in is
Markdown.with_output_format(print, :bold, io, char)
else
print(io, char)
end
end
end
end
printmatch(args...) = printfuzzy(STDOUT, args...)
function printmatches(io::IO, word, matches; cols = displaysize(io)[2])
total = 0
for match in matches
total + length(match) + 1 > cols && break
fuzzyscore(word, match) < 0 && break
print(io, " ")
printmatch(io, word, match)
total += length(match) + 1
end
end
printmatches(args...; cols = displaysize(STDOUT)[2]) = printmatches(STDOUT, args..., cols = cols)
function print_joined_cols(io::IO, ss, delim = "", last = delim; cols = displaysize(io)[2])
i = 0
total = 0
for i = 1:length(ss)
total += length(ss[i])
total + max(i-2,0)*length(delim) + (i>1?1:0)*length(last) > cols && (i-=1; break)
end
join(io, ss[1:i], delim, last)
end
print_joined_cols(args...; cols = displaysize(STDOUT)[2]) = print_joined_cols(STDOUT, args...; cols=cols)
function print_correction(io, word)
cors = levsort(word, accessible(current_module()))
pre = "Perhaps you meant "
print(io, pre)
print_joined_cols(io, cors, ", ", " or "; cols = displaysize(io)[2] - length(pre))
println(io)
return
end
print_correction(word) = print_correction(STDOUT, word)
# Completion data
const builtins = ["abstract", "baremodule", "begin", "bitstype", "break",
"catch", "ccall", "const", "continue", "do", "else",
"elseif", "end", "export", "finally", "for", "function",
"global", "if", "immutable", "import", "importall", "let",
"local", "macro", "module", "quote", "return", "try", "type",
"typealias", "using", "while"]
moduleusings(mod) = ccall(:jl_module_usings, Any, (Any,), mod)
filtervalid(names) = filter(x->!ismatch(r"#", x), map(string, names))
accessible(mod::Module) =
[filter!(s->Base.isdeprecated(mod, s), names(mod, true, true));
map(names, moduleusings(mod))...;
builtins] |> unique |> filtervalid
completions(name) = fuzzysort(name, accessible(current_module()))
completions(name::Symbol) = completions(string(name))
# Searching and apropos
# Docsearch simply returns true or false if an object contains the given needle
docsearch(haystack::AbstractString, needle) = !isempty(search(haystack, needle))
docsearch(haystack::Symbol, needle) = docsearch(string(haystack), needle)
docsearch(::Void, needle) = false
function docsearch(haystack::Array, needle)
for elt in haystack
docsearch(elt, needle) && return true
end
false
end
function docsearch(haystack, needle)
Base.warn_once("unable to search documentation of type $(typeof(haystack))")
false
end
## Searching specific documentation objects
function docsearch(haystack::MultiDoc, needle)
for v in values(haystack.docs)
docsearch(v, needle) && return true
end
false
end
function docsearch(haystack::DocStr, needle)
docsearch(parsedoc(haystack), needle) && return true
if haskey(haystack.data, :fields)
for doc in values(haystack.data[:fields])
docsearch(doc, needle) && return true
end
end
false
end
## Markdown search simply strips all markup and searches plain text version
docsearch(haystack::Markdown.MD, needle) =
docsearch(stripmd(haystack.content), needle)
"""
stripmd(x)
Strip all Markdown markup from x, leaving the result in plain text. Used
internally by apropos to make docstrings containing more than one markdown
element searchable.
"""
stripmd(x::AbstractString) = x # base case
stripmd(x::Void) = " "
stripmd(x::Vector) = string(map(stripmd, x)...)
stripmd(x::Markdown.BlockQuote) = "$(stripmd(x.content))"
stripmd(x::Markdown.Admonition) = "$(stripmd(x.content))"
stripmd(x::Markdown.Bold) = "$(stripmd(x.text))"
stripmd(x::Markdown.Code) = "$(stripmd(x.code))"
stripmd{N}(x::Markdown.Header{N}) = stripmd(x.text)
stripmd(x::Markdown.HorizontalRule) = " "
stripmd(x::Markdown.Image) = "$(stripmd(x.alt)) $(x.url)"
stripmd(x::Markdown.Italic) = "$(stripmd(x.text))"
stripmd(x::Markdown.LaTeX) = "$(x.formula)"
stripmd(x::Markdown.LineBreak) = " "
stripmd(x::Markdown.Link) = "$(stripmd(x.text)) $(x.url)"
stripmd(x::Markdown.List) = join(map(stripmd, x.items), " ")
stripmd(x::Markdown.MD) = join(map(stripmd, x.content), " ")
stripmd(x::Markdown.Paragraph) = stripmd(x.content)
stripmd(x::Markdown.Footnote) = "$(stripmd(x.id)) $(stripmd(x.text))"
stripmd(x::Markdown.Table) =
join([join(map(stripmd, r), " ") for r in x.rows], " ")
# Apropos searches through all available documentation for some string or regex
"""
apropos(string)
Search through all documentation for a string, ignoring case.
"""
apropos(string) = apropos(STDOUT, string)
apropos(io::IO, string) = apropos(io, Regex("\\Q$string", "i"))
function apropos(io::IO, needle::Regex)
for mod in modules
# Module doc might be in README.md instead of the META dict
docsearch(doc(mod), needle) && println(io, mod)
for (k, v) in meta(mod)
docsearch(v, needle) && println(io, k)
end
end
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
module DSP
import Base.trailingsize
export filt, filt!, deconv, conv, conv2, xcorr
_zerosi(b,a,T) = zeros(promote_type(eltype(b), eltype(a), T), max(length(a), length(b))-1)
"""
filt(b, a, x, [si])
Apply filter described by vectors `a` and `b` to vector `x`, with an optional initial filter
state vector `si` (defaults to zeros).
"""
function filt{T,S}(b::Union{AbstractVector, Number}, a::Union{AbstractVector, Number},
x::AbstractArray{T}, si::AbstractArray{S}=_zerosi(b,a,T))
filt!(Array{promote_type(eltype(b), eltype(a), T, S)}(size(x)), b, a, x, si)
end
# in-place filtering: returns results in the out argument, which may shadow x
# (and does so by default)
"""
filt!(out, b, a, x, [si])
Same as [`filt`](:func:`filt`) but writes the result into the `out` argument, which may
alias the input `x` to modify it in-place.
"""
function filt!{T,S,N}(out::AbstractArray, b::Union{AbstractVector, Number}, a::Union{AbstractVector, Number},
x::AbstractArray{T}, si::AbstractArray{S,N}=_zerosi(b,a,T))
isempty(b) && throw(ArgumentError("filter vector b must be non-empty"))
isempty(a) && throw(ArgumentError("filter vector a must be non-empty"))
a[1] == 0 && throw(ArgumentError("filter vector a[1] must be nonzero"))
if size(x) != size(out)
throw(ArgumentError("output size $(size(out)) must match input size $(size(x))"))
end
as = length(a)
bs = length(b)
sz = max(as, bs)
silen = sz - 1
ncols = trailingsize(x,2)
if size(si, 1) != silen
throw(ArgumentError("initial state vector si must have max(length(a),length(b))-1 rows"))
end
if N > 1 && trailingsize(si,2) != ncols
throw(ArgumentError("initial state vector si must be a vector or have the same number of columns as x"))
end
size(x,1) == 0 && return out
sz == 1 && return scale!(out, x, b[1]/a[1]) # Simple scaling without memory
# Filter coefficient normalization
if a[1] != 1
norml = a[1]
a ./= norml
b ./= norml
end
# Pad the coefficients with zeros if needed
bs<sz && (b = copy!(zeros(eltype(b), sz), b))
1<as<sz && (a = copy!(zeros(eltype(a), sz), a))
initial_si = si
for col = 1:ncols
# Reset the filter state
si = initial_si[:, N > 1 ? col : 1]
if as > 1
_filt_iir!(out, b, a, x, si, col)
else
_filt_fir!(out, b, x, si, col)
end
end
return out
end
function _filt_iir!(out, b, a, x, si, col)
silen = length(si)
@inbounds for i=1:size(x, 1)
xi = x[i,col]
val = si[1] + b[1]*xi
for j=1:(silen-1)
si[j] = si[j+1] + b[j+1]*xi - a[j+1]*val
end
si[silen] = b[silen+1]*xi - a[silen+1]*val
out[i,col] = val
end
end
function _filt_fir!(out, b, x, si, col)
silen = length(si)
@inbounds for i=1:size(x, 1)
xi = x[i,col]
val = si[1] + b[1]*xi
for j=1:(silen-1)
si[j] = si[j+1] + b[j+1]*xi
end
si[silen] = b[silen+1]*xi
out[i,col] = val
end
end
"""
deconv(b,a) -> c
Construct vector `c` such that `b = conv(a,c) + r`.
Equivalent to polynomial division.
"""
function deconv{T}(b::StridedVector{T}, a::StridedVector{T})
lb = size(b,1)
la = size(a,1)
if lb < la
return [zero(T)]
end
lx = lb-la+1
x = zeros(T, lx)
x[1] = 1
filt(b, a, x)
end
"""
conv(u,v)
Convolution of two vectors. Uses FFT algorithm.
"""
function conv{T<:Base.LinAlg.BlasFloat}(u::StridedVector{T}, v::StridedVector{T})
nu = length(u)
nv = length(v)
n = nu + nv - 1
np2 = n > 1024 ? nextprod([2,3,5], n) : nextpow2(n)
upad = [u; zeros(T, np2 - nu)]
vpad = [v; zeros(T, np2 - nv)]
if T <: Real
p = plan_rfft(upad)
y = irfft((p*upad).*(p*vpad), np2)
else
p = plan_fft!(upad)
y = ifft!((p*upad).*(p*vpad))
end
return y[1:n]
end
conv{T<:Integer}(u::StridedVector{T}, v::StridedVector{T}) = round(Int,conv(float(u), float(v)))
conv{T<:Integer, S<:Base.LinAlg.BlasFloat}(u::StridedVector{T}, v::StridedVector{S}) = conv(float(u), v)
conv{T<:Integer, S<:Base.LinAlg.BlasFloat}(u::StridedVector{S}, v::StridedVector{T}) = conv(u, float(v))
"""
conv2(u,v,A)
2-D convolution of the matrix `A` with the 2-D separable kernel generated by
the vectors `u` and `v`.
Uses 2-D FFT algorithm.
"""
function conv2{T}(u::StridedVector{T}, v::StridedVector{T}, A::StridedMatrix{T})
m = length(u)+size(A,1)-1
n = length(v)+size(A,2)-1
B = zeros(T, m, n)
B[1:size(A,1),1:size(A,2)] = A
u = fft([u;zeros(T,m-length(u))])
v = fft([v;zeros(T,n-length(v))])
C = ifft(fft(B) .* (u * v.'))
if T <: Real
return real(C)
end
return C
end
"""
conv2(B,A)
2-D convolution of the matrix `B` with the matrix `A`. Uses 2-D FFT algorithm.
"""
function conv2{T}(A::StridedMatrix{T}, B::StridedMatrix{T})
sa, sb = size(A), size(B)
At = zeros(T, sa[1]+sb[1]-1, sa[2]+sb[2]-1)
Bt = zeros(T, sa[1]+sb[1]-1, sa[2]+sb[2]-1)
At[1:sa[1], 1:sa[2]] = A
Bt[1:sb[1], 1:sb[2]] = B
p = plan_fft(At)
C = ifft((p*At).*(p*Bt))
if T <: Real
return real(C)
end
return C
end
conv2{T<:Integer}(A::StridedMatrix{T}, B::StridedMatrix{T}) = round(Int,conv2(float(A), float(B)))
conv2{T<:Integer}(u::StridedVector{T}, v::StridedVector{T}, A::StridedMatrix{T}) = round(Int,conv2(float(u), float(v), float(A)))
"""
xcorr(u,v)
Compute the cross-correlation of two vectors.
"""
function xcorr(u, v)
su = size(u,1); sv = size(v,1)
if su < sv
u = [u;zeros(eltype(u),sv-su)]
elseif sv < su
v = [v;zeros(eltype(v),su-sv)]
end
flipdim(conv(flipdim(u, 1), v), 1)
end
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
#=
import JSON
emojis = JSON.parsefile(download("https://raw.githubusercontent.com/iamcal/emoji-data/0f0cf4ea8845eb52d26df2a48c3c31c3b8cad14e/emoji_pretty.json"))
result = Dict()
for emj in emojis
name = "\\:" * emj["short_name"] * ":"
unicode = emj["unified"]
if '-' in unicode
continue
end
result[name] = "$(Char(parse(UInt32, unicode, 16)))"
end
skeys = sort(collect(keys(result)))
open("emoji_symbols.jl", "w") do fh
println(fh, "const emoji_symbols = Dict(")
for key in skeys
println(fh, " \"", escape_string(key), "\" => \"",
escape_string(result[key]), "\",")
end
println(fh, ")")
end
=#
# This file is a part of Julia. License is MIT: http://julialang.org/license
if is_windows()
const ERROR_ENVVAR_NOT_FOUND = UInt32(203)
_getenvlen(var::Vector{UInt16}) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,C_NULL,0)
_hasenv(s::Vector{UInt16}) = _getenvlen(s) != 0 || Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND
_hasenv(s::AbstractString) = _hasenv(cwstring(s))
function access_env(onError::Function, str::AbstractString)
var = cwstring(str)
len = _getenvlen(var)
if len == 0
return Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND ? "" : onError(str)
end
val = zeros(UInt16,len)
ret = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32),var,val,len)
if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0
error(string("getenv: ", str, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage()))
end
pop!(val) # NUL
return transcode(String, val)
end
function _setenv(svar::AbstractString, sval::AbstractString, overwrite::Bool=true)
var = cwstring(svar)
val = cwstring(sval)
if overwrite || !_hasenv(var)
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,val)
systemerror(:setenv, ret == 0)
end
end
function _unsetenv(svar::AbstractString)
var = cwstring(svar)
ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Ptr{UInt16},Ptr{UInt16}),var,C_NULL)
systemerror(:setenv, ret == 0)
end
else # !windows
_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var)
_hasenv(s::AbstractString) = _getenv(s) != C_NULL
function access_env(onError::Function, var::AbstractString)
val = _getenv(var)
val == C_NULL ? onError(var) : unsafe_string(val)
end
function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true)
ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite)
systemerror(:setenv, ret != 0)
end
function _unsetenv(var::AbstractString)
ret = ccall(:unsetenv, Int32, (Cstring,), var)
systemerror(:unsetenv, ret != 0)
end
end # os test
## ENV: hash interface ##
"""
EnvHash() -> EnvHash
A singleton of this type provides a hash table interface to environment variables.
"""
type EnvHash <: Associative{String,String}; end
"""
ENV
Reference to the singleton `EnvHash`, providing a dictionary interface to system environment
variables.
"""
const ENV = EnvHash()
similar(::EnvHash) = Dict{String,String}()
getindex(::EnvHash, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
get(::EnvHash, k::AbstractString, def) = access_env(k->def, k)
in(k::AbstractString, ::KeyIterator{EnvHash}) = _hasenv(k)
pop!(::EnvHash, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v)
pop!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def
delete!(::EnvHash, k::AbstractString) = (_unsetenv(k); ENV)
setindex!(::EnvHash, v, k::AbstractString) = _setenv(k,string(v))
push!(::EnvHash, k::AbstractString, v) = setindex!(ENV, v, k)
if is_windows()
start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos))
function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}})
if unsafe_load(block[1]) == 0
ccall(:FreeEnvironmentStringsW, stdcall, Int32, (Ptr{UInt16},), block[2])
return true
end
return false
end
function next(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}})
pos = block[1]
blk = block[2]
len = ccall(:wcslen, UInt, (Ptr{UInt16},), pos)
buf = Array{UInt16}(len)
unsafe_copy!(pointer(buf), pos, len)
env = transcode(String, buf)
m = match(r"^(=?[^=]+)=(.*)$"s, env)
if m === nothing
error("malformed environment entry: $env")
end
return (Pair{String,String}(m.captures[1], m.captures[2]), (pos+(len+1)*2, blk))
end
else # !windows
start(::EnvHash) = 0
done(::EnvHash, i) = (ccall(:jl_environ, Any, (Int32,), i) === nothing)
function next(::EnvHash, i)
env = ccall(:jl_environ, Any, (Int32,), i)
if env === nothing
throw(BoundsError())
end
env = env::String
m = match(r"^(.*?)=(.*)$"s, env)
if m === nothing
error("malformed environment entry: $env")
end
return (Pair{String,String}(m.captures[1], m.captures[2]), i+1)
end
end # os-test
#TODO: Make these more efficent
function length(::EnvHash)
i = 0
for (k,v) in ENV
i += 1
end
return i
end
function show(io::IO, ::EnvHash)
for (k,v) = ENV
println(io, "$k=$v")
end
end
"""
withenv(f::Function, kv::Pair...)
Execute `f()` in an environment that is temporarily modified (not replaced as in `setenv`)
by zero or more `"var"=>val` arguments `kv`. `withenv` is generally used via the
`withenv(kv...) do ... end` syntax. A value of `nothing` can be used to temporarily unset an
environment variable (if it is set). When `withenv` returns, the original environment has
been restored.
"""
function withenv{T<:AbstractString}(f::Function, keyvals::Pair{T}...)
old = Dict{T,Any}()
for (key,val) in keyvals
old[key] = get(ENV,key,nothing)
val !== nothing ? (ENV[key]=val) : delete!(ENV, key)
end
try f()
finally
for (key,val) in old
val !== nothing ? (ENV[key]=val) : delete!(ENV, key)
end
end
end
withenv(f::Function) = f() # handle empty keyvals case; see #10853
# This file is a part of Julia. License is MIT: http://julialang.org/license
include("errno_h.jl")
export
E2BIG,
EACCES,
EADDRINUSE,
EADDRNOTAVAIL,
EADV,
EAFNOSUPPORT,
EAGAIN,
EALREADY,
EBADE,
EBADF,
EBADFD,
EBADMSG,
EBADR,
EBADRQC,
EBADSLT,
EBFONT,
EBUSY,
ECANCELED,
ECHILD,
ECHRNG,
ECOMM,
ECONNABORTED,
ECONNREFUSED,
ECONNRESET,
EDEADLK,
EDESTADDRREQ,
EDOM,
EDOTDOT,
EDQUOT,
EEXIST,
EFAULT,
EFBIG,
EHOSTDOWN,
EHOSTUNREACH,
EHWPOISON,
EIDRM,
EILSEQ,
EINPROGRESS,
EINTR,
EINVAL,
EIO,
EISCONN,
EISDIR,
EISNAM,
EKEYEXPIRED,
EKEYREJECTED,
EKEYREVOKED,
EL2HLT,
EL2NSYNC,
EL3HLT,
EL3RST,
ELIBACC,
ELIBBAD,
ELIBEXEC,
ELIBMAX,
ELIBSCN,
ELNRNG,
ELOOP,
EMEDIUMTYPE,
EMFILE,
EMLINK,
EMSGSIZE,
EMULTIHOP,
ENAMETOOLONG,
ENAVAIL,
ENETDOWN,
ENETRESET,
ENETUNREACH,
ENFILE,
ENOANO,
ENOBUFS,
ENOCSI,
ENODATA,
ENODEV,
ENOENT,
ENOEXEC,
ENOKEY,
ENOLCK,
ENOLINK,
ENOMEDIUM,
ENOMEM,
ENOMSG,
ENONET,
ENOPKG,
ENOPROTOOPT,
ENOSPC,
ENOSR,
ENOSTR,
ENOSYS,
ENOTBLK,
ENOTCONN,
ENOTDIR,
ENOTEMPTY,
ENOTNAM,
ENOTRECOVERABLE,
ENOTSOCK,
ENOTTY,
ENOTUNIQ,
ENXIO,
EOPNOTSUPP,
EOVERFLOW,
EOWNERDEAD,
EPERM,
EPFNOSUPPORT,
EPIPE,
EPROTO,
EPROTONOSUPPORT,
EPROTOTYPE,
ERANGE,
EREMCHG,
EREMOTE,
EREMOTEIO,
ERESTART,
ERFKILL,
EROFS,
ESHUTDOWN,
ESOCKTNOSUPPORT,
ESPIPE,
ESRCH,
ESRMNT,
ESTALE,
ESTRPIPE,
ETIME,
ETIMEDOUT,
ETOOMANYREFS,
ETXTBSY,
EUCLEAN,
EUNATCH,
EUSERS,
EXDEV,
EXFULL
const E2BIG = Int32(7)
const EACCES = Int32(13)
const EADDRINUSE = Int32(48)
const EADDRNOTAVAIL = Int32(49)
const EAFNOSUPPORT = Int32(47)
const EAGAIN = Int32(35)
const EALREADY = Int32(37)
const EAUTH = Int32(80)
const EBADARCH = Int32(86)
const EBADEXEC = Int32(85)
const EBADF = Int32(9)
const EBADMACHO = Int32(88)
const EBADMSG = Int32(94)
const EBADRPC = Int32(72)
const EBUSY = Int32(16)
const ECANCELED = Int32(89)
const ECHILD = Int32(10)
const ECONNABORTED = Int32(53)
const ECONNREFUSED = Int32(61)
const ECONNRESET = Int32(54)
const EDEADLK = Int32(11)
const EDESTADDRREQ = Int32(39)
const EDEVERR = Int32(83)
const EDOM = Int32(33)
const EDQUOT = Int32(69)
const EEXIST = Int32(17)
const EFAULT = Int32(14)
const EFBIG = Int32(27)
const EFTYPE = Int32(79)
const EHOSTDOWN = Int32(64)
const EHOSTUNREACH = Int32(65)
const EIDRM = Int32(90)
const EILSEQ = Int32(92)
const EINPROGRESS = Int32(36)
const EINTR = Int32(4)
const EINVAL = Int32(22)
const EIO = Int32(5)
const EISCONN = Int32(56)
const EISDIR = Int32(21)
const ELAST = Int32(106)
const ELOOP = Int32(62)
const EMFILE = Int32(24)
const EMLINK = Int32(31)
const EMSGSIZE = Int32(40)
const EMULTIHOP = Int32(95)
const ENAMETOOLONG = Int32(63)
const ENEEDAUTH = Int32(81)
const ENETDOWN = Int32(50)
const ENETRESET = Int32(52)
const ENETUNREACH = Int32(51)
const ENFILE = Int32(23)
const ENOATTR = Int32(93)
const ENOBUFS = Int32(55)
const ENODATA = Int32(96)
const ENODEV = Int32(19)
const ENOENT = Int32(2)
const ENOEXEC = Int32(8)
const ENOLCK = Int32(77)
const ENOLINK = Int32(97)
const ENOMEM = Int32(12)
const ENOMSG = Int32(91)
const ENOPOLICY = Int32(103)
const ENOPROTOOPT = Int32(42)
const ENOSPC = Int32(28)
const ENOSR = Int32(98)
const ENOSTR = Int32(99)
const ENOSYS = Int32(78)
const ENOTBLK = Int32(15)
const ENOTCONN = Int32(57)
const ENOTDIR = Int32(20)
const ENOTEMPTY = Int32(66)
const ENOTRECOVERABLE = Int32(104)
const ENOTSOCK = Int32(38)
const ENOTSUP = Int32(45)
const ENOTTY = Int32(25)
const ENXIO = Int32(6)
const EOPNOTSUPP = Int32(102)
const EOVERFLOW = Int32(84)
const EOWNERDEAD = Int32(105)
const EPERM = Int32(1)
const EPFNOSUPPORT = Int32(46)
const EPIPE = Int32(32)
const EPROCLIM = Int32(67)
const EPROCUNAVAIL = Int32(76)
const EPROGMISMATCH = Int32(75)
const EPROGUNAVAIL = Int32(74)
const EPROTO = Int32(100)
const EPROTONOSUPPORT = Int32(43)
const EPROTOTYPE = Int32(41)
const EPWROFF = Int32(82)
const EQFULL = Int32(106)
const ERANGE = Int32(34)
const EREMOTE = Int32(71)
const EROFS = Int32(30)
const ERPCMISMATCH = Int32(73)
const ESHLIBVERS = Int32(87)
const ESHUTDOWN = Int32(58)
const ESOCKTNOSUPPORT = Int32(44)
const ESPIPE = Int32(29)
const ESRCH = Int32(3)
const ESTALE = Int32(70)
const ETIME = Int32(101)
const ETIMEDOUT = Int32(60)
const ETOOMANYREFS = Int32(59)
const ETXTBSY = Int32(26)
const EUSERS = Int32(68)
const EXDEV = Int32(18)
# This file is a part of Julia. License is MIT: http://julialang.org/license
# pseudo-definitions to show how everything behaves
#
# throw(label, val) = # throw a value to a dynamically enclosing block
#
# function rethrow(val)
# global current_exception = val
# throw(current_handler(), current_exception)
# end
#
# rethrow() = rethrow(current_exception)
#
# function throw(val)
# global catch_backtrace = backtrace()
# rethrow(val)
# end
## native julia error handling ##
error(s::AbstractString) = throw(ErrorException(s))
error(s...) = throw(ErrorException(Main.Base.string(s...)))
rethrow() = ccall(:jl_rethrow, Bottom, ())
rethrow(e) = ccall(:jl_rethrow_other, Bottom, (Any,), e)
backtrace() = ccall(:jl_backtrace_from_here, Array{Ptr{Void},1}, (Int32,), false)
catch_backtrace() = ccall(:jl_get_backtrace, Array{Ptr{Void},1}, ())
## keyword arg lowering generates calls to this ##
kwerr(kw, args...) = throw(MethodError(typeof(args[1]).name.mt.kwsorter, (kw,args...)))
## system error handling ##
systemerror(p, b::Bool; extrainfo=nothing) = b ? throw(Main.Base.SystemError(string(p), Libc.errno(), extrainfo)) : nothing
## assertion functions and macros ##
assert(x) = x ? nothing : throw(Main.Base.AssertionError())
macro assert(ex, msgs...)
msg = isempty(msgs) ? ex : msgs[1]
if !isempty(msgs) && (isa(msg, Expr) || isa(msg, Symbol))
# message is an expression needing evaluating
msg = :(Main.Base.string($(esc(msg))))
elseif isdefined(Main, :Base) && isdefined(Main.Base, :string)
msg = Main.Base.string(msg)
else
# string() might not be defined during bootstrap
msg = :(Main.Base.string($(Expr(:quote,msg))))
end
:($(esc(ex)) ? $(nothing) : throw(Main.Base.AssertionError($msg)))
end
# NOTE: Please keep the constant values specified below in sync with the doc string
const DEFAULT_RETRY_N = 1
const DEFAULT_RETRY_ON = e->true
const DEFAULT_RETRY_MAX_DELAY = 10.0
"""
retry(f, [retry_on]; n=1, max_delay=10.0) -> Function
Returns a lambda that retries function `f` up to `n` times in the
event of an exception. If `retry_on` is a `Type` then retry only
for exceptions of that type. If `retry_on` is a function
`test_error(::Exception) -> Bool` then retry only if it is true.
The first retry happens after a gap of 50 milliseconds or `max_delay`,
whichever is lower. Subsequently, the delays between retries are
exponentially increased with a random factor up to `max_delay`.
**Examples**
```julia
retry(http_get, e -> e.status == "503")(url)
retry(read, UVError)(io)
```
"""
function retry(f::Function, retry_on::Function=DEFAULT_RETRY_ON; n=DEFAULT_RETRY_N, max_delay=DEFAULT_RETRY_MAX_DELAY)
(args...) -> begin
delay = min(0.05, max_delay)
for i = 1:n+1
try
return f(args...)
catch e
if i > n || try retry_on(e) end !== true
rethrow(e)
end
end
delay = min(max_delay, delay)
sleep(delay * (0.8 + (rand() * 0.2)))
delay = delay * 5
end
end
end
retry(f::Function, t::Type; kw...) = retry(f, e->isa(e, t); kw...)
# This file is a part of Julia. License is MIT: http://julialang.org/license
using Core: CodeInfo
typealias Callable Union{Function,DataType}
const Bottom = Union{}
abstract AbstractSet{T}
abstract Associative{K,V}
# The real @inline macro is not available until after array.jl, so this
# internal macro splices the meta Expr directly into the function body.
macro _inline_meta()
Expr(:meta, :inline)
end
macro _noinline_meta()
Expr(:meta, :noinline)
end
macro _pure_meta()
Expr(:meta, :pure)
end
# another version of inlining that propagates an inbounds context
macro _propagate_inbounds_meta()
Expr(:meta, :inline, :propagate_inbounds)
end
convert(::Type{Any}, x::ANY) = x
convert{T}(::Type{T}, x::T) = x
convert(::Type{Tuple{}}, ::Tuple{}) = ()
convert(::Type{Tuple}, x::Tuple) = x
convert{T}(::Type{Tuple{Vararg{T}}}, x::Tuple) = cnvt_all(T, x...)
cnvt_all(T) = ()
cnvt_all(T, x, rest...) = tuple(convert(T,x), cnvt_all(T, rest...)...)
macro generated(f)
isa(f, Expr) || error("invalid syntax; @generated must be used with a function definition")
if f.head === :function || (isdefined(:length) && f.head === :(=) && length(f.args) == 2 && f.args[1].head == :call)
f.head = :stagedfunction
return Expr(:escape, f)
else
error("invalid syntax; @generated must be used with a function definition")
end
end
argtail(x, rest...) = rest
tail(x::Tuple) = argtail(x...)
tuple_type_head(T::TypeConstructor) = tuple_type_head(T.body)
function tuple_type_head(T::DataType)
@_pure_meta
T.name === Tuple.name || throw(MethodError(tuple_type_head, (T,)))
return T.parameters[1]
end
tuple_type_tail(T::TypeConstructor) = tuple_type_tail(T.body)
function tuple_type_tail(T::DataType)
@_pure_meta
T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
if isvatuple(T) && length(T.parameters) == 1
return T
end
return Tuple{argtail(T.parameters...)...}
end
tuple_type_cons{S}(::Type{S}, ::Type{Union{}}) = Union{}
function tuple_type_cons{S,T<:Tuple}(::Type{S}, ::Type{T})
@_pure_meta
Tuple{S, T.parameters...}
end
isvarargtype(t::ANY) = isa(t, DataType) && (t::DataType).name === Vararg.name
isvatuple(t::DataType) = (n = length(t.parameters); n > 0 && isvarargtype(t.parameters[n]))
unwrapva(t::ANY) = isvarargtype(t) ? t.parameters[1] : t
convert{T<:Tuple{Any,Vararg{Any}}}(::Type{T}, x::Tuple{Any, Vararg{Any}}) =
tuple(convert(tuple_type_head(T),x[1]), convert(tuple_type_tail(T), tail(x))...)
convert{T<:Tuple{Any,Vararg{Any}}}(::Type{T}, x::T) = x
oftype(x,c) = convert(typeof(x),c)
unsigned(x::Int) = reinterpret(UInt, x)
signed(x::UInt) = reinterpret(Int, x)
# conversions used by ccall
ptr_arg_cconvert{T}(::Type{Ptr{T}}, x) = cconvert(T, x)
ptr_arg_unsafe_convert{T}(::Type{Ptr{T}}, x) = unsafe_convert(T, x)
ptr_arg_unsafe_convert(::Type{Ptr{Void}}, x) = x
cconvert(T::Type, x) = convert(T, x) # do the conversion eagerly in most cases
cconvert{P<:Ptr}(::Type{P}, x) = x # but defer the conversion to Ptr to unsafe_convert
unsafe_convert{T}(::Type{T}, x::T) = x # unsafe_convert (like convert) defaults to assuming the convert occurred
unsafe_convert{P<:Ptr}(::Type{P}, x::Ptr) = convert(P, x)
reinterpret{T}(::Type{T}, x) = box(T, x)
reinterpret(::Type{Unsigned}, x::Float16) = reinterpret(UInt16,x)
reinterpret(::Type{Signed}, x::Float16) = reinterpret(Int16,x)
sizeof(x) = Core.sizeof(x)
function append_any(xs...)
# used by apply() and quote
# must be a separate function from append(), since apply() needs this
# exact function.
out = Array{Any}(4)
l = 4
i = 1
for x in xs
for y in x
if i > l
ccall(:jl_array_grow_end, Void, (Any, UInt), out, 16)
l += 16
end
Core.arrayset(out, y, i)
i += 1
end
end
ccall(:jl_array_del_end, Void, (Any, UInt), out, l-i+1)
out
end
# simple Array{Any} operations needed for bootstrap
setindex!(A::Array{Any}, x::ANY, i::Int) = Core.arrayset(A, x, i)
function length_checked_equal(args...)
n = length(args[1])
for i=2:length(args)
if length(args[i]) != n
error("argument dimensions must match")
end
end
n
end
map(f::Function, a::Array{Any,1}) = Any[ f(a[i]) for i=1:length(a) ]
function precompile(f::ANY, args::Tuple)
ccall(:jl_compile_hint, Cint, (Any,), Tuple{Core.Typeof(f), args...}) != 0
end
function precompile(argt::Type)
ccall(:jl_compile_hint, Cint, (Any,), argt) != 0
end
"""
esc(e::ANY)
Only valid in the context of an `Expr` returned from a macro. Prevents the macro hygiene
pass from turning embedded variables into gensym variables. See the [macro](:ref:`man-macros`)
section of the Metaprogramming chapter of the manual for more details and examples.
"""
esc(e::ANY) = Expr(:escape, e)
macro boundscheck(blk)
# hack: use this syntax since it avoids introducing line numbers
:($(Expr(:boundscheck,true));
$(esc(blk));
$(Expr(:boundscheck,:pop)))
end
macro inbounds(blk)
:($(Expr(:inbounds,true));
$(esc(blk));
$(Expr(:inbounds,:pop)))
end
macro label(name::Symbol)
Expr(:symboliclabel, name)
end
macro goto(name::Symbol)
Expr(:symbolicgoto, name)
end
# SimpleVector
function getindex(v::SimpleVector, i::Int)
if !(1 <= i <= length(v))
throw(BoundsError(v,i))
end
x = unsafe_load(convert(Ptr{Ptr{Void}},data_pointer_from_objref(v)) + i*sizeof(Ptr))
x == C_NULL && throw(UndefRefError())
return unsafe_pointer_to_objref(x)
end
length(v::SimpleVector) = v.length
endof(v::SimpleVector) = v.length
start(v::SimpleVector) = 1
next(v::SimpleVector,i) = (v[i],i+1)
done(v::SimpleVector,i) = (i > v.length)
isempty(v::SimpleVector) = (v.length == 0)
indices(v::SimpleVector) = (OneTo(length(v)),)
linearindices(v::SimpleVector) = indices(v, 1)
indices(v::SimpleVector, d) = d <= 1 ? indices(v)[d] : OneTo(1)
function ==(v1::SimpleVector, v2::SimpleVector)
length(v1)==length(v2) || return false
for i = 1:length(v1)
v1[i] == v2[i] || return false
end
return true
end
map(f, v::SimpleVector) = Any[ f(v[i]) for i = 1:length(v) ]
getindex(v::SimpleVector, I::AbstractArray) = Core.svec(Any[ v[i] for i in I ]...)
"""
isassigned(array, i) -> Bool
Tests whether the given array has a value associated with index `i`. Returns `false`
if the index is out of bounds, or has an undefined reference.
"""
function isassigned end
function isassigned(v::SimpleVector, i::Int)
1 <= i <= length(v) || return false
x = unsafe_load(convert(Ptr{Ptr{Void}},data_pointer_from_objref(v)) + i*sizeof(Ptr))
return x != C_NULL
end
# index colon
immutable Colon
end
const (:) = Colon()
# For passing constants through type inference
immutable Val{T}
end
# used by interpolating quote and some other things in the front end
function vector_any(xs::ANY...)
n = length(xs)
a = Array{Any}(n)
@inbounds for i = 1:n
Core.arrayset(a,xs[i],i)
end
a
end
isempty(itr) = done(itr, start(itr))
# This file is a part of Julia. License is MIT: http://julialang.org/license
## condition variables
"""
Condition()
Create an edge-triggered event source that tasks can wait for. Tasks that call `wait` on a
`Condition` are suspended and queued. Tasks are woken up when `notify` is later called on
the `Condition`. Edge triggering means that only tasks waiting at the time `notify` is
called can be woken up. For level-triggered notifications, you must keep extra state to keep
track of whether a notification has happened. The [`Channel`](:class:`Channel`) type does
this, and so can be used for level-triggered events.
"""
type Condition
waitq::Vector{Any}
Condition() = new([])
end
function wait(c::Condition)
ct = current_task()
push!(c.waitq, ct)
try
return wait()
catch
filter!(x->x!==ct, c.waitq)
rethrow()
end
end
"""
notify(condition, val=nothing; all=true, error=false)
Wake up tasks waiting for a condition, passing them `val`. If `all` is `true` (the default),
all waiting tasks are woken, otherwise only one is. If `error` is `true`, the passed value
is raised as an exception in the woken tasks.
"""
notify(c::Condition, arg::ANY=nothing; all=true, error=false) = notify(c, arg, all, error)
function notify(c::Condition, arg, all, error)
if all
for t in c.waitq
error ? schedule(t, arg, error=error) : schedule(t, arg)
end
empty!(c.waitq)
elseif !isempty(c.waitq)
t = shift!(c.waitq)
error ? schedule(t, arg, error=error) : schedule(t, arg)
end
nothing
end
notify_error(c::Condition, err) = notify(c, err, true, true)
n_waiters(c::Condition) = length(c.waitq)
# schedule an expression to run asynchronously, with minimal ceremony
"""
@schedule
Wrap an expression in a `Task` and add it to the local machine's scheduler queue.
"""
macro schedule(expr)
expr = :(()->($expr))
:(enq_work(Task($(esc(expr)))))
end
## scheduler and work queue
global const Workqueue = Any[]
function enq_work(t::Task)
t.state == :runnable || error("schedule: Task not runnable")
ccall(:uv_stop, Void, (Ptr{Void},), eventloop())
push!(Workqueue, t)
t.state = :queued
return t
end
schedule(t::Task) = enq_work(t)
"""
schedule(t::Task, [val]; error=false)
Add a task to the scheduler's queue. This causes the task to run constantly when the system
is otherwise idle, unless the task performs a blocking operation such as `wait`.
If a second argument `val` is provided, it will be passed to the task (via the return value of
`yieldto`) when it runs again. If `error` is `true`, the value is raised as an exception in
the woken task.
"""
function schedule(t::Task, arg; error=false)
# schedule a task to be (re)started with the given value or exception
if error
t.exception = arg
else
t.result = arg
end
return enq_work(t)
end
# fast version of schedule(t,v);wait()
function schedule_and_wait(t::Task, v=nothing)
t.state == :runnable || error("schedule: Task not runnable")
if isempty(Workqueue)
return yieldto(t, v)
else
t.result = v
push!(Workqueue, t)
t.state = :queued
end
return wait()
end
"""
yield()
Switch to the scheduler to allow another scheduled task to run. A task that calls this
function is still runnable, and will be restarted immediately if there are no other runnable
tasks.
"""
yield() = (enq_work(current_task()); wait())
"""
yieldto(task, arg = nothing)
Switch to the given task. The first time a task is switched to, the task's function is
called with no arguments. On subsequent switches, `arg` is returned from the task's last
call to `yieldto`. This is a low-level call that only switches tasks, not considering states
or scheduling in any way. Its use is discouraged.
"""
yieldto(t::Task, x::ANY = nothing) = ccall(:jl_switchto, Any, (Any, Any), t, x)
# yield to a task, throwing an exception in it
function throwto(t::Task, exc)
t.exception = exc
yieldto(t)
end
function wait()
while true
if isempty(Workqueue)
c = process_events(true)
if c==0 && eventloop()!=C_NULL && isempty(Workqueue)
# if there are no active handles and no runnable tasks, just
# wait for signals.
pause()
end
else
t = shift!(Workqueue)
if t.state != :queued
# assume this somehow got queued twice,
# probably broken now, but try discarding this switch and keep going
# can't throw here, because it's probably not the fault of the caller to wait
# and don't want to use print() here, because that may try to incur a task switch
ccall(:jl_safe_printf, Void, (Ptr{UInt8}, Vararg{Int32}),
"\nWARNING: Workqueue inconsistency detected: shift!(Workqueue).state != :queued\n")
continue
end
arg = t.result
t.result = nothing
t.state = :runnable
local result
try
result = yieldto(t, arg)
current_task().state == :runnable || throw(AssertionError("current_task().state == :runnable"))
catch e
ct = current_task()
if ct.state == :queued
if t.state == :runnable
# assume we failed to queue t
# return it to the queue to be scheduled later
t.result = arg
t.state = :queued
push!(Workqueue, t)
end
# return ourself to the runnable state
i = findfirst(Workqueue, ct)
i == 0 || deleteat!(Workqueue, i)
ct.state = :runnable
end
rethrow(e)
end
process_events(false)
# return when we come out of the queue
return result
end
end
assert(false)
end
if is_windows()
pause() = ccall(:Sleep, stdcall, Void, (UInt32,), 0xffffffff)
else
pause() = ccall(:pause, Void, ())
end
## async event notifications
"""
AsyncCondition()
Create a async condition that wakes up tasks waiting for it (by calling `wait` on the object)
when notified from C by a call to uv_async_send.
Waiting tasks are woken with an error when the object is closed (by `close`).
Use `isopen` to check whether it is still active.
"""
type AsyncCondition
handle::Ptr{Void}
cond::Condition
function AsyncCondition()
this = new(Libc.malloc(_sizeof_uv_async), Condition())
associate_julia_struct(this.handle, this)
preserve_handle_new(this)
err = ccall(:uv_async_init, Cint, (Ptr{Void}, Ptr{Void}, Ptr{Void}),
eventloop(), this, uv_jl_asynccb::Ptr{Void})
this
end
end
unsafe_convert(::Type{Ptr{Void}}, async::AsyncCondition) = async.handle
function wait(async::AsyncCondition)
isopen(async) || throw(EOFError())
wait(async.cond)
end
isopen(t::AsyncCondition) = (t.handle != C_NULL)
close(t::AsyncCondition) = ccall(:jl_close_uv, Void, (Ptr{Void},), t)
function _uv_hook_close(async::AsyncCondition)
async.handle = C_NULL
unpreserve_handle(async)
notify_error(async.cond, EOFError())
nothing
end
function uv_asynccb(handle::Ptr{Void})
async = @handle_as handle AsyncCondition
notify(async.cond)
nothing
end
"""
AsyncCondition(callback::Function)
Create a async condition that calls the given `callback` function. The `callback` is passed one argument,
the async condition object itself.
"""
function AsyncCondition(cb::Function)
async = AsyncCondition()
waiter = Task(function()
while isopen(async)
success = try
wait(async)
true
catch # ignore possible exception on close()
false
end
success && cb(async)
end
end)
# must start the task right away so that it can wait for the AsyncCondition before
# we re-enter the event loop. this avoids a race condition. see issue #12719
enq_work(current_task())
yieldto(waiter)
return async
end
## timer-based notifications
"""
Timer(delay, repeat=0)
Create a timer that wakes up tasks waiting for it (by calling `wait` on the timer object) at
a specified interval. Times are in seconds. Waiting tasks are woken with an error when the
timer is closed (by `close`). Use `isopen` to check whether a timer is still active.
"""
type Timer
handle::Ptr{Void}
cond::Condition
isopen::Bool
function Timer(timeout::Real, repeat::Real=0.0)
timeout ≥ 0 || throw(ArgumentError("timer cannot have negative timeout of $timeout seconds"))
repeat ≥ 0 || throw(ArgumentError("timer cannot have negative repeat interval of $repeat seconds"))
this = new(Libc.malloc(_sizeof_uv_timer), Condition(), true)
err = ccall(:uv_timer_init, Cint, (Ptr{Void}, Ptr{Void}), eventloop(), this)
if err != 0
#TODO: this codepath is currently not tested
Libc.free(this.handle)
this.handle = C_NULL
throw(UVError("uv_make_timer",err))
end
associate_julia_struct(this.handle, this)
preserve_handle_new(this)
ccall(:uv_update_time, Void, (Ptr{Void},), eventloop())
ccall(:uv_timer_start, Cint, (Ptr{Void}, Ptr{Void}, UInt64, UInt64),
this, uv_jl_timercb::Ptr{Void},
UInt64(round(timeout * 1000)) + 1, UInt64(round(repeat * 1000)))
return this
end
end
unsafe_convert(::Type{Ptr{Void}}, t::Timer) = t.handle
function wait(t::Timer)
isopen(t) || throw(EOFError())
wait(t.cond)
end
isopen(t::Timer) = t.isopen
function close(t::Timer)
if t.handle != C_NULL
t.isopen = false
ccall(:uv_timer_stop, Cint, (Ptr{Void},), t)
ccall(:jl_close_uv, Void, (Ptr{Void},), t)
end
nothing
end
function _uv_hook_close(t::Timer)
unpreserve_handle(t)
disassociate_julia_struct(t)
t.handle = C_NULL
t.isopen = false
notify_error(t.cond, EOFError())
nothing
end
function uv_timercb(handle::Ptr{Void})
t = @handle_as handle Timer
if ccall(:uv_timer_get_repeat, UInt64, (Ptr{Void},), t) == 0
# timer is stopped now
close(t)
end
notify(t.cond)
nothing
end
"""
sleep(seconds)
Block the current task for a specified number of seconds. The minimum sleep time is 1
millisecond or input of `0.001`.
"""
function sleep(sec::Real)
sec ≥ 0 || throw(ArgumentError("cannot sleep for $sec seconds"))
wait(Timer(sec))
nothing
end
# timer with repeated callback
"""
Timer(callback::Function, delay, repeat=0)
Create a timer to call the given `callback` function. The `callback` is passed one argument,
the timer object itself. The callback will be invoked after the specified initial `delay`,
and then repeating with the given `repeat` interval. If `repeat` is `0`, the timer is only
triggered once. Times are in seconds. A timer is stopped and has its resources freed by
calling `close` on it.
"""
function Timer(cb::Function, timeout::Real, repeat::Real=0.0)
t = Timer(timeout, repeat)
waiter = Task(function()
while isopen(t)
success = try
wait(t)
true
catch # ignore possible exception on close()
false
end
success && cb(t)
end
end)
# must start the task right away so that it can wait for the Timer before
# we re-enter the event loop. this avoids a race condition. see issue #12719
enq_work(current_task())
yieldto(waiter)
return t
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
export
# Modules
Collections,
FFTW,
Meta,
Operators,
Pkg,
LibGit2,
StackTraces,
Profile,
Dates,
Sys,
Test,
Libc,
Libdl,
Mmap,
LinAlg,
BLAS,
LAPACK,
Serializer,
Docs,
Markdown,
Threads,
Iterators,
# Types
AbstractChannel,
AbstractMatrix,
AbstractSet,
AbstractUnitRange,
AbstractVector,
AbstractVecOrMat,
Array,
Associative,
Bidiagonal,
BigFloat,
BigInt,
BitArray,
BitMatrix,
BitVector,
BufferStream,
CartesianIndex,
CartesianRange,
Channel,
Cmd,
Colon,
Complex,
Complex128,
Complex64,
Complex32,
DenseMatrix,
DenseVecOrMat,
DenseVector,
DevNull,
Diagonal,
Dict,
Dims,
EachLine,
Enum,
Enumerate,
Factorization,
FileMonitor,
FloatRange,
Future,
Hermitian,
UniformScaling,
InsertionSort,
IntSet,
IOBuffer,
IOStream,
LinSpace,
LowerTriangular,
Irrational,
Matrix,
MergeSort,
NTuple,
Nullable,
ObjectIdDict,
OrdinalRange,
Pair,
PartialQuickSort,
PollingFileWatcher,
QuickSort,
Range,
RangeIndex,
Rational,
Regex,
RegexMatch,
RemoteChannel,
RepString,
RevString,
RoundFromZero,
RoundDown,
RoundingMode,
RoundNearest,
RoundNearestTiesAway,
RoundNearestTiesUp,
RoundToZero,
RoundUp,
AbstractSerializer,
SerializationState,
Set,
SharedArray,
SharedMatrix,
SharedVector,
StepRange,
StridedArray,
StridedMatrix,
StridedVecOrMat,
StridedVector,
SubArray,
SubString,
Symmetric,
SymTridiagonal,
Timer,
Tridiagonal,
UnitRange,
UpperTriangular,
Val,
VecOrMat,
Vector,
VersionNumber,
WeakKeyDict,
WorkerConfig,
# Ccall types
Cchar,
Cdouble,
Cfloat,
Cint,
Cintmax_t,
Clong,
Clonglong,
Cptrdiff_t,
Cshort,
Csize_t,
Cssize_t,
Cuchar,
Cuint,
Cuintmax_t,
Culong,
Culonglong,
Cushort,
Cwchar_t,
Cstring,
Cwstring,
# Exceptions
ArgumentError,
DimensionMismatch,
CapturedException,
CompositeException,
EOFError,
ErrorException,
InvalidStateException,
KeyError,
LoadError,
InitError,
MethodError,
NullException,
ParseError,
ProcessExitedException,
RemoteException,
SystemError,
TypeError,
AssertionError,
UnicodeError,
# Global constants and variables
ARGS,
C_NULL,
ENDIAN_BOM,
ENV,
JULIA_HOME,
LOAD_PATH,
PROGRAM_FILE,
STDERR,
STDIN,
STDOUT,
VERSION,
# Mathematical constants
Inf,
Inf16,
Inf32,
Inf64,
NaN,
NaN16,
NaN32,
NaN64,
im,
π, pi,
e, eu,
γ, eulergamma,
catalan,
φ, golden,
I,
# Operators
!,
!=,
≠,
!==,
≡,
≢,
$,
%,
÷,
&,
*,
+,
-,
.!=,
.≠,
.+,
.-,
.*,
./,
.÷,
.%,
.<,
.<=,
.≤,
.==,
.>,
.>=,
.≥,
.\,
.^,
/,
//,
.//,
<,
<:,
<<,
<=,
≤,
==,
>,
>=,
≥,
>>,
.>>,
.<<,
>>>,
\,
^,
|,
|>,
~,
:,
=>,
A_ldiv_B!,
A_ldiv_Bc,
A_ldiv_Bt,
A_mul_B!,
A_mul_Bc,
A_mul_Bc!,
A_mul_Bt,
A_mul_Bt!,
A_rdiv_Bc,
A_rdiv_Bt,
Ac_ldiv_B,
Ac_ldiv_B!,
Ac_ldiv_Bc,
Ac_mul_B,
Ac_mul_B!,
Ac_mul_Bc,
Ac_mul_Bc!,
Ac_rdiv_B,
Ac_rdiv_Bc,
At_ldiv_B,
At_ldiv_B!,
At_ldiv_Bt,
At_mul_B,
At_mul_B!,
At_mul_Bt,
At_mul_Bt!,
At_rdiv_B,
At_rdiv_Bt,
# scalar math
@evalpoly,
abs,
abs2,
acos,
acosd,
acosh,
acot,
acotd,
acoth,
acsc,
acscd,
acsch,
angle,
asec,
asecd,
asech,
asin,
asind,
asinh,
atan,
atan2,
atand,
atanh,
big,
binomial,
bswap,
cbrt,
ceil,
cis,
clamp,
cld,
cmp,
complex,
conj,
copysign,
cos,
cosc,
cosd,
cosh,
cospi,
cot,
cotd,
coth,
count_ones,
count_zeros,
csc,
cscd,
csch,
dawson,
deg2rad,
den,
digamma,
div,
divrem,
eps,
erf,
erfc,
erfcinv,
erfcx,
erfi,
erfinv,
exp,
exp10,
exp2,
expm1,
exponent,
factorial,
fld,
fld1,
fldmod,
fldmod1,
flipsign,
float,
tryparse,
floor,
fma,
frexp,
gamma,
gcd,
gcdx,
hex2num,
hypot,
imag,
inv,
invdigamma,
invmod,
isapprox,
iseven,
isfinite,
isinf,
isinteger,
isnan,
isodd,
ispow2,
isqrt,
isreal,
isimag,
issubnormal,
lcm,
ldexp,
leading_ones,
leading_zeros,
lfact,
lgamma,
log,
log10,
log1p,
log2,
maxintfloat,
mod,
mod1,
modf,
mod2pi,
muladd,
nextfloat,
nextpow,
nextpow2,
nextprod,
num,
num2hex,
one,
powermod,
prevfloat,
prevpow,
prevpow2,
rad2deg,
rationalize,
real,
realmax,
realmin,
reim,
reinterpret,
rem,
round,
sec,
secd,
sech,
sign,
signbit,
signed,
signif,
significand,
sin,
sinc,
sind,
sinh,
sinpi,
sqrt,
tan,
tand,
tanh,
trailing_ones,
trailing_zeros,
trigamma,
trunc,
unsafe_trunc,
typemax,
typemin,
unsigned,
widemul,
zero,
√,
∛,
≈,
≉,
# specfun
airy,
airyai,
airyaiprime,
airybi,
airybiprime,
airyprime,
airyx,
besselh,
besselhx,
besseli,
besselix,
besselj,
besselj0,
besselj1,
besseljx,
besselk,
besselkx,
bessely,
bessely0,
bessely1,
besselyx,
beta,
eta,
hankelh1,
hankelh1x,
hankelh2,
hankelh2x,
lbeta,
polygamma,
zeta,
# arrays
bitbroadcast,
broadcast!,
broadcast,
broadcast_getindex,
broadcast_setindex!,
cat,
checkbounds,
checkindex,
circcopy!,
circshift,
circshift!,
clamp!,
colon,
conj!,
copy!,
cummax,
cummin,
cumprod,
cumprod!,
cumsum,
cumsum!,
cumsum_kbn,
eachindex,
extrema,
fill!,
fill,
find,
findfirst,
findlast,
findin,
findmax,
findmin,
findmin!,
findmax!,
findn,
findnext,
findprev,
findnz,
first,
flipdim,
gradient,
hcat,
hvcat,
ind2sub,
indexin,
indices,
indmax,
indmin,
invperm,
ipermute!,
isassigned,
isperm,
issorted,
last,
linearindices,
linspace,
logspace,
mapslices,
max,
maxabs,
maxabs!,
maximum!,
maximum,
min,
minabs,
minabs!,
minimum!,
minimum,
minmax,
ndims,
nonzeros,
countnz,
ones,
parent,
parentindexes,
permute,
permute!,
permutedims,
permutedims!,
prod!,
prod,
promote_shape,
randcycle,
randperm,
randsubseq!,
randsubseq,
range,
reducedim,
repmat,
reshape,
reverse!,
reverse,
rot180,
rotl90,
rotr90,
searchsorted,
searchsortedfirst,
searchsortedlast,
select!,
select,
shuffle,
shuffle!,
size,
slicedim,
sort!,
sort,
sortcols,
selectperm,
selectperm!,
sortperm,
sortperm!,
sortrows,
squeeze,
step,
stride,
strides,
sub2ind,
sum!,
sum,
sumabs!,
sumabs,
sumabs2!,
sumabs2,
sum_kbn,
vcat,
vec,
view,
zeros,
# linear algebra
bkfact!,
bkfact,
blkdiag,
chol,
cholfact!,
cholfact,
cond,
condskeel,
cross,
ctranspose!,
ctranspose,
det,
diag,
diagind,
diagm,
diff,
dot,
eig,
eigfact!,
eigfact,
eigmax,
eigmin,
eigs,
eigvals,
eigvals!,
eigvecs,
expm,
eye,
factorize,
givens,
hessfact!,
hessfact,
isdiag,
ishermitian,
isposdef!,
isposdef,
issymmetric,
istril,
istriu,
kron,
ldltfact,
ldltfact!,
linreg,
logabsdet,
logdet,
logm,
lu,
lufact!,
lufact,
lyap,
norm,
normalize,
normalize!,
nullspace,
ordschur!,
ordschur,
peakflops,
pinv,
qr,
qrfact!,
qrfact,
lq,
lqfact!,
lqfact,
rank,
scale!,
scale,
schur,
schurfact!,
schurfact,
sqrtm,
svd,
svdfact!,
svdfact,
svds,
svdvals!,
svdvals,
sylvester,
trace,
transpose!,
transpose,
tril!,
tril,
triu!,
triu,
vecdot,
vecnorm,
⋅,
×,
# sparse
full,
dropzeros,
dropzeros!,
# bitarrays
falses,
flipbits!,
rol,
rol!,
ror,
ror!,
trues,
# dequeues
append!,
insert!,
pop!,
prepend!,
push!,
resize!,
shift!,
unshift!,
# collections
all!,
all,
allunique,
any!,
any,
collect,
contains,
count,
delete!,
deleteat!,
eltype,
empty!,
endof,
filter!,
filter,
foldl,
foldr,
foreach,
get,
get!,
getindex,
getkey,
haskey,
in,
intersect!,
intersect,
isempty,
issubset,
keys,
keytype,
length,
map!,
map,
mapfoldl,
mapfoldr,
mapreduce,
mapreducedim,
merge!,
merge,
#pop!,
#push!,
reduce,
setdiff!,
setdiff,
setindex!,
similar,
sizehint!,
splice!,
symdiff!,
symdiff,
union!,
union,
unique,
values,
valtype,
∈,
∉,
∋,
∌,
⊆,
⊈,
⊊,
∩,
∪,
# strings and text output
ascii,
base,
base64encode,
base64decode,
Base64EncodePipe,
Base64DecodePipe,
startswith,
bin,
bits,
bytes2hex,
charwidth,
chomp,
chop,
chr2ind,
dec,
digits,
digits!,
dump,
eachmatch,
endswith,
escape_string,
graphemes,
hex,
hex2bytes,
ind2chr,
info,
is_assigned_char,
isalnum,
isalpha,
isascii,
iscntrl,
isdigit,
isgraph,
islower,
ismatch,
isnumber,
isprint,
ispunct,
isspace,
isupper,
isvalid,
isxdigit,
join,
lcfirst,
lowercase,
lpad,
lstrip,
match,
matchall,
ndigits,
nextind,
normalize_string,
oct,
prevind,
print,
print_shortest,
print_with_color,
println,
randstring,
repeat,
replace,
repr,
reverseind,
rpad,
rsearch,
rsearchindex,
rsplit,
rstrip,
search,
searchindex,
show,
showall,
showcompact,
showerror,
split,
sprint,
string,
strip,
strwidth,
summary,
transcode,
ucfirst,
unescape_string,
uppercase,
warn,
# random numbers
AbstractRNG,
MersenneTwister,
RandomDevice,
rand!,
rand,
randn!,
randn,
randexp!,
randexp,
srand,
bitrand,
randjump,
# bigfloat & precision
precision,
rounding,
setprecision,
setrounding,
get_zero_subnormals,
set_zero_subnormals,
# statistics
cor,
cov,
mean!,
mean,
median!,
median,
middle,
midpoints,
quantile!,
quantile,
std,
stdm,
var,
varm,
# signal processing
bfft!,
bfft,
brfft,
conv,
conv2,
dct!,
dct,
deconv,
fft!,
fft,
fftshift,
filt,
filt!,
idct!,
idct,
ifft!,
ifft,
ifftshift,
irfft,
plan_bfft!,
plan_bfft,
plan_brfft,
plan_dct!,
plan_dct,
plan_fft!,
plan_fft,
plan_idct!,
plan_idct,
plan_ifft!,
plan_ifft,
plan_irfft,
plan_rfft,
rfft,
xcorr,
# numerical integration
quadgk,
# iteration
done,
next,
start,
enumerate, # re-exported from Iterators
zip,
# object identity and equality
copy,
deepcopy,
hash,
identity,
isbits,
isequal,
isimmutable,
isless,
ifelse,
lexless,
lexcmp,
object_id,
sizeof,
# tasks and conditions
Condition,
consume,
current_task,
islocked,
istaskdone,
istaskstarted,
lock,
notify,
produce,
ReentrantLock,
schedule,
task_local_storage,
trylock,
unlock,
yield,
yieldto,
# time
sleep,
tic,
time,
time_ns,
toc,
toq,
# dates
Date,
DateTime,
now,
# errors
assert,
backtrace,
catch_backtrace,
error,
rethrow,
retry,
systemerror,
# stack traces
StackTrace,
StackFrame,
stacktrace,
catch_stacktrace,
# types
convert,
fieldoffset,
fieldname,
fieldnames,
isleaftype,
oftype,
promote,
promote_rule,
promote_type,
subtypes,
instances,
supertype,
typeintersect,
typejoin,
widen,
# syntax
esc,
expand,
gensym,
macroexpand,
@macroexpand,
parse,
# help and reflection
apropos,
current_module,
edit,
code_typed,
code_warntype,
code_lowered,
code_llvm,
code_native,
fullname,
functionloc,
isconst,
isinteractive,
less,
method_exists,
methods,
methodswith,
module_name,
module_parent,
names,
versioninfo,
which,
whos,
workspace,
# loading source files
__precompile__,
evalfile,
include,
include_string,
include_dependency,
reload,
# RTS internals
finalizer,
finalize,
gc,
gc_enable,
precompile,
# misc
atexit,
atreplinit,
clipboard,
exit,
ntuple,
quit,
# IP address stuff
@ip_str,
IPAddr,
IPv4,
IPv6,
# I/O and events
accept,
bind,
close,
connect,
countlines,
deserialize,
eachline,
eof,
fd,
fdio,
flush,
getaddrinfo,
gethostname,
getipaddr,
getsockname,
htol,
hton,
IOContext,
displaysize,
ismarked,
isopen,
isreadonly,
listen,
listenany,
ltoh,
mark,
nb_available,
ntoh,
open,
pipeline,
Pipe,
PipeBuffer,
poll_fd,
poll_file,
position,
RawFD,
read,
read!,
readavailable,
readbytes!,
readchomp,
readcsv,
readdir,
readdlm,
readline,
readlines,
readstring,
readuntil,
redirect_stderr,
redirect_stdin,
redirect_stdout,
recv,
recvfrom,
reset,
seek,
seekend,
seekstart,
send,
serialize,
skip,
skipchars,
takebuf_array,
takebuf_string,
truncate,
unmark,
watch_file,
write,
writecsv,
writedlm,
TCPSocket,
UDPSocket,
# multiprocessing
addprocs,
asyncmap,
CachingPool,
clear!,
ClusterManager,
default_worker_pool,
fetch,
init_worker,
interrupt,
isready,
launch,
manage,
myid,
nprocs,
nworkers,
pmap,
procs,
put!,
remote,
remotecall,
remotecall_fetch,
remotecall_wait,
remote_do,
rmprocs,
take!,
timedwait,
wait,
workers,
WorkerPool,
# multimedia I/O
Display,
display,
displayable,
TextDisplay,
istextmime,
MIME,
@MIME_str,
reprmime,
stringmime,
mimewritable,
popdisplay,
pushdisplay,
redisplay,
HTML,
Text,
# shared arrays
sdata,
indexpids,
localindexes,
# paths and file names
abspath,
basename,
dirname,
expanduser,
homedir,
isabspath,
isdirpath,
joinpath,
normpath,
realpath,
relpath,
splitdir,
splitdrive,
splitext,
# filesystem operations
cd,
chmod,
chown,
cp,
ctime,
download,
filemode,
filesize,
gperm,
isblockdev,
ischardev,
isdir,
isfifo,
isfile,
islink,
ismount,
ispath,
isreadable,
issetgid,
issetuid,
issocket,
issticky,
iswritable,
lstat,
mkdir,
mkpath,
mktemp,
mktempdir,
mtime,
mv,
operm,
pwd,
readlink,
rm,
stat,
symlink,
tempdir,
tempname,
touch,
uperm,
walkdir,
# external processes ## TODO: whittle down these exports.
detach,
getpid,
ignorestatus,
kill,
process_exited,
process_running,
readandwrite,
run,
setenv,
spawn,
success,
withenv,
# C interface
cfunction,
cglobal,
disable_sigint,
pointer,
pointer_from_objref,
unsafe_wrap,
unsafe_string,
reenable_sigint,
unsafe_copy!,
unsafe_load,
unsafe_pointer_to_objref,
unsafe_read,
unsafe_store!,
unsafe_write,
# nullable types
isnull,
unsafe_get,
# Macros
# parser internal
@__FILE__,
@__DIR__,
@int128_str,
@uint128_str,
@big_str,
@cmd, # `commands`
# notation for certain types
@b_str, # byte vector
@r_str, # regex
@s_str, # regex substitution string
@v_str, # version number
# documentation
@text_str,
@html_str,
@doc,
@doc_str,
# output
@show,
@printf,
@sprintf,
# profiling
@time,
@timed,
@timev,
@elapsed,
@allocated,
@profile,
# reflection
@which,
@edit,
@functionloc,
@less,
@code_typed,
@code_warntype,
@code_lowered,
@code_llvm,
@code_native,
# platform-conditional code
@static,
is_windows,
is_linux,
is_apple,
is_bsd,
is_unix,
# tasks
@schedule,
@sync,
@async,
@task,
@threadcall,
# multiprocessing
@spawn,
@spawnat,
@fetch,
@fetchfrom,
@everywhere,
@parallel,
# metaprogramming utilities
@generated,
@gensym,
@eval,
@deprecate,
# performance annotations
@boundscheck,
@inbounds,
@fastmath,
@simd,
@inline,
@noinline,
@polly,
@assert,
@enum,
@label,
@goto,
@view,
# SparseArrays module re-exports
SparseArrays,
AbstractSparseArray,
AbstractSparseMatrix,
AbstractSparseVector,
SparseMatrixCSC,
SparseVector,
issparse,
sparse,
sparsevec,
spdiagm,
speye,
spones,
sprand,
sprandn,
spzeros,
symperm,
rowvals,
nzrange,
nnz
# This file is a part of Julia. License is MIT: http://julialang.org/license
## symbols ##
"""
gensym([tag])
Generates a symbol which will not conflict with other variable names.
"""
gensym() = ccall(:jl_gensym, Ref{Symbol}, ())
gensym(s::String) = gensym(s.data)
gensym(a::Array{UInt8,1}) =
ccall(:jl_tagged_gensym, Ref{Symbol}, (Ptr{UInt8}, Int32), a, length(a))
gensym(ss::String...) = map(gensym, ss)
gensym(s::Symbol) =
ccall(:jl_tagged_gensym, Ref{Symbol}, (Ptr{UInt8}, Int32), s, ccall(:strlen, Csize_t, (Ptr{UInt8},), s))
"""
@gensym
Generates a gensym symbol for a variable. For example, `@gensym x y` is transformed into
`x = gensym("x"); y = gensym("y")`.
"""
macro gensym(names...)
blk = Expr(:block)
for name in names
push!(blk.args, :($(esc(name)) = gensym($(string(name)))))
end
push!(blk.args, :nothing)
return blk
end
## expressions ##
copy(e::Expr) = (n = Expr(e.head);
n.args = copy_exprargs(e.args);
n.typ = e.typ;
n)
# copy parts of an AST that the compiler mutates
copy_exprs(x::Expr) = copy(x)
copy_exprs(x::ANY) = x
copy_exprargs(x::Array{Any,1}) = Any[copy_exprs(a) for a in x]
==(x::Expr, y::Expr) = x.head === y.head && isequal(x.args, y.args)
==(x::QuoteNode, y::QuoteNode) = isequal(x.value, y.value)
"""
expand(x)
Takes the expression `x` and returns an equivalent expression in lowered form.
See also [`code_lowered`](:func:`code_lowered`).
"""
expand(x::ANY) = ccall(:jl_expand, Any, (Any,), x)
"""
macroexpand(x)
Takes the expression `x` and returns an equivalent expression with all macros removed (expanded).
"""
macroexpand(x::ANY) = ccall(:jl_macroexpand, Any, (Any,), x)
"""
@macroexpand
Return equivalent expression with all macros removed (expanded).
There is a subtle difference between `@macroexpand` and `macroexpand` in that expansion takes place in
different contexts. This is best seen in the following example:
```jldoctest
julia> module M
macro m()
1
end
function f()
(@macroexpand(@m), macroexpand(:(@m)))
end
end
M
julia> macro m()
2
end
@m (macro with 1 method)
julia> M.f()
(1,2)
```
With `@macroexpand` the expression expands where `@macroexpand` appears in the code (module
`M` in the example). With `macroexpand` the expression expands in the current module where
the code was finally called (REPL in the example).
Note that when calling `macroexpand` or `@macroexpand` directly from the REPL, both of these contexts coincide, hence there is no difference.
"""
macro macroexpand(code)
code_expanded = macroexpand(code)
QuoteNode(code_expanded)
end
## misc syntax ##
"""
eval([m::Module], expr::Expr)
Evaluate an expression in the given module and return the result. Every `Module` (except
those defined with `baremodule`) has its own 1-argument definition of `eval`, which
evaluates expressions in that module.
"""
Core.eval
"""
@eval
Evaluate an expression and return the value.
"""
macro eval(x)
:($(esc(:eval))($(Expr(:quote,x))))
end
macro inline(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :inline) : ex)
end
macro noinline(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :noinline) : ex)
end
macro pure(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :pure) : ex)
end
"""
@propagate_inbounds
Tells the compiler to inline a function while retaining the caller's inbounds context.
"""
macro propagate_inbounds(ex)
if isa(ex, Expr)
pushmeta!(ex, :inline)
pushmeta!(ex, :propagate_inbounds)
esc(ex)
else
esc(ex)
end
end
"""
@polly
Tells the compiler to apply the polyhedral optimizer Polly to a function.
"""
macro polly(ex)
esc(isa(ex, Expr) ? pushmeta!(ex, :polly) : ex)
end
## some macro utilities ##
find_vars(e) = find_vars(e, [])
function find_vars(e, lst)
if isa(e,Symbol)
if current_module()===Main && isdefined(e)
# Main runs on process 1, so send globals from there, excluding
# things defined in Base.
if !isdefined(Base,e) || eval(Base,e)!==eval(current_module(),e)
push!(lst, e)
end
end
elseif isa(e,Expr) && e.head !== :quote && e.head !== :top && e.head !== :core
for x in e.args
find_vars(x,lst)
end
end
lst
end
# wrap an expression in "let a=a,b=b,..." for each var it references
localize_vars(expr) = localize_vars(expr, true)
function localize_vars(expr, esca)
v = find_vars(expr)
# requires a special feature of the front end that knows how to insert
# the correct variables. the list of free variables cannot be computed
# from a macro.
if esca
v = map(esc,v)
end
Expr(:localize, expr, v...)
end
function pushmeta!(ex::Expr, sym::Symbol, args::Any...)
if isempty(args)
tag = sym
else
tag = Expr(sym, args...)
end
inner = ex
while inner.head == :macrocall
inner = inner.args[end]::Expr
end
idx, exargs = findmeta(inner)
if idx != 0
push!(exargs[idx].args, tag)
else
body::Expr = inner.args[2]
unshift!(body.args, Expr(:meta, tag))
end
ex
end
function popmeta!(body::Expr, sym::Symbol)
body.head == :block || return false, []
popmeta!(body.args, sym)
end
popmeta!(arg, sym) = (false, [])
function popmeta!(body::Array{Any,1}, sym::Symbol)
idx, blockargs = findmeta_block(body, args -> findmetaarg(args,sym)!=0)
if idx == 0
return false, []
end
metaargs = blockargs[idx].args
i = findmetaarg(blockargs[idx].args, sym)
if i == 0
return false, []
end
ret = isa(metaargs[i], Expr) ? (metaargs[i]::Expr).args : []
deleteat!(metaargs, i)
isempty(metaargs) && deleteat!(blockargs, idx)
true, ret
end
# Find index of `sym` in a meta expression argument list, or 0.
function findmetaarg(metaargs, sym)
for i = 1:length(metaargs)
arg = metaargs[i]
if (isa(arg, Symbol) && (arg::Symbol) == sym) ||
(isa(arg, Expr) && (arg::Expr).head == sym)
return i
end
end
return 0
end
function findmeta(ex::Expr)
if ex.head == :function || (ex.head == :(=) && typeof(ex.args[1]) == Expr && ex.args[1].head == :call)
body::Expr = ex.args[2]
body.head == :block || error(body, " is not a block expression")
return findmeta_block(ex.args)
end
error(ex, " is not a function expression")
end
findmeta(ex::Array{Any,1}) = findmeta_block(ex)
function findmeta_block(exargs, argsmatch=args->true)
for i = 1:length(exargs)
a = exargs[i]
if isa(a, Expr)
if (a::Expr).head == :meta && argsmatch((a::Expr).args)
return i, exargs
elseif (a::Expr).head == :block
idx, exa = findmeta_block(a.args, argsmatch)
if idx != 0
return idx, exa
end
end
end
end
return 0, []
end
remove_linenums!(ex) = ex
function remove_linenums!(ex::Expr)
filter!(x->!((isa(x,Expr) && x.head === :line) || isa(x,LineNumberNode)), ex.args)
for subex in ex.args
remove_linenums!(subex)
end
ex
end
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Support for @fastmath
# This module provides versions of math functions that may violate
# strict IEEE semantics.
# This allows the following transformations:
# nnan: No NaNs - Allow optimizations to assume the arguments and
# result are not NaN. Such optimizations are required to retain
# defined behavior over NaNs, but the value of the result is
# undefined.
# ninf: No Infs - Allow optimizations to assume the arguments and
# result are not +/-Inf. Such optimizations are required to
# retain defined behavior over +/-Inf, but the value of the
# result is undefined.
# nsz: No Signed Zeros - Allow optimizations to treat the sign of a
# zero argument or result as insignificant.
# arcp: Allow Reciprocal - Allow optimizations to use the reciprocal
# of an argument rather than perform division.
module FastMath
export @fastmath
import Core.Intrinsics: box, unbox, powi_llvm, sqrt_llvm_fast
const fast_op =
Dict(# basic arithmetic
:+ => :add_fast,
:- => :sub_fast,
:* => :mul_fast,
:/ => :div_fast,
:(==) => :eq_fast,
:!= => :ne_fast,
:< => :lt_fast,
:<= => :le_fast,
:abs => :abs_fast,
:abs2 => :abs2_fast,
:cmp => :cmp_fast,
:conj => :conj_fast,
:inv => :inv_fast,
:mod => :mod_fast,
:rem => :rem_fast,
:sign => :sign_fast,
:isfinite => :isfinite_fast,
:isinf => :isinf_fast,
:isnan => :isnan_fast,
:issubnormal => :issubnormal_fast,
# math functions
:^ => :pow_fast,
:acos => :acos_fast,
:acosh => :acosh_fast,
:angle => :angle_fast,
:asin => :asin_fast,
:asinh => :asinh_fast,
:atan => :atan_fast,
:atan2 => :atan2_fast,
:atanh => :atanh_fast,
:cbrt => :cbrt_fast,
:cis => :cis_fast,
:cos => :cos_fast,
:cosh => :cosh_fast,
:exp10 => :exp10_fast,
:exp2 => :exp2_fast,
:exp => :exp_fast,
:expm1 => :expm1_fast,
:hypot => :hypot_fast,
:lgamma => :lgamma_fast,
:log10 => :log10_fast,
:log1p => :log1p_fast,
:log2 => :log2_fast,
:log => :log_fast,
:max => :max_fast,
:min => :min_fast,
:minmax => :minmax_fast,
:sin => :sin_fast,
:sinh => :sinh_fast,
:sqrt => :sqrt_fast,
:tan => :tan_fast,
:tanh => :tanh_fast)
const rewrite_op =
Dict(:+= => :+,
:-= => :-,
:*= => :*,
:/= => :/,
:^= => :^)
function make_fastmath(expr::Expr)
if expr.head === :quote
return expr
end
op = get(rewrite_op, expr.head, :nothing)
if op !== :nothing
var = expr.args[1]
rhs = expr.args[2]
if isa(var, Symbol)
# simple assignment
expr = :($var = $op($var, $rhs))
elseif isa(var, Expr) && var.head === :ref
# array reference
arr = var.args[1]
inds = tuple(var.args[2:end]...)
arrvar = gensym()
indvars = tuple([gensym() for i in inds]...)
expr = quote
$(Expr(:(=), arrvar, arr))
$(Expr(:(=), Expr(:tuple, indvars...), Expr(:tuple, inds...)))
$arrvar[$(indvars...)] = $op($arrvar[$(indvars...)], $rhs)
end
end
end
Expr(make_fastmath(expr.head), map(make_fastmath, expr.args)...)
end
function make_fastmath(symb::Symbol)
fast_symb = get(fast_op, symb, :nothing)
if fast_symb === :nothing
return symb
end
:(Base.FastMath.$fast_symb)
end
make_fastmath(expr) = expr
macro fastmath(expr)
make_fastmath(esc(expr))
end
# Basic arithmetic
FloatTypes = Union{Float32, Float64}
sub_fast{T<:FloatTypes}(x::T) = box(T,Base.neg_float_fast(unbox(T,x)))
add_fast{T<:FloatTypes}(x::T, y::T) =
box(T,Base.add_float_fast(unbox(T,x), unbox(T,y)))
sub_fast{T<:FloatTypes}(x::T, y::T) =
box(T,Base.sub_float_fast(unbox(T,x), unbox(T,y)))
mul_fast{T<:FloatTypes}(x::T, y::T) =
box(T,Base.mul_float_fast(unbox(T,x), unbox(T,y)))
div_fast{T<:FloatTypes}(x::T, y::T) =
box(T,Base.div_float_fast(unbox(T,x), unbox(T,y)))
rem_fast{T<:FloatTypes}(x::T, y::T) =
box(T,Base.rem_float_fast(unbox(T,x), unbox(T,y)))
add_fast{T<:FloatTypes}(x::T, y::T, zs::T...) =
add_fast(add_fast(x, y), zs...)
mul_fast{T<:FloatTypes}(x::T, y::T, zs::T...) =
mul_fast(mul_fast(x, y), zs...)
@fastmath begin
cmp_fast{T<:FloatTypes}(x::T, y::T) = ifelse(x==y, 0, ifelse(x<y, -1, +1))
function mod_fast{T<:FloatTypes}(x::T, y::T)
r = rem(x,y)
ifelse((r > 0) $ (y > 0), r+y, r)
end
end
eq_fast{T<:FloatTypes}(x::T, y::T) =
Base.eq_float_fast(unbox(T,x),unbox(T,y))
ne_fast{T<:FloatTypes}(x::T, y::T) =
Base.ne_float_fast(unbox(T,x),unbox(T,y))
lt_fast{T<:FloatTypes}(x::T, y::T) =
Base.lt_float_fast(unbox(T,x),unbox(T,y))
le_fast{T<:FloatTypes}(x::T, y::T) =
Base.le_float_fast(unbox(T,x),unbox(T,y))
isinf_fast(x) = false
isfinite_fast(x) = true
isnan_fast(x) = false
issubnormal_fast(x) = false
# complex numbers
ComplexTypes = Union{Complex64, Complex128}
@fastmath begin
abs_fast{T<:ComplexTypes}(x::T) = hypot(real(x), imag(x))
abs2_fast{T<:ComplexTypes}(x::T) = real(x)*real(x) + imag(x)*imag(x)
conj_fast{T<:ComplexTypes}(x::T) = T(real(x), -imag(x))
inv_fast{T<:ComplexTypes}(x::T) = conj(x) / abs2(x)
sign_fast{T<:ComplexTypes}(x::T) = x == 0 ? float(zero(x)) : x/abs(x)
add_fast{T<:ComplexTypes}(x::T, y::T) =
T(real(x)+real(y), imag(x)+imag(y))
add_fast{T<:FloatTypes}(x::Complex{T}, b::T) =
Complex{T}(real(x)+b, imag(x))
add_fast{T<:FloatTypes}(a::T, y::Complex{T}) =
Complex{T}(a+real(y), imag(y))
sub_fast{T<:ComplexTypes}(x::T, y::T) =
T(real(x)-real(y), imag(x)-imag(y))
sub_fast{T<:FloatTypes}(x::Complex{T}, b::T) =
Complex{T}(real(x)-b, imag(x))
sub_fast{T<:FloatTypes}(a::T, y::Complex{T}) =
Complex{T}(a-real(y), -imag(y))
mul_fast{T<:ComplexTypes}(x::T, y::T) =
T(real(x)*real(y) - imag(x)*imag(y),
real(x)*imag(y) + imag(x)*real(y))
mul_fast{T<:FloatTypes}(x::Complex{T}, b::T) =
Complex{T}(real(x)*b, imag(x)*b)
mul_fast{T<:FloatTypes}(a::T, y::Complex{T}) =
Complex{T}(a*real(y), a*imag(y))
@inline div_fast{T<:ComplexTypes}(x::T, y::T) =
T(real(x)*real(y) + imag(x)*imag(y),
imag(x)*real(y) - real(x)*imag(y)) / abs2(y)
div_fast{T<:FloatTypes}(x::Complex{T}, b::T) =
Complex{T}(real(x)/b, imag(x)/b)
div_fast{T<:FloatTypes}(a::T, y::Complex{T}) =
Complex{T}(a*real(y), -a*imag(y)) / abs2(y)
eq_fast{T<:ComplexTypes}(x::T, y::T) =
(real(x)==real(y)) & (imag(x)==imag(y))
eq_fast{T<:FloatTypes}(x::Complex{T}, b::T) =
(real(x)==b) & (imag(x)==T(0))
eq_fast{T<:FloatTypes}(a::T, y::Complex{T}) =
(a==real(y)) & (T(0)==imag(y))
ne_fast{T<:ComplexTypes}(x::T, y::T) = !(x==y)
end
# fall-back implementations and type promotion
for op in (:abs, :abs2, :conj, :inv, :sign)
op_fast = fast_op[op]
@eval begin
# fall-back implementation for non-numeric types
$op_fast(xs...) = $op(xs...)
end
end
for op in (:+, :-, :*, :/, :(==), :!=, :<, :<=, :cmp, :mod, :rem)
op_fast = fast_op[op]
@eval begin
# fall-back implementation for non-numeric types
$op_fast(xs...) = $op(xs...)
# type promotion
$op_fast(x::Number, y::Number, zs::Number...) =
$op_fast(promote(x,y,zs...)...)
# fall-back implementation that applies after promotion
$op_fast{T<:Number}(x::T,ys::T...) = $op(x,ys...)
end
end
# Math functions
# builtins
pow_fast{T<:FloatTypes}(x::T, y::Integer) = pow_fast(x, Int32(y))
pow_fast{T<:FloatTypes}(x::T, y::Int32) =
box(T, Base.powi_llvm(unbox(T,x), unbox(Int32,y)))
# TODO: Change sqrt_llvm intrinsic to avoid nan checking; add nan
# checking to sqrt in math.jl; remove sqrt_llvm_fast intrinsic
sqrt_fast{T<:FloatTypes}(x::T) = box(T, Base.sqrt_llvm_fast(unbox(T,x)))
# libm
const libm = Base.libm_name
for f in (:acos, :acosh, :asin, :asinh, :atan, :atanh, :cbrt, :cos,
:cosh, :exp2, :exp, :expm1, :lgamma, :log10, :log1p, :log2,
:log, :sin, :sinh, :tan, :tanh)
f_fast = fast_op[f]
@eval begin
$f_fast(x::Float32) =
ccall(($(string(f,"f")),libm), Float32, (Float32,), x)
$f_fast(x::Float64) =
ccall(($(string(f)),libm), Float64, (Float64,), x)
end
end
pow_fast(x::Float32, y::Float32) =
ccall(("powf",libm), Float32, (Float32,Float32), x, y)
pow_fast(x::Float64, y::Float64) =
ccall(("pow",libm), Float64, (Float64,Float64), x, y)
atan2_fast(x::Float32, y::Float32) =
ccall(("atan2f",libm), Float32, (Float32,Float32), x, y)
atan2_fast(x::Float64, y::Float64) =
ccall(("atan2",libm), Float64, (Float64,Float64), x, y)
# explicit implementations
@fastmath begin
exp10_fast{T<:FloatTypes}(x::T) = exp2(log2(T(10))*x)
exp10_fast(x::Integer) = exp10(float(x))
hypot_fast{T<:FloatTypes}(x::T, y::T) = sqrt(x*x + y*y)
# Note: we use the same comparison for min, max, and minmax, so
# that the compiler can convert between them
max_fast{T<:FloatTypes}(x::T, y::T) = ifelse(y > x, y, x)
min_fast{T<:FloatTypes}(x::T, y::T) = ifelse(y > x, x, y)
minmax_fast{T<:FloatTypes}(x::T, y::T) = ifelse(y > x, (x,y), (y,x))
# complex numbers
cis_fast{T<:FloatTypes}(x::T) = Complex{T}(cos(x), sin(x))
# See <http://en.cppreference.com/w/cpp/numeric/complex>
pow_fast{T<:ComplexTypes}(x::T, y::T) = exp(y*log(x))
pow_fast{T<:FloatTypes}(x::T, y::Complex{T}) = exp(y*log(x))
pow_fast{T<:FloatTypes}(x::Complex{T}, y::T) = exp(y*log(x))
acos_fast{T<:ComplexTypes}(x::T) =
convert(T,π)/2 + im*log(im*x + sqrt(1-x*x))
acosh_fast{T<:ComplexTypes}(x::T) = log(x + sqrt(x+1) * sqrt(x-1))
angle_fast{T<:ComplexTypes}(x::T) = atan2(imag(x), real(x))
asin_fast{T<:ComplexTypes}(x::T) = -im*asinh(im*x)
asinh_fast{T<:ComplexTypes}(x::T) = log(x + sqrt(1+x*x))
atan_fast{T<:ComplexTypes}(x::T) = -im*atanh(im*x)
atanh_fast{T<:ComplexTypes}(x::T) = convert(T,1)/2*(log(1+x) - log(1-x))
cis_fast{T<:ComplexTypes}(x::T) = exp(-imag(x)) * cis(real(x))
cos_fast{T<:ComplexTypes}(x::T) = cosh(im*x)
cosh_fast{T<:ComplexTypes}(x::T) = convert(T,1)/2*(exp(x) + exp(-x))
exp10_fast{T<:ComplexTypes}(x::T) =
exp10(real(x)) * cis(imag(x)*log(convert(T,10)))
exp2_fast{T<:ComplexTypes}(x::T) =
exp2(real(x)) * cis(imag(x)*log(convert(T,2)))
exp_fast{T<:ComplexTypes}(x::T) = exp(real(x)) * cis(imag(x))
expm1_fast{T<:ComplexTypes}(x::T) = exp(x)-1
log10_fast{T<:ComplexTypes}(x::T) = log(x) / log(convert(T,10))
log1p_fast{T<:ComplexTypes}(x::T) = log(1+x)
log2_fast{T<:ComplexTypes}(x::T) = log(x) / log(convert(T,2))
log_fast{T<:ComplexTypes}(x::T) = T(log(abs2(x))/2, angle(x))
sin_fast{T<:ComplexTypes}(x::T) = -im*sinh(im*x)
sinh_fast{T<:ComplexTypes}(x::T) = convert(T,1)/2*(exp(x) - exp(-x))
sqrt_fast{T<:ComplexTypes}(x::T) = sqrt(abs(x)) * cis(angle(x)/2)
tan_fast{T<:ComplexTypes}(x::T) = -im*tanh(im*x)
tanh_fast{T<:ComplexTypes}(x::T) = (a=exp(x); b=exp(-x); (a-b)/(a+b))
end
# fall-back implementations and type promotion
for f in (:acos, :acosh, :angle, :asin, :asinh, :atan, :atanh, :cbrt,
:cis, :cos, :cosh, :exp10, :exp2, :exp, :expm1, :lgamma,
:log10, :log1p, :log2, :log, :sin, :sinh, :sqrt, :tan,
:tanh)
f_fast = fast_op[f]
@eval begin
$f_fast(x) = $f(x)
end
end
for f in (:^, :atan2, :hypot, :max, :min, :minmax)
f_fast = fast_op[f]
@eval begin
# fall-back implementation for non-numeric types
$f_fast(x, y) = $f(x, y)
# type promotion
$f_fast(x::Number, y::Number) = $f_fast(promote(x, y)...)
# fall-back implementation that applies after promotion
$f_fast{T<:Number}(x::T, y::T) = $f(x, y)
end
end
end
const JL_FE_UNDERFLOW = 0x0010
const JL_FE_OVERFLOW = 0x0008
const JL_FE_DIVBYZERO = 0x0004
const JL_FE_INVALID = 0x0001
const JL_FE_TONEAREST = 0x0000
const JL_FE_UPWARD = 0x0800
const JL_FE_DOWNWARD = 0x0400
const JL_FE_TOWARDZERO = 0x0c00
# This file is a part of Julia. License is MIT: http://julialang.org/license
# (This is part of the FFTW module.)
export dct, idct, dct!, idct!, plan_dct, plan_idct, plan_dct!, plan_idct!
# Discrete cosine transforms (type II/III) via FFTW's r2r transforms;
# we follow the Matlab convention and adopt a unitary normalization here.
# Unlike Matlab we compute the multidimensional transform by default,
# similar to the Julia fft functions.
type DCTPlan{T<:fftwNumber,K,inplace} <: Plan{T}
plan::r2rFFTWPlan{T}
r::Array{UnitRange{Int}} # array of indices for rescaling
nrm::Float64 # normalization factor
region::Dims # dimensions being transformed
pinv::DCTPlan{T}
DCTPlan(plan,r,nrm,region) = new(plan,r,nrm,region)
end
size(p::DCTPlan) = size(p.plan)
function show{T,K,inplace}(io::IO, p::DCTPlan{T,K,inplace})
print(io, inplace ? "FFTW in-place " : "FFTW ",
K == REDFT10 ? "DCT (DCT-II)" : "IDCT (DCT-III)", " plan for ")
showfftdims(io, p.plan.sz, p.plan.istride, eltype(p))
end
for (pf, pfr, K, inplace) in ((:plan_dct, :plan_r2r, REDFT10, false),
(:plan_dct!, :plan_r2r!, REDFT10, true),
(:plan_idct, :plan_r2r, REDFT01, false),
(:plan_idct!, :plan_r2r!, REDFT01, true))
@eval function $pf{T<:fftwNumber}(X::StridedArray{T}, region; kws...)
r = [1:n for n in size(X)]
nrm = sqrt(0.5^length(region) * normalization(X,region))
DCTPlan{T,$K,$inplace}($pfr(X, $K, region; kws...), r, nrm,
ntuple(i -> Int(region[i]), length(region)))
end
end
"""
plan_dct!(A [, dims [, flags [, timelimit]]])
Same as [`plan_dct`](:func:`plan_dct`), but operates in-place on `A`.
"""
plan_dct!
"""
plan_idct(A [, dims [, flags [, timelimit]]])
Pre-plan an optimized inverse discrete cosine transform (DCT), similar to
[`plan_fft`](:func:`plan_fft`) except producing a function that computes
[`idct`](:func:`idct`). The first two arguments have the same meaning as for
[`idct`](:func:`idct`).
"""
plan_idct
"""
plan_dct(A [, dims [, flags [, timelimit]]])
Pre-plan an optimized discrete cosine transform (DCT), similar to
[`plan_fft`](:func:`plan_fft`) except producing a function that computes
[`dct`](:func:`dct`). The first two arguments have the same meaning as for
[`dct`](:func:`dct`).
"""
plan_dct
"""
plan_idct!(A [, dims [, flags [, timelimit]]])
Same as [`plan_idct`](:func:`plan_idct`), but operates in-place on `A`.
"""
plan_idct!
function plan_inv{T,K,inplace}(p::DCTPlan{T,K,inplace})
X = Array{T}(p.plan.sz)
iK = inv_kind[K]
DCTPlan{T,iK,inplace}(inplace ?
plan_r2r!(X, iK, p.region, flags=p.plan.flags) :
plan_r2r(X, iK, p.region, flags=p.plan.flags),
p.r, p.nrm, p.region)
end
for f in (:dct, :dct!, :idct, :idct!)
pf = Symbol("plan_", f)
@eval begin
$f{T<:fftwNumber}(x::AbstractArray{T}) = $pf(x) * x
$f{T<:fftwNumber}(x::AbstractArray{T}, region) = $pf(x, region) * x
$pf(x::AbstractArray; kws...) = $pf(x, 1:ndims(x); kws...)
$f{T<:Real}(x::AbstractArray{T}, region=1:ndims(x)) = $f(fftwfloat(x), region)
$pf{T<:Real}(x::AbstractArray{T}, region; kws...) = $pf(fftwfloat(x), region; kws...)
$pf{T<:Complex}(x::AbstractArray{T}, region; kws...) = $pf(fftwcomplex(x), region; kws...)
end
end
"""
dct(A [, dims])
Performs a multidimensional type-II discrete cosine transform (DCT) of the array `A`, using
the unitary normalization of the DCT. The optional `dims` argument specifies an iterable
subset of dimensions (e.g. an integer, range, tuple, or array) to transform along. Most
efficient if the size of `A` along the transformed dimensions is a product of small primes;
see [`nextprod`](:func:`nextprod`). See also [`plan_dct`](:func:`plan_dct`) for even greater
efficiency.
"""
dct
"""
idct(A [, dims])
Computes the multidimensional inverse discrete cosine transform (DCT) of the array `A`
(technically, a type-III DCT with the unitary normalization). The optional `dims` argument
specifies an iterable subset of dimensions (e.g. an integer, range, tuple, or array) to
transform along. Most efficient if the size of `A` along the transformed dimensions is a
product of small primes; see [`nextprod`](:func:`nextprod`). See also
[`plan_idct`](:func:`plan_idct`) for even greater efficiency.
"""
idct
"""
dct!(A [, dims])
Same as [`dct!`](:func:`dct!`), except that it operates in-place on `A`, which must be an
array of real or complex floating-point values.
"""
dct!
"""
idct!(A [, dims])
Same as [`idct!`](:func:`idct!`), but operates in-place on `A`.
"""
idct!
const sqrthalf = sqrt(0.5)
const sqrt2 = sqrt(2.0)
const onerange = 1:1
function A_mul_B!{T}(y::StridedArray{T}, p::DCTPlan{T,REDFT10},
x::StridedArray{T})
assert_applicable(p.plan, x, y)
unsafe_execute!(p.plan, x, y)
scale!(y, p.nrm)
r = p.r
for d in p.region
oldr = r[d]
r[d] = onerange
y[r...] *= sqrthalf
r[d] = oldr
end
return y
end
# note: idct changes input data
function A_mul_B!{T}(y::StridedArray{T}, p::DCTPlan{T,REDFT01},
x::StridedArray{T})
assert_applicable(p.plan, x, y)
scale!(x, p.nrm)
r = p.r
for d in p.region
oldr = r[d]
r[d] = onerange
x[r...] *= sqrt2
r[d] = oldr
end
unsafe_execute!(p.plan, x, y)
return y
end
*{T}(p::DCTPlan{T,REDFT10,false}, x::StridedArray{T}) =
A_mul_B!(Array{T}(p.plan.osz), p, x)
*{T}(p::DCTPlan{T,REDFT01,false}, x::StridedArray{T}) =
A_mul_B!(Array{T}(p.plan.osz), p, copy(x)) # need copy to preserve input
*{T,K}(p::DCTPlan{T,K,true}, x::StridedArray{T}) = A_mul_B!(x, p, x)
# This file is a part of Julia. License is MIT: http://julialang.org/license
module FFTW
import ..DFT: fft, bfft, ifft, rfft, brfft, irfft, plan_fft, plan_bfft, plan_ifft, plan_rfft, plan_brfft, plan_irfft, fft!, bfft!, ifft!, plan_fft!, plan_bfft!, plan_ifft!, Plan, rfft_output_size, brfft_output_size, plan_inv, normalization, ScaledPlan
import Base: show, *, convert, unsafe_convert, size, strides, ndims, pointer, A_mul_B!
export r2r, r2r!, plan_r2r, plan_r2r!
export export_wisdom, import_wisdom, import_system_wisdom, forget_wisdom,
MEASURE, DESTROY_INPUT, UNALIGNED, CONSERVE_MEMORY, EXHAUSTIVE,
PRESERVE_INPUT, PATIENT, ESTIMATE, WISDOM_ONLY, NO_TIMELIMIT,
R2HC, HC2R, DHT, REDFT00, REDFT01, REDFT10, REDFT11,
RODFT00, RODFT01, RODFT10, RODFT11,
fftwNumber, fftwReal, fftwComplex, flops
## FFT: Implement fft by calling fftw.
const libfftw = Base.libfftw_name
const libfftwf = Base.libfftwf_name
const version = convert(VersionNumber, split(unsafe_string(cglobal((:fftw_version,Base.DFT.FFTW.libfftw), UInt8)), ['-', ' '])[2])
## Direction of FFT
const FORWARD = -1
const BACKWARD = 1
## FFTW Flags from fftw3.h
const MEASURE = UInt32(0)
const DESTROY_INPUT = UInt32(1 << 0)
const UNALIGNED = UInt32(1 << 1)
const CONSERVE_MEMORY = UInt32(1 << 2)
const EXHAUSTIVE = UInt32(1 << 3) # NO_EXHAUSTIVE is default
const PRESERVE_INPUT = UInt32(1 << 4) # cancels DESTROY_INPUT
const PATIENT = UInt32(1 << 5) # IMPATIENT is default
const ESTIMATE = UInt32(1 << 6)
const WISDOM_ONLY = UInt32(1 << 21)
const NO_SIMD = UInt32(1 << 17) # disable SIMD, useful for benchmarking
## R2R transform kinds
const R2HC = 0
const HC2R = 1
const DHT = 2
const REDFT00 = 3
const REDFT01 = 4
const REDFT10 = 5
const REDFT11 = 6
const RODFT00 = 7
const RODFT01 = 8
const RODFT10 = 9
const RODFT11 = 10
let k2s = Dict(R2HC => "R2HC", HC2R => "HC2R", DHT => "DHT", REDFT00 => "REDFT00", REDFT01 => "REDFT01", REDFT10 => "REDFT10", REDFT11 => "REDFT11", RODFT00 => "RODFT00", RODFT01 => "RODFT01", RODFT10 => "RODFT10", RODFT11 => "RODFT11")
global kind2string
kind2string(k::Integer) = k2s[Int(k)]
end
# FFTW floating-point types:
typealias fftwNumber Union{Float64,Float32,Complex128,Complex64}
typealias fftwReal Union{Float64,Float32}
typealias fftwComplex Union{Complex128,Complex64}
typealias fftwDouble Union{Float64,Complex128}
typealias fftwSingle Union{Float32,Complex64}
typealias fftwTypeDouble Union{Type{Float64},Type{Complex128}}
typealias fftwTypeSingle Union{Type{Float32},Type{Complex64}}
# For ESTIMATE plans, FFTW allows one to pass NULL for the array pointer,
# since it is not written to. Hence, it is convenient to create an
# array-like type that carries a size and a stride like a "real" array
# but which is converted to C_NULL as a pointer.
immutable FakeArray{T, N} <: DenseArray{T, N}
sz::NTuple{N, Int}
st::NTuple{N, Int}
end
size(a::FakeArray) = a.sz
strides(a::FakeArray) = a.st
unsafe_convert{T}(::Type{Ptr{T}}, a::FakeArray{T}) = convert(Ptr{T}, C_NULL)
pointer{T}(a::FakeArray{T}) = convert(Ptr{T}, C_NULL)
FakeArray{T, N}(::Type{T}, sz::NTuple{N, Int}) =
FakeArray{T, N}(sz, colmajorstrides(sz))
FakeArray{T}(::Type{T}, sz::Int...) = FakeArray(T, sz)
fakesimilar(flags, X, T) = flags & ESTIMATE != 0 ? FakeArray(T, size(X)) : Array{T}(size(X))
alignment_of(A::FakeArray) = Int32(0)
## Julia wrappers around FFTW functions
# Wisdom
# Import and export wisdom to/from a single file for all precisions,
# which is more user-friendly than requiring the user to call a
# separate routine depending on the fp precision of the plans. This
# requires a bit of trickness since we have to (a) use the libc file
# I/O routines with fftw_export_wisdom_to_file/import_wisdom_from_file
# (b) we need 256 bytes of space padding between the wisdoms to work
# around FFTW's internal file i/o buffering [see the BUFSZ constant in
# FFTW's api/import-wisdom-from-file.c file].
function export_wisdom(fname::AbstractString)
f = ccall(:fopen, Ptr{Void}, (Cstring,Cstring), fname, :w)
systemerror("could not open wisdom file $fname for writing", f == C_NULL)
ccall((:fftw_export_wisdom_to_file,libfftw), Void, (Ptr{Void},), f)
ccall(:fputs, Int32, (Ptr{UInt8},Ptr{Void}), " "^256, f) # no NUL, hence no Cstring
ccall((:fftwf_export_wisdom_to_file,libfftwf), Void, (Ptr{Void},), f)
ccall(:fclose, Void, (Ptr{Void},), f)
end
function import_wisdom(fname::AbstractString)
f = ccall(:fopen, Ptr{Void}, (Cstring,Cstring), fname, :r)
systemerror("could not open wisdom file $fname for reading", f == C_NULL)
if ccall((:fftw_import_wisdom_from_file,libfftw),Int32,(Ptr{Void},),f)==0||
ccall((:fftwf_import_wisdom_from_file,libfftwf),Int32,(Ptr{Void},),f)==0
error("failed to import wisdom from $fname")
end
ccall(:fclose, Void, (Ptr{Void},), f)
end
function import_system_wisdom()
if ccall((:fftw_import_system_wisdom,libfftw), Int32, ()) == 0 ||
ccall((:fftwf_import_system_wisdom,libfftwf), Int32, ()) == 0
error("failed to import system wisdom")
end
end
function forget_wisdom()
ccall((:fftw_forget_wisdom,libfftw), Void, ())
ccall((:fftwf_forget_wisdom,libfftwf), Void, ())
end
# Threads
let initialized = false
global set_num_threads
function set_num_threads(nthreads::Integer)
if !initialized
# must re-initialize FFTW if any FFTW routines have been called
ccall((:fftw_cleanup,libfftw), Void, ())
ccall((:fftwf_cleanup,libfftwf), Void, ())
stat = ccall((:fftw_init_threads,libfftw), Int32, ())
statf = ccall((:fftwf_init_threads,libfftwf), Int32, ())
if stat == 0 || statf == 0
error("could not initialize FFTW threads")
end
initialized = true
end
ccall((:fftw_plan_with_nthreads,libfftw), Void, (Int32,), nthreads)
ccall((:fftwf_plan_with_nthreads,libfftwf), Void, (Int32,), nthreads)
end
end
# pointer type for fftw_plan (opaque pointer)
immutable fftw_plan_struct end
typealias PlanPtr Ptr{fftw_plan_struct}
# Planner timelimits
const NO_TIMELIMIT = -1.0 # from fftw3.h
set_timelimit(precision::fftwTypeDouble,seconds) =
ccall((:fftw_set_timelimit,libfftw), Void, (Float64,), seconds)
set_timelimit(precision::fftwTypeSingle,seconds) =
ccall((:fftwf_set_timelimit,libfftwf), Void, (Float64,), seconds)
# Array alignment mod 16:
# FFTW plans may depend on the alignment of the array mod 16 bytes,
# i.e. the address mod 16 of the first element of the array, in order
# to exploit SIMD operations. Julia arrays are, by default, aligned
# to 16-byte boundaries (address mod 16 == 0), but this may not be
# true for data imported from external C code, or for SubArrays.
# Use the undocumented routine fftw_alignment_of to determine the
# alignment of a given pointer modulo whatever FFTW needs; this
# function will be documented in FFTW 3.3.4.
if Base.libfftw_name == "libmkl_rt"
alignment_of{T<:fftwDouble}(A::StridedArray{T}) =
convert(Int32, convert(Int64, pointer(A)) % 16)
alignment_of{T<:fftwSingle}(A::StridedArray{T}) =
convert(Int32, convert(Int64, pointer(A)) % 16)
else
alignment_of{T<:fftwDouble}(A::StridedArray{T}) =
ccall((:fftw_alignment_of, libfftw), Int32, (Ptr{T},), A)
alignment_of{T<:fftwSingle}(A::StridedArray{T}) =
ccall((:fftwf_alignment_of, libfftwf), Int32, (Ptr{T},), A)
end
# FFTWPlan (low-level)
# low-level storage of the FFTW plan, along with the information
# needed to determine whether it is applicable. We need to put
# this into a type to support a finalizer on the fftw_plan.
# K is FORWARD/BACKWARD for forward/backward or r2c/c2r plans, respectively.
# For r2r plans, K is a tuple of the transform kinds along each dimension.
abstract FFTWPlan{T<:fftwNumber,K,inplace} <: Plan{T}
for P in (:cFFTWPlan, :rFFTWPlan, :r2rFFTWPlan) # complex, r2c/c2r, and r2r
@eval begin
type $P{T<:fftwNumber,K,inplace,N} <: FFTWPlan{T,K,inplace}
plan::PlanPtr
sz::NTuple{N, Int} # size of array on which plan operates (Int tuple)
osz::NTuple{N, Int} # size of output array (Int tuple)
istride::NTuple{N, Int} # strides of input
ostride::NTuple{N, Int} # strides of output
ialign::Int32 # alignment mod 16 of input
oalign::Int32 # alignment mod 16 of input
flags::UInt32 # planner flags
region::Any # region (iterable) of dims that are transormed
pinv::ScaledPlan
function $P(plan::PlanPtr, flags::Integer, R::Any,
X::StridedArray{T, N}, Y::StridedArray)
p = new(plan, size(X), size(Y), strides(X), strides(Y),
alignment_of(X), alignment_of(Y), flags, R)
finalizer(p, destroy_plan)
p
end
end
end
end
size(p::FFTWPlan) = p.sz
unsafe_convert(::Type{PlanPtr}, p::FFTWPlan) = p.plan
destroy_plan{T<:fftwDouble}(plan::FFTWPlan{T}) =
ccall((:fftw_destroy_plan,libfftw), Void, (PlanPtr,), plan)
destroy_plan{T<:fftwSingle}(plan::FFTWPlan{T}) =
ccall((:fftwf_destroy_plan,libfftwf), Void, (PlanPtr,), plan)
cost{T<:fftwDouble}(plan::FFTWPlan{T}) =
ccall((:fftw_cost,libfftw), Float64, (PlanPtr,), plan)
cost{T<:fftwSingle}(plan::FFTWPlan{T}) =
ccall((:fftwf_cost,libfftwf), Float64, (PlanPtr,), plan)
function arithmetic_ops{T<:fftwDouble}(plan::FFTWPlan{T})
# Change to individual Ref after we can allocate them on stack
ref = Ref{NTuple{3, Float64}}()
ptr = Ptr{Float64}(Base.unsafe_convert(Ptr{NTuple{3, Float64}}, ref))
ccall((:fftw_flops,libfftw), Void,
(PlanPtr,Ptr{Float64},Ptr{Float64},Ptr{Float64}),
plan, ptr, ptr + 8, ptr + 16)
(round(Int64, ref[][1]), round(Int64, ref[][2]), round(Int64, ref[][3]))
end
function arithmetic_ops{T<:fftwSingle}(plan::FFTWPlan{T})
# Change to individual Ref after we can allocate them on stack
ref = Ref{NTuple{3, Float64}}()
ptr = Ptr{Float64}(Base.unsafe_convert(Ptr{NTuple{3, Float64}}, ref))
ccall((:fftwf_flops,libfftwf), Void,
(PlanPtr,Ptr{Float64},Ptr{Float64},Ptr{Float64}),
plan, ptr, ptr + 8, ptr + 16)
(round(Int64, ref[][1]), round(Int64, ref[][2]), round(Int64, ref[][3]))
end
flops(plan::FFTWPlan) = let ops = arithmetic_ops(plan)
ops[1] + ops[2] + 2 * ops[3] # add + mul + 2*fma
end
# Pretty-printing plans
function showfftdims(io, sz::Dims, istride::Dims, T)
if isempty(sz)
print(io, "0-dimensional")
elseif length(sz) == 1
print(io, sz[1], "-element")
else
print(io, join(sz, "×"))
end
if istride == colmajorstrides(sz)
print(io, " array of ", T)
else
print(io, " $istride-strided array of ", T)
end
end
# The sprint_plan function was released in FFTW 3.3.4
sprint_plan_{T<:fftwDouble}(plan::FFTWPlan{T}) =
ccall((:fftw_sprint_plan,libfftw), Ptr{UInt8}, (PlanPtr,), plan)
sprint_plan_{T<:fftwSingle}(plan::FFTWPlan{T}) =
ccall((:fftwf_sprint_plan,libfftwf), Ptr{UInt8}, (PlanPtr,), plan)
function sprint_plan(plan::FFTWPlan)
unsafe_wrap(String, sprint_plan_(plan), true)
end
function show{T,K,inplace}(io::IO, p::cFFTWPlan{T,K,inplace})
print(io, inplace ? "FFTW in-place " : "FFTW ",
K < 0 ? "forward" : "backward", " plan for ")
showfftdims(io, p.sz, p.istride, T)
version >= v"3.3.4" && print(io, "\n", sprint_plan(p))
end
function show{T,K,inplace}(io::IO, p::rFFTWPlan{T,K,inplace})
print(io, inplace ? "FFTW in-place " : "FFTW ",
K < 0 ? "real-to-complex" : "complex-to-real",
" plan for ")
showfftdims(io, p.sz, p.istride, T)
version >= v"3.3.4" && print(io, "\n", sprint_plan(p))
end
function show{T,K,inplace}(io::IO, p::r2rFFTWPlan{T,K,inplace})
print(io, inplace ? "FFTW in-place r2r " : "FFTW r2r ")
if isempty(K)
print(io, "0-dimensional")
elseif K == ntuple(i -> K[1], length(K))
print(io, kind2string(K[1]))
if length(K) > 1
print(io, "^", length(K))
end
else
print(io, join(map(kind2string, K), "×"))
end
print(io, " plan for ")
showfftdims(io, p.sz, p.istride, T)
version >= v"3.3.4" && print(io, "\n", sprint_plan(p))
end
# Check whether a FFTWPlan is applicable to a given input array, and
# throw an informative error if not:
function assert_applicable{T}(p::FFTWPlan{T}, X::StridedArray{T})
if size(X) != p.sz
throw(ArgumentError("FFTW plan applied to wrong-size array"))
elseif strides(X) != p.istride
throw(ArgumentError("FFTW plan applied to wrong-strides array"))
elseif alignment_of(X) != p.ialign || p.flags & UNALIGNED != 0
throw(ArgumentError("FFTW plan applied to array with wrong memory alignment"))
end
end
function assert_applicable{T,K,inplace}(p::FFTWPlan{T,K,inplace}, X::StridedArray{T}, Y::StridedArray)
assert_applicable(p, X)
if size(Y) != p.osz
throw(ArgumentError("FFTW plan applied to wrong-size output"))
elseif strides(Y) != p.ostride
throw(ArgumentError("FFTW plan applied to wrong-strides output"))
elseif alignment_of(Y) != p.oalign || p.flags & UNALIGNED != 0
throw(ArgumentError("FFTW plan applied to output with wrong memory alignment"))
elseif inplace != (pointer(X) == pointer(Y))
throw(ArgumentError(string("FFTW ",
inplace ? "in-place" : "out-of-place",
" plan applied to ",
inplace ? "out-of-place" : "in-place",
" data")))
end
end
# strides for a column-major (Julia-style) array of size == sz
colmajorstrides(sz) = isempty(sz) ? () : (1,cumprod(Int[sz[1:end-1]...])...)
# Execute
unsafe_execute!{T<:fftwDouble}(plan::FFTWPlan{T}) =
ccall((:fftw_execute,libfftw), Void, (PlanPtr,), plan)
unsafe_execute!{T<:fftwSingle}(plan::FFTWPlan{T}) =
ccall((:fftwf_execute,libfftwf), Void, (PlanPtr,), plan)
unsafe_execute!{T<:fftwDouble}(plan::cFFTWPlan{T},
X::StridedArray{T}, Y::StridedArray{T}) =
ccall((:fftw_execute_dft,libfftw), Void,
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
unsafe_execute!{T<:fftwSingle}(plan::cFFTWPlan{T},
X::StridedArray{T}, Y::StridedArray{T}) =
ccall((:fftwf_execute_dft,libfftwf), Void,
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
unsafe_execute!(plan::rFFTWPlan{Float64,FORWARD},
X::StridedArray{Float64}, Y::StridedArray{Complex128}) =
ccall((:fftw_execute_dft_r2c,libfftw), Void,
(PlanPtr,Ptr{Float64},Ptr{Complex128}), plan, X, Y)
unsafe_execute!(plan::rFFTWPlan{Float32,FORWARD},
X::StridedArray{Float32}, Y::StridedArray{Complex64}) =
ccall((:fftwf_execute_dft_r2c,libfftwf), Void,
(PlanPtr,Ptr{Float32},Ptr{Complex64}), plan, X, Y)
unsafe_execute!(plan::rFFTWPlan{Complex128,BACKWARD},
X::StridedArray{Complex128}, Y::StridedArray{Float64}) =
ccall((:fftw_execute_dft_c2r,libfftw), Void,
(PlanPtr,Ptr{Complex128},Ptr{Float64}), plan, X, Y)
unsafe_execute!(plan::rFFTWPlan{Complex64,BACKWARD},
X::StridedArray{Complex64}, Y::StridedArray{Float32}) =
ccall((:fftwf_execute_dft_c2r,libfftwf), Void,
(PlanPtr,Ptr{Complex64},Ptr{Float32}), plan, X, Y)
unsafe_execute!{T<:fftwDouble}(plan::r2rFFTWPlan{T},
X::StridedArray{T}, Y::StridedArray{T}) =
ccall((:fftw_execute_r2r,libfftw), Void,
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
unsafe_execute!{T<:fftwSingle}(plan::r2rFFTWPlan{T},
X::StridedArray{T}, Y::StridedArray{T}) =
ccall((:fftwf_execute_r2r,libfftwf), Void,
(PlanPtr,Ptr{T},Ptr{T}), plan, X, Y)
# NOTE ON GC (garbage collection):
# The FFTWPlan has a finalizer so that gc will destroy the plan,
# which is necessary for gc to work with plan_fft. However,
# even when we are creating a single-use FFTWPlan [e.g. for fftn(x)],
# we intentionally do NOT call destroy_plan explicitly, and instead
# wait for garbage collection. The reason is that, in the common
# case where the user calls fft(x) a second time soon afterwards,
# if destroy_plan has not yet been called then FFTW will internally
# re-use the table of trigonometric constants from the first plan.
# Compute dims and howmany for FFTW guru planner
function dims_howmany(X::StridedArray, Y::StridedArray,
sz::Array{Int,1}, region)
reg = [region...]
if length(unique(reg)) < length(reg)
throw(ArgumentError("each dimension can be transformed at most once"))
end
ist = [strides(X)...]
ost = [strides(Y)...]
dims = [sz[reg] ist[reg] ost[reg]]'
oreg = [1:ndims(X);]
oreg[reg] = 0
oreg = filter(d -> d > 0, oreg)
howmany = [sz[oreg] ist[oreg] ost[oreg]]'
return (dims, howmany)
end
# check & convert kinds into int32 array with same length as region
function fix_kinds(region, kinds)
if length(kinds) != length(region)
if length(kinds) > length(region)
throw(ArgumentError("too many transform kinds"))
else
if isempty(kinds)
throw(ArgumentError("must supply a transform kind"))
end
k = Array{Int32}(length(region))
k[1:length(kinds)] = [kinds...]
k[length(kinds)+1:end] = kinds[end]
kinds = k
end
else
kinds = Int32[kinds...]
end
for i = 1:length(kinds)
if kinds[i] < 0 || kinds[i] > 10
throw(ArgumentError("invalid transform kind"))
end
end
return kinds
end
# low-level FFTWPlan creation (for internal use in FFTW module)
for (Tr,Tc,fftw,lib) in ((:Float64,:Complex128,"fftw",libfftw),
(:Float32,:Complex64,"fftwf",libfftwf))
@eval function (::Type{cFFTWPlan{$Tc,K,inplace,N}}){K,inplace,N}(X::StridedArray{$Tc,N},
Y::StridedArray{$Tc,N},
region, flags::Integer, timelimit::Real)
direction = K
set_timelimit($Tr, timelimit)
R = isa(region, Tuple) ? region : copy(region)
dims, howmany = dims_howmany(X, Y, [size(X)...], R)
plan = ccall(($(string(fftw,"_plan_guru64_dft")),$lib),
PlanPtr,
(Int32, Ptr{Int}, Int32, Ptr{Int},
Ptr{$Tc}, Ptr{$Tc}, Int32, UInt32),
size(dims,2), dims, size(howmany,2), howmany,
X, Y, direction, flags)
set_timelimit($Tr, NO_TIMELIMIT)
if plan == C_NULL
error("FFTW could not create plan") # shouldn't normally happen
end
return cFFTWPlan{$Tc,K,inplace,N}(plan, flags, R, X, Y)
end
@eval function (::Type{rFFTWPlan{$Tr,$FORWARD,inplace,N}}){inplace,N}(X::StridedArray{$Tr,N},
Y::StridedArray{$Tc,N},
region, flags::Integer, timelimit::Real)
R = isa(region, Tuple) ? region : copy(region)
region = circshift([region...],-1) # FFTW halves last dim
set_timelimit($Tr, timelimit)
dims, howmany = dims_howmany(X, Y, [size(X)...], region)
plan = ccall(($(string(fftw,"_plan_guru64_dft_r2c")),$lib),
PlanPtr,
(Int32, Ptr{Int}, Int32, Ptr{Int},
Ptr{$Tr}, Ptr{$Tc}, UInt32),
size(dims,2), dims, size(howmany,2), howmany,
X, Y, flags)
set_timelimit($Tr, NO_TIMELIMIT)
if plan == C_NULL
error("FFTW could not create plan") # shouldn't normally happen
end
return rFFTWPlan{$Tr,$FORWARD,inplace,N}(plan, flags, R, X, Y)
end
@eval function (::Type{rFFTWPlan{$Tc,$BACKWARD,inplace,N}}){inplace,N}(X::StridedArray{$Tc,N},
Y::StridedArray{$Tr,N},
region, flags::Integer, timelimit::Real)
R = isa(region, Tuple) ? region : copy(region)
region = circshift([region...],-1) # FFTW halves last dim
set_timelimit($Tr, timelimit)
dims, howmany = dims_howmany(X, Y, [size(Y)...], region)
plan = ccall(($(string(fftw,"_plan_guru64_dft_c2r")),$lib),
PlanPtr,
(Int32, Ptr{Int}, Int32, Ptr{Int},
Ptr{$Tc}, Ptr{$Tr}, UInt32),
size(dims,2), dims, size(howmany,2), howmany,
X, Y, flags)
set_timelimit($Tr, NO_TIMELIMIT)
if plan == C_NULL
error("FFTW could not create plan") # shouldn't normally happen
end
return rFFTWPlan{$Tc,$BACKWARD,inplace,N}(plan, flags, R, X, Y)
end
@eval function (::Type{r2rFFTWPlan{$Tr,ANY,inplace,N}}){inplace,N}(X::StridedArray{$Tr,N},
Y::StridedArray{$Tr,N},
region, kinds, flags::Integer,
timelimit::Real)
R = isa(region, Tuple) ? region : copy(region)
knd = fix_kinds(region, kinds)
set_timelimit($Tr, timelimit)
dims, howmany = dims_howmany(X, Y, [size(X)...], region)
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib),
PlanPtr,
(Int32, Ptr{Int}, Int32, Ptr{Int},
Ptr{$Tr}, Ptr{$Tr}, Ptr{Int32}, UInt32),
size(dims,2), dims, size(howmany,2), howmany,
X, Y, knd, flags)
set_timelimit($Tr, NO_TIMELIMIT)
if plan == C_NULL
error("FFTW could not create plan") # shouldn't normally happen
end
r2rFFTWPlan{$Tr,(map(Int,knd)...),inplace,N}(plan, flags, R, X, Y)
end
# support r2r transforms of complex = transforms of real & imag parts
@eval function (::Type{r2rFFTWPlan{$Tc,ANY,inplace,N}}){inplace,N}(X::StridedArray{$Tc,N},
Y::StridedArray{$Tc,N},
region, kinds, flags::Integer,
timelimit::Real)
R = isa(region, Tuple) ? region : copy(region)
knd = fix_kinds(region, kinds)
set_timelimit($Tr, timelimit)
dims, howmany = dims_howmany(X, Y, [size(X)...], region)
dims[2:3, 1:size(dims,2)] *= 2
howmany[2:3, 1:size(howmany,2)] *= 2
howmany = [howmany [2,1,1]] # append loop over real/imag parts
plan = ccall(($(string(fftw,"_plan_guru64_r2r")),$lib),
PlanPtr,
(Int32, Ptr{Int}, Int32, Ptr{Int},
Ptr{$Tc}, Ptr{$Tc}, Ptr{Int32}, UInt32),
size(dims,2), dims, size(howmany,2), howmany,
X, Y, knd, flags)
set_timelimit($Tr, NO_TIMELIMIT)
if plan == C_NULL
error("FFTW could not create plan") # shouldn't normally happen
end
r2rFFTWPlan{$Tc,(map(Int,knd)...),inplace,N}(plan, flags, R, X, Y)
end
end
# Convert arrays of numeric types to FFTW-supported packed complex-float types
# (FIXME: is there a way to use the Julia promotion rules more cleverly here?)
fftwcomplex{T<:fftwComplex}(X::StridedArray{T}) = X
fftwcomplex{T<:fftwReal}(X::AbstractArray{T}) =
copy!(Array{typeof(complex(one(T)))}(size(X)), X)
fftwcomplex{T<:Real}(X::AbstractArray{T}) = copy!(Array{Complex128}(size(X)),X)
fftwcomplex{T<:Complex}(X::AbstractArray{T}) =
copy!(Array{Complex128}(size(X)), X)
fftwfloat{T<:fftwReal}(X::StridedArray{T}) = X
fftwfloat{T<:Real}(X::AbstractArray{T}) = copy!(Array{Float64}(size(X)), X)
fftwfloat{T<:Complex}(X::AbstractArray{T}) = fftwcomplex(X)
for (f,direction) in ((:fft,FORWARD), (:bfft,BACKWARD))
plan_f = Symbol("plan_",f)
plan_f! = Symbol("plan_",f,"!")
idirection = -direction
@eval begin
function $plan_f{T<:fftwComplex,N}(X::StridedArray{T,N}, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
cFFTWPlan{T,$direction,false,N}(X, fakesimilar(flags, X, T),
region, flags, timelimit)
end
function $plan_f!{T<:fftwComplex,N}(X::StridedArray{T,N}, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
cFFTWPlan{T,$direction,true,N}(X, X, region, flags, timelimit)
end
$plan_f{T<:fftwComplex}(X::StridedArray{T}; kws...) =
$plan_f(X, 1:ndims(X); kws...)
$plan_f!{T<:fftwComplex}(X::StridedArray{T}; kws...) =
$plan_f!(X, 1:ndims(X); kws...)
function plan_inv{T<:fftwComplex,N,inplace}(p::cFFTWPlan{T,$direction,inplace,N})
X = Array{T}(p.sz)
Y = inplace ? X : fakesimilar(p.flags, X, T)
ScaledPlan(cFFTWPlan{T,$idirection,inplace,N}(X, Y, p.region,
p.flags, NO_TIMELIMIT),
normalization(X, p.region))
end
end
end
function A_mul_B!{T}(y::StridedArray{T}, p::cFFTWPlan{T}, x::StridedArray{T})
assert_applicable(p, x, y)
unsafe_execute!(p, x, y)
return y
end
function *{T,K,N}(p::cFFTWPlan{T,K,false}, x::StridedArray{T,N})
assert_applicable(p, x)
y = Array{T}(p.osz)::Array{T,N}
unsafe_execute!(p, x, y)
return y
end
function *{T,K}(p::cFFTWPlan{T,K,true}, x::StridedArray{T})
assert_applicable(p, x)
unsafe_execute!(p, x, x)
return x
end
# rfft/brfft and planned variants. No in-place version for now.
for (Tr,Tc) in ((:Float32,:Complex64),(:Float64,:Complex128))
# Note: use $FORWARD and $BACKWARD below because of issue #9775
@eval begin
function plan_rfft{N}(X::StridedArray{$Tr,N}, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
osize = rfft_output_size(X, region)
Y = flags&ESTIMATE != 0 ? FakeArray($Tc,osize...) : Array{$Tc}(osize...)
rFFTWPlan{$Tr,$FORWARD,false,N}(X, Y, region, flags, timelimit)
end
function plan_brfft{N}(X::StridedArray{$Tc,N}, d::Integer, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
osize = brfft_output_size(X, d, region)
Y = flags&ESTIMATE != 0 ? FakeArray($Tr,osize...) : Array{$Tr}(osize...)
# FFTW currently doesn't support PRESERVE_INPUT for
# multidimensional out-of-place c2r transforms, so
# we have to handle 1d and >1d cases separately with a copy. Ugh.
if length(region) <= 1
rFFTWPlan{$Tc,$BACKWARD,false,N}(X, Y, region,
flags | PRESERVE_INPUT,
timelimit)
else
rFFTWPlan{$Tc,$BACKWARD,false,N}(copy(X), Y, region, flags,
timelimit)
end
end
plan_rfft(X::StridedArray{$Tr};kws...)=plan_rfft(X,1:ndims(X);kws...)
plan_brfft(X::StridedArray{$Tr};kws...)=plan_brfft(X,1:ndims(X);kws...)
function plan_inv{N}(p::rFFTWPlan{$Tr,$FORWARD,false,N})
X = Array{$Tr}(p.sz)
Y = p.flags&ESTIMATE != 0 ? FakeArray($Tc,p.osz) : Array{$Tc}(p.osz)
ScaledPlan(rFFTWPlan{$Tc,$BACKWARD,false,N}(Y, X, p.region,
length(p.region) <= 1 ?
p.flags | PRESERVE_INPUT :
p.flags, NO_TIMELIMIT),
normalization(X, p.region))
end
function plan_inv{N}(p::rFFTWPlan{$Tc,$BACKWARD,false,N})
X = Arra{$Tc}(p.sz)
Y = p.flags&ESTIMATE != 0 ? FakeArray($Tr,p.osz) : Array{$Tr}(p.osz)
ScaledPlan(rFFTWPlan{$Tr,$FORWARD,false,N}(Y, X, p.region,
p.flags, NO_TIMELIMIT),
normalization(Y, p.region))
end
function A_mul_B!(y::StridedArray{$Tc}, p::rFFTWPlan{$Tr,$FORWARD}, x::StridedArray{$Tr})
assert_applicable(p, x, y)
unsafe_execute!(p, x, y)
return y
end
function A_mul_B!(y::StridedArray{$Tr}, p::rFFTWPlan{$Tc,$BACKWARD}, x::StridedArray{$Tc})
assert_applicable(p, x, y)
unsafe_execute!(p, x, y) # note: may overwrite x as well as y!
return y
end
function *{N}(p::rFFTWPlan{$Tr,$FORWARD,false}, x::StridedArray{$Tr,N})
assert_applicable(p, x)
y = Array{$Tc}(p.osz)::Array{$Tc,N}
unsafe_execute!(p, x, y)
return y
end
function *{N}(p::rFFTWPlan{$Tc,$BACKWARD,false}, x::StridedArray{$Tc,N})
if p.flags & PRESERVE_INPUT != 0
assert_applicable(p, x)
y = Array{$Tr}(p.osz)::Array{$Tr,N}
unsafe_execute!(p, x, y)
else # need to make a copy to avoid overwriting x
xc = copy(x)
assert_applicable(p, xc)
y = Array{$Tr}(p.osz)::Array{$Tr,N}
unsafe_execute!(p, xc, y)
end
return y
end
end
end
"""
plan_rfft(A [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Pre-plan an optimized real-input FFT, similar to [`plan_fft`](:func:`plan_fft`) except for
[`rfft`](:func:`rfft`) instead of [`fft`](:func:`fft`). The first two arguments, and the
size of the transformed result, are the same as for [`rfft`](:func:`rfft`).
"""
plan_rfft
"""
plan_brfft(A, d [, dims]; flags=FFTW.ESTIMATE; timelimit=Inf)
Pre-plan an optimized real-input unnormalized transform, similar to
[`plan_rfft`](:func:`plan_rfft`) except for [`brfft`](:func:`brfft`) instead of
[`rfft`](:func:`rfft`). The first two arguments and the size of the transformed result, are
the same as for [`brfft`](:func:`brfft`).
"""
plan_brfft
# FFTW r2r transforms (low-level interface)
for f in (:r2r, :r2r!)
pf = Symbol("plan_", f)
@eval begin
$f{T<:fftwNumber}(x::AbstractArray{T}, kinds) = $pf(x, kinds) * x
$f{T<:fftwNumber}(x::AbstractArray{T}, kinds, region) = $pf(x, kinds, region) * x
$pf(x::AbstractArray, kinds; kws...) = $pf(x, kinds, 1:ndims(x); kws...)
$f{T<:Real}(x::AbstractArray{T}, kinds, region=1:ndims(x)) = $f(fftwfloat(x), kinds, region)
$pf{T<:Real}(x::AbstractArray{T}, kinds, region; kws...) = $pf(fftwfloat(x), kinds, region; kws...)
$f{T<:Complex}(x::AbstractArray{T}, kinds, region=1:ndims(x)) = $f(fftwcomplex(x), kinds, region)
$pf{T<:Complex}(x::AbstractArray{T}, kinds, region; kws...) = $pf(fftwcomplex(x), kinds, region; kws...)
end
end
function plan_r2r{T<:fftwNumber,N}(X::StridedArray{T,N}, kinds, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
r2rFFTWPlan{T,ANY,false,N}(X, fakesimilar(flags, X, T), region, kinds,
flags, timelimit)
end
function plan_r2r!{T<:fftwNumber,N}(X::StridedArray{T,N}, kinds, region;
flags::Integer=ESTIMATE,
timelimit::Real=NO_TIMELIMIT)
r2rFFTWPlan{T,ANY,true,N}(X, X, region, kinds, flags, timelimit)
end
"""
r2r(A, kind [, dims])
Performs a multidimensional real-input/real-output (r2r) transform
of type `kind` of the array `A`, as defined in the FFTW manual.
`kind` specifies either a discrete cosine transform of various types
(`FFTW.REDFT00`, `FFTW.REDFT01`, `FFTW.REDFT10`, or
`FFTW.REDFT11`), a discrete sine transform of various types
(`FFTW.RODFT00`, `FFTW.RODFT01`, `FFTW.RODFT10`, or
`FFTW.RODFT11`), a real-input DFT with halfcomplex-format output
(`FFTW.R2HC` and its inverse `FFTW.HC2R`), or a discrete
Hartley transform (`FFTW.DHT`). The `kind` argument may be
an array or tuple in order to specify different transform types
along the different dimensions of `A`; `kind[end]` is used
for any unspecified dimensions. See the FFTW manual for precise
definitions of these transform types, at http://www.fftw.org/doc.
The optional `dims` argument specifies an iterable subset of
dimensions (e.g. an integer, range, tuple, or array) to transform
along. `kind[i]` is then the transform type for `dims[i]`,
with `kind[end]` being used for `i > length(kind)`.
See also [`plan_r2r`](:func:`plan_r2r`) to pre-plan optimized r2r transforms.
"""
FFTW.r2r
"""
r2r!(A, kind [, dims])
Same as [`r2r`](:func:`r2r`), but operates in-place on `A`, which must be
an array of real or complex floating-point numbers.
"""
FFTW.r2r!
"""
plan_r2r!(A, kind [, dims [, flags [, timelimit]]])
Similar to [`plan_fft`](:func:`Base.plan_fft`), but corresponds to [`r2r!`](:func:`r2r!`).
"""
FFTW.plan_r2r!
"""
plan_r2r(A, kind [, dims [, flags [, timelimit]]])
Pre-plan an optimized r2r transform, similar to [`plan_fft`](:func:`Base.plan_fft`)
except that the transforms (and the first three arguments)
correspond to [`r2r`](:func:`r2r`) and [`r2r!`](:func:`r2r!`), respectively.
"""
FFTW.plan_r2r
# mapping from r2r kind to the corresponding inverse transform
const inv_kind = Dict{Int,Int}(R2HC => HC2R, HC2R => R2HC, DHT => DHT,
REDFT00 => REDFT00,
REDFT01 => REDFT10, REDFT10 => REDFT01,
REDFT11 => REDFT11,
RODFT00 => RODFT00,
RODFT01 => RODFT10, RODFT10 => RODFT01,
RODFT11 => RODFT11)
# r2r inverses are normalized to 1/N, where N is a "logical" size
# the transform with length n and kind k:
function logical_size(n::Integer, k::Integer)
k <= DHT && return n
k == REDFT00 && return 2(n-1)
k == RODFT00 && return 2(n+1)
return 2n
end
function plan_inv{T<:fftwNumber,K,inplace,N}(p::r2rFFTWPlan{T,K,inplace,N})
X = Array{T}(p.sz)
iK = fix_kinds(p.region, [inv_kind[k] for k in K])
Y = inplace ? X : fakesimilar(p.flags, X, T)
ScaledPlan(r2rFFTWPlan{T,ANY,inplace,N}(X, Y, p.region, iK,
p.flags, NO_TIMELIMIT),
normalization(real(T),
map(logical_size, [p.sz...][[p.region...]], iK),
1:length(iK)))
end
function A_mul_B!{T}(y::StridedArray{T}, p::r2rFFTWPlan{T}, x::StridedArray{T})
assert_applicable(p, x, y)
unsafe_execute!(p, x, y)
return y
end
function *{T,K,N}(p::r2rFFTWPlan{T,K,false}, x::StridedArray{T,N})
assert_applicable(p, x)
y = Array{T}(p.osz)::Array{T,N}
unsafe_execute!(p, x, y)
return y
end
function *{T,K}(p::r2rFFTWPlan{T,K,true}, x::StridedArray{T})
assert_applicable(p, x)
unsafe_execute!(p, x, x)
return x
end
include("dct.jl")
end # module
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Operations with the file system (paths) ##
export
cd,
chmod,
chown,
cp,
cptree,
mkdir,
mkpath,
mktemp,
mktempdir,
mv,
pwd,
rename,
readlink,
readdir,
rm,
samefile,
sendfile,
symlink,
tempdir,
tempname,
touch,
walkdir
# get and set current directory
"""
pwd() -> AbstractString
Get the current working directory.
"""
function pwd()
b = Array{UInt8}(1024)
len = Ref{Csize_t}(length(b))
uv_error(:getcwd, ccall(:uv_cwd, Cint, (Ptr{UInt8}, Ptr{Csize_t}), b, len))
String(b[1:len[]])
end
"""
cd(dir::AbstractString=homedir())
Set the current working directory.
"""
function cd(dir::AbstractString)
uv_error("chdir $dir", ccall(:uv_chdir, Cint, (Cstring,), dir))
end
cd() = cd(homedir())
if is_windows()
function cd(f::Function, dir::AbstractString)
old = pwd()
try
cd(dir)
f()
finally
cd(old)
end
end
else
function cd(f::Function, dir::AbstractString)
fd = ccall(:open, Int32, (Cstring, Int32), :., 0)
systemerror(:open, fd == -1)
try
cd(dir)
f()
finally
systemerror(:fchdir, ccall(:fchdir, Int32, (Int32,), fd) != 0)
systemerror(:close, ccall(:close, Int32, (Int32,), fd) != 0)
end
end
end
"""
cd(f::Function, dir::AbstractString=homedir())
Temporarily changes the current working directory and applies function `f` before returning.
"""
cd(f::Function) = cd(f, homedir())
"""
mkdir(path::AbstractString, mode::Unsigned=0o777)
Make a new directory with name `path` and permissions `mode`. `mode` defaults to `0o777`,
modified by the current file creation mask.
"""
function mkdir(path::AbstractString, mode::Unsigned=0o777)
@static if is_windows()
ret = ccall(:_wmkdir, Int32, (Cwstring,), path)
else
ret = ccall(:mkdir, Int32, (Cstring, UInt32), path, mode)
end
systemerror(:mkdir, ret != 0; extrainfo=path)
end
"""
mkpath(path::AbstractString, mode::Unsigned=0o777)
Create all directories in the given `path`, with permissions `mode`. `mode` defaults to
`0o777`, modified by the current file creation mask.
"""
function mkpath(path::AbstractString, mode::Unsigned=0o777)
isdirpath(path) && (path = dirname(path))
dir = dirname(path)
(path == dir || isdir(path)) && return
mkpath(dir, mode)
try
mkdir(path, mode)
# If there is a problem with making the directory, but the directory
# does in fact exist, then ignore the error. Else re-throw it.
catch err
if isa(err, SystemError) && isdir(path)
return
else
rethrow()
end
end
end
mkdir(path::AbstractString, mode::Signed) = throw(ArgumentError("mode must be an unsigned integer; try 0o$mode"))
mkpath(path::AbstractString, mode::Signed) = throw(ArgumentError("mode must be an unsigned integer; try 0o$mode"))
"""
rm(path::AbstractString; force::Bool=false, recursive::Bool=false)
Delete the file, link, or empty directory at the given path. If `force=true` is passed, a
non-existing path is not treated as error. If `recursive=true` is passed and the path is a
directory, then all contents are removed recursively.
"""
function rm(path::AbstractString; force::Bool=false, recursive::Bool=false)
if islink(path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment