hyb
2025-10-24 43c4449e6c9231446895ad26d169825ca7a65c9a
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
import threading
from typing import Any, Generic, List, TypeVar
 
from redis.typing import Number
 
T = TypeVar("T")
 
 
class WeightedList(Generic[T]):
    """
    Thread-safe weighted list.
    """
 
    def __init__(self):
        self._items: List[tuple[Any, Number]] = []
        self._lock = threading.RLock()
 
    def add(self, item: Any, weight: float) -> None:
        """Add item with weight, maintaining sorted order"""
        with self._lock:
            # Find insertion point using binary search
            left, right = 0, len(self._items)
            while left < right:
                mid = (left + right) // 2
                if self._items[mid][1] < weight:
                    right = mid
                else:
                    left = mid + 1
 
            self._items.insert(left, (item, weight))
 
    def remove(self, item):
        """Remove first occurrence of item"""
        with self._lock:
            for i, (stored_item, weight) in enumerate(self._items):
                if stored_item == item:
                    self._items.pop(i)
                    return weight
            raise ValueError("Item not found")
 
    def get_by_weight_range(
        self, min_weight: float, max_weight: float
    ) -> List[tuple[Any, Number]]:
        """Get all items within weight range"""
        with self._lock:
            result = []
            for item, weight in self._items:
                if min_weight <= weight <= max_weight:
                    result.append((item, weight))
            return result
 
    def get_top_n(self, n: int) -> List[tuple[Any, Number]]:
        """Get top N the highest weighted items"""
        with self._lock:
            return [(item, weight) for item, weight in self._items[:n]]
 
    def update_weight(self, item, new_weight: float):
        with self._lock:
            """Update weight of an item"""
            old_weight = self.remove(item)
            self.add(item, new_weight)
            return old_weight
 
    def __iter__(self):
        """Iterate in descending weight order"""
        with self._lock:
            items_copy = (
                self._items.copy()
            )  # Create snapshot as lock released after each 'yield'
 
        for item, weight in items_copy:
            yield item, weight
 
    def __len__(self):
        with self._lock:
            return len(self._items)
 
    def __getitem__(self, index) -> tuple[Any, Number]:
        with self._lock:
            item, weight = self._items[index]
            return item, weight