/StaticStorages.jl

Primary LanguageJuliaMIT LicenseMIT

StaticStorages

StaticStorages.jl provides a general mechanism for providing static storages allocated at code-definition (macro expansion) time. These storages are discoverable across packages. It is useful for inserting performance counters and event trackers in distinct packages.

Usage

Arbitrary objects can be stored via put! and retrieved via get:

julia> using StaticStorages

julia> key = StaticStorages.put!(@__MODULE__, [123]);

julia> StaticStorages.get(key) == [123]
true

julia> push!(StaticStorages.get(key), 456);

julia> StaticStorages.get(key) == [123, 456]
true

A unique bucket can be allocated with StaticStorages.BucketKey().

julia> using StaticStorages

julia> bucketkey = StaticStorages.BucketKey();

julia> key = StaticStorages.put!(@__MODULE__, bucketkey, []);

julia> StaticStorages.get(bucketkey, key) == []
true

julia> StaticStorages.getbucket(bucketkey)[key] == []
true

Implementing per-location counter

module CounterDemo

using StaticStorages

const COUNTER_BUCKET = StaticStorages.BucketKey()

macro count()
    counter = Threads.Atomic{UInt}(0)  # allocate a "static storage" at macro expansion time
    key = StaticStorages.put!(__module__, COUNTER_BUCKET, counter)
    quote
        $(QuoteNode(counter))[] += 1
        $(QuoteNode(key))
    end
end

counters() = StaticStorages.getbucket(COUNTER_BUCKET)

end  # module CounterDemo


count_user_a() = CounterDemo.@count
count_user_b() = CounterDemo.@count

ka = count_user_a()
kb = count_user_b()
count_user_b()
count_user_a()
count_user_a()

println("count_user_a() called ", CounterDemo.counters()[ka][], " times")
println("count_user_b() called ", CounterDemo.counters()[kb][], " times")

# output

count_user_a() called 3 times
count_user_b() called 2 times

In a more practical example, the object put via StaticStorages.put! can also contain meta information such as the file and the line number (__source__). A global summary can then be generated by iterating over the entry in the dictionary returned from StaticStorages.getbucket.

Note that even though __module__ is passed to StaticStorages.put!, the bucket returned from StaticStorages.getbucket contains all values added by StaticStorages.put! in all modules and packages.

Implementation details

StaticStorages.jl stores the values in a global dictionary. The import hook is used for merging the values generated during precompilation. However, it does not interfere with user-defined __init__ function.