aboutsummaryrefslogtreecommitdiff
path: root/challenge-049/arne-sommer/raku/lib/Cache/LRU.rakumod
blob: a241a73e1058e8ee10346359ef9099065921cf11 (plain)
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
class Cache::LRU
{
  has $.limit  is rw = 3;
  has $.verbose      = False;
  has %.lookup is rw = ();
  has $.head   is rw = Any;    # Highest
  has $.tail   is rw = Any;    # Lowest

  class LRU-elem
  {
    has $.id;
    has $.payload;
    has $.higher is rw;
    has $.lower  is rw;
  }

  method get-limit
  {
    return self.limit;
  }
    
  method set-limit (Int $new-limit)
  {
    return if $new-limit < 1;
    return if $new-limit == self.limit;

    self.limit = $new-limit;

    self.shrink while self.lookup.keys.elems > self.limit;
    
    say ": New Cache Capacity: { self.limit }" if self.verbose;
  }
  
  method shrink    # remove the last item
  {
    self.lookup{self.tail.id} :delete;
    self.tail = self.tail.higher;
    self.tail.lower = Any;
  }
  
  method !extract ($elem)
  {
    $elem.higher
      ?? ( $elem.higher.lower = $elem.lower )
      !! ( self.head = $elem.lower );

    $elem.lower
      ?? ( $elem.lower.higher = $elem.higher )
      !! ( self.tail = $elem.higher );

    $elem.higher = $elem.lower = Any;
    return $elem;
  }

  method delete ($elem)
  {
    self.lookup{$elem.id}:delete;
    return self!extract($elem);
  }
  
  method get (Int $id)
  {
    say ": get $id " if self.verbose;

    my $current = self.lookup{$id};

    return -1 unless $current;
    
    return $current.payload if $current === self.head;

    self!extract($current);
  
    self.head.higher = $current;
    $current.lower   = self.head;
    self.head        = $current;
  
    return $current.payload;
  }

  method set (Int $id, $value)
  {
    say ": set $id @ $value" if self.verbose;

    my $old-head = self.head;
  
    self.head = LRU-elem.new(id => $id, payload => $value);

    self.head.lower  = $old-head;
    $old-head.higher = self.head if $old-head;
  
    if self.lookup{$id}
    {
      self!extract(self.lookup{$id});
    }
    else   # new
    {
      self.tail = self.head unless self.tail;
      self.shrink if self.lookup.keys == self.limit;
    }
    self.lookup{$id} = self.head;
  }
  
  method dump ($elem = self.head)
  {
    print $elem.id ~ " -> " ~ $elem.payload;
    print " (head)" if $elem === self.head;
    print " (tail)" if $elem === self.tail;
    say "";
   
    self.dump($elem.lower) if $elem.lower;
  }

  method dump2 ($elem = self.head)
  {
    say $elem;
  }
}