Skip to content

Commit

Permalink
Add lazy string type
Browse files Browse the repository at this point in the history
  • Loading branch information
Keno committed Oct 31, 2019
1 parent 42e9490 commit d3b19f5
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 71 deletions.
4 changes: 4 additions & 0 deletions base/Base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ include("refpointer.jl")
include("checked.jl")
using .Checked

# Lazy strings
include("strings/lazy.jl")

# array structures
include("indices.jl")
include("array.jl")
Expand Down Expand Up @@ -154,6 +157,7 @@ include("dict.jl")
include("abstractset.jl")
include("set.jl")

# Strings
include("char.jl")
include("strings/basic.jl")
include("strings/string.jl")
Expand Down
34 changes: 20 additions & 14 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -740,19 +740,21 @@ end
# copy from an some iterable object into an AbstractArray
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
if (sstart < 1)
throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
throw(ArgumentError(LazyString("source start offset (",sstart,") is < 1")))
end
y = iterate(src)
for j = 1:(sstart-1)
if y === nothing
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",j-1)))
throw(ArgumentError(LazyString(
"source has fewer elements than required, ",
"expected at least ", sstart,", got ", j-1)))
end
y = iterate(src, y[2])
end
if y === nothing
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",sstart-1)))
throw(ArgumentError(LazyString(
"source has fewer elements than required, ",
"expected at least ",sstart," got ", sstart-1)))
end
i = Int(dstart)
while y !== nothing
Expand All @@ -766,19 +768,22 @@ end

# this method must be separate from the above since src might not have a length
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
", elements, but n should be nonnegative")))
n == 0 && return dest
dmax = dstart + n - 1
inds = LinearIndices(dest)
if (dstart inds || dmax inds) | (sstart < 1)
sstart < 1 && throw(ArgumentError(string("source start offset (",sstart,") is < 1")))
sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
sstart,") is < 1")))
throw(BoundsError(dest, dstart:dmax))
end
y = iterate(src)
for j = 1:(sstart-1)
if y === nothing
throw(ArgumentError(string("source has fewer elements than required, ",
"expected at least ",sstart,", got ",j-1)))
throw(ArgumentError(LazyString(
"source has fewer elements than required, ",
"expected at least ",sstart,", got ",j-1)))
end
y = iterate(src, y[2])
end
Expand Down Expand Up @@ -834,7 +839,8 @@ function copyto!(dest::AbstractArray, dstart::Integer,
src::AbstractArray, sstart::Integer,
n::Integer)
n == 0 && return dest
n < 0 && throw(ArgumentError(string("tried to copy n=", n, " elements, but n should be nonnegative")))
n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
n," elements, but n should be nonnegative")))
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
(checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
(checkbounds(Bool, srcinds, sstart) && checkbounds(Bool, srcinds, sstart+n-1)) || throw(BoundsError(src, sstart:sstart+n-1))
Expand All @@ -852,12 +858,12 @@ end
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
if length(ir_dest) != length(ir_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(ir_src)," and ",length(ir_dest),")")))
throw(ArgumentError(LazyString("source and destination must have same size (got ",
length(ir_src)," and ",length(ir_dest),")")))
end
if length(jr_dest) != length(jr_src)
throw(ArgumentError(string("source and destination must have same size (got ",
length(jr_src)," and ",length(jr_dest),")")))
throw(ArgumentError(LazyString("source and destination must have same size (got ",
length(jr_src)," and ",length(jr_dest),")")))
end
@boundscheck checkbounds(B, ir_dest, jr_dest)
@boundscheck checkbounds(A, ir_src, jr_src)
Expand Down
2 changes: 2 additions & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ add_with_overflow(x::T, y::T) where {T<:SignedInt} = checked_sadd_int(x, y)
add_with_overflow(x::T, y::T) where {T<:UnsignedInt} = checked_uadd_int(x, y)
add_with_overflow(x::Bool, y::Bool) = (x+y, false)

include("strings/lazy.jl")

# core array operations
include("indices.jl")
include("array.jl")
Expand Down
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export
IOStream,
LinRange,
Irrational,
LazyString,
Matrix,
MergeSort,
Missing,
Expand Down Expand Up @@ -938,6 +939,7 @@ export
@s_str, # regex substitution string
@v_str, # version number
@raw_str, # raw string with no interpolation/unescaping
@lazy_str, # lazy string

# documentation
@text_str,
Expand Down
11 changes: 6 additions & 5 deletions base/math.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ using Core.Intrinsics: sqrt_llvm
using .Base: IEEEFloat

@noinline function throw_complex_domainerror(f::Symbol, x)
throw(DomainError(x, string("$f will only return a complex result if called with a ",
"complex argument. Try $f(Complex(x)).")))
throw(DomainError(x,
LazyString(f," will only return a complex result if called with a complex argument. Try ", f,"(Complex(x)).")))
end
@noinline function throw_exp_domainerror(x)
throw(DomainError(x, string("Exponentiation yielding a complex result requires a ",
"complex argument.\nReplace x^y with (x+0im)^y, ",
"Complex(x)^y, or similar.")))
throw(DomainError(x, LazyString(
"Exponentiation yielding a complex result requires a ",
"complex argument.\nReplace x^y with (x+0im)^y, ",
"Complex(x)^y, or similar.")))
end

# non-type specific math functions
Expand Down
35 changes: 35 additions & 0 deletions base/strings/lazy.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
LazyString <: AbstractString
A lazy representation of string interpolation. This is useful when a string
needs to be constructed in a context where performing the actual interpolation
and string construction is unnecessary or undesirable (e.g. in error paths
of of functions).
This type is designed to be cheap to construct at runtime, trying to offload
as much work as possible to either the macro or later printing operations.
"""
struct LazyString <: AbstractString
parts::Tuple
LazyString(args...) = new(args)
end

macro lazy_str(string)
parts = Any[]
lastidx = idx = 1
while (idx = findnext('$', string, idx)) !== nothing
lastidx < idx && push!(parts, string[lastidx:idx-1])
idx += 1
expr, idx = Meta.parse(string, idx; greedy=false, raise=false)
push!(parts, esc(expr))
lastidx = idx
end
lastidx <= lastindex(string) && push!(parts, string[lastidx:end])
:(LazyString($(parts...)))
end

function print(io::IO, s::LazyString)
for part in s.parts
print(io, part)
end
end
Loading

0 comments on commit d3b19f5

Please sign in to comment.