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<uint8_t> 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}
diff --git a/webrtc/base/buffer.h b/webrtc/base/buffer.h
index 2340396..0ef1e3b 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 <algorithm>  // std::swap (pre-C++11)
 #include <cassert>
 #include <cstring>
 #include <memory>
-#include <utility>  // std::swap (C++11 and later)
+#include <utility>
 
+#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 @@
   template <typename T, typename internal::ByteType<T>::t = 0>
   Buffer(const T* data, size_t size)
       : Buffer(data, size, size) {}
+
   template <typename T, typename internal::ByteType<T>::t = 0>
   Buffer(const T* data, size_t size, size_t capacity)
       : Buffer(size, capacity) {
@@ -82,6 +84,7 @@
     assert(IsConsistent());
     return reinterpret_cast<T*>(data_.get());
   }
+
   template <typename T = uint8_t, typename internal::ByteType<T>::t = 0>
   T* data() {
     assert(IsConsistent());
@@ -92,6 +95,7 @@
     assert(IsConsistent());
     return size_;
   }
+
   size_t capacity() const {
     assert(IsConsistent());
     return capacity_;
@@ -102,6 +106,7 @@
       SetData(buf.data(), buf.size());
     return *this;
   }
+
   Buffer& operator=(Buffer&& buf) {
     assert(IsConsistent());
     assert(buf.IsConsistent());
@@ -119,21 +124,39 @@
 
   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 <typename T, typename internal::ByteType<T>::t = 0>
   void SetData(const T* data, size_t size) {
     assert(IsConsistent());
     size_ = 0;
     AppendData(data, size);
   }
+
   template <typename T, size_t N, typename internal::ByteType<T>::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<T> 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 <typename T = uint8_t, typename F,
+            typename internal::ByteType<T>::t = 0>
+  size_t SetData(size_t max_bytes, F&& setter) {
+    RTC_DCHECK(IsConsistent());
+    size_ = 0;
+    return AppendData<T>(max_bytes, std::forward<F>(setter));
+  }
+
+  // The AppendData functions adds data to the end of the buffer. They accept
+  // the same input types as the constructors.
   template <typename T, typename internal::ByteType<T>::t = 0>
   void AppendData(const T* data, size_t size) {
     assert(IsConsistent());
@@ -143,12 +166,37 @@
     size_ = new_size;
     assert(IsConsistent());
   }
+
   template <typename T, size_t N, typename internal::ByteType<T>::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<T> 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 <typename T = uint8_t, typename F,
+            typename internal::ByteType<T>::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<T>() + old_size;
+    size_t written_bytes =
+        setter(rtc::ArrayView<T>(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 @@
   // 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);