Array types that can use sentinel values of the element type for special values
The package is registered in the General registry and so can be installed at the REPL with ] add SentinelArrays.
SentinelArray(A::AbstractArray, sentinel, value)
SentinelVector{T}(undef, len, sentinel, value)
SentinelArray{T, N}(undef, dims, sentinel, value)
Construct a SentinelArray by either wrapping an existing AbstractArray or using the standard undef pattern, which first constructs an Array to be wrapped by SentinelArray.
A SentinelArray{T} wraps an AbstractArray of type T, and accepts a sentinel and value argument. If the wrapped array has an element equal to sentinel, value is returned instead.
This allows, for example, simulating a Vector{Union{Float64, Missing}} by doing something like SentinelVector{Float64}(undef, len, NaN, missing). The resulting SentinelArray will have
eltype equal to Union{T, typeof(value)}.
For isbits types, a random/reasonable sentinel will be attempted if none provided. For non-isbits, #undef is used as sentinel. The default value, if not provided, is missing.
A SentinelArray allows setting an element to value, which will result in the sentinel being stored in the wrapped array.
For isbits element types, if a setindex! operation is attempted with the SentinelArray's current sentinel value, another sentinel will be attempted to be chosen that doesn't already exist in the wrapped array.
If another sentinel can't be found (i.e. the values already exist in the wrapped array), an error will be thrown.
- For float and date/time types, reasonable sentinels exist that don't have meaningful real values, so it's recommended to use the default sentinels
- For
Integertypes, all bit patterns are valid, so a random value is chosen; if usage will involve extremely high cardinality relative to the type range, consider usingVector{Union{T, Missing}}instead SentinelArrays are not allowed to have plainBoolelements since there isn't a possible sentinel- A
SentinelArrayIS NOT thread-safe when usage relies onsetindex!and potential sentinel collision (due to the check to automatically cycle the sentinel to another value); this will normally only affect smallIntegerelement types where the potential for sentinel collision is highest - Access to a
SentinelArray's raw data is possible viaparent(A)orpointer(A), but note that the raw data will NOT respect the sentinel=>value semantics; i.e. the raw data may have entries of the sentinel value.
- It is generally recommended to use
Vector{Union{T, typeof(value}}instead ofSentinelArrayif possible - Currently, a non-copying operation like
convert(Vector{T}, A::Vector{Union{T, Missing}})isn't possible, even though you may know there aren'tmissingvalues; aSentinelArrayallows this operation by just "unwrapping" the storage array, likeparent(A) - It's also currently not possible to use
Vector{Union{T, Missing}}withMmap.mmap; withSentinelArray, you can write the parent array to disk and then doSentinelArray(Mmap.mmap(array_type, file))(assuming usage of default sentinel/value)
# initialize a new SentinelArray with default sentinel/value
A = SentinelVector{Float64}(undef, 10)
# wrap an existing array, manually providing sentinel/value
parent = zeros(UInt8, 10)
B = SentinelArray(parent, typemax(UInt8), nothing)The package is tested against Julia 1.0, current stable release, and nightly on Linux, OS X, and Windows.
Contributions are very welcome, as are feature requests and suggestions. Please open an issue if you encounter any problems or would just like to ask a question.