@@ -40,7 +40,10 @@ class ExhaustedSpaceError < StandardError; end
40
40
# @option opts :char_set [String]
41
41
def initialize ( opts = { } )
42
42
# 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 = { }
44
47
45
48
@opts = DefaultOpts . merge ( opts )
46
49
if @opts [ :min_length ] < 1 || @opts [ :max_length ] < 1 || @opts [ :max_length ] < @opts [ :min_length ]
@@ -71,11 +74,12 @@ def initialize(opts={})
71
74
# you weren't generating it.
72
75
# @return [String]
73
76
def get ( name )
74
- return @identifiers [ name ] if @identifiers [ name ]
77
+ return @value_by_name [ name ] if @value_by_name [ name ]
75
78
76
- @identifiers [ name ] = generate
79
+ @value_by_name [ name ] = generate
80
+ @name_by_value [ @value_by_name [ name ] ] = name
77
81
78
- @identifiers [ name ]
82
+ @value_by_name [ name ]
79
83
end
80
84
alias [] get
81
85
@@ -93,13 +97,14 @@ def get(name)
93
97
# @return [void]
94
98
def store ( name , value )
95
99
96
- case @identifiers . key ( value )
100
+ case @name_by_value [ value ]
97
101
when name
98
102
# we already have this value and it is associated with this name
99
103
# nothing to do here
100
104
when nil
101
105
# 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
103
108
else
104
109
# then the caller is trying to insert a duplicate
105
110
raise RuntimeError , "Value is not unique!"
@@ -137,16 +142,15 @@ def store(name, value)
137
142
# you to modify the value and still avoid collisions.
138
143
def generate ( len = nil )
139
144
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
141
146
142
147
# pick a random length within the limits
143
148
len ||= rand ( @opts [ :min_length ] .. ( @opts [ :max_length ] ) )
144
149
145
150
ident = ""
146
151
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.
150
154
loop do
151
155
ident = Rex ::Text . rand_base ( 1 , "" , @opts [ :first_char_set ] )
152
156
ident << Rex ::Text . rand_base ( len -1 , "" , @opts [ :char_set ] )
@@ -155,7 +159,7 @@ def generate(len=nil)
155
159
end
156
160
# Try to make another one if it collides with a previously
157
161
# generated one.
158
- break unless @identifiers . value ?( ident )
162
+ break unless @name_by_value . key ?( ident )
159
163
end
160
164
161
165
ident
0 commit comments