Skip to content

Commit c2f304b

Browse files
committed
WIP
1 parent 13681be commit c2f304b

File tree

9 files changed

+510
-238
lines changed

9 files changed

+510
-238
lines changed

aiomisc/cache/base.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
from abc import ABC, abstractmethod
2-
from typing import Any, Hashable
2+
from typing import Any, Hashable, Dict
33

44

5-
class CacheBase(ABC):
6-
__slots__ = "max_size",
5+
class CachePolicy(ABC):
6+
__slots__ = "max_size", "cache"
77

8-
def __init__(self, max_size: int = 0):
8+
def __init__(self, cache: Dict[Hashable, Any], max_size: int = 0):
99
self.max_size = max_size
10+
self.cache = cache
11+
self._on_init()
12+
13+
def _on_init(self):
14+
pass
1015

1116
@abstractmethod
1217
def get(self, key: Hashable):

aiomisc/cache/dllist.py

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
from multiprocessing import RLock
2+
from typing import Optional, Any, Hashable, Type
3+
4+
5+
class Node:
6+
__slots__ = 'prev', 'next', 'value', 'parent'
7+
8+
prev: Optional["Node"]
9+
next: Optional["Node"]
10+
parent: "DLList"
11+
12+
def __init__(self, parent: "DLList", prev: "Node" = None,
13+
next: "Node" = None):
14+
self.parent = parent
15+
self.prev = prev
16+
self.next = next
17+
self.value = None
18+
19+
def __repr__(self) -> str:
20+
return f"<{self.__class__.__name__} " \
21+
f"{id(self)}: next={id(self.next)} " \
22+
f"prev={id(self.prev)}>"
23+
24+
def remove(self):
25+
if self.next is None:
26+
return
27+
28+
with self.parent.lock:
29+
self.prev.next = self.next
30+
self.prev = None
31+
self.next = None
32+
33+
def append_left(self, node: "Node") -> "Node":
34+
"""
35+
Appends node before the parent node
36+
37+
before:
38+
39+
... <-> [self] <-> ...
40+
41+
after:
42+
43+
... <-> [node] <-> [self] <-> ...
44+
45+
"""
46+
with self.parent.lock:
47+
self.parent.nodes.add(node)
48+
node.next = self
49+
50+
if self.prev is not None:
51+
node.prev = self.prev
52+
53+
self.prev = node
54+
return node
55+
56+
def append_right(self, node: "Node") -> "Node":
57+
"""
58+
Appends node after parent node
59+
60+
before:
61+
62+
... <-> [self] <-> ...
63+
64+
after:
65+
66+
... <-> [self] <-> [node] <-> ...
67+
68+
"""
69+
70+
with self.parent.lock:
71+
self.parent.nodes.add(node)
72+
node.prev = self
73+
74+
if self.next is not None:
75+
node.next = self.next
76+
77+
self.next = node
78+
return node
79+
80+
def swap(self, other: "Node"):
81+
"""
82+
Swaps two Nodes and change neighbor links
83+
84+
Example: doubly linked list looks like:
85+
86+
[x] <-> [self] <-> [z] <-> [other] <-> [y]
87+
node x node self node z node other node y
88+
p n p n p n p n p n
89+
-------------------------------------------------------
90+
- self x z self other z y other -
91+
92+
After swap should looks like:
93+
94+
[x] <-> [other] <-> [z] <-> [self] <-> [y]
95+
node x node other node z node self node y
96+
p n p n p n p n p n
97+
--------------------------------------------------------
98+
- other x z other b z y other -
99+
100+
That's means we should make 8 changes
101+
102+
# 4 for "a" and "b"
103+
a.prev, a.next, b.prev, b.next = b.prev, b.next, a.prev, a.next
104+
105+
# 4 for neighbors
106+
x.next, z.prev, z.next, y.prev = b, b, a, a
107+
108+
After general case is should be:
109+
110+
a.prev.next, a.next.prev, b.prev.next, b.next.prev = b, b, a, a
111+
a.prev, a.next, b.prev, b.next = b.prev, b.next, a.prev, a.next
112+
113+
"""
114+
with self.parent.lock:
115+
# store original links
116+
self_prev, self_next, other_prev, other_next = (
117+
self.prev, self.next, other.prev, other.next
118+
)
119+
120+
if self_prev is not None:
121+
self_prev.next = other
122+
self.prev = other_prev
123+
124+
if self_next is not None:
125+
self_next.prev = other
126+
self.next = other_next
127+
128+
if other_next is not None:
129+
other_next.prev = self
130+
other.next = other_next
131+
132+
if other_prev is not None:
133+
other_prev.next = self
134+
other.prev = self_prev
135+
136+
first_set = False
137+
last_set = False
138+
139+
if not last_set and self is self.parent.last:
140+
self.parent.last = other
141+
last_set = True
142+
143+
if not first_set and self is self.parent.first:
144+
self.parent.first = other
145+
first_set = True
146+
147+
if not last_set and other is self.parent.last:
148+
self.parent.last = self
149+
150+
if not first_set and other is self.parent.first:
151+
self.parent.first = self
152+
153+
154+
class Item:
155+
__slots__ = 'node', 'key', 'value'
156+
157+
node: Node
158+
key: Hashable
159+
value: Any
160+
161+
def __init__(self, node: Node, key: Hashable, value: Any):
162+
self.node = node
163+
self.key = key
164+
self.value = value
165+
166+
167+
class DLList:
168+
__slots__ = 'first', 'last', 'lock', 'nodes'
169+
170+
NODE_CLASS: Type[Node] = Node
171+
ITEM_CLASS: Type[Item] = Item
172+
173+
first: Optional[NODE_CLASS]
174+
last: Optional[NODE_CLASS]
175+
176+
def __init__(self):
177+
self.lock = RLock()
178+
self.first = None
179+
self.last = None
180+
self.nodes = set()
181+
182+
def __len__(self):
183+
return len(self.nodes)
184+
185+
def __contains__(self, item: NODE_CLASS):
186+
return item in self.nodes
187+
188+
def __iter__(self):
189+
with self.lock:
190+
first = self.first
191+
while first is not None:
192+
yield first
193+
first = first.next
194+
195+
def _create_node(self, *args, **kwargs):
196+
node = self.NODE_CLASS(self, *args, **kwargs)
197+
self.nodes.add(node)
198+
return node
199+
200+
def remove(self, node: NODE_CLASS):
201+
if node not in self.nodes:
202+
raise ValueError(f"Node {node!r} is not part of {self!r}")
203+
204+
with self.lock:
205+
self.nodes.remove(node)
206+
if node.prev is not None:
207+
node.prev.next = node.next
208+
if node.next is not None:
209+
node.next.prev = node.prev
210+
211+
if self.first is node:
212+
self.first = node.next
213+
214+
if self.last is node:
215+
self.last = node.prev
216+
217+
def create_left(self) -> NODE_CLASS:
218+
with self.lock:
219+
if self.first is None:
220+
self.first = self._create_node()
221+
self.last = self.first
222+
return self.first
223+
224+
node = self._create_node(next=self.first)
225+
self.first.prev = node
226+
self.first = node
227+
return node
228+
229+
def create_right(self) -> NODE_CLASS:
230+
with self.lock:
231+
if self.first is None:
232+
self.last = self._create_node()
233+
self.first = self.last
234+
return self.first
235+
236+
node = self._create_node(prev=self.last)
237+
self.last.next = node
238+
self.last = node
239+
return node

0 commit comments

Comments
 (0)