1
+ use std:: cell:: RefCell ;
2
+ use std:: collections:: HashMap ;
3
+ use std:: ops:: DerefMut ;
4
+ use std:: rc:: Rc ;
5
+
6
+ #[ derive( Debug , Default ) ]
7
+ struct LinkedListNode {
8
+ key : i32 ,
9
+ value : i32 ,
10
+ newer : Option < Rc < RefCell < LinkedListNode > > > ,
11
+ older : Option < Rc < RefCell < LinkedListNode > > > ,
12
+ }
13
+
14
+ #[ derive( Default ) ]
15
+ struct LRUCache {
16
+ head : Option < Rc < RefCell < LinkedListNode > > > ,
17
+ tail : Option < Rc < RefCell < LinkedListNode > > > ,
18
+ /// Key to node map for constant time access to node by key inside list
19
+ map : HashMap < i32 , Rc < RefCell < LinkedListNode > > > ,
20
+ capacity : usize ,
21
+ }
22
+
23
+ fn move_to_head (
24
+ head : & mut Option < Rc < RefCell < LinkedListNode > > > ,
25
+ tail : & mut Option < Rc < RefCell < LinkedListNode > > > ,
26
+ node_ref : & mut Rc < RefCell < LinkedListNode > > ,
27
+ ) {
28
+ let mut borrowed = node_ref. borrow_mut ( ) ;
29
+ let LinkedListNode { newer, older, .. } = borrowed. deref_mut ( ) ;
30
+ match ( older. is_some ( ) , newer. is_some ( ) ) {
31
+ // It is already head
32
+ ( _, false ) => { }
33
+ // It is tail
34
+ ( false , _) => {
35
+ // Reconnect tail to next item, now newer contains old tail
36
+ std:: mem:: swap ( tail, newer) ;
37
+ // Steal link to old tail from new tail and put it to old head
38
+ let stollen_link = tail. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . older . take ( ) ;
39
+ head. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . newer = stollen_link;
40
+ // Now moved node will point to old head and head will point to None
41
+ std:: mem:: swap ( older, head) ;
42
+ // Reconnect old tail node to head
43
+ std:: mem:: swap ( head, newer) ;
44
+ }
45
+ // It is somewhere in between head and tail
46
+ _ => {
47
+ // Invalidate older link (move its value to newer node's link to older)
48
+ std:: mem:: swap ( older, & mut newer. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . older ) ;
49
+ let mut newer_clone = newer. clone ( ) ;
50
+ // At this stage neighbors are pointing to each other, and newer_clone is pointing to node_ref
51
+ std:: mem:: swap (
52
+ & mut newer_clone,
53
+ & mut newer
54
+ . as_mut ( )
55
+ . unwrap ( )
56
+ . borrow_mut ( )
57
+ . older
58
+ . as_mut ( )
59
+ . unwrap ( )
60
+ . borrow_mut ( )
61
+ . newer ,
62
+ ) ;
63
+ // Let's finally put it to head (older now points to old head)
64
+ std:: mem:: swap ( head, older) ;
65
+ // New head have no newer nodes
66
+ * newer = None ;
67
+ // Old head should point to new head
68
+ std:: mem:: swap ( & mut older. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . newer , & mut newer_clone) ;
69
+ }
70
+ }
71
+ }
72
+
73
+ /**
74
+ * `&self` means the method takes an immutable reference.
75
+ * If you need a mutable reference, change it to `&mut self` instead.
76
+ */
77
+ impl LRUCache {
78
+ fn new ( capacity : i32 ) -> Self {
79
+ let capacity = capacity as usize ;
80
+ Self {
81
+ map : HashMap :: with_capacity ( capacity) ,
82
+ capacity,
83
+ ..Default :: default ( )
84
+ }
85
+ }
86
+
87
+ // Also updates recentness of usage
88
+ fn get ( & mut self , key : i32 ) -> i32 {
89
+ let LRUCache {
90
+ head, tail, map, ..
91
+ } = self ;
92
+ if let Some ( node_ref) = map. get_mut ( & key) {
93
+ let value = node_ref. borrow ( ) . value ;
94
+ move_to_head ( head, tail, node_ref) ;
95
+ value
96
+ } else {
97
+ -1
98
+ }
99
+ }
100
+
101
+ fn put ( & mut self , key : i32 , value : i32 ) {
102
+ let LRUCache {
103
+ head,
104
+ tail,
105
+ map,
106
+ capacity,
107
+ } = self ;
108
+ if let Some ( node_ref) = map. get_mut ( & key) {
109
+ node_ref. borrow_mut ( ) . value = value;
110
+ move_to_head ( head, tail, node_ref) ;
111
+ } else {
112
+ if map. len ( ) == * capacity {
113
+ // Should remove old node before add
114
+ // 1. Detaching the oldest node from list
115
+ let mut node = tail. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . newer . take ( ) ;
116
+ // 2. Point tail to newer node, while detached node should be in `node`
117
+ std:: mem:: swap ( tail, & mut node) ;
118
+ // 3. Drop node from `map`
119
+ map. remove ( dbg ! ( & node. as_mut( ) . unwrap( ) . borrow( ) . key) ) ;
120
+ if tail. is_some ( ) {
121
+ // 4. Node from list should be forgotten at the end of scope => drop last link to it
122
+ tail. as_mut ( ) . unwrap ( ) . borrow_mut ( ) . older = None ;
123
+ }
124
+ }
125
+ if map. is_empty ( ) {
126
+ // First node is head and tail at same time
127
+ let node = Rc :: new ( RefCell :: new ( LinkedListNode {
128
+ key,
129
+ value,
130
+ ..Default :: default ( )
131
+ } ) ) ;
132
+ map. insert ( key, node. clone ( ) ) ;
133
+ * head = Some ( node. clone ( ) ) ;
134
+ * tail = Some ( node) ;
135
+ } else {
136
+ // Otherwise connect to head as the most fresh
137
+ let node = Rc :: new ( RefCell :: new ( LinkedListNode {
138
+ key,
139
+ value,
140
+ older : head. take ( ) ,
141
+ ..Default :: default ( )
142
+ } ) ) ;
143
+ let link_for_previous_head = node. clone ( ) ;
144
+ node. borrow_mut ( )
145
+ . older
146
+ . as_mut ( )
147
+ . unwrap ( )
148
+ . borrow_mut ( )
149
+ . newer
150
+ . replace ( link_for_previous_head) ;
151
+ map. insert ( key, node. clone ( ) ) ;
152
+ // Reinitialize head (it is None after previous action) by node as new head.
153
+ * head = Some ( node) ;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Your LRUCache object will be instantiated and called as such:
161
+ * let obj = LRUCache::new(capacity);
162
+ * let ret_1: i32 = obj.get(key);
163
+ * obj.put(key, value);
164
+ */
0 commit comments