Skip to content

Commit 789db44

Browse files
authored
Merge pull request #16 from TuringLang/csp/tref
TRefs for arbitrary storage
2 parents 05a2b90 + 689805e commit 789db44

File tree

3 files changed

+140
-1
lines changed

3 files changed

+140
-1
lines changed

src/Libtask.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module Libtask
22

3-
export consume, produce, TArray, get, tzeros, tfill
3+
export consume, produce, TArray, get, tzeros, tfill, TRef
44

55
include("../deps/deps.jl"); check_deps();
66
include("taskcopy.jl")

src/tref.jl

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
##########
2+
# TRef #
3+
##########
4+
5+
"""
6+
TRef(x)
7+
8+
Implementation of an abstract data structure that
9+
automatically performs copy-on-write after task copying.
10+
11+
Atomic (single-valued) TRef objects must be set or updated
12+
by indexing. For example, to access `val = TRef(1)`, you
13+
must use `val[]`.
14+
15+
Usage:
16+
17+
```julia
18+
TRef(x)
19+
```
20+
21+
Example:
22+
23+
```julia
24+
# Initialize an atomic value
25+
z = TRef(19.2)
26+
z[] += 31
27+
28+
# Initialize a multi-index object
29+
x = TRef([1 2 3; 4 5 6])
30+
x[1, 3] = 999
31+
32+
# Initialize a TRef holding a dictionary.
33+
d = TRef(Dict("A" => 1, 5 => "B"))
34+
d["A"] = 10
35+
```
36+
"""
37+
struct TRef
38+
ref :: Symbol # object_id
39+
orig_task :: Task
40+
TRef() = new(gensym(), current_task())
41+
end
42+
43+
function TRef(x)
44+
res = TRef();
45+
n = n_copies()
46+
task_local_storage(res.ref, (n,Ref(x)))
47+
return res
48+
end
49+
50+
function Base.getindex(S::TRef, I::Vararg{Any,N}) where {N}
51+
_, d = task_local_storage(S.ref)
52+
return d[][I...]
53+
end
54+
55+
function Base.setindex!(S::TRef, x, I::Vararg{Any,N}) where {N}
56+
n, d = task_local_storage(S.ref)
57+
cn = n_copies()
58+
newd = d
59+
if cn > n
60+
# println("[setindex!]: $(S.ref) copying data")
61+
newd = deepcopy(d)
62+
task_local_storage(S.ref, (cn, newd))
63+
end
64+
65+
if isa(newd[], Real)
66+
newd[] = x
67+
else
68+
setindex!(newd[], x, I...)
69+
end
70+
return newd[]
71+
end
72+
73+
function Base.display(S::TRef)
74+
display("Please use show(::TRef) instead.")
75+
end
76+
77+
Base.show(io::IO, S::TRef) = Base.show(io::IO, task_local_storage(S.ref)[2][])
78+
Base.size(S::TRef) = Base.size(task_local_storage(S.ref)[2][])
79+
Base.ndims(S::TRef) = Base.ndims(task_local_storage(S.ref)[2][])
80+
81+
Base.get(S::TRef) = (current_task().storage[S.ref][2][])
82+
83+
# Implements eltype, firstindex, lastindex, and iterate
84+
# functions.
85+
for F in (:eltype, :firstindex, :lastindex, :iterate)
86+
@eval Base.$F(a::TRef, args...) = $F(get(a), args...)
87+
end

test/tref.jl

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
using Libtask
2+
using Test
3+
4+
# Test atomic values.
5+
function f_cta()
6+
t = TRef(1);
7+
t[] = 0;
8+
while true
9+
produce(t[])
10+
t[]
11+
t[] += 1
12+
end
13+
end
14+
15+
t = Task(f_cta)
16+
17+
consume(t); consume(t)
18+
a = copy(t);
19+
consume(a); consume(a)
20+
21+
Base.@assert consume(t) == 2
22+
Base.@assert consume(a) == 4
23+
24+
# Test dictionary functionality.
25+
function dict_test()
26+
t = TRef(Dict("A" => 1, 5 => "B"));
27+
t["A"] = 0;
28+
while true
29+
produce(t["A"])
30+
t["A"]
31+
t["A"] += 1
32+
end
33+
end
34+
35+
t = Task(dict_test)
36+
37+
consume(t); consume(t)
38+
a = copy(t);
39+
consume(a); consume(a)
40+
41+
Base.@assert consume(t) == 2
42+
Base.@assert consume(a) == 4
43+
44+
# Create a TRef storing a matrix.
45+
x = TRef([1 2 3; 4 5 6])
46+
x[1, 3] = 900
47+
Base.@assert x[1,3] == 900
48+
49+
# TRef holding an array.
50+
y = TRef([1,2,3])
51+
y[2] = 19
52+
Base.@assert y[2] == 19

0 commit comments

Comments
 (0)