mirror of
https://github.com/samber/lo.git
synced 2026-04-22 15:37:14 +08:00
feat: support for buffer iterator (#824)
* support for buffer iterator * Code review fix * fix: transforming the Buffer helper into a pull-based operator (it receives an iterator instead of channel) * doc(it): adding loit.Buffer to doc --------- Co-authored-by: Samuel Berthe <dev@samuel-berthe.fr>
This commit is contained in:
+2
-21
@@ -88,6 +88,7 @@ Use `variantHelpers` for different versions of the **same helper function**:
|
||||
```yaml
|
||||
variantHelpers:
|
||||
- core#slice#map # func Map[T, R]([]T, func(T, int) R) []R
|
||||
- core#slice#maperr # func MapErr[T, R]([]T, func(T, int) (R, error)) ([]R, error)
|
||||
- core#slice#mapi # func MapI[T, R]([]T, func(T, int) R) []R (with index)
|
||||
- core#slice#mapwithcontext # func MapWithContext[T, R]([]T, func(T, int, context.Context) R, context.Context) []R
|
||||
```
|
||||
@@ -194,6 +195,7 @@ Use these established subCategories:
|
||||
- For function variants, use consistent suffixes:
|
||||
- `F` suffix for function-based versions (lazy evaluation)
|
||||
- `I` suffix for variants having `index int` argument in predicate callback
|
||||
- `Err` suffix for variants returning an error in predicate callback
|
||||
- `WithContext` suffix when context.Context is provided
|
||||
- `X` suffix for helpers with varying arguments (eg: MustX: Must2, Must3, Must4...)
|
||||
|
||||
@@ -211,27 +213,6 @@ Add these examples in the source code comments, on top of helpers, with a syntax
|
||||
|
||||
If the documentation is created at the same time of the helper source code, then the Go playground execution might fail, since we need to merge+release the source code first to make this new helper available to Go playground compiler. In that case, skip the creation of the example and set no URL.
|
||||
|
||||
## Validation Scripts
|
||||
|
||||
Run these scripts to validate your documentation:
|
||||
|
||||
```bash
|
||||
# Check cross-references
|
||||
node scripts/check-cross-references.js
|
||||
|
||||
# Check for duplicates in categories
|
||||
node scripts/check-duplicates-in-category.js
|
||||
|
||||
# Check filename matches frontmatter
|
||||
node scripts/check-filename-matches-frontmatter.js
|
||||
|
||||
# Check for similar existing helpers
|
||||
node scripts/check-similar-exists.js
|
||||
|
||||
# Check for similar keys in directory
|
||||
node scripts/check-similar-keys-exist-in-directory.js
|
||||
```
|
||||
|
||||
## Example: Complete File
|
||||
|
||||
```yaml
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: Buffer
|
||||
slug: buffer
|
||||
sourceRef: it/seq.go#L1162
|
||||
category: it
|
||||
subCategory: sequence
|
||||
signatures:
|
||||
- "func Buffer[T any](seq iter.Seq[T], size int) iter.Seq[[]T]"
|
||||
playUrl: ""
|
||||
variantHelpers:
|
||||
- it#sequence#buffer
|
||||
similarHelpers:
|
||||
- it#sequence#chunk
|
||||
- it#sequence#sliding
|
||||
- it#sequence#window
|
||||
position: 65
|
||||
---
|
||||
|
||||
Returns a sequence of slices, each containing up to size items read from the sequence.
|
||||
The last slice may be smaller if the sequence closes before filling the buffer.
|
||||
|
||||
Examples:
|
||||
|
||||
```go
|
||||
seq := func(yield func(int) bool) {
|
||||
_ = yield(1)
|
||||
_ = yield(2)
|
||||
_ = yield(3)
|
||||
_ = yield(4)
|
||||
_ = yield(5)
|
||||
_ = yield(6)
|
||||
_ = yield(7)
|
||||
}
|
||||
buffers := it.Buffer(seq, 3)
|
||||
var result [][]int
|
||||
for buffer := range buffers {
|
||||
result = append(result, buffer)
|
||||
}
|
||||
// result contains [[1 2 3] [4 5 6] [7]]
|
||||
```
|
||||
@@ -24,6 +24,13 @@ Functions use `~[]T` constraints to accept any slice type, including named slice
|
||||
## Variants
|
||||
When applicable, some functions can be added to sub-package as well: `mutable`, `it` and `parallel`. Add a documentation for each helper.
|
||||
|
||||
For function variants, use consistent suffixes:
|
||||
- `F` suffix for function-based versions (lazy evaluation)
|
||||
- `I` suffix for variants having `index int` argument in predicate callback
|
||||
- `Err` suffix for variants returning an error in predicate callback
|
||||
- `WithContext` suffix when context.Context is provided
|
||||
- `X` suffix for helpers with varying arguments (eg: MustX: Must2, Must3, Must4...)
|
||||
|
||||
## Testing
|
||||
We try to maintain code coverage above 90%.
|
||||
|
||||
|
||||
@@ -1158,3 +1158,27 @@ func TrimSuffix[T comparable, I ~func(func(T) bool)](collection I, suffix []T) I
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Buffer returns a sequence of slices, each containing up to size items read from the channel.
|
||||
// The last slice may be smaller if the channel closes before filling the buffer.
|
||||
func Buffer[T any](seq iter.Seq[T], size int) iter.Seq[[]T] {
|
||||
return func(yield func([]T) bool) {
|
||||
buffer := make([]T, 0, size)
|
||||
|
||||
seq(func(v T) bool {
|
||||
buffer = append(buffer, v)
|
||||
if len(buffer) < size {
|
||||
return true // keep pulling
|
||||
}
|
||||
// Buffer full, yield it
|
||||
result := buffer
|
||||
buffer = make([]T, 0, size) // allocate new buffer
|
||||
return yield(result) // false = stop, true = continue
|
||||
})
|
||||
|
||||
// Yield remaining partial buffer
|
||||
if len(buffer) > 0 {
|
||||
yield(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1799,3 +1799,24 @@ func TestTrimSuffix(t *testing.T) {
|
||||
actual = TrimSuffix(values("a", "b", "c", "d", "e", "f", "g"), []string{})
|
||||
is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, slices.Collect(actual))
|
||||
}
|
||||
|
||||
func TestBuffer(t *testing.T) {
|
||||
t.Parallel()
|
||||
is := assert.New(t)
|
||||
|
||||
// full batches
|
||||
batches := slices.Collect(Buffer(RangeFrom(1, 6), 2))
|
||||
is.Equal([][]int{{1, 2}, {3, 4}, {5, 6}}, batches)
|
||||
|
||||
// partial last batch
|
||||
batches2 := slices.Collect(Buffer(RangeFrom(1, 5), 2))
|
||||
is.Equal([][]int{{1, 2}, {3, 4}, {5}}, batches2)
|
||||
|
||||
// empty channel
|
||||
batches3 := slices.Collect(Buffer(RangeFrom(1, 0), 2))
|
||||
is.Empty(batches3)
|
||||
|
||||
// stop after first batch (early termination)
|
||||
batches4 := slices.Collect(Take(Buffer(RangeFrom(1, 6), 2), 1))
|
||||
is.Equal([][]int{{1, 2}}, batches4)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user