-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Based on #16580, also much work done by quinnj. `(a=1, ...)` syntax is implemented, and `(; ...)` syntax is implemented but not yet enabled.
- Loading branch information
1 parent
80a2c2f
commit 953079e
Showing
21 changed files
with
611 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
# This file is a part of Julia. License is MIT: https://julialang.org/license | ||
|
||
function NamedTuple{names,T}(args::Tuple) where {names, T <: Tuple} | ||
if length(args) == length(names) | ||
if @generated | ||
N = length(names) | ||
types = T.parameters | ||
Expr(:new, :(NamedTuple{names,T}), Any[ :(convert($(types[i]), args[$i])) for i in 1:N ]...) | ||
else | ||
N = length(names) | ||
NT = NamedTuple{names,T} | ||
ccall(:jl_new_structv, Any, (Any, Ptr{Void}, UInt32), NT, collect(Any, T(args)), N)::NT | ||
end | ||
else | ||
throw(ArgumentError("Wrong number of arguments to named tuple constructor.")) | ||
end | ||
end | ||
|
||
function NamedTuple{names}(args::Tuple) where {names} | ||
NamedTuple{names,typeof(args)}(args) | ||
end | ||
|
||
NamedTuple() = NamedTuple{(),Tuple{}}(()) | ||
|
||
length(t::NamedTuple) = nfields(t) | ||
start(t::NamedTuple) = 1 | ||
done(t::NamedTuple, iter) = iter > nfields(t) | ||
next(t::NamedTuple, iter) = (getfield(t, iter), iter + 1) | ||
endof(t::NamedTuple) = nfields(t) | ||
getindex(t::NamedTuple, i::Int) = getfield(t, i) | ||
getindex(t::NamedTuple, i::Symbol) = getfield(t, i) | ||
indexed_next(t::NamedTuple, i::Int, state) = (getfield(t,i), i+1) | ||
|
||
convert(::Type{NamedTuple{names,T}}, nt::NamedTuple{names,T}) where {names,T} = nt | ||
convert(::Type{NamedTuple{names}}, nt::NamedTuple{names}) where {names} = nt | ||
|
||
function convert(::Type{NamedTuple{names,T}}, nt::NamedTuple{names}) where {names,T} | ||
NamedTuple{names,T}(T(nt)) | ||
end | ||
|
||
function show(io::IO, t::NamedTuple) | ||
n = nfields(t) | ||
if n == 0 | ||
print(io, "NamedTuple()") | ||
else | ||
print(io, "(") | ||
for i = 1:n | ||
print(io, fieldname(typeof(t),i), " = "); show(io, getfield(t,i)) | ||
if n == 1 | ||
print(io, ",") | ||
elseif i < n | ||
print(io, ", ") | ||
end | ||
end | ||
print(io, ")") | ||
end | ||
end | ||
|
||
eltype(::Type{NamedTuple{names,T}}) where {names,T} = eltype(T) | ||
|
||
==(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = Tuple(a) == Tuple(b) | ||
==(a::NamedTuple, b::NamedTuple) = false | ||
|
||
isequal(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = isequal(Tuple(a), Tuple(b)) | ||
isequal(a::NamedTuple, b::NamedTuple) = false | ||
|
||
_nt_names(::NamedTuple{names}) where {names} = names | ||
_nt_names(::Type{T}) where {names,T<:NamedTuple{names}} = names | ||
|
||
hash(x::NamedTuple, h::UInt) = xor(object_id(_nt_names(x)), hash(Tuple(x), h)) | ||
|
||
isless(a::NamedTuple{n}, b::NamedTuple{n}) where {n} = isless(Tuple(a), Tuple(b)) | ||
# TODO: case where one argument's names are a prefix of the other's | ||
|
||
same_names(::NamedTuple{names}...) where {names} = true | ||
same_names(::NamedTuple...) = false | ||
|
||
function map(f, nt::NamedTuple{names}, nts::NamedTuple...) where names | ||
if !same_names(nt, nts...) | ||
throw(ArgumentError("Named tuple names do not match.")) | ||
end | ||
# this method makes sure we don't define a map(f) method | ||
NT = NamedTuple{names} | ||
if @generated | ||
N = length(names) | ||
M = length(nts) | ||
args = Expr[:(f($(Expr[:(getfield(nt, $j)), (:(getfield(nts[$i], $j)) for i = 1:M)...]...))) for j = 1:N] | ||
:( NT(($(args...),)) ) | ||
else | ||
NT(map(f, map(Tuple, (nt, nts...))...)) | ||
end | ||
end | ||
|
||
# a version of `in` for the older world these generated functions run in | ||
@pure function sym_in(x::Symbol, itr::Tuple{Vararg{Symbol}}) | ||
for y in itr | ||
y === x && return true | ||
end | ||
return false | ||
end | ||
|
||
@pure function merge_names(an::Tuple{Vararg{Symbol}}, bn::Tuple{Vararg{Symbol}}) | ||
names = Symbol[an...] | ||
for n in bn | ||
if !sym_in(n, an) | ||
push!(names, n) | ||
end | ||
end | ||
(names...,) | ||
end | ||
|
||
@pure function merge_types(names::Tuple{Vararg{Symbol}}, a::Type{<:NamedTuple}, b::Type{<:NamedTuple}) | ||
bn = _nt_names(b) | ||
Tuple{Any[ fieldtype(sym_in(n, bn) ? b : a, n) for n in names ]...} | ||
end | ||
|
||
""" | ||
merge(a::NamedTuple, b::NamedTuple) | ||
Construct a new named tuple by merging two existing ones. | ||
The order of fields in `a` is preserved, but values are taken from matching | ||
fields in `b`. Fields present only in `b` are appended at the end. | ||
```jldoctest | ||
julia> merge((a=1, b=2, c=3), (b=4, d=5)) | ||
(a = 1, b = 4, c = 3, d = 5) | ||
``` | ||
""" | ||
function merge(a::NamedTuple{an}, b::NamedTuple{bn}) where {an, bn} | ||
if @generated | ||
names = merge_names(an, bn) | ||
types = merge_types(names, a, b) | ||
vals = Any[ :(getfield($(sym_in(n, bn) ? :b : :a), $(Expr(:quote, n)))) for n in names ] | ||
:( NamedTuple{$names,$types}(($(vals...),)) ) | ||
else | ||
names = merge_names(an, bn) | ||
types = merge_types(names, typeof(a), typeof(b)) | ||
NamedTuple{names,types}(map(n->getfield(sym_in(n, bn) ? b : a, n), names)) | ||
end | ||
end | ||
|
||
merge(a::NamedTuple{()}, b::NamedTuple) = b | ||
|
||
""" | ||
merge(a::NamedTuple, iterable) | ||
Interpret an iterable of key-value pairs as a named tuple, and perform a merge. | ||
```jldoctest | ||
julia> merge((a=1, b=2, c=3), [:b=>4, :d=>5]) | ||
(a = 1, b = 4, c = 3, d = 5) | ||
``` | ||
""" | ||
function merge(a::NamedTuple, itr) | ||
names = Symbol[] | ||
vals = Any[] | ||
for (k,v) in itr | ||
push!(names, k) | ||
push!(vals, v) | ||
end | ||
merge(a, NamedTuple{(names...)}((vals...,))) | ||
end | ||
|
||
keys(nt::NamedTuple{names}) where {names} = names | ||
values(nt::NamedTuple) = Tuple(nt) | ||
haskey(nt::NamedTuple, key::Union{Integer, Symbol}) = isdefined(nt, key) | ||
get(nt::NamedTuple, key::Union{Integer, Symbol}, default) = haskey(nt, key) ? getfield(nt, key) : default | ||
get(f::Callable, nt::NamedTuple, key::Union{Integer, Symbol}) = haskey(nt, key) ? getfield(nt, key) : f() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.