package main // SortedIndex — a generic sorted container with O(log N) insert and O(N) iteration // in sort order. Backed by a slice. For posts/2, this is fine; if we need true // O(log N) random access, swap for a btree.BTree from google/btree. // // The key is extracted from the value via Less. The index is NOT safe for // concurrent use; the Store's mu guards all access. type SortedIndex[T any] struct { less func(a, b T) bool items []T index map[any]int // value-identity -> position in items (for fast Update/Delete) } func NewSortedIndex[T any](less func(a, b T) bool) *SortedIndex[T] { return &SortedIndex[T]{ less: less, items: make([]T, 0, 64), index: make(map[any]int, 64), } } func (idx *SortedIndex[T]) Insert(v T) { key := indexKey(v) pos := idx.findPos(v) idx.items = append(idx.items[:pos], append([]T{v}, idx.items[pos:]...)...) // Rebuild index for positions >= pos (slice shifted right by 1) for k, p := range idx.index { if p >= pos { idx.index[k] = p + 1 } } idx.index[key] = pos } func (idx *SortedIndex[T]) Update(v T) { // Same value, but its sort key may have changed. Delete + re-insert. idx.Delete(v) idx.Insert(v) } func (idx *SortedIndex[T]) Delete(v T) { key := indexKey(v) pos, ok := idx.index[key] if !ok { return } idx.items = append(idx.items[:pos], idx.items[pos+1:]...) delete(idx.index, key) // Rebuild index for positions > pos (slice shifted left by 1) for k, p := range idx.index { if p > pos { idx.index[k] = p - 1 } } } func (idx *SortedIndex[T]) Items() []T { out := make([]T, len(idx.items)) copy(out, idx.items) return out } func (idx *SortedIndex[T]) Len() int { return len(idx.items) } // findPos — binary search for insertion point. func (idx *SortedIndex[T]) findPos(v T) int { lo, hi := 0, len(idx.items) for lo < hi { mid := (lo + hi) / 2 if idx.less(idx.items[mid], v) { lo = mid + 1 } else { hi = mid } } return lo } // indexKey — identity key. Pointer types (which *Post, *Comment are) work // because we use pointer identity. Value types would need a different scheme. func indexKey(v any) any { return v }