Skip to content

Commit

Permalink
Fix Atomic#swap with reference types (#6428)
Browse files Browse the repository at this point in the history
  • Loading branch information
JacobUb authored and Serdar Dogruyol committed Jul 28, 2018
1 parent 077920d commit e8ec7f2
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 1 deletion.
16 changes: 16 additions & 0 deletions spec/std/atomic_spec.cr
Expand Up @@ -169,4 +169,20 @@ describe Atomic do
atomic.swap(2).should eq(1)
atomic.get.should eq(2)
end

it "#swap with Reference type" do
atomic = Atomic.new("hello")
atomic.swap("world").should eq("hello")
atomic.get.should eq("world")
end

it "#swap with nil" do
atomic = Atomic(String?).new(nil)

atomic.swap("not nil").should eq(nil)
atomic.get.should eq("not nil")

atomic.swap(nil).should eq("not nil")
atomic.get.should eq(nil)
end
end
7 changes: 6 additions & 1 deletion src/atomic.cr
Expand Up @@ -157,7 +157,12 @@ struct Atomic(T)
# atomic.get # => 10
# ```
def swap(value : T)
Ops.atomicrmw(:xchg, pointerof(@value), value, :sequentially_consistent, false)
{% if T.union? && T.union_types.all? { |t| t == Nil || t < Reference } || T < Reference %}
address = Ops.atomicrmw(:xchg, pointerof(@value).as(LibC::SizeT*), LibC::SizeT.new(value.as(T).object_id), :sequentially_consistent, false)
Pointer(T).new(address).as(T)
{% else %}
Ops.atomicrmw(:xchg, pointerof(@value), value, :sequentially_consistent, false)
{% end %}
end

# Atomically sets this atomic's value to *value*. Returns the **new** value.
Expand Down

0 comments on commit e8ec7f2

Please sign in to comment.