1111
1212#include < cstddef>
1313#include < memory_resource>
14+ #include < mutex>
15+ #include < shared_mutex>
1416#if __cplusplus >= 202002L
1517#include < compare>
1618#endif
@@ -24,7 +26,7 @@ class SieveCache {
2426 values_ = static_cast <V*>(mem_resource_->allocate (capacity_ * sizeof (V)));
2527 }
2628
27- SieveCache (size_t capacity, std::pmr::memory_resource* mem_resource)
29+ explicit SieveCache (size_t capacity, std::pmr::memory_resource* mem_resource)
2830 : capacity_(capacity), size_(0 ), mem_resource_(mem_resource) {
2931 keys_ = static_cast <K*>(mem_resource_->allocate (capacity_ * sizeof (K)));
3032 values_ = static_cast <V*>(mem_resource_->allocate (capacity_ * sizeof (V)));
@@ -79,22 +81,24 @@ class SieveCache {
7981 return !(*this == other);
8082 }
8183
82- V& operator [](const K& key) {
84+ inline V& operator [](const K& key) noexcept {
85+ std::shared_lock<std::shared_mutex> lock (rw_mutex_);
8386 for (size_t i = 0 ; i < size_; ++i) {
8487 if (keys_[i] == key) {
8588 return values_[i];
8689 }
8790 }
8891 if (size_ < capacity_) {
89- new (&keys_[size_]) K ( key);
90- new (&values_[size_]) V ( );
92+ construct (&keys_[size_], key);
93+ construct (&values_[size_]);
9194 ++size_;
9295 return values_[size_ - 1 ];
9396 }
94- return values_[0 ]; // Simplified eviction policy
97+ // Handle the case where cache is full
98+ return values_[0 ];
9599 }
96100
97- V* get (const K& key) {
101+ inline V* get (const K& key) noexcept {
98102 for (size_t i = 0 ; i < size_; ++i) {
99103 if (keys_[i] == key) {
100104 return &values_[i];
@@ -103,34 +107,74 @@ class SieveCache {
103107 return nullptr ;
104108 }
105109
106- size_t capacity () const {
110+ inline V* get_locked (const K& key) noexcept {
111+ std::shared_lock<std::shared_mutex> lock (rw_mutex_);
112+ for (size_t i = 0 ; i < size_; ++i) {
113+ if (keys_[i] == key) {
114+ return &values_[i];
115+ }
116+ }
117+ return nullptr ;
118+ }
119+
120+ constexpr size_t capacity () const {
107121 return capacity_;
108122 }
109123
110- bool empty () const {
124+ constexpr bool empty () const {
111125 return size_ == 0 ;
112126 }
113127
114- bool insert (const K& key, const V& value) {
128+ inline bool insert (const K& key, const V& value) noexcept {
129+ if (size_ < capacity_) {
130+ construct (&keys_[size_], key);
131+ construct (&values_[size_], value);
132+ ++size_;
133+ return true ;
134+ }
135+ return false ; // Cache is full
136+ }
137+
138+ inline bool insert_locked (const K& key, const V& value) noexcept {
139+ std::unique_lock<std::shared_mutex> lock (rw_mutex_);
115140 if (size_ < capacity_) {
116- new (&keys_[size_]) K ( key);
117- new (&values_[size_]) V ( value);
141+ construct (&keys_[size_], key);
142+ construct (&values_[size_], value);
118143 ++size_;
119144 return true ;
120145 }
121146 return false ; // Cache is full
122147 }
123148
124- bool remove (const K& key) {
149+ inline bool remove (const K& key) noexcept {
150+ for (size_t i = 0 ; i < size_; ++i) {
151+ if (keys_[i] == key) {
152+ destroy (&keys_[i]);
153+ destroy (&values_[i]);
154+ for (size_t j = i; j < size_ - 1 ; ++j) {
155+ construct (&keys_[j], std::move (keys_[j + 1 ]));
156+ construct (&values_[j], std::move (values_[j + 1 ]));
157+ destroy (&keys_[j + 1 ]);
158+ destroy (&values_[j + 1 ]);
159+ }
160+ --size_;
161+ return true ;
162+ }
163+ }
164+ return false ; // Key not found
165+ }
166+
167+ inline bool remove_locked (const K& key) noexcept {
168+ std::unique_lock<std::shared_mutex> lock (rw_mutex_);
125169 for (size_t i = 0 ; i < size_; ++i) {
126170 if (keys_[i] == key) {
127- keys_[i]. ~K ( );
128- values_[i]. ~V ( );
171+ destroy (& keys_[i]);
172+ destroy (& values_[i]);
129173 for (size_t j = i; j < size_ - 1 ; ++j) {
130- new (&keys_[j]) K ( std::move (keys_[j + 1 ]));
131- new (&values_[j]) V ( std::move (values_[j + 1 ]));
132- keys_[j + 1 ]. ~K ( );
133- values_[j + 1 ]. ~V ( );
174+ construct (&keys_[j], std::move (keys_[j + 1 ]));
175+ construct (&values_[j], std::move (values_[j + 1 ]));
176+ destroy (& keys_[j + 1 ]);
177+ destroy (& values_[j + 1 ]);
134178 }
135179 --size_;
136180 return true ;
@@ -139,7 +183,17 @@ class SieveCache {
139183 return false ; // Key not found
140184 }
141185
142- bool contains (const K& key) const {
186+ inline bool contains (const K& key) const noexcept {
187+ for (size_t i = 0 ; i < size_; ++i) {
188+ if (keys_[i] == key) {
189+ return true ;
190+ }
191+ }
192+ return false ;
193+ }
194+
195+ inline bool contains_locked (const K& key) const noexcept {
196+ std::lock_guard<std::shared_mutex> lock (rw_mutex_);
143197 for (size_t i = 0 ; i < size_; ++i) {
144198 if (keys_[i] == key) {
145199 return true ;
@@ -148,24 +202,43 @@ class SieveCache {
148202 return false ;
149203 }
150204
151- void clear () {
205+ inline void clear () noexcept {
152206 for (size_t i = 0 ; i < size_; ++i) {
153207 keys_[i].~K ();
154208 values_[i].~V ();
155209 }
156210 size_ = 0 ;
157211 }
158212
159- size_t length () const {
213+ inline void clear_locked () noexcept {
214+ std::unique_lock<std::shared_mutex> lock (rw_mutex_);
215+ for (size_t i = 0 ; i < size_; ++i) {
216+ keys_[i].~K ();
217+ values_[i].~V ();
218+ }
219+ size_ = 0 ;
220+ }
221+
222+ constexpr size_t length () const noexcept {
160223 return size_;
161224 }
162225
163226private:
227+ template <typename T, typename ... Args>
228+ void construct (T* ptr, Args&&... args) noexcept {
229+ new (ptr) T (std::forward<Args>(args)...);
230+ }
231+
232+ template <typename T>
233+ void destroy (T* ptr) noexcept {
234+ ptr->~T ();
235+ }
164236 size_t capacity_;
165237 size_t size_;
166238 K* keys_;
167239 V* values_;
168240 std::pmr::memory_resource* mem_resource_;
241+ mutable std::shared_mutex rw_mutex_;
169242};
170243
171244#endif // SIEVE_HPP
0 commit comments