• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

enetx / g / 28683928753

03 Jul 2026 09:22PM UTC coverage: 90.515% (-1.0%) from 91.496%
28683928753

push

github

enetx
feat!: Go 1.27 generic methods — type-changing chains, jsonv2, checked math, API consolidation

BREAKING CHANGES:
- require Go 1.27: iterator and monad chains change payload type in-chain
  (Map[U], Then[U], ThenOf[U], FilterMap[U], FlatMap[U], Fold[A], Scan[A],
  MapOr[U]); Transform[U] is a universal pipe on every wrapper type
- drop pre-1.27 workarounds: TransformSlice/TransformSet/TransformOption/
  TransformResult(Of), MapOption, MapSeqResult, FlattenResult, package-level
  Flatten and Counter, Slice.AsAny, eager Slice.Map/Set.Map, Int.Wrapping*,
  Slice.MaxBy/MinBy, SeqHeap.Eq, Option.Result alias, Int.IsNonNegative
- Zip is fully typed: Zip[U](other) -> SeqPairs[V, U]; SeqPairs.Collect returns
  []Pair by design (generic-method instantiation cycle)
- Split(sep) requires an explicit separator (String and Bytes); Chars() is the
  canonical per-rune iteration
- Int.IsPositive is strict (> 0); String.TryBigInt returns Result;
  GroupBy renamed to ChunkBy (Rust slice::chunk_by semantics);
  File/Dir Exist -> Exists; Dir.Temp/Dir.CreateTemp -> package TempDir/
  CreateTempDir; pool.Reset panics while tasks are running
- JSON is encoding/json/v2: Option/Result implement MarshalJSONTo/
  UnmarshalJSONFrom; invalid UTF-8 and duplicate object keys are rejected;
  nil slices marshal as []; Slice.Set returns Option instead of panicking

Added:
- Int checked/saturating/overflowing arithmetic, Clamp, Signum, Neg;
  Float math and classification (IsNaN/IsInf/IsFinite/IsNormal, Signum,
  Ceil/Floor/Trunc/Fract, Clamp, Recip, Copysign, MulAdd (FMA), Hypot, Cbrt,
  Exp/Ln families, trig, ToDegrees/ToRadians, IsSignPositive/IsSignNegative)
- Result JSON ({"ok": v} / {"err": "msg"}); Result Or/OrElse/IsOkAnd/IsErrAnd/
  InspectErr/UnwrapErr/MapOr/MapOrElse; Option MapOr/MapOrElse/IsNoneOr/ThenOf
- Bytes<->String parity: JSON/URL/HTML/Rot13/Octal codecs; byte-wise Cut,
  Similarity, Truncate, LeftJustify/RightJustify/Center, IsASCII, IsDigit,
  Chunks, SubBytes, Re... (continued)

1177 of 1283 new or added lines in 37 files covered. (91.74%)

33 existing lines in 3 files now uncovered.

6289 of 6948 relevant lines covered (90.52%)

9875.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.24
/map_ordered.go
1
package g
2

3
import (
4
        "fmt"
5
        "math/rand/v2"
6
        "reflect"
7
        "slices"
8

9
        "github.com/enetx/g/cmp"
10
        "github.com/enetx/g/f"
11
        "github.com/enetx/iter"
12
)
13

14
// Pair is a struct representing a key-value Pair for MapOrd.
15
type Pair[K, V any] = iter.Pair[K, V]
16

17
// MapOrd is an ordered map that maintains insertion order using a slice of
18
// key-value pairs. Key lookups (Get, Insert, Contains, Remove, Entry) scan the
19
// slice linearly and are therefore O(n); use Map for O(1) lookups when order is
20
// not required.
21
type MapOrd[K comparable, V any] []Pair[K, V] // ordered key-value pairs
22

23
// NewMapOrd creates a new ordered Map with the specified size (if provided).
24
// An ordered Map is an Map that maintains the order of its key-value pairs based on the
25
// insertion order. If no size is provided, the default size will be used.
26
//
27
// Parameters:
28
//
29
// - size ...int: (Optional) The initial size of the ordered Map. If not provided, a default size
30
// will be used.
31
//
32
// Returns:
33
//
34
// - MapOrd[K, V]: Ordered Map with the specified initial size (or default
35
// size if not provided).
36
//
37
// Example usage:
38
//
39
//        mapOrd := g.NewMapOrd[string, int](10)
40
//
41
// Creates a new ordered Map with an initial size of 10.
42
func NewMapOrd[K comparable, V any](size ...Int) MapOrd[K, V] {
43
        if len(size) > 0 {
237✔
44
                return make(MapOrd[K, V], 0, size[0])
8✔
45
        }
8✔
46

47
        return make(MapOrd[K, V], 0)
229✔
48
}
49

50
// Transform applies a transformation function to the MapOrd and returns the result.
51
func (mo MapOrd[K, V]) Transform[U any](fn func(MapOrd[K, V]) U) U { return fn(mo) }
2✔
52

53
// Entry returns an OrdEntry for the given key.
54
func (mo *MapOrd[K, V]) Entry(key K) OrdEntry[K, V] {
55
        if i := mo.index(key); i != -1 {
49✔
56
                return OccupiedOrdEntry[K, V]{mo: mo, key: key, idx: i}
24✔
57
        }
24✔
58

59
        return VacantOrdEntry[K, V]{mo: mo, key: key}
25✔
60
}
61

62
// Iter returns an iterator (SeqMapOrd[K, V]) for the ordered Map, allowing for sequential iteration
63
// over its key-value pairs. It is commonly used in combination with higher-order functions,
64
// such as 'ForEach', to perform operations on each key-value pair of the ordered Map.
65
//
66
// Returns:
67
//
68
// A SeqMapOrd[K, V], which can be used for sequential iteration over the key-value pairs of the ordered Map.
69
//
70
// Example usage:
71
//
72
//        m := g.NewMapOrd[int, int]()
73
//        m.Insert(1, 1)
74
//        m.Insert(2, 2)
75
//        m.Insert(3, 3)
76
//
77
//        m.Iter().ForEach(func(k, v int) {
78
//            // Process key-value pair
79
//        })
80
//
81
// The 'Iter' method provides a convenient way to traverse the key-value pairs of an ordered Map
82
// in a functional style, enabling operations like mapping or filtering.
83
func (mo MapOrd[K, V]) Iter() SeqMapOrd[K, V] {
84
        return func(yield func(K, V) bool) {
82✔
85
                for _, v := range mo {
81✔
86
                        if !yield(v.Key, v.Value) {
197✔
87
                                return
18✔
88
                        }
18✔
89
                }
90
        }
91
}
92

93
// IterReverse returns an iterator (SeqMapOrd[K, V]) for the ordered Map that allows for sequential iteration
94
// over its key-value pairs in reverse order. This method is useful when you need to process the elements
95
// from the last to the first.
96
//
97
// Returns:
98
//
99
// A SeqMapOrd[K, V], which can be used for sequential iteration over the key-value pairs of the ordered Map in reverse order.
100
//
101
// Example usage:
102
//
103
//        m := g.NewMapOrd[int, int]()
104
//        m.Insert(1, 1)
105
//        m.Insert(2, 2)
106
//        m.Insert(3, 3)
107
//
108
//        m.IterReverse().ForEach(func(k, v int) {
109
//            // Process key-value pair in reverse order
110
//            fmt.Println("Key:", k, "Value:", v)
111
//        })
112
//
113
// The 'IterReverse' method complements the 'Iter' method by providing a way to access the elements
114
// in a reverse sequence, offering additional flexibility in data processing scenarios.
115
func (mo MapOrd[K, V]) IterReverse() SeqMapOrd[K, V] {
116
        return func(yield func(K, V) bool) {
4✔
117
                for i := len(mo) - 1; i >= 0; i-- {
4✔
118
                        v := mo[i]
4✔
119
                        if !yield(v.Key, v.Value) {
4✔
120
                                return
×
121
                        }
×
122
                }
123
        }
124
}
125

126
// MapOrdFromStd converts a standard Go map to an ordered Map.
127
// The resulting ordered Map will maintain the order of its key-value pairs based on the order of
128
// insertion.
129
// This function is useful when you want to create an ordered Map from an existing Go map.
130
//
131
// Parameters:
132
//
133
// - m map[K]V: The input Go map to be converted to an ordered Map.
134
//
135
// Returns:
136
//
137
// - MapOrd[K, V]: New ordered Map containing the same key-value pairs as the
138
// input Go map.
139
//
140
// Example usage:
141
//
142
//        mapOrd := g.MapOrdFromStd[string, int](goMap)
143
//
144
// Converts the standard Go map 'map[K]V' to an ordered Map.
145
func MapOrdFromStd[K comparable, V any](m map[K]V) MapOrd[K, V] { return Map[K, V](m).Ordered() }
2✔
146

147
// SortBy sorts the ordered Map by a custom comparison function.
148
//
149
// Parameters:
150
//
151
// - fn func(a, b Pair[K, V]) cmp.Ordering: The custom comparison function used for sorting the ordered Map.
152
//
153
// Example usage:
154
//
155
//        hmapo.SortBy(func(a, b g.Pair[g.String, g.Int]) cmp.Ordering { return a.Key.Cmp(b.Key) })
156
//        hmapo.SortBy(func(a, b g.Pair[g.String, g.Int]) cmp.Ordering { return a.Value.Cmp(b.Value) })
157
func (mo MapOrd[K, V]) SortBy(fn func(a, b Pair[K, V]) cmp.Ordering) {
158
        slices.SortFunc(mo, func(a, b Pair[K, V]) int { return int(fn(a, b)) })
12✔
159
}
160

161
// SortByKey sorts the ordered MapOrd[K, V] by the keys using a custom comparison function.
162
//
163
// Parameters:
164
//
165
// - fn func(a, b K) cmp.Ordering: The custom comparison function used for sorting the keys.
166
//
167
// Example usage:
168
//
169
//        hmapo.SortByKey(func(a, b g.String) cmp.Ordering { return a.Cmp(b) })
170
func (mo MapOrd[K, V]) SortByKey(fn func(a, b K) cmp.Ordering) {
171
        slices.SortFunc(mo, func(a, b Pair[K, V]) int { return int(fn(a.Key, b.Key)) })
17✔
172
}
173

174
// SortByValue sorts the ordered MapOrd[K, V] by the values using a custom comparison function.
175
//
176
// Parameters:
177
//
178
// - fn func(a, b V) cmp.Ordering: The custom comparison function used for sorting the values.
179
//
180
// Example usage:
181
//
182
//        hmapo.SortByValue(func(a, b g.Int) cmp.Ordering { return a.Cmp(b) })
183
func (mo MapOrd[K, V]) SortByValue(fn func(a, b V) cmp.Ordering) {
184
        slices.SortFunc(mo, func(a, b Pair[K, V]) int { return int(fn(a.Value, b.Value)) })
7✔
185
}
186

187
// IsSortedBy checks if the ordered Map is sorted according to a custom comparison function.
188
//
189
// Parameters:
190
//
191
// - fn func(a, b Pair[K, V]) cmp.Ordering: The custom comparison function used for checking sort order.
192
//
193
// Returns:
194
//
195
// - bool: true if the map is sorted according to the comparison function, false otherwise.
196
//
197
// Example usage:
198
//
199
//        sorted := hmapo.IsSortedBy(func(a, b g.Pair[g.String, g.Int]) cmp.Ordering { return a.Key.Cmp(b.Key) })
200
func (mo MapOrd[K, V]) IsSortedBy(fn func(a, b Pair[K, V]) cmp.Ordering) bool {
201
        if len(mo) <= 1 {
4✔
202
                return true
2✔
203
        }
2✔
204

205
        for i := 1; i < len(mo); i++ {
2✔
206
                if fn(mo[i-1], mo[i]).IsGt() {
3✔
207
                        return false
1✔
208
                }
1✔
209
        }
210

211
        return true
1✔
212
}
213

214
// IsSortedByKey checks if the ordered MapOrd[K, V] is sorted by the keys using a custom comparison function.
215
//
216
// Parameters:
217
//
218
// - fn func(a, b K) cmp.Ordering: The custom comparison function used for checking key sort order.
219
//
220
// Returns:
221
//
222
// - bool: true if the map is sorted by keys according to the comparison function, false otherwise.
223
//
224
// Example usage:
225
//
226
//        sorted := hmapo.IsSortedByKey(func(a, b g.String) cmp.Ordering { return a.Cmp(b) })
227
func (mo MapOrd[K, V]) IsSortedByKey(fn func(a, b K) cmp.Ordering) bool {
228
        if len(mo) <= 1 {
6✔
229
                return true
2✔
230
        }
2✔
231

232
        for i := 1; i < len(mo); i++ {
4✔
233
                if fn(mo[i-1].Key, mo[i].Key).IsGt() {
6✔
234
                        return false
2✔
235
                }
2✔
236
        }
237

238
        return true
2✔
239
}
240

241
// IsSortedByValue checks if the ordered MapOrd[K, V] is sorted by the values using a custom comparison function.
242
//
243
// Parameters:
244
//
245
// - fn func(a, b V) cmp.Ordering: The custom comparison function used for checking value sort order.
246
//
247
// Returns:
248
//
249
// - bool: true if the map is sorted by values according to the comparison function, false otherwise.
250
//
251
// Example usage:
252
//
253
//        sorted := hmapo.IsSortedByValue(func(a, b g.Int) cmp.Ordering { return a.Cmp(b) })
254
func (mo MapOrd[K, V]) IsSortedByValue(fn func(a, b V) cmp.Ordering) bool {
255
        if len(mo) <= 1 {
6✔
256
                return true
2✔
257
        }
2✔
258

259
        for i := 1; i < len(mo); i++ {
4✔
260
                if fn(mo[i-1].Value, mo[i].Value).IsGt() {
6✔
261
                        return false
2✔
262
                }
2✔
263
        }
264

265
        return true
2✔
266
}
267

268
// Clone creates a new ordered Map with the same key-value pairs.
269
func (mo MapOrd[K, V]) Clone() MapOrd[K, V] {
270
        nmo := NewMapOrd[K, V](mo.Len())
4✔
271
        nmo.Copy(mo)
4✔
272

4✔
273
        return nmo
4✔
274
}
4✔
275

276
// Copy copies key-value pairs from the source ordered Map to the current ordered Map.
277
func (mo *MapOrd[K, V]) Copy(src MapOrd[K, V]) {
278
        idx := mo.indexMap()
6✔
279

6✔
280
        for _, p := range src {
6✔
281
                if i, ok := idx[p.Key]; ok {
12✔
282
                        (*mo)[i].Value = p.Value
×
UNCOV
283
                } else {
×
284
                        *mo = append(*mo, p)
12✔
285
                        idx[p.Key] = len(*mo) - 1
12✔
286
                }
12✔
287
        }
288
}
289

290
// Map converts the ordered Map to a standard Map.
291
func (mo MapOrd[K, V]) Map() Map[K, V] {
292
        m := NewMap[K, V](mo.Len())
2✔
293
        for _, p := range mo {
2✔
294
                m[p.Key] = p.Value
3✔
295
        }
3✔
296

297
        return m
2✔
298
}
299

300
// Safe converts a ordered Map to a thread-safe Map.
301
func (mo MapOrd[K, V]) Safe() *MapSafe[K, V] {
302
        ms := NewMapSafe[K, V]()
2✔
303
        for _, p := range mo {
2✔
304
                ms.Insert(p.Key, p.Value)
3✔
305
        }
3✔
306

307
        return ms
2✔
308
}
309

310
// Insert sets the value for the specified key in the ordered Map,
311
// and returns the previous value if it existed.
312
func (mo *MapOrd[K, V]) Insert(key K, value V) Option[V] {
313
        if i := mo.index(key); i != -1 {
458✔
314
                prev := (*mo)[i].Value
8✔
315
                (*mo)[i].Value = value
8✔
316

8✔
317
                return Some(prev)
8✔
318
        }
8✔
319

320
        mp := Pair[K, V]{Key: key, Value: value}
450✔
321
        *mo = append(*mo, mp)
450✔
322

450✔
323
        return None[V]()
450✔
324
}
325

326
// Get returns the value associated with the given key, wrapped in Option[V].
327
//
328
// It returns Some(value) if the key exists, or None if it does not.
329
func (mo MapOrd[K, V]) Get(key K) Option[V] {
330
        if i := mo.index(key); i != -1 {
56✔
331
                return Some(mo[i].Value)
56✔
332
        }
56✔
333

334
        return None[V]()
×
335
}
336

337
// Shuffle randomly reorders the elements of the ordered Map.
338
// It operates in place and affects the original order of the map's entries.
339
//
340
// The function uses the math/rand/v2 package to generate random indices.
341
func (mo MapOrd[K, V]) Shuffle() {
342
        for i := mo.Len() - 1; i > 0; i-- {
2✔
343
                j := rand.N(i + 1)
53✔
344
                mo[i], mo[j] = mo[j], mo[i]
53✔
345
        }
53✔
346
}
347

348
func (mo MapOrd[K, V]) index(key K) int {
349
        for i, mp := range mo {
570✔
350
                if mp.Key == key {
1,862✔
351
                        return i
91✔
352
                }
91✔
353
        }
354

355
        return -1
479✔
356
}
357

358
// Keys returns an Slice containing all the keys in the ordered Map.
359
func (mo MapOrd[K, V]) Keys() Slice[K] {
360
        if len(mo) == 0 {
11✔
361
                return NewSlice[K]()
2✔
362
        }
2✔
363

364
        keys := make(Slice[K], len(mo))
9✔
365
        for i, p := range mo {
9✔
366
                keys[i] = p.Key
24✔
367
        }
24✔
368

369
        return keys
9✔
370
}
371

372
// Values returns an Slice containing all the values in the ordered Map.
373
func (mo MapOrd[K, V]) Values() Slice[V] {
374
        if len(mo) == 0 {
2✔
375
                return NewSlice[V]()
1✔
376
        }
1✔
377

378
        values := make(Slice[V], len(mo))
1✔
379
        for i, p := range mo {
1✔
380
                values[i] = p.Value
3✔
381
        }
3✔
382

383
        return values
1✔
384
}
385

386
// Remove removes the specified key from the ordered Map and returns the removed value.
387
func (mo *MapOrd[K, V]) Remove(key K) Option[V] {
388
        if mo.IsEmpty() {
9✔
389
                return None[V]()
1✔
390
        }
1✔
391

392
        for i, p := range *mo {
8✔
393
                if p.Key == key {
14✔
394
                        *mo = slices.Delete(*mo, i, i+1)
7✔
395
                        return Some(p.Value)
7✔
396
                }
7✔
397
        }
398

399
        return None[V]()
1✔
400
}
401

402
// Eq compares the current ordered Map to another ordered Map and returns true if they are equal.
403
func (mo MapOrd[K, V]) Eq(other MapOrd[K, V]) bool {
404
        if len(mo) != len(other) {
33✔
405
                return false
2✔
406
        }
2✔
407
        if len(mo) == 0 {
31✔
408
                return true
3✔
409
        }
3✔
410

411
        idx := other.indexMap()
28✔
412

28✔
413
        comparable := f.IsComparable[V]() && reflect.TypeFor[V]().Kind() != reflect.Interface
28✔
414
        for i, mp := range mo {
28✔
415
                j, ok := idx[mp.Key]
74✔
416

74✔
417
                if !ok || j != i {
74✔
418
                        return false
1✔
419
                }
1✔
420

421
                if comparable {
73✔
422
                        if any(other[j].Value) != any(mp.Value) {
70✔
423
                                return false
1✔
424
                        }
1✔
425
                } else {
426
                        if !reflect.DeepEqual(other[j].Value, mp.Value) {
3✔
427
                                return false
1✔
428
                        }
1✔
429
                }
430
        }
431

432
        return true
25✔
433
}
434

435
// String returns a string representation of the ordered Map.
436
func (mo MapOrd[K, V]) String() string {
437
        if len(mo) == 0 {
5✔
438
                return "MapOrd{}"
1✔
439
        }
1✔
440

441
        var b Builder
4✔
442
        b.Grow(Int(len(mo)) * 16)
4✔
443
        b.WriteString("MapOrd{")
4✔
444

4✔
445
        first := true
4✔
446
        for _, pair := range mo {
4✔
447
                if !first {
8✔
448
                        b.WriteString(", ")
4✔
449
                }
4✔
450

451
                first = false
8✔
452
                fmt.Fprint(&b, pair.Key)
8✔
453
                b.WriteByte(':')
8✔
454
                fmt.Fprint(&b, pair.Value)
8✔
455
        }
456

457
        b.WriteString("}")
4✔
458

4✔
459
        return b.String().Std()
4✔
460
}
461

462
// Clear removes all key-value pairs from the ordered Map.
463
func (mo *MapOrd[K, V]) Clear() { *mo = (*mo)[:0] }
2✔
464

465
// Contains checks if the ordered Map contains the specified key.
466
func (mo MapOrd[K, V]) Contains(key K) bool { return mo.index(key) != -1 }
7✔
467

468
// Empty checks if the ordered Map is empty.
469
func (mo MapOrd[K, V]) IsEmpty() bool { return len(mo) == 0 }
13✔
470

471
// Len returns the number of key-value pairs in the ordered Map.
472
func (mo MapOrd[K, V]) Len() Int { return Int(len(mo)) }
38✔
473

474
// Ne compares the current ordered Map to another ordered Map and returns true if they are not equal.
475
func (mo MapOrd[K, V]) Ne(other MapOrd[K, V]) bool { return !mo.Eq(other) }
8✔
476

477
// Print writes the key-value pairs of the MapOrd to the standard output (console)
478
// and returns the MapOrd unchanged.
479
func (mo MapOrd[K, V]) Print() MapOrd[K, V] { fmt.Print(mo); return mo }
1✔
480

481
// Println writes the key-value pairs of the MapOrd to the standard output (console) with a newline
482
// and returns the MapOrd unchanged.
483
func (mo MapOrd[K, V]) Println() MapOrd[K, V] { fmt.Println(mo); return mo }
1✔
484

485
// indexMap builds a map from keys to their corresponding indices in the MapOrd.
486
//
487
// This function is used to create a temporary indexMap that maps each key in the
488
// ordered map to its position (insertion order) within the slice. It is useful
489
// for amortizing the cost of repeated lookups within a single bulk operation
490
// such as Copy or Eq, where the per-key linear scan would otherwise be O(n^2).
491
//
492
// Time complexity: O(n), where n is the number of key-value pairs in the MapOrd.
493
func (mo MapOrd[K, V]) indexMap() map[K]int {
494
        idx := make(map[K]int, len(mo))
34✔
495

34✔
496
        for i, p := range mo {
34✔
497
                idx[p.Key] = i
83✔
498
        }
83✔
499

500
        return idx
34✔
501
}
502

503
// PairOf creates a Pair from the provided key and value.
504
//
505
// Example:
506
//
507
//        p := g.PairOf("answer", 42) // Pair[string, int]
508
func PairOf[K, V any](key K, value V) Pair[K, V] { return Pair[K, V]{Key: key, Value: value} }
3✔
509

510
// MapOrdOf creates a MapOrd from the provided key-value pairs, preserving their order.
511
//
512
// Duplicate keys keep their first-seen position, while the value is updated
513
// to the most recent one (last-write-wins).
514
//
515
// Example:
516
//
517
//        mo := g.MapOrdOf(g.PairOf("a", 1), g.PairOf("b", 2))
518
func MapOrdOf[K comparable, V any](pairs ...Pair[K, V]) MapOrd[K, V] {
519
        mo := NewMapOrd[K, V](Int(len(pairs)))
2✔
520
        idx := make(map[K]int, len(pairs))
2✔
521

2✔
522
        for _, p := range pairs {
2✔
523
                if i, ok := idx[p.Key]; ok {
4✔
NEW
524
                        mo[i].Value = p.Value
×
NEW
525
                        continue
×
526
                }
527

528
                idx[p.Key] = len(mo)
4✔
529
                mo = append(mo, p)
4✔
530
        }
531

532
        return mo
2✔
533
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc