diff --git a/src/corefunctionality.jl b/src/corefunctionality.jl index 911c270..8235c27 100644 --- a/src/corefunctionality.jl +++ b/src/corefunctionality.jl @@ -6,11 +6,9 @@ # NOTE: This code is carefully optimised. Do not tweak it (for readability or otherwise) without benchmarking @inline function intern!(wkd::WeakKeyDict{K}, key)::K where K - kk::K = convert(K, key) - lock(wkd.lock) # hand positioning the locks and unlocks (rather than do block or try finally, seems to be faster) - index = Base.ht_keyindex2(wkd.ht, kk) # returns index if present, or -index if not + index = Base.ht_keyindex2(wkd.ht, key) # returns index if present, or -index if not # note hash of weakref is equal to the hash of value, so avoid constructing it if not required if index > 0 # found it @@ -20,6 +18,7 @@ else # Not found, so add it, # and mark it as a reference we track to delete! + kk::K = convert(K, key) finalizer(kk, wkd.finalizer) # finalizer is set on the strong ref @inbounds Base._setindex!(wkd.ht, nothing, WeakRef(kk), -index) unlock(wkd.lock) @@ -40,19 +39,34 @@ end ################################### +""" + intern(s::T) + +Return a reference to a interned instance of `s`, +adding it to the interning pool if it did not already exist. +""" function intern(s::T)::T where T - intern!(get_pool(T), s) + intern(T, s) end -intern(s::String)=intern!(get_pool(String), s) # Break stack-overflow +""" + intern(::Type{T}, s) +Intern `s` as if it were type `T`, converting it if required. +Note that this will lead to unexpected behavour if the type of `s`, and `T`, +do not have equivalent equality and hash functions +(i.e. this is not safe if `hash(s) != hash(convert(T, s))`). +""" +function intern(::Type{T}, s)::T where T + intern!(get_pool(T), s) +end """ Substrings are interned as their parent string type """ function intern(substr::SubString{T})::T where T - intern(T(substr)) + intern(T, substr) end diff --git a/test/REQUIRE b/test/REQUIRE new file mode 100644 index 0000000..52bb338 --- /dev/null +++ b/test/REQUIRE @@ -0,0 +1 @@ +WeakRefStrings 0.4.4 \ No newline at end of file diff --git a/test/all_kinds_of_types.jl b/test/all_kinds_of_types.jl index 5b8607d..5bfc82f 100644 --- a/test/all_kinds_of_types.jl +++ b/test/all_kinds_of_types.jl @@ -7,12 +7,16 @@ using InternedStrings @test !(ex1==="ex") ex2 = intern("ex") @test ex1===ex2 + ex3 = intern(String, "ex") + @test ex1===ex3 @testset "type inference" begin @test ex1 isa String + @test ex2 isa String @inferred intern("ex") + @inferred intern(String, "ex") end end @@ -21,17 +25,33 @@ end @testset "SubString" begin aa1, bb1, cc1 = intern.(split("aa bb cc")) aa2, bb2, cc2 = intern.(split("aa bb cc")) + aa3, bb3, cc3 = intern.(String, split("aa bb cc")) @test bb1=="bb" @test !(bb1==="bb") @test bb1===bb2 + @test bb1===bb3 @testset "type inference" begin @test intern(split("aa bb cc")[1]) isa String @inferred intern(split("aa bb cc")[1]) + @test intern(String, split("aa bb cc")[1]) isa String + @inferred intern(String, split("aa bb cc")[1]) end end +@testset "WeakRefString" begin + using WeakRefStrings + s1 = "ex" + s2 = "ex" + ex1 = @inferred intern(String, WeakRefString(Vector{UInt8}(s1))) + @test ex1=="ex" + @test !(ex1===s1) + @test ex1 isa String + ex2 = @inferred intern(String, WeakRefString(Vector{UInt8}(s2))) + @test ex1===ex2 +end + #== Uncomment when https://github.com/JuliaLang/julia/issues/26939 is fixed @testset "BigFloat" begin let pi1 = intern(BigFloat(π))