Skip to content

Commit 4cc179a

Browse files
committed
Store inverted hash for better lookups
Also clarifies comment about infinite loops
1 parent afa6a36 commit 4cc179a

File tree

1 file changed

+15
-11
lines changed

1 file changed

+15
-11
lines changed

lib/rex/random_identifier_generator.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ class ExhaustedSpaceError < StandardError; end
4040
# @option opts :char_set [String]
4141
def initialize(opts={})
4242
# Holds all identifiers.
43-
@identifiers = {}
43+
@value_by_name = {}
44+
# Inverse of value_by_name so we can ensure uniqueness without
45+
# having to search through the whole list of values
46+
@name_by_value = {}
4447

4548
@opts = DefaultOpts.merge(opts)
4649
if @opts[:min_length] < 1 || @opts[:max_length] < 1 || @opts[:max_length] < @opts[:min_length]
@@ -71,11 +74,12 @@ def initialize(opts={})
7174
# you weren't generating it.
7275
# @return [String]
7376
def get(name)
74-
return @identifiers[name] if @identifiers[name]
77+
return @value_by_name[name] if @value_by_name[name]
7578

76-
@identifiers[name] = generate
79+
@value_by_name[name] = generate
80+
@name_by_value[@value_by_name[name]] = name
7781

78-
@identifiers[name]
82+
@value_by_name[name]
7983
end
8084
alias [] get
8185

@@ -93,13 +97,14 @@ def get(name)
9397
# @return [void]
9498
def store(name, value)
9599

96-
case @identifiers.key(value)
100+
case @name_by_value[value]
97101
when name
98102
# we already have this value and it is associated with this name
99103
# nothing to do here
100104
when nil
101105
# don't have this value yet, so go ahead and just insert
102-
@identifiers[name] = value
106+
@value_by_name[name] = value
107+
@name_by_value[value] = name
103108
else
104109
# then the caller is trying to insert a duplicate
105110
raise RuntimeError, "Value is not unique!"
@@ -137,16 +142,15 @@ def store(name, value)
137142
# you to modify the value and still avoid collisions.
138143
def generate(len=nil)
139144
raise ArgumentError, "len must be positive integer" if len && len < 1
140-
raise ExhaustedSpaceError if @identifiers.length >= @max_permutations
145+
raise ExhaustedSpaceError if @value_by_name.length >= @max_permutations
141146

142147
# pick a random length within the limits
143148
len ||= rand(@opts[:min_length] .. (@opts[:max_length]))
144149

145150
ident = ""
146151

147-
# XXX: infinite loop if we've exhausted the space. Mitigated by the
148-
# fact that you'd have to call generate at least 26*62 times (in the
149-
# case of 2-character names) to hit it with the default :char_set.
152+
# XXX: Infinite loop if block returns only values we've already
153+
# generated.
150154
loop do
151155
ident = Rex::Text.rand_base(1, "", @opts[:first_char_set])
152156
ident << Rex::Text.rand_base(len-1, "", @opts[:char_set])
@@ -155,7 +159,7 @@ def generate(len=nil)
155159
end
156160
# Try to make another one if it collides with a previously
157161
# generated one.
158-
break unless @identifiers.value?(ident)
162+
break unless @name_by_value.key?(ident)
159163
end
160164

161165
ident

0 commit comments

Comments
 (0)