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)