Index: test/cctest/test-circular-queue.cc |
diff --git a/test/cctest/test-circular-queue.cc b/test/cctest/test-circular-queue.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..aa981b8137cbbce61a02e0735539bf9cd57dcd18 |
--- /dev/null |
+++ b/test/cctest/test-circular-queue.cc |
@@ -0,0 +1,127 @@ |
+// Copyright 2010 the V8 project authors. All rights reserved. |
+// |
+// Tests of circular queues. |
+ |
+#include "v8.h" |
+#include "circular-queue-inl.h" |
+#include "cctest.h" |
+ |
+namespace i = v8::internal; |
+ |
+using i::CircularQueue; |
+using i::SamplingCircularQueue; |
+ |
+ |
+TEST(SingleRecordCircularQueue) { |
+ typedef int Record; |
+ CircularQueue<Record> cq(sizeof(Record) * 2); |
+ CHECK(cq.IsEmpty()); |
+ cq.Enqueue(1); |
+ CHECK(!cq.IsEmpty()); |
+ Record rec = 0; |
+ cq.Dequeue(&rec); |
+ CHECK_EQ(1, rec); |
+ CHECK(cq.IsEmpty()); |
+} |
+ |
+ |
+TEST(MultipleRecordsCircularQueue) { |
+ typedef int Record; |
+ const int kQueueSize = 10; |
+ CircularQueue<Record> cq(sizeof(Record) * (kQueueSize + 1)); |
+ CHECK(cq.IsEmpty()); |
+ cq.Enqueue(1); |
+ CHECK(!cq.IsEmpty()); |
+ for (int i = 2; i <= 5; ++i) { |
+ cq.Enqueue(i); |
+ CHECK(!cq.IsEmpty()); |
+ } |
+ Record rec = 0; |
+ for (int i = 1; i <= 4; ++i) { |
+ CHECK(!cq.IsEmpty()); |
+ cq.Dequeue(&rec); |
+ CHECK_EQ(i, rec); |
+ } |
+ for (int i = 6; i <= 12; ++i) { |
+ cq.Enqueue(i); |
+ CHECK(!cq.IsEmpty()); |
+ } |
+ for (int i = 5; i <= 12; ++i) { |
+ CHECK(!cq.IsEmpty()); |
+ cq.Dequeue(&rec); |
+ CHECK_EQ(i, rec); |
+ } |
+ CHECK(cq.IsEmpty()); |
+} |
+ |
+ |
+TEST(SamplingCircularQueue) { |
+ typedef int Record; |
+ const int kRecordsPerChunk = 4; |
+ SamplingCircularQueue scq(sizeof(Record), |
+ kRecordsPerChunk * sizeof(Record), |
+ 3); |
+ scq.SetUpProducer(); |
+ scq.SetUpConsumer(); |
+ |
+ // Check that we are using non-reserved values. |
+ CHECK_NE(SamplingCircularQueue::kClear, 1); |
+ CHECK_NE(SamplingCircularQueue::kEnd, 1); |
+ // Fill up the first chunk. |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ for (int i = 1; i < 1 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.Enqueue()); |
+ CHECK_NE(NULL, rec); |
+ *rec = i; |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ } |
+ |
+ // Fill up the second chunk. Consumption must still be unavailable. |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ for (int i = 10; i < 10 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.Enqueue()); |
+ CHECK_NE(NULL, rec); |
+ *rec = i; |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ } |
+ |
+ Record* rec = reinterpret_cast<Record*>(scq.Enqueue()); |
+ CHECK_NE(NULL, rec); |
+ *rec = 20; |
+ // Now as we started filling up the third chunk, consumption |
+ // must become possible. |
+ CHECK_NE(NULL, scq.StartDequeue()); |
+ |
+ // Consume the first chunk. |
+ for (int i = 1; i < 1 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.StartDequeue()); |
+ CHECK_NE(NULL, rec); |
+ CHECK_EQ(i, *rec); |
+ CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ scq.FinishDequeue(); |
+ CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ } |
+ // Now consumption must not be possible, as consumer now polls |
+ // the first chunk for emptinness. |
+ CHECK_EQ(NULL, scq.StartDequeue()); |
+ |
+ scq.FlushResidualRecords(); |
+ // From now, consumer no more polls ahead of the current chunk, |
+ // so it's possible to consume the second chunk. |
+ CHECK_NE(NULL, scq.StartDequeue()); |
+ // Consume the second chunk |
+ for (int i = 10; i < 10 + kRecordsPerChunk; ++i) { |
+ Record* rec = reinterpret_cast<Record*>(scq.StartDequeue()); |
+ CHECK_NE(NULL, rec); |
+ CHECK_EQ(i, *rec); |
+ CHECK_EQ(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ scq.FinishDequeue(); |
+ CHECK_NE(rec, reinterpret_cast<Record*>(scq.StartDequeue())); |
+ } |
+ // Consumption must still be possible as the first cell of the |
+ // last chunk is not clean. |
+ CHECK_NE(NULL, scq.StartDequeue()); |
+ |
+ scq.TearDownConsumer(); |
+ scq.TearDownProducer(); |
+} |