1
- from typing import List , Optional
1
+ from typing import List , Optional , Generic , TypeVar , Dict
2
2
from selfie_lib .CommentTracker import SnapshotFileLayout
3
- import inspect
3
+ from abc import ABC , abstractmethod
4
+ import inspect , threading
4
5
from functools import total_ordering
5
6
7
+ T = TypeVar ("T" )
8
+ U = TypeVar ("U" )
9
+
6
10
7
11
@total_ordering
8
12
class CallLocation :
@@ -56,6 +60,17 @@ def ide_link(self, layout: "SnapshotFileLayout") -> str:
56
60
]
57
61
return "\n " .join (links )
58
62
63
+ def __eq__ (self , other ):
64
+ if not isinstance (other , CallStack ):
65
+ return NotImplemented
66
+ return (
67
+ self .location == other .location
68
+ and self .rest_of_stack == other .rest_of_stack
69
+ )
70
+
71
+ def __hash__ (self ):
72
+ return hash ((self .location , tuple (self .rest_of_stack )))
73
+
59
74
60
75
def recordCall (callerFileOnly : bool = False ) -> CallStack :
61
76
stack_frames = inspect .stack ()[1 :]
@@ -74,3 +89,46 @@ def recordCall(callerFileOnly: bool = False) -> CallStack:
74
89
rest_of_stack = call_locations [1 :]
75
90
76
91
return CallStack (location , rest_of_stack )
92
+
93
+
94
+ class FirstWrite (Generic [U ]):
95
+ def __init__ (self , snapshot : U , call_stack : CallStack ):
96
+ self .snapshot = snapshot
97
+ self .call_stack = call_stack
98
+
99
+
100
+ class WriteTracker (ABC , Generic [T , U ]):
101
+ def __init__ (self ):
102
+ self .lock = threading .Lock ()
103
+ self .writes : Dict [T , FirstWrite [U ]] = {}
104
+
105
+ @abstractmethod
106
+ def record (self , key : T , snapshot : U , call : CallStack , layout : SnapshotFileLayout ):
107
+ pass
108
+
109
+ def recordInternal (
110
+ self ,
111
+ key : T ,
112
+ snapshot : U ,
113
+ call : CallStack ,
114
+ layout : SnapshotFileLayout ,
115
+ allow_multiple_equivalent_writes : bool = True ,
116
+ ):
117
+ with self .lock :
118
+ this_write = FirstWrite (snapshot , call )
119
+ if key not in self .writes :
120
+ self .writes [key ] = this_write
121
+ return
122
+
123
+ existing = self .writes [key ]
124
+ if existing .snapshot != snapshot :
125
+ raise ValueError (
126
+ f"Snapshot was set to multiple values!\n first time: { existing .call_stack .location .ide_link (layout )} \n this time: { call .location .ide_link (layout )} \n "
127
+ )
128
+ elif not allow_multiple_equivalent_writes :
129
+ raise ValueError ("Snapshot was set to the same value multiple times." )
130
+
131
+
132
+ class DiskWriteTracker (WriteTracker [T , U ]):
133
+ def record (self , key : T , snapshot : U , call : CallStack , layout : SnapshotFileLayout ):
134
+ super ().recordInternal (key , snapshot , call , layout )
0 commit comments