Skip to content

Commit

Permalink
FEATURE: add interface compatible constant version of thread local var
Browse files Browse the repository at this point in the history
ThreadLocalVar can be expensive as it spins a thread in finalizers. In some
cases consumers may want to swap in a constant value implementations that
is very cheap.

`Concurrent::ConstantThreadLocalVar` is interface compatible with
AbstractThreadLocalVar, however does not allow any changing of .value
  • Loading branch information
SamSaffron committed Sep 13, 2019
1 parent bbeacbc commit db332e8
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
35 changes: 35 additions & 0 deletions lib/concurrent/atomic/constant_thread_local_var.rb
@@ -0,0 +1,35 @@
require 'concurrent/atomic/abstract_thread_local_var'

module Concurrent
class ConstantThreadLocalVar < AbstractThreadLocalVar
def value
default
end

def value=(value)
if value != default
raise ArgumentError, "Constant thread local vars may not be altered"
end
end

def bind(value)
self.value = value
if block_given?
yield
end
end

protected
def allocate_storage
# nothing to do
end

def default
if @default_block
@default_block.call
else
@default
end
end
end
end
1 change: 1 addition & 0 deletions lib/concurrent/atomics.rb
Expand Up @@ -8,3 +8,4 @@
require 'concurrent/atomic/reentrant_read_write_lock'
require 'concurrent/atomic/semaphore'
require 'concurrent/atomic/thread_local_var'
require 'concurrent/atomic/constant_thread_local_var'
56 changes: 56 additions & 0 deletions spec/concurrent/atomic/constant_thread_local_var_spec.rb
@@ -0,0 +1,56 @@
require 'rbconfig'

module Concurrent

require 'concurrent/atomic/constant_thread_local_var'

RSpec.describe ConstantThreadLocalVar do

context "#value" do
it 'can return default value' do
v = described_class.new("apple")
expect(v.value).to eq("apple")

v = described_class.new do
"orange"
end
expect(v.value).to eq("orange")
end
end

context "#value=" do
it 'can set value to same value' do
v = described_class.new("apple")
v.value = "apple"
end

it 'will raise an ArgumentError when attempting to change immutable value' do
v = described_class.new do
"apple"
end

expect do
v.value = "orange"
end.to raise_error(ArgumentError)
end
end

context '#bind' do
it 'will raise when attempting to bind to a different value' do
v = described_class.new("apple")
expect do
v.bind("orange") {}
end.to raise_error(ArgumentError)
end

it 'works when bind value is the same' do

v = described_class.new("apple")
v.bind("apple") do
expect(v.value).to eq("apple")
end
end
end
end

end

0 comments on commit db332e8

Please sign in to comment.