BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdlcc_objectpool.h
Go to the documentation of this file.
1/// @file bdlcc_objectpool.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlcc_objectpool.h -*-C++-*-
8#ifndef INCLUDED_BDLCC_OBJECTPOOL
9#define INCLUDED_BDLCC_OBJECTPOOL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlcc_objectpool bdlcc_objectpool
15/// @brief Provide a thread-safe object pool.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlcc
19/// @{
20/// @addtogroup bdlcc_objectpool
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlcc_objectpool-purpose"> Purpose</a>
25/// * <a href="#bdlcc_objectpool-classes"> Classes </a>
26/// * <a href="#bdlcc_objectpool-description"> Description </a>
27/// * <a href="#bdlcc_objectpool-thread-safety"> Thread Safety </a>
28/// * <a href="#bdlcc_objectpool-object-construction-and-destruction"> Object Construction and Destruction </a>
29/// * <a href="#bdlcc_objectpool-integrating-with-bslma-managedptr-and-bsl-shared_ptr"> Integrating with bslma::ManagedPtr and bsl::shared_ptr </a>
30/// * <a href="#bdlcc_objectpool-creator-and-resetter-template-contract"> Creator and Resetter Template Contract </a>
31/// * <a href="#bdlcc_objectpool-exception-safety"> Exception safety </a>
32/// * <a href="#bdlcc_objectpool-pool-replenishment-policy"> Pool replenishment policy </a>
33/// * <a href="#bdlcc_objectpool-usage"> Usage </a>
34/// * <a href="#bdlcc_objectpool-example-1-handling-database-queries"> Example 1: Handling Database Queries </a>
35/// * <a href="#bdlcc_objectpool-object-pool-creation-and-functor-argument"> Object Pool Creation and Functor Argument </a>
36/// * <a href="#bdlcc_objectpool-creating-an-object-pool-that-constructs-default-objects"> Creating an Object Pool that Constructs Default Objects </a>
37/// * <a href="#bdlcc_objectpool-creating-an-object-pool-that-constructs-non-default-objects"> Creating an Object Pool that Constructs Non-Default Objects </a>
38/// * <a href="#bdlcc_objectpool-modified-queryhandler"> Modified queryHandler </a>
39///
40/// # Purpose {#bdlcc_objectpool-purpose}
41/// Provide a thread-safe object pool.
42///
43/// # Classes {#bdlcc_objectpool-classes}
44///
45/// - bdlcc::ObjectPool: thread-safe container of managed objects
46/// - bdlcc::ObjectPoolFunctors: namespace for resetter/creator implementations
47///
48/// @see bdlcc_sharedobjectpool
49///
50/// # Description {#bdlcc_objectpool-description}
51/// This component provides a generic thread-safe pool of objects,
52/// `bdlcc::ObjectPool`, using the acquire-release idiom and a `struct` with
53/// useful functors for a pool of objects, `bdlcc::ObjectPoolFunctors`. An
54/// object pool provides two main methods: `getObject`, which returns an object
55/// from the pool, and `releaseObject`, which returns an object to the pool for
56/// further reuse (thus avoiding the overhead of object construction and
57/// destruction). A major requirement of using the object pool is that any call
58/// to `getObject` can be satisfied by any object in the pool.
59///
60/// ## Thread Safety {#bdlcc_objectpool-thread-safety}
61///
62///
63/// The `bdlcc::ObjectPool` class template is fully thread-safe (see
64/// {@ref bsldoc_glossary |Fully Thread-Safe}), assuming that the allocator is fully
65/// thread-safe. Each method is executed by the calling thread.
66///
67/// ## Object Construction and Destruction {#bdlcc_objectpool-object-construction-and-destruction}
68///
69///
70/// The object pool owns the memory required to store the pooled objects, and
71/// manages the construction, resetting, and destruction of objects. The user
72/// may supply functors to create objects and to reset them to a valid state for
73/// their return to the pool. Alternatively, this component supplies reasonable
74/// defaults. Upon destruction, the object pool deallocates all memory
75/// associated with the objects in the pool.
76///
77/// The object pool also implements the `bdlma::Factory` protocol for TYPE. Its
78/// `createObject` and `deleteObject` methods are provided *only* for this
79/// purpose and should not be invoked directly (they are just synonyms for
80/// `getObject` and `releaseObject`, respectively). The pool can thus be used
81/// anywhere a `bdlma::Factory` (or, therefore, a `bdlma::Deleter`) is expected.
82///
83/// ### Integrating with bslma::ManagedPtr and bsl::shared_ptr {#bdlcc_objectpool-integrating-with-bslma-managedptr-and-bsl-shared_ptr}
84///
85///
86/// A `bdlcc::ObjectPool` is designed to work with both managed and shared
87/// pointer types. Note however, that @ref bdlcc_sharedobjectpool is an
88/// object-pool specifically designed for use with shared pointers.
89///
90/// Because `bdlcc::ObjectPool` provides a `deleteObject` method, it can serve
91/// as a factory of both `bslma::ManagedPtr` and `bsl::shared_ptr` objects. For
92/// example, to create a managed pointer from an object pool of `bsl::string`
93/// objects:
94/// @code
95/// bdlcc::ObjectPool<bsl::string> pool;
96/// bslma::ManagedPtr<bsl::string> managedPtr(pool.getObject(), &pool);
97/// @endcode
98/// To create a shared pointer (using the same object pool):
99/// @code
100/// bslma::Allocator *allocator = bslma::Default::allocator();
101/// bsl::shared_ptr<bsl::string> sharedPtr(pool.getObject(), &pool, allocator);
102/// @endcode
103/// Note that an allocator is a *required* argument to the `bsl::shared_ptr`
104/// constructor used here, and the provided allocator is used to supply memory
105/// for the internal representation of the pointer, and not to allocate memory
106/// for the object itself.
107///
108/// ## Creator and Resetter Template Contract {#bdlcc_objectpool-creator-and-resetter-template-contract}
109///
110///
111/// `bdlcc::ObjectPool` is templated on two types `CREATOR` and `RESETTER` in
112/// addition to the underlying object `TYPE`. Objects of these types may be
113/// provided at construction. The namespace `bdlcc::ObjectPoolFunctors`
114/// provides several commonly used implementations. The creator will be invoked
115/// as: `void(*)(void*, bslma::Allocator*)`. The resetter will be invoked as:
116/// `void(*)(TYPE*)`. The creator functor is called to construct a new object
117/// of the parameterized `TYPE` when the pool must be expanded (and thus it
118/// typically invokes placement `new` and passes its allocator argument to the
119/// constructor of `TYPE`). The resetter functor is called before each object
120/// is returned to the pool, and is required to put the object into a state such
121/// that it is ready to be reused. The defaults for these types are as follows:
122/// @code
123/// CREATOR = bdlcc::ObjectPoolFunctors::DefaultCreator
124/// RESETTER = bdlcc::ObjectPoolFunctors::Nil
125/// @endcode
126/// `bdlcc::ObjectPoolFunctors::Nil` is a no-op; it is only suitable if the
127/// objects stored in the pool are *always* in a valid state to be reused.
128/// Otherwise another kind of `RESETTER` should be provided. In
129/// `bdlcc::ObjectPoolFunctors`, the classes `Clear`, `RemoveAll`, and `Reset`
130/// are all acceptable types for `RESETTER`. Since these functor types are
131/// fully inlined, it is generally most efficient to define `reset` (or `clear`
132/// or `removeAll`) in the underlying `TYPE` and allow the functor to call that
133/// method. The `CREATOR` functor defaults to an object that invokes the
134/// default constructor with placement new, passing the allocator argument if
135/// the type traits of the object indicate it uses an allocator (see
136/// @ref bslalg_typetraits ). If a custom creator functor or a custom `CREATOR`
137/// type is specified, it is the user's responsibility to ensure that it
138/// correctly passes its allocator argument to the constructor of `TYPE` if
139/// `TYPE` takes an allocator.
140///
141/// ## Exception safety {#bdlcc_objectpool-exception-safety}
142///
143///
144/// There are two potential sources of exceptions in this component: memory
145/// allocation and object construction. The object pool is exception-neutral
146/// with full guarantee of rollback for the following methods: if an exception
147/// is thrown in `getObject`, `reserveCapacity`, or `increaseCapacity`, then the
148/// pool is in a valid unmodified state (i.e., identical to its state prior to
149/// the call to `getObject`). No other method of `bdlcc::ObjectPool` can throw.
150///
151/// ## Pool replenishment policy {#bdlcc_objectpool-pool-replenishment-policy}
152///
153///
154/// The `growBy` parameter can be specified in the pool's constructor to
155/// instruct the pool how to increase its capacity each time the pool is
156/// depleted. If `growBy` is positive, the pool always replenishes itself with
157/// enough objects to satisfy at least `growBy` object requests before the next
158/// replenishment. If `growBy` is negative, the pool will increase its capacity
159/// geometrically until it exceeds the internal maximum (which is
160/// implementation-defined), and after that it will be replenished with constant
161/// number of objects. If `growBy` is not specified, it defaults to -1 (i.e.,
162/// geometric increase beginning at 1).
163///
164/// ## Usage {#bdlcc_objectpool-usage}
165///
166///
167/// This section illustrates intended use of this component.
168///
169/// ### Example 1: Handling Database Queries {#bdlcc_objectpool-example-1-handling-database-queries}
170///
171///
172/// In this example, we simulate a database server accepting queries from
173/// clients and executing each query in a separate thread. Client requests are
174/// simulated by function `getClientQuery` which returns a query to be executed.
175/// The class `Query` encapsulates a database query and `queryFactory` is an
176/// object of a query factory class `QueryFactory`.
177/// @code
178/// enum {
179/// k_CONNECTION_OPEN_TIME = 100, // (simulated) time to open a
180/// // connection (in microseconds)
181///
182/// k_CONNECTION_CLOSE_TIME = 8, // (simulated) time to close a
183/// // connection (in microseconds)
184///
185/// k_QUERY_EXECUTION_TIME = 4 // (simulated) time to execute a query
186/// // (in microseconds)
187/// };
188///
189/// /// This class simulates a database connection.
190/// class my_DatabaseConnection
191/// {
192/// public:
193/// my_DatabaseConnection()
194/// {
195/// bslmt::ThreadUtil::microSleep(k_CONNECTION_OPEN_TIME);
196/// }
197///
198/// ~my_DatabaseConnection()
199/// {
200/// bslmt::ThreadUtil::microSleep(k_CONNECTION_CLOSE_TIME);
201/// }
202///
203/// void executeQuery(Query *query)
204/// {
205/// bslmt::ThreadUtil::microSleep(k_QUERY_EXECUTION_TIME);
206/// (void)query;
207/// }
208/// };
209/// @endcode
210/// The server runs several threads which, on each iteration, obtain a new
211/// client request from the query factory, and process it, until the desired
212/// total number of requests is achieved.
213/// @code
214/// extern "C" void serverThread(bsls::AtomicInt *queries,
215/// int max,
216/// void (*queryHandler)(Query*))
217/// {
218/// while (++(*queries) <= max) {
219/// Query *query = queryFactory->createQuery();
220/// queryHandler(query);
221/// }
222/// }
223/// @endcode
224/// We first give an implementation that does not uses the object pool. Later
225/// we will give an implementation using an object pool to manage the database
226/// connections. We also keep track of total response time for each case. When
227/// object pool is *not* used, each thread, in order to execute a query, creates
228/// a *new* database connection, calls its `executeQuery` method to execute the
229/// query and finally closes the connection.
230/// @code
231/// /// Handle the specified `query` without using an objectpool.
232/// extern "C" void queryHandler1(Query *query)
233/// {
234/// bsls::Types::Int64 t1 = bsls::TimeUtil::getTimer();
235/// my_DatabaseConnection connection;
236/// connection.executeQuery(query);
237/// bsls::Types::Int64 t2 = bsls::TimeUtil::getTimer();
238///
239/// totalResponseTime1 += t2 - t1;
240///
241/// queryFactory->destroyQuery(query);
242///
243/// // `connection` is implicitly destroyed on function return.
244/// }
245/// @endcode
246/// The main thread starts and joins these threads:
247/// @code
248/// enum {
249/// k_NUM_THREADS = 8,
250/// k_NUM_QUERIES = 1000
251/// };
252///
253/// bsls::AtomicInt numQueries(0);
254/// bslmt::ThreadGroup tg;
255///
256/// tg.addThreads(bdlf::BindUtil::bind(&serverThread,
257/// &numQueries,
258/// static_cast<int>(k_NUM_QUERIES),
259/// &queryHandler1),
260/// k_NUM_THREADS);
261/// tg.joinAll();
262/// @endcode
263/// In above strategy, clients always incur the delay associated with opening
264/// and closing a database connection. Now we show an implementation that will
265/// use object pool to *pool* the database connections.
266///
267/// ### Object Pool Creation and Functor Argument {#bdlcc_objectpool-object-pool-creation-and-functor-argument}
268///
269///
270/// In order to create an object pool, we may specify, at construction time, a
271/// functor encapsulating object creation. The pool invokes this functor to
272/// create an object in a memory location supplied by the allocator specified at
273/// construction and owned by the pool. By default, the creator invokes the
274/// default constructor of the underlying type, passing the pool's allocator if
275/// the type uses the bslma::Allocator protocol to supply memory (as specified
276/// by the "Uses Bslma Allocator" trait, see @ref bslalg_typetraits ). If this
277/// behavior is not sufficient, we can supply our own functor for type creation.
278///
279/// ### Creating an Object Pool that Constructs Default Objects {#bdlcc_objectpool-creating-an-object-pool-that-constructs-default-objects}
280///
281///
282/// When the default constructor of our type is sufficient, whether or not that
283/// type uses `bslma::Allocator`, we can simply use the default behavior of
284/// `bdlcc::ObjectPool`:
285/// @code
286/// bdlcc::ObjectPool<my_DatabaseConnection> pool(-1);
287/// @endcode
288///
289/// ### Creating an Object Pool that Constructs Non-Default Objects {#bdlcc_objectpool-creating-an-object-pool-that-constructs-non-default-objects}
290///
291///
292/// In this example, if we decide that connection IDs must be supplied to
293/// objects allocated from the pool, we must define a function which invokes
294/// placement new appropriately. When using a custom creator functor, it is the
295/// responsibility of client code to pass the pool's allocator (supplied as the
296/// second argument to the functor) to the new object if it uses
297/// bslma::Allocator.
298/// @code
299/// void createConnection(void *arena, bslma::Allocator *alloc, int id)
300/// {
301/// new (arena) my_DatabaseConnection(id, alloc);
302/// }
303/// @endcode
304/// then...
305/// @code
306/// int myId = 100;
307/// bdlcc::ObjectPool<my_DatabaseConnection> pool(
308/// bdlf::BindUtil::bind(&createConnection,
309/// bdlf::PlaceHolders::_1,
310/// bdlf::PlaceHolders::_2,
311/// myId));
312/// @endcode
313/// Whichever creator we choose, the modified server looks like
314/// @code
315/// connectionPool = &pool;
316///
317/// for (int i = 0; i < k_NUM_QUERIES; ++i) {
318/// my_Query *query = getClientQuery();
319/// bslmt::ThreadUtil::create(&threads[i], queryHandler2, (void *)query);
320/// }
321/// for (int i = 0; i < k_NUM_QUERIES; ++i) {
322/// bslmt::ThreadUtil::join(threads[i]);
323/// }
324/// @endcode
325///
326/// ### Modified queryHandler {#bdlcc_objectpool-modified-queryhandler}
327///
328///
329/// Now each thread, instead of creating a new connection, gets a connection
330/// from the object pool. After using the connection, the client returns it
331/// back to the pool for further reuse. The modified `queryHandler` is
332/// following.
333/// @code
334/// bdlcc::ObjectPool<my_DatabaseConnection> *connectionPool;
335///
336/// /// Process the specified `query`.
337/// void queryHandler2(Query *query)
338/// {
339/// bsls::Types::Int64 t1 = bsls::TimeUtil::getTimer();
340/// my_DatabaseConnection *connection = connectionPool->getObject();
341/// connection->executeQuery(query);
342/// bsls::Types::Int64 t2 = bsls::TimeUtil::getTimer();
343///
344/// totalResponseTime2 += t2 - t1;
345///
346/// connectionPool->releaseObject(connection);
347/// queryFactory->destroyQuery(query);
348/// }
349/// @endcode
350/// The total response time for each strategy is:
351/// @code
352/// totalResponseTime1 = 199970775520
353/// totalResponseTime2 = 100354490480
354/// @endcode
355/// @}
356/** @} */
357/** @} */
358
359/** @addtogroup bdl
360 * @{
361 */
362/** @addtogroup bdlcc
363 * @{
364 */
365/** @addtogroup bdlcc_objectpool
366 * @{
367 */
368
369#include <bdlscm_version.h>
370
371#include <bdlma_factory.h>
373
375
376#include <bslma_allocator.h>
377#include <bslma_default.h>
380
382
383#include <bslmt_lockguard.h>
384#include <bslmt_mutex.h>
385#include <bslmt_threadutil.h>
386
388#include <bsls_assert.h>
389#include <bsls_atomic.h>
391#include <bsls_objectbuffer.h>
392#include <bsls_performancehint.h>
393#include <bsls_review.h>
394
395#include <bsl_climits.h>
396#include <bsl_functional.h>
397#include <bsl_memory.h>
398
399#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
400#include <bslalg_typetraits.h>
401#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
402
403
404namespace bdlcc {
405
406 // =========================
407 // struct ObjectPoolFunctors
408 // =========================
409
410/// This struct provides several functors that are suitable `RESETTER`
411/// parameter types for `ObjectPool`. It also provides a `typedef` that
412/// specifies the default `CREATOR` parameter type for `ObjectPool`.
413///
414/// See @ref bdlcc_objectpool
416
417 // PUBLIC TYPES
418
419 /// The default `CREATOR` parameter type for the `ObjectPool` class
420 /// template.
422
423 /// This fully-inlined class, suitable as the `RESETTER` parameter type
424 /// for `ObjectPool`, is a functor taking a pointer to the parameterized
425 /// `TYPE` argument, and can be invoked as: `void(*)(TYPE*)`. It does
426 /// nothing.
427 ///
428 /// See @ref bdlcc_objectpool
429 template <class TYPE>
430 class Nil {
431
432 public:
433 // Use compiler-generated constructors.
434
435 /// Inlined no-op function.
436 void operator()(TYPE *object) const;
437 };
438
439 /// This fully-inlined class, suitable as the `RESETTER` parameter type
440 /// for `ObjectPool`, is a functor taking a pointer to the parameterized
441 /// `TYPE` argument, and can be invoked as: `void(*)(TYPE*)`. It calls
442 /// `reset` upon the provided object.
443 ///
444 /// See @ref bdlcc_objectpool
445 template <class TYPE>
446 class Reset {
447
448 public:
449 // Use compiler-generated constructors.
450
451 /// Inlined call to `object->reset()`.
452 void operator()(TYPE *object) const;
453 };
454
455 /// This fully-inlined class, suitable as the `RESETTER` parameter type
456 /// for `ObjectPool`, is a functor taking a pointer to the parameterized
457 /// `TYPE` argument, and can be invoked as: `void(*)(TYPE*)`. It calls
458 /// `clear` upon the provided object.
459 ///
460 /// See @ref bdlcc_objectpool
461 template <class TYPE>
462 class Clear {
463
464 public:
465 // Use compiler-generated constructors.
466
467 /// Inlined call to `object->clear()`.
468 void operator()(TYPE *object) const;
469 };
470
471 /// This fully-inlined class, suitable as the `RESETTER` parameter type
472 /// for `ObjectPool`, is a functor taking a pointer to the parameterized
473 /// `TYPE` argument, and can be invoked as: `void(*)(TYPE*)`. It calls
474 /// `removeAll` upon the provided object.
475 ///
476 /// See @ref bdlcc_objectpool
477 template <class TYPE>
478 class RemoveAll {
479
480 public:
481 // Use compiler-generated constructors.
482
483 /// Inlined call to `object->removeAll()`.
484 void operator()(TYPE *object) const;
485 };
486
487};
488
489 // =================================
490 // class ObjectPool_CreatorConverter
491 // =================================
492
493/// The purpose of this private class is to avoid ambiguity between
494/// different template instantiations of `bsl::function` accepted by the
495/// constructors of `ObjectPool`. It should not be used directly.
496///
497/// This version of the converter ignores the parameterized `OTHERTYPE`. It
498/// requires a reference to an object of the parameterized `TYPE` in its
499/// constructor.
500///
501/// See @ref bdlcc_objectpool
502template <class TYPE, class OTHERTYPE>
504
505 // DATA
506 const TYPE& d_creator;
507
508 public:
509 // CREATORS
511
512 // ACCESSORS
513 const TYPE& creator() const;
514};
515
516/// The purpose of this private class is to avoid ambiguity between
517/// different template instantiations of bsl::function accepted by the
518/// constructors of `ObjectPool`. It should not be used directly.
519///
520/// This version of the converter is a full template specialization for the
521/// case that the default creator type is used with a unary creator. In
522/// this case, `creator` will return a binder (see @ref bdlf_bind ) that adapts
523/// the unary creator to a binary creator that discards the second argument.
524/// This usage is **DEPRECATED** and provided only for backward compatibility.
525template <>
527 bsl::function<void(void *)> > {
528
529 // DATA
530 const bsl::function<void(void *)>& d_creator;
531
532 public:
533 // CREATORS
535
536 // ACCESSORS
538};
539
540 // =============================
541 // class ObjectPool_GeneralProxy
542 // =============================
543
544/// This private class template provides a default constructor which simply
545/// invokes the default constructor of the parameterized `TYPE`.
546///
547/// See @ref bdlcc_objectpool
548template <class TYPE>
550
551 // DATA
553
554 private:
555 // NOT IMPLEMENTED
558
559 public:
560 // TRAITS
563
564 // CREATORS
565
566 /// Create a new proxy and a new object of the parameterized `TYPE`. If
567 /// `TYPE` declares the "Uses Allocator" trait, the specified
568 /// `basicAllocator` is supplied to its default constructor; otherwise
569 /// `basicAllocator` is ignored.
570 explicit
572
573 /// Create a new proxy and a new object constructed from the specified
574 /// `other` object. If `TYPE` declares the "Uses Allocator" trait, the
575 /// specified `basicAllocator` is supplied to its copy constructor;
576 /// otherwise `basicAllocator` is ignored.
577 ObjectPool_GeneralProxy(const TYPE& other,
578 bslma::Allocator *basicAllocator);
579
580 /// Destroy this proxy and the underlying object.
582
583 // MANIPULATORS
584
585 /// Return a reference to the modifiable object held by this proxy.
586 TYPE& object();
587};
588
589 // =============================
590 // class ObjectPool_DefaultProxy
591 // =============================
592
593// SPECIALIZATIONS
594
595/// This private class template provides a default constructor that creates
596/// a proxied `bsl::function` object that invokes the default constructor of
597/// the parameterized `TYPE` with placement `new`.
598///
599/// See @ref bdlcc_objectpool
600template <class TYPE>
602
603 // PRIVATE TYPES
605
606 // DATA
607 Creator d_object;
608
609 private:
610 // NOT IMPLEMENTED
613
614 private:
615 // PRIVATE CLASS METHODS
616
617 /// Invoke, with the specified `arena` and `allocator`,
618 /// `bslalg::ScalarPrimitives::defaultConstruct(arena, allocator)`.
619 /// This method is necessary to select the correct overload for TYPE.
620 static void defaultConstruct(void *arena, bslma::Allocator *allocator);
621
622 public:
623 // TRAITS
626
627 // CREATORS
628
629 /// Create a new proxy for a function object which invokes the default
630 /// constructor of TYPE. Use the specified `basicAllocator` to supply
631 /// memory.
632 explicit
634
635 /// Create a proxy for a newly created function object constructed from
636 /// the specified `rhs` creator. Use the specified `basicAllocator` to
637 /// supply memory.
639 bslma::Allocator *basicAllocator);
640
641 /// Destroy this proxy and the underlying object.
643
644 // MANIPULATORS
645
646 /// Return a reference to the modifiable function object held by this
647 /// proxy.
648 Creator& object();
649};
650
651 // ============================
652 // class ObjectPool_ProxyPicker
653 // ============================
654
655/// For a `CREATOR` type other than the specialization below, provide a
656/// metafunction that returns `ObjectPool_GeneralProxy<CREATOR>` as the
657/// creator proxy for all types.
658///
659/// See @ref bdlcc_objectpool
660///
661/// See @ref bdlcc_objectpool
662template <class CREATOR>
664 template <class TYPE>
668};
669
670/// For the ObjectPoolFunctors::DefaultCreator, provide a metafunction that
671/// returns `ObjectPool_DefaultProxy<TYPE>` as the creator proxy for type
672/// `TYPE`.
673template <>
675{
676 template <class TYPE>
677 struct Selector
678 {
680 };
681};
682 // ================
683 // class ObjectPool
684 // ================
685
686/// This class provides a thread-safe pool of reusable objects. It also
687/// implements the `bdlma::Factory` protocol: "creating" objects gets them
688/// from the pool and "deleting" objects returns them to the pool.
689///
690/// See @ref bdlcc_objectpool
691template <class TYPE,
693 class RESETTER = ObjectPoolFunctors::Nil<TYPE> >
694class ObjectPool : public bdlma::Factory<TYPE> {
695
696 // PRIVATE TYPES
698
699 /// This class stores a list pointer for linking the object nodes
700 /// together in the free objects list, in which case the reference count
701 /// is 0. The list pointer is set to 0 when the reference count is not
702 /// 0, although that is not necessary. A negative reference count
703 /// indicates a node which does not contain an initialized object (the
704 /// object was destroyed and the creator threw before node could be
705 /// released again).
706 union ObjectNode {
707
708 struct {
709 bsls::AtomicOperations::AtomicTypes::Pointer d_next_p;
710 bsls::AtomicOperations::AtomicTypes::Int d_refCount;
711 } d_inUse;
713 // padding provider for proper alignment
714 // of 'TYPE' objects
715 };
716
717 /// This class stores information about a block, which is organized as a
718 /// `BlockNode` followed by `d_numObjects` frames, each containing an
719 /// `ObjectNode` followed by a `TYPE`, all of it suitably aligned.
720 union BlockNode {
721
722 struct {
723 BlockNode *d_next_p;
724 int d_numObjects; // number of objects in this block
725 } d_inUse;
727 // padding provider for proper alignment
728 // of 'ObjectNode'
729 };
730
731 /// This class, private to ObjectPool, implements a proctor for objects
732 /// created and stored into a temporary list of object nodes as in the
733 /// `ObjectPool` type, used in the replenishing method called from
734 /// `getObject`, `reserveCapacity` and `increaseCapacity`, to ensure the
735 /// exception-neutrality with full rollback guarantees of the object
736 /// pool.
737 ///
738 /// See @ref bdlcc_objectpool
739 class AutoCleanup {
740
741 public:
742 // TYPES
744 ObjectNode;
746 BlockNode;
747
748 private:
749 // DATA
750 BlockNode *d_block_p; // held, not owned
751 ObjectNode *d_head_p; // held, not owned
752 bdlma::InfrequentDeleteBlockList *d_allocator_p; // held, not owned
753 int d_numNodes;
754
755 public:
756 // CREATORS
757
758 /// Create a proctor for the list of the optionally specified
759 /// `numNodes` number of nodes with the specified `head`, using the
760 /// `allocator` to deallocate the block starting at the specified
761 /// `block` at destruction after all the objects in the list have
762 /// been destroyed, unless the `release` method has been called.
763 AutoCleanup(BlockNode *block,
764 ObjectNode *head,
766 int numNodes = 0);
767
768 /// Destroy this object, using the `allocator` to deallocate the
769 /// block under management at destruction after all the objects
770 /// under management in the list have been destroyed, unless the
771 /// `release` method has been called.
772 ~AutoCleanup();
773
774 // MANIPULATORS
775
776 /// Increment the number of nodes under management. Nodes are added
777 /// sequentially in the list.
778 AutoCleanup& operator++();
779
780 /// Release the currently held list of nodes from management by this
781 /// proctor.
782 void release();
783 };
784
785 enum {
786 // A block containing 'N' objects is organized with a single
787 // 'BlockNode' followed by 'N' frames, each frame consisting of one
788 // 'ObjectNode' and a 'TYPE', all suitably aligned. The following
789 // constants describe the size of a frame in terms of its multiple of
790 // 'sizeof(ObjectNode)'. We choose 'sizeof(ObjectNode)' as the basic
791 // unit because it lets us do pointer arithmetic on 'ObjectNode *' more
792 // easily.
793
794 k_ROUNDED_NUM_OBJECTS = (sizeof(TYPE) + sizeof(ObjectNode) - 1) /
795 sizeof(ObjectNode),
796 // number of 'ObjectNode' needed to
797 // contain an object of 'TYPE' (rounded up
798 // to the next integer)
799
800 k_NUM_OBJECTS_PER_FRAME = 1 + k_ROUNDED_NUM_OBJECTS,
801 // number of 'ObjectNode' equivalent (in
802 // size) to a frame (object node followed
803 // by 'TYPE')
804
805 k_MAX_NUM_OBJECTS_PER_FRAME = (INT_MAX / sizeof(ObjectNode) - 1) /
806 k_NUM_OBJECTS_PER_FRAME
807 // 'N' must be less than this
808 // 'k_MAX_NUM_OBJECTS_PER_FRAME' so that
809 // the number of bytes in a block, which
810 // is '(1 + N * NUM_OBJECTS_PER_FRAME)'
811 // times 'sizeof(ObjectNode)', does not
812 // overflow
813 };
814
815 /// Default configuration parameters. Adjust these to tune up
816 /// performance of `ObjectPool`.
817 enum {
818 k_GROW_FACTOR = 2, // multiplicative factor to grow
819 // capacity
820
821 k_MAX_NUM_OBJECTS = -32 // minimum 'd_numReplenishObjects'
822 // value beyond which
823 // 'd_numReplenishObjects' becomes
824 // positive
825 };
826
827 // DATA
829 d_freeObjectsList; // list of free objects
830
831 typename ObjectPool_ProxyPicker<CREATOR>::template Selector<TYPE>::Proxy
832 d_objectCreator; // functor for object
833 // creation
834
836 d_objectResetter; // functor to reset object
837
838 int d_numReplenishObjects; // pool growth behavior
839 // option (see above)
840
841 bsls::AtomicInt d_numAvailableObjects; // number of available
842 // objects
843
844 bsls::AtomicInt d_numObjects; // number of objects created
845 // by this pool
846
847 BlockNode *d_blockList; // list of memory blocks
848
850 d_blockAllocator; // memory block supplier
851
852 bslma::Allocator *d_allocator_p; // held, not owned
853
854 bslmt::Mutex d_mutex; // pool replenishment
855 // serializer
856
857 private:
858 // NOT IMPLEMENTED
859 ObjectPool(const MyType&, bslma::Allocator * = 0);
860 ObjectPool& operator=(const MyType&);
861
862 // FRIENDS
863 friend class AutoCleanup;
864
865 private:
866 // PRIVATE MANIPULATORS
867
868 /// Add additional objects to this pool based on the replenishment
869 /// policy specified by the `growBy` argument at construction.
870 void replenish();
871
872 /// Create the specified `numObjects` objects and attach them to this
873 /// object pool.
874 void addObjects(int numObjects);
875
876 public:
877 // TYPES
878 typedef RESETTER ResetterType;
879 typedef CREATOR CreatorType;
880
881 // TRAITS
883
884 // CREATORS
885
886 /// Create an object pool that invokes the default constructor of the
887 /// the parameterized `TYPE` to construct objects. When the pool is
888 /// depleted, it will increase its capacity according to the optionally
889 /// specified `growBy` value. If `growBy` is positive, the pool
890 /// replenishes itself with at least `growBy` new objects. If `growBy`
891 /// is negative, the amount of increase begins at `-growBy` and grows
892 /// geometrically up to an implementation-defined maximum. When objects
893 /// are returned to the pool, the default value of RESETTER is invoked
894 /// with a pointer to the returned object to restore the object to a
895 /// reusable state. Optionally specify a `basicAllocator` used to
896 /// supply memory. If `basicAllocator` is 0, the currently installed default allocator is used.
897 ///
898 /// \pre The behavior is undefined unless
899 /// `0 != growBy`.
900 explicit
901 ObjectPool(int growBy = -1,
902 bslma::Allocator *basicAllocator = 0);
903
904 /// Create an object pool that uses the specified `objectCreator`
905 /// (encapsulating the construction of objects) to create objects. The
906 /// client must ensure that `objectCreator(buf, alloc)` creates an
907 /// object at memory location `buf` using `alloc` to supply memory.
908 /// When the pool is depleted, it will grow capacity according to the
909 /// optionally specified `growBy` value. If `growBy` is positive, the
910 /// pool replenishes itself with at least `growBy` new objects. If
911 /// `growBy` is negative, the amount of increase begins at `-growBy` and
912 /// grows geometrically up to an implementation-defined maximum. When
913 /// objects are returned to the pool, the default value of RESETTER is
914 /// invoked with a pointer to the returned object to restore the object
915 /// to a reusable state. Optionally specify a `basicAllocator` used to
916 /// supply memory. If `basicAllocator` is 0, the currently installed default allocator is used.
917 ///
918 /// \pre The behavior is undefined unless
919 /// `0 != growBy`.
920 explicit
921 ObjectPool(const CREATOR& objectCreator,
922 int growBy,
923 bslma::Allocator *basicAllocator = 0);
924 explicit
925 ObjectPool(const CREATOR& objectCreator,
926 bslma::Allocator *basicAllocator = 0);
927
928 /// Create an object pool that uses the specified `objectCreator`
929 /// (encapsulating the construction of objects) to create objects. The
930 /// client must ensure that `objectCreator(buf, alloc)` creates an
931 /// object at memory location `buf` using `alloc` to supply memory.
932 /// When the pool is depleted, it will increase its capacity according
933 /// to the optionally specified `growBy` value. If `growBy` is
934 /// positive, the pool replenishes itself with at least `growBy` new
935 /// objects. If `growBy` is negative, the amount of increase begins at
936 /// `-growBy` and grows geometrically up to an implementation-defined
937 /// maximum. When objects are returned to the pool, the specified
938 /// `objectResetter` is invoked with a pointer to the returned object to
939 /// restore the object to a reusable state. Optionally specify a
940 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
941 /// the currently installed default allocator is used.
942 ///
943 /// \pre The behavior is undefined unless `0 != growBy`.
944 ObjectPool(const CREATOR& objectCreator,
945 const RESETTER& objectResetter,
946 int growBy = -1,
947 bslma::Allocator *basicAllocator = 0);
948
949 /// @deprecated Use a creator of the parameterized `CREATOR` type.
950 template <class ANYPROTO>
951 explicit
953 int growBy,
954 bslma::Allocator *basicAllocator = 0);
955 template <class ANYPROTO>
956 explicit
958 bslma::Allocator *basicAllocator = 0);
959
960 /// Destroy this object pool. All objects created by this pool are
961 /// destroyed (even if some of them are still in use) and memory is
962 /// reclaimed.
963 virtual ~ObjectPool();
964
965 // MANIPULATORS
966
967 /// Return an address of modifiable object from this object pool. If
968 /// this pool is empty, it is replenished according to the strategy
969 /// specified at the pool construction (or an implementation-defined
970 /// strategy if none was provided).
971 TYPE *getObject();
972
973 /// Create the specified `numObjects` objects and add them to this object pool.
974 ///
975 /// \pre The behavior is undefined unless `0 <= numObjects`.
977
978 /// Return the specified `object` back to this object pool. Invoke the
979 /// RESETTER specified at construction, or the default RESETTER if none
980 /// was provided, before making the object available for reuse.
981 ///
982 /// \note Note that if RESETTER is the default type (`ObjectPoolFunctors::Nil`),
983 /// then this method should be invoked to return only *valid* objects
984 /// because the pool uses the released objects to satisfy further `getObject` requests.
985 ///
986 /// \pre The behavior is undefined unless the `object`
987 /// was obtained from this object pool's `getObject` method and is not
988 /// already in a released state.
989 void releaseObject(TYPE *object);
990
991 /// Create enough objects to satisfy requests for at least the specified
992 /// `numObjects` objects before the next replenishment.
993 ///
994 /// \pre The behavior is undefined unless `0 <= numObjects`.
995 /// \note Note that this method is
996 /// different from `increaseCapacity` in that the number of created
997 /// objects may be less than `numObjects`.
999
1000 // ACCESSORS
1001
1002 /// Return a *snapshot* of the number of objects available in this pool.
1004
1005 /// Return the (instantaneous) number of objects managed by this pool.
1006 /// This includes both the objects available in the pool and the objects
1007 /// that were allocated from the pool and not yet released.
1008 int numObjects() const;
1009
1010 // 'bdlma::Factory' INTERFACE
1011
1012 /// This concrete implementation of `bdlma::Factory::createObject`
1013 /// invokes `getObject`. This should not be invoked directly.
1014 virtual TYPE *createObject();
1015
1016 /// This concrete implementation of `bdlma::Factory::deleteObject`
1017 /// invokes `releaseObject` on the specified `object`, returning it to this pool.
1018 ///
1019 /// \pre The behavior is undefined if `object` is already in a released state.
1020 ///
1021 /// \note Note that this does *not* destroy the object and
1022 /// should not be invoked directly.
1023 virtual void deleteObject(TYPE *object);
1024};
1025
1026// ============================================================================
1027// INLINE DEFINITIONS
1028// ============================================================================
1029
1030 // ----------
1031 // ObjectPool
1032 // ----------
1033
1034// PRIVATE MANIPULATORS
1035template <class TYPE, class CREATOR, class RESETTER>
1037{
1038 int numObjects = d_numReplenishObjects >= 0
1039 ? d_numReplenishObjects
1040 : -d_numReplenishObjects;
1041 addObjects(numObjects);
1042
1043 // Grow pool capacity only if 'd_numReplenishObjects' is negative and
1044 // greater than 'k_MAX_NUM_OBJECTS' (i.e., if the absolute value of
1045 // 'numObjects' is less than 'k_MAX_NUM_OBJECTS').
1046
1047 if (d_numReplenishObjects < 0) {
1048 if (d_numReplenishObjects > k_MAX_NUM_OBJECTS) {
1049 d_numReplenishObjects *= k_GROW_FACTOR;
1050 }
1051 else {
1052 d_numReplenishObjects = -d_numReplenishObjects;
1053 }
1054 }
1055}
1056
1057template <class TYPE, class CREATOR, class RESETTER>
1058void ObjectPool<TYPE, CREATOR, RESETTER>::addObjects(int numObjects)
1059{
1060 // Allocate a single memory block to be used for creating block nodes,
1061 // object nodes, and objects. Too large a value for 'numObjects' would
1062 // cause overflow in 'NUM_BYTES_PER_BLOCK' below.
1063
1064 BSLS_ASSERT(numObjects <= k_MAX_NUM_OBJECTS_PER_FRAME);
1065
1066 const int NUM_BYTES_PER_BLOCK = (int)(sizeof(BlockNode) +
1067 sizeof(ObjectNode) * numObjects *
1068 k_NUM_OBJECTS_PER_FRAME);
1069
1070 BlockNode *start = (BlockNode *) d_blockAllocator.allocate(
1071 NUM_BYTES_PER_BLOCK);
1072
1073 // Create a block node
1074
1075 start->d_inUse.d_next_p = d_blockList;
1076 start->d_inUse.d_numObjects = numObjects;
1077
1078 // Create and link 'numObjects' objects
1079
1080 ObjectNode *last = (ObjectNode *)(start + 1);
1081 AutoCleanup startGuard(start, last, &d_blockAllocator, 0);
1082
1083 for (int i = 0; i < numObjects; ++i, ++startGuard) {
1084 bsls::AtomicOperations::initPointer(&last->d_inUse.d_next_p,
1085 last + k_NUM_OBJECTS_PER_FRAME);
1086 bsls::AtomicOperations::initInt(&last->d_inUse.d_refCount, 0);
1087 d_objectCreator.object()(last + 1, d_allocator_p);
1088 last += k_NUM_OBJECTS_PER_FRAME;
1089 }
1090 last -= k_NUM_OBJECTS_PER_FRAME;
1091 bsls::AtomicOperations::initInt(&last->d_inUse.d_refCount, 0);
1092
1093 // If all went well (no exceptions), attach it to 'd_blockList'
1094
1095 startGuard.release();
1096 d_blockList = start;
1097
1098 // Attach the created objects to 'd_freeObjectsList'
1099
1100 ++start;
1101 ObjectNode *old;
1102 do {
1103 old = d_freeObjectsList;
1104 bsls::AtomicOperations::setPtrRelaxed(&last->d_inUse.d_next_p, old);
1105 } while (old != d_freeObjectsList.testAndSwap(old, (ObjectNode *)start));
1106
1107 d_numObjects.addRelaxed(numObjects);
1108 d_numAvailableObjects.addRelaxed(numObjects);
1109}
1110
1111// CREATORS
1112template <class TYPE, class CREATOR, class RESETTER>
1114 int growBy,
1115 bslma::Allocator *basicAllocator)
1116: d_freeObjectsList(0)
1117, d_objectCreator(basicAllocator)
1118, d_objectResetter(basicAllocator)
1119, d_numReplenishObjects(growBy)
1120, d_blockList(0)
1121, d_blockAllocator(basicAllocator)
1122, d_allocator_p(bslma::Default::allocator(basicAllocator))
1123{
1124 BSLS_ASSERT(0 != d_numReplenishObjects);
1125}
1126
1127template <class TYPE, class CREATOR, class RESETTER>
1129 const CREATOR& objectCreator,
1130 int growBy,
1131 bslma::Allocator *basicAllocator)
1132: d_freeObjectsList(0)
1133, d_objectCreator(objectCreator, basicAllocator)
1134, d_objectResetter(basicAllocator)
1135, d_numReplenishObjects(growBy)
1136, d_blockList(0)
1137, d_blockAllocator(basicAllocator)
1138, d_allocator_p(bslma::Default::allocator(basicAllocator))
1139{
1140 BSLS_ASSERT(0 != d_numReplenishObjects);
1141}
1142
1143template <class TYPE, class CREATOR, class RESETTER>
1144inline
1146 const CREATOR& objectCreator,
1147 bslma::Allocator *basicAllocator)
1148: d_freeObjectsList(0)
1149, d_objectCreator(objectCreator, basicAllocator)
1150, d_objectResetter(basicAllocator)
1151, d_numReplenishObjects(-1)
1152, d_blockList(0)
1153, d_blockAllocator(basicAllocator)
1154, d_allocator_p(bslma::Default::allocator(basicAllocator))
1155{
1156 BSLS_ASSERT(0 != d_numReplenishObjects);
1157}
1158
1159template <class TYPE, class CREATOR, class RESETTER>
1160template <class ANYPROTO>
1162 const bsl::function<ANYPROTO>& objectCreator,
1163 bslma::Allocator *basicAllocator)
1164: d_freeObjectsList(0)
1165, d_objectCreator(
1166 ObjectPool_CreatorConverter<CREATOR, bsl::function<ANYPROTO> >(
1167 objectCreator).creator(),
1168 basicAllocator)
1169, d_objectResetter(basicAllocator)
1170, d_numReplenishObjects(-1)
1171, d_blockList(0)
1172, d_blockAllocator(basicAllocator)
1173, d_allocator_p(bslma::Default::allocator(basicAllocator))
1174{
1175 BSLS_ASSERT(0 != d_numReplenishObjects);
1176}
1177
1178template <class TYPE, class CREATOR, class RESETTER>
1179template <class ANYPROTO>
1181 const bsl::function<ANYPROTO>& objectCreator,
1182 int growBy,
1183 bslma::Allocator *basicAllocator)
1184: d_freeObjectsList(0)
1185, d_objectCreator(
1186 ObjectPool_CreatorConverter<CREATOR, bsl::function<ANYPROTO> >(
1187 objectCreator).creator(),
1188 basicAllocator)
1189, d_objectResetter(basicAllocator)
1190, d_numReplenishObjects(growBy)
1191, d_blockList(0)
1192, d_blockAllocator(basicAllocator)
1193, d_allocator_p(bslma::Default::allocator(basicAllocator))
1194{
1195 BSLS_ASSERT(0 != d_numReplenishObjects);
1196}
1197
1198template <class TYPE, class CREATOR, class RESETTER>
1200 const CREATOR& objectCreator,
1201 const RESETTER& objectResetter,
1202 int growBy,
1203 bslma::Allocator *basicAllocator)
1204: d_freeObjectsList(0)
1205, d_objectCreator(objectCreator, basicAllocator)
1206, d_objectResetter(objectResetter, basicAllocator)
1207, d_numReplenishObjects(growBy)
1208, d_blockList(0)
1209, d_blockAllocator(basicAllocator)
1210, d_allocator_p(bslma::Default::allocator(basicAllocator))
1211{
1212 BSLS_ASSERT(0 != d_numReplenishObjects);
1213}
1214
1215template <class TYPE, class CREATOR, class RESETTER>
1217{
1218 // Traverse the 'd_blockList', destroying all the objects associated with
1219 // each block, irrespective of whether their reference count is zero or
1220 // not.
1221
1222 for (; d_blockList; d_blockList = d_blockList->d_inUse.d_next_p) {
1223 int numObjects = d_blockList->d_inUse.d_numObjects;
1224 ObjectNode *p = (ObjectNode *)(d_blockList + 1);
1225 for (; numObjects != 0; --numObjects) {
1226 ((TYPE *)(p + 1))->~TYPE();
1227 p += k_NUM_OBJECTS_PER_FRAME;
1228 }
1229 }
1230}
1231
1232// MANIPULATORS
1233template <class TYPE, class CREATOR, class RESETTER>
1235{
1236 ObjectNode *p;
1237 do {
1238 p = d_freeObjectsList.loadAcquire();
1241
1242 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
1243 p = d_freeObjectsList;
1244 if (!p) {
1245 replenish();
1246 continue;
1247 }
1248 }
1250 2 != bsls::AtomicOperations::addIntNv(&p->d_inUse.d_refCount,2))) {
1252 for (int i = 0; i < 3; ++i) {
1253 // To avoid unnecessary contention, assume that if we did not
1254 // get the first reference, then the other thread is about to
1255 // complete the pop. Wait for a few cycles until it does. If
1256 // it does not complete then go on and try to acquire it
1257 // ourselves.
1258
1259 if (d_freeObjectsList != p) {
1260 break;
1261 }
1262 }
1263 }
1264
1265 // Force a dependent read of d_next_p to make sure that we're not
1266 // racing against a thread calling 'deallocate' for 'p' and that
1267 // checked the 'refCount' *before* we incremented it. Either we can
1268 // observe the new free list value (== p) and because of the release
1269 // barrier, we can observe the new 'd_next_p' value (this relies on a
1270 // dependent load) or 'loadRelaxed' will the "old" (!= p) and the
1271 // condition will fail. Note that 'h' is made volatile so that the
1272 // compiler does not replace the 'h->d_inUse' load with 'p->d_inUse'
1273 // (and thus removing the data dependency). TBD to be completely
1274 // thorough 'h->d_inUse.d_next_p' needs a load dependent barrier (no-op
1275 // on all current architectures though).
1276
1277 const ObjectNode *volatile h = d_freeObjectsList.loadRelaxed();
1278
1280 ObjectNode *next = static_cast<ObjectNode *>(
1281 bsls::AtomicOperations::getPtrRelaxed(&h->d_inUse.d_next_p));
1283 d_freeObjectsList.testAndSwap(p, next) == p)) {
1284 break;
1285 }
1286 }
1287
1289
1290 int refCount;
1291 for (;;) {
1292 refCount = bsls::AtomicOperations::getInt(&p->d_inUse.d_refCount);
1293
1294 if (refCount & 1) {
1295 // The node is now free but not on the free list. Try to take
1296 // it.
1297
1299 &p->d_inUse.d_refCount,
1300 refCount,
1301 refCount^1)) {
1302 // Taken!
1304 &p->d_inUse.d_next_p,
1305 0); // not strictly necessary
1306 d_numAvailableObjects.addRelaxed(-1);
1307 return (TYPE*)(p + 1); // RETURN
1308
1309 }
1310 }
1311 else if (refCount == bsls::AtomicOperations::testAndSwapInt(
1312 &p->d_inUse.d_refCount,
1313 refCount,
1314 refCount - 2)) {
1315 break;
1316 }
1317 }
1318 } while (1);
1319
1320 bsls::AtomicOperations::setPtrRelaxed(&p->d_inUse.d_next_p,
1321 0); // not strictly necessary
1322 d_numAvailableObjects.addRelaxed(-1);
1323 return (TYPE *)(p+1);
1324}
1325
1326template <class TYPE, class CREATOR, class RESETTER>
1328{
1329 if (numObjects > 0) {
1330 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
1331 addObjects(numObjects);
1332 }
1333}
1334
1335template <class TYPE, class CREATOR, class RESETTER>
1337{
1338 ObjectNode *current = (ObjectNode *)(void *)object - 1;
1339 d_objectResetter.object()(object);
1340
1342 &current->d_inUse.d_refCount);
1343 do {
1344 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(2 == refCount)) {
1346 &current->d_inUse.d_refCount,
1347 2,
1348 0);
1349 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(2 == refCount)) {
1350 break;
1351 }
1352 }
1353
1355
1356 const int oldRefCount = refCount;
1358 &current->d_inUse.d_refCount,
1359 refCount,
1360 refCount - 1);
1361 if (oldRefCount == refCount) {
1362 // Someone else is still trying to pop this item. Just let them
1363 // have it.
1364
1365 d_numAvailableObjects.addRelaxed(1);
1366 return; // RETURN
1367 }
1368
1369 } while (1);
1370
1371 ObjectNode *head = d_freeObjectsList.loadRelaxed();
1372 for (;;) {
1373 bsls::AtomicOperations::setPtrRelaxed(&current->d_inUse.d_next_p,
1374 head);
1375 ObjectNode * const oldHead = head;
1376 head = d_freeObjectsList.testAndSwap(head, current);
1377 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(oldHead == head)) {
1378 break;
1379 }
1381 }
1382 d_numAvailableObjects.addRelaxed(1);
1383}
1384
1385template <class TYPE, class CREATOR, class RESETTER>
1387{
1388 bslmt::LockGuard<bslmt::Mutex> guard(&d_mutex);
1389 numObjects -= d_numObjects;
1390 if (numObjects > 0) {
1391 addObjects(numObjects);
1392 }
1393}
1394
1395// ACCESSORS
1396template <class TYPE, class CREATOR, class RESETTER>
1397inline
1399{
1400 return d_numAvailableObjects;
1401}
1402
1403template <class TYPE, class CREATOR, class RESETTER>
1404inline
1406{
1407 return d_numObjects;
1408}
1409
1410template <class TYPE, class CREATOR, class RESETTER>
1411inline
1413{
1414 return getObject();
1415}
1416
1417template <class TYPE, class CREATOR, class RESETTER>
1418inline
1420{
1421 releaseObject(object);
1422}
1423
1424 // ---------------------------
1425 // ObjectPool_CreatorConverter
1426 // ---------------------------
1427
1428// CREATORS
1429template <class TYPE, class OTHERTYPE>
1430inline
1432ObjectPool_CreatorConverter(const TYPE& creator)
1433: d_creator(creator)
1434{
1435}
1436
1437template <class TYPE, class OTHERTYPE>
1438inline
1441{
1442 return d_creator;
1443}
1444
1445inline
1447 bsl::function<void(void *)> >::
1448ObjectPool_CreatorConverter(const bsl::function<void(void *)>& creator)
1449: d_creator(creator)
1450{
1451}
1452
1453 // -----------------------
1454 // ObjectPool_DefaultProxy
1455 // -----------------------
1456
1457// CLASS METHODS
1458template <class TYPE>
1459inline
1461::defaultConstruct(void *arena, bslma::Allocator *allocator)
1462{
1463 bslalg::ScalarPrimitives::defaultConstruct((TYPE *)arena, allocator);
1464}
1465
1466// CREATORS
1467template <class TYPE>
1468inline
1469ObjectPool_GeneralProxy<TYPE>
1470::ObjectPool_GeneralProxy(bslma::Allocator *basicAllocator)
1471{
1473 basicAllocator);
1474}
1475
1476template <class TYPE>
1477inline
1479::ObjectPool_GeneralProxy(const TYPE& other, bslma::Allocator *basicAllocator)
1480{
1481 bslalg::ScalarPrimitives::copyConstruct(&d_object.object(),
1482 other,
1483 basicAllocator);
1484}
1485
1486template <class TYPE>
1487inline
1490{
1491 bslma::DestructionUtil::destroy(&d_object.object());
1492}
1493
1494template <class TYPE>
1495inline
1498: d_object(bsl::allocator_arg_t(),
1499 bsl::allocator<Creator>(basicAllocator),
1500 &ObjectPool_DefaultProxy::defaultConstruct)
1501{
1502}
1503
1504template <class TYPE>
1505inline
1508 bslma::Allocator *basicAllocator)
1509: d_object(bsl::allocator_arg_t(),
1510 bsl::allocator<Creator>(basicAllocator),
1511 rhs)
1512{
1513}
1514
1515template <class TYPE>
1516inline
1521
1522// MANIPULATORS
1523template <class TYPE>
1524inline
1526{
1527 return d_object.object();
1528}
1529
1530template <class TYPE>
1531inline
1535{
1536 return d_object;
1537}
1538
1539 // -------------------------
1540 // ObjectPoolFunctors::Reset
1541 // -------------------------
1542
1543// ACCESSORS
1544template <class TYPE>
1545inline
1547{
1548 object->reset();
1549}
1550
1551 // -----------------------
1552 // ObjectPoolFunctors::Nil
1553 // -----------------------
1554
1555// ACCESSORS
1556template <class TYPE>
1557inline
1559{
1560}
1561
1562 // -------------------------
1563 // ObjectPoolFunctors::Clear
1564 // -------------------------
1565
1566// ACCESSORS
1567template <class TYPE>
1568inline
1570{
1571 object->clear();
1572}
1573
1574 // -----------------------------
1575 // ObjectPoolFunctors::RemoveAll
1576 // -----------------------------
1577
1578// ACCESSORS
1579template <class TYPE>
1580inline
1582{
1583 object->removeAll();
1584}
1585
1586 // ----------------------
1587 // ObjectPool_AutoCleanup
1588 // ----------------------
1589
1590// CREATORS
1591template <class TYPE, class CREATOR, class RESETTER>
1592inline
1594 BlockNode *block,
1595 ObjectNode *head,
1597 int numNodes)
1598: d_block_p(block)
1599, d_head_p(head)
1600, d_allocator_p(allocator)
1601, d_numNodes(numNodes)
1602{
1603}
1604
1605template <class TYPE, class CREATOR, class RESETTER>
1607{
1608 enum {
1609 k_NUM_OBJECTS_PER_FRAME =
1611 };
1612 if (d_head_p) {
1613 for (++d_head_p; d_numNodes > 0; --d_numNodes) {
1614 ((TYPE *)d_head_p)->~TYPE();
1615 d_head_p += k_NUM_OBJECTS_PER_FRAME;
1616 }
1617 d_allocator_p->deallocate(d_block_p);
1618 }
1619}
1620
1621// MANIPULATORS
1622template <class TYPE, class CREATOR, class RESETTER>
1623inline
1624typename ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup&
1625ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::operator++()
1626{
1627 ++d_numNodes;
1628 return *this;
1629}
1630
1631template <class TYPE, class CREATOR, class RESETTER>
1632inline
1633void ObjectPool<TYPE, CREATOR, RESETTER>::AutoCleanup::release()
1634{
1635 d_block_p = 0;
1636 d_head_p = 0;
1637}
1638
1639} // close package namespace
1640
1641
1642#endif
1643
1644// ----------------------------------------------------------------------------
1645// Copyright 2018 Bloomberg Finance L.P.
1646//
1647// Licensed under the Apache License, Version 2.0 (the "License");
1648// you may not use this file except in compliance with the License.
1649// You may obtain a copy of the License at
1650//
1651// http://www.apache.org/licenses/LICENSE-2.0
1652//
1653// Unless required by applicable law or agreed to in writing, software
1654// distributed under the License is distributed on an "AS IS" BASIS,
1655// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1656// See the License for the specific language governing permissions and
1657// limitations under the License.
1658// ----------------------------- END-OF-FILE ----------------------------------
1659
1660/** @} */
1661/** @} */
1662/** @} */
Definition bdlcc_objectpool.h:462
void operator()(TYPE *object) const
Inlined call to object->clear().
Definition bdlcc_objectpool.h:1569
Definition bdlcc_objectpool.h:430
void operator()(TYPE *object) const
Inlined no-op function.
Definition bdlcc_objectpool.h:1558
Definition bdlcc_objectpool.h:478
void operator()(TYPE *object) const
Inlined call to object->removeAll().
Definition bdlcc_objectpool.h:1581
Definition bdlcc_objectpool.h:446
void operator()(TYPE *object) const
Inlined call to object->reset().
Definition bdlcc_objectpool.h:1546
Definition bdlcc_objectpool.h:503
const TYPE & creator() const
Definition bdlcc_objectpool.h:1440
ObjectPool_CreatorConverter(const TYPE &creator)
Definition bdlcc_objectpool.h:1432
Definition bdlcc_objectpool.h:601
~ObjectPool_DefaultProxy()
Destroy this proxy and the underlying object.
Definition bdlcc_objectpool.h:1518
Creator & object()
Definition bdlcc_objectpool.h:1534
BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool_DefaultProxy, bslma::UsesBslmaAllocator)
Definition bdlcc_objectpool.h:549
TYPE & object()
Return a reference to the modifiable object held by this proxy.
Definition bdlcc_objectpool.h:1525
BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool_GeneralProxy, bslma::UsesBslmaAllocator)
~ObjectPool_GeneralProxy()
Destroy this proxy and the underlying object.
Definition bdlcc_objectpool.h:1489
Definition bdlcc_objectpool.h:694
ObjectPool(const CREATOR &objectCreator, int growBy, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1128
ObjectPool(const bsl::function< ANYPROTO > &objectCreator, int growBy, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1180
RESETTER ResetterType
Definition bdlcc_objectpool.h:878
friend class AutoCleanup
Definition bdlcc_objectpool.h:863
void reserveCapacity(int numObjects)
Definition bdlcc_objectpool.h:1386
void increaseCapacity(int numObjects)
Definition bdlcc_objectpool.h:1327
virtual void deleteObject(TYPE *object)
Definition bdlcc_objectpool.h:1419
ObjectPool(const CREATOR &objectCreator, const RESETTER &objectResetter, int growBy=-1, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1199
int numAvailableObjects() const
Return a snapshot of the number of objects available in this pool.
Definition bdlcc_objectpool.h:1398
void releaseObject(TYPE *object)
Definition bdlcc_objectpool.h:1336
virtual TYPE * createObject()
Definition bdlcc_objectpool.h:1412
virtual ~ObjectPool()
Definition bdlcc_objectpool.h:1216
int numObjects() const
Definition bdlcc_objectpool.h:1405
BSLMF_NESTED_TRAIT_DECLARATION(ObjectPool, bslma::UsesBslmaAllocator)
TYPE * getObject()
Definition bdlcc_objectpool.h:1234
ObjectPool(const CREATOR &objectCreator, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1145
ObjectPool(int growBy=-1, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1113
CREATOR CreatorType
Definition bdlcc_objectpool.h:879
ObjectPool(const bsl::function< ANYPROTO > &objectCreator, bslma::Allocator *basicAllocator=0)
Definition bdlcc_objectpool.h:1161
Definition bdlma_factory.h:118
Definition bdlma_infrequentdeleteblocklist.h:245
Forward declaration.
Definition bslstl_function.h:946
Definition bslalg_constructorproxy.h:376
Definition bslma_allocator.h:545
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:317
Definition bsls_atomic.h:744
Definition bsls_atomic.h:1362
#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_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_UNLIKELY_HINT
Definition bsls_performancehint.h:484
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdlcc_boundedqueue.h:270
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76
Definition bdlcc_objectpool.h:415
bsl::function< void(void *, bslma::Allocator *)> DefaultCreator
Definition bdlcc_objectpool.h:421
Definition bdlcc_objectpool.h:665
ObjectPool_GeneralProxy< CREATOR > Proxy
Definition bdlcc_objectpool.h:666
ObjectPool_DefaultProxy< TYPE > Proxy
Definition bdlcc_objectpool.h:679
Definition bdlcc_objectpool.h:663
static void defaultConstruct(TARGET_TYPE *address, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1577
static void copyConstruct(TARGET_TYPE *address, const TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1617
Definition bslma_usesbslmaallocator.h:344
AlignmentToType< VALUE >::Type Type
Definition bsls_alignmentfromtype.h:388
static void setPtrRelaxed(AtomicTypes::Pointer *atomicPtr, void *value)
Definition bsls_atomicoperations.h:2340
static void initPointer(AtomicTypes::Pointer *atomicPtr, void *initialValue=0)
Definition bsls_atomicoperations.h:2326
static int getIntRelaxed(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1536
static int getInt(AtomicTypes::Int const *atomicInt)
Definition bsls_atomicoperations.h:1524
static void initInt(AtomicTypes::Int *atomicInt, int initialValue=0)
Definition bsls_atomicoperations.h:1542
static int addIntNv(AtomicTypes::Int *atomicInt, int value)
Definition bsls_atomicoperations.h:1614
static int testAndSwapInt(AtomicTypes::Int *atomicInt, int compareValue, int swapValue)
Definition bsls_atomicoperations.h:1578
static void * getPtrRelaxed(AtomicTypes::Pointer const *atomicPtr)
Definition bsls_atomicoperations.h:2320
Definition bsls_objectbuffer.h:277