@@ -15,11 +15,27 @@ def initialize
1515
1616 # Print a short summary of the list.
1717 def to_s
18- "#<#{ self . class . name } size= #{ @size } >"
18+ sprintf ( "#<%s:0x%x size=%d>" , self . class . name , object_id , @size )
1919 end
2020
2121 alias inspect to_s
2222
23+ # Fast, safe, unbounded accumulation of children.
24+ def to_a
25+ items = [ ]
26+ current = self
27+
28+ while current . tail != self
29+ unless current . tail . is_a? ( Iterator )
30+ items << current . tail
31+ end
32+
33+ current = current . tail
34+ end
35+
36+ return items
37+ end
38+
2339 # Points at the end of the list.
2440 attr_accessor :head
2541
@@ -118,31 +134,47 @@ def remove(node)
118134
119135 # @returns [Boolean] Returns true if the list is empty.
120136 def empty?
121- @tail . equal? ( self )
137+ @size == 0
122138 end
123139
124- # Iterate over each node in the linked list. It is generally safe to remove the current node, any previous node or any future node during iteration.
125- #
126- # @yields {|node| ...} Yields each node in the list.
127- # @returns [List] Returns self.
128- def each
129- return to_enum unless block_given?
130-
131- current = self
140+ def validate! ( node = nil )
141+ previous = self
142+ current = @tail
143+ found = node . equal? ( self )
132144
133145 while true
134- node = current . tail
135- # binding.irb if node.nil? && !node.equal?(self)
136- break if node . equal? ( self )
146+ break if current . equal? ( self )
147+
148+ if current . head != previous
149+ raise "Invalid previous linked list node!"
150+ end
137151
138- yield node
152+ if current . is_a? ( List ) and !current . equal? ( self )
153+ raise "Invalid list in list node!"
154+ end
139155
140- # If the node has deleted itself or any subsequent node, it will no longer be the next node, so don't use it for continued traversal:
141- if current . tail . equal? ( node )
142- current = node
156+ if node
157+ found ||= current . equal? ( node )
143158 end
159+
160+ previous = current
161+ current = current . tail
144162 end
145163
164+ if node and !found
165+ raise "Node not found in list!"
166+ end
167+ end
168+
169+ # Iterate over each node in the linked list. It is generally safe to remove the current node, any previous node or any future node during iteration.
170+ #
171+ # @yields {|node| ...} Yields each node in the list.
172+ # @returns [List] Returns self.
173+ def each ( &block )
174+ return to_enum unless block_given?
175+
176+ Iterator . each ( self , &block )
177+
146178 return self
147179 end
148180
@@ -160,22 +192,119 @@ def include?(needle)
160192
161193 # @returns [Node] Returns the first node in the list, if it is not empty.
162194 def first
163- unless @tail . equal? ( self )
164- @tail
195+ # validate!
196+
197+ current = @tail
198+
199+ while !current . equal? ( self )
200+ if current . is_a? ( Iterator )
201+ current = current . tail
202+ else
203+ return current
204+ end
165205 end
206+
207+ return nil
166208 end
167209
168210 # @returns [Node] Returns the last node in the list, if it is not empty.
169211 def last
170- unless @head . equal? ( self )
171- @head
212+ # validate!
213+
214+ current = @head
215+
216+ while !current . equal? ( self )
217+ if current . is_a? ( Iterator )
218+ current = current . head
219+ else
220+ return current
221+ end
172222 end
223+
224+ return nil
173225 end
174- end
175-
176- # A linked list Node.
177- class List ::Node
178- attr_accessor :head
179- attr_accessor :tail
226+
227+ def shift
228+ if node = first
229+ remove! ( node )
230+ end
231+ end
232+
233+ # A linked list Node.
234+ class Node
235+ attr_accessor :head
236+ attr_accessor :tail
237+
238+ alias inspect to_s
239+ end
240+
241+ class Iterator < Node
242+ def initialize ( list )
243+ @list = list
244+
245+ # Insert the iterator as the first item in the list:
246+ @tail = list . tail
247+ @tail . head = self
248+ list . tail = self
249+ @head = list
250+ end
251+
252+ def remove!
253+ @head . tail = @tail
254+ @tail . head = @head
255+ @head = nil
256+ @tail = nil
257+ @list = nil
258+ end
259+
260+ def move_next
261+ # Move to the next item (which could be an iterator or the end):
262+ @tail . head = @head
263+ @head . tail = @tail
264+ @head = @tail
265+ @tail = @tail . tail
266+ @head . tail = self
267+ @tail . head = self
268+ end
269+
270+ def move_current
271+ while true
272+ # Are we at the end of the list?
273+ if @tail . equal? ( @list )
274+ return nil
275+ end
276+
277+ if @tail . is_a? ( Iterator )
278+ move_next
279+ else
280+ return @tail
281+ end
282+ end
283+ end
284+
285+ def each
286+ while current = move_current
287+ yield current
288+
289+ if current . equal? ( @tail )
290+ move_next
291+ end
292+ end
293+ end
294+
295+ def self . each ( list , &block )
296+ list . validate!
297+
298+ return if list . empty?
299+
300+ iterator = Iterator . new ( list )
301+
302+ iterator . each ( &block )
303+ ensure
304+ iterator &.remove!
305+ end
306+ end
307+
308+ private_constant :Iterator
180309 end
181310end
0 commit comments