Skip to content

Commit

Permalink
Add user friendly wrapper to split2SliceChunks
Browse files Browse the repository at this point in the history
  • Loading branch information
avrahams committed Jun 26, 2022
1 parent 0eaaf1b commit 30ec3c6
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
10 changes: 2 additions & 8 deletions httputils/httphelper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,7 @@ func TestSplitSlice2Chunks(t *testing.T) {
}

//split splice to chunks
chunksChan := make(chan []testStruct, 10)
wg := sync.WaitGroup{}
SplitSlice2Chunks(testTypeSlice, 100, chunksChan, &wg)
go func() {
wg.Wait()
close(chunksChan)
}()
chunksChan, totalTestTypes := SplitSlice2Chunks(testTypeSlice, 100, 10)
testWg := sync.WaitGroup{}
var totalReceived, numOfChunks, maxChunkSize, minChunkSize, maxChunkLength, minChunkLength int
testWg.Add(1)
Expand Down Expand Up @@ -166,7 +160,7 @@ func TestSplitSlice2Chunks(t *testing.T) {
//wait for all chunks to arrive
testWg.Wait()
//compare with expected
assert.Equal(t, len(testTypeSlice), totalReceived, "total elements received is not equal to number of element sent")
assert.Equal(t, totalTestTypes, totalReceived, "total elements received is not equal to number of element sent")
assert.Equal(t, 3, minChunkLength, "minChunkLength must be same as expected minChunkLength")
assert.Equal(t, 3, maxChunkLength, "maxChunkLength must be same as expected maxChunkLength")
assert.Equal(t, 77, minChunkSize, "minChunkSize must be same as expected minChunkSize")
Expand Down
26 changes: 23 additions & 3 deletions httputils/httphelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,30 @@ func HttpRespToString(resp *http.Response) (string, error) {
}

//SplitSlice2Chunks - *recursively* splits a slice to chunks of sub slices that do not exceed max bytes size
//Returns a channels for receiving []T chunks and the original len of []T
//If []T is empty the function will return a closed chunks channel
//Chunks might be bigger than max size if the slice contains element(s) that are bigger than the max size
//this split algorithm fits for slices with elements that share more or less the same size per element
//uses optimistic average size splitting to enhance performance and reduce the use of json encoding for size calculations
func SplitSlice2Chunks[T any](slice []T, maxSize int, chunks chan<- []T, wg *sync.WaitGroup) {
//chunks channel will be closed after splitting is done
func SplitSlice2Chunks[T any](slice []T, maxSize int, channelBuffer int) (chunksChannel <-chan []T, sliceSize int) {
channel := make(chan []T, channelBuffer)
sliceSize = len(slice)
if sliceSize > 0 {
go func(chunksChannel chan<- []T) {
splitWg := &sync.WaitGroup{}
splitSlice2Chunks(slice, maxSize, chunksChannel, splitWg)
splitWg.Wait()
close(chunksChannel)
}(channel)
} else {
close(channel)
}
chunksChannel = channel
return chunksChannel, sliceSize
}

func splitSlice2Chunks[T any](slice []T, maxSize int, chunks chan<- []T, wg *sync.WaitGroup) {
wg.Add(1)
go func(slice []T, maxSize int, chunks chan<- []T, wg *sync.WaitGroup) {
defer wg.Done()
Expand Down Expand Up @@ -124,11 +144,11 @@ func SplitSlice2Chunks[T any](slice []T, maxSize int, chunks chan<- []T, wg *syn
//split the slice to slices of avgSliceSize size
startIndex := 0
for i := avgSliceSize; i < last; i += avgSliceSize {
SplitSlice2Chunks(slice[startIndex:i], maxSize, chunks, wg)
splitSlice2Chunks(slice[startIndex:i], maxSize, chunks, wg)
startIndex = i
}
//send the last part of the slice
SplitSlice2Chunks(slice[startIndex:last], maxSize, chunks, wg)
splitSlice2Chunks(slice[startIndex:last], maxSize, chunks, wg)
}(slice, maxSize, chunks, wg)
}

Expand Down

0 comments on commit 30ec3c6

Please sign in to comment.