Skip to content

Commit

Permalink
[GR-20446] Implement Enumerator::Lazy#with_index
Browse files Browse the repository at this point in the history
PullRequest: truffleruby/2669
  • Loading branch information
bjfish committed Jun 7, 2021
2 parents e76da03 + 68db106 commit e6e7a0e
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Compatibility:
* Fix `ObjectSpace._id2ref` for Symbols and frozen String literals (#2358).
* Implemented `Enumerator::Lazy#filter_map` (#2356).
* Fix LLVM toolchain issue on macOS 10.13 (#2352, [oracle/graal#3383](https://github.com/oracle/graal/issues/3383)).
* Implemented `Enumerator::Lazy#with_index` (#2356).

Performance:

Expand Down
31 changes: 31 additions & 0 deletions spec/ruby/core/enumerator/lazy/with_index_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- encoding: us-ascii -*-

require_relative '../../../spec_helper'
require_relative 'fixtures/classes'

ruby_version_is "2.7" do
describe "Enumerator::Lazy#with_index" do
it "enumerates with an index" do
(0..Float::INFINITY).lazy.with_index.map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
end

it "enumerates with an index starting at a given offset" do
(0..Float::INFINITY).lazy.with_index(3).map { |i, idx| [i, idx] }.first(3).should == [[0, 3], [1, 4], [2, 5]]
end

it "enumerates with an index starting at 0 when offset is nil" do
(0..Float::INFINITY).lazy.with_index(nil).map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
end

it "raises TypeError when offset does not convert to Integer" do
-> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError)
end

it "enumerates with a given block" do
result = []
(0..Float::INFINITY).lazy.with_index { |i, idx| result << [i * 2, idx] }.first(3)
result.should == [[0,0],[2,1],[4,2]]
end
end
end

1 change: 0 additions & 1 deletion spec/tags/truffle/methods_tags.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ fails:Public methods on TracePoint should include parameters
fails:Public methods on TracePoint should include raised_exception
fails:Public methods on TracePoint should include return_value
fails:Public methods on ENV.singleton_class should include freeze
fails:Public methods on Enumerator::Lazy should include with_index
fails:Public methods on IO should include set_encoding_by_bom
fails:Public methods on BasicSocket should include read_nonblock
fails:Public methods on BasicSocket should include write_nonblock
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/truffleruby/core/CoreLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ public boolean isTruffleBootMainMethod(SharedMethodInfo info) {
"/core/truffle/debug.rb",
"/core/truffle/diggable.rb",
"/core/truffle/encoding_operations.rb",
"/core/truffle/enumerator_operations.rb",
"/core/truffle/hash_operations.rb",
"/core/truffle/interop_operations.rb",
"/core/truffle/numeric_operations.rb",
Expand Down
26 changes: 26 additions & 0 deletions src/main/ruby/truffleruby/core/enumerator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,14 @@ def each(*args, &block)
end

class Lazy < Enumerator

aliases = Truffle::EnumeratorOperations::LAZY_OVERRIDE_METHODS.map do |m|
name = :"_enumerable_#{m}"
alias_method name, :"#{m}"
name
end
private(*aliases)

class StopLazyError < Exception # rubocop:disable Lint/InheritException
end

Expand All @@ -299,6 +307,7 @@ def initialize(receiver, size=nil)
def to_enum(method_name=:each, *method_args, &block)
size = block_given? ? block : nil
ret = Lazy.allocate
method_name = Truffle::EnumeratorOperations.lazy_method(method_name)

ret.__send__ :initialize_enumerator, self, size, method_name, *method_args

Expand Down Expand Up @@ -492,6 +501,23 @@ def flat_map
end
alias_method :collect_concat, :flat_map

def with_index(offset=0, &block)
offset = if Primitive.nil?(offset)
0
else
Truffle::Type.coerce_to offset, Integer, :to_int
end

Lazy.new(self, enumerator_size) do |yielder, *args|
if block
yielder.yield yield(*args, offset)
else
yielder.yield(*args, offset)
end
offset += 1
end
end

def zip(*lists)
return super(*lists) { |entry| yield entry } if block_given?

Expand Down
24 changes: 24 additions & 0 deletions src/main/ruby/truffleruby/core/truffle/enumerator_operations.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

# Copyright (c) 2021, 2021 Oracle and/or its affiliates. All rights reserved. This
# code is released under a tri EPL/GPL/LGPL license. You can use it,
# redistribute it and/or modify it under the terms of the:
#
# Eclipse Public License version 2.0, or
# GNU General Public License version 2, or
# GNU Lesser General Public License version 2.1.

module Truffle
module EnumeratorOperations
LAZY_OVERRIDE_METHODS = %i[map collect flat_map collect_concat select find_all filter filter_map reject grep grep_v
zip take take_while drop drop_while uniq with_index]

def self.lazy_method(meth)
if LAZY_OVERRIDE_METHODS.include?(meth)
:"_enumerable_#{meth}"
else
meth
end
end
end
end

0 comments on commit e6e7a0e

Please sign in to comment.