From d31340356428af861c12f9de87f298cbbd985843 Mon Sep 17 00:00:00 2001 From: kwiberg Date: Mon, 5 Sep 2016 07:46:20 -0700 Subject: [PATCH] rtc::Buffer: Let SetData and AppendData accept anything with .data() and .size() In addition to setting or appending from another Buffer, which was already possible, this allows for e.g. std::vector and rtc::ArrayView arguments. Review-Url: https://codereview.webrtc.org/2293983002 Cr-Commit-Position: refs/heads/master@{#14073} --- webrtc/base/BUILD.gn | 1 + webrtc/base/array_view.h | 34 ++----------- webrtc/base/array_view_unittest.cc | 35 -------------- webrtc/base/base.gyp | 1 + webrtc/base/buffer.h | 15 +++++- webrtc/base/buffer_unittest.cc | 27 +++++++++++ webrtc/base/type_traits.h | 77 ++++++++++++++++++++++++++++++ 7 files changed, 123 insertions(+), 67 deletions(-) create mode 100644 webrtc/base/type_traits.h diff --git a/webrtc/base/BUILD.gn b/webrtc/base/BUILD.gn index ac1b30b6af..a91b615c11 100644 --- a/webrtc/base/BUILD.gn +++ b/webrtc/base/BUILD.gn @@ -171,6 +171,7 @@ rtc_static_library("rtc_base_approved") { "timeutils.cc", "timeutils.h", "trace_event.h", + "type_traits.h", ] if (is_android) { diff --git a/webrtc/base/array_view.h b/webrtc/base/array_view.h index 725a2d79d6..59e0395199 100644 --- a/webrtc/base/array_view.h +++ b/webrtc/base/array_view.h @@ -11,37 +11,11 @@ #ifndef WEBRTC_BASE_ARRAY_VIEW_H_ #define WEBRTC_BASE_ARRAY_VIEW_H_ -#include - #include "webrtc/base/checks.h" +#include "webrtc/base/type_traits.h" namespace rtc { -namespace internal { - -// (Internal; please don't use outside this file.) Determines if the given -// class has zero-argument .data() and .size() methods whose return values are -// convertible to T* and size_t, respectively. -template -class HasDataAndSize { - private: - template < - typename C, - typename std::enable_if< - std::is_convertible().data()), T*>::value && - std::is_convertible().size()), - size_t>::value>::type* = nullptr> - static int Test(int); - - template - static char Test(...); - - public: - static constexpr bool value = std::is_same(0)), int>::value; -}; - -} // namespace internal - // Many functions read from or write to arrays. The obvious way to do this is // to use two arguments, a pointer to the first element and an element count: // @@ -122,9 +96,9 @@ class ArrayView final { // or ArrayView, const std::vector to ArrayView, and // rtc::Buffer to ArrayView (with the same const behavior as // std::vector). - template ::value>::type* = nullptr> + template < + typename U, + typename std::enable_if::value>::type* = nullptr> ArrayView(U& u) : ArrayView(u.data(), u.size()) {} // Indexing, size, and iteration. These allow mutation even if the ArrayView diff --git a/webrtc/base/array_view_unittest.cc b/webrtc/base/array_view_unittest.cc index 9d5e1afc60..91facb0043 100644 --- a/webrtc/base/array_view_unittest.cc +++ b/webrtc/base/array_view_unittest.cc @@ -21,41 +21,6 @@ namespace rtc { namespace { -namespace test_has_data_and_size { - -template -using DS = internal::HasDataAndSize; - -template -struct Test1 { - DR data(); - SR size(); -}; -static_assert(DS, int>::value, ""); -static_assert(DS, const int>::value, ""); -static_assert(DS, const int>::value, ""); -static_assert(!DS, int>::value, ""); // Wrong const. -static_assert(!DS, int>::value, ""); // Wrong ptr type. - -struct Test2 { - int* data; - size_t size; -}; -static_assert(!DS::value, ""); // Because they aren't methods. - -struct Test3 { - int* data(); -}; -static_assert(!DS::value, ""); // Because .size() is missing. - -class Test4 { - int* data(); - size_t size(); -}; -static_assert(!DS::value, ""); // Because methods are private. - -} // namespace test_has_data_and_size - template void Call(ArrayView) {} diff --git a/webrtc/base/base.gyp b/webrtc/base/base.gyp index 5ff461d4ed..93f87b2957 100644 --- a/webrtc/base/base.gyp +++ b/webrtc/base/base.gyp @@ -103,6 +103,7 @@ 'timeutils.cc', 'timeutils.h', 'trace_event.h', + 'type_traits.h', ], 'conditions': [ ['os_posix==1', { diff --git a/webrtc/base/buffer.h b/webrtc/base/buffer.h index e9f7cfac10..6ae49f7a8f 100644 --- a/webrtc/base/buffer.h +++ b/webrtc/base/buffer.h @@ -19,6 +19,7 @@ #include "webrtc/base/array_view.h" #include "webrtc/base/checks.h" +#include "webrtc/base/type_traits.h" namespace rtc { @@ -197,7 +198,12 @@ class BufferT { SetData(array, N); } - void SetData(const BufferT& buf) { SetData(buf.data(), buf.size()); } + template ::value>::type* = nullptr> + void SetData(const W& w) { + SetData(w.data(), w.size()); + } // Replace the data in the buffer with at most |max_elements| of data, using // the function |setter|, which should have the following signature: @@ -239,7 +245,12 @@ class BufferT { AppendData(array, N); } - void AppendData(const BufferT& buf) { AppendData(buf.data(), buf.size()); } + template ::value>::type* = nullptr> + void AppendData(const W& w) { + AppendData(w.data(), w.size()); + } template @@ -74,6 +76,11 @@ TEST(BufferTest, TestSetData) { EXPECT_EQ(buf.capacity(), 7u * 3 / 2); EXPECT_FALSE(buf.empty()); EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); + Buffer buf2; + buf2.SetData(buf); + EXPECT_EQ(buf.size(), 9u); + EXPECT_EQ(buf.capacity(), 7u * 3 / 2); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 9)); } TEST(BufferTest, TestAppendData) { @@ -81,6 +88,26 @@ TEST(BufferTest, TestAppendData) { buf.AppendData(kTestData + 10, 2); const int8_t exp[] = {0x4, 0x5, 0x6, 0xa, 0xb}; EXPECT_EQ(buf, Buffer(exp)); + Buffer buf2; + buf2.AppendData(buf); + buf2.AppendData(rtc::ArrayView(buf)); + const int8_t exp2[] = {0x4, 0x5, 0x6, 0xa, 0xb, 0x4, 0x5, 0x6, 0xa, 0xb}; + EXPECT_EQ(buf2, Buffer(exp2)); +} + +TEST(BufferTest, TestSetAndAppendWithUnknownArg) { + struct TestDataContainer { + size_t size() const { return 3; } + const uint8_t* data() const { return kTestData; } + }; + Buffer buf; + buf.SetData(TestDataContainer()); + EXPECT_EQ(3u, buf.size()); + EXPECT_EQ(Buffer(kTestData, 3), buf); + buf.AppendData(TestDataContainer()); + EXPECT_EQ(6u, buf.size()); + EXPECT_EQ(0, memcmp(buf.data(), kTestData, 3)); + EXPECT_EQ(0, memcmp(buf.data() + 3, kTestData, 3)); } TEST(BufferTest, TestSetSizeSmaller) { diff --git a/webrtc/base/type_traits.h b/webrtc/base/type_traits.h new file mode 100644 index 0000000000..d6a6c37334 --- /dev/null +++ b/webrtc/base/type_traits.h @@ -0,0 +1,77 @@ +/* + * Copyright 2016 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_BASE_TYPE_TRAITS_H_ +#define WEBRTC_BASE_TYPE_TRAITS_H_ + +#include +#include + +namespace rtc { + +// Determines if the given class has zero-argument .data() and .size() methods +// whose return values are convertible to T* and size_t, respectively. +template +class HasDataAndSize { + private: + template < + typename C, + typename std::enable_if< + std::is_convertible().data()), T*>::value && + std::is_convertible().size()), + std::size_t>::value>::type* = nullptr> + static int Test(int); + + template + static char Test(...); + + public: + static constexpr bool value = std::is_same(0)), int>::value; +}; + +namespace test_has_data_and_size { + +template +struct Test1 { + DR data(); + SR size(); +}; +static_assert(HasDataAndSize, int>::value, ""); +static_assert(HasDataAndSize, const int>::value, ""); +static_assert(HasDataAndSize, const int>::value, ""); +static_assert(!HasDataAndSize, int>::value, + "implicit cast of const int* to int*"); +static_assert(!HasDataAndSize, int>::value, + "implicit cast of char* to int*"); + +struct Test2 { + int* data; + size_t size; +}; +static_assert(!HasDataAndSize::value, + ".data and .size aren't functions"); + +struct Test3 { + int* data(); +}; +static_assert(!HasDataAndSize::value, ".size() is missing"); + +class Test4 { + int* data(); + size_t size(); +}; +static_assert(!HasDataAndSize::value, + ".data() and .size() are private"); + +} // namespace test_has_data_and_size + +} // namespace rtc + +#endif // WEBRTC_BASE_TYPE_TRAITS_H_