Skip to content

Commit 7bb3285

Browse files
itaratoandrykonchin
authored andcommitted
Add Enumerator#product.
1 parent b6c229a commit 7bb3285

File tree

4 files changed

+44
-0
lines changed

4 files changed

+44
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Compatibility:
2929
* Add `Module#refinements` (#3039, @itarato).
3030
* Add `Refinement#refined_class` (#3039, @itarato).
3131
* Add `rb_hash_new_capa` function (#3039, @itarato).
32+
* Add `Enumerator#product` (#3039, @itarato).
3233

3334
Performance:
3435

spec/truffleruby.next-specs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,5 @@ spec/ruby/core/module/refinements_spec.rb
3434
spec/ruby/core/refinement/refined_class_spec.rb
3535
spec/ruby/core/module/used_refinements_spec.rb
3636
spec/ruby/optional/capi/hash_spec.rb
37+
38+
spec/ruby/core/enumerator/product_spec.rb

src/main/ruby/truffleruby/core/enumerator.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,40 @@ def self.produce(initial = nil)
231231
end
232232
end
233233

234+
def self.product(*enums, **kwargs, &block)
235+
Truffle::KernelOperations.validate_no_kwargs(kwargs)
236+
237+
return Product.new(*enums) if Primitive.nil?(block)
238+
product_iterator([], enums, &block)
239+
end
240+
241+
class << self
242+
protected def product_iterator(current, rest_enums, &block)
243+
return block.call(current) if rest_enums.empty?
244+
245+
rest_enums_tail = rest_enums[1..]
246+
rest_enums.first.each_entry do |next_e|
247+
product_iterator(current + [next_e], rest_enums_tail, &block)
248+
end
249+
end
250+
end
251+
252+
class Product < Enumerator
253+
def initialize(*enums, **kwargs)
254+
Truffle::KernelOperations.validate_no_kwargs(kwargs)
255+
256+
@enums = enums
257+
end
258+
259+
def each(&block)
260+
Primitive.class(self).product_iterator([], @enums, &block)
261+
end
262+
263+
def size
264+
@enums.map(&:size).reduce(1, &:*)
265+
end
266+
end
267+
234268
class Yielder
235269
attr_accessor :memo
236270

src/main/ruby/truffleruby/core/truffle/kernel_operations.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,13 @@ def self.value_frozen?(value)
242242
KERNEL_FROZEN.bind(value).call
243243
end
244244

245+
def self.validate_no_kwargs(kwargs)
246+
return if (kwargs_size = kwargs.size) == 0
247+
248+
raise ArgumentError, "unknown keyword: #{kwargs.keys.first.inspect}" if kwargs_size == 1
249+
raise ArgumentError, "unknown keywords: #{kwargs.keys.map(&:inspect).join(', ')}"
250+
end
251+
245252
# To get the class even if the value's class does not include `Kernel`, use `Primitive.class`.
246253
end
247254
end

0 commit comments

Comments
 (0)