BDE 4.14.0 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. The behavior is
551 /// undefined unless `lowWatermark <= highWatermark`, `1 <= lowWatermark`,
552 /// and `1 <= highWatermark`.
554 bsl::size_t lowWatermark,
555 bsl::size_t highWatermark,
556 bslma::Allocator *basicAllocator = 0);
557
558 /// Create an empty cache using the specified `evictionPolicy`,
559 /// `lowWatermark`, and `highWatermark`. The specified `hashFunction` is
560 /// used to generate the hash values for a given key, and the specified
561 /// `equalFunction` is used to determine whether two keys have the same
562 /// value. Optionally specify the `basicAllocator` used to supply memory.
563 /// If `basicAllocator` is 0, the currently installed default allocator is
564 /// used. The behavior is undefined unless `lowWatermark <=
565 /// highWatermark`, `1 <= lowWatermark`, and `1 <= highWatermark`.
567 bsl::size_t lowWatermark,
568 bsl::size_t highWatermark,
569 const HASH& hashFunction,
570 const EQUAL& equalFunction,
571 bslma::Allocator *basicAllocator = 0);
572
573 /// Destroy this object.
574 ~Cache() = default;
575
576 // MANIPULATORS
577
578 /// Remove all items from this cache. Do *not* invoke the post-eviction
579 /// callback.
580 void clear();
581
582 /// Remove the item having the specified `key` from this cache. Invoke the
583 /// post-eviction callback for the removed item. Return 0 on success and 1
584 /// if `key` does not exist.
585 int erase(const KEY& key);
586
587 /// Remove the items having the keys in the specified range
588 /// `[ begin, end )`, from this cache. Invoke the post-eviction
589 /// callback for each removed item. Return the number of items
590 /// successfully removed.
591 template <class INPUT_ITERATOR>
592 int eraseBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end);
593
594 /// Remove the items having the specified `keys` from this cache.
595 /// Invoke the post-eviction callback for each removed item. Return the
596 /// number of items successfully removed.
597 int eraseBulk(const bsl::vector<KEY>& keys);
598
599 void insert(const KEY& key, const VALUE& value);
600 void insert(const KEY& key, bslmf::MovableRef<VALUE> value);
601 void insert(bslmf::MovableRef<KEY> key, const VALUE& value);
602 /// Move the specified `key` and its associated `value` into this cache.
603 /// If `key` already exists, then its value will be replaced with `value`.
604 /// 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.
610
611 void insert(const KEY& key, const ValuePtrType& valuePtr);
612 /// Insert the specified `key` and its associated `valuePtr` into this
613 /// cache. If `key` already exists, then its value will be replaced
614 /// with `value`. Note that the method with `key` moved provides the
615 /// `basic` but not the `strong` exception guarantee -- if a throw
616 /// occurs, the cache will not be modified, but `key` may be changed.
617 /// Also note that `key` must be copyable, even if it is moved.
618 void insert(bslmf::MovableRef<KEY> key, const ValuePtrType& valuePtr);
619
620 /// Insert the specified range of Key-Value pairs specified by
621 /// `[ begin, end )` into this cache. If a key already exists, then its
622 /// value will be replaced with the value. Return the number of items
623 /// successfully inserted.
624 template <class INPUT_ITERATOR>
625 int insertBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end);
626
627 /// Insert the specified `data` (composed of Key-Value pairs) into this
628 /// cache. If a key already exists, then its value will be replaced
629 /// with the value. Return the number of items successfully inserted.
631
632 /// Insert the specified `data` (composed of Key-Value pairs) into this
633 /// cache. If a key already exists, then its value will be replaced
634 /// with the value. Return the number of items successfully inserted.
635 /// If an exception occurs during this action, we provide only the
636 /// basic guarantee - both this cache and `data` will be in some valid
637 /// but unspecified state.
639
640 /// Remove the item at the front of the eviction queue. Invoke the
641 /// post-eviction callback for the removed item. Return 0 on success,
642 /// and 1 if this cache is empty.
643 int popFront();
644
645 /// Set the post-eviction callback to the specified
646 /// `postEvictionCallback`. The post-eviction callback is invoked for
647 /// each item evicted or removed from this cache.
649 const PostEvictionCallback& postEvictionCallback);
650
651 /// Load, into the specified `value`, the value associated with the
652 /// specified `key` in this cache. If the optionally specified
653 /// `modifyEvictionQueue` is `true` and the eviction policy is LRU, then
654 /// move the cached item to the back of the eviction queue. Return 0 on
655 /// success, and 1 if `key` does not exist in this cache. Note that a
656 /// write lock is acquired only if this queue is modified.
658 const KEY& key,
659 bool modifyEvictionQueue = true);
660
661 // ACCESSORS
662
663 /// Return (a copy of) the key-equality functor used by this cache that
664 /// returns `true` if two `KEY` objects have the same value, and `false`
665 /// otherwise.
666 EQUAL equalFunction() const;
667
668 /// Return the eviction policy used by this cache.
670
671 /// Return (a copy of) the unary hash functor used by this cache to
672 /// generate a hash value (of type `std::size_t`) for a `KEY` object.
673 HASH hashFunction() const;
674
675 /// Return the high watermark of this cache, which is the size at which
676 /// eviction of existing items begins.
677 bsl::size_t highWatermark() const;
678
679 /// Return the low watermark of this cache, which is the size at which
680 /// eviction of existing items ends.
681 bsl::size_t lowWatermark() const;
682
683 /// Return the current size of this cache.
684 bsl::size_t size() const;
685
686 /// Call the specified `visitor` for every item stored in this cache in
687 /// the order of the eviction queue until `visitor` returns `false`.
688 /// The `VISITOR` type must be a callable object that can be invoked in
689 /// the same way as the function `bool (const KEY&, const VALUE&)`
690 template <class VISITOR>
691 void visit(VISITOR& visitor) const;
692};
693
694/// This class implements a test utility that gives the test driver access
695/// to the lock / unlock method of the RW mutex. Its purpose is to allow
696/// testing that the locking actually happens as planned.
697///
698/// See @ref bdlcc_cache
699template <class KEY,
700 class VALUE,
701 class HASH,
702 class EQUAL>
704
705 // DATA
707
708 public:
709 // CREATORS
710
711 /// Create a `Cache_TestUtil` object to test locking in the specified
712 /// `cache`.
714
715 /// Destroy this object.
716 ~Cache_TestUtil() = default;
717
718 // MANIPULATORS
719
720 /// Call the `lockRead` method of `bdlcc::Cache` `d_rwlock` lock.
721 void lockRead();
722
723 /// Call the `lockWrite` method of `bdlcc::Cache` `d_rwlock` lock.
724 void lockWrite();
725
726 /// Call the `unlock` method of `bdlcc::Cache` `d_rwlock` lock.
727 void unlock();
728
729};
730
731// ============================================================================
732// INLINE FUNCTION DEFINITIONS
733// ============================================================================
734
735 // ------------------------
736 // class Cache_QueueProctor
737 // ------------------------
738
739// PRIVATE ACCESSORS
740template <class KEY>
741inline
743{
744 return !d_queue_p || d_queue_p->empty() ? 0
745 : &*d_queue_p->rbegin();
746}
747
748// CREATORS
749template <class KEY>
750inline
752: d_queue_p(queue)
753, d_last_p(last())
754{}
755
756template <class KEY>
757inline
759{
760 if (d_queue_p) {
761 while (last() != d_last_p) {
762 d_queue_p->pop_back();
763 }
764 }
765}
766
767// MANIPULATORS
768template <class KEY>
769inline
771{
772 d_queue_p = 0;
773}
774
775 // -----------
776 // class Cache
777 // -----------
778
779// CREATORS
780template <class KEY, class VALUE, class HASH, class EQUAL>
782: d_allocator_p(bslma::Default::allocator(basicAllocator))
783, d_map(d_allocator_p)
784, d_queue(d_allocator_p)
785, d_evictionPolicy(CacheEvictionPolicy::e_LRU)
786, d_lowWatermark(bsl::numeric_limits<bsl::size_t>::max())
787, d_highWatermark(bsl::numeric_limits<bsl::size_t>::max())
788, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
789{
790}
791
792template <class KEY, class VALUE, class HASH, class EQUAL>
794 CacheEvictionPolicy::Enum evictionPolicy,
795 bsl::size_t lowWatermark,
796 bsl::size_t highWatermark,
797 bslma::Allocator *basicAllocator)
798: d_allocator_p(bslma::Default::allocator(basicAllocator))
799, d_map(d_allocator_p)
800, d_queue(d_allocator_p)
801, d_evictionPolicy(evictionPolicy)
802, d_lowWatermark(lowWatermark)
803, d_highWatermark(highWatermark)
804, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
805{
809}
810
811template <class KEY, class VALUE, class HASH, class EQUAL>
813 CacheEvictionPolicy::Enum evictionPolicy,
814 bsl::size_t lowWatermark,
815 bsl::size_t highWatermark,
816 const HASH& hashFunction,
817 const EQUAL& equalFunction,
818 bslma::Allocator *basicAllocator)
819: d_allocator_p(bslma::Default::allocator(basicAllocator))
820, d_map(0, hashFunction, equalFunction, d_allocator_p)
821, d_queue(d_allocator_p)
822, d_evictionPolicy(evictionPolicy)
823, d_lowWatermark(lowWatermark)
824, d_highWatermark(highWatermark)
825, d_postEvictionCallback(bsl::allocator_arg, d_allocator_p)
826{
830}
831
832// PRIVATE MANIPULATORS
833template <class KEY, class VALUE, class HASH, class EQUAL>
835{
836 if (d_map.size() < d_highWatermark) {
837 return; // RETURN
838 }
839
840 while (d_map.size() >= d_lowWatermark && d_map.size() > 0) {
841 const typename MapType::iterator mapIt = d_map.find(d_queue.front());
842 BSLS_ASSERT(mapIt != d_map.end());
843 evictItem(mapIt);
844 }
845}
846
847template <class KEY, class VALUE, class HASH, class EQUAL>
848void Cache<KEY, VALUE, HASH, EQUAL>::evictItem(
849 const typename MapType::iterator& mapIt)
850{
851 ValuePtrType value = mapIt->second.first;
852
853 d_queue.erase(mapIt->second.second);
854 d_map.erase(mapIt);
855
856 if (d_postEvictionCallback) {
857 d_postEvictionCallback(value);
858 }
859}
860template <class KEY, class VALUE, class HASH, class EQUAL>
861inline
862bool Cache<KEY, VALUE, HASH, EQUAL>::insertValuePtrMoveImp(
863 KEY *key_p,
864 bool moveKey,
865 ValuePtrType *valuePtr_p,
866 bool moveValuePtr)
867{
868#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
869 enum { k_RVALUE_ASSIGN = true };
870#else
871 enum { k_RVALUE_ASSIGN = false };
872#endif
873
874 enforceHighWatermark();
875
876 KEY& key = *key_p;
877 ValuePtrType& valuePtr = *valuePtr_p;
878
879 typename MapType::iterator mapIt = d_map.find(key);
880 if (mapIt != d_map.end()) {
881 if (k_RVALUE_ASSIGN && moveValuePtr) {
882 mapIt->second.first = bslmf::MovableRefUtil::move(valuePtr);
883 }
884 else {
885 mapIt->second.first = valuePtr;
886 }
887
888 typename QueueType::iterator queueIt = mapIt->second.second;
889
890 // Move 'queueIt' to the back of 'd_queue'.
891
892 d_queue.splice(d_queue.end(), d_queue, queueIt);
893
894 return false; // RETURN
895 }
896 else {
897 Cache_QueueProctor<KEY> proctor(&d_queue);
898 d_queue.push_back(key);
899 typename QueueType::iterator queueIt = d_queue.end();
900 --queueIt;
901
902 bsls::ObjectBuffer<MapValue> mapValueFootprint;
903 MapValue *mapValue_p = mapValueFootprint.address();
904
905 if (moveValuePtr) {
906 new (mapValue_p) MapValue(bslmf::MovableRefUtil::move(valuePtr),
907 queueIt,
908 d_allocator_p);
909 }
910 else {
911 new (mapValue_p) MapValue(valuePtr,
912 queueIt,
913 d_allocator_p);
914 }
915 bslma::DestructorGuard<MapValue> mapValueGuard(mapValue_p);
916
917 if (moveKey) {
918 d_map.emplace(bslmf::MovableRefUtil::move(key),
919 bslmf::MovableRefUtil::move(*mapValue_p));
920 }
921 else {
922 d_map.emplace(key,
923 bslmf::MovableRefUtil::move(*mapValue_p));
924 }
925
926 proctor.release();
927
928 return true; // RETURN
929 }
930}
931
932// MANIPULATORS
933template <class KEY, class VALUE, class HASH, class EQUAL>
935{
936 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
937 d_map.clear();
938 d_queue.clear();
939}
940
941template <class KEY, class VALUE, class HASH, class EQUAL>
943{
944 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
945
946 const typename MapType::iterator mapIt = d_map.find(key);
947 if (mapIt == d_map.end()) {
948 return 1; // RETURN
949 }
950
951 evictItem(mapIt);
952 return 0;
953}
954
955template <class KEY, class VALUE, class HASH, class EQUAL>
956template <class INPUT_ITERATOR>
958 INPUT_ITERATOR end)
959{
960 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
961
962 int count = 0;
963 for (; begin != end; ++begin) {
964 const typename MapType::iterator mapIt = d_map.find(*begin);
965 if (mapIt == d_map.end()) {
966 continue;
967 }
968 ++count;
969 evictItem(mapIt);
970 }
971
972 return count;
973}
974
975template <class KEY, class VALUE, class HASH, class EQUAL>
976inline
978{
979 return eraseBulk(keys.begin(), keys.end());
980}
981
982template <class KEY, class VALUE, class HASH, class EQUAL>
983inline
984void Cache<KEY, VALUE, HASH, EQUAL>::insert(const KEY& key, const VALUE& value)
985{
986 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
987
988 KEY *key_p = const_cast<KEY *>(&key);
989 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(d_allocator_p, value);
990
991 insertValuePtrMoveImp(key_p, false, &valuePtr, true);
992}
993
994template <class KEY, class VALUE, class HASH, class EQUAL>
997{
998 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
999
1000 KEY *key_p = const_cast<KEY *>(&key);
1001 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(
1002 d_allocator_p,
1004 // might throw, but BEFORE 'value' is moved
1005
1006 insertValuePtrMoveImp(key_p, false, &valuePtr, true);
1007}
1008
1009template <class KEY, class VALUE, class HASH, class EQUAL>
1011 const VALUE& value)
1012{
1013 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1014
1015 KEY& localKey = key;
1016 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(d_allocator_p, value);
1017 // might throw
1018
1019 insertValuePtrMoveImp(&localKey, true, &valuePtr, true);
1020}
1021
1022template <class KEY, class VALUE, class HASH, class EQUAL>
1025{
1026 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1027
1028 KEY& localKey = key;
1029 ValuePtrType valuePtr = bsl::allocate_shared<VALUE>(
1030 d_allocator_p,
1032 // might throw, but BEFORE 'value' is moved
1033
1034 insertValuePtrMoveImp(&localKey, true, &valuePtr, true);
1035}
1036
1037template <class KEY, class VALUE, class HASH, class EQUAL>
1038inline
1040 const ValuePtrType& valuePtr)
1041{
1042 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1043
1044 KEY *key_p = const_cast<KEY *>(&key);
1045 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&valuePtr);
1046
1047 insertValuePtrMoveImp(key_p, false, valuePtr_p, false);
1048}
1049
1050template <class KEY, class VALUE, class HASH, class EQUAL>
1052 const ValuePtrType& valuePtr)
1053{
1054 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1055
1056 KEY& localKey = key;
1057 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&valuePtr);
1058
1059 insertValuePtrMoveImp(&localKey, true, valuePtr_p, false);
1060}
1061
1062template <class KEY, class VALUE, class HASH, class EQUAL>
1063template <class INPUT_ITERATOR>
1065 INPUT_ITERATOR end)
1066{
1067 int count = 0;
1068 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1069
1070 for (; begin != end; ++begin) {
1071 KEY *key_p = const_cast<KEY *>( &begin->first);
1072 ValuePtrType *valuePtr_p = const_cast<ValuePtrType *>(&begin->second);
1073
1074 count += insertValuePtrMoveImp(key_p, false, valuePtr_p, false);
1075 }
1076
1077 return count;
1078}
1079
1080template <class KEY, class VALUE, class HASH, class EQUAL>
1081inline
1083{
1084 return insertBulk(data.begin(), data.end());
1085}
1086
1087template <class KEY, class VALUE, class HASH, class EQUAL>
1090{
1091 typedef bsl::vector<KVType> Vec;
1092
1093 Vec& local = data;
1094
1095 int count = 0;
1096 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1097
1098 for (typename Vec::iterator it = local.begin(); it < local.end(); ++it) {
1099 KEY *key_p = &it->first;
1100 ValuePtrType *valuePtr_p = &it->second;
1101
1102 count += insertValuePtrMoveImp(key_p, true, valuePtr_p, true);
1103 }
1104 return count;
1105}
1106
1107template <class KEY, class VALUE, class HASH, class EQUAL>
1108inline
1110{
1111 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1112
1113 if (d_map.size() > 0) {
1114 const typename MapType::iterator mapIt = d_map.find(d_queue.front());
1115 BSLS_ASSERT(mapIt != d_map.end());
1116 evictItem(mapIt);
1117 return 0; // RETURN
1118 }
1119
1120 return 1;
1121}
1122
1123template <class KEY, class VALUE, class HASH, class EQUAL>
1125 const PostEvictionCallback& postEvictionCallback)
1126{
1127 bslmt::WriteLockGuard<LockType> guard(&d_rwlock);
1128 d_postEvictionCallback = postEvictionCallback;
1129}
1130
1131template <class KEY, class VALUE, class HASH, class EQUAL>
1134 const KEY& key,
1135 bool modifyEvictionQueue)
1136{
1137 int writeLock = d_evictionPolicy == CacheEvictionPolicy::e_LRU &&
1138 modifyEvictionQueue ? 1 : 0;
1139 if (writeLock) {
1140 d_rwlock.lockWrite();
1141 }
1142 else {
1143 d_rwlock.lockRead();
1144 }
1145
1146 // Since the guard is constructed with a locked synchronization object, the
1147 // guard's call to 'unlock' correctly handles both read and write
1148 // scenarios.
1149
1150 bslmt::ReadLockGuard<LockType> guard(&d_rwlock, true);
1151
1152 typename MapType::iterator mapIt = d_map.find(key);
1153 if (mapIt == d_map.end()) {
1154 return 1; // RETURN
1155 }
1156
1157 *value = mapIt->second.first;
1158
1159 if (writeLock) {
1160 typename QueueType::iterator queueIt = mapIt->second.second;
1161 typename QueueType::iterator last = d_queue.end();
1162 --last;
1163 if (last != queueIt) {
1164 d_queue.splice(d_queue.end(), d_queue, queueIt);
1165 }
1166 }
1167
1168 return 0;
1169}
1170
1171// ACCESSORS
1172template <class KEY, class VALUE, class HASH, class EQUAL>
1173inline
1175{
1176 return d_map.key_eq();
1177}
1178
1179template <class KEY, class VALUE, class HASH, class EQUAL>
1180inline
1183{
1184 return d_evictionPolicy;
1185}
1186
1187template <class KEY, class VALUE, class HASH, class EQUAL>
1188inline
1190{
1191 return d_map.hash_function();
1192}
1193
1194template <class KEY, class VALUE, class HASH, class EQUAL>
1195inline
1197{
1198 return d_highWatermark;
1199}
1200
1201template <class KEY, class VALUE, class HASH, class EQUAL>
1202inline
1204{
1205 return d_lowWatermark;
1206}
1207
1208template <class KEY, class VALUE, class HASH, class EQUAL>
1209inline
1211{
1212 bslmt::ReadLockGuard<LockType> guard(&d_rwlock);
1213 return d_map.size();
1214}
1215
1216template <class KEY, class VALUE, class HASH, class EQUAL>
1217template <class VISITOR>
1218void Cache<KEY, VALUE, HASH, EQUAL>::visit(VISITOR& visitor) const
1219{
1220 bslmt::ReadLockGuard<LockType> guard(&d_rwlock);
1221
1222 for (typename QueueType::const_iterator queueIt = d_queue.begin();
1223 queueIt != d_queue.end(); ++queueIt) {
1224
1225 const KEY& key = *queueIt;
1226 const typename MapType::const_iterator mapIt = d_map.find(key);
1227 BSLS_ASSERT(mapIt != d_map.end());
1228 const ValuePtrType& valuePtr = mapIt->second.first;
1229
1230 if (!visitor(key, *valuePtr)) {
1231 break;
1232 }
1233 }
1234}
1235
1236 // --------------------
1237 // class Cache_TestUtil
1238 // --------------------
1239
1240// CREATORS
1241template <class KEY, class VALUE, class HASH, class EQUAL>
1242inline
1248
1249// MANIPULATORS
1250template <class KEY, class VALUE, class HASH, class EQUAL>
1251inline
1253{
1254 d_cache.d_rwlock.lockRead();
1255}
1256
1257template <class KEY, class VALUE, class HASH, class EQUAL>
1258inline
1260{
1261 d_cache.d_rwlock.lockWrite();
1262}
1263
1264template <class KEY, class VALUE, class HASH, class EQUAL>
1265inline
1267{
1268 d_cache.d_rwlock.unlock();
1269}
1270
1271} // close package namespace
1272
1273
1274namespace bslma {
1275
1276template <class KEY, class VALUE, class HASH, class EQUAL>
1277struct UsesBslmaAllocator<bdlcc::Cache<KEY, VALUE, HASH, EQUAL> >
1279{
1280};
1281
1282} // close namespace bslma
1283
1284
1285
1286#endif
1287
1288// ----------------------------------------------------------------------------
1289// Copyright 2017 Bloomberg Finance L.P.
1290//
1291// Licensed under the Apache License, Version 2.0 (the "License");
1292// you may not use this file except in compliance with the License.
1293// You may obtain a copy of the License at
1294//
1295// http://www.apache.org/licenses/LICENSE-2.0
1296//
1297// Unless required by applicable law or agreed to in writing, software
1298// distributed under the License is distributed on an "AS IS" BASIS,
1299// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1300// See the License for the specific language governing permissions and
1301// limitations under the License.
1302// ----------------------------- END-OF-FILE ----------------------------------
1303
1304/** @} */
1305/** @} */
1306/** @} */
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:751
void release()
Definition bdlcc_cache.h:770
~Cache_QueueProctor()
Definition bdlcc_cache.h:758
Definition bdlcc_cache.h:703
void lockRead()
Call the lockRead method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1252
~Cache_TestUtil()=default
Destroy this object.
void unlock()
Call the unlock method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1266
Cache_TestUtil(Cache< KEY, VALUE, HASH, EQUAL > &cache)
Definition bdlcc_cache.h:1243
void lockWrite()
Call the lockWrite method of bdlcc::Cache d_rwlock lock.
Definition bdlcc_cache.h:1259
Definition bdlcc_cache.h:444
bsl::size_t lowWatermark() const
Definition bdlcc_cache.h:1203
void clear()
Definition bdlcc_cache.h:934
void insert(bslmf::MovableRef< KEY > key, const ValuePtrType &valuePtr)
Definition bdlcc_cache.h:1051
HASH hashFunction() const
Definition bdlcc_cache.h:1189
int insertBulk(bslmf::MovableRef< bsl::vector< KVType > > data)
Definition bdlcc_cache.h:1088
void insert(const KEY &key, bslmf::MovableRef< VALUE > value)
Definition bdlcc_cache.h:995
bsl::size_t size() const
Return the current size of this cache.
Definition bdlcc_cache.h:1210
int tryGetValue(bsl::shared_ptr< VALUE > *value, const KEY &key, bool modifyEvictionQueue=true)
Definition bdlcc_cache.h:1132
int insertBulk(const bsl::vector< KVType > &data)
Definition bdlcc_cache.h:1082
void insert(const KEY &key, const VALUE &value)
Definition bdlcc_cache.h:984
void insert(const KEY &key, const ValuePtrType &valuePtr)
Definition bdlcc_cache.h:1039
Cache(bslma::Allocator *basicAllocator=0)
Definition bdlcc_cache.h:781
void visit(VISITOR &visitor) const
Definition bdlcc_cache.h:1218
int eraseBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end)
Definition bdlcc_cache.h:957
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:1023
Cache(CacheEvictionPolicy::Enum evictionPolicy, bsl::size_t lowWatermark, bsl::size_t highWatermark, bslma::Allocator *basicAllocator=0)
Definition bdlcc_cache.h:793
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:812
void insert(bslmf::MovableRef< KEY > key, const VALUE &value)
Definition bdlcc_cache.h:1010
~Cache()=default
Destroy this object.
CacheEvictionPolicy::Enum evictionPolicy() const
Return the eviction policy used by this cache.
Definition bdlcc_cache.h:1182
EQUAL equalFunction() const
Definition bdlcc_cache.h:1174
int eraseBulk(const bsl::vector< KEY > &keys)
Definition bdlcc_cache.h:977
int insertBulk(INPUT_ITERATOR begin, INPUT_ITERATOR end)
Definition bdlcc_cache.h:1064
void setPostEvictionCallback(const PostEvictionCallback &postEvictionCallback)
Definition bdlcc_cache.h:1124
int popFront()
Definition bdlcc_cache.h:1109
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:942
bsl::size_t highWatermark() const
Definition bdlcc_cache.h:1196
Definition bslstl_list.h:739
Forward declaration.
Definition bslstl_function.h:934
Forward declaration required by List_NodeProctor.
Definition bslstl_list.h:1033
Definition bslstl_pair.h:1210
Definition bslstl_sharedptr.h:1830
Definition bslstl_unorderedmap.h:1089
BloombergLP::bslstl::HashTableIterator< value_type, difference_type > iterator
Definition bslstl_unorderedmap.h:1158
BloombergLP::bslstl::HashTableIterator< const value_type, difference_type > const_iterator
Definition bslstl_unorderedmap.h:1160
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2511
iterator end() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2519
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslma_destructorguard.h:132
Definition bslmf_movableref.h:751
Definition bslmt_readlockguard.h:287
Definition bslmt_readerwritermutex.h:244
Definition bslmt_writelockguard.h:221
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_REVIEW(X)
Definition bsls_review.h:949
Definition bdlcc_boundedqueue.h:270
Definition bdlb_printmethods.h:283
Definition balxml_encoderoptions.h:68
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:311
Definition bslstl_hash.h:498
Definition bslma_usesbslmaallocator.h:343
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
Definition bsls_objectbuffer.h:276
TYPE * address()
Definition bsls_objectbuffer.h:334