BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlcc_cache.h
Go to the documentation of this file.
1/// @file bdlcc_cache.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_cache.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_CACHE
9#define INCLUDED_BDLCC_CACHE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_cache bdlcc_cache
15/// @brief Provide a in-process cache with configurable eviction policy.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_cache
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_cache-purpose"> Purpose</a>
25/// * <a href="#bdlcc_cache-classes"> Classes </a>
26/// * <a href="#bdlcc_cache-description"> Description </a>
27/// * <a href="#bdlcc_cache-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlcc_cache-thread-contention"> Thread Contention </a>
29/// * <a href="#bdlcc_cache-post-eviction-callback-and-potential-deadlocks"> Post-eviction Callback and Potential Deadlocks </a>
30/// * <a href="#bdlcc_cache-runtime-complexity"> Runtime Complexity </a>
31/// * <a href="#bdlcc_cache-usage"> Usage </a>
32/// * <a href="#bdlcc_cache-example-1-basic-usage"> Example 1: Basic Usage </a>
33/// * <a href="#bdlcc_cache-example-2-updating-cache-in-the-background"> Example 2: Updating Cache in The Background </a>
34///
35/// # Purpose {#bdlcc_cache-purpose}
36/// Provide a in-process cache with configurable eviction policy.
37///
38/// # Classes {#bdlcc_cache-classes}
39///
40/// - bdlcc::Cache: in-process key-value cache
41///
42/// # Description {#bdlcc_cache-description}
43/// This component defines a single class template, `bdlcc::Cache`,
44/// implementing a thread-safe in-memory key-value cache with a configurable
45/// eviction policy.
46///
47/// `bdlcc::Cache` class uses similar template parameters to
48/// `bsl::unordered_map`: the key type (`KEY`), the value type (`VALUE`), the
49/// optional hash function (`HASH`), and the optional equal function (`EQUAL`).
50/// `bdlcc::Cache` does not support the standard allocator template parameter
51/// (although `bslma::Allocator` is supported).
52///
53/// The cache size can be controlled by setting the low watermark and high
54/// watermark attributes, which is used instead of a single maximum size
55/// attribute for performance benefits. Eviction of cached items starts when
56/// `size() >= highWatermark` and continues until `size() < lowWatermark`. A
57/// fixed maximum size is obtained by setting the high and low watermarks to the
58/// same value.
59///
60/// Two eviction policies are supported: LRU (Least Recently Used) and FIFO
61/// (First In, First Out). With LRU, the item that has *not* been accessed for
62/// the longest period of time will be evicted first. With FIFO, the eviction
63/// order is based on the order of insertion, with the earliest inserted item
64/// being evicted first.
65///
66/// ## Thread Safety {#bdlcc_cache-thread-safety}
67///
68///
69/// The `bdlcc::Cache` class template is fully thread-safe (see
70/// @ref bsldoc_glossary ) provided that the allocator supplied at construction and
71/// the default allocator in effect during the lifetime of cached items are both
72/// fully thread-safe. The thread-safety of the container does not extend to
73/// thread-safety of the contained objects. Thread-safety for the contained
74/// objects, if needed, must be arranged by the user separately.
75///
76/// ## Thread Contention {#bdlcc_cache-thread-contention}
77///
78///
79/// Threads accessing a `bdlcc::Cache` may block while waiting for other threads
80/// to complete their operations upon the cache. Concurrent reading is
81/// supported. Neither readers or writers are starved by the other group.
82///
83/// All of the modifier methods of the cache potentially requires a write lock.
84/// Of particular note is the `tryGetValue` method, which requires a writer lock
85/// only if the eviction queue needs to be modified. This means `tryGetValue`
86/// requires only a read lock if the eviction policy is set to FIFO or the
87/// argument `modifyEvictionQueue` is set to `false`. For limited cases where
88/// contention is likely, temporarily setting `modifyEvictionQueue` to `false`
89/// might be of value.
90///
91/// The `visit` method acquires a read lock and calls the supplied visitor
92/// function for every item in the cache, or until the visitor function returns
93/// `false`. If the supplied visitor is expensive or the cache is very large,
94/// calls to modifier methods might be starved until the `visit` method finishes
95/// looping through the cache items. Therefore, the `visit` method should be
96/// used judiciously by making the method call relatively cheap or ensuring that
97/// no time-sensitive write operation is done at the same time as a call to the
98/// `visit` method. A `visit` method call is inexpensive if the visitor returns
99/// quickly, or if the visitor returns false after only a subset of the cache
100/// items were processed.
101///
102/// ## Post-eviction Callback and Potential Deadlocks {#bdlcc_cache-post-eviction-callback-and-potential-deadlocks}
103///
104///
105/// When an item is evicted or erased from the cache, the previously set
106/// post-eviction callback (via the `setPostEvictionCallback` method) will be
107/// invoked within the calling thread, supplying a pointer to the item being
108/// removed.
109///
110/// The cache object itself should not be used in a post-eviction callback;
111/// otherwise, a deadlock may result. Since a write lock is held during the
112/// call to the callback, invoking any operation on the cache that acquires a
113/// lock inside the callback will lead to a deadlock.
114///
115/// ## Runtime Complexity {#bdlcc_cache-runtime-complexity}
116///
117///
118/// @code
119/// +----------------------------------------------------+--------------------+
120/// | Operation | Complexity |
121/// +====================================================+====================+
122/// | insert | Average: O[1] |
123/// | | Worst: O[n] |
124/// +----------------------------------------------------+--------------------+
125/// | tryGetValue | Average: O[1] |
126/// | | Worst: O[n] |
127/// +----------------------------------------------------+--------------------+
128/// | popFront | O[1] |
129/// +----------------------------------------------------+--------------------+
130/// | erase | Average: O[1] |
131/// | | Worst: O[n] |
132/// +----------------------------------------------------+--------------------+
133/// | visit | O[n] |
134/// +----------------------------------------------------+--------------------+
135/// @endcode
136///
137/// ## Usage {#bdlcc_cache-usage}
138///
139///
140/// In this section we show intended use of this component.
141///
142/// ### Example 1: Basic Usage {#bdlcc_cache-example-1-basic-usage}
143///
144///
145/// This examples shows some basic usage of the cache. First, we define a
146/// custom post-eviction callback function, `myPostEvictionCallback` that simply
147/// prints the evicted item to stdout:
148/// @code
149/// void myPostEvictionCallback(bsl::shared_ptr<bsl::string> value)
150/// {
151/// bsl::cout << "Evicted: " << *value << bsl::endl;
152/// }
153/// @endcode
154/// Then, we define a `bdlcc::Cache` object, `myCache`, that maps `int` to
155/// `bsl::string` and uses the LRU eviction policy:
156/// @code
157/// bdlcc::Cache<int, bsl::string>
158/// myCache(bdlcc::CacheEvictionPolicy::e_LRU, 6, 7, &talloc);
159/// @endcode
160/// Next, we insert 3 items into the cache and verify that the size of the cache
161/// has been updated correctly:
162/// @code
163/// myCache.insert(0, "Alex");
164/// myCache.insert(1, "John");
165/// myCache.insert(2, "Rob");
166/// assert(myCache.size() == 3);
167/// @endcode
168/// Then, we bulk insert 3 additional items into the cache and verify that the
169/// size of the cache has been updated correctly:
170/// @code
171/// typedef bsl::pair<int, bsl::shared_ptr<bsl::string> > PairType;
172/// bsl::vector<PairType> insertData(&talloc);
173/// insertData.push_back(PairType(3,
174/// bsl::allocate_shared<bsl::string>(&talloc, "Jim" )));
175/// insertData.push_back(PairType(4,
176/// bsl::allocate_shared<bsl::string>(&talloc, "Jeff")));
177/// insertData.push_back(PairType(5,
178/// bsl::allocate_shared<bsl::string>(&talloc, "Ian" )));
179/// myCache.insertBulk(insertData);
180/// assert(myCache.size() == 6);
181/// @endcode
182/// Next, we retrieve the second value of the second item stored in the cache
183/// using the `tryGetValue` method:
184/// @code
185/// bsl::shared_ptr<bsl::string> value;
186/// int rc = myCache.tryGetValue(&value, 1);
187/// assert(rc == 0);
188/// assert(*value == "John");
189/// @endcode
190/// Then, we set the cache's post-eviction callback to `myPostEvictionCallback`:
191/// @code
192/// myCache.setPostEvictionCallback(myPostEvictionCallback);
193/// @endcode
194/// Now, we insert two more items into the cache to trigger the eviction
195/// behavior:
196/// @code
197/// myCache.insert(6, "Steve");
198/// assert(myCache.size() == 7);
199/// myCache.insert(7, "Tim");
200/// assert(myCache.size() == 6);
201/// @endcode
202/// Notice that after we insert "Steve", the size of the cache is 7, the high
203/// watermark. After the following item, "Tim", is inserted, the size of the
204/// cache goes back down to 6, the low watermark.
205///
206/// Finally, we observe the following output to stdout:
207/// @code
208/// Evicted: Alex
209/// Evicted: Rob
210/// @endcode
211/// Notice that the item "John" was not evicted even though it was inserted
212/// before "Rob", because "John" was accessed after "Rob" was inserted.
213///
214/// ### Example 2: Updating Cache in The Background {#bdlcc_cache-example-2-updating-cache-in-the-background}
215///
216///
217/// Suppose that a service needs to retrieve some values that are relatively
218/// expensive to compute. Clients of the service cannot wait for computing the
219/// values, so the service should pre-compute and cache them. In addition, the
220/// values are only valid for around one hour, so older items must be
221/// periodically updated in the cache. This problem can be solved using
222/// `bdlcc::Cache` with a background updater thread.
223///
224/// First, we define the types representing the cached values and the cache
225/// itself:
226/// @code
227/// struct MyValue {
228/// int d_data; // data
229/// bdlt::Datetime d_timestamp; // last update time stamp
230/// };
231/// typedef bdlcc::Cache<int, MyValue> MyCache;
232/// @endcode
233/// Then, suppose that we have access to a function `retrieveValue` that returns
234/// a `MyValue` object given a `int` key:
235/// @code
236/// MyValue retrieveValue(int key)
237/// {
238/// MyValue ret = {key, bdlt::CurrentTime::utc()};
239/// return ret;
240/// }
241/// @endcode
242/// Next, we define a visitor type to aggregate keys of the out-of-date values
243/// in the cache:
244/// @code
245/// /// Visitor to `MyCache`.
246/// struct MyVisitor {
247/// bsl::vector<int> d_oldKeys; // list of out-of-date keys
248///
249/// MyVisitor()
250/// : d_oldKeys(&talloc)
251/// {}
252///
253/// /// Check if the specified `value` is older than 1 hour. If so,
254/// /// insert the specified `key` into `d_oldKeys`.
255/// bool operator() (int key, const MyValue& value)
256/// {
257/// if (veryVerbose) {
258/// bsl::cout << "Visiting " << key
259/// << ", age: "
260/// << bdlt::CurrentTime::utc() - value.d_timestamp
261/// << bsl::endl;
262/// }
263///
264/// if (bdlt::CurrentTime::utc() - value.d_timestamp <
265/// // bdlt::DatetimeInterval(0, 60)) {
266/// bdlt::DatetimeInterval(0, 0, 0, 3)) {
267/// return false; // RETURN
268/// }
269///
270/// d_oldKeys.push_back(key);
271/// return true;
272/// }
273/// };
274/// @endcode
275/// Then, we define the background thread function to find and update the
276/// out-of-date values:
277/// @code
278/// void myWorker(MyCache *cache)
279/// {
280/// while (true) {
281/// if (cache->size() == 0) {
282/// break;
283/// }
284///
285/// // Find and update the old values once per five seconds.
286/// bslmt::ThreadUtil::microSleep(0, 5);
287/// MyVisitor visitor;
288/// cache->visit(visitor);
289/// for (bsl::vector<int>::const_iterator itr =
290/// visitor.d_oldKeys.begin();
291/// itr != visitor.d_oldKeys.end(); ++itr) {
292/// if (veryVerbose) bsl::cout << "Updating " << *itr << bsl::endl;
293/// cache->insert(*itr, retrieveValue(*itr));
294/// }
295/// }
296/// }
297///
298/// extern "C" void *myWorkerThread(void *v_cache)
299/// {
300/// MyCache *cache = (MyCache *) v_cache;
301/// myWorker(cache);
302/// return 0;
303/// }
304/// @endcode
305/// Finally, we define the entry point of the application:
306/// @code
307/// void example2()
308/// {
309/// MyCache myCache(bdlcc::CacheEvictionPolicy::e_FIFO, 100, 120, &talloc);
310///
311/// // Pre-populate the cache.
312///
313/// myCache.insert(0, retrieveValue(0));
314/// myCache.insert(1, retrieveValue(1));
315/// myCache.insert(2, retrieveValue(2));
316/// assert(myCache.size() == 3);
317///
318/// bslmt::ThreadUtil::Handle myWorkerHandle;
319///
320/// int rc = bslmt::ThreadUtil::create(&myWorkerHandle, myWorkerThread,
321/// &myCache);
322/// assert(rc == 0);
323///
324/// // Do some work.
325///
326/// bslmt::ThreadUtil::microSleep(0, 7);
327/// assert(myCache.size() == 3);
328///
329/// // Clean up.
330///
331/// myCache.clear();
332/// assert(myCache.size() == 0);
333/// bslmt::ThreadUtil::join(myWorkerHandle);
334/// }
335/// @endcode
336/// @}
337/** @} */
338/** @} */
339
340/** @addtogroup bdl
341 * @{
342 */
343/** @addtogroup bdlcc
344 * @{
345 */
346/** @addtogroup bdlcc_cache
347 * @{
348 */
349
350#include <bslim_printer.h>
351
353#include <bslmt_readlockguard.h>
354#include <bslmt_writelockguard.h>
355
356#include <bslma_allocator.h>
358
359#include <bslmf_allocatorargt.h>
360#include <bslmf_assert.h>
362#include <bslmf_movableref.h>
363
364#include <bsls_assert.h>
365#include <bsls_libraryfeatures.h>
366#include <bsls_review.h>
367
368#include <bsl_memory.h>
369#include <bsl_map.h>
370#include <bsl_unordered_map.h>
371#include <bsl_list.h>
372#include <bsl_vector.h>
373#include <bsl_functional.h>
374#include <bsl_iostream.h>
375#include <bsl_limits.h>
376#include <bsl_cstddef.h> // 'bsl::size_t'
377
378
379namespace bdlcc {
380
382
383 // TYPES
384
385 /// Enumeration of supported cache eviction policies.
386 enum Enum {
387
388 e_LRU, // Least Recently Used
389 e_FIFO // First In, First Out
390 };
391};
392
393/// This class implements a proctor that, on destruction, restores the queue to
394/// its state at the time of the proctor's creation. We assume that the only
395/// change to the queue is that 0 or more items have been added to the end. If
396/// `release` has been called, the destructor takes no action.
397///
398/// See @ref bdlcc_cache
399template <class KEY>
401
402 // DATA
403 bsl::list<KEY> *d_queue_p; // queue (held, not owned)
404 KEY *d_last_p;
405
406 private:
407 // PRIVATE ACCESSORS
408
409 /// Return a pointer to the element at the end of the queue, or 0 if the
410 /// queue is empty.
411 KEY *last() const;
412
413 public:
414 // CREATORS
415
416 /// Create a `Cache_QueueProctor` object to monitor the specified `queue`.
417 explicit Cache_QueueProctor(bsl::list<KEY> *queue);
418
419 /// Destroy this proctor object. Remove any elements that we added since
420 /// the proctor was created.
422
423 // MANIPULATORS
424
425 /// Release the queue specified on construction, so that it will not be
426 /// modified on the destruction of this proctor.
427 void release();
428};
429
430template <class KEY,
431 class VALUE,
432 class HASH = bsl::hash<KEY>,
433 class EQUAL = bsl::equal_to<KEY> >
434class Cache_TestUtil;
435
436/// This class represents a simple in-process key-value store supporting a
437/// variety of eviction policies.
438///
439/// See @ref bdlcc_cache
440template <class KEY,
441 class VALUE,
442 class HASH = bsl::hash<KEY>,
443 class EQUAL = bsl::equal_to<KEY> >
444class Cache {
445
446 public:
447 // PUBLIC TYPES
448
449 /// Shared pointer type pointing to value type.
451
452 /// Type of function to call after an item has been evicted from the cache.
454
455 /// Value type of a bulk insert entry.
457
458 private:
459 // PRIVATE TYPES
460
461 /// Eviction queue type.
463
464 /// Value type of the hash map.
466
467 /// Hash map type.
469
471
472 // DATA
473 bslma::Allocator *d_allocator_p; // memory allocator
474 // (held, not owned)
475
476 mutable LockType d_rwlock; // reader-writer lock
477
478 MapType d_map; // hash table storing
479 // key-value pairs
480
481 QueueType d_queue; // queue storing
482 // eviction order of
483 // keys, the key of the
484 // first item to be
485 // evicted is at the
486 // front of the queue
487
488 CacheEvictionPolicy::Enum d_evictionPolicy; // eviction policy
489
490 bsl::size_t d_lowWatermark; // the size of this
491 // cache when eviction
492 // stops
493
494 bsl::size_t d_highWatermark; // the size of this
495 // cache when eviction
496 // starts after an
497 // insert
498
499 PostEvictionCallback d_postEvictionCallback; // the function to call
500 // after a value has
501 // been evicted from the
502 // cache
503
504 // FRIENDS
505 friend class Cache_TestUtil<KEY, VALUE, HASH, EQUAL>;
506
507 // PRIVATE MANIPULATORS
508
509 /// Evict items from this cache if `size() >= highWatermark()` until
510 /// `size() < lowWatermark()` beginning from the front of the eviction
511 /// queue. Invoke the post-eviction callback for each item evicted.
512 void enforceHighWatermark();
513
514 /// Evict the item at the specified `mapIt` and invoke the post-eviction
515 /// callback for that item.
516 void evictItem(const typename MapType::iterator& mapIt);
517
518 /// Add a node with the specified `*key_p` and the specified `*valuePtr_p`
519 /// to the cache. If an entry already exists for `*key_p`, override its
520 /// value with `*valuePtr_p`. If the specified `moveKey` is `true`, move
521 /// `*key_p`, and if the specified `moveValuePtr` is `true`, move
522 /// `*valuePtr_p`, if the boolean values corresponding to `*key_p` or
523 /// `*valuePtr_p` are `false`, do not move or modify the arguments. Return
524 /// `true` if `*key_p` was not previously in the cache and `false`
525 /// otherwise.
526 bool insertValuePtrMoveImp(KEY *key_p,
527 bool moveKey,
528 ValuePtrType *valuePtr_p,
529 bool moveValuePtr);
530
531 private:
532 // NOT IMPLEMENTED
534
535 // BDE_VERIFY pragma: -FD01
537 // BDE_VERIFY pragma: +FD01
538
539 public:
540 // CREATORS
541
542 /// Create an empty LRU cache having no size limit. Optionally specify a
543 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
544 /// currently installed default allocator is used.
545 explicit Cache(bslma::Allocator *basicAllocator = 0);
546
547 /// Create an empty cache using the specified `evictionPolicy` and the
548 /// specified `lowWatermark` and `highWatermark`. Optionally specify the
549 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0, the
550 /// currently installed default allocator is used.
551 ///
552 /// \pre The behavior is undefined unless `lowWatermark <= highWatermark`, `1 <= lowWatermark`,
553 /// and `1 <= highWatermark`.
555 bsl::size_t lowWatermark,
556 bsl::size_t highWatermark,
557 bslma::Allocator *basicAllocator = 0);
558
559 /// Create an empty cache using the specified `evictionPolicy`,
560 /// `lowWatermark`, and `highWatermark`. The specified `hashFunction` is
561 /// used to generate the hash values for a given key, and the specified
562 /// `equalFunction` is used to determine whether two keys have the same
563 /// value. Optionally specify the `basicAllocator` used to supply memory.
564 /// If `basicAllocator` is 0, the currently installed default allocator is used.
565 ///
566 /// \pre The behavior is undefined unless `lowWatermark <=
567 /// highWatermark`, `1 <= lowWatermark`, and `1 <= highWatermark`.
569 bsl::size_t lowWatermark,
570 bsl::size_t highWatermark,
571 const HASH& hashFunction,
572 const EQUAL& equalFunction,
573 bslma::Allocator *basicAllocator = 0);
574
575 /// Destroy this object.
576 ~Cache() = default;
577
578 // MANIPULATORS
579
580 /// Remove all items from this cache. Do *not* invoke the post-eviction
581 /// callback.
582 void clear();
583
584 /// Remove the item having the specified `key` from this cache. Invoke the
585 /// post-eviction callback for the removed item. Return 0 on success and 1
586 /// if `key` does not exist.
587 int erase(const KEY& key);
588
589 /// Remove the items having the keys in the specified range
590 /// `[ begin, end )`, from this cache. Invoke the post-eviction
591 /// callback for each removed item. Return the number of items
592 /// successfully removed.
593 template <class INPUT_ITERATOR>
594 int eraseBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end);
595
596 /// Remove the items having the specified `keys` from this cache.
597 /// Invoke the post-eviction callback for each removed item. Return the
598 /// number of items successfully removed.
599 int eraseBulk(const bsl::vector<KEY>& keys);
600
601 /// Move the specified `key` and its associated `value` into this cache.
602 /// If `key` already exists, then its value will be replaced with `value`.
603 ///
604 /// \note Note that all the methods that take moved objects provide the `basic`
605 /// but not the `strong` exception guarantee -- throws may occur after the
606 /// objects are moved out of; the cache will not be modified, but `key` or
607 /// `value` may be changed. Also note that `key` must be copyable, even if
608 /// it is moved.
609 void insert(const KEY& key, const VALUE& value);
610 void insert(const KEY& key, bslmf::MovableRef<VALUE> value);
611 void insert(bslmf::MovableRef<KEY> key, const VALUE& value);
613
614 /// Insert the specified `key` and its associated `valuePtr` into this
615 /// cache. If `key` already exists, then its value will be replaced with `value`.
616 ///
617 /// \note Note that the method with `key` moved provides the
618 /// `basic` but not the `strong` exception guarantee -- if a throw
619 /// occurs, the cache will not be modified, but `key` may be changed.
620 /// Also note that `key` must be copyable, even if it is moved.
621 void insert(const KEY& key, const ValuePtrType& valuePtr);
622 void insert(bslmf::MovableRef<KEY> key, const ValuePtrType& valuePtr);
623
624 /// Insert the specified range of Key-Value pairs specified by
625 /// `[ begin, end )` into this cache. If a key already exists, then its
626 /// value will be replaced with the value. Return the number of items
627 /// successfully inserted.
628 template <class INPUT_ITERATOR>
629 int insertBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end);
630
631 /// Insert the specified `data` (composed of Key-Value pairs) into this
632 /// cache. If a key already exists, then its value will be replaced
633 /// with the value. Return the number of items successfully inserted.
635
636 /// Insert the specified `data` (composed of Key-Value pairs) into this
637 /// cache. If a key already exists, then its value will be replaced
638 /// with the value. Return the number of items successfully inserted.
639 /// If an exception occurs during this action, we provide only the
640 /// basic guarantee - both this cache and `data` will be in some valid
641 /// but unspecified state.
643
644 /// Remove the item at the front of the eviction queue. Invoke the
645 /// post-eviction callback for the removed item. Return 0 on success,
646 /// and 1 if this cache is empty.
647 int popFront();
648
649 /// Set the post-eviction callback to the specified
650 /// `postEvictionCallback`. The post-eviction callback is invoked for
651 /// each item evicted or removed from this cache.
653 const PostEvictionCallback& postEvictionCallback);
654
655 /// Load, into the specified `value`, the value associated with the
656 /// specified `key` in this cache. If the optionally specified
657 /// `modifyEvictionQueue` is `true` and the eviction policy is LRU, then
658 /// move the cached item to the back of the eviction queue. Return 0 on success, and 1 if `key` does not exist in this cache.
659 ///
660 /// \note Note that a
661 /// write lock is acquired only if this queue is modified.
663 const KEY& key,
664 bool modifyEvictionQueue = true);
665
666 // ACCESSORS
667
668 /// Return (a copy of) the key-equality functor used by this cache that
669 /// returns `true` if two `KEY` objects have the same value, and `false`
670 /// otherwise.
671 EQUAL equalFunction() const;
672
673 /// Return the eviction policy used by this cache.
675
676 /// Return (a copy of) the unary hash functor used by this cache to
677 /// generate a hash value (of type `std::size_t`) for a `KEY` object.
678 HASH hashFunction() const;
679
680 /// Return the high watermark of this cache, which is the size at which
681 /// eviction of existing items begins.
682 bsl::size_t highWatermark() const;
683
684 /// Return the low watermark of this cache, which is the size at which
685 /// eviction of existing items ends.
686 bsl::size_t lowWatermark() const;
687
688 /// Return the current size of this cache.
689 bsl::size_t size() const;
690
691 /// Call the specified `visitor` for every item stored in this cache in
692 /// the order of the eviction queue until `visitor` returns `false`.
693 /// The `VISITOR` type must be a callable object that can be invoked in
694 /// the same way as the function `bool (const KEY&, const VALUE&)`
695 template <class VISITOR>
696 void visit(VISITOR& visitor) const;
697};
698
699/// This class implements a test utility that gives the test driver access
700/// to the lock / unlock method of the RW mutex. Its purpose is to allow
701/// testing that the locking actually happens as planned.
702///
703/// See @ref bdlcc_cache
704template <class KEY,
705 class VALUE,
706 class HASH,
707 class EQUAL>
709
710 // DATA
712
713 public:
714 // CREATORS
715
716 /// Create a `Cache_TestUtil` object to test locking in the specified
717 /// `cache`.
719
720 /// Destroy this object.
721 ~Cache_TestUtil() = default;
722
723 // MANIPULATORS
724
725 /// Call the `lockRead` method of `bdlcc::Cache` `d_rwlock` lock.
726 void lockRead();
727
728 /// Call the `lockWrite` method of `bdlcc::Cache` `d_rwlock` lock.
729 void lockWrite();
730
731 /// Call the `unlock` method of `bdlcc::Cache` `d_rwlock` lock.
732 void unlock();
733
734};
735
736// ============================================================================
737// INLINE FUNCTION DEFINITIONS
738// ============================================================================
739
740 // ------------------------
741 // class Cache_QueueProctor
742 // ------------------------
743
744// PRIVATE ACCESSORS
745template <class KEY>
746inline
748{
749 return !d_queue_p || d_queue_p->empty() ? 0
750 : &*d_queue_p->rbegin();
751}
752
753// CREATORS
754template <class KEY>
755inline
757: d_queue_p(queue)
758, d_last_p(last())
759{}
760
761template <class KEY>
762inline
764{
765 if (d_queue_p) {
766 while (last() != d_last_p) {
767 d_queue_p->pop_back();
768 }
769 }
770}
771
772// MANIPULATORS
773template <class KEY>
774inline
776{
777 d_queue_p = 0;
778}
779
780 // -----------
781 // class Cache
782 // -----------
783
784// CREATORS
785template <class KEY, class VALUE, class HASH, class EQUAL>
787: d_allocator_p(bslma::Default::allocator(basicAllocator))
788, d_map(d_allocator_p)
789, d_queue(d_allocator_p)
790, d_evictionPolicy(CacheEvictionPolicy::e_LRU)
791, d_lowWatermark(bsl::numeric_limits<bsl::size_t>::max())
792, d_highWatermark(bsl::numeric_limits<bsl::size_t>::max())
793, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
794{
795}
796
797template <class KEY, class VALUE, class HASH, class EQUAL>
799 CacheEvictionPolicy::Enum evictionPolicy,
800 bsl::size_t lowWatermark,
801 bsl::size_t highWatermark,
802 bslma::Allocator *basicAllocator)
803: d_allocator_p(bslma::Default::allocator(basicAllocator))
804, d_map(d_allocator_p)
805, d_queue(d_allocator_p)
806, d_evictionPolicy(evictionPolicy)
807, d_lowWatermark(lowWatermark)
808, d_highWatermark(highWatermark)
809, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
810{
814}
815
816template <class KEY, class VALUE, class HASH, class EQUAL>
818 CacheEvictionPolicy::Enum evictionPolicy,
819 bsl::size_t lowWatermark,
820 bsl::size_t highWatermark,
821 const HASH& hashFunction,
822 const EQUAL& equalFunction,
823 bslma::Allocator *basicAllocator)
824: d_allocator_p(bslma::Default::allocator(basicAllocator))
825, d_map(0, hashFunction, equalFunction, d_allocator_p)
826, d_queue(d_allocator_p)
827, d_evictionPolicy(evictionPolicy)
828, d_lowWatermark(lowWatermark)
829, d_highWatermark(highWatermark)
830, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
831{
835}
836
837// PRIVATE MANIPULATORS
838template <class KEY, class VALUE, class HASH, class EQUAL>
840{
841 if (d_map.size() < d_highWatermark) {
842 return; // RETURN
843 }
844
845 while (d_map.size() >= d_lowWatermark && d_map.size() > 0) {
846 const typename MapType::iterator mapIt = d_map.find(d_queue.front());
847 BSLS_ASSERT(mapIt != d_map.end());
848 evictItem(mapIt);
849 }
850}
851
852template <class KEY, class VALUE, class HASH, class EQUAL>
853void Cache<KEY, VALUE, HASH, EQUAL>::evictItem(
854 const typename MapType::iterator& mapIt)
855{
856 ValuePtrType value = mapIt->second.first;
857
858 d_queue.erase(mapIt->second.second);
859 d_map.erase(mapIt);
860
861 if (d_postEvictionCallback) {
862 d_postEvictionCallback(value);
863 }
864}
865template <class KEY, class VALUE, class HASH, class EQUAL>
866inline
867bool Cache<KEY, VALUE, HASH, EQUAL>::insertValuePtrMoveImp(
868 KEY *key_p,
869 bool moveKey,
870 ValuePtrType *valuePtr_p,
871 bool moveValuePtr)
872{
873#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
874 enum { k_RVALUE_ASSIGN = true };
875#else
876 enum { k_RVALUE_ASSIGN = false };
877#endif
878
879 enforceHighWatermark();
880
881 KEY& key = *key_p;
882 ValuePtrType& valuePtr = *valuePtr_p;
883
884 typename MapType::iterator mapIt = d_map.find(key);
885 if (mapIt != d_map.end()) {
886 if (k_RVALUE_ASSIGN && moveValuePtr) {
887 mapIt->second.first = bslmf::MovableRefUtil::move(valuePtr);
888 }
889 else {
890 mapIt->second.first = valuePtr;
891 }
892
893 typename QueueType::iterator queueIt = mapIt->second.second;
894
895 // Move 'queueIt' to the back of 'd_queue'.
896
897 d_queue.splice(d_queue.end(), d_queue, queueIt);
898
899 return false; // RETURN
900 }
901 else {
902 Cache_QueueProctor<KEY> proctor(&d_queue);
903 d_queue.push_back(key);
904 typename QueueType::iterator queueIt = d_queue.end();
905 --queueIt;
906
907 bsls::ObjectBuffer<MapValue> mapValueFootprint;
908 MapValue *mapValue_p = mapValueFootprint.address();
909
910 if (moveValuePtr) {
911 new (mapValue_p) MapValue(bslmf::MovableRefUtil::move(valuePtr),
912 queueIt,
913 d_allocator_p);
914 }
915 else {
916 new (mapValue_p) MapValue(valuePtr,
917 queueIt,
918 d_allocator_p);
919 }
920 bslma::DestructorGuard<MapValue> mapValueGuard(mapValue_p);
921
922 if (moveKey) {
923 d_map.emplace(bslmf::MovableRefUtil::move(key),
924 bslmf::MovableRefUtil::move(*mapValue_p));
925 }
926 else {
927 d_map.emplace(key,
928 bslmf::MovableRefUtil::move(*mapValue_p));
929 }
930
931 proctor.release();
932
933 return true; // RETURN
934 }
935}
936
937// MANIPULATORS
938template <class KEY, class VALUE, class HASH, class EQUAL>
940{
941 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
942 d_map.clear();
943 d_queue.clear();
944}
945
946template <class KEY, class VALUE, class HASH, class EQUAL>
948{
949 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
950
951 const typename MapType::iterator mapIt = d_map.find(key);
952 if (mapIt == d_map.end()) {
953 return 1; // RETURN
954 }
955
956 evictItem(mapIt);
957 return 0;
958}
959
960template <class KEY, class VALUE, class HASH, class EQUAL>
961template <class INPUT_ITERATOR>
963 INPUT_ITERATOR end)
964{
965 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
966
967 int count = 0;
968 for (; begin != end; ++begin) {
969 const typename MapType::iterator mapIt = d_map.find(*begin);
970 if (mapIt == d_map.end()) {
971 continue;
972 }
973 ++count;
974 evictItem(mapIt);
975 }
976
977 return count;
978}
979
980template <class KEY, class VALUE, class HASH, class EQUAL>
981inline
983{
984 return eraseBulk(keys.begin(), keys.end());
985}
986
987template <class KEY, class VALUE, class HASH, class EQUAL>
988inline
989void Cache<KEY, VALUE, HASH, EQUAL>::insert(const KEY& key, const VALUE& value)
990{
991 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
992
993 KEY *key_p = const_cast<KEY *>(&key);
994 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(d_allocator_p, value);
995
996 insertValuePtrMoveImp(key_p, false, &valuePtr, true);
997}
998
999template <class KEY, class VALUE, class HASH, class EQUAL>
1002{
1003 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1004
1005 KEY *key_p = const_cast<KEY *>(&key);
1006 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(
1007 d_allocator_p,
1009 // might throw, but BEFORE 'value' is moved
1010
1011 insertValuePtrMoveImp(key_p, false, &valuePtr, true);
1012}
1013
1014template <class KEY, class VALUE, class HASH, class EQUAL>
1016 const VALUE& value)
1017{
1018 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1019
1020 KEY& localKey = key;
1021 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(d_allocator_p, value);
1022 // might throw
1023
1024 insertValuePtrMoveImp(&localKey, true, &valuePtr, true);
1025}
1026
1027template <class KEY, class VALUE, class HASH, class EQUAL>
1030{
1031 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1032
1033 KEY& localKey = key;
1034 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(
1035 d_allocator_p,
1037 // might throw, but BEFORE 'value' is moved
1038
1039 insertValuePtrMoveImp(&localKey, true, &valuePtr, true);
1040}
1041
1042template <class KEY, class VALUE, class HASH, class EQUAL>
1043inline
1045 const ValuePtrType& valuePtr)
1046{
1047 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1048
1049 KEY *key_p = const_cast<KEY *>(&key);
1050 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&valuePtr);
1051
1052 insertValuePtrMoveImp(key_p, false, valuePtr_p, false);
1053}
1054
1055template <class KEY, class VALUE, class HASH, class EQUAL>
1057 const ValuePtrType& valuePtr)
1058{
1059 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1060
1061 KEY& localKey = key;
1062 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&valuePtr);
1063
1064 insertValuePtrMoveImp(&localKey, true, valuePtr_p, false);
1065}
1066
1067template <class KEY, class VALUE, class HASH, class EQUAL>
1068template <class INPUT_ITERATOR>
1070 INPUT_ITERATOR end)
1071{
1072 int count = 0;
1073 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1074
1075 for (; begin != end; ++begin) {
1076 KEY *key_p = const_cast<KEY *>( &begin->first);
1077 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&begin->second);
1078
1079 count += insertValuePtrMoveImp(key_p, false, valuePtr_p, false);
1080 }
1081
1082 return count;
1083}
1084
1085template <class KEY, class VALUE, class HASH, class EQUAL>
1086inline
1088{
1089 return insertBulk(data.begin(), data.end());
1090}
1091
1092template <class KEY, class VALUE, class HASH, class EQUAL>
1095{
1096 typedef bsl::vector<KVType> Vec;
1097
1098 Vec& local = data;
1099
1100 int count = 0;
1101 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1102
1103 for (typename Vec::iterator it = local.begin(); it < local.end(); ++it) {
1104 KEY *key_p = &it->first;
1105 ValuePtrType *valuePtr_p = &it->second;
1106
1107 count += insertValuePtrMoveImp(key_p, true, valuePtr_p, true);
1108 }
1109 return count;
1110}
1111
1112template <class KEY, class VALUE, class HASH, class EQUAL>
1113inline
1115{
1116 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1117
1118 if (d_map.size() > 0) {
1119 const typename MapType::iterator mapIt = d_map.find(d_queue.front());
1120 BSLS_ASSERT(mapIt != d_map.end());
1121 evictItem(mapIt);
1122 return 0; // RETURN
1123 }
1124
1125 return 1;
1126}
1127
1128template <class KEY, class VALUE, class HASH, class EQUAL>
1130 const PostEvictionCallback& postEvictionCallback)
1131{
1132 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1133 d_postEvictionCallback = postEvictionCallback;
1134}
1135
1136template <class KEY, class VALUE, class HASH, class EQUAL>
1139 const KEY& key,
1140 bool modifyEvictionQueue)
1141{
1142 int writeLock = d_evictionPolicy == CacheEvictionPolicy::e_LRU &&
1143 modifyEvictionQueue ? 1 : 0;
1144 if (writeLock) {
1145 d_rwlock.lockWrite();
1146 }
1147 else {
1148 d_rwlock.lockRead();
1149 }
1150
1151 // Since the guard is constructed with a locked synchronization object, the
1152 // guard's call to 'unlock' correctly handles both read and write
1153 // scenarios.
1154
1155 bslmt::ReadLockGuard<LockType> guard(&d_rwlock, true);
1156
1157 typename MapType::iterator mapIt = d_map.find(key);
1158 if (mapIt == d_map.end()) {
1159 return 1; // RETURN
1160 }
1161
1162 *value = mapIt->second.first;
1163
1164 if (writeLock) {
1165 typename QueueType::iterator queueIt = mapIt->second.second;
1166 typename QueueType::iterator last = d_queue.end();
1167 --last;
1168 if (last != queueIt) {
1169 d_queue.splice(d_queue.end(), d_queue, queueIt);
1170 }
1171 }
1172
1173 return 0;
1174}
1175
1176// ACCESSORS
1177template <class KEY, class VALUE, class HASH, class EQUAL>
1178inline
1180{
1181 return d_map.key_eq();
1182}
1183
1184template <class KEY, class VALUE, class HASH, class EQUAL>
1185inline
1188{
1189 return d_evictionPolicy;
1190}
1191
1192template <class KEY, class VALUE, class HASH, class EQUAL>
1193inline
1195{
1196 return d_map.hash_function();
1197}
1198
1199template <class KEY, class VALUE, class HASH, class EQUAL>
1200inline
1202{
1203 return d_highWatermark;
1204}
1205
1206template <class KEY, class VALUE, class HASH, class EQUAL>
1207inline
1209{
1210 return d_lowWatermark;
1211}
1212
1213template <class KEY, class VALUE, class HASH, class EQUAL>
1214inline
1216{
1217 bslmt::ReadLockGuard<LockType> guard(&d_rwlock);
1218 return d_map.size();
1219}
1220
1221template <class KEY, class VALUE, class HASH, class EQUAL>
1222template <class VISITOR>
1223void Cache<KEY, VALUE, HASH, EQUAL>::visit(VISITOR& visitor) const
1224{
1225 bslmt::ReadLockGuard<LockType> guard(&d_rwlock);
1226
1227 for (typename QueueType::const_iterator queueIt = d_queue.begin();
1228 queueIt != d_queue.end(); ++queueIt) {
1229
1230 const KEY& key = *queueIt;
1231 const typename MapType::const_iterator mapIt = d_map.find(key);
1232 BSLS_ASSERT(mapIt != d_map.end());
1233 const ValuePtrType& valuePtr = mapIt->second.first;
1234
1235 if (!visitor(key, *valuePtr)) {
1236 break;
1237 }
1238 }
1239}
1240
1241 // --------------------
1242 // class Cache_TestUtil
1243 // --------------------
1244
1245// CREATORS
1246template <class KEY, class VALUE, class HASH, class EQUAL>
1247inline
1253
1254// MANIPULATORS
1255template <class KEY, class VALUE, class HASH, class EQUAL>
1256inline
1258{
1259 d_cache.d_rwlock.lockRead();
1260}
1261
1262template <class KEY, class VALUE, class HASH, class EQUAL>
1263inline
1265{
1266 d_cache.d_rwlock.lockWrite();
1267}
1268
1269template <class KEY, class VALUE, class HASH, class EQUAL>
1270inline
1272{
1273 d_cache.d_rwlock.unlock();
1274}
1275
1276} // close package namespace
1277
1278
1279namespace bslma {
1280
1281template <class KEY, class VALUE, class HASH, class EQUAL>
1282struct UsesBslmaAllocator<bdlcc::Cache<KEY, VALUE, HASH, EQUAL> >
1284{
1285};
1286
1287} // close namespace bslma
1288
1289
1290
1291#endif
1292
1293// ----------------------------------------------------------------------------
1294// Copyright 2017 Bloomberg Finance L.P.
1295//
1296// Licensed under the Apache License, Version 2.0 (the "License");
1297// you may not use this file except in compliance with the License.
1298// You may obtain a copy of the License at
1299//
1300// http://www.apache.org/licenses/LICENSE-2.0
1301//
1302// Unless required by applicable law or agreed to in writing, software
1303// distributed under the License is distributed on an "AS IS" BASIS,
1304// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1305// See the License for the specific language governing permissions and
1306// limitations under the License.
1307// ----------------------------- END-OF-FILE ----------------------------------
1308
1309/** @} */
1310/** @} */
1311/** @} */
Definition bdlcc_cache.h:400
Cache_QueueProctor(bsl::list< KEY > *queue)
Create a Cache_QueueProctor object to monitor the specified queue.
Definition bdlcc_cache.h:756
void release()
Definition bdlcc_cache.h:775
~Cache_QueueProctor()
Definition bdlcc_cache.h:763
Definition bdlcc_cache.h:708
void lockRead()
Call the lockRead method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1257
~Cache_TestUtil()=default
Destroy this object.
void unlock()
Call the unlock method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1271
Cache_TestUtil(Cache< KEY, VALUE, HASH, EQUAL > &cache)
Definition bdlcc_cache.h:1248
void lockWrite()
Call the lockWrite method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1264
Definition bdlcc_cache.h:444
bsl::size_t lowWatermark() const
Definition bdlcc_cache.h:1208
void clear()
Definition bdlcc_cache.h:939
void insert(bslmf::MovableRef< KEY > key, const ValuePtrType &valuePtr)
Definition bdlcc_cache.h:1056
HASH hashFunction() const
Definition bdlcc_cache.h:1194
int insertBulk(bslmf::MovableRef< bsl::vector< KVType > > data)
Definition bdlcc_cache.h:1093
void insert(const KEY &key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_cache.h:1000
bsl::size_t size() const
Return the current size of this cache.
Definition bdlcc_cache.h:1215
int tryGetValue(bsl::shared_ptr< VALUE > *value, const KEY &key, bool modifyEvictionQueue=true)
Definition bdlcc_cache.h:1137
int insertBulk(const bsl::vector< KVType > &data)
Definition bdlcc_cache.h:1087
void insert(const KEY &key, const VALUE &value)
Definition bdlcc_cache.h:989
void insert(const KEY &key, const ValuePtrType &valuePtr)
Definition bdlcc_cache.h:1044
Cache(bslma::Allocator *basicAllocator=0)
Definition bdlcc_cache.h:786
void visit(VISITOR &visitor) const
Definition bdlcc_cache.h:1223
int eraseBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end)
Definition bdlcc_cache.h:962
bsl::pair< KEY, ValuePtrType > KVType
Value type of a bulk insert entry.
Definition bdlcc_cache.h:456
void insert(bslmf::MovableRef< KEY > key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_cache.h:1028
Cache(CacheEvictionPolicy::Enum evictionPolicy, bsl::size_t lowWatermark, bsl::size_t highWatermark, bslma::Allocator *basicAllocator=0)
Definition bdlcc_cache.h:798
bsl::function< void(const ValuePtrType &)> PostEvictionCallback
Type of function to call after an item has been evicted from the cache.
Definition bdlcc_cache.h:453
Cache(CacheEvictionPolicy::Enum evictionPolicy, bsl::size_t lowWatermark, bsl::size_t highWatermark, const HASH &hashFunction, const EQUAL &equalFunction, bslma::Allocator *basicAllocator=0)
Definition bdlcc_cache.h:817
void insert(bslmf::MovableRef< KEY > key, const VALUE &value)
Definition bdlcc_cache.h:1015
~Cache()=default
Destroy this object.
CacheEvictionPolicy::Enum evictionPolicy() const
Return the eviction policy used by this cache.
Definition bdlcc_cache.h:1187
EQUAL equalFunction() const
Definition bdlcc_cache.h:1179
int eraseBulk(const bsl::vector< KEY > &keys)
Definition bdlcc_cache.h:982
int insertBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end)
Definition bdlcc_cache.h:1069
void setPostEvictionCallback(const PostEvictionCallback &postEvictionCallback)
Definition bdlcc_cache.h:1129
int popFront()
Definition bdlcc_cache.h:1114
bsl::shared_ptr< VALUE > ValuePtrType
Shared pointer type pointing to value type.
Definition bdlcc_cache.h:450
int erase(const KEY &key)
Definition bdlcc_cache.h:947
bsl::size_t highWatermark() const
Definition bdlcc_cache.h:1201
Forward declaration.
Definition bslstl_function.h:946
Forward declaration required by List_NodeProctor.
Definition bslstl_list.h:1078
List_Iterator< KEY > iterator
Definition bslstl_list.h:1115
List_Iterator< const KEY > const_iterator
Definition bslstl_list.h:1116
Definition bslstl_pair.h:1280
Definition bslstl_sharedptr.h:1838
Definition bslstl_unorderedmap.h:1123
BloombergLP::bslstl::HashTableIterator< value_type, difference_type > iterator
Definition bslstl_unorderedmap.h:1233
BloombergLP::bslstl::HashTableIterator< const value_type, difference_type > const_iterator
Definition bslstl_unorderedmap.h:1235
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2866
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2874
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslma_destructorguard.h:132
Definition bslmf_movableref.h:752
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwritermutex.h:244
Definition bslmt_writelockguard.h:221
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_REVIEW(X)
Definition bsls_review.h:1019
Definition bdlcc_boundedqueue.h:270
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76
Definition bdlcc_cache.h:381
Enum
Enumeration of supported cache eviction policies.
Definition bdlcc_cache.h:386
@ e_LRU
Definition bdlcc_cache.h:388
@ e_FIFO
Definition bdlcc_cache.h:389
Definition bslstl_equalto.h:316
Definition bslstl_hash.h:495
Definition bslma_usesbslmaallocator.h:344
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bsls_objectbuffer.h:277
TYPE * address()
Definition bsls_objectbuffer.h:335