Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-enumerator / mrblib / enumerator.rb
1 ##
2 # enumerator.rb Enumerator class
3 # See Copyright Notice in mruby.h
4
5 ##
6 # A class which allows both internal and external iteration.
7 #
8 # An Enumerator can be created by the following methods.
9 # - {Kernel#to_enum}
10 # - {Kernel#enum_for}
11 # - {Enumerator#initialize Enumerator.new}
12 #
13 # Most methods have two forms: a block form where the contents
14 # are evaluated for each item in the enumeration, and a non-block form
15 # which returns a new Enumerator wrapping the iteration.
16 #
17 #       enumerator = %w(one two three).each
18 #       puts enumerator.class # => Enumerator
19 #
20 #       enumerator.each_with_object("foo") do |item, obj|
21 #         puts "#{obj}: #{item}"
22 #       end
23 #
24 #       # foo: one
25 #       # foo: two
26 #       # foo: three
27 #
28 #       enum_with_obj = enumerator.each_with_object("foo")
29 #       puts enum_with_obj.class # => Enumerator
30 #
31 #       enum_with_obj.each do |item, obj|
32 #         puts "#{obj}: #{item}"
33 #       end
34 #
35 #       # foo: one
36 #       # foo: two
37 #       # foo: three
38 #
39 # This allows you to chain Enumerators together.  For example, you
40 # can map a list's elements to strings containing the index
41 # and the element as a string via:
42 #
43 #       puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
44 #       # => ["0:foo", "1:bar", "2:baz"]
45 #
46 # An Enumerator can also be used as an external iterator.
47 # For example, Enumerator#next returns the next value of the iterator
48 # or raises StopIteration if the Enumerator is at the end.
49 #
50 #       e = [1,2,3].each   # returns an enumerator object.
51 #       puts e.next   # => 1
52 #       puts e.next   # => 2
53 #       puts e.next   # => 3
54 #       puts e.next   # raises StopIteration
55 #
56 # You can use this to implement an internal iterator as follows:
57 #
58 #       def ext_each(e)
59 #         while true
60 #           begin
61 #             vs = e.next_values
62 #           rescue StopIteration
63 #             return $!.result
64 #           end
65 #           y = yield(*vs)
66 #           e.feed y
67 #         end
68 #       end
69 #
70 #       o = Object.new
71 #
72 #       def o.each
73 #         puts yield
74 #         puts yield(1)
75 #         puts yield(1, 2)
76 #         3
77 #       end
78 #
79 #       # use o.each as an internal iterator directly.
80 #       puts o.each {|*x| puts x; [:b, *x] }
81 #       # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
82 #
83 #       # convert o.each to an external iterator for
84 #       # implementing an internal iterator.
85 #       puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
86 #       # => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
87 #
88 class Enumerator
89   include Enumerable
90
91   ##
92   # @overload initialize(size = nil, &block)
93   # @overload initialize(obj, method = :each, *args)
94   #
95   # Creates a new Enumerator object, which can be used as an
96   # Enumerable.
97   #
98   # In the first form, iteration is defined by the given block, in
99   # which a "yielder" object, given as block parameter, can be used to
100   # yield a value by calling the +yield+ method (aliased as +<<+):
101   #
102   #     fib = Enumerator.new do |y|
103   #       a = b = 1
104   #       loop do
105   #         y << a
106   #         a, b = b, a + b
107   #       end
108   #     end
109   #
110   #     p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
111   #
112   # In the second, deprecated, form, a generated Enumerator iterates over the
113   # given object using the given method with the given arguments passed. This
114   # form is left only for internal use.
115   #
116   # Use of this form is discouraged.  Use Kernel#enum_for or Kernel#to_enum
117   # instead.
118   def initialize(obj=NONE, meth=:each, *args, &block)
119     if block
120       obj = Generator.new(&block)
121     elsif obj == NONE
122       raise ArgumentError, "wrong number of arguments (given 0, expected 1+)"
123     end
124
125     @obj = obj
126     @meth = meth
127     @args = args
128     @fib = nil
129     @dst = nil
130     @lookahead = nil
131     @feedvalue = nil
132     @stop_exc = false
133   end
134   attr_accessor :obj, :meth, :args
135   attr_reader :fib
136
137   def initialize_copy(obj)
138     raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator
139     raise TypeError, "can't copy execution context" if obj.fib
140     @obj = obj.obj
141     @meth = obj.meth
142     @args = obj.args
143     @fib = nil
144     @lookahead = nil
145     @feedvalue = nil
146     self
147   end
148
149   ##
150   # call-seq:
151   #   e.with_index(offset = 0) {|(*args), idx| ... }
152   #   e.with_index(offset = 0)
153   #
154   # Iterates the given block for each element with an index, which
155   # starts from +offset+.  If no block is given, returns a new Enumerator
156   # that includes the index, starting from +offset+
157   #
158   # +offset+:: the starting index to use
159   #
160   def with_index(offset=0, &block)
161     return to_enum :with_index, offset unless block
162
163     if offset.nil?
164       offset = 0
165     else
166       offset = offset.__to_int
167     end
168
169     n = offset - 1
170     enumerator_block_call do |*i|
171       n += 1
172       block.call i.__svalue, n
173     end
174   end
175
176   ##
177   # call-seq:
178   #   e.each_with_index {|(*args), idx| ... }
179   #   e.each_with_index
180   #
181   # Same as Enumerator#with_index(0), i.e. there is no starting offset.
182   #
183   # If no block is given, a new Enumerator is returned that includes the index.
184   #
185   def each_with_index(&block)
186     with_index(0, &block)
187   end
188
189   ##
190   # call-seq:
191   #   e.each_with_object(obj) {|(*args), obj| ... }
192   #   e.each_with_object(obj)
193   #   e.with_object(obj) {|(*args), obj| ... }
194   #   e.with_object(obj)
195   #
196   # Iterates the given block for each element with an arbitrary object, +obj+,
197   # and returns +obj+
198   #
199   # If no block is given, returns a new Enumerator.
200   #
201   # @example
202   #   to_three = Enumerator.new do |y|
203   #     3.times do |x|
204   #       y << x
205   #     end
206   #   end
207   #
208   #   to_three_with_string = to_three.with_object("foo")
209   #   to_three_with_string.each do |x,string|
210   #     puts "#{string}: #{x}"
211   #   end
212   #
213   #   # => foo:0
214   #   # => foo:1
215   #   # => foo:2
216   #
217   def with_object(object, &block)
218     return to_enum(:with_object, object) unless block
219
220     enumerator_block_call do |i|
221       block.call [i,object]
222     end
223     object
224   end
225
226   def inspect
227     if @args && @args.size > 0
228       args = @args.join(", ")
229       "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>"
230     else
231       "#<#{self.class}: #{@obj.inspect}:#{@meth}>"
232     end
233   end
234
235   ##
236   # call-seq:
237   #   enum.each { |elm| block }                    -> obj
238   #   enum.each                                    -> enum
239   #   enum.each(*appending_args) { |elm| block }   -> obj
240   #   enum.each(*appending_args)                   -> an_enumerator
241   #
242   # Iterates over the block according to how this Enumerator was constructed.
243   # If no block and no arguments are given, returns self.
244   #
245   # === Examples
246   #
247   #   "Hello, world!".scan(/\w+/)                     #=> ["Hello", "world"]
248   #   "Hello, world!".to_enum(:scan, /\w+/).to_a      #=> ["Hello", "world"]
249   #   "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
250   #
251   #   obj = Object.new
252   #
253   #   def obj.each_arg(a, b=:b, *rest)
254   #     yield a
255   #     yield b
256   #     yield rest
257   #     :method_returned
258   #   end
259   #
260   #   enum = obj.to_enum :each_arg, :a, :x
261   #
262   #   enum.each.to_a                  #=> [:a, :x, []]
263   #   enum.each.equal?(enum)          #=> true
264   #   enum.each { |elm| elm }         #=> :method_returned
265   #
266   #   enum.each(:y, :z).to_a          #=> [:a, :x, [:y, :z]]
267   #   enum.each(:y, :z).equal?(enum)  #=> false
268   #   enum.each(:y, :z) { |elm| elm } #=> :method_returned
269   #
270   def each(*argv, &block)
271     obj = self
272     if 0 < argv.length
273       obj = self.dup
274       args = obj.args
275       if !args.empty?
276         args = args.dup
277         args.concat argv
278       else
279         args = argv.dup
280       end
281       obj.args = args
282     end
283     return obj unless block
284     enumerator_block_call(&block)
285   end
286
287   def enumerator_block_call(&block)
288     @obj.__send__ @meth, *@args, &block
289   end
290   private :enumerator_block_call
291
292   ##
293   # call-seq:
294   #   e.next   -> object
295   #
296   # Returns the next object in the enumerator, and move the internal position
297   # forward.  When the position reached at the end, StopIteration is raised.
298   #
299   # === Example
300   #
301   #   a = [1,2,3]
302   #   e = a.to_enum
303   #   p e.next   #=> 1
304   #   p e.next   #=> 2
305   #   p e.next   #=> 3
306   #   p e.next   #raises StopIteration
307   #
308   # Note that enumeration sequence by +next+ does not affect other non-external
309   # enumeration methods, unless the underlying iteration methods itself has
310   # side-effect
311   #
312   def next
313     next_values.__svalue
314   end
315
316   ##
317   # call-seq:
318   #   e.next_values   -> array
319   #
320   # Returns the next object as an array in the enumerator, and move the
321   # internal position forward.  When the position reached at the end,
322   # StopIteration is raised.
323   #
324   # This method can be used to distinguish <code>yield</code> and <code>yield
325   # nil</code>.
326   #
327   # === Example
328   #
329   #   o = Object.new
330   #   def o.each
331   #     yield
332   #     yield 1
333   #     yield 1, 2
334   #     yield nil
335   #     yield [1, 2]
336   #   end
337   #   e = o.to_enum
338   #   p e.next_values
339   #   p e.next_values
340   #   p e.next_values
341   #   p e.next_values
342   #   p e.next_values
343   #   e = o.to_enum
344   #   p e.next
345   #   p e.next
346   #   p e.next
347   #   p e.next
348   #   p e.next
349   #
350   #   ## yield args       next_values      next
351   #   #  yield            []               nil
352   #   #  yield 1          [1]              1
353   #   #  yield 1, 2       [1, 2]           [1, 2]
354   #   #  yield nil        [nil]            nil
355   #   #  yield [1, 2]     [[1, 2]]         [1, 2]
356   #
357   # Note that +next_values+ does not affect other non-external enumeration
358   # methods unless underlying iteration method itself has side-effect
359   #
360   def next_values
361     if @lookahead
362       vs = @lookahead
363       @lookahead = nil
364       return vs
365     end
366     raise @stop_exc if @stop_exc
367
368     curr = Fiber.current
369
370     if !@fib || !@fib.alive?
371       @dst = curr
372       @fib = Fiber.new do
373         result = each do |*args|
374           feedvalue = nil
375           Fiber.yield args
376           if @feedvalue
377             feedvalue = @feedvalue
378             @feedvalue = nil
379           end
380           feedvalue
381         end
382         @stop_exc = StopIteration.new "iteration reached an end"
383         @stop_exc.result = result
384         Fiber.yield nil
385       end
386       @lookahead = nil
387     end
388
389     vs = @fib.resume curr
390     if @stop_exc
391       @fib = nil
392       @dst = nil
393       @lookahead = nil
394       @feedvalue = nil
395       raise @stop_exc
396     end
397     vs
398   end
399
400   ##
401   # call-seq:
402   #   e.peek   -> object
403   #
404   # Returns the next object in the enumerator, but doesn't move the internal
405   # position forward.  If the position is already at the end, StopIteration
406   # is raised.
407   #
408   # === Example
409   #
410   #   a = [1,2,3]
411   #   e = a.to_enum
412   #   p e.next   #=> 1
413   #   p e.peek   #=> 2
414   #   p e.peek   #=> 2
415   #   p e.peek   #=> 2
416   #   p e.next   #=> 2
417   #   p e.next   #=> 3
418   #   p e.next   #raises StopIteration
419   #
420   def peek
421     peek_values.__svalue
422   end
423
424   ##
425   # call-seq:
426   #   e.peek_values   -> array
427   #
428   # Returns the next object as an array, similar to Enumerator#next_values, but
429   # doesn't move the internal position forward.  If the position is already at
430   # the end, StopIteration is raised.
431   #
432   # === Example
433   #
434   #   o = Object.new
435   #   def o.each
436   #     yield
437   #     yield 1
438   #     yield 1, 2
439   #   end
440   #   e = o.to_enum
441   #   p e.peek_values    #=> []
442   #   e.next
443   #   p e.peek_values    #=> [1]
444   #   p e.peek_values    #=> [1]
445   #   e.next
446   #   p e.peek_values    #=> [1, 2]
447   #   e.next
448   #   p e.peek_values    # raises StopIteration
449   #
450   def peek_values
451     if @lookahead.nil?
452       @lookahead = next_values
453     end
454     @lookahead.dup
455   end
456
457   ##
458   # call-seq:
459   #   e.rewind   -> e
460   #
461   # Rewinds the enumeration sequence to the beginning.
462   #
463   # If the enclosed object responds to a "rewind" method, it is called.
464   #
465   def rewind
466     @obj.rewind if @obj.respond_to? :rewind
467     @fib = nil
468     @dst = nil
469     @lookahead = nil
470     @feedvalue = nil
471     @stop_exc = false
472     self
473   end
474
475   ##
476   # call-seq:
477   #   e.feed obj   -> nil
478   #
479   # Sets the value to be returned by the next yield inside +e+.
480   #
481   # If the value is not set, the yield returns nil.
482   #
483   # This value is cleared after being yielded.
484   #
485   #   # Array#map passes the array's elements to "yield" and collects the
486   #   # results of "yield" as an array.
487   #   # Following example shows that "next" returns the passed elements and
488   #   # values passed to "feed" are collected as an array which can be
489   #   # obtained by StopIteration#result.
490   #   e = [1,2,3].map
491   #   p e.next           #=> 1
492   #   e.feed "a"
493   #   p e.next           #=> 2
494   #   e.feed "b"
495   #   p e.next           #=> 3
496   #   e.feed "c"
497   #   begin
498   #     e.next
499   #   rescue StopIteration
500   #     p $!.result      #=> ["a", "b", "c"]
501   #   end
502   #
503   #   o = Object.new
504   #   def o.each
505   #     x = yield         # (2) blocks
506   #     p x               # (5) => "foo"
507   #     x = yield         # (6) blocks
508   #     p x               # (8) => nil
509   #     x = yield         # (9) blocks
510   #     p x               # not reached w/o another e.next
511   #   end
512   #
513   #   e = o.to_enum
514   #   e.next              # (1)
515   #   e.feed "foo"        # (3)
516   #   e.next              # (4)
517   #   e.next              # (7)
518   #                       # (10)
519   #
520   def feed(value)
521     raise TypeError, "feed value already set" if @feedvalue
522     @feedvalue = value
523     nil
524   end
525
526   # just for internal
527   class Generator
528     include Enumerable
529     def initialize(&block)
530       raise TypeError, "wrong argument type #{self.class} (expected Proc)" unless block.kind_of? Proc
531
532       @proc = block
533     end
534
535     def each(*args, &block)
536       args.unshift Yielder.new(&block)
537       @proc.call(*args)
538     end
539   end
540
541   # just for internal
542   class Yielder
543     def initialize(&block)
544       raise LocalJumpError, "no block given" unless block
545
546       @proc = block
547     end
548
549     def yield(*args)
550       @proc.call(*args)
551     end
552
553     def << *args
554       self.yield(*args)
555       self
556     end
557   end
558 end
559
560 module Kernel
561   ##
562   # call-seq:
563   #   obj.to_enum(method = :each, *args)                 -> enum
564   #   obj.enum_for(method = :each, *args)                -> enum
565   #   obj.to_enum(method = :each, *args) {|*args| block} -> enum
566   #   obj.enum_for(method = :each, *args){|*args| block} -> enum
567   #
568   # Creates a new Enumerator which will enumerate by calling +method+ on
569   # +obj+, passing +args+ if any.
570   #
571   # If a block is given, it will be used to calculate the size of
572   # the enumerator without the need to iterate it (see Enumerator#size).
573   #
574   # === Examples
575   #
576   #   str = "xyz"
577   #
578   #   enum = str.enum_for(:each_byte)
579   #   enum.each { |b| puts b }
580   #   # => 120
581   #   # => 121
582   #   # => 122
583   #
584   #   # protect an array from being modified by some_method
585   #   a = [1, 2, 3]
586   #   some_method(a.to_enum)
587   #
588   # It is typical to call to_enum when defining methods for
589   # a generic Enumerable, in case no block is passed.
590   #
591   # Here is such an example, with parameter passing and a sizing block:
592   #
593   #     module Enumerable
594   #       # a generic method to repeat the values of any enumerable
595   #       def repeat(n)
596   #         raise ArgumentError, "#{n} is negative!" if n < 0
597   #         unless block_given?
598   #           return to_enum(__method__, n) do # __method__ is :repeat here
599   #             sz = size     # Call size and multiply by n...
600   #             sz * n if sz  # but return nil if size itself is nil
601   #           end
602   #         end
603   #         each do |*val|
604   #           n.times { yield *val }
605   #         end
606   #       end
607   #     end
608   #
609   #     %i[hello world].repeat(2) { |w| puts w }
610   #       # => Prints 'hello', 'hello', 'world', 'world'
611   #     enum = (1..14).repeat(3)
612   #       # => returns an Enumerator when called without a block
613   #     enum.first(4) # => [1, 1, 1, 2]
614   #
615   def to_enum(meth=:each, *args)
616     Enumerator.new self, meth, *args
617   end
618   alias enum_for to_enum
619 end
620
621 module Enumerable
622   # use Enumerator to use infinite sequence
623   def zip(*args, &block)
624     args = args.map do |a|
625       if a.respond_to?(:each)
626         a.to_enum(:each)
627       else
628         raise TypeError, "wrong argument type #{a.class} (must respond to :each)"
629       end
630     end
631
632     result = block ? nil : []
633
634     each do |*val|
635       tmp = [val.__svalue]
636       args.each do |arg|
637         v = if arg.nil?
638           nil
639         else
640           begin
641             arg.next
642           rescue StopIteration
643             nil
644           end
645         end
646         tmp.push(v)
647       end
648       if result.nil?
649         block.call(tmp)
650       else
651         result.push(tmp)
652       end
653     end
654
655     result
656   end
657 end