9#ifndef INCLUDED_BDLCC_BOUNDEDQUEUE
10#define INCLUDED_BDLCC_BOUNDEDQUEUE
244#include <bdlscm_version.h>
266#include <bsl_climits.h>
267#include <bsl_cstdint.h>
280template <
class TYPE,
class NODE>
364template <
class TYPE,
bool RECLAIMABLE>
371 bool d_isUnconstructedFlag;
386 void setIsUnconstructed(
bool isUnconstructedFlag);
391 bool isUnconstructed()
const;
402 void setIsUnconstructed(
bool );
407 bool isUnconstructed()
const;
429 static const unsigned int k_FINISHED_SHIFT = 32;
431 static const unsigned int k_MAXIMUM_CIRCULAR_DIFFERENCE =
432 static_cast<unsigned int>(1) << (
sizeof(
unsigned int) * CHAR_BIT - 1);
435 typedef unsigned int Uint;
437 typedef typename bsls::AtomicOperations::AtomicTypes::Uint AtomicUint;
438 typedef typename bsls::AtomicOperations::AtomicTypes::Uint64 AtomicUint64;
453 AtomicUint64 d_pushCount;
461 AtomicUint64 d_pushIndex;
471 AtomicUint64 d_popCount;
478 AtomicUint64 d_popIndex;
481 mutable AtomicUint d_emptyWaiterCount;
485 AtomicUint d_emptyCountSeen;
503 const Uint64 d_capacity;
513 BoundedQueue<TYPE> >;
521 static bool circularlyGreater(Uint lhs, Uint rhs);
528 static bool isQuiescentState(bsls::Types::Uint64 count);
541 static Uint64 markFinishedOperation(AtomicUint64 *count);
542 static Uint64 markFinishedOperation(AtomicUint64 *count, int num);
554 static void markReclaimed(AtomicUint64 *count);
565 static void markStartedOperation(AtomicUint64 *count);
566 static void markStartedOperation(AtomicUint64 *count, int num);
579 static Uint64 unmarkStartedOperation(AtomicUint64 *count);
586 void popComplete(Node *node);
591 void popFrontHelper(TYPE *value);
601 void pushExceptionComplete();
610 bool updateEmptyCountSeen(Uint emptyCount);
785template <
class TYPE,
class NODE>
794template <
class TYPE,
class NODE>
798 d_queue_p->popComplete(d_node_p);
820 d_queue_p->pushExceptionComplete();
840 bool isUnconstructedFlag)
842 d_isUnconstructedFlag = isUnconstructedFlag;
857 return d_isUnconstructedFlag;
876 return lhs > rhs ? (lhs - rhs) <= k_MAXIMUM_CIRCULAR_DIFFERENCE
877 : (rhs - lhs) > k_MAXIMUM_CIRCULAR_DIFFERENCE;
884 return (count >> k_FINISHED_SHIFT) == (count & k_STARTED_MASK);
892 return AtomicOp::addUint64NvAcqRel(count, k_FINISHED_INC);
901 return AtomicOp::addUint64NvAcqRel(count, num * k_FINISHED_INC);
906void BoundedQueue<TYPE>::markReclaimed(AtomicUint64 *count)
908 AtomicOp::addUint64AcqRel(count, k_STARTED_INC + k_FINISHED_INC);
913void BoundedQueue<TYPE>::markStartedOperation(AtomicUint64 *count)
915 AtomicOp::addUint64AcqRel(count, k_STARTED_INC);
920void BoundedQueue<TYPE>::markStartedOperation(AtomicUint64 *count,
int num)
922 AtomicOp::addUint64AcqRel(count, num * k_STARTED_INC);
930 return AtomicOp::addUint64NvAcqRel(count, k_STARTED_DEC);
936void BoundedQueue<TYPE>::popComplete(Node *node)
938 node->d_value.object().~TYPE();
940 Uint64 count = markFinishedOperation(&d_popCount);
941 if (isQuiescentState(count)) {
947 if (AtomicOp::testAndSwapUint64AcqRel(&d_popCount,
950 d_pushSemaphore.postWithRedundantSignal(
951 static_cast<int>(count & k_STARTED_MASK),
952 static_cast<int>(d_capacity),
955 Uint emptyCount = AtomicOp::getUintAcquire(&d_emptyWaiterCount);
957 if (isEmpty() && updateEmptyCountSeen(emptyCount)) {
961 d_emptyCondition.broadcast();
968void BoundedQueue<TYPE>::popFrontHelper(TYPE *value)
970 markStartedOperation(&d_popCount);
974 Uint64 index = (AtomicOp::addUint64NvAcqRel(&d_popIndex, 1) - 1)
976 Node *node = &d_element_p[index];
985 while (node->isUnconstructed()) {
986 markReclaimed(&d_popCount);
988 index = (AtomicOp::addUint64NvAcqRel(&d_popIndex, 1) - 1) % d_capacity;
989 node = &d_element_p[index];
992 BoundedQueue_PopCompleteGuard<BoundedQueue<TYPE>, Node> guard(
this, node);
994#if defined(BSLMF_MOVABLEREF_USES_RVALUE_REFERENCES)
997 *value = node->d_value.object();
1001template <
class TYPE>
1003void BoundedQueue<TYPE>::pushComplete()
1005 Uint64 count = markFinishedOperation(&d_pushCount);
1006 if (isQuiescentState(count)) {
1012 if (AtomicOp::testAndSwapUint64AcqRel(&d_pushCount,
1015 d_popSemaphore.postWithRedundantSignal(
1016 static_cast<int>(count & k_STARTED_MASK),
1017 static_cast<int>(d_capacity),
1023template <
class TYPE>
1025void BoundedQueue<TYPE>::pushExceptionComplete()
1027 Uint64 count = unmarkStartedOperation(&d_pushCount);
1029 int numToPost =
static_cast<int>(count & k_STARTED_MASK);
1031 if (0 != numToPost && isQuiescentState(count)) {
1037 if (AtomicOp::testAndSwapUint64AcqRel(&d_pushCount,
1040 d_popSemaphore.post(numToPost);
1045template <
class TYPE>
1047bool BoundedQueue<TYPE>::updateEmptyCountSeen(Uint emptyCount)
1049 Uint emptyCountSeen = AtomicOp::getUintAcquire(&d_emptyCountSeen);
1050 while (circularlyGreater(emptyCount, emptyCountSeen)) {
1051 const Uint origEmptyCountSeen = emptyCountSeen;
1053 emptyCountSeen = AtomicOp::testAndSwapUintAcqRel(&d_emptyCountSeen,
1057 if (origEmptyCountSeen == emptyCountSeen) {
1065template <
class TYPE>
1073, d_capacity(capacity > 2 ? capacity : 2)
1074, d_allocator_p(
bslma::Default::allocator(basicAllocator))
1084 d_element_p =
static_cast<Node *
>(
1085 d_allocator_p->
allocate(
static_cast<bsl::size_t
>(
1086 d_capacity *
sizeof(
Node))));
1088 for (bsl::size_t i = 0; i < d_capacity; ++i) {
1089 d_element_p[i].setIsUnconstructed(
false);
1092 d_pushSemaphore.
post(
static_cast<int>(d_capacity));
1095template <
class TYPE>
1100 d_allocator_p->deallocate(d_element_p);
1105template <
class TYPE>
1109 int rv = d_popSemaphore.wait();
1117 popFrontHelper(value);
1122template <
class TYPE>
1125 int rv = d_pushSemaphore.wait();
1133 markStartedOperation(&d_pushCount);
1137 Uint64 index = (AtomicOp::addUint64NvAcqRel(&d_pushIndex, 1) - 1)
1139 Node& node = d_element_p[index];
1141 node.setIsUnconstructed(
true);
1151 node.setIsUnconstructed(
false);
1158template <
class TYPE>
1161 int rv = d_pushSemaphore.wait();
1169 markStartedOperation(&d_pushCount);
1173 Uint64 index = (AtomicOp::addUint64NvAcqRel(&d_pushIndex, 1) - 1)
1175 Node& node = d_element_p[index];
1177 node.setIsUnconstructed(
true);
1181 TYPE& dummy = value;
1188 node.setIsUnconstructed(
false);
1195template <
class TYPE>
1198 int reclaim = d_popSemaphore.takeAll();
1202 int count = reclaim;
1210 markStartedOperation(&d_popCount, count);
1215 Uint64 index = AtomicOp::addUint64NvAcqRel(&d_popIndex, count)
1218 for (
int i = 0; i < count; ++i, ++index) {
1219 Node& node = d_element_p[index % d_capacity];
1221 if (!node.isUnconstructed()) {
1222 node.d_value.object().~TYPE();
1233 Uint64 popCount = markFinishedOperation(&d_popCount, count);
1235 if (isQuiescentState(popCount)) {
1240 if (AtomicOp::testAndSwapUint64AcqRel(&d_popCount,
1243 d_pushSemaphore.post(
static_cast<int>(
1244 popCount & k_STARTED_MASK));
1247 Uint emptyCount = AtomicOp::getUintAcquire(
1248 &d_emptyWaiterCount);
1250 if (isEmpty() && updateEmptyCountSeen(emptyCount)) {
1254 d_emptyCondition.broadcast();
1261template <
class TYPE>
1265 int rv = d_popSemaphore.tryWait();
1276 popFrontHelper(value);
1281template <
class TYPE>
1284 int rv = d_pushSemaphore.tryWait();
1295 markStartedOperation(&d_pushCount);
1299 Uint64 index = (AtomicOp::addUint64NvAcqRel(&d_pushIndex, 1) - 1)
1301 Node& node = d_element_p[index];
1303 node.setIsUnconstructed(
true);
1313 node.setIsUnconstructed(
false);
1320template <
class TYPE>
1323 int rv = d_pushSemaphore.tryWait();
1334 markStartedOperation(&d_pushCount);
1338 Uint64 index = (AtomicOp::addUint64NvAcqRel(&d_pushIndex, 1) - 1)
1340 Node& node = d_element_p[index];
1342 node.setIsUnconstructed(
true);
1346 TYPE& dummy = value;
1353 node.setIsUnconstructed(
false);
1362template <
class TYPE>
1366 d_popSemaphore.disable();
1371 d_emptyCondition.broadcast();
1374template <
class TYPE>
1378 d_pushSemaphore.disable();
1381template <
class TYPE>
1385 d_popSemaphore.enable();
1388template <
class TYPE>
1392 d_pushSemaphore.enable();
1396template <
class TYPE>
1400 return static_cast<bsl::size_t
>(d_capacity);
1403template <
class TYPE>
1407 return d_capacity ==
static_cast<Uint64
>(d_pushSemaphore.getValue());
1410template <
class TYPE>
1414 return 0 == d_pushSemaphore.getValue();
1417template <
class TYPE>
1421 return d_popSemaphore.isDisabled();
1424template <
class TYPE>
1428 return d_pushSemaphore.isDisabled();
1431template <
class TYPE>
1435 return d_popSemaphore.getValue();
1438template <
class TYPE>
1441 Uint emptyCount = AtomicOp::addUintNvAcqRel(&d_emptyWaiterCount, 1) - 1;
1443 int state = d_popSemaphore.getDisabledState();
1444 if (1 == (state & 1)) {
1458 bool empty = isEmpty()
1459 || circularlyGreater(AtomicOp::getUintAcquire(&d_emptyCountSeen),
1462 while (!empty && state == d_popSemaphore.getDisabledState()) {
1463 int rv = d_emptyCondition.wait(&d_emptyMutex);
1468 || circularlyGreater(AtomicOp::getUintAcquire(&d_emptyCountSeen),
1481template <
class TYPE>
1485 return d_allocator_p;
#define BSLMF_NESTED_TRAIT_DECLARATION(t_TYPE, t_TRAIT)
Definition bslmf_nestedtraitdeclaration.h:231
Definition bdlcc_boundedqueue.h:281
~BoundedQueue_PopCompleteGuard()
Definition bdlcc_boundedqueue.h:796
Definition bdlcc_boundedqueue.h:314
void release()
Definition bdlcc_boundedqueue.h:827
~BoundedQueue_PushExceptionCompleteProctor()
Definition bdlcc_boundedqueue.h:817
Definition bdlcc_boundedqueue.h:418
bsl::size_t capacity() const
Definition bdlcc_boundedqueue.h:1398
bool isPopFrontDisabled() const
Definition bdlcc_boundedqueue.h:1419
int pushBack(bslmf::MovableRef< TYPE > value)
Definition bdlcc_boundedqueue.h:1159
int waitUntilEmpty() const
Definition bdlcc_boundedqueue.h:1439
void enablePushBack()
Definition bdlcc_boundedqueue.h:1390
BoundedQueue(bsl::size_t capacity, bslma::Allocator *basicAllocator=0)
Definition bdlcc_boundedqueue.h:1066
void removeAll()
Definition bdlcc_boundedqueue.h:1196
void enablePopFront()
Definition bdlcc_boundedqueue.h:1383
int tryPopFront(TYPE *value)
Definition bdlcc_boundedqueue.h:1263
int popFront(TYPE *value)
Definition bdlcc_boundedqueue.h:1107
bool isEmpty() const
Definition bdlcc_boundedqueue.h:1405
void disablePopFront()
Definition bdlcc_boundedqueue.h:1364
int pushBack(const TYPE &value)
Definition bdlcc_boundedqueue.h:1123
bsl::size_t numElements() const
Definition bdlcc_boundedqueue.h:1433
bool isFull() const
Definition bdlcc_boundedqueue.h:1412
bool isPushBackDisabled() const
Definition bdlcc_boundedqueue.h:1426
~BoundedQueue()
Destroy this object.
Definition bdlcc_boundedqueue.h:1096
bslma::Allocator * allocator() const
Return the allocator used by this object to supply memory.
Definition bdlcc_boundedqueue.h:1483
int tryPushBack(const TYPE &value)
Definition bdlcc_boundedqueue.h:1282
void disablePushBack()
Definition bdlcc_boundedqueue.h:1376
TYPE value_type
Definition bdlcc_boundedqueue.h:622
int tryPushBack(bslmf::MovableRef< TYPE > value)
Definition bdlcc_boundedqueue.h:1321
Definition bslma_allocator.h:545
virtual void * allocate(size_type size)=0
Definition bslmf_movableref.h:752
Definition bslmt_condition.h:220
Definition bslmt_fastpostsemaphore.h:328
void post()
Atomically increment the count of this semaphore.
Definition bslmt_fastpostsemaphore.h:610
@ e_DISABLED
Definition bslmt_fastpostsemaphore.h:349
@ e_WOULD_BLOCK
Definition bslmt_fastpostsemaphore.h:354
Definition bslmt_lockguard.h:234
Definition bslmt_mutex.h:317
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlcc_boundedqueue.h:270
Definition baljsn_encoder_testtypes.h:76
bsls::ObjectBuffer< TYPE > d_value
Definition bdlcc_boundedqueue.h:397
bsls::ObjectBuffer< TYPE > d_value
Definition bdlcc_boundedqueue.h:375
Definition bdlcc_boundedqueue.h:365
static void moveConstruct(TARGET_TYPE *address, TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1660
static void copyConstruct(TARGET_TYPE *address, const TARGET_TYPE &original, bslma::Allocator *allocator)
Definition bslalg_scalarprimitives.h:1617
Definition bslmf_isbitwisecopyable.h:298
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
Definition bsls_atomicoperations.h:836
static void initUint64(AtomicTypes::Uint64 *atomicUint, Types::Uint64 initialValue=0)
Definition bsls_atomicoperations.h:2123
static void initUint(AtomicTypes::Uint *atomicUint, unsigned int initialValue=0)
Definition bsls_atomicoperations.h:1924
unsigned long long Uint64
Definition bsls_types.h:139
Definition bsls_objectbuffer.h:277