From b01c7816a8c4ef34102ead1a3eca4f389e7a8f43 Mon Sep 17 00:00:00 2001 From: ossu Date: Wed, 24 Feb 2016 01:05:56 -0800 Subject: [PATCH] Added functional variants of Buffer::SetData and Buffer::AppendData. They are invoked with the maximum size of the data to be added, and a callable that generates that data, like this: buffer.AppendData(10, [] (rtc::ArrayView av) { for (uint8_t i = 0; i != 5; ++i) av[i] = i; return 5; }); The callable returns the number of bytes actually written, and the final Buffer size will be adjusted accordingly. SetData and AppendData both return the number of bytes added (i.e. the return value of the callable). These versions will be useful when converting AudioEncoder::Encode to use Buffer rather than raw pointers. Also added a few tests for the new functionality. Review URL: https://codereview.webrtc.org/1717273002 Cr-Commit-Position: refs/heads/master@{#11733} --- webrtc/base/buffer.cc | 1 + webrtc/base/buffer.h | 59 ++++++++++++++++++++-- webrtc/base/buffer_unittest.cc | 90 ++++++++++++++++++++++++++++++++++ webrtc/base/bufferqueue.cc | 2 + 4 files changed, 147 insertions(+), 5 deletions(-) diff --git a/webrtc/base/buffer.cc b/webrtc/base/buffer.cc index 62855f1620..d0965a34bf 100644 --- a/webrtc/base/buffer.cc +++ b/webrtc/base/buffer.cc @@ -10,6 +10,7 @@ #include "webrtc/base/buffer.h" +#include #include #include diff --git a/webrtc/base/buffer.h b/webrtc/base/buffer.h index 234039607a..0ef1e3b5c8 100644 --- a/webrtc/base/buffer.h +++ b/webrtc/base/buffer.h @@ -11,12 +11,13 @@ #ifndef WEBRTC_BASE_BUFFER_H_ #define WEBRTC_BASE_BUFFER_H_ -#include // std::swap (pre-C++11) #include #include #include -#include // std::swap (C++11 and later) +#include +#include "webrtc/base/array_view.h" +#include "webrtc/base/checks.h" #include "webrtc/base/constructormagic.h" #include "webrtc/base/deprecation.h" @@ -62,6 +63,7 @@ class Buffer { template ::t = 0> Buffer(const T* data, size_t size) : Buffer(data, size, size) {} + template ::t = 0> Buffer(const T* data, size_t size, size_t capacity) : Buffer(size, capacity) { @@ -82,6 +84,7 @@ class Buffer { assert(IsConsistent()); return reinterpret_cast(data_.get()); } + template ::t = 0> T* data() { assert(IsConsistent()); @@ -92,6 +95,7 @@ class Buffer { assert(IsConsistent()); return size_; } + size_t capacity() const { assert(IsConsistent()); return capacity_; @@ -102,6 +106,7 @@ class Buffer { SetData(buf.data(), buf.size()); return *this; } + Buffer& operator=(Buffer&& buf) { assert(IsConsistent()); assert(buf.IsConsistent()); @@ -119,21 +124,39 @@ class Buffer { bool operator!=(const Buffer& buf) const { return !(*this == buf); } - // Replace the contents of the buffer. Accepts the same types as the - // constructors. + // The SetData functions replace the contents of the buffer. They accept the + // same input types as the constructors. template ::t = 0> void SetData(const T* data, size_t size) { assert(IsConsistent()); size_ = 0; AppendData(data, size); } + template ::t = 0> void SetData(const T(&array)[N]) { SetData(array, N); } + void SetData(const Buffer& buf) { SetData(buf.data(), buf.size()); } - // Append data to the buffer. Accepts the same types as the constructors. + // Replace the data in the buffer with at most |max_bytes| of data, using the + // function |setter|, which should have the following signature: + // size_t setter(ArrayView view) + // |setter| is given an appropriately typed ArrayView of the area in which to + // write the data (i.e. starting at the beginning of the buffer) and should + // return the number of bytes actually written. This number must be <= + // |max_bytes|. + template ::t = 0> + size_t SetData(size_t max_bytes, F&& setter) { + RTC_DCHECK(IsConsistent()); + size_ = 0; + return AppendData(max_bytes, std::forward(setter)); + } + + // The AppendData functions adds data to the end of the buffer. They accept + // the same input types as the constructors. template ::t = 0> void AppendData(const T* data, size_t size) { assert(IsConsistent()); @@ -143,12 +166,37 @@ class Buffer { size_ = new_size; assert(IsConsistent()); } + template ::t = 0> void AppendData(const T(&array)[N]) { AppendData(array, N); } + void AppendData(const Buffer& buf) { AppendData(buf.data(), buf.size()); } + // Append at most |max_bytes| of data to the end of the buffer, using the + // function |setter|, which should have the following signature: + // size_t setter(ArrayView view) + // |setter| is given an appropriately typed ArrayView of the area in which to + // write the data (i.e. starting at the former end of the buffer) and should + // return the number of bytes actually written. This number must be <= + // |max_bytes|. + template ::t = 0> + size_t AppendData(size_t max_bytes, F&& setter) { + RTC_DCHECK(IsConsistent()); + const size_t old_size = size_; + SetSize(old_size + max_bytes); + T *base_ptr = data() + old_size; + size_t written_bytes = + setter(rtc::ArrayView(base_ptr, max_bytes)); + + RTC_CHECK_LE(written_bytes, max_bytes); + size_ = old_size + written_bytes; + RTC_DCHECK(IsConsistent()); + return written_bytes; + } + // Sets the size of the buffer. If the new size is smaller than the old, the // buffer contents will be kept but truncated; if the new size is greater, // the existing contents will be kept and the new space will be @@ -175,6 +223,7 @@ class Buffer { // b.Pass() does the same thing as std::move(b). // Deprecated; remove in March 2016 (bug 5373). RTC_DEPRECATED Buffer&& Pass() { return DEPRECATED_Pass(); } + Buffer&& DEPRECATED_Pass() { assert(IsConsistent()); return std::move(*this); diff --git a/webrtc/base/buffer_unittest.cc b/webrtc/base/buffer_unittest.cc index f917bc6181..6e9e7bf7ba 100644 --- a/webrtc/base/buffer_unittest.cc +++ b/webrtc/base/buffer_unittest.cc @@ -189,4 +189,94 @@ TEST(BufferTest, TestClear) { EXPECT_EQ(buf.data(), data); // No reallocation. } +TEST(BufferTest, TestLambdaSetAppend) { + auto setter = [] (rtc::ArrayView av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + buf1.AppendData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.SetData(15, setter), 15u); + EXPECT_EQ(buf2.AppendData(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); +} + +TEST(BufferTest, TestLambdaSetAppendSigned) { + auto setter = [] (rtc::ArrayView av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + buf1.AppendData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.SetData(15, setter), 15u); + EXPECT_EQ(buf2.AppendData(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); +} + +TEST(BufferTest, TestLambdaAppendEmpty) { + auto setter = [] (rtc::ArrayView av) { + for (int i = 0; i != 15; ++i) + av[i] = kTestData[i]; + return 15; + }; + + Buffer buf1; + buf1.SetData(kTestData, 15); + + Buffer buf2; + EXPECT_EQ(buf2.AppendData(15, setter), 15u); + EXPECT_EQ(buf1, buf2); + EXPECT_EQ(buf1.capacity(), buf2.capacity()); +} + +TEST(BufferTest, TestLambdaAppendPartial) { + auto setter = [] (rtc::ArrayView av) { + for (int i = 0; i != 7; ++i) + av[i] = kTestData[i]; + return 7; + }; + + Buffer buf; + EXPECT_EQ(buf.AppendData(15, setter), 7u); + EXPECT_EQ(buf.size(), 7u); // Size is exactly what we wrote. + EXPECT_GE(buf.capacity(), 7u); // Capacity is valid. + EXPECT_NE(buf.data(), nullptr); // Data is actually stored. +} + +TEST(BufferTest, TestMutableLambdaSetAppend) { + uint8_t magic_number = 17; + auto setter = [magic_number] (rtc::ArrayView av) mutable { + for (int i = 0; i != 15; ++i) { + av[i] = magic_number; + ++magic_number; + } + return 15; + }; + + EXPECT_EQ(magic_number, 17); + + Buffer buf; + EXPECT_EQ(buf.SetData(15, setter), 15u); + EXPECT_EQ(buf.AppendData(15, setter), 15u); + EXPECT_EQ(buf.size(), 30u); // Size is exactly what we wrote. + EXPECT_GE(buf.capacity(), 30u); // Capacity is valid. + EXPECT_NE(buf.data(), nullptr); // Data is actually stored. + + for (uint8_t i = 0; i != buf.size(); ++i) { + EXPECT_EQ(buf.data()[i], magic_number + i); + } +} + } // namespace rtc diff --git a/webrtc/base/bufferqueue.cc b/webrtc/base/bufferqueue.cc index 1ac57abc0c..9c2324e768 100644 --- a/webrtc/base/bufferqueue.cc +++ b/webrtc/base/bufferqueue.cc @@ -10,6 +10,8 @@ #include "webrtc/base/bufferqueue.h" +#include + namespace rtc { BufferQueue::BufferQueue(size_t capacity, size_t default_size)