Skip to content

Commit e143857

Browse files
authored
Genericize lib.OrderedMap (#1948)
1 parent 143ff7e commit e143857

25 files changed

Lines changed: 264 additions & 279 deletions

pkg/bifs/stats.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,12 +265,12 @@ func bif_mode_or_antimode(
265265
// Do not use a Go map[string]int as that makes the output in the case of ties
266266
// (e.g. input = [3,3,4,4]) non-determinstic. That's bad for unit tests and also
267267
// simply bad UX.
268-
counts := lib.NewOrderedMap()
268+
counts := lib.NewOrderedMap[int]()
269269

270270
// We use stringification to detect uniqueness. Yet we want the output to be typed,
271271
// e.g. mode of an array of ints should be an int, not a string. Here we store
272272
// a reference to one representative for each equivalence class.
273-
reps := lib.NewOrderedMap()
273+
reps := lib.NewOrderedMap[*mlrval.Mlrval]()
274274

275275
if collection.IsArray() {
276276
a := collection.AcquireArrayValue()
@@ -280,7 +280,7 @@ func bif_mode_or_antimode(
280280
for _, e := range a {
281281
valueString := e.OriginalString()
282282
if counts.Has(valueString) {
283-
counts.Put(valueString, counts.Get(valueString).(int)+1)
283+
counts.Put(valueString, counts.Get(valueString)+1)
284284
} else {
285285
counts.Put(valueString, 1)
286286
reps.Put(valueString, e)
@@ -294,7 +294,7 @@ func bif_mode_or_antimode(
294294
for pe := m.Head; pe != nil; pe = pe.Next {
295295
valueString := pe.Value.OriginalString()
296296
if counts.Has(valueString) {
297-
counts.Put(valueString, counts.Get(valueString).(int)+1)
297+
counts.Put(valueString, counts.Get(valueString)+1)
298298
} else {
299299
counts.Put(valueString, 1)
300300
reps.Put(valueString, pe.Value)
@@ -306,16 +306,15 @@ func bif_mode_or_antimode(
306306
maxv := -1
307307
for pf := counts.Head; pf != nil; pf = pf.Next {
308308
k := pf.Key
309-
v := pf.Value.(int)
309+
v := pf.Value
310310
if first || cmp(v, maxv) {
311311
maxk = k
312312
maxv = v
313313
first = false
314314
}
315315
}
316-
// OrderedMap has interface{} values, so dereference as Mlrval. Then, copy the Mlrval
317-
// so we're not returning a pointer to input data.
318-
return reps.Get(maxk).(*mlrval.Mlrval).Copy()
316+
// Copy the Mlrval so we're not returning a pointer to input data.
317+
return reps.Get(maxk).Copy()
319318
}
320319

321320
func BIF_sum(collection *mlrval.Mlrval) *mlrval.Mlrval {

pkg/lib/ordered_map.go

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,42 @@
11
// ================================================================
2-
// ORDERED MAP FROM STRING TO INTERFACE{}
2+
// ORDERED MAP FROM STRING TO GENERIC VALUE TYPE
33
//
4-
// Quite like types.OrderedMap but only with interface{} keys. See orderedMap.go for
4+
// Quite like types.OrderedMap but only with string keys. See orderedMap.go for
55
// more information.
66
// ================================================================
77

88
package lib
99

1010
// ----------------------------------------------------------------
11-
type OrderedMap struct {
11+
type OrderedMap[V any] struct {
1212
FieldCount int64
13-
Head *orderedMapEntry
14-
Tail *orderedMapEntry
15-
keysToEntries map[string]*orderedMapEntry
13+
Head *orderedMapEntry[V]
14+
Tail *orderedMapEntry[V]
15+
keysToEntries map[string]*orderedMapEntry[V]
1616
}
1717

18-
type orderedMapEntry struct {
18+
type orderedMapEntry[V any] struct {
1919
Key string
20-
Value interface{}
21-
Prev *orderedMapEntry
22-
Next *orderedMapEntry
20+
Value V
21+
Prev *orderedMapEntry[V]
22+
Next *orderedMapEntry[V]
2323
}
2424

2525
// ----------------------------------------------------------------
26-
func NewOrderedMap() *OrderedMap {
27-
return &OrderedMap{
26+
func NewOrderedMap[V any]() *OrderedMap[V] {
27+
return &OrderedMap[V]{
2828
FieldCount: 0,
2929
Head: nil,
3030
Tail: nil,
31-
keysToEntries: make(map[string]*orderedMapEntry),
31+
keysToEntries: make(map[string]*orderedMapEntry[V]),
3232
}
3333
}
3434

3535
// ----------------------------------------------------------------
3636
// Value-copy is up to the caller -- PutReference and PutCopy
3737
// are in the public OrderedMap API.
38-
func newOrderedMapEntry(key *string, value interface{}) *orderedMapEntry {
39-
return &orderedMapEntry{
38+
func newOrderedMapEntry[V any](key *string, value V) *orderedMapEntry[V] {
39+
return &orderedMapEntry[V]{
4040
*key,
4141
value,
4242
nil,
@@ -45,15 +45,15 @@ func newOrderedMapEntry(key *string, value interface{}) *orderedMapEntry {
4545
}
4646

4747
// ----------------------------------------------------------------
48-
func (omap *OrderedMap) IsEmpty() bool {
48+
func (omap *OrderedMap[V]) IsEmpty() bool {
4949
return omap.FieldCount == 0
5050
}
5151

52-
func (omap *OrderedMap) Has(key string) bool {
52+
func (omap *OrderedMap[V]) Has(key string) bool {
5353
return omap.findEntry(&key) != nil
5454
}
5555

56-
func (omap *OrderedMap) findEntry(key *string) *orderedMapEntry {
56+
func (omap *OrderedMap[V]) findEntry(key *string) *orderedMapEntry[V] {
5757
if omap.keysToEntries != nil {
5858
return omap.keysToEntries[*key]
5959
} else {
@@ -67,7 +67,7 @@ func (omap *OrderedMap) findEntry(key *string) *orderedMapEntry {
6767
}
6868

6969
// ----------------------------------------------------------------
70-
func (omap *OrderedMap) Put(key string, value interface{}) {
70+
func (omap *OrderedMap[V]) Put(key string, value V) {
7171
pe := omap.findEntry(&key)
7272
if pe == nil {
7373
pe = newOrderedMapEntry(&key, value)
@@ -90,30 +90,30 @@ func (omap *OrderedMap) Put(key string, value interface{}) {
9090
}
9191

9292
// ----------------------------------------------------------------
93-
func (omap *OrderedMap) Get(key string) interface{} {
93+
func (omap *OrderedMap[V]) Get(key string) V {
9494
pe := omap.findEntry(&key)
9595
if pe == nil {
96-
return nil
97-
} else {
98-
return pe.Value
96+
var zero V
97+
return zero
9998
}
99+
return pe.Value
100100
}
101101

102102
// The Get is sufficient for pointer values -- the caller can check if the
103103
// return value is nil. For int/string values (which are non-nullable) we have
104104
// this method.
105-
func (omap *OrderedMap) GetWithCheck(key string) (interface{}, bool) {
105+
func (omap *OrderedMap[V]) GetWithCheck(key string) (V, bool) {
106106
pe := omap.findEntry(&key)
107107
if pe == nil {
108-
return nil, false
109-
} else {
110-
return pe.Value, true
108+
var zero V
109+
return zero, false
111110
}
111+
return pe.Value, true
112112
}
113113

114114
// ----------------------------------------------------------------
115115
// Returns true if it was found and removed
116-
func (omap *OrderedMap) Remove(key string) bool {
116+
func (omap *OrderedMap[V]) Remove(key string) bool {
117117
pe := omap.findEntry(&key)
118118
if pe == nil {
119119
return false
@@ -124,7 +124,7 @@ func (omap *OrderedMap) Remove(key string) bool {
124124
}
125125

126126
// ----------------------------------------------------------------
127-
func (omap *OrderedMap) unlink(pe *orderedMapEntry) {
127+
func (omap *OrderedMap[V]) unlink(pe *orderedMapEntry[V]) {
128128
if pe == omap.Head {
129129
if pe == omap.Tail {
130130
omap.Head = nil

pkg/terminals/regtest/regtester.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ func (regtester *RegTester) executeSingleCmdFile(
464464
// Set any case-specific environment variables before running the case.
465465
for pe := envKeyValuePairs.Head; pe != nil; pe = pe.Next {
466466
key := pe.Key
467-
value := pe.Value.(string)
467+
value := pe.Value
468468
if verbosityLevel >= 3 {
469469
fmt.Printf("SETENV %s=%s\n", key, value)
470470
}
@@ -825,12 +825,12 @@ func (regtester *RegTester) compareFiles(
825825
func (regtester *RegTester) loadEnvFile(
826826
filename string,
827827
caseDir string,
828-
) (*lib.OrderedMap, error) {
828+
) (*lib.OrderedMap[string], error) {
829829
// If the file doesn't exist that's the normal case -- most cases do not
830830
// have a .env file.
831831
_, err := os.Stat(filename)
832832
if os.IsNotExist(err) {
833-
return lib.NewOrderedMap(), nil
833+
return lib.NewOrderedMap[string](), nil
834834
}
835835

836836
// If the file does exist and isn't loadable, that's an error.
@@ -839,7 +839,7 @@ func (regtester *RegTester) loadEnvFile(
839839
return nil, err
840840
}
841841

842-
keyValuePairs := lib.NewOrderedMap()
842+
keyValuePairs := lib.NewOrderedMap[string]()
843843
lines := strings.Split(contents, "\n")
844844
for _, line := range lines {
845845
line = strings.TrimSuffix(line, "\r")

pkg/transformers/count.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ type TransformerCount struct {
117117
// * Map keys are strings "foo,bar" and "baz,quux".
118118
// * groupedCounts maps "foo,bar" to 1 and "baz,quux" to 1.
119119
// * groupByValues maps "foo,bar" to ["foo", "bar"] and "baz,quux" to ["baz", "quux"].
120-
groupedCounts *lib.OrderedMap
121-
groupingValues *lib.OrderedMap
120+
groupedCounts *lib.OrderedMap[int64]
121+
groupingValues *lib.OrderedMap[[]*mlrval.Mlrval]
122122
}
123123

124124
func NewTransformerCount(
@@ -133,8 +133,8 @@ func NewTransformerCount(
133133
outputFieldName: outputFieldName,
134134

135135
ungroupedCount: 0,
136-
groupedCounts: lib.NewOrderedMap(),
137-
groupingValues: lib.NewOrderedMap(),
136+
groupedCounts: lib.NewOrderedMap[int64](),
137+
groupingValues: lib.NewOrderedMap[[]*mlrval.Mlrval](),
138138
}
139139

140140
if groupByFieldNames == nil {
@@ -200,7 +200,7 @@ func (tr *TransformerCount) countGrouped(
200200
} else {
201201
tr.groupedCounts.Put(
202202
groupingKey,
203-
tr.groupedCounts.Get(groupingKey).(int64)+1,
203+
tr.groupedCounts.Get(groupingKey)+1,
204204
)
205205
}
206206

@@ -224,14 +224,14 @@ func (tr *TransformerCount) countGrouped(
224224
// * Grouping values for key is ["foo", "bar"]
225225
// Here we populate a record with "a=foo,b=bar".
226226

227-
groupingValuesForKey := tr.groupingValues.Get(groupingKey).([]*mlrval.Mlrval)
227+
groupingValuesForKey := tr.groupingValues.Get(groupingKey)
228228
i := 0
229229
for _, groupingValueForKey := range groupingValuesForKey {
230230
newrec.PutCopy(tr.groupByFieldNames[i], groupingValueForKey)
231231
i++
232232
}
233233

234-
countForGroup := outer.Value.(int64)
234+
countForGroup := outer.Value
235235
newrec.PutCopy(tr.outputFieldName, mlrval.FromInt(countForGroup))
236236

237237
outrecAndContext := types.NewRecordAndContext(newrec, &inrecAndContext.Context)

pkg/transformers/count_similar.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ type TransformerCountSimilar struct {
105105
counterFieldName string
106106

107107
// State:
108-
recordListsByGroup *lib.OrderedMap // map from string to *list.List
108+
recordListsByGroup *lib.OrderedMap[*list.List] // map from string to *list.List
109109
}
110110

111111
// ----------------------------------------------------------------
@@ -116,7 +116,7 @@ func NewTransformerCountSimilar(
116116
tr := &TransformerCountSimilar{
117117
groupByFieldNames: groupByFieldNames,
118118
counterFieldName: counterFieldName,
119-
recordListsByGroup: lib.NewOrderedMap(),
119+
recordListsByGroup: lib.NewOrderedMap[*list.List](),
120120
}
121121
return tr, nil
122122
}
@@ -138,18 +138,17 @@ func (tr *TransformerCountSimilar) Transform(
138138
return
139139
}
140140

141-
irecordListForGroup := tr.recordListsByGroup.Get(groupingKey)
142-
if irecordListForGroup == nil { // first time
143-
irecordListForGroup = list.New()
144-
tr.recordListsByGroup.Put(groupingKey, irecordListForGroup)
141+
recordListForGroup := tr.recordListsByGroup.Get(groupingKey)
142+
if recordListForGroup == nil { // first time
143+
recordListForGroup = list.New()
144+
tr.recordListsByGroup.Put(groupingKey, recordListForGroup)
145145
}
146-
recordListForGroup := irecordListForGroup.(*list.List)
147146

148147
recordListForGroup.PushBack(inrecAndContext)
149148
} else {
150149

151150
for outer := tr.recordListsByGroup.Head; outer != nil; outer = outer.Next {
152-
recordListForGroup := outer.Value.(*list.List)
151+
recordListForGroup := outer.Value
153152
// TODO: make 64-bit friendly
154153
groupSize := recordListForGroup.Len()
155154
mgroupSize := mlrval.FromInt(int64(groupSize))

pkg/transformers/group_by.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ type TransformerGroupBy struct {
9393

9494
// state
9595
// map from string to *list.List
96-
recordListsByGroup *lib.OrderedMap
96+
recordListsByGroup *lib.OrderedMap[*list.List]
9797
}
9898

9999
func NewTransformerGroupBy(
@@ -103,7 +103,7 @@ func NewTransformerGroupBy(
103103
tr := &TransformerGroupBy{
104104
groupByFieldNames: groupByFieldNames,
105105

106-
recordListsByGroup: lib.NewOrderedMap(),
106+
recordListsByGroup: lib.NewOrderedMap[*list.List](),
107107
}
108108

109109
return tr, nil
@@ -132,11 +132,11 @@ func (tr *TransformerGroupBy) Transform(
132132
tr.recordListsByGroup.Put(groupingKey, recordListForGroup)
133133
}
134134

135-
recordListForGroup.(*list.List).PushBack(inrecAndContext)
135+
recordListForGroup.PushBack(inrecAndContext)
136136

137137
} else {
138138
for outer := tr.recordListsByGroup.Head; outer != nil; outer = outer.Next {
139-
recordListForGroup := outer.Value.(*list.List)
139+
recordListForGroup := outer.Value
140140
for inner := recordListForGroup.Front(); inner != nil; inner = inner.Next() {
141141
outputRecordsAndContexts.PushBack(inner.Value.(*types.RecordAndContext))
142142
}

pkg/transformers/group_like.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,13 @@ func transformerGroupLikeParseCLI(
7979
// ----------------------------------------------------------------
8080
type TransformerGroupLike struct {
8181
// map from string to *list.List
82-
recordListsByGroup *lib.OrderedMap
82+
recordListsByGroup *lib.OrderedMap[*list.List]
8383
}
8484

8585
func NewTransformerGroupLike() (*TransformerGroupLike, error) {
8686

8787
tr := &TransformerGroupLike{
88-
recordListsByGroup: lib.NewOrderedMap(),
88+
recordListsByGroup: lib.NewOrderedMap[*list.List](),
8989
}
9090

9191
return tr, nil
@@ -111,11 +111,11 @@ func (tr *TransformerGroupLike) Transform(
111111
tr.recordListsByGroup.Put(groupingKey, recordListForGroup)
112112
}
113113

114-
recordListForGroup.(*list.List).PushBack(inrecAndContext)
114+
recordListForGroup.PushBack(inrecAndContext)
115115

116116
} else {
117117
for outer := tr.recordListsByGroup.Head; outer != nil; outer = outer.Next {
118-
recordListForGroup := outer.Value.(*list.List)
118+
recordListForGroup := outer.Value
119119
for inner := recordListForGroup.Front(); inner != nil; inner = inner.Next() {
120120
outputRecordsAndContexts.PushBack(inner.Value.(*types.RecordAndContext))
121121
}

0 commit comments

Comments
 (0)