dlinked 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dlinked'
4
+
5
+ # A complete, working implementation of a Least Recently Used (LRU) Cache
6
+ # built on top of DLinked::CacheList.
7
+ #
8
+ # An LRU Cache is a high-performance cache that evicts the least recently
9
+ # used item when it reaches its capacity. This example demonstrates how
10
+ # DLinked::CacheList's O(1) operations make it a perfect foundation for
11
+ # this data structure.
12
+ class LRUCache
13
+ # @!attribute [r] capacity
14
+ # @return [Integer] The maximum number of items the cache can hold.
15
+ # @!attribute [r] size
16
+ # @return [Integer] The current number of items in the cache.
17
+ attr_reader :capacity, :size
18
+
19
+ # Initializes a new LRU cache.
20
+ #
21
+ # @param capacity [Integer] The maximum number of items the cache can store.
22
+ # Must be a positive integer.
23
+ def initialize(capacity)
24
+ raise ArgumentError, 'Capacity must be a positive integer' unless capacity.is_a?(Integer) && capacity > 0
25
+
26
+ @capacity = capacity
27
+ @size = 0
28
+ @list = DLinked::CacheList.new
29
+ @data = {}
30
+ end
31
+
32
+ # Retrieves the value for a given key from the cache.
33
+ #
34
+ # If the key exists, it is marked as "most recently used" by being moved
35
+ # to the head of the list. This is an O(1) operation.
36
+ #
37
+ # @param key [Object] The key to look up.
38
+ # @return [Object, nil] The cached value, or `nil` if the key is not found.
39
+ def get(key)
40
+ return nil unless @data.key?(key)
41
+
42
+ # "Touch" the item by moving it to the front of the list, marking it as
43
+ # the most recently used.
44
+ @list.move_to_head_by_key(key)
45
+
46
+ @data[key]
47
+ end
48
+
49
+ # Adds or updates a key-value pair in the cache.
50
+ #
51
+ # - If the key already exists, its value is updated.
52
+ # - If the key is new, it is added to the cache.
53
+ #
54
+ # In both cases, the item is marked as "most recently used."
55
+ #
56
+ # If adding a new item causes the cache to exceed its capacity, the
57
+ # least recently used (LRU) item is automatically evicted.
58
+ # All operations here are O(1).
59
+ #
60
+ # @param key [Object] The key to set.
61
+ # @param value [Object] The value to store.
62
+ # @return [Object] The stored value.
63
+ def set(key, value)
64
+ if @data.key?(key)
65
+ # Key exists, just update the value and mark it as most recently used.
66
+ @list.move_to_head_by_key(key)
67
+ else
68
+ # Key is new. Add it to the front of the list.
69
+ # We store the key in the list, and the value in the hash.
70
+ @list.prepend_key(key, key)
71
+ @size += 1
72
+
73
+ # If we exceeded capacity, evict the least recently used item.
74
+ evict if @size > @capacity
75
+ end
76
+
77
+ # Store the actual data in our hash.
78
+ @data[key] = value
79
+ end
80
+
81
+ # Removes a key-value pair from the cache.
82
+ # This is an O(1) operation.
83
+ #
84
+ # @param key [Object] The key to remove.
85
+ # @return [Object, nil] The value of the removed item, or `nil` if the key was not found.
86
+ def delete(key)
87
+ return nil unless @data.key?(key)
88
+
89
+ @list.remove_by_key(key)
90
+ @size -= 1
91
+ @data.delete(key)
92
+ end
93
+
94
+ # Provides a human-readable view of the cache's state, showing the
95
+ # order of items from most to least recently used.
96
+ #
97
+ # @return [String]
98
+ def to_s
99
+ # Iterate over the keys in the list (from MRU to LRU) and look up their values.
100
+ items = @list.map { |key| "#{key}:#{@data[key]}" }.join(', ')
101
+ "LRUCache (capacity: #{@capacity}, size: #{@size}) [MRU] #{items} [LRU]"
102
+ end
103
+
104
+ private
105
+
106
+ # Evicts the least recently used (LRU) item from the cache.
107
+ # This is an O(1) operation.
108
+ def evict
109
+ # DLinked::CacheList automatically tracks the LRU item at the tail.
110
+ lru_key = @list.pop_key
111
+ return unless lru_key
112
+
113
+ @data.delete(lru_key)
114
+ @size -= 1
115
+ puts "Evicted: #{lru_key}"
116
+ end
117
+ end
118
+
119
+ # --- DEMONSTRATION ---
120
+ if __FILE__ == $PROGRAM_NAME
121
+ puts "--- LRU Cache Demonstration (Capacity: 3) ---"
122
+ cache = LRUCache.new(3)
123
+
124
+ puts "\n1. Setting initial values: a=1, b=2, c=3"
125
+ cache.set(:a, 1)
126
+ cache.set(:b, 2)
127
+ cache.set(:c, 3)
128
+ puts cache # c should be MRU
129
+
130
+ puts "\n2. Accessing key 'a'"
131
+ cache.get(:a)
132
+ puts cache # a should now be MRU
133
+
134
+ puts "\n3. Adding a new item 'd=4' (should evict 'b')"
135
+ cache.set(:d, 4)
136
+ puts cache # d should be MRU, b should be gone
137
+
138
+ puts "\n4. Checking contents"
139
+ puts "cache.get(:a) -> #{cache.get(:a)}"
140
+ puts "cache.get(:b) -> #{cache.get(:b) || 'nil (evicted)'}"
141
+ puts "cache.get(:c) -> #{cache.get(:c)}"
142
+ puts "cache.get(:d) -> #{cache.get(:d)}"
143
+
144
+ puts "\n5. Deleting key 'c'"
145
+ cache.delete(:c)
146
+ puts cache
147
+
148
+ puts "\n6. Clearing the cache"
149
+ cache.set(:e, 5)
150
+ cache.set(:f, 6)
151
+ puts cache
152
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dlinked
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.8
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniele Frisanco
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-14 00:00:00.000000000 Z
11
+ date: 2026-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0.9'
111
+ - !ruby/object:Gem::Dependency
112
+ name: benchmark-ips
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.8'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.8'
111
125
  description: Provides a native Doubly Linked List data structure in Ruby, focusing
112
126
  on O(1) performance for head/tail operations and standard Enumerable compatibility.
113
127
  email:
@@ -120,6 +134,8 @@ files:
120
134
  - ".gitignore"
121
135
  - ".rubocop.yml"
122
136
  - CHANGELOG.md
137
+ - CODE_OF_CONDUCT.md
138
+ - CONTRIBUTING.md
123
139
  - Gemfile
124
140
  - LICENSE.txt
125
141
  - README.md
@@ -132,6 +148,7 @@ files:
132
148
  - lib/d_linked/list/node.rb
133
149
  - lib/d_linked/version.rb
134
150
  - lib/dlinked.rb
151
+ - lru_cache_example.rb
135
152
  homepage: https://github.com/danielefrisanco/dlinked
136
153
  licenses:
137
154
  - MIT