|
15 | 15 | package keepsorted |
16 | 16 |
|
17 | 17 | import ( |
| 18 | + "cmp" |
18 | 19 | "errors" |
19 | 20 | "fmt" |
20 | 21 | "iter" |
@@ -493,3 +494,42 @@ func (t numericTokens) compare(o numericTokens) int { |
493 | 494 | // smaller is less than the other. |
494 | 495 | return t.len() - o.len() |
495 | 496 | } |
| 497 | + |
| 498 | +type prefixOrder struct { |
| 499 | + opts blockOptions |
| 500 | + prefixWeights map[string]int |
| 501 | + prefixes []string |
| 502 | +} |
| 503 | + |
| 504 | +func newPrefixOrder(opts blockOptions) *prefixOrder { |
| 505 | + // Assign a weight to each prefix so that they will be sorted into their |
| 506 | + // predetermined order. |
| 507 | + // Weights are negative so that entries with matching prefixes are put before |
| 508 | + // any non-matching line (which will have a weight of 0). |
| 509 | + // |
| 510 | + // An empty prefix can be used to move "non-matching" entries to a position |
| 511 | + // between other prefixes. |
| 512 | + prefixWeights := make(map[string]int) |
| 513 | + for i, p := range opts.PrefixOrder { |
| 514 | + prefixWeights[p] = i - len(opts.PrefixOrder) |
| 515 | + } |
| 516 | + // Sort prefixes longest -> shortest to find the most appropriate weight. |
| 517 | + longestFirst := comparing(func(s string) int { return len(s) }).reversed() |
| 518 | + prefixes := slices.SortedStableFunc(slices.Values(opts.PrefixOrder), longestFirst) |
| 519 | + |
| 520 | + return &prefixOrder{opts, prefixWeights, prefixes} |
| 521 | +} |
| 522 | + |
| 523 | +func (o prefixOrder) match(s string) orderedPrefix { |
| 524 | + pre, _ := o.opts.hasPrefix(s, slices.Values(o.prefixes)) |
| 525 | + return orderedPrefix{pre, o.prefixWeights[pre]} |
| 526 | +} |
| 527 | + |
| 528 | +type orderedPrefix struct { |
| 529 | + prefix string |
| 530 | + weight int |
| 531 | +} |
| 532 | + |
| 533 | +func (pre orderedPrefix) compare(other orderedPrefix) int { |
| 534 | + return cmp.Compare(pre.weight, other.weight) |
| 535 | +} |
0 commit comments