Skip to content

Commit

Permalink
Make StaticArray and Slice .map to return their own type (#5124)
Browse files Browse the repository at this point in the history
  • Loading branch information
firejox authored and RX14 committed Oct 15, 2017
1 parent a4f8161 commit af06abd
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 4 deletions.
26 changes: 26 additions & 0 deletions spec/std/slice_spec.cr
Expand Up @@ -362,6 +362,32 @@ describe "Slice" do
3.times { a.includes?(b.shift).should be_true }
end

it "does map" do
a = Slice[1, 2, 3]
b = a.map { |x| x * 2 }
b.should eq(Slice[2, 4, 6])
end

it "does map!" do
a = Slice[1, 2, 3]
b = a.map! { |x| x * 2 }
a.should eq(Slice[2, 4, 6])
a.to_unsafe.should eq(b.to_unsafe)
end

it "does map_with_index" do
a = Slice[1, 1, 2, 2]
b = a.map_with_index { |e, i| e + i }
b.should eq(Slice[1, 2, 4, 5])
end

it "does map_with_index!" do
a = Slice[1, 1, 2, 2]
b = a.map_with_index! { |e, i| e + i }
a.should eq(Slice[1, 2, 4, 5])
a.to_unsafe.should eq(b.to_unsafe)
end

it "creates empty slice" do
slice = Slice(Int32).empty
slice.empty?.should be_true
Expand Down
16 changes: 14 additions & 2 deletions spec/std/static_array_spec.cr
Expand Up @@ -109,15 +109,27 @@ describe "StaticArray" do
a[2].should eq(1)
end

it "maps!" do
it "does map" do
a = StaticArray[0, 1, 2]
b = a.map { |e| e * 2 }
b.should eq(StaticArray[0, 2, 4])
end

it "does map!" do
a = StaticArray(Int32, 3).new { |i| i + 1 }
a.map! { |i| i + 1 }
a[0].should eq(2)
a[1].should eq(3)
a[2].should eq(4)
end

it "map_with_index!" do
it "does map_with_index" do
a = StaticArray[1, 1, 2, 2]
b = a.map_with_index { |e, i| e + i }
b.should eq(StaticArray[1, 2, 4, 5])
end

it "does map_with_index!" do
a = StaticArray(Int32, 3).new { |i| i + 1 }
a.map_with_index! { |e, i| i * 2 }
a[0].should eq(0)
Expand Down
2 changes: 1 addition & 1 deletion src/kernel.cr
Expand Up @@ -5,7 +5,7 @@ STDOUT = (IO::FileDescriptor.new(1, blocking: LibC.isatty(1) == 0)).tap { |f| f.
STDERR = (IO::FileDescriptor.new(2, blocking: LibC.isatty(2) == 0)).tap { |f| f.flush_on_newline = true }

PROGRAM_NAME = String.new(ARGV_UNSAFE.value)
ARGV = (ARGV_UNSAFE + 1).to_slice(ARGC_UNSAFE - 1).map { |c_str| String.new(c_str) }
ARGV = Array.new(ARGC_UNSAFE - 1) { |i| String.new(ARGV_UNSAFE[1 + i]) }
ARGF = IO::ARGF.new(ARGV, STDIN)

# Repeatedly executes the block, passing an incremental `Int32`
Expand Down
38 changes: 38 additions & 0 deletions src/slice.cr
Expand Up @@ -236,6 +236,44 @@ struct Slice(T)
@pointer.shuffle!(size, random)
end

# Invokes the given block for each element of `self`, replacing the element
# with the value returned by the block. Returns `self`.
#
# ```
# slice = Slice[1, 2, 3]
# slice.map! { |x| x * x }
# slice # => Slice[1, 4, 9]
# ```
def map!
check_writable

@pointer.map!(size) { |e| yield e }
self
end

# Returns a new slice where elements are mapped by the given block.
#
# ```
# slice = Slice[1, 2.5, "a"]
# slice.map &.to_s # => Slice["1", "2.5", "a"]
# ```
def map(*, read_only = false, &block : T -> U) forall U
Slice.new(size, read_only: read_only) { |i| yield @pointer[i] }
end

# Like `map!`, but the block gets passed both the element and its index.
def map_with_index!(&block : (T, Int32) -> T)
check_writable

@pointer.map_with_index!(size) { |e, i| yield e, i }
self
end

# Like `map`, but the block gets passed both the element and its index.
def map_with_index(*, read_only = false, &block : (T, Int32) -> U) forall U
Slice.new(size, read_only: read_only) { |i| yield @pointer[i], i }
end

def copy_from(source : Pointer(T), count)
check_writable

Expand Down
17 changes: 16 additions & 1 deletion src/static_array.cr
Expand Up @@ -165,12 +165,27 @@ struct StaticArray(T, N)
self
end

# Like `map`, but the block gets passed both the element and its index.
# Returns a new static array where elements are mapped by the given block.
#
# ```
# array = StaticArray[1, 2.5, "a"]
# tuple.map &.to_s # => StaticArray["1", "2.5", "a"]
# ```
def map(&block : T -> U) forall U
StaticArray(U, N).new { |i| yield to_unsafe[i] }
end

# Like `map!`, but the block gets passed both the element and its index.
def map_with_index!(&block : (T, Int32) -> T)
to_unsafe.map_with_index!(size) { |e, i| yield e, i }
self
end

# Like `map`, but the block gets passed both the element and its index.
def map_with_index(&block : (T, Int32) -> U) forall U
StaticArray(U, N).new { |i| yield to_unsafe[i], i }
end

# Reverses the elements of this array in-place, then returns `self`.
#
# ```
Expand Down

0 comments on commit af06abd

Please sign in to comment.