-
Notifications
You must be signed in to change notification settings - Fork 1
/
cache_expected.py
146 lines (125 loc) · 5.53 KB
/
cache_expected.py
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import sys
import hash_table_expected
# Implement a data structure that stores the most recently accessed N pages.
# See the below test cases to see how it should work.
#
# Note: Please do not use a library like collections.OrderedDict). The goal is
# to implement the data structure yourself!
class Cache:
# Initialize the cache.
# |n|: The size of the cache.
def __init__(self, n):
assert(n >= 1)
self.list_head = {"url": "", "contents": "", "prev": None, "next": None}
self.list_tail = {"url": "", "contents": "", "prev": None, "next": None}
self.list_head["next"] = self.list_tail
self.list_tail["prev"] = self.list_head
self.n = n
self.count = 0
self.url_to_node = hash_table_expected.HashTable()
# Access a page and update the cache so that it stores the most recently
# accessed N pages. This needs to be done with mostly O(1).
# |url|: The accessed URL
# |contents|: The contents of the URL
def access_page(self, url, contents):
(node, _) = self.url_to_node.get(url)
if node is not None:
assert(node["prev"])
assert(node["next"])
node["prev"]["next"] = node["next"]
node["next"]["prev"] = node["prev"]
else:
if self.count >= self.n:
tail = self.list_tail["prev"]
self.url_to_node.delete(tail["url"])
tail["prev"]["next"] = self.list_tail
self.list_tail["prev"] = tail["prev"]
self.count -= 1
node = {"url": url, "contents": contents, "prev": None, "next": None}
self.url_to_node.put(url, node)
self.count += 1
node["next"] = self.list_head["next"]
node["prev"] = self.list_head
self.list_head["next"]["prev"] = node
self.list_head["next"] = node
# Return the URLs stored in the cache. The URLs are ordered in the order
# in which the URLs are mostly recently accessed.
def get_pages(self):
node = self.list_head["next"]
urls = []
count = 0
while node["next"]:
assert(node["url"] != "")
assert(self.url_to_node.get(node["url"]) == (node, True))
assert(node["prev"]["next"] == node)
assert(node["next"]["prev"] == node)
urls.append(node["url"])
node = node["next"]
count += 1
assert(count == self.count)
return urls
def cache_test():
# Set the size of the cache to 4.
cache = Cache(4)
# Initially, no page is cached.
assert cache.get_pages() == []
# Access "a.com".
cache.access_page("a.com", "AAA")
# "a.com" is cached.
assert cache.get_pages() == ["a.com"]
# Access "b.com".
cache.access_page("b.com", "BBB")
# The cache is updated to:
# (most recently accessed)<-- "b.com", "a.com" -->(least recently accessed)
assert cache.get_pages() == ["b.com", "a.com"]
# Access "c.com".
cache.access_page("c.com", "CCC")
# The cache is updated to:
# (most recently accessed)<-- "c.com", "b.com", "a.com" -->(least recently accessed)
assert cache.get_pages() == ["c.com", "b.com", "a.com"]
# Access "d.com".
cache.access_page("d.com", "DDD")
# The cache is updated to:
# (most recently accessed)<-- "d.com", "c.com", "b.com", "a.com" -->(least recently accessed)
assert cache.get_pages() == ["d.com", "c.com", "b.com", "a.com"]
# Access "d.com" again.
cache.access_page("d.com", "DDD")
# The cache is updated to:
# (most recently accessed)<-- "d.com", "c.com", "b.com", "a.com" -->(least recently accessed)
assert cache.get_pages() == ["d.com", "c.com", "b.com", "a.com"]
# Access "a.com" again.
cache.access_page("a.com", "AAA")
# The cache is updated to:
# (most recently accessed)<-- "a.com", "d.com", "c.com", "b.com" -->(least recently accessed)
assert cache.get_pages() == ["a.com", "d.com", "c.com", "b.com"]
cache.access_page("c.com", "CCC")
assert cache.get_pages() == ["c.com", "a.com", "d.com", "b.com"]
cache.access_page("a.com", "AAA")
assert cache.get_pages() == ["a.com", "c.com", "d.com", "b.com"]
cache.access_page("a.com", "AAA")
assert cache.get_pages() == ["a.com", "c.com", "d.com", "b.com"]
# Access "e.com".
cache.access_page("e.com", "EEE")
# The cache is full, so we need to remove the least recently accessed page "b.com".
# The cache is updated to:
# (most recently accessed)<-- "e.com", "a.com", "c.com", "d.com" -->(least recently accessed)
assert cache.get_pages() == ["e.com", "a.com", "c.com", "d.com"]
# Access "f.com".
cache.access_page("f.com", "FFF")
# The cache is full, so we need to remove the least recently accessed page "c.com".
# The cache is updated to:
# (most recently accessed)<-- "f.com", "e.com", "a.com", "c.com" -->(least recently accessed)
assert cache.get_pages() == ["f.com", "e.com", "a.com", "c.com"]
# Access "e.com".
cache.access_page("e.com", "EEE")
# The cache is updated to:
# (most recently accessed)<-- "e.com", "f.com", "a.com", "c.com" -->(least recently accessed)
assert cache.get_pages() == ["e.com", "f.com", "a.com", "c.com"]
# Access "a.com".
cache.access_page("a.com", "AAA")
# The cache is updated to:
# (most recently accessed)<-- "a.com", "e.com", "f.com", "c.com" -->(least recently accessed)
assert cache.get_pages() == ["a.com", "e.com", "f.com", "c.com"]
print("Tests passed!")
if __name__ == "__main__":
cache_test()