File: int_allocator.rb

package info (click to toggle)
ruby-amq-protocol 2.3.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 504 kB
  • sloc: ruby: 5,222; python: 248; makefile: 4
file content (85 lines) | stat: -rw-r--r-- 2,526 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# encoding: utf-8

require "amq/bit_set"

module AMQ
  # Simple bitset-based integer allocator, heavily inspired by com.rabbitmq.utility.IntAllocator class
  # in the RabbitMQ Java client.
  #
  # Unlike monotonically incrementing identifier, this allocator is suitable for very long running programs
  # that aggressively allocate and release channels.
  class IntAllocator

    #
    # API
    #

    # @return [Integer] Number of integers in the allocation range
    attr_reader :number_of_bits
    # @return [Integer] Upper boundary of the integer range available for allocation
    attr_reader :hi
    # @return [Integer] Lower boundary of the integer range available for allocation
    attr_reader :lo

    # @param [Integer] lo    Lower boundary of the integer range available for allocation
    # @param [Integer] hi    Upper boundary of the integer range available for allocation
    # @raise [ArgumentError] if upper boundary is not greater than the lower one
    def initialize(lo, hi)
      raise ArgumentError.new "upper boundary must be greater than the lower one (given: hi = #{hi}, lo = #{lo})" unless hi > lo

      @hi = hi
      @lo = lo

      @number_of_bits = hi - lo
      @range          = Range.new(1, @number_of_bits)
      @free_set       = BitSet.new(@number_of_bits)
    end # initialize(hi, lo)

    # Attempts to allocate next available integer. If allocation succeeds, allocated value is returned.
    # Otherwise, -1 is returned.
    #
    # Current implementation of this method is O(n), where n is number of bits in the range available for
    # allocation.
    #
    # @return [Integer] Allocated integer if allocation succeeded. -1 otherwise.
    def allocate

      if n = @free_set.next_clear_bit

        if n < @hi - 1 then
          @free_set.set(n)
          n + 1
        else
          -1
        end

      else
        -1
      end
    end # allocate

    # Releases previously allocated integer. If integer provided as argument was not previously allocated,
    # this method has no effect.
    #
    # @return [NilClass] nil
    def free(reservation)
      @free_set.unset(reservation-1)
    end # free(reservation)
    alias release free

    # @return [Boolean] true if provided argument was previously allocated, false otherwise
    def allocated?(reservation)
      @free_set.get(reservation-1)
    end # allocated?(reservation)

    # Releases the whole allocation range
    def reset
      @free_set.clear
    end # reset



    protected

  end # IntAllocator
end # AMQ