1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-25 22:21:49 +02:00
Files
fp-go/v2/readerresult/benchmark_test.go

287 lines
6.1 KiB
Go
Raw Normal View History

// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerresult
import (
"context"
"errors"
"testing"
F "github.com/IBM/fp-go/v2/function"
)
type BenchContext struct {
Value int
}
var benchError = errors.New("benchmark error")
// Benchmark basic operations
func BenchmarkOf(b *testing.B) {
ctx := BenchContext{Value: 42}
b.ResetTimer()
for i := 0; i < b.N; i++ {
rr := Of[BenchContext](i)
_ = rr(ctx)
}
}
func BenchmarkLeft(b *testing.B) {
ctx := BenchContext{Value: 42}
err := benchError
b.ResetTimer()
for i := 0; i < b.N; i++ {
rr := Left[BenchContext, int](err)
_ = rr(ctx)
}
}
func BenchmarkMap(b *testing.B) {
ctx := BenchContext{Value: 42}
rr := Of[BenchContext](10)
double := func(x int) int { return x * 2 }
b.ResetTimer()
for i := 0; i < b.N; i++ {
mapped := F.Pipe1(rr, Map[BenchContext](double))
_ = mapped(ctx)
}
}
func BenchmarkMapChain(b *testing.B) {
ctx := BenchContext{Value: 42}
rr := Of[BenchContext](1)
double := func(x int) int { return x * 2 }
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := F.Pipe3(
rr,
Map[BenchContext](double),
Map[BenchContext](double),
Map[BenchContext](double),
)
_ = result(ctx)
}
}
func BenchmarkChain(b *testing.B) {
ctx := BenchContext{Value: 42}
rr := Of[BenchContext](10)
addOne := func(x int) ReaderResult[BenchContext, int] {
return Of[BenchContext](x + 1)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
chained := F.Pipe1(rr, Chain(addOne))
_ = chained(ctx)
}
}
func BenchmarkChainDeep(b *testing.B) {
ctx := BenchContext{Value: 42}
rr := Of[BenchContext](1)
addOne := func(x int) ReaderResult[BenchContext, int] {
return Of[BenchContext](x + 1)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := F.Pipe5(
rr,
Chain(addOne),
Chain(addOne),
Chain(addOne),
Chain(addOne),
Chain(addOne),
)
_ = result(ctx)
}
}
func BenchmarkAp(b *testing.B) {
ctx := BenchContext{Value: 42}
fab := Of[BenchContext](func(x int) int { return x * 2 })
fa := Of[BenchContext](21)
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := MonadAp(fab, fa)
_ = result(ctx)
}
}
func BenchmarkSequenceT2(b *testing.B) {
ctx := BenchContext{Value: 42}
rr1 := Of[BenchContext](10)
rr2 := Of[BenchContext](20)
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := SequenceT2(rr1, rr2)
_ = result(ctx)
}
}
func BenchmarkSequenceT4(b *testing.B) {
ctx := BenchContext{Value: 42}
rr1 := Of[BenchContext](10)
rr2 := Of[BenchContext](20)
rr3 := Of[BenchContext](30)
rr4 := Of[BenchContext](40)
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := SequenceT4(rr1, rr2, rr3, rr4)
_ = result(ctx)
}
}
func BenchmarkDoNotation(b *testing.B) {
ctx := context.Background()
type State struct {
A int
B int
C int
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := F.Pipe3(
Do[context.Context](State{}),
Bind(
func(a int) func(State) State {
return func(s State) State { s.A = a; return s }
},
func(s State) ReaderResult[context.Context, int] {
return Of[context.Context](10)
},
),
Bind(
func(b int) func(State) State {
return func(s State) State { s.B = b; return s }
},
func(s State) ReaderResult[context.Context, int] {
return Of[context.Context](s.A * 2)
},
),
Bind(
func(c int) func(State) State {
return func(s State) State { s.C = c; return s }
},
func(s State) ReaderResult[context.Context, int] {
return Of[context.Context](s.A + s.B)
},
),
)
_ = result(ctx)
}
}
func BenchmarkErrorPropagation(b *testing.B) {
ctx := BenchContext{Value: 42}
err := benchError
rr := Left[BenchContext, int](err)
double := func(x int) int { return x * 2 }
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := F.Pipe5(
rr,
Map[BenchContext](double),
Map[BenchContext](double),
Map[BenchContext](double),
Map[BenchContext](double),
Map[BenchContext](double),
)
_ = result(ctx)
}
}
func BenchmarkTraverseArray(b *testing.B) {
ctx := BenchContext{Value: 42}
arr := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
kleisli := func(x int) ReaderResult[BenchContext, int] {
return Of[BenchContext](x * 2)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
traversed := TraverseArray(kleisli)
result := traversed(arr)
_ = result(ctx)
}
}
func BenchmarkSequenceArray(b *testing.B) {
ctx := BenchContext{Value: 42}
arr := []ReaderResult[BenchContext, int]{
Of[BenchContext](1),
Of[BenchContext](2),
Of[BenchContext](3),
Of[BenchContext](4),
Of[BenchContext](5),
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
result := SequenceArray(arr)
_ = result(ctx)
}
}
// Real-world scenario benchmarks
func BenchmarkRealWorldPipeline(b *testing.B) {
type Config struct {
Multiplier int
Offset int
}
ctx := Config{Multiplier: 5, Offset: 10}
type State struct {
Input int
Result int
}
getMultiplier := func(cfg Config) int { return cfg.Multiplier }
getOffset := func(cfg Config) int { return cfg.Offset }
b.ResetTimer()
for i := 0; i < b.N; i++ {
step1 := Bind(
func(m int) func(State) State {
return func(s State) State { s.Result = s.Input * m; return s }
},
func(s State) ReaderResult[Config, int] {
return Asks(getMultiplier)
},
)
step2 := Bind(
func(off int) func(State) State {
return func(s State) State { s.Result += off; return s }
},
func(s State) ReaderResult[Config, int] {
return Asks(getOffset)
},
)
result := F.Pipe3(
Do[Config](State{Input: 10}),
step1,
step2,
Map[Config](func(s State) int { return s.Result }),
)
_ = result(ctx)
}
}