-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
313 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# frozen_string_literal: true | ||
|
||
class Array | ||
# Flattens the array to the specified level. | ||
# | ||
# If no level is provided, flattens recursively. | ||
# | ||
# @param level [Integer, nil] The level of flattening. If nil, flatten recursively. | ||
# @return [Array] A new array with the flattened elements. | ||
# | ||
# @example | ||
# [1, [2, 3, [4, 5]]].flatten #=> [1, 2, 3, 4, 5] | ||
# [1, [2, 3, [4, 5]]].flatten(1) #=> [1, 2, 3, [4, 5]] | ||
def flatten(level = nil) | ||
return self.dup if level == 0 | ||
|
||
result = [] | ||
each do |element| | ||
if element.is_a?(Array) && (level.nil? || level > 0) | ||
result.concat(level.nil? ? element.flatten : element.flatten(level - 1)) | ||
else | ||
result << element | ||
end | ||
end | ||
result | ||
end | ||
end |
29 changes: 29 additions & 0 deletions
29
lib/native_ruby/iterators/immutable/array/each_with_index.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# frozen_string_literal: true | ||
|
||
class Array | ||
# Iterates the given block for each element with its index. | ||
# | ||
# This implementation is considered immutable because it does not modify | ||
# the array's size or structure during iteration. The array's length is | ||
# calculated once at the beginning and remains constant throughout the iteration. | ||
# | ||
# If no block is given, returns an Enumerator object. | ||
# | ||
# @yield [Object, Integer] Passes each element of the array and its index to the block. | ||
# @yieldparam element [Object] The current element in the iteration. | ||
# @yieldparam index [Integer] The index of the current element. | ||
# @return [Array] Returns self. | ||
# @return [Enumerator] If no block is given. | ||
def each_with_index | ||
return to_enum(:each_with_index) { self.length } unless block_given? | ||
|
||
i = 0 | ||
length = self.length | ||
while i < length | ||
yield self[i], i | ||
i = i.succ | ||
end | ||
|
||
self | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,4 +27,6 @@ def map | |
end | ||
result | ||
end | ||
|
||
alias_method :collect, :map | ||
end |
29 changes: 29 additions & 0 deletions
29
lib/native_ruby/iterators/mutable/array/each_with_index.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# frozen_string_literal: true | ||
|
||
class Array | ||
# Iterates the given block for each element with index. | ||
# | ||
# This implementation is considered mutable because: | ||
# 1. It recalculates self.length on each iteration, allowing for potential | ||
# changes to the array's size during iteration. | ||
# 2. If the array is modified during iteration (e.g., by the yielded block), | ||
# the method will operate on the modified array. | ||
# | ||
# If no block is given, returns an Enumerator object. | ||
# | ||
# @yield [Object, Integer] Passes each element of the array and its index to the block. | ||
# @yieldparam element [Object] The current element in the iteration. | ||
# @yieldparam index [Integer] The index of the current element. | ||
# @return [Array] Returns self. | ||
# @return [Enumerator] If no block is given. | ||
def each_with_index | ||
return to_enum(:each_with_index) { self.length } unless block_given? | ||
|
||
i = 0 | ||
while i < self.length # Note: self.length is evaluated on each iteration | ||
yield self[i], i | ||
i = i.succ | ||
end | ||
self | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,4 +28,6 @@ def map | |
end | ||
result | ||
end | ||
|
||
alias_method :collect, :map | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'benchmark' | ||
|
||
RSpec.describe 'Array#all?' do | ||
before do | ||
class Array | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'benchmark' | ||
|
||
RSpec.describe 'Array#assoc' do | ||
before do | ||
class Array | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe 'Array#flatten' do | ||
before do | ||
class Array | ||
alias_method :original_flatten, :flatten | ||
end | ||
|
||
NativeRuby.config { |c| c.load(:class, { class: Array, method: :flatten }) } | ||
end | ||
|
||
after do | ||
class Array | ||
alias_method :flatten, :original_flatten | ||
end | ||
end | ||
|
||
it 'flattens nested arrays' do | ||
expect([1, [2, 3, [4, 5]]].flatten).to eq([1, 2, 3, 4, 5]) | ||
end | ||
|
||
it 'flattens to the specified level' do | ||
expect([1, [2, 3, [4, 5]]].flatten(1)).to eq([1, 2, 3, [4, 5]]) | ||
end | ||
|
||
it 'returns a new array' do | ||
original = [1, [2, 3]] | ||
flattened = original.flatten | ||
expect(flattened).not_to be(original) | ||
end | ||
|
||
it 'does not modify the original array' do | ||
original = [1, [2, 3, [4, 5]]] | ||
original.flatten | ||
expect(original).to eq([1, [2, 3, [4, 5]]]) | ||
end | ||
|
||
it 'handles empty arrays' do | ||
expect([].flatten).to eq([]) | ||
end | ||
|
||
it 'handles arrays with no nested arrays' do | ||
expect([1, 2, 3].flatten).to eq([1, 2, 3]) | ||
end | ||
|
||
it 'handles deeply nested arrays' do | ||
expect([1, [2, [3, [4, [5]]]]].flatten).to eq([1, 2, 3, 4, 5]) | ||
end | ||
|
||
it 'handles arrays with nil elements' do | ||
expect([1, [2, nil, [3, nil]]].flatten).to eq([1, 2, nil, 3, nil]) | ||
end | ||
|
||
it 'returns an Enumerator when called without arguments' do | ||
expect([1, [2, 3]].method(:flatten).arity).to eq(-1) | ||
end | ||
|
||
it 'works with a large array' do | ||
large_array = (1..1000).to_a.map { |i| [i, [i + 1000, [i + 2000]]] } | ||
flattened = large_array.flatten | ||
expect(flattened.size).to eq(3000) | ||
expect(flattened.first).to eq(1) | ||
expect(flattened.last).to eq(3000) | ||
end | ||
|
||
it 'benchmarks native implementation against original' do | ||
array = (1..10000).to_a.map { |i| [i, [i + 10000, [i + 20000]]] } | ||
iterations = 10 | ||
|
||
puts "Benchmark results (average over #{iterations} iterations):" | ||
Benchmark.bm(20) do |x| | ||
x.report('Original flatten:') do | ||
iterations.times { array.original_flatten } | ||
end | ||
x.report('Native flatten:') do | ||
iterations.times { array.flatten } | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe 'Array#each_with_index' do | ||
before do | ||
class Array | ||
alias_method :original_each_with_index, :each_with_index | ||
end | ||
|
||
NativeRuby.config { |c| c.load(:iterators, { class: Array, method: :each_with_index, mutable: false }) } | ||
end | ||
|
||
after do | ||
class Array | ||
alias_method :each_with_index, :original_each_with_index | ||
end | ||
end | ||
|
||
it 'iterates the given block for each element with its index' do | ||
array = %w[a b c] | ||
result = [] | ||
array.each_with_index { |item, index| result << [item, index] } | ||
expect(result).to eq([['a', 0], ['b', 1], ['c', 2]]) | ||
end | ||
|
||
it 'returns self' do | ||
array = [1, 2, 3] | ||
expect(array.each_with_index { |item, index| }).to eq(array) | ||
end | ||
|
||
it 'does not modify the original array' do | ||
array = [1, 2, 3] | ||
array.each_with_index { |item, index| item * 2 } | ||
expect(array).to eq([1, 2, 3]) | ||
end | ||
|
||
it 'works with an empty array' do | ||
result = [] | ||
[].each_with_index { |item, index| result << [item, index] } | ||
expect(result).to be_empty | ||
end | ||
|
||
it 'returns an Enumerator if no block is given' do | ||
expect([1, 2, 3].each_with_index).to be_an(Enumerator) | ||
end | ||
|
||
it 'returns an Enumerator with the correct size' do | ||
enum = [1, 2, 3].each_with_index | ||
expect(enum.size).to eq(3) | ||
end | ||
|
||
it 'works with a large array' do | ||
large_array = (1..1_000_000).to_a | ||
count = 0 | ||
large_array.each_with_index { |item, index| count += 1 if item == index + 1 } | ||
expect(count).to eq(1_000_000) | ||
end | ||
|
||
it 'benchmarks native implementation against original' do | ||
array = (1..1_000_000).to_a | ||
iterations = 10 | ||
|
||
puts "Benchmark results (average over #{iterations} iterations):" | ||
Benchmark.bm(25) do |x| | ||
x.report('Original each_with_index:') do | ||
iterations.times { array.original_each_with_index { |item, index| } } | ||
end | ||
x.report('Native each_with_index:') do | ||
iterations.times { array.each_with_index { |item, index| } } | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'benchmark' | ||
|
||
RSpec.describe 'Immutable Array#map' do | ||
before do | ||
class Array | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe 'Array#each_with_index' do | ||
before do | ||
class Array | ||
alias_method :original_each_with_index, :each_with_index | ||
end | ||
|
||
NativeRuby.config { |c| c.load(:iterators, { class: Array, method: :each_with_index, mutable: true }) } | ||
end | ||
|
||
after do | ||
class Array | ||
alias_method :each_with_index, :original_each_with_index | ||
end | ||
end | ||
|
||
it 'iterates the given block for each element with its index' do | ||
array = %w[a b c] | ||
result = [] | ||
array.each_with_index { |item, index| result << [item, index] } | ||
expect(result).to eq([['a', 0], ['b', 1], ['c', 2]]) | ||
end | ||
|
||
it 'returns self' do | ||
array = [1, 2, 3] | ||
expect(array.each_with_index { |item, index| }).to eq(array) | ||
end | ||
|
||
it 'does not modify the original array' do | ||
array = [1, 2, 3] | ||
array.each_with_index { |item, index| item * 2 } | ||
expect(array).to eq([1, 2, 3]) | ||
end | ||
|
||
it 'works with an empty array' do | ||
result = [] | ||
[].each_with_index { |item, index| result << [item, index] } | ||
expect(result).to be_empty | ||
end | ||
|
||
it 'returns an Enumerator if no block is given' do | ||
expect([1, 2, 3].each_with_index).to be_an(Enumerator) | ||
end | ||
|
||
it 'returns an Enumerator with the correct size' do | ||
enum = [1, 2, 3].each_with_index | ||
expect(enum.size).to eq(3) | ||
end | ||
|
||
it 'works with a large array' do | ||
large_array = (1..1_000_000).to_a | ||
count = 0 | ||
large_array.each_with_index { |item, index| count += 1 if item == index + 1 } | ||
expect(count).to eq(1_000_000) | ||
end | ||
|
||
it 'benchmarks native implementation against original' do | ||
array = (1..1_000_000).to_a | ||
iterations = 10 | ||
|
||
puts "Benchmark results (average over #{iterations} iterations):" | ||
Benchmark.bm(25) do |x| | ||
x.report('Original each_with_index:') do | ||
iterations.times { array.original_each_with_index { |item, index| } } | ||
end | ||
x.report('Native each_with_index:') do | ||
iterations.times { array.each_with_index { |item, index| } } | ||
end | ||
end | ||
end | ||
end |