class Concurrent::RubyThreadLocalVar

@!macro internal_implementation_note
@!visibility private

def self.thread_finalizer(array)

@!visibility private
def self.thread_finalizer(array)
  proc do
    Thread.new do # avoid error: can't be called from trap context
      LOCK.synchronize do
        # The thread which used this thread-local array is now gone
        # So don't hold onto a reference to the array (thus blocking GC)
        ARRAYS.delete(array.object_id)
      end
    end
  end
end

def self.threadlocal_finalizer(index)

@!visibility private
def self.threadlocal_finalizer(index)
  proc do
    Thread.new do # avoid error: can't be called from trap context
      LOCK.synchronize do
        FREE.push(index)
        # The cost of GC'ing a TLV is linear in the number of threads using TLVs
        # But that is natural! More threads means more storage is used per TLV
        # So naturally more CPU time is required to free more storage
        ARRAYS.each_value do |array|
          array[index] = nil
        end
      end
    end
  end
end

def allocate_storage

@!visibility private
def allocate_storage
  @index = LOCK.synchronize do
    FREE.pop || begin
      result = @@next
      @@next += 1
      result
    end
  end
  ObjectSpace.define_finalizer(self, self.class.threadlocal_finalizer(@index))
end

def default_for(thread)

def default_for(thread)
  if @default_block
    raise "Cannot use default_for with default block"
  else
    @default
  end
end

def get_threadlocal_array(thread = Thread.current)

def get_threadlocal_array(thread = Thread.current)
  thread.thread_variable_get(:__threadlocal_array__)
end

def get_threadlocal_array(thread = Thread.current)

def get_threadlocal_array(thread = Thread.current)
  thread[:__threadlocal_array__]
end

def set_threadlocal_array(array, thread = Thread.current)

def set_threadlocal_array(array, thread = Thread.current)
  thread.thread_variable_set(:__threadlocal_array__, array)
end

def set_threadlocal_array(array, thread = Thread.current)

def set_threadlocal_array(array, thread = Thread.current)
  thread[:__threadlocal_array__] = array
end

def value

@!macro thread_local_var_method_get
def value
  if array = get_threadlocal_array
    value = array[@index]
    if value.nil?
      default
    elsif value.equal?(NULL)
      nil
    else
      value
    end
  else
    default
  end
end

def value=(value)

@!macro thread_local_var_method_set
def value=(value)
  me = Thread.current
  # We could keep the thread-local arrays in a hash, keyed by Thread
  # But why? That would require locking
  # Using Ruby's built-in thread-local storage is faster
  unless array = get_threadlocal_array(me)
    array = set_threadlocal_array([], me)
    LOCK.synchronize { ARRAYS[array.object_id] = array }
    ObjectSpace.define_finalizer(me, self.class.thread_finalizer(array))
  end
  array[@index] = (value.nil? ? NULL : value)
  value
end

def value_for(thread)

@!visibility private
This exists only for use in testing
def value_for(thread)
  if array = get_threadlocal_array(thread)
    value = array[@index]
    if value.nil?
      default_for(thread)
    elsif value.equal?(NULL)
      nil
    else
      value
    end
  else
    default_for(thread)
  end
end