From 63e04bf0d6068b08d4f9b07cf5772ade9afcfc3a Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 1 Mar 2018 16:25:50 -0500 Subject: [PATCH 1/8] add AbstractChar supertype of Char --- NEWS.md | 3 + base/arrayshow.jl | 2 +- base/boot.jl | 14 +- base/char.jl | 117 +++++--- base/compiler/validation.jl | 2 +- base/filesystem.jl | 1 + base/io.jl | 14 +- base/iterators.jl | 2 +- base/parse.jl | 2 +- base/range.jl | 2 +- base/reduce.jl | 4 +- base/shell.jl | 2 +- base/show.jl | 4 +- base/strings/basic.jl | 31 +- base/strings/io.jl | 6 +- base/strings/search.jl | 24 +- base/strings/string.jl | 5 +- base/strings/unicode.jl | 82 +++--- base/strings/util.jl | 34 +-- doc/src/base/strings.md | 6 +- doc/src/manual/strings.md | 10 +- doc/src/manual/types.md | 2 +- stdlib/Dates/src/io.jl | 6 +- stdlib/DelimitedFiles/docs/src/index.md | 8 +- stdlib/DelimitedFiles/src/DelimitedFiles.jl | 38 +-- stdlib/LinearAlgebra/src/bidiag.jl | 4 +- stdlib/LinearAlgebra/src/blas.jl | 98 +++---- stdlib/LinearAlgebra/src/bunchkaufman.jl | 4 +- stdlib/LinearAlgebra/src/cholesky.jl | 4 +- stdlib/LinearAlgebra/src/deprecated.jl | 2 +- stdlib/LinearAlgebra/src/lapack.jl | 310 ++++++++++---------- stdlib/LinearAlgebra/src/matmul.jl | 18 +- stdlib/Markdown/src/parse/util.jl | 2 +- stdlib/Pkg3/ext/TOML/src/parser.jl | 4 +- stdlib/Pkg3/ext/TOML/src/print.jl | 2 +- stdlib/REPL/src/LineEdit.jl | 6 +- stdlib/Random/src/generation.jl | 4 +- stdlib/SparseArrays/src/sparsevector.jl | 2 +- stdlib/Unicode/src/Unicode.jl | 4 +- test/char.jl | 19 ++ 40 files changed, 492 insertions(+), 412 deletions(-) diff --git a/NEWS.md b/NEWS.md index 17332744894b1..ad7b2452c92fe 100644 --- a/NEWS.md +++ b/NEWS.md @@ -458,6 +458,9 @@ Library improvements * The function `thisind(s::AbstractString, i::Integer)` returns the largest valid index less or equal than `i` in the string `s` or `0` if no such index exists ([#24414]). + * `Char` is now a subtype of `AbstractChar`, and most of the functions that + take character arguments now accept any `AbstractChar`. + * `Irrational` is now a subtype of `AbstractIrrational` ([#24245]). * Introduced the `empty` function, the functional pair to `empty!` which returns a new, diff --git a/base/arrayshow.jl b/base/arrayshow.jl index d8e3916fb974a..b7ea956b8b1a5 100644 --- a/base/arrayshow.jl +++ b/base/arrayshow.jl @@ -39,7 +39,7 @@ methods. By default returns a string of the same width as original with a centered cdot, used in printing of structural zeros of structured matrices. Accept keyword args `c` for alternate single character marker. """ -function replace_with_centered_mark(s::AbstractString;c::Char = '⋅') +function replace_with_centered_mark(s::AbstractString;c::AbstractChar = '⋅') N = length(s) return join(setindex!([" " for i=1:N],string(c),ceil(Int,N/2))) end diff --git a/base/boot.jl b/base/boot.jl index 996f21addf9ae..a77344bbb4730 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -143,7 +143,7 @@ export Signed, Int, Int8, Int16, Int32, Int64, Int128, Unsigned, UInt, UInt8, UInt16, UInt32, UInt64, UInt128, # string types - Char, AbstractString, String, IO, + AbstractChar, Char, AbstractString, String, IO, # errors ErrorException, BoundsError, DivideError, DomainError, Exception, InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError, @@ -177,7 +177,8 @@ primitive type Float32 <: AbstractFloat 32 end primitive type Float64 <: AbstractFloat 64 end #primitive type Bool <: Integer 8 end -primitive type Char 32 end +abstract type AbstractChar end +primitive type Char <: AbstractChar 32 end primitive type Int8 <: Signed 8 end #primitive type UInt8 <: Unsigned 8 end @@ -460,7 +461,7 @@ function write(io::IO, x::String) end show(io::IO, @nospecialize x) = ccall(:jl_static_show, Cvoid, (Ptr{Cvoid}, Any), io_pointer(io), x) -print(io::IO, x::Char) = ccall(:jl_uv_putc, Cvoid, (Ptr{Cvoid}, Char), io_pointer(io), x) +print(io::IO, x::AbstractChar) = ccall(:jl_uv_putc, Cvoid, (Ptr{Cvoid}, Char), io_pointer(io), x) print(io::IO, x::String) = (write(io, x); nothing) print(io::IO, @nospecialize x) = show(io, x) print(io::IO, @nospecialize(x), @nospecialize a...) = (print(io, x); print(io, a...)) @@ -701,9 +702,10 @@ UInt32(x::BuiltinInts) = toUInt32(x)::UInt32 UInt64(x::BuiltinInts) = toUInt64(x)::UInt64 UInt128(x::BuiltinInts) = toUInt128(x)::UInt128 -Char(x::Number) = Char(UInt32(x)) -Char(x::Char) = x -(::Type{T})(x::Char) where {T<:Number} = T(UInt32(x)) +(::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x)) +(::Type{AbstractChar})(x::Number) = Char(x) +(::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(UInt32(x)) +(::Type{T})(x::T) where {T<:AbstractChar} = x (::Type{T})(x::T) where {T<:Number} = x diff --git a/base/char.jl b/base/char.jl index 4d994d690a726..08bed28e86bc9 100644 --- a/base/char.jl +++ b/base/char.jl @@ -1,12 +1,49 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -struct InvalidCharError <: Exception - char::Char +""" +The `AbstractChar` type is the supertype of all character implementations +in Julia. A character represents a Unicode code point, and can be converted +to/from `UInt32` in order to obtain the numerical value of the code point. +These numerical values determine how characters are compared with `<` and `==`, +for example. + +A given `AbstractChar` subtype may be capable of representing only a subset +of Unicode, in which case conversion from an unsupported `UInt32` value +may throw an error. Conversely, the built-in [`Char`](@ref) type represents +a *superset* of Unicode (in order to losslessly encode invalid byte streams), +in which case conversion of a non-Unicode value *to* `UInt32` throws an error. +The [`isvalid`](@ref) function can be used to check which codepoints are +representable in a given `AbstractChar` type. + +Internally, an `AbstractChar` type may use a variety of encodings. Conversion +to `UInt32` will not reveal this encoding because it always returns the +Unicode value of the character. (Typically, the raw encoding can be obtained +via [`reinterpret`](@ref).) +""" +AbstractChar + +""" + Char(c::Union{Number,AbstractChar}) + +`Char` is a 32-bit [`AbstractChar`](@ref) type that is the default representation +of characters in Julia. `Char` is the type used for character literals like `'x'` +and it is also the element type of [`String`](@ref). + +In order to losslessly represent arbitrary byte streams stored in a `String`, +a `Char` value may store information that cannot be converted to a Unicode +codepoint — converting such a `Char` to `UInt32` will throw an error. +The [`isvalid(c::Char)`](@ref) function can be used to query whether `c` +represents a valid Unicode character. +""" +Char + +struct InvalidCharError{T<:AbstractChar} <: Exception + char::T end struct CodePointError <: Exception code::Integer end -@noinline invalid_char(c::Char) = throw(InvalidCharError(c)) +@noinline invalid_char(c::AbstractChar) = throw(InvalidCharError(c)) @noinline code_point_err(u::UInt32) = throw(CodePointError(u)) function ismalformed(c::Char) @@ -24,6 +61,11 @@ function isoverlong(c::Char) is_overlong_enc(u) end +# fallback: other AbstractChar types, by default, are assumed +# not to support malformed or overlong encodings. +ismalformed(c::AbstractChar) = false +isoverlong(c::AbstractChar) = false + function UInt32(c::Char) # TODO: use optimized inline LLVM u = reinterpret(UInt32, c) @@ -69,50 +111,57 @@ function Char(b::Union{Int8,UInt8}) 0 ≤ b ≤ 0x7f ? reinterpret(Char, (b % UInt32) << 24) : Char(UInt32(b)) end -convert(::Type{Char}, x::Number) = Char(x) -convert(::Type{T}, x::Char) where {T<:Number} = T(x) +convert(::Type{AbstractChar}, x::Number) = Char(x) # default to Char +convert(::Type{T}, x::Number) where {T<:AbstractChar} = T(x) +convert(::Type{T}, x::AbstractChar) where {T<:Number} = T(x) -rem(x::Char, ::Type{T}) where {T<:Number} = rem(UInt32(x), T) +rem(x::AbstractChar, ::Type{T}) where {T<:Number} = 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 -firstindex(c::Char) = 1 -lastindex(c::Char) = 1 -getindex(c::Char) = c -getindex(c::Char, i::Integer) = i == 1 ? c : throw(BoundsError()) -getindex(c::Char, I::Integer...) = all(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 +size(c::AbstractChar) = () +size(c::AbstractChar,d) = convert(Int, d) < 1 ? throw(BoundsError()) : 1 +ndims(c::AbstractChar) = 0 +ndims(::Type{<:AbstractChar}) = 0 +length(c::AbstractChar) = 1 +firstindex(c::AbstractChar) = 1 +lastindex(c::AbstractChar) = 1 +getindex(c::AbstractChar) = c +getindex(c::AbstractChar, i::Integer) = i == 1 ? c : throw(BoundsError()) +getindex(c::AbstractChar, I::Integer...) = all(x -> x == 1, I) ? c : throw(BoundsError()) +first(c::AbstractChar) = c +last(c::AbstractChar) = c +eltype(::Type{T}) where {T<:AbstractChar} = T + +start(c::AbstractChar) = false +next(c::AbstractChar, state) = (c, true) +done(c::AbstractChar, state) = state +isempty(c::AbstractChar) = false +in(x::AbstractChar, y::AbstractChar) = x == y ==(x::Char, y::Char) = reinterpret(UInt32, x) == reinterpret(UInt32, y) isless(x::Char, y::Char) = reinterpret(UInt32, x) < reinterpret(UInt32, y) hash(x::Char, h::UInt) = hash_uint64(((reinterpret(UInt32, x) + UInt64(0xd4d64234)) << 32) ⊻ UInt64(h)) -widen(::Type{Char}) = Char --(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 +# fallbacks: +isless(x::AbstractChar, y::AbstractChar) = isless(Char(x), Char(y)) +==(x::AbstractChar, y::AbstractChar) = Char(x) == Char(y) +hash(x::AbstractChar, h::UInt) = + hash_uint64(((UInt32(x) + UInt64(0xd060fad0)) << 32) ⊻ UInt64(h)) +widen(::Type{T}) where {T<:AbstractChar} = T + +-(x::AbstractChar, y::AbstractChar) = Int(x) - Int(y) +-(x::T, y::Integer) where {T<:AbstractChar} = T(Int32(x) - Int32(y)) ++(x::T, y::Integer) where {T<:AbstractChar} = T(Int32(x) + Int32(y)) ++(x::Integer, y::AbstractChar) = y + x -print(io::IO, c::Char) = (write(io, c); nothing) +print(io::IO, c::AbstractChar) = (write(io, c); nothing) const hex_chars = UInt8['0':'9';'a':'z'] -function show(io::IO, c::Char) +function show(io::IO, c::AbstractChar) if c <= '\\' b = c == '\0' ? 0x30 : c == '\a' ? 0x61 : @@ -154,14 +203,14 @@ function show(io::IO, c::Char) return end -function show(io::IO, ::MIME"text/plain", c::Char) +function show(io::IO, ::MIME"text/plain", c::T) where {T<:AbstractChar} show(io, c) if !ismalformed(c) print(io, ": ") if isoverlong(c) print(io, "[overlong] ") u = decode_overlong(c) - c = Char(u) + c = T(u) else u = UInt32(c) end diff --git a/base/compiler/validation.jl b/base/compiler/validation.jl index 6a913e1d158c4..d93b8f1c1a0f8 100644 --- a/base/compiler/validation.jl +++ b/base/compiler/validation.jl @@ -209,7 +209,7 @@ is_valid_lvalue(x) = isa(x, Slot) || isa(x, SSAValue) || isa(x, GlobalRef) function is_valid_argument(x) if isa(x, Slot) || isa(x, SSAValue) || isa(x, GlobalRef) || isa(x, QuoteNode) || (isa(x,Expr) && (x.head in (:static_parameter, :boundscheck, :copyast))) || - isa(x, Number) || isa(x, AbstractString) || isa(x, Char) || isa(x, Tuple) || + isa(x, Number) || isa(x, AbstractString) || isa(x, AbstractChar) || isa(x, Tuple) || isa(x, Type) || isa(x, Core.Box) || isa(x, Module) || x === nothing return true end diff --git a/base/filesystem.jl b/base/filesystem.jl index a6aa8bc33a60e..34c584f71549b 100644 --- a/base/filesystem.jl +++ b/base/filesystem.jl @@ -170,6 +170,7 @@ function read(f::File, ::Type{Char}) end return reinterpret(Char, c) end +read(f::File, ::Type{T}) where {T<:AbstractChar} = T(read(f, Char)) # fallback function unsafe_read(f::File, p::Ptr{UInt8}, nel::UInt) check_open(f) diff --git a/base/io.jl b/base/io.jl index 6f1ed0b654b77..2282b6e0d639a 100644 --- a/base/io.jl +++ b/base/io.jl @@ -229,7 +229,7 @@ read(io::AbstractPipe, byte::Type{UInt8}) = read(pipe_reader(io), byte) unsafe_read(io::AbstractPipe, p::Ptr{UInt8}, nb::UInt) = unsafe_read(pipe_reader(io), p, nb) read(io::AbstractPipe) = read(pipe_reader(io)) readuntil(io::AbstractPipe, arg::UInt8; kw...) = readuntil(pipe_reader(io), arg; kw...) -readuntil(io::AbstractPipe, arg::Char; kw...) = readuntil(pipe_reader(io), arg; kw...) +readuntil(io::AbstractPipe, arg::AbstractChar; kw...) = readuntil(pipe_reader(io), arg; kw...) readuntil(io::AbstractPipe, arg::AbstractString; kw...) = readuntil(pipe_reader(io), arg; kw...) readuntil(io::AbstractPipe, arg::AbstractVector; kw...) = readuntil(pipe_reader(io), arg; kw...) readuntil_vector!(io::AbstractPipe, target::AbstractVector, keep::Bool, out) = readuntil_vector!(pipe_reader(io), target, keep, out) @@ -303,7 +303,7 @@ read!(filename::AbstractString, a) = open(io->read!(io, a), filename) readuntil(filename::AbstractString, delim; keep::Bool = false) Read a string from an I/O stream or a file, up to the given delimiter. -The delimiter can be a `UInt8`, `Char`, string, or vector. +The delimiter can be a `UInt8`, `AbstractChar`, string, or vector. Keyword argument `keep` controls whether the delimiter is included in the result. The text is assumed to be encoded in UTF-8. @@ -570,6 +570,7 @@ function write(io::IO, c::Char) n += 1 end end +write(io::IO, c::AbstractChar) = write(io, Char(c)) # fallback function write(io::IO, s::Symbol) pname = unsafe_convert(Ptr{UInt8}, s) @@ -627,12 +628,13 @@ function read(io::IO, ::Type{Char}) end return reinterpret(Char, c) end +read(io::IO, ::Type{T}) where {T<:AbstractChar} = T(read(io, Char)) # fallback # readuntil_string is useful below since it has # an optimized method for s::IOStream readuntil_string(s::IO, delim::UInt8, keep::Bool) = String(readuntil(s, delim, keep=keep)) -function readuntil(s::IO, delim::Char; keep::Bool=false) +function readuntil(s::IO, delim::AbstractChar; keep::Bool=false) if delim ≤ '\x7f' return readuntil_string(s, delim % UInt8, keep) end @@ -994,7 +996,7 @@ function skipchars(predicate, io::IO; linecomment=nothing) end """ - countlines(io::IO; eol::Char = '\\n') + countlines(io::IO; eol::AbstractChar = '\\n') 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 @@ -1017,7 +1019,7 @@ julia> countlines(io, eol = '.') 1 ``` """ -function countlines(io::IO; eol::Char='\n') +function countlines(io::IO; eol::AbstractChar='\n') isascii(eol) || throw(ArgumentError("only ASCII line terminators are supported")) aeol = UInt8(eol) a = Vector{UInt8}(uninitialized, 8192) @@ -1034,4 +1036,4 @@ function countlines(io::IO; eol::Char='\n') nl end -countlines(f::AbstractString; eol::Char = '\n') = open(io->countlines(io, eol = eol), f)::Int +countlines(f::AbstractString; eol::AbstractChar = '\n') = open(io->countlines(io, eol = eol), f)::Int diff --git a/base/iterators.jl b/base/iterators.jl index 817c699f26f9c..fcaa133b36765 100644 --- a/base/iterators.jl +++ b/base/iterators.jl @@ -90,7 +90,7 @@ first(r::Reverse) = last(r.itr) # and the last shall be first reverse(R::AbstractRange) = Base.reverse(R) # copying ranges is cheap reverse(G::Generator) = Generator(G.f, reverse(G.iter)) reverse(r::Reverse) = r.itr -reverse(x::Union{Number,Char}) = x +reverse(x::Union{Number,AbstractChar}) = x reverse(p::Pair) = Base.reverse(p) # copying pairs is cheap start(r::Reverse{<:Tuple}) = length(r.itr) diff --git a/base/parse.jl b/base/parse.jl index 04cb305603329..814c67c36929b 100644 --- a/base/parse.jl +++ b/base/parse.jl @@ -33,7 +33,7 @@ julia> parse(Complex{Float64}, "3.2e-1 + 4.5im") """ parse(T::Type, str; base = Int) -function parse(::Type{T}, c::Char; base::Integer = 36) where T<:Integer +function parse(::Type{T}, c::AbstractChar; base::Integer = 36) where T<:Integer a::Int = (base <= 36 ? 10 : 36) 2 <= base <= 62 || throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base")) d = '0' <= c <= '9' ? c-'0' : diff --git a/base/range.jl b/base/range.jl index cbe79060be684..98e69c2b349ab 100644 --- a/base/range.jl +++ b/base/range.jl @@ -917,7 +917,7 @@ in(x::Integer, r::AbstractUnitRange{<:Integer}) = (first(r) <= x) & (x <= last(r in(x::Real, r::AbstractRange{T}) where {T<:Integer} = isinteger(x) && !isempty(r) && x >= minimum(r) && x <= maximum(r) && (mod(convert(T,x),step(r))-mod(first(r),step(r)) == 0) -in(x::Char, r::AbstractRange{Char}) = +in(x::AbstractChar, r::AbstractRange{<:AbstractChar}) = !isempty(r) && x >= minimum(r) && x <= maximum(r) && (mod(Int(x) - Int(first(r)), step(r)) == 0) diff --git a/base/reduce.jl b/base/reduce.jl index 31ee4d79578bc..195c0adc85009 100644 --- a/base/reduce.jl +++ b/base/reduce.jl @@ -259,7 +259,7 @@ reduce_empty(op, T) = _empty_reduce_error() reduce_empty(::typeof(+), T) = zero(T) reduce_empty(::typeof(+), ::Type{Bool}) = zero(Int) reduce_empty(::typeof(*), T) = one(T) -reduce_empty(::typeof(*), ::Type{Char}) = "" +reduce_empty(::typeof(*), ::Type{<:AbstractChar}) = "" reduce_empty(::typeof(&), ::Type{Bool}) = true reduce_empty(::typeof(|), ::Type{Bool}) = false @@ -307,7 +307,7 @@ different types than its inputs. """ reduce_first(op, x) = x reduce_first(::typeof(+), x::Bool) = Int(x) -reduce_first(::typeof(*), x::Char) = string(x) +reduce_first(::typeof(*), x::AbstractChar) = string(x) reduce_first(::typeof(add_sum), x) = reduce_first(+, x) reduce_first(::typeof(add_sum), x::SmallSigned) = Int(x) diff --git a/base/shell.jl b/base/shell.jl index 3905d8bc39b97..5bdcccc010f5c 100644 --- a/base/shell.jl +++ b/base/shell.jl @@ -197,7 +197,7 @@ function print_shell_escaped_posixly(io::IO, args::AbstractString...) # that any (reasonable) shell will definitely never consider them to be special have_single = false have_double = false - function isword(c::Char) + function isword(c::AbstractChar) if '0' <= c <= '9' || 'a' <= c <= 'z' || 'A' <= c <= 'Z' # word characters elseif c == '_' || c == '/' || c == '+' || c == '-' diff --git a/base/show.jl b/base/show.jl index 5341d26e4d51e..f8bd22f822ba7 100644 --- a/base/show.jl +++ b/base/show.jl @@ -763,8 +763,8 @@ const expr_parens = Dict(:tuple=>('(',')'), :vcat=>('[',']'), ## AST decoding helpers ## -is_id_start_char(c::Char) = ccall(:jl_id_start_char, Cint, (UInt32,), c) != 0 -is_id_char(c::Char) = ccall(:jl_id_char, Cint, (UInt32,), c) != 0 +is_id_start_char(c::AbstractChar) = ccall(:jl_id_start_char, Cint, (UInt32,), c) != 0 +is_id_char(c::AbstractChar) = ccall(:jl_id_char, Cint, (UInt32,), c) != 0 function isidentifier(s::AbstractString) isempty(s) && return false c, rest = Iterators.peel(s) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 50091f5f11049..88ad487a058ea 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -3,7 +3,7 @@ """ The `AbstractString` type is the supertype of all string implementations in Julia. Strings are encodings of sequences of [Unicode](https://unicode.org/) -code points as represented by the `Char` type. Julia makes a few assumptions +code points as represented by the `AbstractChar` type. Julia makes a few assumptions about strings: * Strings are encoded in terms of fixed-size "code units" @@ -13,9 +13,9 @@ about strings: * Any index `i` such that `1 ≤ i ≤ ncodeunits(s)` is in bounds * String indexing is done in terms of these code units: * Characters are extracted by `s[i]` with a valid string index `i` - * Each `Char` in a string is encoded by one or more code units - * Only the index of the first code unit of a `Char` is a valid index - * The encoding of a `Char` is independent of what precedes or follows it + * Each `AbstractChar` in a string is encoded by one or more code units + * Only the index of the first code unit of a `AbstractChar` is a valid index + * The encoding of a `AbstractChar` is independent of what precedes or follows it * String encodings are [self-synchronizing] – i.e. `isvalid(s, i)` is O(1) [self-synchronizing]: https://en.wikipedia.org/wiki/Self-synchronizing_code @@ -122,7 +122,7 @@ Stacktrace: throw(MethodError(isvalid, (s, i))) : isvalid(s, Int(i)) """ - next(s::AbstractString, i::Integer) -> Tuple{Char, Int} + next(s::AbstractString, i::Integer) -> Tuple{<:AbstractChar, Int} Return a tuple of the character in `s` at index `i` with the index of the start of the following character in `s`. This is the key method that allows strings to @@ -140,7 +140,7 @@ See also: [`getindex`](@ref), [`start`](@ref), [`done`](@ref), start(s::AbstractString) = 1 done(s::AbstractString, i::Integer) = i > ncodeunits(s) -eltype(::Type{<:AbstractString}) = Char +eltype(::Type{<:AbstractString}) = Char # some string types may use another AbstractChar sizeof(s::AbstractString) = ncodeunits(s) * sizeof(codeunit(s)) firstindex(s::AbstractString) = 1 lastindex(s::AbstractString) = thisind(s, ncodeunits(s)) @@ -187,7 +187,7 @@ string(s::AbstractString) = s (::Type{Vector{UInt8}})(s::AbstractString) = unsafe_wrap(Vector{UInt8}, String(s)) (::Type{Array{UInt8}})(s::AbstractString) = unsafe_wrap(Vector{UInt8}, String(s)) -(::Type{Vector{Char}})(s::AbstractString) = collect(s) +(::Type{Vector{T}})(s::AbstractString) where {T<:AbstractChar} = collect(T, s) Symbol(s::AbstractString) = Symbol(String(s)) @@ -199,7 +199,7 @@ promote_rule(::Type{<:AbstractString}, ::Type{<:AbstractString}) = String ## string & character concatenation ## """ - *(s::Union{AbstractString, Char}, t::Union{AbstractString, Char}...) -> AbstractString + *(s::Union{AbstractString, AbstractChar}, t::Union{AbstractString, AbstractChar}...) -> AbstractString Concatenate strings and/or characters, producing a [`String`](@ref). This is equivalent to calling the [`string`](@ref) function on the arguments. Concatenation of built-in @@ -215,7 +215,7 @@ julia> 'j' * "ulia" "julia" ``` """ -(*)(s1::Union{Char, AbstractString}, ss::Union{Char, AbstractString}...) = string(s1, ss...) +(*)(s1::Union{AbstractChar, AbstractString}, ss::Union{AbstractChar, AbstractString}...) = string(s1, ss...) one(::Union{T,Type{T}}) where {T<:AbstractString} = convert(T, "") @@ -486,7 +486,7 @@ done(e::EachStringIndex, state) = done(e.s, state) eltype(::Type{<:EachStringIndex}) = Int """ - isascii(c::Union{Char,AbstractString}) -> Bool + isascii(c::Union{AbstractChar,AbstractString}) -> Bool Test whether a character belongs to the ASCII character set, or whether this is true for all elements of a string. @@ -508,6 +508,7 @@ false """ isascii(c::Char) = bswap(reinterpret(UInt32, c)) < 0x80 isascii(s::AbstractString) = all(isascii, s) +isascii(c::AbstractChar) = UInt32(c) < 0x80 ## string map, filter, has ## @@ -515,10 +516,10 @@ function map(f, s::AbstractString) out = IOBuffer(sizehint=sizeof(s)) for c in s c′ = f(c) - isa(c′, Char) || throw(ArgumentError( - "map(f, s::AbstractString) requires f to return Char; " * + isa(c′, AbstractChar) || throw(ArgumentError( + "map(f, s::AbstractString) requires f to return AbstractChar; " * "try map(f, collect(s)) or a comprehension instead")) - write(out, c′::Char) + write(out, c′::AbstractChar) end String(take!(out)) end @@ -605,7 +606,7 @@ julia> repeat("ha", 3) repeat(s::AbstractString, r::Integer) = repeat(String(s), r) """ - ^(s::Union{AbstractString,Char}, n::Integer) + ^(s::Union{AbstractString,AbstractChar}, n::Integer) Repeat a string or character `n` times. This can also be written as `repeat(s, n)`. @@ -617,7 +618,7 @@ julia> "Test "^3 "Test Test Test " ``` """ -(^)(s::Union{AbstractString,Char}, r::Integer) = repeat(s, r) +(^)(s::Union{AbstractString,AbstractChar}, r::Integer) = repeat(s, r) # reverse-order iteration for strings and indices thereof start(r::Iterators.Reverse{<:AbstractString}) = lastindex(r.itr) diff --git a/base/strings/io.jl b/base/strings/io.jl index 5601fd49c03d0..ea0de4018994e 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -240,8 +240,8 @@ join(strings, delim, last) = sprint(join, strings, delim, last) ## string escaping & unescaping ## -need_full_hex(c::Union{Nothing, Char}) = c !== nothing && isxdigit(c) -escape_nul(c::Union{Nothing, Char}) = +need_full_hex(c::Union{Nothing, AbstractChar}) = c !== nothing && isxdigit(c) +escape_nul(c::Union{Nothing, AbstractChar}) = (c !== nothing && '0' <= c <= '7') ? "\\x00" : "\\0" """ @@ -486,7 +486,7 @@ function unindent(str::AbstractString, indent::Int; tabwidth=8) String(take!(buf)) end -function String(chars::AbstractVector{Char}) +function String(chars::AbstractVector{<:AbstractChar}) sprint(sizehint=length(chars)) do io for c in chars write(io, c) diff --git a/base/strings/search.jl b/base/strings/search.jl index 2b3c0633e07f3..27e0edf8b4c0a 100644 --- a/base/strings/search.jl +++ b/base/strings/search.jl @@ -2,7 +2,7 @@ nothing_sentinel(i) = i == 0 ? nothing : i -function findnext(pred::EqualTo{Char}, s::String, i::Integer) +function findnext(pred::EqualTo{<:AbstractChar}, s::String, i::Integer) if i < 1 || i > sizeof(s) i == sizeof(s) + 1 && return nothing throw(BoundsError(s, i)) @@ -36,7 +36,7 @@ function _search(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = q == C_NULL ? 0 : Int(q-p+1) end -function _search(a::ByteArray, b::Char, i::Integer = 1) +function _search(a::ByteArray, b::AbstractChar, i::Integer = 1) if isascii(b) _search(a,UInt8(b),i) else @@ -44,7 +44,7 @@ function _search(a::ByteArray, b::Char, i::Integer = 1) end end -function findprev(pred::EqualTo{Char}, s::String, i::Integer) +function findprev(pred::EqualTo{<:AbstractChar}, s::String, i::Integer) c = pred.x c ≤ '\x7f' && return nothing_sentinel(_rsearch(s, c % UInt8, i)) b = first_utf8_byte(c) @@ -74,7 +74,7 @@ function _rsearch(a::Union{String,ByteArray}, b::Union{Int8,UInt8}, i::Integer = q == C_NULL ? 0 : Int(q-p+1) end -function _rsearch(a::ByteArray, b::Char, i::Integer = length(a)) +function _rsearch(a::ByteArray, b::AbstractChar, i::Integer = length(a)) if isascii(b) _rsearch(a,UInt8(b),i) else @@ -114,10 +114,10 @@ function findnext(testf::Function, s::AbstractString, i::Integer) return nothing end -in(c::Char, s::AbstractString) = (findfirst(equalto(c),s)!==nothing) +in(c::AbstractChar, s::AbstractString) = (findfirst(equalto(c),s)!==nothing) function _searchindex(s::Union{AbstractString,ByteArray}, - t::Union{AbstractString,Char,Int8,UInt8}, + t::Union{AbstractString,AbstractChar,Int8,UInt8}, i::Integer) if isempty(t) return 1 <= i <= nextind(s,lastindex(s)) ? i : @@ -135,7 +135,7 @@ function _searchindex(s::Union{AbstractString,ByteArray}, end end -_searchindex(s::AbstractString, t::Char, i::Integer) = coalesce(findnext(equalto(t), s, i), 0) +_searchindex(s::AbstractString, t::AbstractChar, i::Integer) = coalesce(findnext(equalto(t), s, i), 0) function _search_bloom_mask(c) UInt64(1) << (c & 63) @@ -212,7 +212,7 @@ function _searchindex(s::ByteArray, t::ByteArray, i::Integer) end function _search(s::Union{AbstractString,ByteArray}, - t::Union{AbstractString,Char,Int8,UInt8}, + t::Union{AbstractString,AbstractChar,Int8,UInt8}, i::Integer) idx = _searchindex(s,t,i) if isempty(t) @@ -286,7 +286,7 @@ function findprev(testf::Function, s::AbstractString, i::Integer) end function _rsearchindex(s::AbstractString, - t::Union{AbstractString,Char,Int8,UInt8}, + t::Union{AbstractString,AbstractChar,Int8,UInt8}, i::Integer) if isempty(t) return 1 <= i <= nextind(s, lastindex(s)) ? i : @@ -387,7 +387,7 @@ function _rsearchindex(s::ByteArray, t::ByteArray, k::Integer) end function _rsearch(s::Union{AbstractString,ByteArray}, - t::Union{AbstractString,Char,Int8,UInt8}, + t::Union{AbstractString,AbstractChar,Int8,UInt8}, i::Integer) idx = _rsearchindex(s,t,i) if isempty(t) @@ -426,7 +426,7 @@ julia> findprev("Julia", "JuliaLang", 6) findprev(t::AbstractString, s::AbstractString, i::Integer) = _rsearch(s, t, i) """ - contains(haystack::AbstractString, needle::Union{AbstractString,Regex,Char}) + contains(haystack::AbstractString, needle::Union{AbstractString,Regex,AbstractChar}) Determine whether the second argument is a substring of the first. If `needle` is a regular expression, checks whether `haystack` contains a match. @@ -448,7 +448,7 @@ false """ function contains end -contains(haystack::AbstractString, needle::Union{AbstractString,Char}) = +contains(haystack::AbstractString, needle::Union{AbstractString,AbstractChar}) = _searchindex(haystack, needle, firstindex(haystack)) != 0 in(::AbstractString, ::AbstractString) = error("use contains(x,y) for string containment") diff --git a/base/strings/string.jl b/base/strings/string.jl index 487bfd8819d1d..fa4d85474ba37 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -317,7 +317,7 @@ end # TODO: delete or move to char.jl codelen(c::Char) = 4 - (trailing_zeros(0xff000000 | reinterpret(UInt32, c)) >> 3) -function string(a::Union{String,Char}...) +function string(a::Union{String,AbstractChar}...) sprint() do io for x in a write(io, x) @@ -341,7 +341,7 @@ function repeat(s::String, r::Integer) end """ - repeat(c::Char, r::Integer) -> String + repeat(c::AbstractChar, r::Integer) -> String Repeat a character `r` times. This can equivalently be accomplished by calling [`c^r`](@ref ^). @@ -351,6 +351,7 @@ julia> repeat('A', 3) "AAA" ``` """ +repeat(c::AbstractChar, r::Integer) = repeat(Char(c), r) # fallback function repeat(c::Char, r::Integer) r == 0 && return "" r < 0 && throw(ArgumentError("can't repeat a character $r times")) diff --git a/base/strings/unicode.jl b/base/strings/unicode.jl index 16c38f1754742..d6b3e708beda0 100644 --- a/base/strings/unicode.jl +++ b/base/strings/unicode.jl @@ -12,7 +12,7 @@ import Base: show, ==, hash, string, Symbol, isless, length, eltype, start, isvalid(value) -> Bool Returns `true` if the given value is valid for its type, which currently can be either -`Char` or `String`. +`AbstractChar` or `String`. # Examples ```jldoctest @@ -29,7 +29,7 @@ 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`](@ref). +be either `AbstractChar` or `String`. Values for `AbstractChar` can be of type `AbstractChar` or [`UInt32`](@ref). Values for `String` can be of that type, or `Vector{UInt8}`. # Examples @@ -43,10 +43,10 @@ true """ isvalid(T,value) -isvalid(c::Char) = !ismalformed(c) & !isoverlong(c) & ((c ≤ '\ud7ff') | ('\ue000' ≤ c) & (c ≤ '\U10ffff')) -isvalid(::Type{Char}, c::Unsigned) = ((c ≤ 0xd7ff ) | ( 0xe000 ≤ c) & (c ≤ 0x10ffff )) -isvalid(::Type{Char}, c::Integer) = isvalid(Char, Unsigned(c)) -isvalid(::Type{Char}, c::Char) = isvalid(c) +isvalid(c::AbstractChar) = !ismalformed(c) & !isoverlong(c) & ((c ≤ '\ud7ff') | ('\ue000' ≤ c) & (c ≤ '\U10ffff')) +isvalid(::Type{<:AbstractChar}, c::Unsigned) = ((c ≤ 0xd7ff ) | ( 0xe000 ≤ c) & (c ≤ 0x10ffff )) +isvalid(::Type{T}, c::Integer) where {T<:AbstractChar} = isvalid(T, Unsigned(c)) +isvalid(::Type{<:AbstractChar}, c::AbstractChar) = isvalid(c) # utf8 category constants const UTF8PROC_CATEGORY_CN = 0 @@ -218,8 +218,8 @@ julia> textwidth('❤') 2 ``` """ -function textwidth(c::Char) - ismalformed(c) && (c = '\ufffd') +function textwidth(c::AbstractChar) + ismalformed(c) && return 1 Int(ccall(:utf8proc_charwidth, Cint, (UInt32,), c)) end @@ -236,17 +236,17 @@ julia> textwidth("March") """ textwidth(s::AbstractString) = mapreduce(textwidth, +, 0, s) -lowercase(c::Char) = isascii(c) ? ('A' <= c <= 'Z' ? c + 0x20 : c) : - Char(ccall(:utf8proc_tolower, UInt32, (UInt32,), c)) -uppercase(c::Char) = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : - Char(ccall(:utf8proc_toupper, UInt32, (UInt32,), c)) -titlecase(c::Char) = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : - Char(ccall(:utf8proc_totitle, UInt32, (UInt32,), c)) +lowercase(c::T) where {T<:AbstractChar} = isascii(c) ? ('A' <= c <= 'Z' ? c + 0x20 : c) : + T(ccall(:utf8proc_tolower, UInt32, (UInt32,), c)) +uppercase(c::T) where {T<:AbstractChar} = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : + T(ccall(:utf8proc_toupper, UInt32, (UInt32,), c)) +titlecase(c::T) where {T<:AbstractChar} = isascii(c) ? ('a' <= c <= 'z' ? c - 0x20 : c) : + T(ccall(:utf8proc_totitle, UInt32, (UInt32,), c)) ############################################################################ # returns UTF8PROC_CATEGORY code in 0:30 giving Unicode category -function category_code(c::Char) +function category_code(c::AbstractChar) !ismalformed(c) ? category_code(UInt32(c)) : Cint(31) end @@ -255,7 +255,7 @@ function category_code(x::Integer) end # more human-readable representations of the category code -function category_abbrev(c::Char) +function category_abbrev(c::AbstractChar) ismalformed(c) && return "Ma" c ≤ '\U10ffff' || return "In" unsafe_string(ccall(:utf8proc_category_string, Cstring, (UInt32,), c)) @@ -268,7 +268,7 @@ isassigned(c) = UTF8PROC_CATEGORY_CN < category_code(c) <= UTF8PROC_CATEGORY_CO ## libc character class predicates ## """ - islower(c::Char) -> Bool + islower(c::AbstractChar) -> Bool Tests whether a character is a lowercase letter. A character is classified as lowercase if it belongs to Unicode category Ll, @@ -286,12 +286,12 @@ julia> islower('❤') false ``` """ -islower(c::Char) = category_code(c) == UTF8PROC_CATEGORY_LL +islower(c::AbstractChar) = category_code(c) == UTF8PROC_CATEGORY_LL # true for Unicode upper and mixed case """ - isupper(c::Char) -> Bool + isupper(c::AbstractChar) -> Bool Tests whether a character is an uppercase letter. A character is classified as uppercase if it belongs to Unicode category Lu, @@ -309,13 +309,13 @@ julia> isupper('❤') false ``` """ -function isupper(c::Char) +function isupper(c::AbstractChar) cat = category_code(c) cat == UTF8PROC_CATEGORY_LU || cat == UTF8PROC_CATEGORY_LT end # Documented in Unicode module -function iscased(c::Char) +function iscased(c::AbstractChar) cat = category_code(c) return cat == UTF8PROC_CATEGORY_LU || cat == UTF8PROC_CATEGORY_LT || @@ -324,7 +324,7 @@ end """ - isdigit(c::Char) -> Bool + isdigit(c::AbstractChar) -> Bool Tests whether a character is a decimal digit (0-9). @@ -340,10 +340,10 @@ julia> isdigit('α') false ``` """ -isdigit(c::Char) = '0' <= c <= '9' +isdigit(c::AbstractChar) = '0' <= c <= '9' """ - isalpha(c::Char) -> Bool + isalpha(c::AbstractChar) -> Bool Tests whether a character is alphabetic. A character is classified as alphabetic if it belongs to the Unicode general @@ -361,10 +361,10 @@ julia> isalpha('9') false ``` """ -isalpha(c::Char) = UTF8PROC_CATEGORY_LU <= category_code(c) <= UTF8PROC_CATEGORY_LO +isalpha(c::AbstractChar) = UTF8PROC_CATEGORY_LU <= category_code(c) <= UTF8PROC_CATEGORY_LO """ - isnumeric(c::Char) -> Bool + isnumeric(c::AbstractChar) -> Bool Tests whether a character is numeric. A character is classified as numeric if it belongs to the Unicode general category Number, @@ -388,12 +388,12 @@ julia> isnumeric('❤') false ``` """ -isnumeric(c::Char) = UTF8PROC_CATEGORY_ND <= category_code(c) <= UTF8PROC_CATEGORY_NO +isnumeric(c::AbstractChar) = UTF8PROC_CATEGORY_ND <= category_code(c) <= UTF8PROC_CATEGORY_NO # following C++ only control characters from the Latin-1 subset return true """ - iscntrl(c::Char) -> Bool + iscntrl(c::AbstractChar) -> Bool Tests whether a character is a control character. Control characters are the non-printing characters of the Latin-1 subset of Unicode. @@ -407,10 +407,10 @@ julia> iscntrl('a') false ``` """ -iscntrl(c::Char) = c <= '\x1f' || '\x7f' <= c <= '\u9f' +iscntrl(c::AbstractChar) = c <= '\x1f' || '\x7f' <= c <= '\u9f' """ - ispunct(c::Char) -> Bool + ispunct(c::AbstractChar) -> Bool Tests whether a character belongs to the Unicode general category Punctuation, i.e. a character whose category code begins with 'P'. @@ -427,12 +427,12 @@ julia> ispunct(';') true ``` """ -ispunct(c::Char) = UTF8PROC_CATEGORY_PC <= category_code(c) <= UTF8PROC_CATEGORY_PO +ispunct(c::AbstractChar) = UTF8PROC_CATEGORY_PC <= category_code(c) <= UTF8PROC_CATEGORY_PO # \u85 is the Unicode Next Line (NEL) character """ - isspace(c::Char) -> Bool + isspace(c::AbstractChar) -> Bool Tests whether a character is any whitespace character. Includes ASCII characters '\\t', '\\n', '\\v', '\\f', '\\r', and ' ', Latin-1 character U+0085, and characters in Unicode @@ -453,12 +453,12 @@ julia> isspace('\\x20') true ``` """ -@inline isspace(c::Char) = +@inline isspace(c::AbstractChar) = c == ' ' || '\t' <= c <= '\r' || c == '\u85' || '\ua0' <= c && category_code(c) == UTF8PROC_CATEGORY_ZS """ - isprint(c::Char) -> Bool + isprint(c::AbstractChar) -> Bool Tests whether a character is printable, including spaces, but not a control character. @@ -471,12 +471,12 @@ julia> isprint('A') true ``` """ -isprint(c::Char) = UTF8PROC_CATEGORY_LU <= category_code(c) <= UTF8PROC_CATEGORY_ZS +isprint(c::AbstractChar) = UTF8PROC_CATEGORY_LU <= category_code(c) <= UTF8PROC_CATEGORY_ZS # true in principal if a printer would use ink """ - isxdigit(c::Char) -> Bool + isxdigit(c::AbstractChar) -> Bool Test whether a character is a valid hexadecimal digit. Note that this does not include `x` (as in the standard `0x` prefix). @@ -490,7 +490,7 @@ julia> isxdigit('x') false ``` """ -isxdigit(c::Char) = '0'<=c<='9' || 'a'<=c<='f' || 'A'<=c<='F' +isxdigit(c::AbstractChar) = '0'<=c<='9' || 'a'<=c<='f' || 'A'<=c<='F' ## uppercase, lowercase, and titlecase transformations ## @@ -608,14 +608,14 @@ end ############################################################################ # iterators for grapheme segmentation -isgraphemebreak(c1::Char, c2::Char) = +isgraphemebreak(c1::AbstractChar, c2::AbstractChar) = ismalformed(c1) || ismalformed(c2) || ccall(:utf8proc_grapheme_break, Bool, (UInt32, UInt32), c1, c2) # Stateful grapheme break required by Unicode-9 rules: the string # must be processed in sequence, with state initialized to Ref{Int32}(0). # Requires utf8proc v2.0 or later. -function isgraphemebreak!(state::Ref{Int32}, c1::Char, c2::Char) +function isgraphemebreak!(state::Ref{Int32}, c1::AbstractChar, c2::AbstractChar) if ismalformed(c1) || ismalformed(c2) state[] = 0 return true @@ -634,8 +634,8 @@ graphemes(s::AbstractString) = GraphemeIterator{typeof(s)}(s) eltype(::Type{GraphemeIterator{S}}) where {S} = SubString{S} eltype(::Type{GraphemeIterator{SubString{S}}}) where {S} = SubString{S} -function length(g::GraphemeIterator) - c0 = typemax(Char) +function length(g::GraphemeIterator{S}) where {S} + c0 = eltype(S)(0x00000000) n = 0 state = Ref{Int32}(0) for c in g.s diff --git a/base/strings/util.jl b/base/strings/util.jl index 397613e57f271..ef06c1ee51dfa 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -1,6 +1,6 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license -const Chars = Union{Char,Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}} +const Chars = Union{AbstractChar,Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}} # starts with and ends with predicates @@ -185,7 +185,7 @@ strip(s::AbstractString, chars::Chars) = lstrip(rstrip(s, chars), chars) ## string padding functions ## """ - lpad(s, n::Integer, p::Union{Char,AbstractString}=' ') -> String + lpad(s, n::Integer, p::Union{AbstractChar,AbstractString}=' ') -> String Stringify `s` and pad the resulting string on the left with `p` to make it `n` characters (code points) long. If `s` is already `n` characters long, an equal @@ -197,12 +197,12 @@ julia> lpad("March", 10) " March" ``` """ -lpad(s, n::Integer, p::Union{Char,AbstractString}=' ') = lpad(string(s), n, string(p)) +lpad(s, n::Integer, p::Union{AbstractChar,AbstractString}=' ') = lpad(string(s), n, string(p)) function lpad( - s::Union{Char,AbstractString}, + s::Union{AbstractChar,AbstractString}, n::Integer, - p::Union{Char,AbstractString}=' ', + p::Union{AbstractChar,AbstractString}=' ', ) :: String m = n - length(s) m ≤ 0 && return string(s) @@ -212,7 +212,7 @@ function lpad( end """ - rpad(s, n::Integer, p::Union{Char,AbstractString}=' ') -> String + rpad(s, n::Integer, p::Union{AbstractChar,AbstractString}=' ') -> String Stringify `s` and pad the resulting string on the right with `p` to make it `n` characters (code points) long. If `s` is already `n` characters long, an equal @@ -224,12 +224,12 @@ julia> rpad("March", 20) "March " ``` """ -rpad(s, n::Integer, p::Union{Char,AbstractString}=' ') = rpad(string(s), n, string(p)) +rpad(s, n::Integer, p::Union{AbstractChar,AbstractString}=' ') = rpad(string(s), n, string(p)) function rpad( - s::Union{Char,AbstractString}, + s::Union{AbstractChar,AbstractString}, n::Integer, - p::Union{Char,AbstractString}=' ', + p::Union{AbstractChar,AbstractString}=' ', ) :: String m = n - length(s) m ≤ 0 && return string(s) @@ -267,10 +267,10 @@ function split end split(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _split(str, splitter, limit, keep, T <: SubString ? T[] : SubString{T}[]) -split(str::T, splitter::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}; +split(str::T, splitter::Union{Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _split(str, occursin(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) -split(str::T, splitter::Char; +split(str::T, splitter::AbstractChar; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _split(str, equalto(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) @@ -334,10 +334,10 @@ function rsplit end rsplit(str::T, splitter; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _rsplit(str, splitter, limit, keep, T <: SubString ? T[] : SubString{T}[]) -rsplit(str::T, splitter::Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}; +rsplit(str::T, splitter::Union{Tuple{Vararg{<:AbstractChar}},AbstractVector{<:AbstractChar},Set{<:AbstractChar}}; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _rsplit(str, occursin(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) -rsplit(str::T, splitter::Char; +rsplit(str::T, splitter::AbstractChar; limit::Integer=0, keep::Bool=true) where {T<:AbstractString} = _rsplit(str, equalto(splitter), limit, keep, T <: SubString ? T[] : SubString{T}[]) @@ -362,11 +362,11 @@ _replace(io, repl::Function, str, r, pattern) = _replace(io, repl::Function, str, r, pattern::Function) = print(io, repl(str[first(r)])) -replace(str::String, pat_repl::Pair{Char}; count::Integer=typemax(Int)) = +replace(str::String, pat_repl::Pair{<:AbstractChar}; count::Integer=typemax(Int)) = replace(str, equalto(first(pat_repl)) => last(pat_repl); count=count) -replace(str::String, pat_repl::Pair{<:Union{Tuple{Vararg{Char}}, - AbstractVector{Char},Set{Char}}}; +replace(str::String, pat_repl::Pair{<:Union{Tuple{Vararg{<:AbstractChar}}, + AbstractVector{<:AbstractChar},Set{<:AbstractChar}}}; count::Integer=typemax(Int)) = replace(str, occursin(first(pat_repl)) => last(pat_repl), count=count) @@ -410,7 +410,7 @@ If `count` is provided, replace at most `count` occurrences. or a regular expression. If `r` is a function, each occurrence is replaced with `r(s)` where `s` is the matched substring (when `pat`is a `Regex` or `AbstractString`) or -character (when `pat` is a `Char` or a collection of `Char`). +character (when `pat` is a `AbstractChar` or a collection of `AbstractChar`). If `pat` is a regular expression and `r` is a `SubstitutionString`, then capture group references in `r` are replaced with the corresponding matched text. To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`). diff --git a/doc/src/base/strings.md b/doc/src/base/strings.md index d71e7ef5b237f..146372720d391 100644 --- a/doc/src/base/strings.md +++ b/doc/src/base/strings.md @@ -1,13 +1,15 @@ # [Strings](@id lib-strings) ```@docs +Core.AbstractChar +Core.Char Base.length(::AbstractString) Base.sizeof(::AbstractString) -Base.:*(::Union{Char, AbstractString}, ::Union{Char, AbstractString}...) +Base.:*(::Union{AbstractChar, AbstractString}, ::Union{AbstractChar, AbstractString}...) Base.:^(::AbstractString, ::Integer) Base.string Base.repeat(::AbstractString, ::Integer) -Base.repeat(::Char, ::Integer) +Base.repeat(::AbstractChar, ::Integer) Base.repr(::Any) Core.String(::AbstractString) Base.SubString diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index dcfd739dbc3ae..d39147ed780cb 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -29,8 +29,7 @@ There are a few noteworthy high-level features about Julia's strings: a string argument, you should declare the type as `AbstractString` in order to accept any string type. * Like C and Java, but unlike most dynamic languages, Julia has a first-class type representing - a single character, called `Char`. This is just a special kind of 32-bit primitive type whose numeric - value represents a Unicode code point. + a single character, called `AbstractChar`. This is just a special kind of 32-bit primitive type whose numeric value represents a Unicode code point. * As in Java, strings are immutable: the value of an `AbstractString` object cannot be changed. To construct a different string value, you construct a new string from parts of other strings. * Conceptually, a string is a *partial function* from indices to characters: for some index values, @@ -41,9 +40,10 @@ There are a few noteworthy high-level features about Julia's strings: ## [Characters](@id man-characters) -A `Char` value represents a single character: it is just a 32-bit primitive type with a special literal +An `AbstractChar` value represents a single character: it is just a 32-bit primitive type with a special literal representation and appropriate arithmetic behaviors, whose numeric value is interpreted as a -[Unicode code point](https://en.wikipedia.org/wiki/Code_point). Here is how `Char` values are +[Unicode code point](https://en.wikipedia.org/wiki/Code_point). Julia comes with a concrete +`Char` type implementing the `AbstractChar` interface. Here is how `Char` values are input and shown: ```jldoctest @@ -429,7 +429,7 @@ julia> "v: $v" "v: [1, 2, 3]" ``` -[`string`](@ref) is the identity for `AbstractString` and `Char` values, so these are interpolated +[`string`](@ref) is the identity for `AbstractString` and `AbstractChar` values, so these are interpolated into strings as themselves, unquoted and unescaped: ```jldoctest diff --git a/doc/src/manual/types.md b/doc/src/manual/types.md index c64215b7a9203..b0fa96264ed2b 100644 --- a/doc/src/manual/types.md +++ b/doc/src/manual/types.md @@ -246,7 +246,7 @@ primitive type Float32 <: AbstractFloat 32 end primitive type Float64 <: AbstractFloat 64 end primitive type Bool <: Integer 8 end -primitive type Char 32 end +primitive type Char <: AbstractChar 32 end primitive type Int8 <: Signed 8 end primitive type UInt8 <: Unsigned 8 end diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index ffcde456ddf49..5e3ec8dce705f 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -182,10 +182,10 @@ struct Delim{T, length} <: AbstractDateToken d::T end -Delim(d::Char) = Delim{Char, 1}(d) +Delim(d::T) where {T<:AbstractChar} = Delim{T, 1}(d) Delim(d::String) = Delim{String, length(d)}(d) -@inline function tryparsenext(d::Delim{Char, N}, str, i::Int, len) where N +@inline function tryparsenext(d::Delim{<:AbstractChar, N}, str, i::Int, len) where N for j=1:N i > len && return (nothing, i) c, i = next(str, i) @@ -214,7 +214,7 @@ end write(io, d.d) end -function _show_content(io::IO, d::Delim{Char, N}) where N +function _show_content(io::IO, d::Delim{<:AbstractChar, N}) where N if d.d in keys(CONVERSION_SPECIFIERS) for i = 1:N write(io, '\\', d.d) diff --git a/stdlib/DelimitedFiles/docs/src/index.md b/stdlib/DelimitedFiles/docs/src/index.md index 2a343d5269eaf..839bdb8f0f0e5 100644 --- a/stdlib/DelimitedFiles/docs/src/index.md +++ b/stdlib/DelimitedFiles/docs/src/index.md @@ -5,10 +5,10 @@ DocTestSetup = :(using DelimitedFiles) ``` ```@docs -DelimitedFiles.readdlm(::Any, ::Char, ::Type, ::Char) -DelimitedFiles.readdlm(::Any, ::Char, ::Char) -DelimitedFiles.readdlm(::Any, ::Char, ::Type) -DelimitedFiles.readdlm(::Any, ::Char) +DelimitedFiles.readdlm(::Any, ::AbstractChar, ::Type, ::AbstractChar) +DelimitedFiles.readdlm(::Any, ::AbstractChar, ::AbstractChar) +DelimitedFiles.readdlm(::Any, ::AbstractChar, ::Type) +DelimitedFiles.readdlm(::Any, ::AbstractChar) DelimitedFiles.readdlm(::Any, ::Type) DelimitedFiles.readdlm(::Any) DelimitedFiles.writedlm diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index 904ab945669b5..861ddd9747e42 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -63,7 +63,7 @@ julia> rm("delim_file.txt") readdlm(input, T::Type; opts...) = readdlm(input, invalid_dlm(Char), T, '\n'; opts...) """ - readdlm(source, delim::Char, T::Type; options...) + readdlm(source, delim::AbstractChar, T::Type; options...) The end of line delimiter is taken as `\\n`. @@ -89,7 +89,7 @@ julia> readdlm("delim_file.txt", ',', Float64) julia> rm("delim_file.txt") ``` """ -readdlm(input, dlm::Char, T::Type; opts...) = readdlm(input, dlm, T, '\n'; opts...) +readdlm(input, dlm::AbstractChar, T::Type; opts...) = readdlm(input, dlm, T, '\n'; opts...) """ readdlm(source; options...) @@ -124,7 +124,7 @@ julia> rm("delim_file.txt") readdlm(input; opts...) = readdlm(input, invalid_dlm(Char), '\n'; opts...) """ - readdlm(source, delim::Char; options...) + readdlm(source, delim::AbstractChar; 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 @@ -167,19 +167,19 @@ julia> readdlm("delim_file.txt", ',') julia> rm("delim_file.txt") ``` """ -readdlm(input, dlm::Char; opts...) = readdlm(input, dlm, '\n'; opts...) +readdlm(input, dlm::AbstractChar; opts...) = readdlm(input, dlm, '\n'; opts...) """ - readdlm(source, delim::Char, eol::Char; options...) + readdlm(source, delim::AbstractChar, eol::AbstractChar; 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(input, dlm::AbstractChar, eol::AbstractChar; 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=false, comment_char='#') + readdlm(source, delim::AbstractChar, T::Type, eol::AbstractChar; header=false, skipstart=0, skipblanks=true, use_mmap, quotes=true, dims, comments=false, 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 @@ -228,14 +228,14 @@ julia> readdlm("delim_file.txt", '\\t', Int, '\\n') 4 8 ``` """ -readdlm(input, dlm::Char, T::Type, eol::Char; opts...) = +readdlm(input, dlm::AbstractChar, T::Type, eol::AbstractChar; opts...) = readdlm_auto(input, dlm, T, eol, false; opts...) -readdlm_auto(input::Vector{UInt8}, dlm::Char, T::Type, eol::Char, auto::Bool; opts...) = +readdlm_auto(input::Vector{UInt8}, dlm::AbstractChar, T::Type, eol::AbstractChar, 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_auto(input::IO, dlm::AbstractChar, T::Type, eol::AbstractChar, auto::Bool; opts...) = readdlm_string(read(input, String), dlm, T, eol, auto, val_opts(opts)) -function readdlm_auto(input::AbstractString, dlm::Char, T::Type, eol::Char, auto::Bool; opts...) +function readdlm_auto(input::AbstractString, dlm::AbstractChar, T::Type, eol::AbstractChar, auto::Bool; opts...) isfile(input) || throw(ArgumentError("Cannot open \'$input\': not a file")) optsd = val_opts(opts) use_mmap = get(optsd, :use_mmap, Sys.iswindows() ? false : true) @@ -327,13 +327,13 @@ mutable struct DLMStore{T} <: DLMHandler end function DLMStore(::Type{T}, dims::NTuple{2,Integer}, - has_header::Bool, sbuff::String, auto::Bool, eol::Char) where T + has_header::Bool, sbuff::String, auto::Bool, eol::AbstractChar) where T (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), Matrix{T}(uninitialized, nrows-hdr_offset, ncols), - nrows, ncols, 0, 0, hdr_offset, sbuff, auto, eol) + nrows, ncols, 0, 0, hdr_offset, sbuff, auto, Char(eol)) end _chrinstr(sbuff::String, chr::UInt8, startpos::Int, endpos::Int) = @@ -369,7 +369,7 @@ function store_cell(dlmstore::DLMStore{T}, row::Int, col::Int, 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 + elseif ((T <: Number) || (T <: AbstractChar)) && dlmstore.auto throw(TypeError(:store_cell, "", Any, T)) else error("missing value at row $lastrow column $cidx") @@ -423,7 +423,7 @@ function result(dlmstore::DLMStore{T}) where T 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 + elseif ((T <: Number) || (T <: AbstractChar)) && dlmstore.auto throw(TypeError(:store_cell, "", Any, T)) else error("missing value at row $lastrow column $cidx") @@ -439,7 +439,7 @@ function result(dlmstore::DLMStore{T}) where T end -function readdlm_string(sbuff::String, dlm::Char, T::Type, eol::Char, auto::Bool, optsd::Dict) +function readdlm_string(sbuff::String, dlm::AbstractChar, T::Type, eol::AbstractChar, auto::Bool, optsd::Dict) ign_empty = (dlm == invalid_dlm(Char)) quotes = get(optsd, :quotes, true) comments = get(optsd, :comments, false) @@ -495,7 +495,7 @@ function val_opts(opts) 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) +function dlm_fill(T::DataType, offarr::Vector{Vector{Int}}, dims::NTuple{2,Integer}, has_header::Bool, sbuff::String, auto::Bool, eol::AbstractChar) idx = 1 offidx = 1 offsets = offarr[1] @@ -560,7 +560,7 @@ function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{Any,2}, cells[row, col] = SubString(sbuff, startpos, endpos) false end -function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{<:Char,2}, row::Int, col::Int) +function colval(sbuff::String, startpos::Int, endpos::Int, cells::Array{<:AbstractChar,2}, row::Int, col::Int) if startpos == endpos cells[row, col] = next(sbuff, startpos)[1] return false @@ -732,7 +732,7 @@ end # todo: keyword argument for # of digits to print writedlm_cell(io::IO, elt::AbstractFloat, dlm, quotes) = print(io, elt) function writedlm_cell(io::IO, elt::AbstractString, dlm::T, quotes::Bool) where T - if quotes && !isempty(elt) && (('"' in elt) || ('\n' in elt) || ((T <: Char) ? (dlm in elt) : contains(elt, dlm))) + if quotes && !isempty(elt) && (('"' in elt) || ('\n' in elt) || ((T <: AbstractChar) ? (dlm in elt) : contains(elt, dlm))) print(io, '"', replace(elt, r"\"" => "\"\""), '"') else print(io, elt) diff --git a/stdlib/LinearAlgebra/src/bidiag.jl b/stdlib/LinearAlgebra/src/bidiag.jl index 56f745340e493..f52aee3f63dbf 100644 --- a/stdlib/LinearAlgebra/src/bidiag.jl +++ b/stdlib/LinearAlgebra/src/bidiag.jl @@ -5,13 +5,13 @@ struct Bidiagonal{T,V<:AbstractVector{T}} <: AbstractMatrix{T} dv::V # diagonal ev::V # sub/super diagonal uplo::Char # upper bidiagonal ('U') or lower ('L') - function Bidiagonal{T}(dv::V, ev::V, uplo::Char) where {T,V<:AbstractVector{T}} + function Bidiagonal{T}(dv::V, ev::V, uplo::AbstractChar) where {T,V<:AbstractVector{T}} if length(ev) != length(dv)-1 throw(DimensionMismatch("length of diagonal vector is $(length(dv)), length of off-diagonal vector is $(length(ev))")) end new{T,V}(dv, ev, uplo) end - function Bidiagonal(dv::V, ev::V, uplo::Char) where {T,V<:AbstractVector{T}} + function Bidiagonal(dv::V, ev::V, uplo::AbstractChar) where {T,V<:AbstractVector{T}} Bidiagonal{T}(dv, ev, uplo) end end diff --git a/stdlib/LinearAlgebra/src/blas.jl b/stdlib/LinearAlgebra/src/blas.jl index 5d6d5198b79d9..6919caba0aebd 100644 --- a/stdlib/LinearAlgebra/src/blas.jl +++ b/stdlib/LinearAlgebra/src/blas.jl @@ -551,7 +551,7 @@ for (fname, elty) in ((:dgemv_,:Float64), # CHARACTER TRANS #* .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*),Y(*) - function gemv!(trans::Char, alpha::($elty), A::AbstractVecOrMat{$elty}, X::AbstractVector{$elty}, beta::($elty), Y::AbstractVector{$elty}) + function gemv!(trans::AbstractChar, alpha::($elty), A::AbstractVecOrMat{$elty}, X::AbstractVector{$elty}, beta::($elty), Y::AbstractVector{$elty}) m,n = size(A,1),size(A,2) if trans == 'N' && (length(X) != n || length(Y) != m) throw(DimensionMismatch("A has dimensions $(size(A)), X has length $(length(X)) and Y has length $(length(Y))")) @@ -570,10 +570,10 @@ for (fname, elty) in ((:dgemv_,:Float64), beta, Y, stride(Y,1)) Y end - function gemv(trans::Char, alpha::($elty), A::AbstractMatrix{$elty}, X::AbstractVector{$elty}) + function gemv(trans::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, X::AbstractVector{$elty}) gemv!(trans, alpha, A, X, zero($elty), similar(X, $elty, size(A, (trans == 'N' ? 1 : 2)))) end - function gemv(trans::Char, A::AbstractMatrix{$elty}, X::AbstractVector{$elty}) + function gemv(trans::AbstractChar, A::AbstractMatrix{$elty}, X::AbstractVector{$elty}) gemv!(trans, one($elty), A, X, zero($elty), similar(X, $elty, size(A, (trans == 'N' ? 1 : 2)))) end end @@ -635,7 +635,7 @@ for (fname, elty) in ((:dgbmv_,:Float64), # CHARACTER TRANS # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*),Y(*) - function gbmv!(trans::Char, m::Integer, kl::Integer, ku::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) + function gbmv!(trans::AbstractChar, m::Integer, kl::Integer, ku::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) chkstride1(A) ccall((@blasfunc($fname), libblas), Cvoid, (Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, Ref{BlasInt}, @@ -647,12 +647,12 @@ for (fname, elty) in ((:dgbmv_,:Float64), x, stride(x,1), beta, y, stride(y,1)) y end - function gbmv(trans::Char, m::Integer, kl::Integer, ku::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function gbmv(trans::AbstractChar, m::Integer, kl::Integer, ku::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) n = size(A,2) leny = trans == 'N' ? m : n gbmv!(trans, m, kl, ku, alpha, A, x, zero($elty), similar(x, $elty, leny)) end - function gbmv(trans::Char, m::Integer, kl::Integer, ku::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function gbmv(trans::AbstractChar, m::Integer, kl::Integer, ku::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) gbmv(trans, m, kl, ku, one($elty), A, x) end end @@ -682,7 +682,7 @@ for (fname, elty, lib) in ((:dsymv_,:Float64,libblas), # CHARACTER UPLO # .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*),Y(*) - function symv!(uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) + function symv!(uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) m, n = size(A) if m != n throw(DimensionMismatch("matrix A is $m by $n but must be square")) @@ -703,10 +703,10 @@ for (fname, elty, lib) in ((:dsymv_,:Float64,libblas), y, stride(y,1)) y end - function symv(uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function symv(uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) symv!(uplo, alpha, A, x, zero($elty), similar(x)) end - function symv(uplo::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function symv(uplo::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) symv(uplo, one($elty), A, x) end end @@ -733,7 +733,7 @@ symv(ul, A, x) for (fname, elty) in ((:zhemv_,:ComplexF64), (:chemv_,:ComplexF32)) @eval begin - function hemv!(uplo::Char, α::$elty, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, β::$elty, y::AbstractVector{$elty}) + function hemv!(uplo::AbstractChar, α::$elty, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, β::$elty, y::AbstractVector{$elty}) m, n = size(A) if m != n throw(DimensionMismatch("matrix A is $m by $n but must be square")) @@ -757,10 +757,10 @@ for (fname, elty) in ((:zhemv_,:ComplexF64), y, incy) y end - function hemv(uplo::Char, α::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function hemv(uplo::AbstractChar, α::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) hemv!(uplo, α, A, x, zero($elty), similar(x)) end - function hemv(uplo::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function hemv(uplo::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) hemv(uplo, one($elty), A, x) end end @@ -777,7 +777,7 @@ for (fname, elty) in ((:dsbmv_,:Float64), # CHARACTER UPLO # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*),Y(*) - function sbmv!(uplo::Char, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) + function sbmv!(uplo::AbstractChar, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) chkstride1(A) ccall((@blasfunc($fname), libblas), Cvoid, (Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, Ref{$elty}, @@ -788,11 +788,11 @@ for (fname, elty) in ((:dsbmv_,:Float64), beta, y, stride(y,1)) y end - function sbmv(uplo::Char, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function sbmv(uplo::AbstractChar, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) n = size(A,2) sbmv!(uplo, k, alpha, A, x, zero($elty), similar(x, $elty, n)) end - function sbmv(uplo::Char, k::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function sbmv(uplo::AbstractChar, k::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) sbmv(uplo, k, one($elty), A, x) end end @@ -840,7 +840,7 @@ for (fname, elty) in ((:zhbmv_,:ComplexF64), # CHARACTER UPLO # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*),Y(*) - function hbmv!(uplo::Char, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) + function hbmv!(uplo::AbstractChar, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}, beta::($elty), y::AbstractVector{$elty}) chkstride1(A) ccall((@blasfunc($fname), libblas), Cvoid, (Ref{UInt8}, Ref{BlasInt}, Ref{BlasInt}, Ref{$elty}, @@ -851,11 +851,11 @@ for (fname, elty) in ((:zhbmv_,:ComplexF64), beta, y, stride(y,1)) y end - function hbmv(uplo::Char, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function hbmv(uplo::AbstractChar, k::Integer, alpha::($elty), A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) n = size(A,2) hbmv!(uplo, k, alpha, A, x, zero($elty), similar(x, $elty, n)) end - function hbmv(uplo::Char, k::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function hbmv(uplo::AbstractChar, k::Integer, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) hbmv(uplo, k, one($elty), A, x) end end @@ -895,7 +895,7 @@ for (fname, elty) in ((:dtrmv_,:Float64), # CHARACTER DIAG,TRANS,UPLO # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*) - function trmv!(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function trmv!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) n = checksquare(A) if n != length(x) throw(DimensionMismatch("A has size ($n,$n), x has length $(length(x))")) @@ -908,7 +908,7 @@ for (fname, elty) in ((:dtrmv_,:Float64), A, max(1,stride(A,2)), x, max(1,stride(x, 1))) x end - function trmv(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function trmv(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) trmv!(uplo, trans, diag, A, copy(x)) end end @@ -948,7 +948,7 @@ for (fname, elty) in ((:dtrsv_,:Float64), # CHARACTER DIAG,TRANS,UPLO # .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),X(*) - function trsv!(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function trsv!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) n = checksquare(A) if n != length(x) throw(DimensionMismatch("size of A is $n != length(x) = $(length(x))")) @@ -961,7 +961,7 @@ for (fname, elty) in ((:dtrsv_,:Float64), A, max(1,stride(A,2)), x, stride(x, 1)) x end - function trsv(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) + function trsv(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, x::AbstractVector{$elty}) trsv!(uplo, trans, diag, A, copy(x)) end end @@ -1013,7 +1013,7 @@ for (fname, elty, lib) in ((:dsyr_,:Float64,libblas), (:zsyr_,:ComplexF64,liblapack), (:csyr_,:ComplexF32,liblapack)) @eval begin - function syr!(uplo::Char, α::$elty, x::AbstractVector{$elty}, A::AbstractMatrix{$elty}) + function syr!(uplo::AbstractChar, α::$elty, x::AbstractVector{$elty}, A::AbstractMatrix{$elty}) n = checksquare(A) if length(x) != n throw(DimensionMismatch("A has size ($n,$n), x has length $(length(x))")) @@ -1042,7 +1042,7 @@ function her! end for (fname, elty, relty) in ((:zher_,:ComplexF64, :Float64), (:cher_,:ComplexF32, :Float32)) @eval begin - function her!(uplo::Char, α::$relty, x::AbstractVector{$elty}, A::AbstractMatrix{$elty}) + function her!(uplo::AbstractChar, α::$relty, x::AbstractVector{$elty}, A::AbstractMatrix{$elty}) n = checksquare(A) if length(x) != n throw(DimensionMismatch("A has size ($n,$n), x has length $(length(x))")) @@ -1081,7 +1081,7 @@ for (gemm, elty) in # CHARACTER TRANSA,TRANSB # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),B(LDB,*),C(LDC,*) - function gemm!(transA::Char, transB::Char, alpha::($elty), A::AbstractVecOrMat{$elty}, B::AbstractVecOrMat{$elty}, beta::($elty), C::AbstractVecOrMat{$elty}) + function gemm!(transA::AbstractChar, transB::AbstractChar, alpha::($elty), A::AbstractVecOrMat{$elty}, B::AbstractVecOrMat{$elty}, beta::($elty), C::AbstractVecOrMat{$elty}) # if any([stride(A,1), stride(B,1), stride(C,1)] .!= 1) # error("gemm!: BLAS module requires contiguous matrix columns") # end # should this be checked on every call? @@ -1106,10 +1106,10 @@ for (gemm, elty) in max(1,stride(C,2))) C end - function gemm(transA::Char, transB::Char, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function gemm(transA::AbstractChar, transB::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) gemm!(transA, transB, alpha, A, B, zero($elty), similar(B, $elty, (size(A, transA == 'N' ? 1 : 2), size(B, transB == 'N' ? 2 : 1)))) end - function gemm(transA::Char, transB::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function gemm(transA::AbstractChar, transB::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) gemm(transA, transB, one($elty), A, B) end end @@ -1143,7 +1143,7 @@ for (mfname, elty) in ((:dsymm_,:Float64), # CHARACTER SIDE,UPLO # .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),B(LDB,*),C(LDC,*) - function symm!(side::Char, uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}, beta::($elty), C::AbstractMatrix{$elty}) + function symm!(side::AbstractChar, uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}, beta::($elty), C::AbstractMatrix{$elty}) m, n = size(C) j = checksquare(A) if j != (side == 'L' ? m : n) @@ -1164,10 +1164,10 @@ for (mfname, elty) in ((:dsymm_,:Float64), max(1,stride(B,2)), beta, C, max(1,stride(C,2))) C end - function symm(side::Char, uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function symm(side::AbstractChar, uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) symm!(side, uplo, alpha, A, B, zero($elty), similar(B)) end - function symm(side::Char, uplo::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function symm(side::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) symm(side, uplo, one($elty), A, B) end end @@ -1211,7 +1211,7 @@ for (mfname, elty) in ((:zhemm_,:ComplexF64), # CHARACTER SIDE,UPLO # .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),B(LDB,*),C(LDC,*) - function hemm!(side::Char, uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}, beta::($elty), C::AbstractMatrix{$elty}) + function hemm!(side::AbstractChar, uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}, beta::($elty), C::AbstractMatrix{$elty}) m, n = size(C) j = checksquare(A) if j != (side == 'L' ? m : n) @@ -1232,10 +1232,10 @@ for (mfname, elty) in ((:zhemm_,:ComplexF64), max(1,stride(B,2)), beta, C, max(1,stride(C,2))) C end - function hemm(side::Char, uplo::Char, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function hemm(side::AbstractChar, uplo::AbstractChar, alpha::($elty), A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) hemm!(side, uplo, alpha, A, B, zero($elty), similar(B)) end - function hemm(side::Char, uplo::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function hemm(side::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) hemm(side, uplo, one($elty), A, B) end end @@ -1274,7 +1274,7 @@ for (fname, elty) in ((:dsyrk_,:Float64), # CHARACTER TRANS,UPLO # * .. Array Arguments .. # REAL A(LDA,*),C(LDC,*) - function syrk!(uplo::Char, trans::Char, + function syrk!(uplo::AbstractChar, trans::AbstractChar, alpha::($elty), A::AbstractVecOrMat{$elty}, beta::($elty), C::AbstractMatrix{$elty}) n = checksquare(C) @@ -1294,12 +1294,12 @@ for (fname, elty) in ((:dsyrk_,:Float64), end end end -function syrk(uplo::Char, trans::Char, alpha::Number, A::AbstractVecOrMat) +function syrk(uplo::AbstractChar, trans::AbstractChar, alpha::Number, A::AbstractVecOrMat) T = eltype(A) n = size(A, trans == 'N' ? 1 : 2) syrk!(uplo, trans, convert(T,alpha), A, zero(T), similar(A, T, (n, n))) end -syrk(uplo::Char, trans::Char, A::AbstractVecOrMat) = syrk(uplo, trans, one(eltype(A)), A) +syrk(uplo::AbstractChar, trans::AbstractChar, A::AbstractVecOrMat) = syrk(uplo, trans, one(eltype(A)), A) """ herk!(uplo, trans, alpha, A, beta, C) @@ -1331,7 +1331,7 @@ for (fname, elty, relty) in ((:zherk_, :ComplexF64, :Float64), # * .. # * .. Array Arguments .. # COMPLEX A(LDA,*),C(LDC,*) - function herk!(uplo::Char, trans::Char, α::$relty, A::AbstractVecOrMat{$elty}, + function herk!(uplo::AbstractChar, trans::AbstractChar, α::$relty, A::AbstractVecOrMat{$elty}, β::$relty, C::AbstractMatrix{$elty}) n = checksquare(C) nn = size(A, trans == 'N' ? 1 : 2) @@ -1350,11 +1350,11 @@ for (fname, elty, relty) in ((:zherk_, :ComplexF64, :Float64), C, max(1,stride(C,2))) C end - function herk(uplo::Char, trans::Char, α::$relty, A::AbstractVecOrMat{$elty}) + function herk(uplo::AbstractChar, trans::AbstractChar, α::$relty, A::AbstractVecOrMat{$elty}) n = size(A, trans == 'N' ? 1 : 2) herk!(uplo, trans, α, A, zero($relty), similar(A, (n,n))) end - herk(uplo::Char, trans::Char, A::AbstractVecOrMat{$elty}) = herk(uplo, trans, one($relty), A) + herk(uplo::AbstractChar, trans::AbstractChar, A::AbstractVecOrMat{$elty}) = herk(uplo, trans, one($relty), A) end end @@ -1373,7 +1373,7 @@ for (fname, elty) in ((:dsyr2k_,:Float64), # .. # .. Array Arguments .. # REAL PRECISION A(LDA,*),B(LDB,*),C(LDC,*) - function syr2k!(uplo::Char, trans::Char, + function syr2k!(uplo::AbstractChar, trans::AbstractChar, alpha::($elty), A::AbstractVecOrMat{$elty}, B::AbstractVecOrMat{$elty}, beta::($elty), C::AbstractMatrix{$elty}) n = checksquare(C) @@ -1394,12 +1394,12 @@ for (fname, elty) in ((:dsyr2k_,:Float64), end end end -function syr2k(uplo::Char, trans::Char, alpha::Number, A::AbstractVecOrMat, B::AbstractVecOrMat) +function syr2k(uplo::AbstractChar, trans::AbstractChar, alpha::Number, A::AbstractVecOrMat, B::AbstractVecOrMat) T = eltype(A) n = size(A, trans == 'N' ? 1 : 2) syr2k!(uplo, trans, convert(T,alpha), A, B, zero(T), similar(A, T, (n, n))) end -syr2k(uplo::Char, trans::Char, A::AbstractVecOrMat, B::AbstractVecOrMat) = syr2k(uplo, trans, one(eltype(A)), A, B) +syr2k(uplo::AbstractChar, trans::AbstractChar, A::AbstractVecOrMat, B::AbstractVecOrMat) = syr2k(uplo, trans, one(eltype(A)), A, B) for (fname, elty1, elty2) in ((:zher2k_,:ComplexF64,:Float64), (:cher2k_,:ComplexF32,:Float32)) @eval begin @@ -1413,7 +1413,7 @@ for (fname, elty1, elty2) in ((:zher2k_,:ComplexF64,:Float64), (:cher2k_,:Comple # .. # .. Array Arguments .. # COMPLEX A(LDA,*),B(LDB,*),C(LDC,*) - function her2k!(uplo::Char, trans::Char, alpha::($elty1), + function her2k!(uplo::AbstractChar, trans::AbstractChar, alpha::($elty1), A::AbstractVecOrMat{$elty1}, B::AbstractVecOrMat{$elty1}, beta::($elty2), C::AbstractMatrix{$elty1}) n = checksquare(C) @@ -1432,11 +1432,11 @@ for (fname, elty1, elty2) in ((:zher2k_,:ComplexF64,:Float64), (:cher2k_,:Comple beta, C, max(1,stride(C,2))) C end - function her2k(uplo::Char, trans::Char, alpha::($elty1), A::AbstractVecOrMat{$elty1}, B::AbstractVecOrMat{$elty1}) + function her2k(uplo::AbstractChar, trans::AbstractChar, alpha::($elty1), A::AbstractVecOrMat{$elty1}, B::AbstractVecOrMat{$elty1}) n = size(A, trans == 'N' ? 1 : 2) her2k!(uplo, trans, alpha, A, B, zero($elty2), similar(A, $elty1, (n,n))) end - her2k(uplo::Char, trans::Char, A::AbstractVecOrMat{$elty1}, B::AbstractVecOrMat{$elty1}) = her2k(uplo, trans, one($elty1), A, B) + her2k(uplo::AbstractChar, trans::AbstractChar, A::AbstractVecOrMat{$elty1}, B::AbstractVecOrMat{$elty1}) = her2k(uplo, trans, one($elty1), A, B) end end @@ -1501,7 +1501,7 @@ for (mmname, smname, elty) in # CHARACTER DIAG,SIDE,TRANSA,UPLO # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),B(LDB,*) - function trmm!(side::Char, uplo::Char, transa::Char, diag::Char, alpha::Number, + function trmm!(side::AbstractChar, uplo::AbstractChar, transa::AbstractChar, diag::AbstractChar, alpha::Number, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) m, n = size(B) nA = checksquare(A) @@ -1517,7 +1517,7 @@ for (mmname, smname, elty) in alpha, A, max(1,stride(A,2)), B, max(1,stride(B,2))) B end - function trmm(side::Char, uplo::Char, transa::Char, diag::Char, + function trmm(side::AbstractChar, uplo::AbstractChar, transa::AbstractChar, diag::AbstractChar, alpha::$elty, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) trmm!(side, uplo, transa, diag, alpha, A, copy(B)) end @@ -1528,7 +1528,7 @@ for (mmname, smname, elty) in # CHARACTER DIAG,SIDE,TRANSA,UPLO # * .. Array Arguments .. # DOUBLE PRECISION A(LDA,*),B(LDB,*) - function trsm!(side::Char, uplo::Char, transa::Char, diag::Char, + function trsm!(side::AbstractChar, uplo::AbstractChar, transa::AbstractChar, diag::AbstractChar, alpha::$elty, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) m, n = size(B) k = checksquare(A) @@ -1546,7 +1546,7 @@ for (mmname, smname, elty) in max(1,stride(A,2)), B, max(1,stride(B,2))) B end - function trsm(side::Char, uplo::Char, transa::Char, diag::Char, alpha::$elty, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function trsm(side::AbstractChar, uplo::AbstractChar, transa::AbstractChar, diag::AbstractChar, alpha::$elty, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) trsm!(side, uplo, transa, diag, alpha, A, copy(B)) end end diff --git a/stdlib/LinearAlgebra/src/bunchkaufman.jl b/stdlib/LinearAlgebra/src/bunchkaufman.jl index 80db51dcb802c..6f9b562564599 100644 --- a/stdlib/LinearAlgebra/src/bunchkaufman.jl +++ b/stdlib/LinearAlgebra/src/bunchkaufman.jl @@ -12,7 +12,7 @@ struct BunchKaufman{T,S<:AbstractMatrix} <: Factorization{T} rook::Bool info::BlasInt end -BunchKaufman(A::AbstractMatrix{T}, ipiv::Vector{BlasInt}, uplo::Char, symmetric::Bool, +BunchKaufman(A::AbstractMatrix{T}, ipiv::Vector{BlasInt}, uplo::AbstractChar, symmetric::Bool, rook::Bool, info::BlasInt) where {T} = BunchKaufman{T,typeof(A)}(A, ipiv, uplo, symmetric, rook, info) @@ -88,7 +88,7 @@ size(B::BunchKaufman, d::Integer) = size(getfield(B, :LD), d) issymmetric(B::BunchKaufman) = B.symmetric ishermitian(B::BunchKaufman) = !B.symmetric -function _ipiv2perm_bk(v::AbstractVector{T}, maxi::Integer, uplo::Char) where T +function _ipiv2perm_bk(v::AbstractVector{T}, maxi::Integer, uplo::AbstractChar) where T p = T[1:maxi;] uploL = uplo == 'L' i = uploL ? 1 : maxi diff --git a/stdlib/LinearAlgebra/src/cholesky.jl b/stdlib/LinearAlgebra/src/cholesky.jl index 1f390615da0e6..72b4c9a940af6 100644 --- a/stdlib/LinearAlgebra/src/cholesky.jl +++ b/stdlib/LinearAlgebra/src/cholesky.jl @@ -36,7 +36,7 @@ struct Cholesky{T,S<:AbstractMatrix} <: Factorization{T} end Cholesky(A::AbstractMatrix{T}, uplo::Symbol, info::BlasInt) where {T} = Cholesky{T,typeof(A)}(A, char_uplo(uplo), info) -Cholesky(A::AbstractMatrix{T}, uplo::Char, info::BlasInt) where {T} = +Cholesky(A::AbstractMatrix{T}, uplo::AbstractChar, info::BlasInt) where {T} = Cholesky{T,typeof(A)}(A, uplo, info) struct CholeskyPivoted{T,S<:AbstractMatrix} <: Factorization{T} @@ -47,7 +47,7 @@ struct CholeskyPivoted{T,S<:AbstractMatrix} <: Factorization{T} tol::Real info::BlasInt end -function CholeskyPivoted(A::AbstractMatrix{T}, uplo::Char, piv::Vector{BlasInt}, +function CholeskyPivoted(A::AbstractMatrix{T}, uplo::AbstractChar, piv::Vector{BlasInt}, rank::BlasInt, tol::Real, info::BlasInt) where T CholeskyPivoted{T,typeof(A)}(A, uplo, piv, rank, tol, info) end diff --git a/stdlib/LinearAlgebra/src/deprecated.jl b/stdlib/LinearAlgebra/src/deprecated.jl index c68016c29d816..38efdf5f06f96 100644 --- a/stdlib/LinearAlgebra/src/deprecated.jl +++ b/stdlib/LinearAlgebra/src/deprecated.jl @@ -49,7 +49,7 @@ end # PR #22703 @deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, isupper::Bool) Bidiagonal(dv, ev, ifelse(isupper, :U, :L)) -@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, uplo::Char) Bidiagonal(dv, ev, ifelse(uplo == 'U', :U, :L)) +@deprecate Bidiagonal(dv::AbstractVector, ev::AbstractVector, uplo::AbstractChar) Bidiagonal(dv, ev, ifelse(uplo == 'U', :U, :L)) @deprecate Bidiagonal(A::AbstractMatrix, isupper::Bool) Bidiagonal(A, ifelse(isupper, :U, :L)) # PR #22925 diff --git a/stdlib/LinearAlgebra/src/lapack.jl b/stdlib/LinearAlgebra/src/lapack.jl index 87c5c76adebe8..fc11c83af3322 100644 --- a/stdlib/LinearAlgebra/src/lapack.jl +++ b/stdlib/LinearAlgebra/src/lapack.jl @@ -9,7 +9,7 @@ const liblapack = Base.liblapack_name import ..LinearAlgebra.BLAS.@blasfunc -import ..LinearAlgebra: BlasFloat, Char, BlasInt, LAPACKException, +import ..LinearAlgebra: BlasFloat, BlasInt, LAPACKException, DimensionMismatch, SingularException, PosDefException, chkstride1, checksquare using ..LinearAlgebra: triu, tril, dot @@ -52,7 +52,7 @@ function chkposdef(ret::BlasInt) end "Check that upper/lower (for special matrices) is correctly specified" -function chkuplo(uplo::Char) +function chkuplo(uplo::AbstractChar) if !(uplo == 'U' || uplo == 'L') throw(ArgumentError("uplo argument must be 'U' (upper) or 'L' (lower), got $uplo")) end @@ -60,7 +60,7 @@ function chkuplo(uplo::Char) end "Check that {c}transpose is correctly specified" -function chktrans(trans::Char) +function chktrans(trans::AbstractChar) if !(trans == 'N' || trans == 'C' || trans == 'T') throw(ArgumentError("trans argument must be 'N' (no transpose), 'T' (transpose), or 'C' (conjugate transpose), got $trans")) end @@ -68,7 +68,7 @@ function chktrans(trans::Char) end "Check that left/right hand side multiply is correctly specified" -function chkside(side::Char) +function chkside(side::AbstractChar) if !(side == 'L' || side == 'R') throw(ArgumentError("side argument must be 'L' (left hand multiply) or 'R' (right hand multiply), got $side")) end @@ -76,7 +76,7 @@ function chkside(side::Char) end "Check that unit diagonal flag is correctly specified" -function chkdiag(diag::Char) +function chkdiag(diag::AbstractChar) if !(diag == 'U' || diag =='N') throw(ArgumentError("diag argument must be 'U' (unit diagonal) or 'N' (non-unit diagonal), got $diag")) end @@ -140,7 +140,7 @@ for (gbtrf, gbtrs, elty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION AB( LDAB, * ), B( LDB, * ) - function gbtrs!(trans::Char, kl::Integer, ku::Integer, m::Integer, + function gbtrs!(trans::AbstractChar, kl::Integer, ku::Integer, m::Integer, AB::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(AB, B, ipiv) @@ -181,7 +181,7 @@ first subdiagonal containing a nonzero band, `ku` is the last superdiagonal containing one, and `m` is the first dimension of the matrix `AB`. `ipiv` is the vector of pivots returned from `gbtrf!`. Returns the vector or matrix `X`, overwriting `B` in-place. """ -gbtrs!(trans::Char, kl::Integer, ku::Integer, m::Integer, AB::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) +gbtrs!(trans::AbstractChar, kl::Integer, ku::Integer, m::Integer, AB::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) ## (GE) general matrices: balancing and back-transforming for (gebal, gebak, elty, relty) in @@ -196,7 +196,7 @@ for (gebal, gebak, elty, relty) in # INTEGER IHI, ILP, INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), SCALE( * ) - function gebal!(job::Char, A::AbstractMatrix{$elty}) + function gebal!(job::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs @@ -218,7 +218,7 @@ for (gebal, gebak, elty, relty) in # INTEGER IHI, ILP, INFO, LDV, M, N # .. Array Arguments .. # DOUBLE PRECISION SCALE( * ), V( LDV, * ) - function gebak!(job::Char, side::Char, + function gebak!(job::AbstractChar, side::AbstractChar, ilo::BlasInt, ihi::BlasInt, scale::AbstractVector{$relty}, V::AbstractMatrix{$elty}) chkstride1(scale, V) @@ -246,7 +246,7 @@ and scaled). Modifies `A` in-place and returns `ilo`, `ihi`, and `scale`. If permuting was turned on, `A[i,j] = 0` if `j > i` and `1 < j < ilo` or `j > ihi`. `scale` contains information about the scaling/permutations performed. """ -gebal!(job::Char, A::AbstractMatrix) +gebal!(job::AbstractChar, A::AbstractMatrix) """ gebak!(job, side, ilo, ihi, scale, V) @@ -256,7 +256,7 @@ the unscaled/unpermuted eigenvectors of the original matrix. Modifies `V` in-place. `side` can be `L` (left eigenvectors are transformed) or `R` (right eigenvectors are transformed). """ -gebak!(job::Char, side::Char, ilo::BlasInt, ihi::BlasInt, scale::AbstractVector, V::AbstractMatrix) +gebak!(job::AbstractChar, side::AbstractChar, ilo::BlasInt, ihi::BlasInt, scale::AbstractVector, V::AbstractMatrix) # (GE) general matrices, direct decompositions # @@ -790,7 +790,7 @@ for (tzrzf, ormrz, elty) in # .. # .. Array Arguments .. # COMPLEX*16 A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) - function ormrz!(side::Char, trans::Char, A::AbstractMatrix{$elty}, + function ormrz!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractMatrix{$elty}) chktrans(trans) chkside(side) @@ -834,7 +834,7 @@ can be unmodified (`trans = N`), transposed (`trans = T`), or conjugate transposed (`trans = C`). Returns matrix `C` which is modified in-place with the result of the multiplication. """ -ormrz!(side::Char, trans::Char, A::AbstractMatrix, tau::AbstractVector, C::AbstractMatrix) +ormrz!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix, tau::AbstractVector, C::AbstractMatrix) """ tzrzf!(A) -> (A, tau) @@ -856,7 +856,7 @@ for (gels, gesv, getrs, getri, elty) in # * .. Scalar Arguments .. # CHARACTER TRANS # INTEGER INFO, LDA, LDB, LWORK, M, N, NRHS - function gels!(trans::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function gels!(trans::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chktrans(trans) chkstride1(A, B) btrn = trans == 'T' @@ -923,7 +923,7 @@ for (gels, gesv, getrs, getri, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function getrs!(trans::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) + function getrs!(trans::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chktrans(trans) chkstride1(A, B, ipiv) n = checksquare(A) @@ -982,7 +982,7 @@ may be one of `N` (no modification), `T` (transpose), or `C` (conjugate transpose). `gels!` searches for the minimum norm/least squares solution. `A` may be under or over determined. The solution is returned in `B`. """ -gels!(trans::Char, A::AbstractMatrix, B::AbstractVecOrMat) +gels!(trans::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) """ gesv!(A, B) -> (B, A, ipiv) @@ -1003,7 +1003,7 @@ is the `LU` factorization from `getrf!`, with `ipiv` the pivoting information. `trans` may be one of `N` (no modification), `T` (transpose), or `C` (conjugate transpose). """ -getrs!(trans::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) +getrs!(trans::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) """ getri!(A, ipiv) @@ -1034,8 +1034,8 @@ for (gesvx, elty) in # $ BERR( * ), C( * ), FERR( * ), R( * ), # $ WORK( * ), X( LDX, * # - function gesvx!(fact::Char, trans::Char, A::AbstractMatrix{$elty}, - AF::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, equed::Char, + function gesvx!(fact::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, + AF::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, equed::AbstractChar, R::AbstractVector{$elty}, C::AbstractVector{$elty}, B::AbstractVecOrMat{$elty}) chktrans(trans) chkstride1(ipiv, R, C, B) @@ -1103,8 +1103,8 @@ for (gesvx, elty, relty) in # $ RWORK( * ) # COMPLEX*16 A( LDA, * ), AF( LDAF, * ), B( LDB, * ), # $ WORK( * ), X( LDX, * ) - function gesvx!(fact::Char, trans::Char, A::AbstractMatrix{$elty}, - AF::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, equed::Char, + function gesvx!(fact::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, + AF::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, equed::AbstractChar, R::AbstractVector{$relty}, C::AbstractVector{$relty}, B::AbstractVecOrMat{$elty}) chktrans(trans) chkstride1(A, AF, ipiv, R, C, B) @@ -1179,8 +1179,8 @@ condition number of `A` after equilbrating; `ferr`, the forward error bound for each solution vector in `X`; `berr`, the forward error bound for each solution vector in `X`; and `work`, the reciprocal pivot growth factor. """ -gesvx!(fact::Char, trans::Char, A::AbstractMatrix, AF::AbstractMatrix, - ipiv::AbstractVector{BlasInt}, equed::Char, R::AbstractVector, C::AbstractVector, B::AbstractVecOrMat) +gesvx!(fact::AbstractChar, trans::AbstractChar, A::AbstractMatrix, AF::AbstractMatrix, + ipiv::AbstractVector{BlasInt}, equed::AbstractChar, R::AbstractVector, C::AbstractVector, B::AbstractVecOrMat) """ gesvx!(A, B) @@ -1473,7 +1473,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ), # $ WI( * ), WORK( * ), WR( * ) - function geev!(jobvl::Char, jobvr::Char, A::AbstractMatrix{$elty}) + function geev!(jobvl::AbstractChar, jobvr::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs @@ -1529,7 +1529,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), S( * ), U( LDU, * ), # VT( LDVT, * ), WORK( * ) - function gesdd!(job::Char, A::AbstractMatrix{$elty}) + function gesdd!(job::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) @@ -1609,7 +1609,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), S( * ), U( LDU, * ), # $ VT( LDVT, * ), WORK( * ) - function gesvd!(jobu::Char, jobvt::Char, A::AbstractMatrix{$elty}) + function gesvd!(jobu::AbstractChar, jobvt::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) m, n = size(A) minmn = min(m, n) @@ -1677,7 +1677,7 @@ for (geev, gesvd, gesdd, ggsvd, elty, relty) in # DOUBLE PRECISION ALPHA( * ), BETA( * ), RWORK( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), Q( LDQ, * ), # $ U( LDU, * ), V( LDV, * ), WORK( * ) - function ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function ggsvd!(jobu::AbstractChar, jobv::AbstractChar, jobq::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n @@ -1752,7 +1752,7 @@ aren't computed. If `jobvl = V` or `jobvr = V`, the corresponding eigenvectors are computed. Returns the eigenvalues in `W`, the right eigenvectors in `VR`, and the left eigenvectors in `VL`. """ -geev!(jobvl::Char, jobvr::Char, A::AbstractMatrix) +geev!(jobvl::AbstractChar, jobvr::AbstractChar, A::AbstractMatrix) """ gesdd!(job, A) -> (U, S, VT) @@ -1764,7 +1764,7 @@ are computed. If `job = O`, `A` is overwritten with the columns of (thin) `U` and the rows of (thin) `V'`. If `job = S`, the columns of (thin) `U` and the rows of (thin) `V'` are computed and returned separately. """ -gesdd!(job::Char, A::AbstractMatrix) +gesdd!(job::AbstractChar, A::AbstractMatrix) """ gesvd!(jobu, jobvt, A) -> (U, S, VT) @@ -1780,7 +1780,7 @@ computed and returned separately. `jobu` and `jobvt` can't both be `O`. Returns `U`, `S`, and `Vt`, where `S` are the singular values of `A`. """ -gesvd!(jobu::Char, jobvt::Char, A::AbstractMatrix) +gesvd!(jobu::AbstractChar, jobvt::AbstractChar, A::AbstractMatrix) """ ggsvd!(jobu, jobv, jobq, A, B) -> (U, V, Q, alpha, beta, k, l, R) @@ -1793,13 +1793,13 @@ the orthogonal/unitary matrix `Q` is computed. If `jobu`, `jobv` or `jobq` is `N`, that matrix is not computed. This function is only available in LAPACK versions prior to 3.6.0. """ -ggsvd!(jobu::Char, jobv::Char, jobq::Char, A::AbstractMatrix, B::AbstractMatrix) +ggsvd!(jobu::AbstractChar, jobv::AbstractChar, jobq::AbstractChar, A::AbstractMatrix, B::AbstractMatrix) for (f, elty) in ((:dggsvd3_, :Float64), (:sggsvd3_, :Float32)) @eval begin - function ggsvd3!(jobu::Char, jobv::Char, jobq::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function ggsvd3!(jobu::AbstractChar, jobv::AbstractChar, jobq::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n @@ -1855,7 +1855,7 @@ end for (f, elty, relty) in ((:zggsvd3_, :ComplexF64, :Float64), (:cggsvd3_, :ComplexF32, :Float32)) @eval begin - function ggsvd3!(jobu::Char, jobv::Char, jobq::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function ggsvd3!(jobu::AbstractChar, jobv::AbstractChar, jobq::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) m, n = size(A) if size(B, 2) != n @@ -1942,7 +1942,7 @@ for (geevx, ggev, elty) in # DOUBLE PRECISION A( LDA, * ), RCONDE( * ), RCONDV( * ), # $ SCALE( * ), VL( LDVL, * ), VR( LDVR, * ), # $ WI( * ), WORK( * ), WR( * ) - function geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::AbstractMatrix{$elty}) + function geevx!(balanc::AbstractChar, jobvl::AbstractChar, jobvr::AbstractChar, sense::AbstractChar, A::AbstractMatrix{$elty}) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) @@ -2020,7 +2020,7 @@ for (geevx, ggev, elty) in # DOUBLE PRECISION A( LDA, * ), ALPHAI( * ), ALPHAR( * ), # $ B( LDB, * ), BETA( * ), VL( LDVL, * ), # $ VR( LDVR, * ), WORK( * ) - function ggev!(jobvl::Char, jobvr::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function ggev!(jobvl::AbstractChar, jobvr::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A,B) n, m = checksquare(A,B) if n != m @@ -2093,7 +2093,7 @@ for (geevx, ggev, elty, relty) in # $ SCALE( * ) # COMPLEX*16 A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ), # $ W( * ), WORK( * ) - function geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::AbstractMatrix{$elty}) + function geevx!(balanc::AbstractChar, jobvl::AbstractChar, jobvr::AbstractChar, sense::AbstractChar, A::AbstractMatrix{$elty}) n = checksquare(A) chkfinite(A) # balancing routines don't support NaNs and Infs lda = max(1,stride(A,2)) @@ -2166,7 +2166,7 @@ for (geevx, ggev, elty, relty) in # COMPLEX*16 A( LDA, * ), ALPHA( * ), B( LDB, * ), # $ BETA( * ), VL( LDVL, * ), VR( LDVR, * ), # $ WORK( * ) - function ggev!(jobvl::Char, jobvr::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function ggev!(jobvl::AbstractChar, jobvr::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m @@ -2238,7 +2238,7 @@ condition numbers are computed for the right eigenvectors and the eigenvectors. If `sense = E,B`, the right and left eigenvectors must be computed. """ -geevx!(balanc::Char, jobvl::Char, jobvr::Char, sense::Char, A::AbstractMatrix) +geevx!(balanc::AbstractChar, jobvl::AbstractChar, jobvr::AbstractChar, sense::AbstractChar, A::AbstractMatrix) """ ggev!(jobvl, jobvr, A, B) -> (alpha, beta, vl, vr) @@ -2248,7 +2248,7 @@ the left eigenvectors aren't computed. If `jobvr = N`, the right eigenvectors aren't computed. If `jobvl = V` or `jobvr = V`, the corresponding eigenvectors are computed. """ -ggev!(jobvl::Char, jobvr::Char, A::AbstractMatrix, B::AbstractMatrix) +ggev!(jobvl::AbstractChar, jobvr::AbstractChar, A::AbstractMatrix, B::AbstractMatrix) # One step incremental condition estimation of max/min singular values for (laic1, elty) in @@ -2387,7 +2387,7 @@ for (gtsv, gttrf, gttrs, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION B( LDB, * ), D( * ), DL( * ), DU( * ), DU2( * ) - function gttrs!(trans::Char, dl::AbstractVector{$elty}, d::AbstractVector{$elty}, + function gttrs!(trans::AbstractChar, dl::AbstractVector{$elty}, d::AbstractVector{$elty}, du::AbstractVector{$elty}, du2::AbstractVector{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chktrans(trans) @@ -2443,7 +2443,7 @@ Solves the equation `A * X = B` (`trans = N`), `transpose(A) * X = B` (`trans = or `adjoint(A) * X = B` (`trans = C`) using the `LU` factorization computed by `gttrf!`. `B` is overwritten with the solution `X`. """ -gttrs!(trans::Char, dl::AbstractVector, d::AbstractVector, du::AbstractVector, du2::AbstractVector, +gttrs!(trans::AbstractChar, dl::AbstractVector, d::AbstractVector, du::AbstractVector, du2::AbstractVector, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) ## (OR) orthogonal (or UN, unitary) matrices, extractors and multiplication @@ -2596,7 +2596,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in # INTEGER INFO, K, LDA, LDC, LWORK, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) - function ormlq!(side::Char, trans::Char, A::AbstractMatrix{$elty}, + function ormlq!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractVecOrMat{$elty}) chktrans(trans) chkside(side) @@ -2642,7 +2642,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in # INTEGER INFO, K, LDA, LDC, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) - function ormqr!(side::Char, trans::Char, A::AbstractMatrix{$elty}, + function ormqr!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractVecOrMat{$elty}) chktrans(trans) chkside(side) @@ -2691,7 +2691,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in # INTEGER INFO, K, LDA, LDC, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) - function ormql!(side::Char, trans::Char, A::AbstractMatrix{$elty}, + function ormql!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractVecOrMat{$elty}) chktrans(trans) chkside(side) @@ -2740,7 +2740,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in # INTEGER INFO, K, LDA, LDC, LWORK, M, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * ) - function ormrq!(side::Char, trans::Char, A::AbstractMatrix{$elty}, + function ormrq!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractVecOrMat{$elty}) chktrans(trans) chkside(side) @@ -2779,7 +2779,7 @@ for (orglq, orgqr, orgql, orgrq, ormlq, ormqr, ormql, ormrq, gemqrt, elty) in C end - function gemqrt!(side::Char, trans::Char, V::AbstractMatrix{$elty}, T::AbstractMatrix{$elty}, C::AbstractVecOrMat{$elty}) + function gemqrt!(side::AbstractChar, trans::AbstractChar, V::AbstractMatrix{$elty}, T::AbstractMatrix{$elty}, C::AbstractVecOrMat{$elty}) chktrans(trans) chkside(side) chkstride1(V, T, C) @@ -2874,7 +2874,7 @@ Computes `Q * C` (`trans = N`), `transpose(Q) * C` (`trans = T`), `adjoint(Q) * for `side = R` using `Q` from a `LQ` factorization of `A` computed using `gelqf!`. `C` is overwritten. """ -ormlq!(side::Char, trans::Char, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) +ormlq!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) """ ormqr!(side, trans, A, tau, C) @@ -2884,7 +2884,7 @@ Computes `Q * C` (`trans = N`), `transpose(Q) * C` (`trans = T`), `adjoint(Q) * for `side = R` using `Q` from a `QR` factorization of `A` computed using `geqrf!`. `C` is overwritten. """ -ormqr!(side::Char, trans::Char, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) +ormqr!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) """ ormql!(side, trans, A, tau, C) @@ -2894,7 +2894,7 @@ Computes `Q * C` (`trans = N`), `transpose(Q) * C` (`trans = T`), `adjoint(Q) * for `side = R` using `Q` from a `QL` factorization of `A` computed using `geqlf!`. `C` is overwritten. """ -ormql!(side::Char, trans::Char, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) +ormql!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) """ ormrq!(side, trans, A, tau, C) @@ -2904,7 +2904,7 @@ Computes `Q * C` (`trans = N`), `transpose(Q) * C` (`trans = T`), `adjoint(Q) * for `side = R` using `Q` from a `RQ` factorization of `A` computed using `gerqf!`. `C` is overwritten. """ -ormrq!(side::Char, trans::Char, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) +ormrq!(side::AbstractChar, trans::AbstractChar, A::AbstractMatrix, tau::AbstractVector, C::AbstractVecOrMat) """ gemqrt!(side, trans, V, T, C) @@ -2914,7 +2914,7 @@ Computes `Q * C` (`trans = N`), `transpose(Q) * C` (`trans = T`), `adjoint(Q) * for `side = R` using `Q` from a `QR` factorization of `A` computed using `geqrt!`. `C` is overwritten. """ -gemqrt!(side::Char, trans::Char, V::AbstractMatrix, T::AbstractMatrix, C::AbstractVecOrMat) +gemqrt!(side::AbstractChar, trans::AbstractChar, V::AbstractMatrix, T::AbstractMatrix, C::AbstractVecOrMat) # (PO) positive-definite symmetric matrices, for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in @@ -2929,7 +2929,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function posv!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function posv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A, B) n = checksquare(A) chkuplo(uplo) @@ -2952,7 +2952,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in # INTEGER INFO, LDA, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) - function potrf!(uplo::Char, A::AbstractMatrix{$elty}) + function potrf!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) checksquare(A) chkuplo(uplo) @@ -2977,7 +2977,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in # INTEGER INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) - function potri!(uplo::Char, A::AbstractMatrix{$elty}) + function potri!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) chkuplo(uplo) info = Ref{BlasInt}() @@ -2995,7 +2995,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in # INTEGER INFO, LDA, LDB, N, NRHS # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function potrs!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function potrs!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A, B) n = checksquare(A) chkuplo(uplo) @@ -3026,7 +3026,7 @@ for (posv, potrf, potri, potrs, pstrf, elty, rtyp) in # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), WORK( 2*N ) # INTEGER PIV( N ) - function pstrf!(uplo::Char, A::AbstractMatrix{$elty}, tol::Real) + function pstrf!(uplo::AbstractChar, A::AbstractMatrix{$elty}, tol::Real) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -3053,7 +3053,7 @@ of `A` is computed. If `uplo = L` the lower Cholesky decomposition of `A` is computed. `A` is overwritten by its Cholesky decomposition. `B` is overwritten with the solution `X`. """ -posv!(uplo::Char, A::AbstractMatrix, B::AbstractVecOrMat) +posv!(uplo::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) """ potrf!(uplo, A) @@ -3062,7 +3062,7 @@ Computes the Cholesky (upper if `uplo = U`, lower if `uplo = L`) decomposition of positive-definite matrix `A`. `A` is overwritten and returned with an info code. """ -potrf!(uplo::Char, A::AbstractMatrix) +potrf!(uplo::AbstractChar, A::AbstractMatrix) """ potri!(uplo, A) @@ -3073,7 +3073,7 @@ decomposition. `A` is overwritten by its inverse and returned. """ -potri!(uplo::Char, A::AbstractMatrix) +potri!(uplo::AbstractChar, A::AbstractMatrix) """ potrs!(uplo, A, B) @@ -3084,7 +3084,7 @@ positive definite matrix whose Cholesky decomposition was computed by computed. If `uplo = L` the lower Cholesky decomposition of `A` was computed. `B` is overwritten with the solution `X`. """ -potrs!(uplo::Char, A::AbstractMatrix, B::AbstractVecOrMat) +potrs!(uplo::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) """ pstrf!(uplo, A, tol) -> (A, piv, rank, info) @@ -3097,7 +3097,7 @@ Returns `A`, the pivots `piv`, the rank of `A`, and an `info` code. If `info = 0 the factorization succeeded. If `info = i > 0 `, then `A` is indefinite or rank-deficient. """ -pstrf!(uplo::Char, A::AbstractMatrix, tol::Real) +pstrf!(uplo::AbstractChar, A::AbstractMatrix, tol::Real) # (PT) positive-definite, symmetric, tri-diagonal matrices # Direct solvers for general tridiagonal and symmetric positive-definite tridiagonal @@ -3210,7 +3210,7 @@ for (pttrs, elty, relty) in # * .. Array Arguments .. # DOUBLE PRECISION D( * ) # COMPLEX*16 B( LDB, * ), E( * ) - function pttrs!(uplo::Char, D::AbstractVector{$relty}, E::AbstractVector{$elty}, B::AbstractVecOrMat{$elty}) + function pttrs!(uplo::AbstractChar, D::AbstractVector{$relty}, E::AbstractVector{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(B, D, E) chkuplo(uplo) n = length(D) @@ -3253,7 +3253,7 @@ for (trtri, trtrs, elty) in # INTEGER INFO, LDA, N # .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ) - function trtri!(uplo::Char, diag::Char, A::AbstractMatrix{$elty}) + function trtri!(uplo::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -3274,7 +3274,7 @@ for (trtri, trtrs, elty) in # INTEGER INFO, LDA, LDB, N, NRHS # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function trtrs!(uplo::Char, trans::Char, diag::Char, + function trtrs!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chktrans(trans) chkdiag(diag) @@ -3304,7 +3304,7 @@ triangular matrix `A`. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `A` is overwritten with its inverse. """ -trtri!(uplo::Char, diag::Char, A::AbstractMatrix) +trtri!(uplo::AbstractChar, diag::AbstractChar, A::AbstractMatrix) """ trtrs!(uplo, trans, diag, A, B) @@ -3315,7 +3315,7 @@ triangular matrix `A`. If `diag = N`, `A` has non-unit diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `B` is overwritten with the solution `X`. """ -trtrs!(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix, B::AbstractVecOrMat) +trtrs!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) #Eigenvector computation and condition number estimation for (trcon, trevc, trrfs, elty) in @@ -3331,7 +3331,7 @@ for (trcon, trevc, trrfs, elty) in # .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function trcon!(norm::Char, uplo::Char, diag::Char, A::AbstractMatrix{$elty}) + function trcon!(norm::AbstractChar, uplo::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) chkdiag(diag) n = checksquare(A) @@ -3360,7 +3360,7 @@ for (trcon, trevc, trrfs, elty) in # LOGICAL SELECT( * ) # DOUBLE PRECISION T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ), #$ WORK( * ) - function trevc!(side::Char, howmny::Char, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, + function trevc!(side::AbstractChar, howmny::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, VL::AbstractMatrix{$elty} = similar(T), VR::AbstractMatrix{$elty} = similar(T)) # Extract @@ -3418,7 +3418,7 @@ for (trcon, trevc, trrfs, elty) in # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), BERR( * ), FERR( * ), #$ WORK( * ), X( LDX, * ) - function trrfs!(uplo::Char, trans::Char, diag::Char, + function trrfs!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}, X::AbstractVecOrMat{$elty}, Ferr::AbstractVector{$elty} = similar(B, $elty, size(B,2)), Berr::AbstractVector{$elty} = similar(B, $elty, size(B,2))) @@ -3460,7 +3460,7 @@ for (trcon, trevc, trrfs, elty, relty) in # .. Array Arguments .. # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function trcon!(norm::Char, uplo::Char, diag::Char, A::AbstractMatrix{$elty}) + function trcon!(norm::AbstractChar, uplo::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -3490,7 +3490,7 @@ for (trcon, trevc, trrfs, elty, relty) in # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ), #$ WORK( * ) - function trevc!(side::Char, howmny::Char, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, + function trevc!(side::AbstractChar, howmny::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, VL::AbstractMatrix{$elty} = similar(T), VR::AbstractMatrix{$elty} = similar(T)) # Extract @@ -3548,7 +3548,7 @@ for (trcon, trevc, trrfs, elty, relty) in # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), BERR( * ), FERR( * ), #$ WORK( * ), X( LDX, * ) - function trrfs!(uplo::Char, trans::Char, diag::Char, + function trrfs!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}, X::AbstractVecOrMat{$elty}, Ferr::AbstractVector{$relty} = similar(B, $relty, size(B,2)), Berr::AbstractVector{$relty} = similar(B, $relty, size(B,2))) @@ -3586,7 +3586,7 @@ diagonal elements. If `diag = U`, all diagonal elements of `A` are one. If `norm = I`, the condition number is found in the infinity norm. If `norm = O` or `1`, the condition number is found in the one norm. """ -trcon!(norm::Char, uplo::Char, diag::Char, A::AbstractMatrix) +trcon!(norm::AbstractChar, uplo::AbstractChar, diag::AbstractChar, A::AbstractMatrix) """ trevc!(side, howmny, select, T, VL = similar(T), VR = similar(T)) @@ -3599,7 +3599,7 @@ eigenvectors are found and backtransformed using `VL` and `VR`. If `howmny = S`, only the eigenvectors corresponding to the values in `select` are computed. """ -trevc!(side::Char, howmny::Char, select::AbstractVector{BlasInt}, T::AbstractMatrix, +trevc!(side::AbstractChar, howmny::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix, VL::AbstractMatrix = similar(T), VR::AbstractMatrix = similar(T)) """ @@ -3614,7 +3614,7 @@ diagonal elements. If `diag = U`, all diagonal elements of `A` are one. `Ferr` and `Berr` are optional inputs. `Ferr` is the forward error and `Berr` is the backward error, each component-wise. """ -trrfs!(uplo::Char, trans::Char, diag::Char, A::AbstractMatrix, B::AbstractVecOrMat, +trrfs!(uplo::AbstractChar, trans::AbstractChar, diag::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat, X::AbstractVecOrMat, Ferr::AbstractVector, Berr::AbstractVector) ## (ST) Symmetric tridiagonal - eigendecomposition @@ -3625,7 +3625,7 @@ for (stev, stebz, stegr, stein, elty) in # , (:cstev_,:ComplexF32) ) @eval begin - function stev!(job::Char, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}) + function stev!(job::AbstractChar, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 @@ -3646,7 +3646,7 @@ for (stev, stebz, stegr, stein, elty) in #* matrix T. The user may ask for all eigenvalues, all eigenvalues #* in the half-open interval (VL, VU], or the IL-th through IU-th #* eigenvalues. - function stebz!(range::Char, order::Char, vl::$elty, vu::$elty, il::Integer, iu::Integer, abstol::Real, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}) + function stebz!(range::AbstractChar, order::AbstractChar, vl::$elty, vu::$elty, il::Integer, iu::Integer, abstol::Real, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 @@ -3676,7 +3676,7 @@ for (stev, stebz, stegr, stein, elty) in w[1:m[]], iblock[1:m[]], isplit[1:nsplit[1]] end - function stegr!(jobz::Char, range::Char, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}, vl::Real, vu::Real, il::Integer, iu::Integer) + function stegr!(jobz::AbstractChar, range::AbstractChar, dv::AbstractVector{$elty}, ev::AbstractVector{$elty}, vl::Real, vu::Real, il::Integer, iu::Integer) chkstride1(dv, ev) n = length(dv) if length(ev) != n - 1 @@ -3767,7 +3767,7 @@ for (stev, stebz, stegr, stein, elty) in end end end -stegr!(jobz::Char, dv::AbstractVector, ev::AbstractVector) = stegr!(jobz, 'A', dv, ev, 0.0, 0.0, 0, 0) +stegr!(jobz::AbstractChar, dv::AbstractVector, ev::AbstractVector) = stegr!(jobz, 'A', dv, ev, 0.0, 0.0, 0, 0) # Allow user to skip specification of iblock and isplit stein!(dv::AbstractVector, ev::AbstractVector, w_in::AbstractVector) = stein!(dv, ev, w_in, zeros(BlasInt,0), zeros(BlasInt,0)) @@ -3782,7 +3782,7 @@ diagonal and `ev` as off-diagonal. If `job = N` only the eigenvalues are found and returned in `dv`. If `job = V` then the eigenvectors are also found and returned in `Zmat`. """ -stev!(job::Char, dv::AbstractVector, ev::AbstractVector) +stev!(job::AbstractChar, dv::AbstractVector, ev::AbstractVector) """ stebz!(range, order, vl, vu, il, iu, abstol, dv, ev) -> (dv, iblock, isplit) @@ -3795,7 +3795,7 @@ are found. If `range = V`, the eigenvalues in the half-open interval block. If `order = E`, they are ordered across all the blocks. `abstol` can be set as a tolerance for convergence. """ -stebz!(range::Char, order::Char, vl, vu, il::Integer, iu::Integer, abstol::Real, dv::AbstractVector, ev::AbstractVector) +stebz!(range::AbstractChar, order::AbstractChar, vl, vu, il::Integer, iu::Integer, abstol::Real, dv::AbstractVector, ev::AbstractVector) """ stegr!(jobz, range, dv, ev, vl, vu, il, iu) -> (w, Z) @@ -3808,7 +3808,7 @@ are found. If `range = V`, the eigenvalues in the half-open interval `il` and `iu` are found. The eigenvalues are returned in `w` and the eigenvectors in `Z`. """ -stegr!(jobz::Char, range::Char, dv::AbstractVector, ev::AbstractVector, vl::Real, vu::Real, il::Integer, iu::Integer) +stegr!(jobz::AbstractChar, range::AbstractChar, dv::AbstractVector, ev::AbstractVector, vl::Real, vu::Real, il::Integer, iu::Integer) """ stein!(dv, ev_in, w_in, iblock_in, isplit_in) @@ -3834,7 +3834,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function syconv!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function syconv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -3856,7 +3856,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), WORK( * ) - function sysv!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function sysv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -3890,7 +3890,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function sytrf!(uplo::Char, A::AbstractMatrix{$elty}) + function sytrf!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -3922,7 +3922,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) -# function sytri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) +# function sytri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) @@ -3951,7 +3951,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function sytri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function sytri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -3974,7 +3974,7 @@ for (syconv, sysv, sytrf, sytri, sytrs, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function sytrs!(uplo::Char, A::AbstractMatrix{$elty}, + function sytrs!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4006,7 +4006,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), WORK( * ) - function sysv_rook!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function sysv_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -4040,7 +4040,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function sytrf_rook!(uplo::Char, A::AbstractMatrix{$elty}) + function sytrf_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -4072,7 +4072,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function sytri_rook!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function sytri_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -4095,7 +4095,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ) - function sytrs_rook!(uplo::Char, A::AbstractMatrix{$elty}, + function sytrs_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4121,7 +4121,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty) in # .. Array Arguments .. # INTEGER IPIV( * ) # DOUBLE PRECISION A( LDA, * ), E( * ) - function syconvf_rook!(uplo::Char, way::Char, + function syconvf_rook!(uplo::AbstractChar, way::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, e::AbstractVector{$elty} = Vector{$elty}(uninitialized, length(ipiv))) # extract @@ -4170,7 +4170,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function syconv!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function syconv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A,ipiv) n = checksquare(A) chkuplo(uplo) @@ -4192,7 +4192,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) - function hesv!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function hesv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -4226,7 +4226,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function hetrf!(uplo::Char, A::AbstractMatrix{$elty}) + function hetrf!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -4256,7 +4256,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) -# function hetri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) +# function hetri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) @@ -4286,7 +4286,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function hetri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function hetri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -4308,7 +4308,7 @@ for (syconv, hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) - function hetrs!(uplo::Char, A::AbstractMatrix{$elty}, + function hetrs!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4338,7 +4338,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) - function hesv_rook!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function hesv_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -4372,7 +4372,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function hetrf_rook!(uplo::Char, A::AbstractMatrix{$elty}) + function hetrf_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -4402,7 +4402,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function hetri_rook!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function hetri_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A,ipiv) n = checksquare(A) chkuplo(uplo) @@ -4424,7 +4424,7 @@ for (hesv, hetrf, hetri, hetrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) - function hetrs_rook!(uplo::Char, A::AbstractMatrix{$elty}, + function hetrs_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4455,7 +4455,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) - function sysv!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function sysv!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -4490,7 +4490,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function sytrf!(uplo::Char, A::AbstractMatrix{$elty}) + function sytrf!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -4523,7 +4523,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) -# function sytri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) +# function sytri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::Vector{BlasInt}) # chkstride1(A) # n = checksquare(A) # chkuplo(uplo) @@ -4552,7 +4552,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function sytri!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function sytri!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -4574,7 +4574,7 @@ for (sysv, sytrf, sytri, sytrs, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) - function sytrs!(uplo::Char, A::AbstractMatrix{$elty}, + function sytrs!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4606,7 +4606,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) - function sysv_rook!(uplo::Char, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) + function sysv_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractVecOrMat{$elty}) chkstride1(A,B) n = checksquare(A) chkuplo(uplo) @@ -4641,7 +4641,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function sytrf_rook!(uplo::Char, A::AbstractMatrix{$elty}) + function sytrf_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) chkuplo(uplo) @@ -4674,7 +4674,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function sytri_rook!(uplo::Char, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) + function sytri_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}) chkstride1(A, ipiv) n = checksquare(A) chkuplo(uplo) @@ -4696,7 +4696,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # * .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ) - function sytrs_rook!(uplo::Char, A::AbstractMatrix{$elty}, + function sytrs_rook!(uplo::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat{$elty}) chkstride1(A,B,ipiv) n = checksquare(A) @@ -4722,7 +4722,7 @@ for (sysv, sytrf, sytri, sytrs, syconvf, elty, relty) in # .. Array Arguments .. # INTEGER IPIV( * ) # COMPLEX*16 A( LDA, * ), E( * ) - function syconvf_rook!(uplo::Char, way::Char, + function syconvf_rook!(uplo::AbstractChar, way::AbstractChar, A::AbstractMatrix{$elty}, ipiv::AbstractVector{BlasInt}, e::AbstractVector{$elty} = Vector{$elty}(uninitialized, length(ipiv))) chkstride1(A, ipiv, e) @@ -4767,7 +4767,7 @@ is upper triangular. If `uplo = L`, it is lower triangular. `ipiv` is the pivot vector from the triangular factorization. `A` is overwritten by `L` and `D`. """ -syconv!(uplo::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) +syconv!(uplo::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) """ sysv!(uplo, A, B) -> (B, A, ipiv) @@ -4778,7 +4778,7 @@ the upper half of `A` is stored. If `uplo = L`, the lower half is stored. Bunch-Kaufman factorization. `ipiv` contains pivoting information about the factorization. """ -sysv!(uplo::Char, A::AbstractMatrix, B::AbstractVecOrMat) +sysv!(uplo::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) """ sytrf!(uplo, A) -> (A, ipiv, info) @@ -4792,7 +4792,7 @@ the error code `info` which is a non-negative integer. If `info` is positive the matrix is singular and the diagonal part of the factorization is exactly zero at position `info`. """ -sytrf!(uplo::Char, A::AbstractMatrix) +sytrf!(uplo::AbstractChar, A::AbstractMatrix) """ sytri!(uplo, A, ipiv) @@ -4801,7 +4801,7 @@ Computes the inverse of a symmetric matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `A` is overwritten by its inverse. """ -sytri!(uplo::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) +sytri!(uplo::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) """ sytrs!(uplo, A, ipiv, B) @@ -4811,7 +4811,7 @@ results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. """ -sytrs!(uplo::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) +sytrs!(uplo::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) """ @@ -4823,7 +4823,7 @@ the upper half of `A` is stored. If `uplo = L`, the lower half is stored. Bunch-Kaufman factorization. `ipiv` contains pivoting information about the factorization. """ -hesv!(uplo::Char, A::AbstractMatrix, B::AbstractVecOrMat) +hesv!(uplo::AbstractChar, A::AbstractMatrix, B::AbstractVecOrMat) """ hetrf!(uplo, A) -> (A, ipiv, info) @@ -4837,7 +4837,7 @@ the error code `info` which is a non-negative integer. If `info` is positive the matrix is singular and the diagonal part of the factorization is exactly zero at position `info`. """ -hetrf!(uplo::Char, A::AbstractMatrix) +hetrf!(uplo::AbstractChar, A::AbstractMatrix) """ hetri!(uplo, A, ipiv) @@ -4846,7 +4846,7 @@ Computes the inverse of a Hermitian matrix `A` using the results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `A` is overwritten by its inverse. """ -hetri!(uplo::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) +hetri!(uplo::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}) """ hetrs!(uplo, A, ipiv, B) @@ -4856,7 +4856,7 @@ results of `sytrf!`. If `uplo = U`, the upper half of `A` is stored. If `uplo = L`, the lower half is stored. `B` is overwritten by the solution `X`. """ -hetrs!(uplo::Char, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) +hetrs!(uplo::AbstractChar, A::AbstractMatrix, ipiv::AbstractVector{BlasInt}, B::AbstractVecOrMat) # Symmetric (real) eigensolvers for (syev, syevr, sygvd, elty) in @@ -4869,7 +4869,7 @@ for (syev, syevr, sygvd, elty) in # INTEGER INFO, LDA, LWORK, N # * .. Array Arguments .. # DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ) - function syev!(jobz::Char, uplo::Char, A::AbstractMatrix{$elty}) + function syev!(jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) W = similar(A, $elty, n) @@ -4901,7 +4901,7 @@ for (syev, syevr, sygvd, elty) in # * .. Array Arguments .. # INTEGER ISUPPZ( * ), IWORK( * ) # DOUBLE PRECISION A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * ) - function syevr!(jobz::Char, range::Char, uplo::Char, A::AbstractMatrix{$elty}, + function syevr!(jobz::AbstractChar, range::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) chkstride1(A) n = checksquare(A) @@ -4950,7 +4950,7 @@ for (syev, syevr, sygvd, elty) in end w[1:m[]], Z[:,1:(jobz == 'V' ? m[] : 0)] end - syevr!(jobz::Char, A::AbstractMatrix{$elty}) = + syevr!(jobz::AbstractChar, A::AbstractMatrix{$elty}) = syevr!(jobz, 'A', 'U', A, 0.0, 0.0, 0, 0, -1.0) # Generalized eigenproblem @@ -4963,7 +4963,7 @@ for (syev, syevr, sygvd, elty) in # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), B( LDB, * ), W( * ), WORK( * ) - function sygvd!(itype::Integer, jobz::Char, uplo::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function sygvd!(itype::Integer, jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m @@ -5013,7 +5013,7 @@ for (syev, syevr, sygvd, elty, relty) in # * .. Array Arguments .. # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function syev!(jobz::Char, uplo::Char, A::AbstractMatrix{$elty}) + function syev!(jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) W = similar(A, $relty, n) @@ -5048,7 +5048,7 @@ for (syev, syevr, sygvd, elty, relty) in # INTEGER ISUPPZ( * ), IWORK( * ) # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), WORK( * ), Z( LDZ, * ) - function syevr!(jobz::Char, range::Char, uplo::Char, A::AbstractMatrix{$elty}, + function syevr!(jobz::AbstractChar, range::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) chkstride1(A) n = checksquare(A) @@ -5102,7 +5102,7 @@ for (syev, syevr, sygvd, elty, relty) in end w[1:m[]], Z[:,1:(jobz == 'V' ? m[] : 0)] end - syevr!(jobz::Char, A::AbstractMatrix{$elty}) = + syevr!(jobz::AbstractChar, A::AbstractMatrix{$elty}) = syevr!(jobz, 'A', 'U', A, 0.0, 0.0, 0, 0, -1.0) # SUBROUTINE ZHEGVD( ITYPE, JOBZ, UPLO, N, A, LDA, B, LDB, W, WORK, @@ -5115,7 +5115,7 @@ for (syev, syevr, sygvd, elty, relty) in # INTEGER IWORK( * ) # DOUBLE PRECISION RWORK( * ), W( * ) # COMPLEX*16 A( LDA, * ), B( LDB, * ), WORK( * ) - function sygvd!(itype::Integer, jobz::Char, uplo::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function sygvd!(itype::Integer, jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m @@ -5164,7 +5164,7 @@ Finds the eigenvalues (`jobz = N`) or eigenvalues and eigenvectors (`jobz = V`) of a symmetric matrix `A`. If `uplo = U`, the upper triangle of `A` is used. If `uplo = L`, the lower triangle of `A` is used. """ -syev!(jobz::Char, uplo::Char, A::AbstractMatrix) +syev!(jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix) """ syevr!(jobz, range, uplo, A, vl, vu, il, iu, abstol) -> (W, Z) @@ -5179,7 +5179,7 @@ found. `abstol` can be set as a tolerance for convergence. The eigenvalues are returned in `W` and the eigenvectors in `Z`. """ -syevr!(jobz::Char, range::Char, uplo::Char, A::AbstractMatrix, +syevr!(jobz::AbstractChar, range::AbstractChar, uplo::AbstractChar, A::AbstractMatrix, vl::AbstractFloat, vu::AbstractFloat, il::Integer, iu::Integer, abstol::AbstractFloat) """ @@ -5194,7 +5194,7 @@ of `A` and `B` are used. If `uplo = L`, the lower triangles of `A` and `A * B * x = lambda * x`. If `itype = 3`, the problem to solve is `B * A * x = lambda * x`. """ -sygvd!(itype::Integer, jobz::Char, uplo::Char, A::AbstractMatrix, B::AbstractMatrix) +sygvd!(itype::Integer, jobz::AbstractChar, uplo::AbstractChar, A::AbstractMatrix, B::AbstractMatrix) ## (BD) Bidiagonal matrices - singular value decomposition for (bdsqr, relty, elty) in @@ -5203,7 +5203,7 @@ for (bdsqr, relty, elty) in (:zbdsqr_,:Float64,:ComplexF64), (:cbdsqr_,:Float32,:ComplexF32)) @eval begin - function bdsqr!(uplo::Char, d::AbstractVector{$relty}, e_::AbstractVector{$relty}, + function bdsqr!(uplo::AbstractChar, d::AbstractVector{$relty}, e_::AbstractVector{$relty}, Vt::AbstractMatrix{$elty}, U::AbstractMatrix{$elty}, C::AbstractMatrix{$elty}) chkstride1(d, e_, Vt, U, C) # Extract number @@ -5255,7 +5255,7 @@ compute the product `Q' * C`. Returns the singular values in `d`, and the matrix `C` overwritten with `Q' * C`. """ -bdsqr!(uplo::Char, d::AbstractVector, e_::AbstractVector, Vt::AbstractMatrix, U::AbstractMatrix, C::AbstractMatrix) +bdsqr!(uplo::AbstractChar, d::AbstractVector, e_::AbstractVector, Vt::AbstractMatrix, U::AbstractMatrix, C::AbstractMatrix) #Defined only for real types for (bdsdc, elty) in @@ -5273,7 +5273,7 @@ for (bdsdc, elty) in # INTEGER IQ( * ), IWORK( * ) # DOUBLE PRECISION D( * ), E( * ), Q( * ), U( LDU, * ), # $ VT( LDVT, * ), WORK( * ) - function bdsdc!(uplo::Char, compq::Char, d::AbstractVector{$elty}, e_::AbstractVector{$elty}) + function bdsdc!(uplo::AbstractChar, compq::AbstractChar, d::AbstractVector{$elty}, e_::AbstractVector{$elty}) chkstride1(d, e_) n, ldiq, ldq, ldu, ldvt = length(d), 1, 1, 1, 1 chkuplo(uplo) @@ -5326,7 +5326,7 @@ and vectors are found in compact form. Only works for real types. Returns the singular values in `d`, and if `compq = P`, the compact singular vectors in `iq`. """ -bdsdc!(uplo::Char, compq::Char, d::AbstractVector, e_::AbstractVector) +bdsdc!(uplo::AbstractChar, compq::AbstractChar, d::AbstractVector, e_::AbstractVector) for (gecon, elty) in ((:dgecon_,:Float64), @@ -5342,7 +5342,7 @@ for (gecon, elty) in # * .. Array Arguments .. # INTEGER IWORK( * ) # DOUBLE PRECISION A( LDA, * ), WORK( * ) - function gecon!(normtype::Char, A::AbstractMatrix{$elty}, anorm::$elty) + function gecon!(normtype::AbstractChar, A::AbstractMatrix{$elty}, anorm::$elty) chkstride1(A) n = checksquare(A) lda = max(1, stride(A, 2)) @@ -5376,7 +5376,7 @@ for (gecon, elty, relty) in # * .. Array Arguments .. # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), WORK( * ) - function gecon!(normtype::Char, A::AbstractMatrix{$elty}, anorm::$relty) + function gecon!(normtype::AbstractChar, A::AbstractMatrix{$elty}, anorm::$relty) chkstride1(A) n = checksquare(A) lda = max(1, stride(A, 2)) @@ -5404,7 +5404,7 @@ the condition number is found in the infinity norm. If `normtype = O` or `1`, the condition number is found in the one norm. `A` must be the result of `getrf!` and `anorm` is the norm of `A` in the relevant norm. """ -gecon!(normtype::Char, A::AbstractMatrix, anorm) +gecon!(normtype::AbstractChar, A::AbstractMatrix, anorm) for (gehrd, elty) in ((:dgehrd_,:Float64), @@ -5515,7 +5515,7 @@ for (ormhr, elty) in # .. # .. Array Arguments .. # DOUBLE PRECISION a( lda, * ), c( ldc, * ), tau( * ), work( * ) - function ormhr!(side::Char, trans::Char, ilo::Integer, ihi::Integer, A::AbstractMatrix{$elty}, + function ormhr!(side::AbstractChar, trans::AbstractChar, ilo::Integer, ihi::Integer, A::AbstractMatrix{$elty}, tau::AbstractVector{$elty}, C::AbstractVecOrMat{$elty}) chkstride1(A, tau, C) @@ -5565,7 +5565,7 @@ for (gees, gges, elty) in # LOGICAL BWORK( * ) # DOUBLE PRECISION A( LDA, * ), VS( LDVS, * ), WI( * ), WORK( * ), # $ WR( * ) - function gees!(jobvs::Char, A::AbstractMatrix{$elty}) + function gees!(jobvs::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) sdim = Vector{BlasInt}(uninitialized, 1) @@ -5604,7 +5604,7 @@ for (gees, gges, elty) in # DOUBLE PRECISION A( LDA, * ), ALPHAI( * ), ALPHAR( * ), # $ B( LDB, * ), BETA( * ), VSL( LDVSL, * ), # $ VSR( LDVSR, * ), WORK( * ) - function gges!(jobvsl::Char, jobvsr::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function gges!(jobvsl::AbstractChar, jobvsr::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m @@ -5658,7 +5658,7 @@ for (gees, gges, elty, relty) in # LOGICAL BWORK( * ) # DOUBLE PRECISION RWORK( * ) # COMPLEX*16 A( LDA, * ), VS( LDVS, * ), W( * ), WORK( * ) - function gees!(jobvs::Char, A::AbstractMatrix{$elty}) + function gees!(jobvs::AbstractChar, A::AbstractMatrix{$elty}) chkstride1(A) n = checksquare(A) sort = 'N' @@ -5699,7 +5699,7 @@ for (gees, gges, elty, relty) in # COMPLEX*16 A( LDA, * ), ALPHA( * ), B( LDB, * ), # $ BETA( * ), VSL( LDVSL, * ), VSR( LDVSR, * ), # $ WORK( * ) - function gges!(jobvsl::Char, jobvsr::Char, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) + function gges!(jobvsl::AbstractChar, jobvsr::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}) chkstride1(A, B) n, m = checksquare(A, B) if n != m @@ -5750,7 +5750,7 @@ vectors (`jobvs = V`) of matrix `A`. `A` is overwritten by its Schur form. Returns `A`, `vs` containing the Schur vectors, and `w`, containing the eigenvalues. """ -gees!(jobvs::Char, A::AbstractMatrix) +gees!(jobvs::AbstractChar, A::AbstractMatrix) """ @@ -5763,7 +5763,7 @@ vectors (`jobsvl = V`), or right Schur vectors (`jobvsr = V`) of `A` and The generalized eigenvalues are returned in `alpha` and `beta`. The left Schur vectors are returned in `vsl` and the right Schur vectors are returned in `vsr`. """ -gges!(jobvsl::Char, jobvsr::Char, A::AbstractMatrix, B::AbstractMatrix) +gges!(jobvsl::AbstractChar, jobvsr::AbstractChar, A::AbstractMatrix, B::AbstractMatrix) for (trexc, trsen, tgsen, elty) in ((:dtrexc_, :dtrsen_, :dtgsen_, :Float64), @@ -5775,7 +5775,7 @@ for (trexc, trsen, tgsen, elty) in # * .. # * .. Array Arguments .. # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WORK( * ) - function trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) + function trexc!(compq::AbstractChar, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) chkstride1(T, Q) n = checksquare(T) ldt = max(1, stride(T, 2)) @@ -5806,7 +5806,7 @@ for (trexc, trsen, tgsen, elty) in # LOGICAL SELECT( * ) # INTEGER IWORK( * ) # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WI( * ), WORK( * ), WR( * ) - function trsen!(job::Char, compq::Char, select::AbstractVector{BlasInt}, + function trsen!(job::AbstractChar, compq::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) chkstride1(T, Q, select) n = checksquare(T) @@ -5927,7 +5927,7 @@ for (trexc, trsen, tgsen, elty, relty) in # .. # .. Array Arguments .. # DOUBLE PRECISION Q( LDQ, * ), T( LDT, * ), WORK( * ) - function trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) + function trexc!(compq::AbstractChar, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) chkstride1(T, Q) n = checksquare(T) ldt = max(1, stride(T, 2)) @@ -5956,7 +5956,7 @@ for (trexc, trsen, tgsen, elty, relty) in # .. Array Arguments .. # LOGICAL SELECT( * ) # COMPLEX Q( LDQ, * ), T( LDT, * ), W( * ), WORK( * ) - function trsen!(job::Char, compq::Char, select::AbstractVector{BlasInt}, + function trsen!(job::AbstractChar, compq::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix{$elty}, Q::AbstractMatrix{$elty}) chkstride1(select, T, Q) n = checksquare(T) @@ -6068,7 +6068,7 @@ Reorder the Schur factorization of a matrix. If `compq = V`, the Schur vectors `Q` are reordered. If `compq = N` they are not modified. `ifst` and `ilst` specify the reordering of the vectors. """ -trexc!(compq::Char, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix, Q::AbstractMatrix) +trexc!(compq::AbstractChar, ifst::BlasInt, ilst::BlasInt, T::AbstractMatrix, Q::AbstractMatrix) """ trsen!(compq, job, select, T, Q) -> (T, Q, w, s, sep) @@ -6086,7 +6086,7 @@ Returns `T`, `Q`, reordered eigenvalues in `w`, the condition number of the cluster of eigenvalues `s`, and the condition number of the invariant subspace `sep`. """ -trsen!(compq::Char, job::Char, select::AbstractVector{BlasInt}, T::AbstractMatrix, Q::AbstractMatrix) +trsen!(compq::AbstractChar, job::AbstractChar, select::AbstractVector{BlasInt}, T::AbstractMatrix, Q::AbstractMatrix) """ tgsen!(select, S, T, Q, Z) -> (S, T, alpha, beta, Q, Z) @@ -6101,7 +6101,7 @@ for (fn, elty, relty) in ((:dtrsyl_, :Float64, :Float64), (:ztrsyl_, :ComplexF64, :Float64), (:ctrsyl_, :ComplexF32, :Float32)) @eval begin - function trsyl!(transa::Char, transb::Char, A::AbstractMatrix{$elty}, + function trsyl!(transa::AbstractChar, transb::AbstractChar, A::AbstractMatrix{$elty}, B::AbstractMatrix{$elty}, C::AbstractMatrix{$elty}, isgn::Int=1) chkstride1(A, B, C) m, n = checksquare(A, B) @@ -6139,6 +6139,6 @@ transposed. Similarly for `transb` and `B`. If `isgn = 1`, the equation Returns `X` (overwriting `C`) and `scale`. """ -trsyl!(transa::Char, transb::Char, A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, isgn::Int=1) +trsyl!(transa::AbstractChar, transb::AbstractChar, A::AbstractMatrix, B::AbstractMatrix, C::AbstractMatrix, isgn::Int=1) end # module diff --git a/stdlib/LinearAlgebra/src/matmul.jl b/stdlib/LinearAlgebra/src/matmul.jl index af88d00a051ae..6b25d94dbfa53 100644 --- a/stdlib/LinearAlgebra/src/matmul.jl +++ b/stdlib/LinearAlgebra/src/matmul.jl @@ -259,7 +259,7 @@ mul!(C::AbstractMatrix, adjA::Adjoint{<:Any,<:AbstractVecOrMat}, transB::Transpo (A = adjA.parent; B = transB.parent; generic_matmatmul!(C, 'C', 'T', A, B)) # Supporting functions for matrix multiplication -function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) +function copytri!(A::AbstractMatrix, uplo::AbstractChar, conjugate::Bool=false) n = checksquare(A) if uplo == 'U' for i = 1:(n-1), j = (i+1):n @@ -275,7 +275,7 @@ function copytri!(A::AbstractMatrix, uplo::Char, conjugate::Bool=false) A end -function gemv!(y::StridedVector{T}, tA::Char, A::StridedVecOrMat{T}, x::StridedVector{T}) where T<:BlasFloat +function gemv!(y::StridedVector{T}, tA::AbstractChar, A::StridedVecOrMat{T}, x::StridedVector{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) if nA != length(x) throw(DimensionMismatch("second dimension of A, $nA, does not match length of x, $(length(x))")) @@ -293,7 +293,7 @@ function gemv!(y::StridedVector{T}, tA::Char, A::StridedVecOrMat{T}, x::StridedV return generic_matvecmul!(y, tA, A, x) end -function syrk_wrapper!(C::StridedMatrix{T}, tA::Char, A::StridedVecOrMat{T}) where T<:BlasFloat +function syrk_wrapper!(C::StridedMatrix{T}, tA::AbstractChar, A::StridedVecOrMat{T}) where T<:BlasFloat nC = checksquare(C) if tA == 'T' (nA, mA) = size(A,1), size(A,2) @@ -321,7 +321,7 @@ function syrk_wrapper!(C::StridedMatrix{T}, tA::Char, A::StridedVecOrMat{T}) whe return generic_matmatmul!(C, tA, tAt, A, A) end -function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA::Char, A::Union{StridedVecOrMat{T}, StridedVecOrMat{Complex{T}}}) where T<:BlasReal +function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA::AbstractChar, A::Union{StridedVecOrMat{T}, StridedVecOrMat{Complex{T}}}) where T<:BlasReal nC = checksquare(C) if tA == 'C' (nA, mA) = size(A,1), size(A,2) @@ -352,7 +352,7 @@ function herk_wrapper!(C::Union{StridedMatrix{T}, StridedMatrix{Complex{T}}}, tA return generic_matmatmul!(C,tA, tAt, A, A) end -function gemm_wrapper(tA::Char, tB::Char, +function gemm_wrapper(tA::AbstractChar, tB::AbstractChar, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) @@ -361,7 +361,7 @@ function gemm_wrapper(tA::Char, tB::Char, gemm_wrapper!(C, tA, tB, A, B) end -function gemm_wrapper!(C::StridedVecOrMat{T}, tA::Char, tB::Char, +function gemm_wrapper!(C::StridedVecOrMat{T}, tA::AbstractChar, tB::AbstractChar, A::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where T<:BlasFloat mA, nA = lapack_size(tA, A) @@ -398,9 +398,9 @@ end # blas.jl defines matmul for floats; other integer and mixed precision # cases are handled here -lapack_size(t::Char, M::AbstractVecOrMat) = (size(M, t=='N' ? 1 : 2), size(M, t=='N' ? 2 : 1)) +lapack_size(t::AbstractChar, M::AbstractVecOrMat) = (size(M, t=='N' ? 1 : 2), size(M, t=='N' ? 2 : 1)) -function copyto!(B::AbstractVecOrMat, ir_dest::UnitRange{Int}, jr_dest::UnitRange{Int}, tM::Char, M::AbstractVecOrMat, ir_src::UnitRange{Int}, jr_src::UnitRange{Int}) +function copyto!(B::AbstractVecOrMat, ir_dest::UnitRange{Int}, jr_dest::UnitRange{Int}, tM::AbstractChar, M::AbstractVecOrMat, ir_src::UnitRange{Int}, jr_src::UnitRange{Int}) if tM == 'N' copyto!(B, ir_dest, jr_dest, M, ir_src, jr_src) else @@ -410,7 +410,7 @@ function copyto!(B::AbstractVecOrMat, ir_dest::UnitRange{Int}, jr_dest::UnitRang B end -function copy_transpose!(B::AbstractMatrix, ir_dest::UnitRange{Int}, jr_dest::UnitRange{Int}, tM::Char, M::AbstractVecOrMat, ir_src::UnitRange{Int}, jr_src::UnitRange{Int}) +function copy_transpose!(B::AbstractMatrix, ir_dest::UnitRange{Int}, jr_dest::UnitRange{Int}, tM::AbstractChar, M::AbstractVecOrMat, ir_src::UnitRange{Int}, jr_src::UnitRange{Int}) if tM == 'N' LinearAlgebra.copy_transpose!(B, ir_dest, jr_dest, M, ir_src, jr_src) else diff --git a/stdlib/Markdown/src/parse/util.jl b/stdlib/Markdown/src/parse/util.jl index 26aa1e6f5932f..3e178aa3ea3e3 100644 --- a/stdlib/Markdown/src/parse/util.jl +++ b/stdlib/Markdown/src/parse/util.jl @@ -82,7 +82,7 @@ function startswith(stream::IO, s::AbstractString; eat = true, padding = false, return result end -function startswith(stream::IO, c::Char; eat = true) +function startswith(stream::IO, c::AbstractChar; eat = true) if !eof(stream) && peek(stream) == UInt8(c) eat && read(stream, Char) return true diff --git a/stdlib/Pkg3/ext/TOML/src/parser.jl b/stdlib/Pkg3/ext/TOML/src/parser.jl index 4d8539e4e1b5f..37a01ab7dee3c 100644 --- a/stdlib/Pkg3/ext/TOML/src/parser.jl +++ b/stdlib/Pkg3/ext/TOML/src/parser.jl @@ -100,7 +100,7 @@ function peek(p::Parser) #, i::Int=0 end "Returns `true` and consumes the next character if it matches `ch`, otherwise do nothing and return `false`" -function consume(p::Parser, ch::Char) +function consume(p::Parser, ch::AbstractChar) eof(p) && return false c = peek(p) if get(c) == ch @@ -111,7 +111,7 @@ function consume(p::Parser, ch::Char) end end -function expect(p::Parser, ch::Char) +function expect(p::Parser, ch::AbstractChar) consume(p, ch) && return true lo = position(p) if eof(p) diff --git a/stdlib/Pkg3/ext/TOML/src/print.jl b/stdlib/Pkg3/ext/TOML/src/print.jl index ff30f5c0efc84..7ac2f0afdae69 100644 --- a/stdlib/Pkg3/ext/TOML/src/print.jl +++ b/stdlib/Pkg3/ext/TOML/src/print.jl @@ -1,5 +1,5 @@ "Identify if character in subset of bare key symbols" -isbare(c::Char) = 'A' <= c <= 'Z' || 'a' <= c <= 'z' || isdigit(c) || c == '-' || c == '_' +isbare(c::AbstractChar) = 'A' <= c <= 'Z' || 'a' <= c <= 'z' || isdigit(c) || c == '-' || c == '_' function printkey(io::IO, keys::Vector{String}) for (i, k) in enumerate(keys) diff --git a/stdlib/REPL/src/LineEdit.jl b/stdlib/REPL/src/LineEdit.jl index 084e494e13328..3a52459da4d93 100644 --- a/stdlib/REPL/src/LineEdit.jl +++ b/stdlib/REPL/src/LineEdit.jl @@ -1199,7 +1199,7 @@ end const wildcard = '\U10f7ff' # "Private Use" Char -normalize_key(key::Char) = string(key) +normalize_key(key::AbstractChar) = string(key) normalize_key(key::Integer) = normalize_key(Char(key)) function normalize_key(key::AbstractString) wildcard in key && error("Matching '\U10f7ff' not supported.") @@ -1429,7 +1429,7 @@ function keymap_merge(target,source) # We first resolve redirects in the source value = source[key] visited = Vector{Any}() - while isa(value, Union{Char,AbstractString}) + while isa(value, Union{AbstractChar,AbstractString}) value = normalize_key(value) if value in visited error("Eager redirection cycle detected for key " * escape_string(key)) @@ -1441,7 +1441,7 @@ function keymap_merge(target,source) value = source[value] end - if isa(value, Union{Char,AbstractString}) + if isa(value, Union{AbstractChar,AbstractString}) value = getEntry(ret, value) if value === nothing error("Could not find redirected value " * escape_string(source[key])) diff --git a/stdlib/Random/src/generation.jl b/stdlib/Random/src/generation.jl index 14112e1697e6a..cd5b18784ad5b 100644 --- a/stdlib/Random/src/generation.jl +++ b/stdlib/Random/src/generation.jl @@ -156,9 +156,9 @@ rand(r::AbstractRNG, ::SamplerType{Complex{T}}) where {T<:Real} = ### random characters # returns a random valid Unicode scalar value (i.e. 0 - 0xd7ff, 0xe000 - # 0x10ffff) -function rand(r::AbstractRNG, ::SamplerType{Char}) +function rand(r::AbstractRNG, ::SamplerType{T}) where {T<:AbstractChar} c = rand(r, 0x00000000:0x0010f7ff) - (c < 0xd800) ? Char(c) : Char(c+0x800) + (c < 0xd800) ? T(c) : T(c+0x800) end diff --git a/stdlib/SparseArrays/src/sparsevector.jl b/stdlib/SparseArrays/src/sparsevector.jl index da090dbece4b3..b814e683e0a6c 100644 --- a/stdlib/SparseArrays/src/sparsevector.jl +++ b/stdlib/SparseArrays/src/sparsevector.jl @@ -1654,7 +1654,7 @@ end ### BLAS-2 / sparse A * sparse x -> dense y -function densemv(A::SparseMatrixCSC, x::AbstractSparseVector; trans::Char='N') +function densemv(A::SparseMatrixCSC, x::AbstractSparseVector; trans::AbstractChar='N') local xlen::Int, ylen::Int m, n = size(A) if trans == 'N' || trans == 'n' diff --git a/stdlib/Unicode/src/Unicode.jl b/stdlib/Unicode/src/Unicode.jl index 4c933f8b08a19..fa220f4cc24fd 100644 --- a/stdlib/Unicode/src/Unicode.jl +++ b/stdlib/Unicode/src/Unicode.jl @@ -74,11 +74,11 @@ true isassigned(c) = Base.Unicode.isassigned(c) """ - iscased(c::Char) -> Bool + iscased(c::AbstractChar) -> Bool Tests whether a character is cased, i.e. is lower-, upper- or title-cased. """ -iscased(c::Char) = Base.Unicode.iscased(c) +iscased(c::AbstractChar) = Base.Unicode.iscased(c) """ graphemes(s::AbstractString) -> GraphemeIterator diff --git a/test/char.jl b/test/char.jl index d1e1288ef11cf..69ea0bbb14a40 100644 --- a/test/char.jl +++ b/test/char.jl @@ -250,3 +250,22 @@ end test_overlong('\u8430', 0x8430, "'萰'") test_overlong("\xf0\x88\x90\xb0"[1], 0x8430, "'\\xf0\\x88\\x90\\xb0'") end + +# create a new AbstractChar type to test the fallbacks +primitive type ASCIIChar <: AbstractChar 8 end +ASCIIChar(c::UInt8) = reinterpret(ASCIIChar, c) +ASCIIChar(c::UInt32) = ASCIIChar(UInt8(c)) +Base.UInt8(c::ASCIIChar) = reinterpret(UInt8, c) +Base.UInt32(c::ASCIIChar) = UInt32(UInt8(c)) + +@testset "abstractchar" begin + @test AbstractChar('x') === AbstractChar(UInt32('x')) === 'x' + + @test isascii(ASCIIChar('x')) + @test ASCIIChar('x') < 'y' + @test ASCIIChar('x') == 'x' === Char(ASCIIChar('x')) + @test ASCIIChar('x')^3 == "xxx" + @test repr(ASCIIChar('x')) == "'x'" + @test string(ASCIIChar('x')) == "x" + @test read(IOBuffer("x"), ASCIIChar) === ASCIIChar('x') +end From 07c665d26bf700669ba42224fe4718c9e4f6fc59 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Thu, 1 Mar 2018 17:22:21 -0500 Subject: [PATCH 2/8] NEWS link --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index ad7b2452c92fe..794294ab3cc54 100644 --- a/NEWS.md +++ b/NEWS.md @@ -459,7 +459,7 @@ Library improvements less or equal than `i` in the string `s` or `0` if no such index exists ([#24414]). * `Char` is now a subtype of `AbstractChar`, and most of the functions that - take character arguments now accept any `AbstractChar`. + take character arguments now accept any `AbstractChar` ([#26286]). * `Irrational` is now a subtype of `AbstractIrrational` ([#24245]). From 402f9eda800b7bf574fd67ea75894329a2385ee6 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 09:04:40 -0500 Subject: [PATCH 3/8] fixes from feedback --- base/char.jl | 6 +++--- base/strings/basic.jl | 4 ++-- base/strings/util.jl | 2 +- doc/src/manual/strings.md | 5 +++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/base/char.jl b/base/char.jl index 08bed28e86bc9..9daae1ea607fd 100644 --- a/base/char.jl +++ b/base/char.jl @@ -18,7 +18,8 @@ representable in a given `AbstractChar` type. Internally, an `AbstractChar` type may use a variety of encodings. Conversion to `UInt32` will not reveal this encoding because it always returns the Unicode value of the character. (Typically, the raw encoding can be obtained -via [`reinterpret`](@ref).) +via [`reinterpret`](@ref).) Character I/O uses UTF-8 by default for all +character types, regardless of their internal encoding. """ AbstractChar @@ -148,8 +149,7 @@ hash(x::Char, h::UInt) = # fallbacks: isless(x::AbstractChar, y::AbstractChar) = isless(Char(x), Char(y)) ==(x::AbstractChar, y::AbstractChar) = Char(x) == Char(y) -hash(x::AbstractChar, h::UInt) = - hash_uint64(((UInt32(x) + UInt64(0xd060fad0)) << 32) ⊻ UInt64(h)) +hash(x::AbstractChar, h::UInt) = hash(Char(x), h) widen(::Type{T}) where {T<:AbstractChar} = T -(x::AbstractChar, y::AbstractChar) = Int(x) - Int(y) diff --git a/base/strings/basic.jl b/base/strings/basic.jl index 88ad487a058ea..f96c44b5da61b 100644 --- a/base/strings/basic.jl +++ b/base/strings/basic.jl @@ -14,8 +14,8 @@ about strings: * String indexing is done in terms of these code units: * Characters are extracted by `s[i]` with a valid string index `i` * Each `AbstractChar` in a string is encoded by one or more code units - * Only the index of the first code unit of a `AbstractChar` is a valid index - * The encoding of a `AbstractChar` is independent of what precedes or follows it + * Only the index of the first code unit of an `AbstractChar` is a valid index + * The encoding of an `AbstractChar` is independent of what precedes or follows it * String encodings are [self-synchronizing] – i.e. `isvalid(s, i)` is O(1) [self-synchronizing]: https://en.wikipedia.org/wiki/Self-synchronizing_code diff --git a/base/strings/util.jl b/base/strings/util.jl index ef06c1ee51dfa..44cd811df6938 100644 --- a/base/strings/util.jl +++ b/base/strings/util.jl @@ -410,7 +410,7 @@ If `count` is provided, replace at most `count` occurrences. or a regular expression. If `r` is a function, each occurrence is replaced with `r(s)` where `s` is the matched substring (when `pat`is a `Regex` or `AbstractString`) or -character (when `pat` is a `AbstractChar` or a collection of `AbstractChar`). +character (when `pat` is an `AbstractChar` or a collection of `AbstractChar`). If `pat` is a regular expression and `r` is a `SubstitutionString`, then capture group references in `r` are replaced with the corresponding matched text. To remove instances of `pat` from `string`, set `r` to the empty `String` (`""`). diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index d39147ed780cb..37ba9a9a43359 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -28,8 +28,9 @@ There are a few noteworthy high-level features about Julia's strings: additional `AbstractString` subtypes (e.g. for other encodings). If you define a function expecting a string argument, you should declare the type as `AbstractString` in order to accept any string type. - * Like C and Java, but unlike most dynamic languages, Julia has a first-class type representing - a single character, called `AbstractChar`. This is just a special kind of 32-bit primitive type whose numeric value represents a Unicode code point. + * Like C and Java, but unlike most dynamic languages, Julia has a first-class type for representing + a single character, called `AbstractChar`. The built-in `Char` subtype of `AbstractChar` + is a 32-bit primitive type that can represent any Unicode character. * As in Java, strings are immutable: the value of an `AbstractString` object cannot be changed. To construct a different string value, you construct a new string from parts of other strings. * Conceptually, a string is a *partial function* from indices to characters: for some index values, From cc5e4450b38b74597da18b49dc96091cb4b5edcc Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 13:55:07 -0500 Subject: [PATCH 4/8] use print when io-specific text encoding (usually UTF-8) is desired, and write when encoding should be determined by the argument type --- base/char.jl | 75 +++++++++++-- base/grisu/grisu.jl | 55 ++++----- base/io.jl | 13 ++- base/printf.jl | 118 ++++++++++---------- base/strings/io.jl | 22 ++-- stdlib/Dates/src/io.jl | 36 +++--- stdlib/DelimitedFiles/src/DelimitedFiles.jl | 6 +- stdlib/Distributed/src/cluster.jl | 2 +- stdlib/SHA/src/types.jl | 18 +-- test/char.jl | 1 - 10 files changed, 201 insertions(+), 145 deletions(-) diff --git a/base/char.jl b/base/char.jl index 9daae1ea607fd..aa8d064e44c90 100644 --- a/base/char.jl +++ b/base/char.jl @@ -18,8 +18,13 @@ representable in a given `AbstractChar` type. Internally, an `AbstractChar` type may use a variety of encodings. Conversion to `UInt32` will not reveal this encoding because it always returns the Unicode value of the character. (Typically, the raw encoding can be obtained -via [`reinterpret`](@ref).) Character I/O uses UTF-8 by default for all -character types, regardless of their internal encoding. +via [`reinterpret`](@ref).) + +`print(io, c)` of any `c::AbstractChar` produces UTF-8 output by default +(via conversion to `Char` if necessary). `write(io, c)`, in contrast, +may emit a different encoding depending on `typeof(c)`, and `read(io, typeof(c))` +should read the same encoding as `write`. New `AbstractChar` types should provide +their own implementations of `write` and `read`. """ AbstractChar @@ -64,7 +69,23 @@ end # fallback: other AbstractChar types, by default, are assumed # not to support malformed or overlong encodings. + +""" + ismalformed(c::AbstractChar) + +Return `true` if `c` represents malformed (non-Unicode) data according to the +encoding used by `c`. Defaults to `false` for non-`Char` types. See also +[`show_invalid`](@ref). +""" ismalformed(c::AbstractChar) = false + +""" + isoverlong(c::AbstractChar) + +Return `true` if `c` represents an overlong UTF-8 sequence. Defaults +to `false` for non-`Char` types. See also [`decode_overlong`](@ref) +and [`show_invalid`](@ref). +""" isoverlong(c::AbstractChar) = false function UInt32(c::Char) @@ -92,6 +113,15 @@ function decode_overlong(c::Char) (u & 0x007f0000 >> 4) | (u & 0x7f000000 >> 6) end +""" + decode_overlong(c::AbstractChar) + +When [`isoverlong(c)`](@ref) is `true`, `decode_overlong(c)` returns +the Unicode codepoint value of `c`. `AbstractChar` implementations +that support overlong encodings should implement `Base.decode_overlong`. +""" +decode_overlong + function Char(u::UInt32) u < 0x80 && return reinterpret(Char, u << 24) u < 0x00200000 || code_point_err(u)::Union{} @@ -157,10 +187,37 @@ widen(::Type{T}) where {T<:AbstractChar} = T +(x::T, y::Integer) where {T<:AbstractChar} = T(Int32(x) + Int32(y)) +(x::Integer, y::AbstractChar) = y + x -print(io::IO, c::AbstractChar) = (write(io, c); nothing) +# `print` should output UTF-8 by default for all AbstractChar types. +# (Packages may implement other IO subtypes to specify different encodings.) +# In contrast, `write(io, c)` outputs a `c` in an encoding determined by typeof(c). +print(io::IO, c::Char) = (write(io, c); nothing) +print(io::IO, c::AbstractChar) = print(io, Char(c)) # fallback: convert to output UTF-8 const hex_chars = UInt8['0':'9';'a':'z'] +function show_invalid(io::IO, c::Char) + write(io, 0x27) + u = reinterpret(UInt32, c) + while true + a = hex_chars[((u >> 28) & 0xf) + 1] + b = hex_chars[((u >> 24) & 0xf) + 1] + write(io, 0x5c, UInt8('x'), a, b) + (u <<= 8) == 0 && break + end + write(io, 0x27) +end + +""" + show_invalid(io::IO, c::AbstractChar) + +Called by `show(io, c)` when [`isoverlong(c)`](@ref) or +[`ismalformed(c)`](@ref) return `true`. Subclasses +of `AbstractChar` should define `Base.show_invalid` methods +if they support storing invalid character data. +""" +show_invalid + +# show c to io, assuming UTF-8 encoded output function show(io::IO, c::AbstractChar) if c <= '\\' b = c == '\0' ? 0x30 : @@ -180,17 +237,11 @@ function show(io::IO, c::AbstractChar) end end if isoverlong(c) || ismalformed(c) + show_invalid(io, c) + elseif isprint(c) write(io, 0x27) - u = reinterpret(UInt32, c) - while true - a = hex_chars[((u >> 28) & 0xf) + 1] - b = hex_chars[((u >> 24) & 0xf) + 1] - write(io, 0x5c, 'x', a, b) - (u <<= 8) == 0 && break - end + print(io, c) # use print, not write, to use UTF-8 for any AbstractChar write(io, 0x27) - elseif isprint(c) - write(io, 0x27, c, 0x27) else # unprintable, well-formed, non-overlong Unicode u = UInt32(c) write(io, 0x27, 0x5c, c <= '\x7f' ? 0x78 : c <= '\uffff' ? 0x75 : 0x55) diff --git a/base/grisu/grisu.jl b/base/grisu/grisu.jl index 8c4ce7f52d586..f72e08b2ddded 100644 --- a/base/grisu/grisu.jl +++ b/base/grisu/grisu.jl @@ -58,13 +58,13 @@ infstr(x::Float32) = "Inf32" infstr(x::Float16) = "Inf16" function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, compact) - isnan(x) && return write(io, typed ? nanstr(x) : "NaN") + isnan(x) && return print(io, typed ? nanstr(x) : "NaN") if isinf(x) - signbit(x) && write(io,'-') - write(io, typed ? infstr(x) : "Inf") + signbit(x) && print(io,'-') + print(io, typed ? infstr(x) : "Inf") return end - typed && isa(x,Float16) && write(io, "Float16(") + typed && isa(x,Float16) && print(io, "Float16(") (len,pt,neg),buffer = grisu(x,mode,n),DIGITS pdigits = pointer(buffer) if mode == PRECISION @@ -72,27 +72,28 @@ function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, compact) len -= 1 end end - neg && write(io,'-') + neg && print(io,'-') exp_form = pt <= -4 || pt > 6 exp_form = exp_form || (pt >= len && abs(mod(x + 0.05, 10^(pt - len)) - 0.05) > 0.05) # see issue #6608 if exp_form # .00001 to 100000. # => #.#######e### + # assumes ASCII/UTF8 encoding of digits is okay for out: unsafe_write(io, pdigits, 1) - write(io, '.') + print(io, '.') if len > 1 unsafe_write(io, pdigits+1, len-1) else - write(io, '0') + print(io, '0') end - write(io, (typed && isa(x,Float32)) ? 'f' : 'e') - write(io, string(pt - 1)) - typed && isa(x,Float16) && write(io, ")") + print(io, (typed && isa(x,Float32)) ? 'f' : 'e') + print(io, string(pt - 1)) + typed && isa(x,Float16) && print(io, ")") return elseif pt <= 0 # => 0.00######## - write(io, "0.") + print(io, "0.") while pt < 0 - write(io, '0') + print(io, '0') pt += 1 end unsafe_write(io, pdigits, len) @@ -100,17 +101,17 @@ function _show(io::IO, x::AbstractFloat, mode, n::Int, typed, compact) # => ########00.0 unsafe_write(io, pdigits, len) while pt > len - write(io, '0') + print(io, '0') len += 1 end - write(io, ".0") + print(io, ".0") else # => ####.#### unsafe_write(io, pdigits, pt) - write(io, '.') + print(io, '.') unsafe_write(io, pdigits+pt, len-pt) end - typed && !compact && isa(x,Float32) && write(io, "f0") - typed && isa(x,Float16) && write(io, ")") + typed && !compact && isa(x,Float32) && print(io, "f0") + typed && isa(x,Float16) && print(io, ")") nothing end @@ -149,9 +150,9 @@ Base.print(io::IO, x::Float16) = _show(io, x, SHORTEST, 0, false, false) # 0 < pt ########e### len+k+1 function _print_shortest(io::IO, x::AbstractFloat, dot::Bool, mode, n::Int) - isnan(x) && return write(io, "NaN") - x < 0 && write(io,'-') - isinf(x) && return write(io, "Inf") + isnan(x) && return print(io, "NaN") + x < 0 && print(io,'-') + isinf(x) && return print(io, "Inf") (len,pt,neg),buffer = grisu(x,mode,n),DIGITS pdigits = pointer(buffer) e = pt-len @@ -159,14 +160,14 @@ function _print_shortest(io::IO, x::AbstractFloat, dot::Bool, mode, n::Int) if -pt > k+1 || e+dot > k+1 # => ########e### unsafe_write(io, pdigits+0, len) - write(io, 'e') - write(io, string(e)) + print(io, 'e') + print(io, string(e)) return elseif pt <= 0 # => 0.000######## - write(io, "0.") + print(io, "0.") while pt < 0 - write(io, '0') + print(io, '0') pt += 1 end unsafe_write(io, pdigits+0, len) @@ -174,15 +175,15 @@ function _print_shortest(io::IO, x::AbstractFloat, dot::Bool, mode, n::Int) # => ########000. unsafe_write(io, pdigits+0, len) while e > 0 - write(io, '0') + print(io, '0') e -= 1 end if dot - write(io, '.') + print(io, '.') end else # => ####.#### unsafe_write(io, pdigits+0, pt) - write(io, '.') + print(io, '.') unsafe_write(io, pdigits+pt, len-pt) end nothing diff --git a/base/io.jl b/base/io.jl index 2282b6e0d639a..bed7ea052025c 100644 --- a/base/io.jl +++ b/base/io.jl @@ -83,7 +83,7 @@ Return `true` if the specified IO object is readable (if that can be determined) # Examples ```jldoctest julia> open("myfile.txt", "w") do io - write(io, "Hello world!"); + print(io, "Hello world!"); isreadable(io) end false @@ -106,7 +106,7 @@ Return `true` if the specified IO object is writable (if that can be determined) # Examples ```jldoctest julia> open("myfile.txt", "w") do io - write(io, "Hello world!"); + print(io, "Hello world!"); iswritable(io) end true @@ -152,7 +152,8 @@ read(stream, t) write(filename::AbstractString, x) Write the canonical binary representation of a value to the given I/O stream or file. -Return the number of bytes written into the stream. +Return the number of bytes written into the stream. See also [`print`](@ref) to +write a text representation (with an encoding that may depend upon `io`). You can write multiple values with the same `write` call. i.e. the following are equivalent: @@ -570,7 +571,8 @@ function write(io::IO, c::Char) n += 1 end end -write(io::IO, c::AbstractChar) = write(io, Char(c)) # fallback +# write(io, ::AbstractChar) is not defined: implementations +# must provide their own encoding-specific method. function write(io::IO, s::Symbol) pname = unsafe_convert(Ptr{UInt8}, s) @@ -628,7 +630,8 @@ function read(io::IO, ::Type{Char}) end return reinterpret(Char, c) end -read(io::IO, ::Type{T}) where {T<:AbstractChar} = T(read(io, Char)) # fallback +# read(io, T) is not defined for other AbstractChar: implementations +# must provide their own encoding-specific method. # readuntil_string is useful below since it has # an optimized method for s::IOStream diff --git a/base/printf.jl b/base/printf.jl index 9b62a635bdd4d..96078bb9d1a24 100644 --- a/base/printf.jl +++ b/base/printf.jl @@ -13,7 +13,7 @@ function gen(s::AbstractString) blk = Expr(:block, :(local neg, pt, len, exp, do_out, args)) for x in parse(s) if isa(x,AbstractString) - push!(blk.args, :(write(out, $(length(x)==1 ? x[1] : x)))) + push!(blk.args, :(print(out, $(length(x)==1 ? x[1] : x)))) else c = lowercase(x[end]) f = c=='f' ? gen_f : @@ -146,19 +146,19 @@ function special_handler(flags::String, width::Int) $x < 0 ? $(pad("-Inf", width)) : $(pad("$(pos)Inf", width)) end - ex = :(isfinite($x) ? $blk : write(out, $abn)) + ex = :(isfinite($x) ? $blk : print(out, $abn)) x, ex, blk end function pad(m::Int, n, c::Char) if m <= 1 - :($n > 0 && write(out,$c)) + :($n > 0 && print(out,$c)) else @gensym i quote $i = $n while $i > 0 - write(out,$c) + print(out,$c) $i -= 1 end end @@ -169,11 +169,11 @@ function dynamic_pad(m, val, c::Char) @gensym i quote if $m <= 1 - $val > 0 && write(out,$c) + $val > 0 && print(out,$c) else $i = $val while $i > 0 - write(out,$c) + print(out,$c) $i -= 1 end end @@ -184,11 +184,11 @@ function print_fixed(out, precision, pt, ndigits, trailingzeros=true) pdigits = pointer(DIGITS) if pt <= 0 # 0.0dddd0 - write(out, '0') - write(out, '.') + print(out, '0') + print(out, '.') precision += pt while pt < 0 - write(out, '0') + print(out, '0') pt += 1 end unsafe_write(out, pdigits, ndigits) @@ -197,30 +197,30 @@ function print_fixed(out, precision, pt, ndigits, trailingzeros=true) # dddd000.000000 unsafe_write(out, pdigits, ndigits) while ndigits < pt - write(out, '0') + print(out, '0') ndigits += 1 end if trailingzeros - write(out, '.') + print(out, '.') end else # 0 < pt < ndigits # dd.dd0000 ndigits -= pt unsafe_write(out, pdigits, pt) - write(out, '.') + print(out, '.') unsafe_write(out, pdigits+pt, ndigits) precision -= ndigits end if trailingzeros while precision > 0 - write(out, '0') + print(out, '0') precision -= 1 end end end function print_exp_e(out, exp::Integer) - write(out, exp < 0 ? '-' : '+') + print(out, exp < 0 ? '-' : '+') exp = abs(exp) d = div(exp,100) if d > 0 @@ -228,15 +228,15 @@ function print_exp_e(out, exp::Integer) print(out, exp) return end - write(out, Char('0'+d)) + print(out, Char('0'+d)) end exp = rem(exp,100) - write(out, Char('0'+div(exp,10))) - write(out, Char('0'+rem(exp,10))) + print(out, Char('0'+div(exp,10))) + print(out, Char('0'+rem(exp,10))) end function print_exp_a(out, exp::Integer) - write(out, exp < 0 ? '-' : '+') + print(out, exp < 0 ? '-' : '+') exp = abs(exp) print(out, exp) end @@ -299,12 +299,12 @@ function gen_d(flags::String, width::Int, precision::Int, c::Char) push!(blk.args, pad(width-precision, padding, ' ')) end # print sign - '+' in flags ? push!(blk.args, :(write(out, neg ? '-' : '+'))) : - ' ' in flags ? push!(blk.args, :(write(out, neg ? '-' : ' '))) : - push!(blk.args, :(neg && write(out, '-'))) + '+' in flags ? push!(blk.args, :(print(out, neg ? '-' : '+'))) : + ' ' in flags ? push!(blk.args, :(print(out, neg ? '-' : ' '))) : + push!(blk.args, :(neg && print(out, '-'))) # print prefix for ch in prefix - push!(blk.args, :(write(out, $ch))) + push!(blk.args, :(print(out, $ch))) end # print zero padding & leading zeros if space_pad && precision > 1 @@ -362,9 +362,9 @@ function gen_f(flags::String, width::Int, precision::Int, c::Char) push!(blk.args, pad(width-1, padding, ' ')) end # print sign - '+' in flags ? push!(blk.args, :(write(out, neg ? '-' : '+'))) : - ' ' in flags ? push!(blk.args, :(write(out, neg ? '-' : ' '))) : - push!(blk.args, :(neg && write(out, '-'))) + '+' in flags ? push!(blk.args, :(print(out, neg ? '-' : '+'))) : + ' ' in flags ? push!(blk.args, :(print(out, neg ? '-' : ' '))) : + push!(blk.args, :(neg && print(out, '-'))) # print zero padding if padding !== nothing && !('-' in flags) && '0' in flags push!(blk.args, pad(width-1, padding, '0')) @@ -374,8 +374,8 @@ function gen_f(flags::String, width::Int, precision::Int, c::Char) push!(blk.args, :(print_fixed(out,$precision,pt,len))) else push!(blk.args, :(unsafe_write(out, pointer(DIGITS), len))) - push!(blk.args, :(while pt >= (len+=1) write(out,'0') end)) - '#' in flags && push!(blk.args, :(write(out, '.'))) + push!(blk.args, :(while pt >= (len+=1) print(out,'0') end)) + '#' in flags && push!(blk.args, :(print(out, '.'))) end # print space padding if padding !== nothing && '-' in flags @@ -456,9 +456,9 @@ function gen_e(flags::String, width::Int, precision::Int, c::Char, inside_g::Boo push!(blk.args, pad(width, padding, ' ')) end # print sign - '+' in flags ? push!(blk.args, :(write(out, neg ? '-' : '+'))) : - ' ' in flags ? push!(blk.args, :(write(out, neg ? '-' : ' '))) : - push!(blk.args, :(neg && write(out, '-'))) + '+' in flags ? push!(blk.args, :(print(out, neg ? '-' : '+'))) : + ' ' in flags ? push!(blk.args, :(print(out, neg ? '-' : ' '))) : + push!(blk.args, :(neg && print(out, '-'))) # print zero padding if padding !== nothing && !('-' in flags) && '0' in flags push!(blk.args, pad(width, padding, '0')) @@ -472,12 +472,12 @@ function gen_e(flags::String, width::Int, precision::Int, c::Char, inside_g::Boo endidx -= 1 end; if endidx > 1 - write(out, '.') + print(out, '.') unsafe_write(out, pointer(DIGITS)+1, endidx-1) end )) else - push!(blk.args, :(write(out, '.'))) + push!(blk.args, :(print(out, '.'))) push!(blk.args, :(unsafe_write(out, pointer(DIGITS)+1, $(ndigits-1)))) if ndigits < precision+1 n = precision+1-ndigits @@ -486,7 +486,7 @@ function gen_e(flags::String, width::Int, precision::Int, c::Char, inside_g::Boo end end for ch in expmark - push!(blk.args, :(write(out, $ch))) + push!(blk.args, :(print(out, $ch))) end push!(blk.args, :(print_exp_e(out, exp))) # print space padding @@ -562,21 +562,21 @@ function gen_a(flags::String, width::Int, precision::Int, c::Char) push!(blk.args, pad(width, padding, ' ')) end # print sign - '+' in flags ? push!(blk.args, :(write(out, neg ? '-' : '+'))) : - ' ' in flags ? push!(blk.args, :(write(out, neg ? '-' : ' '))) : - push!(blk.args, :(neg && write(out, '-'))) + '+' in flags ? push!(blk.args, :(print(out, neg ? '-' : '+'))) : + ' ' in flags ? push!(blk.args, :(print(out, neg ? '-' : ' '))) : + push!(blk.args, :(neg && print(out, '-'))) # hex prefix for ch in hexmark - push!(blk.args, :(write(out, $ch))) + push!(blk.args, :(print(out, $ch))) end # print zero padding if padding !== nothing && !('-' in flags) && '0' in flags push!(blk.args, pad(width, padding, '0')) end - # print digits + # print digits: assumes ASCII/UTF8 encoding of digits is okay for `out` push!(blk.args, :(write(out, DIGITS[1]))) if precision > 0 - push!(blk.args, :(write(out, '.'))) + push!(blk.args, :(print(out, '.'))) push!(blk.args, :(unsafe_write(out, pointer(DIGITS)+1, $(ndigits-1)))) if ndigits < precision+1 n = precision+1-ndigits @@ -586,15 +586,15 @@ function gen_a(flags::String, width::Int, precision::Int, c::Char) ifvpblk = Expr(:if, :(len > 1), Expr(:block)) vpblk = ifvpblk.args[2] if '#' in flags - push!(blk.args, :(write(out, '.'))) + push!(blk.args, :(print(out, '.'))) else - push!(vpblk.args, :(write(out, '.'))) + push!(vpblk.args, :(print(out, '.'))) end push!(vpblk.args, :(unsafe_write(out, pointer(DIGITS)+1, len-1))) push!(blk.args, ifvpblk) end for ch in expmark - push!(blk.args, :(write(out, $ch))) + push!(blk.args, :(print(out, $ch))) end push!(blk.args, :(print_exp_a(out, exp))) # print space padding @@ -619,7 +619,7 @@ function gen_c(flags::String, width::Int, precision::Int, c::Char) p = '0' in flags ? '0' : ' ' push!(blk.args, pad(width-1, :($width-textwidth($x)), p)) end - push!(blk.args, :(write(out, $x))) + push!(blk.args, :(print(out, $x))) if width > 1 && '-' in flags push!(blk.args, pad(width-1, :($width-textwidth($x)), ' ')) end @@ -655,7 +655,7 @@ function gen_s(flags::String, width::Int, precision::Int, c::Char) if !('-' in flags) push!(blk.args, pad(width, :($width-textwidth($x)), ' ')) end - push!(blk.args, :(write(out, $x))) + push!(blk.args, :(print(out, $x))) if '-' in flags push!(blk.args, pad(width, :($width-textwidth($x)), ' ')) end @@ -671,7 +671,7 @@ function gen_s(flags::String, width::Int, precision::Int, c::Char) push!(blk.args, :(show(io, $x))) end if precision!=-1 - push!(blk.args, :(write(out, _limit(String(take!(io)), $precision)))) + push!(blk.args, :(print(out, _limit(String(take!(io)), $precision)))) end end :(($x)::Any), blk @@ -693,9 +693,9 @@ function gen_p(flags::String, width::Int, precision::Int, c::Char) if width > 0 && !('-' in flags) push!(blk.args, pad(width, width, ' ')) end - push!(blk.args, :(write(out, '0'))) - push!(blk.args, :(write(out, 'x'))) - push!(blk.args, :(write(out, String(string(unsigned($x), pad = $ptrwidth, base = 16))))) + push!(blk.args, :(print(out, '0'))) + push!(blk.args, :(print(out, 'x'))) + push!(blk.args, :(print(out, String(string(unsigned($x), pad = $ptrwidth, base = 16))))) if width > 0 && '-' in flags push!(blk.args, pad(width, width, ' ')) end @@ -759,9 +759,9 @@ function gen_g(flags::String, width::Int, precision::Int, c::Char) $padexpr; end)) end # print sign - '+' in flags ? push!(blk.args, :(write(out, neg ? '-' : '+'))) : - ' ' in flags ? push!(blk.args, :(write(out, neg ? '-' : ' '))) : - push!(blk.args, :(neg && write(out, '-'))) + '+' in flags ? push!(blk.args, :(print(out, neg ? '-' : '+'))) : + ' ' in flags ? push!(blk.args, :(print(out, neg ? '-' : ' '))) : + push!(blk.args, :(neg && print(out, '-'))) # print zero padding if !('-' in flags) && '0' in flags padexpr = dynamic_pad(:width, :padding, '0') @@ -769,7 +769,7 @@ function gen_g(flags::String, width::Int, precision::Int, c::Char) $padexpr; end)) end # finally print value - push!(blk.args, :(write(out,tmpstr))) + push!(blk.args, :(print(out,tmpstr))) # print space padding if '-' in flags padexpr = dynamic_pad(:width, :padding, ' ') @@ -1115,20 +1115,20 @@ function bigfloat_printf(out, d::BigFloat, flags::String, width::Int, precision: fmt_len += ndigits(precision)+1 end fmt = IOBuffer(maxsize=fmt_len) - write(fmt, '%') - write(fmt, flags) + print(fmt, '%') + print(fmt, flags) if width > 0 print(fmt, width) end if precision == 0 - write(fmt, '.') - write(fmt, '0') + print(fmt, '.') + print(fmt, '0') elseif precision > 0 - write(fmt, '.') + print(fmt, '.') print(fmt, precision) end - write(fmt, 'R') - write(fmt, c) + print(fmt, 'R') + print(fmt, c) write(fmt, UInt8(0)) printf_fmt = take!(fmt) @assert length(printf_fmt) == fmt_len diff --git a/base/strings/io.jl b/base/strings/io.jl index ea0de4018994e..a65a93fe90f14 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -134,7 +134,9 @@ julia> string("a", 1, true) """ string(xs...) = print_to_string(xs...) -print(io::IO, s::AbstractString) = (write(io, s); nothing) +# note: print uses an encoding determined by `io` (defaults to UTF-8), whereas +# write uses an encoding determined by `s` (UTF-8 for `String`) +print(io::IO, s::AbstractString) = for c in s; print(io, c); end write(io::IO, s::AbstractString) = (len = 0; for c in s; len += write(io, c); end; len) show(io::IO, s::AbstractString) = print_quoted(io, s) @@ -445,42 +447,42 @@ function unindent(str::AbstractString, indent::Int; tabwidth=8) elseif ch == '\n' # Now we need to output enough indentation for i = 1:col-indent - write(buf, ' ') + print(buf, ' ') end col = 0 - write(buf, '\n') + print(buf, '\n') else cutting = false # Now we need to output enough indentation to get to # correct place for i = 1:col-indent - write(buf, ' ') + print(buf, ' ') end col += 1 - write(buf, ch) + print(buf, ch) end elseif ch == '\t' # Handle internal tabs upd = div(col + tabwidth, tabwidth) * tabwidth # output the number of spaces that would have been seen # with original indentation for i = 1:(upd-col) - write(buf, ' ') + print(buf, ' ') end col = upd elseif ch == '\n' cutting = true col = 0 - write(buf, '\n') + print(buf, '\n') else col += 1 - write(buf, ch) + print(buf, ch) end end # If we were still "cutting" when we hit the end of the string, # we need to output the right number of spaces for the indentation if cutting for i = 1:col-indent - write(buf, ' ') + print(buf, ' ') end end String(take!(buf)) @@ -489,7 +491,7 @@ end function String(chars::AbstractVector{<:AbstractChar}) sprint(sizehint=length(chars)) do io for c in chars - write(io, c) + print(io, c) end end end diff --git a/stdlib/Dates/src/io.jl b/stdlib/Dates/src/io.jl index 5e3ec8dce705f..93d3fe53431da 100644 --- a/stdlib/Dates/src/io.jl +++ b/stdlib/Dates/src/io.jl @@ -76,14 +76,14 @@ end function _show_content(io::IO, d::DatePart{c}) where c for i = 1:d.width - write(io, c) + print(io, c) end end function Base.show(io::IO, d::DatePart{c}) where c - write(io, "DatePart(") + print(io, "DatePart(") _show_content(io, d) - write(io, ")") + print(io, ")") end ### Parse tokens @@ -131,19 +131,19 @@ end for (c, fn) in zip("YmdHMS", [year, month, day, hour, minute, second]) @eval function format(io, d::DatePart{$c}, dt) - write(io, string($fn(dt), base = 10, pad = d.width)) + print(io, string($fn(dt), base = 10, pad = d.width)) end end for (tok, fn) in zip("uU", [monthabbr, monthname]) @eval function format(io, d::DatePart{$tok}, dt, locale) - write(io, $fn(month(dt), locale)) + print(io, $fn(month(dt), locale)) end end for (tok, fn) in zip("eE", [dayabbr, dayname]) @eval function format(io, ::DatePart{$tok}, dt, locale) - write(io, $fn(dayofweek(dt), locale)) + print(io, $fn(dayofweek(dt), locale)) end end @@ -157,9 +157,9 @@ end l = lastindex(str) if l == n # fast path - write(io, str) + print(io, str) else - write(io, SubString(str, l - (n - 1), l)) + print(io, SubString(str, l - (n - 1), l)) end end @@ -173,7 +173,7 @@ function format(io, d::DatePart{'s'}, dt) str = string(ms, pad = 3) end - write(io, rpad(str, d.width, '0')) + print(io, rpad(str, d.width, '0')) end ### Delimiters @@ -211,17 +211,17 @@ end end @inline function format(io, d::Delim, dt, locale) - write(io, d.d) + print(io, d.d) end function _show_content(io::IO, d::Delim{<:AbstractChar, N}) where N if d.d in keys(CONVERSION_SPECIFIERS) for i = 1:N - write(io, '\\', d.d) + print(io, '\\', d.d) end else for i = 1:N - write(io, d.d) + print(io, d.d) end end end @@ -229,16 +229,16 @@ end function _show_content(io::IO, d::Delim) for c in d.d if c in keys(CONVERSION_SPECIFIERS) - write(io, '\\') + print(io, '\\') end - write(io, c) + print(io, c) end end function Base.show(io::IO, d::Delim) - write(io, "Delim(") + print(io, "Delim(") _show_content(io, d) - write(io, ")") + print(io, ")") end ### DateFormat construction @@ -370,11 +370,11 @@ function DateFormat(f::AbstractString, locale::AbstractString) end function Base.show(io::IO, df::DateFormat) - write(io, "dateformat\"") + print(io, "dateformat\"") for t in df.tokens _show_content(io, t) end - write(io, '"') + print(io, '"') end """ diff --git a/stdlib/DelimitedFiles/src/DelimitedFiles.jl b/stdlib/DelimitedFiles/src/DelimitedFiles.jl index 861ddd9747e42..a7f6620fd2e9a 100644 --- a/stdlib/DelimitedFiles/src/DelimitedFiles.jl +++ b/stdlib/DelimitedFiles/src/DelimitedFiles.jl @@ -747,7 +747,7 @@ function writedlm(io::IO, a::AbstractMatrix, dlm; opts...) for i = axes(a, 1) for j = axes(a, 2) writedlm_cell(pb, a[i, j], dlm, quotes) - j == lastc ? write(pb,'\n') : print(pb,dlm) + j == lastc ? print(pb,'\n') : print(pb,dlm) end (bytesavailable(pb) > (16*1024)) && write(io, take!(pb)) end @@ -763,7 +763,7 @@ function writedlm_row(io::IO, row, dlm, quotes) while !done(row, state) (x, state) = next(row, state) writedlm_cell(io, x, dlm, quotes) - done(row, state) ? write(io,'\n') : print(io,dlm) + done(row, state) ? print(io,'\n') : print(io,dlm) end end @@ -773,7 +773,7 @@ end # purely as an optimization. function writedlm_row(io::IO, row::Union{Number,AbstractString}, dlm, quotes) writedlm_cell(io, row, dlm, quotes) - write(io, '\n') + print(io, '\n') end # write an iterable collection of iterable rows diff --git a/stdlib/Distributed/src/cluster.jl b/stdlib/Distributed/src/cluster.jl index 6b7545bed4f2a..867b46dd3afb3 100644 --- a/stdlib/Distributed/src/cluster.jl +++ b/stdlib/Distributed/src/cluster.jl @@ -1124,7 +1124,7 @@ function init_parallel() register_worker(LPROC) end -write_cookie(io::IO) = write(io.in, string(cluster_cookie(), "\n")) +write_cookie(io::IO) = print(io.in, string(cluster_cookie(), "\n")) function process_opts(opts) # startup worker. diff --git a/stdlib/SHA/src/types.jl b/stdlib/SHA/src/types.jl index 68440f2c36319..e5bf01760edbc 100644 --- a/stdlib/SHA/src/types.jl +++ b/stdlib/SHA/src/types.jl @@ -138,15 +138,15 @@ copy(ctx::T) where {T<:SHA3_CTX} = T(copy(ctx.state), ctx.bytecount, copy(ctx.bu # Make printing these types a little friendlier import Base.show -show(io::IO, ::SHA1_CTX) = write(io, "SHA1 hash state") -show(io::IO, ::SHA2_224_CTX) = write(io, "SHA2 224-bit hash state") -show(io::IO, ::SHA2_256_CTX) = write(io, "SHA2 256-bit hash state") -show(io::IO, ::SHA2_384_CTX) = write(io, "SHA2 384-bit hash state") -show(io::IO, ::SHA2_512_CTX) = write(io, "SHA2 512-bit hash state") -show(io::IO, ::SHA3_224_CTX) = write(io, "SHA3 224-bit hash state") -show(io::IO, ::SHA3_256_CTX) = write(io, "SHA3 256-bit hash state") -show(io::IO, ::SHA3_384_CTX) = write(io, "SHA3 384-bit hash state") -show(io::IO, ::SHA3_512_CTX) = write(io, "SHA3 512-bit hash state") +show(io::IO, ::SHA1_CTX) = print(io, "SHA1 hash state") +show(io::IO, ::SHA2_224_CTX) = print(io, "SHA2 224-bit hash state") +show(io::IO, ::SHA2_256_CTX) = print(io, "SHA2 256-bit hash state") +show(io::IO, ::SHA2_384_CTX) = print(io, "SHA2 384-bit hash state") +show(io::IO, ::SHA2_512_CTX) = print(io, "SHA2 512-bit hash state") +show(io::IO, ::SHA3_224_CTX) = print(io, "SHA3 224-bit hash state") +show(io::IO, ::SHA3_256_CTX) = print(io, "SHA3 256-bit hash state") +show(io::IO, ::SHA3_384_CTX) = print(io, "SHA3 384-bit hash state") +show(io::IO, ::SHA3_512_CTX) = print(io, "SHA3 512-bit hash state") # use our types to define a method to get a pointer to the state buffer diff --git a/test/char.jl b/test/char.jl index 69ea0bbb14a40..751de8e8b0fb3 100644 --- a/test/char.jl +++ b/test/char.jl @@ -267,5 +267,4 @@ Base.UInt32(c::ASCIIChar) = UInt32(UInt8(c)) @test ASCIIChar('x')^3 == "xxx" @test repr(ASCIIChar('x')) == "'x'" @test string(ASCIIChar('x')) == "x" - @test read(IOBuffer("x"), ASCIIChar) === ASCIIChar('x') end From 26c6adea3b7c6896ec387f22c86d00c1491122d0 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 14:24:01 -0500 Subject: [PATCH 5/8] restore optimized print for strings, and analogous optimizations for SubString{String} --- base/strings/io.jl | 6 ++++-- base/strings/string.jl | 5 +---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/base/strings/io.jl b/base/strings/io.jl index a65a93fe90f14..573baf753a02a 100644 --- a/base/strings/io.jl +++ b/base/strings/io.jl @@ -140,8 +140,10 @@ print(io::IO, s::AbstractString) = for c in s; print(io, c); end write(io::IO, s::AbstractString) = (len = 0; for c in s; len += write(io, c); end; len) show(io::IO, s::AbstractString) = print_quoted(io, s) -write(to::GenericIOBuffer, s::SubString{String}) = - s.ncodeunits ≤ 0 ? 0 : unsafe_write(to, pointer(s.string, s.offset+1), UInt(s.ncodeunits)) +# optimized methods to avoid iterating over chars +write(io::IO, s::Union{String,SubString{String}}) = + GC.@preserve s unsafe_write(io, pointer(s), reinterpret(UInt, sizeof(s))) +print(io::IO, s::Union{String,SubString{String}}) = (write(io, s); nothing) ## printing literal quoted string data ## diff --git a/base/strings/string.jl b/base/strings/string.jl index fa4d85474ba37..260d6644647ff 100644 --- a/base/strings/string.jl +++ b/base/strings/string.jl @@ -81,9 +81,6 @@ codeunit(s::String) = UInt8 GC.@preserve s unsafe_load(pointer(s, i)) end -write(io::IO, s::String) = - GC.@preserve s unsafe_write(io, pointer(s), reinterpret(UInt, sizeof(s))) - ## comparison ## function cmp(a::String, b::String) @@ -320,7 +317,7 @@ codelen(c::Char) = 4 - (trailing_zeros(0xff000000 | reinterpret(UInt32, c)) >> 3 function string(a::Union{String,AbstractChar}...) sprint() do io for x in a - write(io, x) + print(io, x) end end end From fbfbcb3bd9ff112dc654205a14f0594ee4f15562 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 14:47:23 -0500 Subject: [PATCH 6/8] updates in response to documentation comments --- doc/src/manual/strings.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/src/manual/strings.md b/doc/src/manual/strings.md index 37ba9a9a43359..ffe4ad84824d0 100644 --- a/doc/src/manual/strings.md +++ b/doc/src/manual/strings.md @@ -30,7 +30,8 @@ There are a few noteworthy high-level features about Julia's strings: type. * Like C and Java, but unlike most dynamic languages, Julia has a first-class type for representing a single character, called `AbstractChar`. The built-in `Char` subtype of `AbstractChar` - is a 32-bit primitive type that can represent any Unicode character. + is a 32-bit primitive type that can represent any Unicode character (and which is based + on the UTF-8 encoding). * As in Java, strings are immutable: the value of an `AbstractString` object cannot be changed. To construct a different string value, you construct a new string from parts of other strings. * Conceptually, a string is a *partial function* from indices to characters: for some index values, @@ -41,10 +42,11 @@ There are a few noteworthy high-level features about Julia's strings: ## [Characters](@id man-characters) -An `AbstractChar` value represents a single character: it is just a 32-bit primitive type with a special literal -representation and appropriate arithmetic behaviors, whose numeric value is interpreted as a -[Unicode code point](https://en.wikipedia.org/wiki/Code_point). Julia comes with a concrete -`Char` type implementing the `AbstractChar` interface. Here is how `Char` values are +An `Char` value represents a single character: it is just a 32-bit primitive type with a special literal +representation and appropriate arithmetic behaviors, and which can be converted +to a numeric value representing a +[Unicode code point](https://en.wikipedia.org/wiki/Code_point). (Julia packages may define + other subtypes of `AbstractChar`, e.g. to optimize operations for other [text encodings](https://en.wikipedia.org/wiki/Character_encoding).) Here is how `Char` values are input and shown: ```jldoctest From 954a5dfcca7048134df4323f637003d48121e717 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 17:38:05 -0500 Subject: [PATCH 7/8] add codepoint function and more conversions, and move some stuff from boot.jl to char.jl --- base/boot.jl | 5 ---- base/char.jl | 55 ++++++++++++++++++++++++++++------------- base/exports.jl | 1 + doc/src/base/strings.md | 1 + test/char.jl | 2 +- 5 files changed, 41 insertions(+), 23 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index a77344bbb4730..ce944ca9d97cf 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -702,11 +702,6 @@ UInt32(x::BuiltinInts) = toUInt32(x)::UInt32 UInt64(x::BuiltinInts) = toUInt64(x)::UInt64 UInt128(x::BuiltinInts) = toUInt128(x)::UInt128 -(::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x)) -(::Type{AbstractChar})(x::Number) = Char(x) -(::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(UInt32(x)) -(::Type{T})(x::T) where {T<:AbstractChar} = x - (::Type{T})(x::T) where {T<:Number} = x Int(x::Ptr) = bitcast(Int, x) diff --git a/base/char.jl b/base/char.jl index aa8d064e44c90..84eb0d2c2f32a 100644 --- a/base/char.jl +++ b/base/char.jl @@ -3,9 +3,11 @@ """ The `AbstractChar` type is the supertype of all character implementations in Julia. A character represents a Unicode code point, and can be converted -to/from `UInt32` in order to obtain the numerical value of the code point. +to an integer via the [`codepoint`](@ref) function in order to obtain the +numerical value of the code point, or constructed from the same integer. These numerical values determine how characters are compared with `<` and `==`, -for example. +for example. New `T <: AbstractChar` types should define a `codepoint(::T)` +method and a `T(::UInt32)` constructor, at minimum. A given `AbstractChar` subtype may be capable of representing only a subset of Unicode, in which case conversion from an unsupported `UInt32` value @@ -16,15 +18,14 @@ The [`isvalid`](@ref) function can be used to check which codepoints are representable in a given `AbstractChar` type. Internally, an `AbstractChar` type may use a variety of encodings. Conversion -to `UInt32` will not reveal this encoding because it always returns the -Unicode value of the character. (Typically, the raw encoding can be obtained -via [`reinterpret`](@ref).) - -`print(io, c)` of any `c::AbstractChar` produces UTF-8 output by default -(via conversion to `Char` if necessary). `write(io, c)`, in contrast, -may emit a different encoding depending on `typeof(c)`, and `read(io, typeof(c))` -should read the same encoding as `write`. New `AbstractChar` types should provide -their own implementations of `write` and `read`. +via `codepoint(char)` will not reveal this encoding because it always returns the +Unicode value of the character. `print(io, c)` of any `c::AbstractChar` +produces UTF-8 output by default (via conversion to `Char` if necessary). + +`write(io, c)`, in contrast, may emit a different encoding depending on +`typeof(c)`, and `read(io, typeof(c))` should read the same encoding as `write`. +New `AbstractChar` types should typically provide their own implementations of +`write` and `read`. """ AbstractChar @@ -43,14 +44,32 @@ represents a valid Unicode character. """ Char +(::Type{T})(x::Integer) where {T<:AbstractChar} = T(UInt32(x)) +(::Type{AbstractChar})(x::Number) = Char(x) +(::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(codepoint(x)) +(::Type{T})(x::T) where {T<:AbstractChar} = x + +codepoint(c::Char) = UInt32(c) + +""" + codepoint(c::AbstractChar) + +Return the Unicode codepoint (an unsigned integer) corresponding +to the character `c` (or throw an exception if `c` does not represent +a valid character). For `Char`, this is a `UInt32` value, but +`AbstractChar` types that represent only a subset of Unicode may +return a different-sized integer (e.g. `UInt8`). +""" +codepoint # defined for Char in boot.jl + struct InvalidCharError{T<:AbstractChar} <: Exception char::T end -struct CodePointError <: Exception - code::Integer +struct CodePointError{T<:Integer} <: Exception + code::T end @noinline invalid_char(c::AbstractChar) = throw(InvalidCharError(c)) -@noinline code_point_err(u::UInt32) = throw(CodePointError(u)) +@noinline code_point_err(u::Integer) = throw(CodePointError(u)) function ismalformed(c::Char) u = reinterpret(UInt32, c) @@ -145,8 +164,10 @@ end convert(::Type{AbstractChar}, x::Number) = Char(x) # default to Char convert(::Type{T}, x::Number) where {T<:AbstractChar} = T(x) convert(::Type{T}, x::AbstractChar) where {T<:Number} = T(x) +convert(::Type{T}, c::AbstractChar) where {T<:AbstractChar} = T(c) +convert(::Type{T}, c::T) where {T<:AbstractChar} = c -rem(x::AbstractChar, ::Type{T}) where {T<:Number} = rem(UInt32(x), T) +rem(x::AbstractChar, ::Type{T}) where {T<:Number} = rem(codepoint(x), T) typemax(::Type{Char}) = reinterpret(Char, typemax(UInt32)) typemin(::Type{Char}) = reinterpret(Char, typemin(UInt32)) @@ -243,7 +264,7 @@ function show(io::IO, c::AbstractChar) print(io, c) # use print, not write, to use UTF-8 for any AbstractChar write(io, 0x27) else # unprintable, well-formed, non-overlong Unicode - u = UInt32(c) + u = codepoint(c) write(io, 0x27, 0x5c, c <= '\x7f' ? 0x78 : c <= '\uffff' ? 0x75 : 0x55) d = max(2, 8 - (leading_zeros(u) >> 2)) while 0 < d @@ -263,7 +284,7 @@ function show(io::IO, ::MIME"text/plain", c::T) where {T<:AbstractChar} u = decode_overlong(c) c = T(u) else - u = UInt32(c) + u = codepoint(c) end h = string(u, base = 16, pad = u ≤ 0xffff ? 4 : 6) print(io, (isascii(c) ? "ASCII/" : ""), "Unicode U+", h) diff --git a/base/exports.jl b/base/exports.jl index b7d3241a7eeba..d030e36131e7b 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -563,6 +563,7 @@ export bytes2hex, chomp, chop, + codepoint, codeunit, codeunits, digits, diff --git a/doc/src/base/strings.md b/doc/src/base/strings.md index 146372720d391..816f607e915c6 100644 --- a/doc/src/base/strings.md +++ b/doc/src/base/strings.md @@ -3,6 +3,7 @@ ```@docs Core.AbstractChar Core.Char +Base.codepoint Base.length(::AbstractString) Base.sizeof(::AbstractString) Base.:*(::Union{AbstractChar, AbstractString}, ::Union{AbstractChar, AbstractString}...) diff --git a/test/char.jl b/test/char.jl index 751de8e8b0fb3..cfcbe489a27b6 100644 --- a/test/char.jl +++ b/test/char.jl @@ -263,7 +263,7 @@ Base.UInt32(c::ASCIIChar) = UInt32(UInt8(c)) @test isascii(ASCIIChar('x')) @test ASCIIChar('x') < 'y' - @test ASCIIChar('x') == 'x' === Char(ASCIIChar('x')) + @test ASCIIChar('x') == 'x' === Char(ASCIIChar('x')) == convert(Char, ASCIIChar('x')) @test ASCIIChar('x')^3 == "xxx" @test repr(ASCIIChar('x')) == "'x'" @test string(ASCIIChar('x')) == "x" From bd21bf9c8b9f48476671f28685defe98184b3c80 Mon Sep 17 00:00:00 2001 From: "Steven G. Johnson" Date: Fri, 2 Mar 2018 23:13:49 -0500 Subject: [PATCH 8/8] more tests, fixes --- base/char.jl | 9 +++++---- test/char.jl | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/base/char.jl b/base/char.jl index 84eb0d2c2f32a..a93cb0d1b2330 100644 --- a/base/char.jl +++ b/base/char.jl @@ -20,11 +20,12 @@ representable in a given `AbstractChar` type. Internally, an `AbstractChar` type may use a variety of encodings. Conversion via `codepoint(char)` will not reveal this encoding because it always returns the Unicode value of the character. `print(io, c)` of any `c::AbstractChar` -produces UTF-8 output by default (via conversion to `Char` if necessary). +produces an encoding determined by `io` (UTF-8 for all built-in [`IO`](@ref) +types), via conversion to `Char` if necessary. -`write(io, c)`, in contrast, may emit a different encoding depending on +`write(io, c)`, in contrast, may emit an encoding depending on `typeof(c)`, and `read(io, typeof(c))` should read the same encoding as `write`. -New `AbstractChar` types should typically provide their own implementations of +New `AbstractChar` types must provide their own implementations of `write` and `read`. """ AbstractChar @@ -44,7 +45,7 @@ represents a valid Unicode character. """ Char -(::Type{T})(x::Integer) where {T<:AbstractChar} = T(UInt32(x)) +(::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x)) (::Type{AbstractChar})(x::Number) = Char(x) (::Type{T})(x::AbstractChar) where {T<:Union{Number,AbstractChar}} = T(codepoint(x)) (::Type{T})(x::T) where {T<:AbstractChar} = x diff --git a/test/char.jl b/test/char.jl index cfcbe489a27b6..19ee3d3215f99 100644 --- a/test/char.jl +++ b/test/char.jl @@ -255,16 +255,17 @@ end primitive type ASCIIChar <: AbstractChar 8 end ASCIIChar(c::UInt8) = reinterpret(ASCIIChar, c) ASCIIChar(c::UInt32) = ASCIIChar(UInt8(c)) -Base.UInt8(c::ASCIIChar) = reinterpret(UInt8, c) -Base.UInt32(c::ASCIIChar) = UInt32(UInt8(c)) +Base.codepoint(c::ASCIIChar) = reinterpret(UInt8, c) @testset "abstractchar" begin @test AbstractChar('x') === AbstractChar(UInt32('x')) === 'x' @test isascii(ASCIIChar('x')) @test ASCIIChar('x') < 'y' - @test ASCIIChar('x') == 'x' === Char(ASCIIChar('x')) == convert(Char, ASCIIChar('x')) + @test ASCIIChar('x') == 'x' === Char(ASCIIChar('x')) === convert(Char, ASCIIChar('x')) @test ASCIIChar('x')^3 == "xxx" @test repr(ASCIIChar('x')) == "'x'" @test string(ASCIIChar('x')) == "x" + @test_throws MethodError write(IOBuffer(), ASCIIChar('x')) + @test_throws MethodError read(IOBuffer('x'), ASCIIChar) end