Mark scoped_refptr move and swap operations as noexcept
to align with chromium scoped_refptr implementation
and prefer move over copy in some cases.
Bug: webrtc:11078
Change-Id: I3178e74e611e4b23435668878e6bcc98bc2ce77d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/159541
Commit-Queue: Danil Chapovalov <danilchap@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29768}
diff --git a/api/scoped_refptr_unittest.cc b/api/scoped_refptr_unittest.cc
new file mode 100644
index 0000000..75a202b
--- /dev/null
+++ b/api/scoped_refptr_unittest.cc
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include "api/scoped_refptr.h"
+
+#include <utility>
+#include <vector>
+
+#include "test/gtest.h"
+
+namespace rtc {
+namespace {
+
+struct FunctionsCalled {
+ int addref = 0;
+ int release = 0;
+};
+
+class ScopedRefCounted {
+ public:
+ explicit ScopedRefCounted(FunctionsCalled* called) : called_(*called) {}
+ ScopedRefCounted(const ScopedRefCounted&) = delete;
+ ScopedRefCounted& operator=(const ScopedRefCounted&) = delete;
+
+ void AddRef() {
+ ++called_.addref;
+ ++ref_count_;
+ }
+ void Release() {
+ ++called_.release;
+ if (0 == --ref_count_)
+ delete this;
+ }
+
+ private:
+ ~ScopedRefCounted() = default;
+
+ FunctionsCalled& called_;
+ int ref_count_ = 0;
+};
+
+TEST(ScopedRefptrTest, IsCopyConstructable) {
+ FunctionsCalled called;
+ scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+ scoped_refptr<ScopedRefCounted> another_ptr = ptr;
+
+ EXPECT_TRUE(ptr);
+ EXPECT_TRUE(another_ptr);
+ EXPECT_EQ(called.addref, 2);
+}
+
+TEST(ScopedRefptrTest, IsCopyAssignable) {
+ FunctionsCalled called;
+ scoped_refptr<ScopedRefCounted> another_ptr;
+ scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+ another_ptr = ptr;
+
+ EXPECT_TRUE(ptr);
+ EXPECT_TRUE(another_ptr);
+ EXPECT_EQ(called.addref, 2);
+}
+
+TEST(ScopedRefptrTest, IsMoveConstructableWithoutExtraAddRefRelease) {
+ FunctionsCalled called;
+ scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+ scoped_refptr<ScopedRefCounted> another_ptr = std::move(ptr);
+
+ EXPECT_FALSE(ptr);
+ EXPECT_TRUE(another_ptr);
+ EXPECT_EQ(called.addref, 1);
+ EXPECT_EQ(called.release, 0);
+}
+
+TEST(ScopedRefptrTest, IsMoveAssignableWithoutExtraAddRefRelease) {
+ FunctionsCalled called;
+ scoped_refptr<ScopedRefCounted> another_ptr;
+ scoped_refptr<ScopedRefCounted> ptr = new ScopedRefCounted(&called);
+ another_ptr = std::move(ptr);
+
+ EXPECT_FALSE(ptr);
+ EXPECT_TRUE(another_ptr);
+ EXPECT_EQ(called.addref, 1);
+ EXPECT_EQ(called.release, 0);
+}
+
+TEST(ScopedRefptrTest, MovableDuringVectorReallocation) {
+ static_assert(
+ std::is_nothrow_move_constructible<scoped_refptr<ScopedRefCounted>>(),
+ "");
+ // Test below describes a scenario where it is helpful for move constructor
+ // to be noexcept.
+ FunctionsCalled called;
+ std::vector<scoped_refptr<ScopedRefCounted>> ptrs;
+ ptrs.reserve(1);
+ // Insert more elements than reserved to provoke reallocation.
+ ptrs.push_back(new ScopedRefCounted(&called));
+ ptrs.push_back(new ScopedRefCounted(&called));
+
+ EXPECT_EQ(called.addref, 2);
+ EXPECT_EQ(called.release, 0);
+}
+
+} // namespace
+} // namespace rtc