lib/concurrent/atomic/atomic_fixnum.rb



module Concurrent

  # @!macro [attach] atomic_fixnum
  #
  #   A numeric value that can be updated atomically. Reads and writes to an atomic
  #   fixnum and thread-safe and guaranteed to succeed. Reads and writes may block
  #   briefly but no explicit locking is required.
  #
  #   @since 0.5.0
  #   @see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicLong.html java.util.concurrent.atomic.AtomicLong
  class MutexAtomicFixnum

    # @!macro [attach] atomic_fixnum_method_initialize
    #
    # Creates a new `AtomicFixnum` with the given initial value.
    #
    # @param [Fixnum] init the initial value
    # @raise [ArgumentError] if the initial value is not a `Fixnum`
    def initialize(init = 0)
      raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
      @value = init
      @mutex = Mutex.new
    end

    # @!macro [attach] atomic_fixnum_method_value
    #
    #   Retrieves the current `Fixnum` value.
    #
    #   @return [Fixnum] the current value
    def value
      @mutex.lock
      result = @value
      @mutex.unlock

      result
    end

    # @!macro [attach] atomic_fixnum_method_value_eq
    #
    #   Explicitly sets the value.
    #
    #   @param [Fixnum] value the new value to be set
    #
    #   @return [Fixnum] the current value
    #
    #   @raise [ArgumentError] if the new value is not a `Fixnum`
    def value=(value)
      raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
      @mutex.lock
      result = @value = value
      @mutex.unlock

      result
    end

    # @!macro [attach] atomic_fixnum_method_increment
    #
    #   Increases the current value by 1.
    #
    #   @return [Fixnum] the current value after incrementation
    def increment
      @mutex.lock
      @value += 1
      result = @value
      @mutex.unlock

      result
    end

    alias_method :up, :increment

    # @!macro [attach] atomic_fixnum_method_decrement
    #
    #   Decreases the current value by 1.
    #
    #   @return [Fixnum] the current value after decrementation
    def decrement
      @mutex.lock
      @value -= 1
      result = @value
      @mutex.unlock

      result
    end

    alias_method :down, :decrement

    # @!macro [attach] atomic_fixnum_method_compare_and_set
    # 
    #   Atomically sets the value to the given updated value if the current
    #   value == the expected value.
    #
    #   @param [Fixnum] expect the expected value
    #   @param [Fixnum] update the new value
    #
    #   @return [Boolean] true if the value was updated else false 
    def compare_and_set(expect, update)

      @mutex.lock
      if @value == expect
        @value = update
        result = true
      else
        result = false
      end
      @mutex.unlock

      result
    end
  end

  if RUBY_PLATFORM == 'java'

    # @!macro atomic_fixnum
    class JavaAtomicFixnum

      # @!macro atomic_fixnum_method_initialize
      #
      def initialize(init = 0)
        raise ArgumentError.new('initial value must be a Fixnum') unless init.is_a?(Fixnum)
        @atomic = java.util.concurrent.atomic.AtomicLong.new(init)
      end

      # @!macro atomic_fixnum_method_value
      #
      def value
        @atomic.get
      end

      # @!macro atomic_fixnum_method_value_eq
      #
      def value=(value)
        raise ArgumentError.new('value must be a Fixnum') unless value.is_a?(Fixnum)
        @atomic.set(value)
      end

      # @!macro atomic_fixnum_method_increment
      #
      def increment
        @atomic.increment_and_get
      end

      alias_method :up, :increment

      # @!macro atomic_fixnum_method_decrement
      #
      def decrement
        @atomic.decrement_and_get
      end

      alias_method :down, :decrement

      # @!macro atomic_fixnum_method_compare_and_set
      #
      def compare_and_set(expect, update)
        @atomic.compare_and_set(expect, update)
      end
    end

    # @!macro atomic_fixnum
    class AtomicFixnum < JavaAtomicFixnum
    end

  else

    # @!macro atomic_fixnum
    class AtomicFixnum < MutexAtomicFixnum
    end
  end
end