cache.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783
  1. #pragma once
  2. #include <util/generic/algorithm.h>
  3. #include <util/generic/ptr.h>
  4. #include <util/generic/intrlist.h>
  5. #include <util/generic/hash_set.h>
  6. #include <util/generic/vector.h>
  7. #include <util/generic/yexception.h>
  8. #include <utility>
  9. template <class TValue>
  10. struct TUniformSizeProvider {
  11. size_t operator()(const TValue&) {
  12. return 1;
  13. }
  14. };
  15. template <typename TKey, typename TValue, class TSizeProvider = TUniformSizeProvider<TValue>>
  16. class TLRUList {
  17. public:
  18. TLRUList(size_t maxSize, const TSizeProvider& sizeProvider = TSizeProvider())
  19. : List()
  20. , SizeProvider(sizeProvider)
  21. , ItemsAmount(0)
  22. , TotalSize(0)
  23. , MaxSize(maxSize)
  24. {
  25. }
  26. public:
  27. struct TItem: public TIntrusiveListItem<TItem> {
  28. typedef TIntrusiveListItem<TItem> TBase;
  29. // universal reference for TKey here prevents TItem(/*non-const*/ TItem&) from compiling,
  30. // so explicitly specify const TKey& and TKey&&
  31. explicit TItem(const TKey& key)
  32. : TBase()
  33. , Key(key)
  34. , Value()
  35. {
  36. }
  37. explicit TItem(TKey&& key)
  38. : TBase()
  39. , Key(std::move(key))
  40. , Value()
  41. {
  42. }
  43. template<typename TKeyRef, typename TValueRef>
  44. TItem(TKeyRef&& key, TValueRef&& value)
  45. : TBase()
  46. , Key(std::forward<TKeyRef>(key))
  47. , Value(std::forward<TValueRef>(value))
  48. {
  49. }
  50. TItem(const TItem&) = default;
  51. TItem(TItem&&) = default;
  52. bool operator<(const TItem& rhs) const {
  53. return Key < rhs.Key;
  54. }
  55. bool operator==(const TItem& rhs) const {
  56. return Key == rhs.Key;
  57. }
  58. TKey Key;
  59. TValue Value;
  60. struct THash {
  61. size_t operator()(const TItem& item) const {
  62. return ::THash<TKey>()(item.Key);
  63. }
  64. size_t operator()(const TKey& key) const {
  65. return ::THash<TKey>()(key);
  66. }
  67. };
  68. struct TEqualTo {
  69. bool operator()(const TItem& lhs, const TItem& rhs) const {
  70. return lhs.Key == rhs.Key;
  71. }
  72. bool operator()(const TItem& lhs, const TKey& rhs) const {
  73. return lhs.Key == rhs;
  74. }
  75. bool operator()(const TKey& lhs, const TItem& rhs) const {
  76. return lhs == rhs.Key;
  77. }
  78. };
  79. };
  80. public:
  81. TItem* Insert(TItem* item) {
  82. List.PushBack(item);
  83. ++ItemsAmount;
  84. TotalSize += SizeProvider(item->Value);
  85. return RemoveIfOverflown();
  86. }
  87. TItem* RemoveIfOverflown() {
  88. TItem* deleted = nullptr;
  89. if (TotalSize > MaxSize && ItemsAmount > 1) {
  90. deleted = GetOldest();
  91. Erase(deleted);
  92. }
  93. return deleted;
  94. }
  95. TItem* GetOldest() {
  96. typename TListType::TIterator it = List.Begin();
  97. Y_ASSERT(it != List.End());
  98. return &*it;
  99. }
  100. void Erase(TItem* item) {
  101. item->Unlink();
  102. --ItemsAmount;
  103. TotalSize -= SizeProvider(item->Value);
  104. }
  105. void Promote(TItem* item) {
  106. item->Unlink();
  107. List.PushBack(item);
  108. }
  109. [[nodiscard]] size_t GetSize() const {
  110. return ItemsAmount;
  111. }
  112. [[nodiscard]] size_t GetTotalSize() const {
  113. return TotalSize;
  114. }
  115. size_t GetMaxSize() const {
  116. return MaxSize;
  117. }
  118. // It does not remove current items if newSize is less than TotalSize.
  119. // Caller should use RemoveIfOverflown to clean up list in this case
  120. void SetMaxSize(size_t newSize) {
  121. MaxSize = newSize;
  122. }
  123. private:
  124. typedef TIntrusiveList<TItem> TListType;
  125. TListType List;
  126. TSizeProvider SizeProvider;
  127. size_t ItemsAmount;
  128. size_t TotalSize;
  129. size_t MaxSize;
  130. };
  131. template <typename TKey, typename TValue, class TSizeProvider = TUniformSizeProvider<TValue>>
  132. class TLFUList {
  133. public:
  134. TLFUList(size_t maxSize, const TSizeProvider& sizeProvider = TSizeProvider())
  135. : List()
  136. , SizeProvider(sizeProvider)
  137. , ItemsAmount(0)
  138. , TotalSize(0)
  139. , MaxSize(maxSize)
  140. {
  141. }
  142. struct TItem: public TIntrusiveListItem<TItem> {
  143. typedef TIntrusiveListItem<TItem> TBase;
  144. explicit TItem(const TKey& key)
  145. : TBase()
  146. , Key(key)
  147. , Value()
  148. , Counter(0)
  149. {
  150. }
  151. explicit TItem(TKey&& key)
  152. : TBase()
  153. , Key(std::move(key))
  154. , Value()
  155. , Counter(0)
  156. {
  157. }
  158. template<typename TKeyRef, typename TValueRef>
  159. TItem(TKeyRef&& key, TValueRef&& value)
  160. : TBase()
  161. , Key(std::forward<TKeyRef>(key))
  162. , Value(std::forward<TValueRef>(value))
  163. , Counter(0)
  164. {
  165. }
  166. TItem(const TItem&) = default;
  167. TItem(TItem&&) = default;
  168. bool operator<(const TItem& rhs) const {
  169. return Key < rhs.Key;
  170. }
  171. bool operator==(const TItem& rhs) const {
  172. return Key == rhs.Key;
  173. }
  174. TKey Key;
  175. TValue Value;
  176. size_t Counter;
  177. struct THash {
  178. size_t operator()(const TItem& item) const {
  179. return ::THash<TKey>()(item.Key);
  180. }
  181. size_t operator()(const TKey& key) const {
  182. return ::THash<TKey>()(key);
  183. }
  184. };
  185. struct TEqualTo {
  186. bool operator()(const TItem& lhs, const TItem& rhs) const {
  187. return lhs.Key == rhs.Key;
  188. }
  189. bool operator()(const TItem& lhs, const TKey& rhs) const {
  190. return lhs.Key == rhs;
  191. }
  192. bool operator()(const TKey& lhs, const TItem& rhs) const {
  193. return lhs == rhs.Key;
  194. }
  195. };
  196. };
  197. public:
  198. TItem* Insert(TItem* item) {
  199. List.PushBack(item); // give a chance for promotion
  200. ++ItemsAmount;
  201. TotalSize += SizeProvider(item->Value);
  202. return RemoveIfOverflown();
  203. }
  204. TItem* RemoveIfOverflown() {
  205. TItem* deleted = nullptr;
  206. if (TotalSize > MaxSize && ItemsAmount > 1) {
  207. deleted = GetLeastFrequentlyUsed();
  208. Erase(deleted);
  209. }
  210. return deleted;
  211. }
  212. TItem* GetLeastFrequentlyUsed() {
  213. typename TListType::TIterator it = List.Begin();
  214. Y_ASSERT(it != List.End());
  215. return &*it;
  216. }
  217. void Erase(TItem* item) {
  218. item->Unlink();
  219. --ItemsAmount;
  220. TotalSize -= SizeProvider(item->Value);
  221. }
  222. void Promote(TItem* item) {
  223. size_t counter = ++item->Counter;
  224. typename TListType::TIterator it = item;
  225. while (it != List.End() && counter >= it->Counter) {
  226. ++it;
  227. }
  228. item->LinkBefore(&*it);
  229. }
  230. [[nodiscard]] size_t GetSize() const {
  231. return ItemsAmount;
  232. }
  233. [[nodiscard]] size_t GetTotalSize() const {
  234. return TotalSize;
  235. }
  236. size_t GetMaxSize() const {
  237. return MaxSize;
  238. }
  239. // It does not remove current items if newSize is less than TotalSize.
  240. // Caller should use RemoveIfOverflown to clean up list in this case
  241. void SetMaxSize(size_t newSize) {
  242. MaxSize = newSize;
  243. }
  244. private:
  245. typedef TIntrusiveList<TItem> TListType;
  246. TListType List;
  247. TSizeProvider SizeProvider;
  248. size_t ItemsAmount;
  249. size_t TotalSize;
  250. size_t MaxSize;
  251. };
  252. // Least Weighted list
  253. // discards the least weighted items first
  254. // doesn't support promotion
  255. template <typename TKey, typename TValue, typename TWeight, typename TWeighter>
  256. class TLWList {
  257. public:
  258. TLWList(size_t maxSize)
  259. : Size(0)
  260. , MaxSize(maxSize)
  261. {
  262. }
  263. struct TItem {
  264. explicit TItem(const TKey& key)
  265. : Key(key)
  266. , Value()
  267. , Weight(TWeighter::Weight(Value))
  268. {
  269. }
  270. explicit TItem(TKey&& key)
  271. : Key(std::move(key))
  272. , Value()
  273. , Weight(TWeighter::Weight(Value))
  274. {
  275. }
  276. template<typename TKeyRef, typename TValueRef>
  277. TItem(TKeyRef&& key, TValueRef&& value)
  278. : Key(std::forward<TKeyRef>(key))
  279. , Value(std::forward<TValueRef>(value))
  280. , Weight(TWeighter::Weight(Value))
  281. {
  282. }
  283. TItem(const TItem&) = default;
  284. TItem(TItem&&) = default;
  285. bool operator<(const TItem& rhs) const {
  286. return Key < rhs.Key;
  287. }
  288. bool operator==(const TItem& rhs) const {
  289. return Key == rhs.Key;
  290. }
  291. TKey Key;
  292. TValue Value;
  293. TWeight Weight;
  294. struct THash {
  295. size_t operator()(const TItem& item) const {
  296. return ::THash<TKey>()(item.Key);
  297. }
  298. size_t operator()(const TKey& key) const {
  299. return ::THash<TKey>()(key);
  300. }
  301. };
  302. struct TEqualTo {
  303. bool operator()(const TItem& lhs, const TItem& rhs) const {
  304. return lhs.Key == rhs.Key;
  305. }
  306. bool operator()(const TItem& lhs, const TKey& rhs) const {
  307. return lhs.Key == rhs;
  308. }
  309. bool operator()(const TKey& lhs, const TItem& rhs) const {
  310. return lhs == rhs.Key;
  311. }
  312. };
  313. };
  314. struct THeapComparator {
  315. bool operator()(TItem* const item1, TItem* const item2) const {
  316. return item1->Weight > item2->Weight;
  317. }
  318. };
  319. public:
  320. TItem* Insert(TItem* item) {
  321. FixHeap();
  322. if (Size >= MaxSize && item->Weight < GetLightest()->Weight) {
  323. return item;
  324. }
  325. Heap.push_back(item);
  326. PushHeap(Heap.begin(), Heap.end(), THeapComparator());
  327. ++Size;
  328. return RemoveIfOverflown();
  329. }
  330. TItem* RemoveIfOverflown() {
  331. if (Size <= MaxSize) {
  332. return nullptr;
  333. }
  334. auto lightest = GetLightest();
  335. Erase(lightest);
  336. PopHeap(Heap.begin(), Heap.end(), THeapComparator());
  337. return lightest;
  338. }
  339. TItem* GetLightest() {
  340. FixHeap();
  341. Y_ASSERT(!Heap.empty());
  342. return Heap.front();
  343. }
  344. // This method doesn't remove items from the heap.
  345. // Erased items are stored in Removed set
  346. // and will be deleted on-access (using FixHeap method)
  347. void Erase(TItem* item) {
  348. Y_ASSERT(Size > 0);
  349. --Size;
  350. Removed.insert(item);
  351. }
  352. void Promote(TItem*) {
  353. // do nothing
  354. }
  355. [[nodiscard]] size_t GetSize() const {
  356. return Size;
  357. }
  358. [[nodiscard]] size_t GetTotalSize() const {
  359. return Size;
  360. }
  361. size_t GetMaxSize() const {
  362. return MaxSize;
  363. }
  364. // It does not remove current items if newSize is less than TotalSize.
  365. // Caller should use RemoveIfOverflown to clean up list in this case
  366. void SetMaxSize(size_t newSize) {
  367. MaxSize = newSize;
  368. }
  369. void Clear() {
  370. Heap.clear();
  371. Removed.clear();
  372. Size = 0;
  373. }
  374. private:
  375. // Physically remove erased elements from the heap
  376. void FixHeap() {
  377. if (Removed.empty()) {
  378. return;
  379. }
  380. Heap.erase(std::remove_if(Heap.begin(), Heap.end(), [this](TItem* item) {
  381. return this->Removed.contains(item);
  382. }),
  383. Heap.end());
  384. MakeHeap(Heap.begin(), Heap.end(), THeapComparator());
  385. Removed.clear();
  386. Size = Heap.size();
  387. }
  388. private:
  389. TVector<TItem*> Heap;
  390. THashSet<TItem*> Removed;
  391. size_t Size;
  392. size_t MaxSize;
  393. };
  394. template <typename TKey, typename TValue, typename TListType, typename TDeleter, typename TAllocator = std::allocator<void>>
  395. class TCache {
  396. typedef typename TListType::TItem TItem;
  397. typedef typename TItem::THash THash;
  398. typedef THashMultiSet<TItem, THash, typename TItem::TEqualTo, TAllocator> TIndex;
  399. typedef typename TIndex::iterator TIndexIterator;
  400. typedef typename TIndex::const_iterator TIndexConstIterator;
  401. public:
  402. class TIterator {
  403. public:
  404. explicit TIterator(const TIndexConstIterator& iter)
  405. : Iter(iter)
  406. {
  407. }
  408. TValue& operator*() {
  409. return const_cast<TValue&>(Iter->Value);
  410. }
  411. TValue* operator->() {
  412. return const_cast<TValue*>(&Iter->Value);
  413. }
  414. bool operator==(const TIterator& rhs) const {
  415. return Iter == rhs.Iter;
  416. }
  417. bool operator!=(const TIterator& rhs) const {
  418. return Iter != rhs.Iter;
  419. }
  420. TIterator& operator++() {
  421. ++Iter;
  422. return *this;
  423. }
  424. const TKey& Key() const {
  425. return Iter->Key;
  426. }
  427. const TValue& Value() const {
  428. return Iter->Value;
  429. }
  430. friend class TCache<TKey, TValue, TListType, TDeleter, TAllocator>;
  431. private:
  432. TIndexConstIterator Iter;
  433. };
  434. TCache(TListType&& list, bool multiValue = false)
  435. : Index()
  436. , List(std::move(list))
  437. , MultiValue(multiValue)
  438. {
  439. }
  440. ~TCache() {
  441. Clear();
  442. }
  443. [[nodiscard]] size_t Size() const {
  444. return Index.size();
  445. }
  446. [[nodiscard]] size_t TotalSize() const {
  447. return List.GetTotalSize();
  448. }
  449. TIterator Begin() const {
  450. return TIterator(Index.begin());
  451. }
  452. TIterator End() const {
  453. return TIterator(Index.end());
  454. }
  455. TIterator Find(const TKey& key) {
  456. TIndexIterator it = Index.find(key);
  457. if (it != Index.end())
  458. List.Promote(const_cast<TItem*>(&*it));
  459. return TIterator(it);
  460. }
  461. TIterator FindWithoutPromote(const TKey& key) const {
  462. return TIterator(Index.find(key));
  463. }
  464. // note: it shouldn't touch 'value' if it returns false.
  465. bool PickOut(const TKey& key, TValue* value) {
  466. Y_ASSERT(value);
  467. TIndexIterator it = Index.find(key);
  468. if (it == Index.end())
  469. return false;
  470. *value = std::move(it->Value);
  471. List.Erase(const_cast<TItem*>(&*it));
  472. Index.erase(it);
  473. Y_ASSERT(Index.size() == List.GetSize());
  474. return true;
  475. }
  476. bool Insert(const std::pair<TKey, TValue>& p) {
  477. return Insert(p.first, p.second);
  478. }
  479. template<typename TKeyRef, typename TValueRef>
  480. bool InsertImpl(TKeyRef&& key, TValueRef&& value) {
  481. if (!MultiValue && Index.find(key) != Index.end())
  482. return false;
  483. TIndexIterator it = Index.emplace(std::forward<TKeyRef>(key), std::forward<TValueRef>(value));
  484. TItem* insertedItem = const_cast<TItem*>(&*it);
  485. auto removedItem = List.Insert(insertedItem);
  486. auto insertedWasRemoved = removedItem == insertedItem;
  487. if (removedItem) {
  488. EraseFromIndex(removedItem);
  489. while ((removedItem = List.RemoveIfOverflown())) {
  490. insertedWasRemoved = insertedWasRemoved || insertedItem == removedItem;
  491. EraseFromIndex(removedItem);
  492. }
  493. }
  494. Y_ASSERT(Index.size() == List.GetSize());
  495. return !insertedWasRemoved;
  496. }
  497. // a lot of code calls Insert(key, {arguments for TValue constructor})
  498. // template version InsertImpl can not process this
  499. bool Insert(const TKey& key, const TValue& value) {
  500. return InsertImpl(key, value);
  501. }
  502. bool Insert(const TKey& key, TValue&& value) {
  503. return InsertImpl(key, std::move(value));
  504. }
  505. bool Insert(TKey&& key, const TValue& value) {
  506. return InsertImpl(std::move(key), value);
  507. }
  508. bool Insert(TKey&& key, TValue&& value) {
  509. return InsertImpl(std::move(key), std::move(value));
  510. }
  511. template<typename TKeyRef, typename TValueRef>
  512. void UpdateImpl(TKeyRef&& key, TValueRef&& value) {
  513. if (MultiValue)
  514. ythrow yexception() << "TCache: can't \"Update\" in multicache";
  515. TIterator it = Find(key);
  516. if (it != End()) {
  517. Erase(it);
  518. }
  519. InsertImpl(std::forward<TKeyRef>(key), std::forward<TValueRef>(value));
  520. Y_ASSERT(Index.size() == List.GetSize());
  521. }
  522. void Update(const TKey& key, const TValue& value) {
  523. UpdateImpl(key, value);
  524. }
  525. void Update(const TKey& key, TValue&& value) {
  526. UpdateImpl(key, std::move(value));
  527. }
  528. void Update(TKey&& key, const TValue& value) {
  529. UpdateImpl(std::move(key), value);
  530. }
  531. void Update(TKey&& key, TValue&& value) {
  532. UpdateImpl(std::move(key), std::move(value));
  533. }
  534. void Erase(TIterator it) {
  535. TItem* item = const_cast<TItem*>(&*it.Iter);
  536. List.Erase(item);
  537. TDeleter::Destroy(item->Value);
  538. Index.erase(it.Iter);
  539. Y_ASSERT(Index.size() == List.GetSize());
  540. }
  541. bool Empty() const {
  542. return Index.empty();
  543. }
  544. void Clear() {
  545. for (TIndexIterator it = Index.begin(); it != Index.end(); ++it) {
  546. TItem* item = const_cast<TItem*>(&*it);
  547. List.Erase(item);
  548. TDeleter::Destroy(item->Value);
  549. }
  550. Y_ASSERT(List.GetSize() == 0);
  551. Index.clear();
  552. }
  553. void SetMaxSize(size_t newSize) {
  554. List.SetMaxSize(newSize);
  555. TItem* removedItem = nullptr;
  556. while ((removedItem = List.RemoveIfOverflown())) {
  557. EraseFromIndex(removedItem);
  558. }
  559. Y_ASSERT(Index.size() == List.GetSize());
  560. }
  561. size_t GetMaxSize() const {
  562. return List.GetMaxSize();
  563. }
  564. void Reserve(size_t hint) {
  565. Index.reserve(hint);
  566. }
  567. typedef typename TIndex::node_allocator_type TNodeAllocatorType;
  568. TNodeAllocatorType& GetNodeAllocator() {
  569. return Index.GetNodeAllocator();
  570. }
  571. protected:
  572. TIndex Index;
  573. TListType List;
  574. bool MultiValue;
  575. TIterator FindByItem(TItem* item) {
  576. std::pair<TIndexIterator, TIndexIterator> p = Index.equal_range(*item);
  577. // we have to delete the exact unlinked item (there may be multiple items for one key)
  578. TIndexIterator it;
  579. for (it = p.first; it != p.second; ++it)
  580. if (&*it == item)
  581. break;
  582. return (it == p.second ? End() : TIterator(it));
  583. }
  584. void EraseFromIndex(TItem* item) {
  585. TDeleter::Destroy(item->Value);
  586. TIterator it = FindByItem(item);
  587. Y_ASSERT(it != End());
  588. Index.erase(it.Iter);
  589. }
  590. };
  591. struct TNoopDelete {
  592. template <class T>
  593. static inline void Destroy(const T&) noexcept {
  594. }
  595. };
  596. template <typename TKey, typename TValue, typename TDeleter = TNoopDelete, class TSizeProvider = TUniformSizeProvider<TValue>, typename TAllocator = std::allocator<void>>
  597. class TLRUCache: public TCache<TKey, TValue, TLRUList<TKey, TValue, TSizeProvider>, TDeleter, TAllocator> {
  598. using TListType = TLRUList<TKey, TValue, TSizeProvider>;
  599. typedef TCache<TKey, TValue, TListType, TDeleter, TAllocator> TBase;
  600. public:
  601. TLRUCache(size_t maxSize, bool multiValue = false, const TSizeProvider& sizeProvider = TSizeProvider())
  602. : TBase(TListType(maxSize, sizeProvider), multiValue)
  603. {
  604. }
  605. public:
  606. typedef typename TBase::TIterator TIterator;
  607. TValue& GetOldest() {
  608. return TBase::List.GetOldest()->Value;
  609. }
  610. TIterator FindOldest() {
  611. return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetOldest());
  612. }
  613. size_t TotalSize() const {
  614. return TBase::List.GetTotalSize();
  615. }
  616. };
  617. template <typename TKey, typename TValue, typename TDeleter = TNoopDelete, typename TAllocator = std::allocator<void>, class TSizeProvider = TUniformSizeProvider<TValue>>
  618. class TLFUCache: public TCache<TKey, TValue, TLFUList<TKey, TValue, TSizeProvider>, TDeleter, TAllocator> {
  619. typedef TCache<TKey, TValue, TLFUList<TKey, TValue, TSizeProvider>, TDeleter, TAllocator> TBase;
  620. using TListType = TLFUList<TKey, TValue, TSizeProvider>;
  621. public:
  622. typedef typename TBase::TIterator TIterator;
  623. TLFUCache(size_t maxSize, bool multiValue = false, const TSizeProvider& sizeProvider = TSizeProvider())
  624. : TBase(TListType(maxSize, sizeProvider), multiValue)
  625. {
  626. }
  627. TValue& GetLeastFrequentlyUsed() {
  628. return TBase::List.GetLeastFrequentlyUsed()->Value;
  629. }
  630. TIterator FindLeastFrequentlyUsed() {
  631. return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetLeastFrequentlyUsed());
  632. }
  633. };
  634. // Least Weighted cache
  635. // discards the least weighted items first
  636. // doesn't support promotion
  637. template <typename TKey, typename TValue, typename TWeight, typename TWeighter, typename TDeleter = TNoopDelete, typename TAllocator = std::allocator<void>>
  638. class TLWCache: public TCache<TKey, TValue, TLWList<TKey, TValue, TWeight, TWeighter>, TDeleter, TAllocator> {
  639. typedef TCache<TKey, TValue, TLWList<TKey, TValue, TWeight, TWeighter>, TDeleter, TAllocator> TBase;
  640. using TListType = TLWList<TKey, TValue, TWeight, TWeighter>;
  641. public:
  642. typedef typename TBase::TIterator TIterator;
  643. TLWCache(size_t maxSize, bool multiValue = false)
  644. : TBase(TListType(maxSize), multiValue)
  645. {
  646. }
  647. TValue& GetLightest() {
  648. return TBase::List.GetLightest()->Value;
  649. }
  650. TIterator FindLightest() {
  651. return TBase::Empty() ? TBase::End() : this->FindByItem(TBase::List.GetLightest());
  652. }
  653. };