}
void IOBufQueue::trimStart(size_t amount) {
+ auto trimmed = trimStartAtMost(amount);
+ if (trimmed != amount) {
+ throw std::underflow_error(
+ "Attempt to trim more bytes than are present in IOBufQueue");
+ }
+}
+
+size_t IOBufQueue::trimStartAtMost(size_t amount) {
+ auto original = amount;
while (amount > 0) {
if (!head_) {
- throw std::underflow_error(
- "Attempt to trim more bytes than are present in IOBufQueue");
+ break;
}
if (head_->length() > amount) {
head_->trimStart(amount);
chainLength_ -= amount;
+ amount = 0;
break;
}
amount -= head_->length();
chainLength_ -= head_->length();
head_ = head_->pop();
}
+ return original - amount;
}
void IOBufQueue::trimEnd(size_t amount) {
+ auto trimmed = trimEndAtMost(amount);
+ if (trimmed != amount) {
+ throw std::underflow_error(
+ "Attempt to trim more bytes than are present in IOBufQueue");
+ }
+}
+
+size_t IOBufQueue::trimEndAtMost(size_t amount) {
+ auto original = amount;
while (amount > 0) {
if (!head_) {
- throw std::underflow_error(
- "Attempt to trim more bytes than are present in IOBufQueue");
+ break;
}
if (head_->prev()->length() > amount) {
head_->prev()->trimEnd(amount);
chainLength_ -= amount;
+ amount = 0;
break;
}
amount -= head_->prev()->length();
head_.reset();
}
}
+ return original - amount;
}
std::unique_ptr<folly::IOBuf> IOBufQueue::pop_front() {
*/
void trimStart(size_t amount);
+ /**
+ * Similar to trimStart, but will trim at most amount bytes and returns
+ * the number of bytes trimmed.
+ */
+ size_t trimStartAtMost(size_t amount);
+
/**
* Similar to IOBuf::trimEnd, but works on the whole queue. Will
* pop off buffers that have been completely trimmed.
*/
void trimEnd(size_t amount);
+ /**
+ * Similar to trimEnd, but will trim at most amount bytes and returns
+ * the number of bytes trimmed.
+ */
+ size_t trimEndAtMost(size_t amount);
+
/**
* Transfer ownership of the queue's entire IOBuf chain to the caller.
*/
checkConsistency(queue);
}
+TEST(IOBufQueue, TrimStartAtMost) {
+ IOBufQueue queue(clOptions);
+ unique_ptr<IOBuf> a = IOBuf::create(4);
+ a->append(4);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(6);
+ a->append(6);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(8);
+ a->append(8);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(10);
+ a->append(10);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+
+ EXPECT_EQ(4, queue.front()->countChainElements());
+ EXPECT_EQ(28, queue.front()->computeChainDataLength());
+ EXPECT_EQ(4, queue.front()->length());
+
+ queue.trimStartAtMost(1);
+ checkConsistency(queue);
+ EXPECT_EQ(4, queue.front()->countChainElements());
+ EXPECT_EQ(27, queue.front()->computeChainDataLength());
+ EXPECT_EQ(3, queue.front()->length());
+
+ queue.trimStartAtMost(50);
+ checkConsistency(queue);
+ EXPECT_EQ(nullptr, queue.front());
+ EXPECT_EQ(0, queue.chainLength());
+}
+
+TEST(IOBufQueue, TrimEndAtMost) {
+ IOBufQueue queue(clOptions);
+ unique_ptr<IOBuf> a = IOBuf::create(4);
+ a->append(4);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(6);
+ a->append(6);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(8);
+ a->append(8);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+ a = IOBuf::create(10);
+ a->append(10);
+ queue.append(std::move(a));
+ checkConsistency(queue);
+
+ EXPECT_EQ(4, queue.front()->countChainElements());
+ EXPECT_EQ(28, queue.front()->computeChainDataLength());
+ EXPECT_EQ(4, queue.front()->length());
+
+ queue.trimEndAtMost(1);
+ checkConsistency(queue);
+ EXPECT_EQ(4, queue.front()->countChainElements());
+ EXPECT_EQ(27, queue.front()->computeChainDataLength());
+ EXPECT_EQ(4, queue.front()->length());
+
+ queue.trimEndAtMost(50);
+ checkConsistency(queue);
+ EXPECT_EQ(nullptr, queue.front());
+ EXPECT_EQ(0, queue.chainLength());
+}
+
TEST(IOBufQueue, TrimPack) {
IOBufQueue queue(clOptions);
unique_ptr<IOBuf> a = IOBuf::create(64);