mirror of
https://github.com/mistergibson/gxg-web-client.git
synced 2026-08-15 03:26:00 -07:00
188 lines
4.3 KiB
Ruby
188 lines
4.3 KiB
Ruby
class Rubinius::Randomizer
|
|
def self.allocate
|
|
Rubinius.primitive :randomizer_allocate
|
|
raise PrimitiveFailure, "Randomizer.allocate primitive failed"
|
|
end
|
|
|
|
def initialize
|
|
self.seed = generate_seed
|
|
end
|
|
|
|
private :initialize
|
|
|
|
attr_reader :seed
|
|
def seed=(new_seed)
|
|
set_seed new_seed
|
|
@seed = new_seed
|
|
end
|
|
|
|
def set_seed(new_seed)
|
|
Rubinius.primitive :randomizer_seed
|
|
raise PrimitiveFailure, "Randomizer#seed primitive failed"
|
|
end
|
|
|
|
def swap_seed(new_seed)
|
|
old_seed = self.seed
|
|
self.seed = new_seed
|
|
old_seed
|
|
end
|
|
|
|
def random(limit)
|
|
if undefined.equal?(limit)
|
|
random_float
|
|
else
|
|
if limit.kind_of?(Range)
|
|
if time_value?(limit.min)
|
|
random_time_range(limit)
|
|
else
|
|
random_range(limit)
|
|
end
|
|
elsif limit.kind_of?(Float)
|
|
raise ArgumentError, "invalid argument - #{limit}" if limit <= 0
|
|
random_float * limit
|
|
elsif limit.is_a?(Integer)
|
|
raise ArgumentError, "invalid argument - #{limit}" if limit <= 0
|
|
random_integer(limit - 1)
|
|
elsif limit.respond_to?(:to_f)
|
|
raise ArgumentError, "invalid argument - #{limit}" if limit <= 0
|
|
random_float * limit
|
|
else
|
|
limit_int = Rubinius::Type.coerce_to limit, Integer, :to_int
|
|
raise ArgumentError, "invalid argument - #{limit}" if limit_int <= 0
|
|
|
|
random_integer(limit_int - 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Generate a random Float, in the range 0...1.0
|
|
def random_float
|
|
Rubinius.primitive :randomizer_rand_float
|
|
raise PrimitiveFailure, "Randomizer#rand_float primitive failed"
|
|
end
|
|
|
|
# Generate a random Integer, in the range 0...limit
|
|
def random_integer(limit)
|
|
Rubinius.primitive :randomizer_rand_int
|
|
raise PrimitiveFailure, "Randomizer#rand_int primitive failed"
|
|
end
|
|
|
|
def random_range(limit)
|
|
return nil if limit.first.nil? || limit.last.nil?
|
|
|
|
min, max = limit.last.coerce(limit.first)
|
|
diff = max - min
|
|
|
|
return if diff < 0
|
|
return min if diff == 0
|
|
|
|
diff += 1 if max.kind_of?(Integer) && !limit.exclude_end?
|
|
random(diff) + min
|
|
end
|
|
|
|
def generate_seed
|
|
Rubinius.primitive :randomizer_gen_seed
|
|
raise PrimitiveFailure, "Randomizer#gen_seed primitive failed"
|
|
end
|
|
|
|
##
|
|
# Returns a random value from a range made out of Time, Date or DateTime
|
|
# instances.
|
|
#
|
|
# @param [Range] range
|
|
# @return [Time|Date|DateTime]
|
|
#
|
|
def random_time_range(range)
|
|
min = time_to_float(range.min)
|
|
max = time_to_float(range.max)
|
|
time = Time.at(random(min..max))
|
|
|
|
if Object.const_defined?(:DateTime) && range.min.is_a?(DateTime)
|
|
time = time.to_datetime
|
|
elsif Object.const_defined?(:DateTime) && range.min.is_a?(Date)
|
|
time = time.to_date
|
|
end
|
|
|
|
return time
|
|
end
|
|
|
|
##
|
|
# Casts a Time/Date/DateTime instance to a Float.
|
|
#
|
|
# @param [Time|Date|DateTime] input
|
|
# @return [Float]
|
|
#
|
|
def time_to_float(input)
|
|
return input.respond_to?(:to_time) ? input.to_time.to_f : input.to_f
|
|
end
|
|
|
|
##
|
|
# Checks if a given value is a Time, Date or DateTime object.
|
|
#
|
|
# @param [Mixed] input
|
|
# @return [TrueClass|FalseClass]
|
|
#
|
|
def time_value?(input)
|
|
return input.is_a?(Time) || (Object.const_defined?(:Date) && input.is_a?(Date))
|
|
end
|
|
end
|
|
|
|
class Random
|
|
def self.new_seed
|
|
Thread.current.randomizer.generate_seed
|
|
end
|
|
|
|
def self.srand(seed=undefined)
|
|
if undefined.equal? seed
|
|
seed = Thread.current.randomizer.generate_seed
|
|
end
|
|
|
|
seed = Rubinius::Type.coerce_to seed, Integer, :to_int
|
|
Thread.current.randomizer.swap_seed seed
|
|
end
|
|
|
|
def self.rand(limit=undefined)
|
|
Thread.current.randomizer.random(limit)
|
|
end
|
|
|
|
def initialize(seed=undefined)
|
|
@randomizer = Rubinius::Randomizer.new
|
|
if !undefined.equal?(seed)
|
|
@randomizer.swap_seed seed.to_int
|
|
end
|
|
end
|
|
|
|
private :initialize
|
|
|
|
def rand(limit=undefined)
|
|
@randomizer.random(limit)
|
|
end
|
|
|
|
def seed
|
|
@randomizer.seed
|
|
end
|
|
|
|
def state
|
|
@randomizer.seed
|
|
end
|
|
private :state
|
|
|
|
def ==(other)
|
|
return false unless other.kind_of?(Random)
|
|
seed == other.seed
|
|
end
|
|
|
|
# Returns a random binary string.
|
|
# The argument size specified the length of the result string.
|
|
def bytes(length)
|
|
length = Rubinius::Type.coerce_to length, Integer, :to_int
|
|
s = ''
|
|
i = 0
|
|
while i < length
|
|
s << @randomizer.random_integer(255).chr
|
|
i += 1
|
|
end
|
|
|
|
s
|
|
end
|
|
end
|