-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathsort_ordered.go
More file actions
93 lines (83 loc) · 3.05 KB
/
sort_ordered.go
File metadata and controls
93 lines (83 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package extsort
import (
"bytes"
"cmp"
"encoding/gob"
"sync"
)
// OrderedSorter provides external sorting for types that implement cmp.Ordered.
// It embeds GenericSorter and adds optimized byte serialization using gob encoding
// with a sync.Pool for buffer reuse to reduce allocations.
type OrderedSorter[T cmp.Ordered] struct {
GenericSorter[T]
bufferPool sync.Pool
}
// newOrderedSorter creates a new OrderedSorter with an initialized buffer pool
// for efficient gob encoding/decoding operations.
func newOrderedSorter[T cmp.Ordered]() *OrderedSorter[T] {
s := &OrderedSorter[T]{
bufferPool: sync.Pool{
New: func() any {
return &bytes.Buffer{}
},
},
}
return s
}
// fromBytesOrdered deserializes a byte slice back to the original type T
// using gob decoding. It reuses buffers from the pool for efficiency.
// Returns an error if decoding fails.
func (s *OrderedSorter[T]) fromBytesOrdered(d []byte) (T, error) {
var v T
buf := s.bufferPool.Get().(*bytes.Buffer)
buf.Reset()
buf.Write(d)
defer s.bufferPool.Put(buf)
dec := gob.NewDecoder(buf)
err := dec.Decode(&v)
return v, err
}
// toBytesOrdered serializes a value of type T to bytes using gob encoding.
// It reuses buffers from the pool and returns a copy of the serialized data.
// Returns an error if encoding fails.
func (s *OrderedSorter[T]) toBytesOrdered(d T) ([]byte, error) {
buf := s.bufferPool.Get().(*bytes.Buffer)
buf.Reset()
defer s.bufferPool.Put(buf)
enc := gob.NewEncoder(buf)
err := enc.Encode(d)
if err != nil {
return nil, err
}
// Need to copy the bytes since we're returning the buffer to the pool
result := make([]byte, buf.Len())
copy(result, buf.Bytes())
return result, nil
}
// Ordered performs external sorting on a channel of cmp.Ordered types.
// It returns the sorter instance, output channel with sorted results, and error channel.
// Uses gob encoding for serialization and the < operator for comparison.
//
// IMPORTANT: The input channel MUST be closed to signal the end of data.
// Sort() will continue reading from the input channel until it is closed.
func Ordered[T cmp.Ordered](input <-chan T, config *Config) (*OrderedSorter[T], <-chan T, <-chan error) {
orderedSorter := newOrderedSorter[T]()
s, output, errChan := Generic(input, orderedSorter.fromBytesOrdered, orderedSorter.toBytesOrdered, cmp.Compare, config)
if s == nil {
return nil, output, errChan
}
orderedSorter.GenericSorter = *s
return orderedSorter, output, errChan
}
// OrderedMock performs external sorting with a mock implementation that limits
// the number of items to sort (useful for testing). Takes the same parameters as
// Ordered plus n which limits the number of items processed.
func OrderedMock[T cmp.Ordered](input <-chan T, config *Config, n int) (*OrderedSorter[T], <-chan T, <-chan error) {
orderedSorter := newOrderedSorter[T]()
s, output, errChan := MockGeneric(input, orderedSorter.fromBytesOrdered, orderedSorter.toBytesOrdered, cmp.Compare, config, n)
if s == nil {
return nil, output, errChan
}
orderedSorter.GenericSorter = *s
return orderedSorter, output, errChan
}