summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/memory
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/rtc_base/memory')
-rw-r--r--third_party/libwebrtc/rtc_base/memory/BUILD.gn61
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc98
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc.h57
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build225
-rw-r--r--third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc81
-rw-r--r--third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h248
-rw-r--r--third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc129
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc197
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer.h118
-rw-r--r--third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc249
10 files changed, 1463 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/memory/BUILD.gn b/third_party/libwebrtc/rtc_base/memory/BUILD.gn
new file mode 100644
index 0000000000..ee3baa40fb
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/BUILD.gn
@@ -0,0 +1,61 @@
+# Copyright (c) 2018 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.
+
+import("../../webrtc.gni")
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+
+rtc_library("aligned_malloc") {
+ sources = [
+ "aligned_malloc.cc",
+ "aligned_malloc.h",
+ ]
+ deps = [ "..:checks" ]
+}
+
+# Test only utility.
+rtc_library("fifo_buffer") {
+ testonly = true
+ visibility = [
+ ":unittests",
+ "..:rtc_base_tests_utils",
+ "..:rtc_base_unittests",
+ ]
+ sources = [
+ "fifo_buffer.cc",
+ "fifo_buffer.h",
+ ]
+ deps = [
+ "..:stream",
+ "..:threading",
+ "../../api/task_queue:pending_task_safety_flag",
+ "../synchronization:mutex",
+ ]
+}
+
+rtc_library("unittests") {
+ testonly = true
+ sources = [
+ "aligned_malloc_unittest.cc",
+ "always_valid_pointer_unittest.cc",
+ "fifo_buffer_unittest.cc",
+ ]
+ deps = [
+ ":aligned_malloc",
+ ":always_valid_pointer",
+ ":fifo_buffer",
+ "../../test:test_support",
+ ]
+}
+
+rtc_source_set("always_valid_pointer") {
+ sources = [ "always_valid_pointer.h" ]
+ deps = [ "..:checks" ]
+}
diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc
new file mode 100644
index 0000000000..7add079398
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2011 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 "rtc_base/memory/aligned_malloc.h"
+
+#include <stdlib.h> // for free, malloc
+#include <string.h> // for memcpy
+
+#include "rtc_base/checks.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+// Reference on memory alignment:
+// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
+namespace webrtc {
+
+uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
+ // The pointer should be aligned with `alignment` bytes. The - 1 guarantees
+ // that it is aligned towards the closest higher (right) address.
+ return (start_pos + alignment - 1) & ~(alignment - 1);
+}
+
+// Alignment must be an integer power of two.
+bool ValidAlignment(size_t alignment) {
+ if (!alignment) {
+ return false;
+ }
+ return (alignment & (alignment - 1)) == 0;
+}
+
+void* GetRightAlign(const void* pointer, size_t alignment) {
+ if (!pointer) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+ uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
+ return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
+}
+
+void* AlignedMalloc(size_t size, size_t alignment) {
+ if (size == 0) {
+ return NULL;
+ }
+ if (!ValidAlignment(alignment)) {
+ return NULL;
+ }
+
+ // The memory is aligned towards the lowest address that so only
+ // alignment - 1 bytes needs to be allocated.
+ // A pointer to the start of the memory must be stored so that it can be
+ // retreived for deletion, ergo the sizeof(uintptr_t).
+ void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
+ RTC_CHECK(memory_pointer) << "Couldn't allocate memory in AlignedMalloc";
+
+ // Aligning after the sizeof(uintptr_t) bytes will leave room for the header
+ // in the same memory block.
+ uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
+ align_start_pos += sizeof(uintptr_t);
+ uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
+ void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
+
+ // Store the address to the beginning of the memory just before the aligned
+ // memory.
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+ void* header_pointer = reinterpret_cast<void*>(header_pos);
+ uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
+ memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
+
+ return aligned_pointer;
+}
+
+void AlignedFree(void* mem_block) {
+ if (mem_block == NULL) {
+ return;
+ }
+ uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
+ uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
+
+ // Read out the address of the AlignedMemory struct from the header.
+ uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
+ void* memory_start = reinterpret_cast<void*>(memory_start_pos);
+ free(memory_start);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h
new file mode 100644
index 0000000000..1c7d303885
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2011 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 RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
+#define RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
+
+// The functions declared here
+// 1) Allocates block of aligned memory.
+// 2) Re-calculates a pointer such that it is aligned to a higher or equal
+// address.
+// Note: alignment must be a power of two. The alignment is in bytes.
+
+#include <stddef.h>
+
+namespace webrtc {
+
+// Returns a pointer to the first boundry of `alignment` bytes following the
+// address of `ptr`.
+// Note that there is no guarantee that the memory in question is available.
+// `ptr` has no requirements other than it can't be NULL.
+void* GetRightAlign(const void* ptr, size_t alignment);
+
+// Allocates memory of `size` bytes aligned on an `alignment` boundry.
+// The return value is a pointer to the memory. Note that the memory must
+// be de-allocated using AlignedFree.
+void* AlignedMalloc(size_t size, size_t alignment);
+// De-allocates memory created using the AlignedMalloc() API.
+void AlignedFree(void* mem_block);
+
+// Templated versions to facilitate usage of aligned malloc without casting
+// to and from void*.
+template <typename T>
+T* GetRightAlign(const T* ptr, size_t alignment) {
+ return reinterpret_cast<T*>(
+ GetRightAlign(reinterpret_cast<const void*>(ptr), alignment));
+}
+template <typename T>
+T* AlignedMalloc(size_t size, size_t alignment) {
+ return reinterpret_cast<T*>(AlignedMalloc(size, alignment));
+}
+
+// Deleter for use with unique_ptr. E.g., use as
+// std::unique_ptr<Foo, AlignedFreeDeleter> foo;
+struct AlignedFreeDeleter {
+ inline void operator()(void* ptr) const { AlignedFree(ptr); }
+};
+
+} // namespace webrtc
+
+#endif // RTC_BASE_MEMORY_ALIGNED_MALLOC_H_
diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build
new file mode 100644
index 0000000000..f5720480dd
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_gn/moz.build
@@ -0,0 +1,225 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/rtc_base/memory/aligned_malloc.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_ENABLE_LIBEVENT"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["RTC_ENABLE_WIN_WGC"] = True
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["TARGET_CPU"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["TARGET_CPU"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "arm":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["OS_TARGET"] == "Android" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "aarch64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "arm":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["OS_TARGET"] == "Linux" and CONFIG["TARGET_CPU"] == "x86_64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("aligned_malloc_gn")
diff --git a/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc
new file mode 100644
index 0000000000..8e750035f0
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/aligned_malloc_unittest.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2012 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 "rtc_base/memory/aligned_malloc.h"
+
+#include <memory>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <stdint.h>
+#endif
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+// Returns true if `size` and `alignment` are valid combinations.
+bool CorrectUsage(size_t size, size_t alignment) {
+ std::unique_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ if (scoped.get() == NULL) {
+ return false;
+ }
+ const uintptr_t scoped_address = reinterpret_cast<uintptr_t>(scoped.get());
+ return 0u == scoped_address % alignment;
+}
+
+TEST(AlignedMalloc, GetRightAlign) {
+ const size_t size = 100;
+ const size_t alignment = 32;
+ const size_t left_misalignment = 1;
+ std::unique_ptr<char, AlignedFreeDeleter> scoped(
+ static_cast<char*>(AlignedMalloc(size, alignment)));
+ EXPECT_TRUE(scoped.get() != NULL);
+ const uintptr_t aligned_address = reinterpret_cast<uintptr_t>(scoped.get());
+ const uintptr_t misaligned_address = aligned_address - left_misalignment;
+ const char* misaligned_ptr =
+ reinterpret_cast<const char*>(misaligned_address);
+ const char* realigned_ptr = GetRightAlign(misaligned_ptr, alignment);
+ EXPECT_EQ(scoped.get(), realigned_ptr);
+}
+
+TEST(AlignedMalloc, IncorrectSize) {
+ const size_t incorrect_size = 0;
+ const size_t alignment = 64;
+ EXPECT_FALSE(CorrectUsage(incorrect_size, alignment));
+}
+
+TEST(AlignedMalloc, IncorrectAlignment) {
+ const size_t size = 100;
+ const size_t incorrect_alignment = 63;
+ EXPECT_FALSE(CorrectUsage(size, incorrect_alignment));
+}
+
+TEST(AlignedMalloc, AlignTo2Bytes) {
+ size_t size = 100;
+ size_t alignment = 2;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo32Bytes) {
+ size_t size = 100;
+ size_t alignment = 32;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+TEST(AlignedMalloc, AlignTo128Bytes) {
+ size_t size = 100;
+ size_t alignment = 128;
+ EXPECT_TRUE(CorrectUsage(size, alignment));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h
new file mode 100644
index 0000000000..4e68104b55
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2022 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 RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_
+#define RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_
+
+#include <memory>
+#include <utility>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+// This template allows the instantiation of a pointer to Interface in such a
+// way that if it is passed a null pointer, an object of class Default will be
+// created, which will be deallocated when the pointer is deleted.
+template <typename Interface, typename Default = Interface>
+class AlwaysValidPointer {
+ public:
+ explicit AlwaysValidPointer(Interface* pointer)
+ : owned_instance_(pointer ? nullptr : std::make_unique<Default>()),
+ pointer_(pointer ? pointer : owned_instance_.get()) {
+ RTC_DCHECK(pointer_);
+ }
+
+ template <typename Arg,
+ typename std::enable_if<!(std::is_invocable<Arg>::value),
+ bool>::type = true>
+ AlwaysValidPointer(Interface* pointer, Arg arg)
+ : owned_instance_(pointer ? nullptr
+ : std::make_unique<Default>(std::move(arg))),
+ pointer_(pointer ? pointer : owned_instance_.get()) {
+ RTC_DCHECK(pointer_);
+ }
+
+ // Multiple arguments
+ template <typename Arg1, typename... Args>
+ AlwaysValidPointer(Interface* pointer, Arg1 arg1, Args... args)
+ : owned_instance_(pointer
+ ? nullptr
+ : std::make_unique<Default>(std::move(arg1),
+ std::move(args...))),
+ pointer_(pointer ? pointer : owned_instance_.get()) {
+ RTC_DCHECK(pointer_);
+ }
+
+ // Create a pointer by
+ // a) using |pointer|, without taking ownership
+ // b) calling |function| and taking ownership of the result
+ template <typename Func,
+ typename std::enable_if<std::is_invocable<Func>::value,
+ bool>::type = true>
+ AlwaysValidPointer(Interface* pointer, Func function)
+ : owned_instance_(pointer ? nullptr : function()),
+ pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
+ RTC_DCHECK(pointer_);
+ }
+
+ // Create a pointer by
+ // a) taking over ownership of |instance|
+ // b) or fallback to |pointer|, without taking ownership.
+ // c) or Default.
+ AlwaysValidPointer(std::unique_ptr<Interface>&& instance, Interface* pointer)
+ : owned_instance_(
+ instance
+ ? std::move(instance)
+ : (pointer == nullptr ? std::make_unique<Default>() : nullptr)),
+ pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
+ RTC_DCHECK(pointer_);
+ }
+
+ // Create a pointer by
+ // a) taking over ownership of |instance|
+ // b) or fallback to |pointer|, without taking ownership.
+ // c) or Default (with forwarded args).
+ template <typename... Args>
+ AlwaysValidPointer(std::unique_ptr<Interface>&& instance,
+ Interface* pointer,
+ Args... args)
+ : owned_instance_(
+ instance ? std::move(instance)
+ : (pointer == nullptr
+ ? std::make_unique<Default>(std::move(args...))
+ : nullptr)),
+ pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
+ RTC_DCHECK(pointer_);
+ }
+
+ Interface* get() { return pointer_; }
+ Interface* operator->() { return pointer_; }
+ Interface& operator*() { return *pointer_; }
+
+ Interface* get() const { return pointer_; }
+ Interface* operator->() const { return pointer_; }
+ Interface& operator*() const { return *pointer_; }
+
+ private:
+ const std::unique_ptr<Interface> owned_instance_;
+ Interface* const pointer_;
+};
+
+// This class is similar to AlwaysValidPointer, but it does not create
+// a default object and crashes if none of the input pointers are non-null.
+template <typename Interface>
+class AlwaysValidPointerNoDefault {
+ public:
+ explicit AlwaysValidPointerNoDefault(Interface* pointer) : pointer_(pointer) {
+ RTC_CHECK(pointer_);
+ }
+
+ // Create a pointer by
+ // a) taking over ownership of |instance|
+ // b) or fallback to |pointer|, without taking ownership.
+ // At least one of the arguments must be non-null.
+ explicit AlwaysValidPointerNoDefault(std::unique_ptr<Interface> instance,
+ Interface* pointer = nullptr)
+ : owned_instance_(std::move(instance)),
+ pointer_(owned_instance_ ? owned_instance_.get() : pointer) {
+ RTC_CHECK(pointer_);
+ }
+
+ Interface* get() { return pointer_; }
+ Interface* operator->() { return pointer_; }
+ Interface& operator*() { return *pointer_; }
+
+ Interface* get() const { return pointer_; }
+ Interface* operator->() const { return pointer_; }
+ Interface& operator*() const { return *pointer_; }
+
+ private:
+ const std::unique_ptr<Interface> owned_instance_;
+ Interface* const pointer_;
+};
+
+template <typename T, typename U, typename V, typename W>
+bool operator==(const AlwaysValidPointer<T, U>& a,
+ const AlwaysValidPointer<V, W>& b) {
+ return a.get() == b.get();
+}
+
+template <typename T, typename U, typename V, typename W>
+bool operator!=(const AlwaysValidPointer<T, U>& a,
+ const AlwaysValidPointer<V, W>& b) {
+ return !(a == b);
+}
+
+template <typename T, typename U>
+bool operator==(const AlwaysValidPointer<T, U>& a, std::nullptr_t) {
+ return a.get() == nullptr;
+}
+
+template <typename T, typename U>
+bool operator!=(const AlwaysValidPointer<T, U>& a, std::nullptr_t) {
+ return !(a == nullptr);
+}
+
+template <typename T, typename U>
+bool operator==(std::nullptr_t, const AlwaysValidPointer<T, U>& a) {
+ return a.get() == nullptr;
+}
+
+template <typename T, typename U>
+bool operator!=(std::nullptr_t, const AlwaysValidPointer<T, U>& a) {
+ return !(a == nullptr);
+}
+
+template <typename T, typename U>
+bool operator==(const AlwaysValidPointerNoDefault<T>& a,
+ const AlwaysValidPointerNoDefault<U>& b) {
+ return a.get() == b.get();
+}
+
+template <typename T, typename U>
+bool operator!=(const AlwaysValidPointerNoDefault<T>& a,
+ const AlwaysValidPointerNoDefault<U>& b) {
+ return !(a == b);
+}
+
+template <typename T>
+bool operator==(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) {
+ return a.get() == nullptr;
+}
+
+template <typename T>
+bool operator!=(const AlwaysValidPointerNoDefault<T>& a, std::nullptr_t) {
+ return !(a == nullptr);
+}
+
+template <typename T>
+bool operator==(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) {
+ return a.get() == nullptr;
+}
+
+template <typename T>
+bool operator!=(std::nullptr_t, const AlwaysValidPointerNoDefault<T>& a) {
+ return !(a == nullptr);
+}
+
+// Comparison with raw pointer.
+template <typename T, typename U, typename V>
+bool operator==(const AlwaysValidPointer<T, U>& a, const V* b) {
+ return a.get() == b;
+}
+
+template <typename T, typename U, typename V>
+bool operator!=(const AlwaysValidPointer<T, U>& a, const V* b) {
+ return !(a == b);
+}
+
+template <typename T, typename U, typename V>
+bool operator==(const T* a, const AlwaysValidPointer<U, V>& b) {
+ return a == b.get();
+}
+
+template <typename T, typename U, typename V>
+bool operator!=(const T* a, const AlwaysValidPointer<U, V>& b) {
+ return !(a == b);
+}
+
+template <typename T, typename U>
+bool operator==(const AlwaysValidPointerNoDefault<T>& a, const U* b) {
+ return a.get() == b;
+}
+
+template <typename T, typename U>
+bool operator!=(const AlwaysValidPointerNoDefault<T>& a, const U* b) {
+ return !(a == b);
+}
+
+template <typename T, typename U>
+bool operator==(const T* a, const AlwaysValidPointerNoDefault<U>& b) {
+ return a == b.get();
+}
+
+template <typename T, typename U>
+bool operator!=(const T* a, const AlwaysValidPointerNoDefault<U>& b) {
+ return !(a == b);
+}
+
+} // namespace webrtc
+
+#endif // RTC_BASE_MEMORY_ALWAYS_VALID_POINTER_H_
diff --git a/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc
new file mode 100644
index 0000000000..a228c102d0
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/always_valid_pointer_unittest.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2004 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 "rtc_base/memory/always_valid_pointer.h"
+
+#include <string>
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+TEST(AlwaysValidPointerTest, DefaultToEmptyValue) {
+ AlwaysValidPointer<std::string> ptr(nullptr);
+ EXPECT_EQ(*ptr, "");
+}
+TEST(AlwaysValidPointerTest, DefaultWithForwardedArgument) {
+ AlwaysValidPointer<std::string> ptr(nullptr, "test");
+ EXPECT_EQ(*ptr, "test");
+}
+TEST(AlwaysValidPointerTest, DefaultToSubclass) {
+ struct A {
+ virtual ~A() {}
+ virtual int f() = 0;
+ };
+ struct B : public A {
+ int b = 0;
+ explicit B(int val) : b(val) {}
+ virtual ~B() {}
+ int f() override { return b; }
+ };
+ AlwaysValidPointer<A, B> ptr(nullptr, 3);
+ EXPECT_EQ(ptr->f(), 3);
+ EXPECT_EQ((*ptr).f(), 3);
+ EXPECT_EQ(ptr.get()->f(), 3);
+}
+TEST(AlwaysValidPointerTest, NonDefaultValue) {
+ std::string str("keso");
+ AlwaysValidPointer<std::string> ptr(&str, "test");
+ EXPECT_EQ(*ptr, "keso");
+}
+
+TEST(AlwaysValidPointerTest, TakeOverOwnershipOfInstance) {
+ std::string str("keso");
+ std::unique_ptr<std::string> str2 = std::make_unique<std::string>("kent");
+ AlwaysValidPointer<std::string> ptr(std::move(str2), &str);
+ EXPECT_EQ(*ptr, "kent");
+ EXPECT_EQ(str2, nullptr);
+}
+
+TEST(AlwaysValidPointerTest, TakeOverOwnershipFallbackOnPointer) {
+ std::string str("keso");
+ std::unique_ptr<std::string> str2;
+ AlwaysValidPointer<std::string> ptr(std::move(str2), &str);
+ EXPECT_EQ(*ptr, "keso");
+}
+
+TEST(AlwaysValidPointerTest, TakeOverOwnershipFallbackOnDefault) {
+ std::unique_ptr<std::string> str;
+ std::string* str_ptr = nullptr;
+ AlwaysValidPointer<std::string> ptr(std::move(str), str_ptr);
+ EXPECT_EQ(*ptr, "");
+}
+
+TEST(AlwaysValidPointerTest,
+ TakeOverOwnershipFallbackOnDefaultWithForwardedArgument) {
+ std::unique_ptr<std::string> str2;
+ AlwaysValidPointer<std::string> ptr(std::move(str2), nullptr, "keso");
+ EXPECT_EQ(*ptr, "keso");
+}
+
+TEST(AlwaysValidPointerTest, TakeOverOwnershipDoesNotForwardDefaultArguments) {
+ std::unique_ptr<std::string> str = std::make_unique<std::string>("kalle");
+ std::unique_ptr<std::string> str2 = std::make_unique<std::string>("anka");
+ AlwaysValidPointer<std::string> ptr(std::move(str), nullptr, *str2);
+ EXPECT_EQ(*ptr, "kalle");
+ EXPECT_TRUE(!str);
+ EXPECT_EQ(*str2, "anka");
+}
+
+TEST(AlwaysValidPointerTest, DefaultToLambda) {
+ AlwaysValidPointer<std::string> ptr(
+ nullptr, []() { return std::make_unique<std::string>("onkel skrue"); });
+ EXPECT_EQ(*ptr, "onkel skrue");
+}
+
+TEST(AlwaysValidPointerTest, NoDefaultObjectPassValidPointer) {
+ std::string str("foo");
+ AlwaysValidPointerNoDefault<std::string> ptr(&str);
+ EXPECT_EQ(*ptr, "foo");
+ EXPECT_EQ(ptr, &str);
+}
+
+TEST(AlwaysValidPointerTest, NoDefaultObjectWithTakeOverOwnership) {
+ std::unique_ptr<std::string> str = std::make_unique<std::string>("yum");
+ AlwaysValidPointerNoDefault<std::string> ptr(std::move(str));
+ EXPECT_EQ(*ptr, "yum");
+ std::unique_ptr<std::string> str2 = std::make_unique<std::string>("fun");
+ AlwaysValidPointerNoDefault<std::string> ptr2(std::move(str), str2.get());
+ EXPECT_EQ(*ptr2, "fun");
+ EXPECT_EQ(ptr2, str2.get());
+}
+
+#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+
+TEST(AlwaysValidPointerTest, NoDefaultObjectPassNullPointer) {
+ auto pass_null = []() {
+ AlwaysValidPointerNoDefault<std::string> ptr(nullptr);
+ };
+ EXPECT_DEATH(pass_null(), "");
+}
+
+TEST(AlwaysValidPointerTest, NoDefaultObjectPassNullUniquePointer) {
+ auto pass_null = []() {
+ std::unique_ptr<std::string> str;
+ AlwaysValidPointerNoDefault<std::string> ptr(std::move(str));
+ };
+ EXPECT_DEATH(pass_null(), "");
+}
+
+#endif
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc
new file mode 100644
index 0000000000..c159bc979f
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.cc
@@ -0,0 +1,197 @@
+/*
+ * 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 "rtc_base/memory/fifo_buffer.h"
+
+#include <algorithm>
+
+#include "rtc_base/thread.h"
+
+namespace rtc {
+
+FifoBuffer::FifoBuffer(size_t size)
+ : state_(SS_OPEN),
+ buffer_(new char[size]),
+ buffer_length_(size),
+ data_length_(0),
+ read_position_(0),
+ owner_(Thread::Current()) {
+ // all events are done on the owner_ thread
+}
+
+FifoBuffer::FifoBuffer(size_t size, Thread* owner)
+ : state_(SS_OPEN),
+ buffer_(new char[size]),
+ buffer_length_(size),
+ data_length_(0),
+ read_position_(0),
+ owner_(owner) {
+ // all events are done on the owner_ thread
+}
+
+FifoBuffer::~FifoBuffer() {}
+
+bool FifoBuffer::GetBuffered(size_t* size) const {
+ webrtc::MutexLock lock(&mutex_);
+ *size = data_length_;
+ return true;
+}
+
+StreamState FifoBuffer::GetState() const {
+ webrtc::MutexLock lock(&mutex_);
+ return state_;
+}
+
+StreamResult FifoBuffer::Read(rtc::ArrayView<uint8_t> buffer,
+ size_t& bytes_read,
+ int& error) {
+ webrtc::MutexLock lock(&mutex_);
+ const bool was_writable = data_length_ < buffer_length_;
+ size_t copy = 0;
+ StreamResult result = ReadLocked(buffer.data(), buffer.size(), &copy);
+
+ if (result == SR_SUCCESS) {
+ // If read was successful then adjust the read position and number of
+ // bytes buffered.
+ read_position_ = (read_position_ + copy) % buffer_length_;
+ data_length_ -= copy;
+ bytes_read = copy;
+
+ // if we were full before, and now we're not, post an event
+ if (!was_writable && copy > 0) {
+ PostEvent(SE_WRITE, 0);
+ }
+ }
+ return result;
+}
+
+StreamResult FifoBuffer::Write(rtc::ArrayView<const uint8_t> buffer,
+ size_t& bytes_written,
+ int& error) {
+ webrtc::MutexLock lock(&mutex_);
+
+ const bool was_readable = (data_length_ > 0);
+ size_t copy = 0;
+ StreamResult result = WriteLocked(buffer.data(), buffer.size(), &copy);
+
+ if (result == SR_SUCCESS) {
+ // If write was successful then adjust the number of readable bytes.
+ data_length_ += copy;
+ bytes_written = copy;
+ // if we didn't have any data to read before, and now we do, post an event
+ if (!was_readable && copy > 0) {
+ PostEvent(SE_READ, 0);
+ }
+ }
+ return result;
+}
+
+void FifoBuffer::Close() {
+ webrtc::MutexLock lock(&mutex_);
+ state_ = SS_CLOSED;
+}
+
+const void* FifoBuffer::GetReadData(size_t* size) {
+ webrtc::MutexLock lock(&mutex_);
+ *size = (read_position_ + data_length_ <= buffer_length_)
+ ? data_length_
+ : buffer_length_ - read_position_;
+ return &buffer_[read_position_];
+}
+
+void FifoBuffer::ConsumeReadData(size_t size) {
+ webrtc::MutexLock lock(&mutex_);
+ RTC_DCHECK(size <= data_length_);
+ const bool was_writable = data_length_ < buffer_length_;
+ read_position_ = (read_position_ + size) % buffer_length_;
+ data_length_ -= size;
+ if (!was_writable && size > 0) {
+ PostEvent(SE_WRITE, 0);
+ }
+}
+
+void* FifoBuffer::GetWriteBuffer(size_t* size) {
+ webrtc::MutexLock lock(&mutex_);
+ if (state_ == SS_CLOSED) {
+ return nullptr;
+ }
+
+ // if empty, reset the write position to the beginning, so we can get
+ // the biggest possible block
+ if (data_length_ == 0) {
+ read_position_ = 0;
+ }
+
+ const size_t write_position =
+ (read_position_ + data_length_) % buffer_length_;
+ *size = (write_position > read_position_ || data_length_ == 0)
+ ? buffer_length_ - write_position
+ : read_position_ - write_position;
+ return &buffer_[write_position];
+}
+
+void FifoBuffer::ConsumeWriteBuffer(size_t size) {
+ webrtc::MutexLock lock(&mutex_);
+ RTC_DCHECK(size <= buffer_length_ - data_length_);
+ const bool was_readable = (data_length_ > 0);
+ data_length_ += size;
+ if (!was_readable && size > 0) {
+ PostEvent(SE_READ, 0);
+ }
+}
+
+StreamResult FifoBuffer::ReadLocked(void* buffer,
+ size_t bytes,
+ size_t* bytes_read) {
+ if (data_length_ == 0) {
+ return (state_ != SS_CLOSED) ? SR_BLOCK : SR_EOS;
+ }
+
+ const size_t available = data_length_;
+ const size_t read_position = read_position_ % buffer_length_;
+ const size_t copy = std::min(bytes, available);
+ const size_t tail_copy = std::min(copy, buffer_length_ - read_position);
+ char* const p = static_cast<char*>(buffer);
+ memcpy(p, &buffer_[read_position], tail_copy);
+ memcpy(p + tail_copy, &buffer_[0], copy - tail_copy);
+
+ if (bytes_read) {
+ *bytes_read = copy;
+ }
+ return SR_SUCCESS;
+}
+
+StreamResult FifoBuffer::WriteLocked(const void* buffer,
+ size_t bytes,
+ size_t* bytes_written) {
+ if (state_ == SS_CLOSED) {
+ return SR_EOS;
+ }
+
+ if (data_length_ >= buffer_length_) {
+ return SR_BLOCK;
+ }
+
+ const size_t available = buffer_length_ - data_length_;
+ const size_t write_position =
+ (read_position_ + data_length_) % buffer_length_;
+ const size_t copy = std::min(bytes, available);
+ const size_t tail_copy = std::min(copy, buffer_length_ - write_position);
+ const char* const p = static_cast<const char*>(buffer);
+ memcpy(&buffer_[write_position], p, tail_copy);
+ memcpy(&buffer_[0], p + tail_copy, copy - tail_copy);
+
+ if (bytes_written) {
+ *bytes_written = copy;
+ }
+ return SR_SUCCESS;
+}
+
+} // namespace rtc
diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h
new file mode 100644
index 0000000000..a225c688ac
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer.h
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+#ifndef RTC_BASE_MEMORY_FIFO_BUFFER_H_
+#define RTC_BASE_MEMORY_FIFO_BUFFER_H_
+
+#include <memory>
+
+#include "api/task_queue/pending_task_safety_flag.h"
+#include "rtc_base/stream.h"
+#include "rtc_base/synchronization/mutex.h"
+
+namespace rtc {
+
+// FifoBuffer allows for efficient, thread-safe buffering of data between
+// writer and reader.
+class FifoBuffer final : public StreamInterface {
+ public:
+ // Creates a FIFO buffer with the specified capacity.
+ explicit FifoBuffer(size_t length);
+ // Creates a FIFO buffer with the specified capacity and owner
+ FifoBuffer(size_t length, Thread* owner);
+ ~FifoBuffer() override;
+
+ FifoBuffer(const FifoBuffer&) = delete;
+ FifoBuffer& operator=(const FifoBuffer&) = delete;
+
+ // Gets the amount of data currently readable from the buffer.
+ bool GetBuffered(size_t* data_len) const;
+
+ // StreamInterface methods
+ StreamState GetState() const override;
+ StreamResult Read(rtc::ArrayView<uint8_t> buffer,
+ size_t& bytes_read,
+ int& error) override;
+ StreamResult Write(rtc::ArrayView<const uint8_t> buffer,
+ size_t& bytes_written,
+ int& error) override;
+ void Close() override;
+
+ // Seek to a byte offset from the beginning of the stream. Returns false if
+ // the stream does not support seeking, or cannot seek to the specified
+ // position.
+ bool SetPosition(size_t position);
+
+ // Get the byte offset of the current position from the start of the stream.
+ // Returns false if the position is not known.
+ bool GetPosition(size_t* position) const;
+
+ // Seek to the start of the stream.
+ bool Rewind() { return SetPosition(0); }
+
+ // GetReadData returns a pointer to a buffer which is owned by the stream.
+ // The buffer contains data_len bytes. null is returned if no data is
+ // available, or if the method fails. If the caller processes the data, it
+ // must call ConsumeReadData with the number of processed bytes. GetReadData
+ // does not require a matching call to ConsumeReadData if the data is not
+ // processed. Read and ConsumeReadData invalidate the buffer returned by
+ // GetReadData.
+ const void* GetReadData(size_t* data_len);
+ void ConsumeReadData(size_t used);
+ // GetWriteBuffer returns a pointer to a buffer which is owned by the stream.
+ // The buffer has a capacity of buf_len bytes. null is returned if there is
+ // no buffer available, or if the method fails. The call may write data to
+ // the buffer, and then call ConsumeWriteBuffer with the number of bytes
+ // written. GetWriteBuffer does not require a matching call to
+ // ConsumeWriteData if no data is written. Write and
+ // ConsumeWriteData invalidate the buffer returned by GetWriteBuffer.
+ void* GetWriteBuffer(size_t* buf_len);
+ void ConsumeWriteBuffer(size_t used);
+
+ private:
+ void PostEvent(int events, int err) {
+ owner_->PostTask(webrtc::SafeTask(
+ task_safety_.flag(),
+ [this, events, err]() { SignalEvent(this, events, err); }));
+ }
+
+ // Helper method that implements Read. Caller must acquire a lock
+ // when calling this method.
+ StreamResult ReadLocked(void* buffer, size_t bytes, size_t* bytes_read)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
+ // Helper method that implements Write. Caller must acquire a lock
+ // when calling this method.
+ StreamResult WriteLocked(const void* buffer,
+ size_t bytes,
+ size_t* bytes_written)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
+ webrtc::ScopedTaskSafety task_safety_;
+
+ // keeps the opened/closed state of the stream
+ StreamState state_ RTC_GUARDED_BY(mutex_);
+ // the allocated buffer
+ std::unique_ptr<char[]> buffer_ RTC_GUARDED_BY(mutex_);
+ // size of the allocated buffer
+ const size_t buffer_length_;
+ // amount of readable data in the buffer
+ size_t data_length_ RTC_GUARDED_BY(mutex_);
+ // offset to the readable data
+ size_t read_position_ RTC_GUARDED_BY(mutex_);
+ // stream callbacks are dispatched on this thread
+ Thread* const owner_;
+ // object lock
+ mutable webrtc::Mutex mutex_;
+};
+
+} // namespace rtc
+
+#endif // RTC_BASE_MEMORY_FIFO_BUFFER_H_
diff --git a/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc b/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc
new file mode 100644
index 0000000000..27eb8d8b45
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/memory/fifo_buffer_unittest.cc
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2004 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 "rtc_base/memory/fifo_buffer.h"
+
+#include <string.h>
+
+#include "test/gtest.h"
+
+namespace rtc {
+
+TEST(FifoBufferTest, TestAll) {
+ rtc::AutoThread main_thread;
+ const size_t kSize = 16;
+ const uint8_t in[kSize * 2 + 1] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
+ uint8_t out[kSize * 2];
+ void* p;
+ const void* q;
+ size_t bytes;
+ FifoBuffer buf(kSize);
+
+ // Test assumptions about base state
+ EXPECT_EQ(SS_OPEN, buf.GetState());
+ int error;
+ EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+ EXPECT_TRUE(nullptr != buf.GetWriteBuffer(&bytes));
+ EXPECT_EQ(kSize, bytes);
+ buf.ConsumeWriteBuffer(0);
+
+ // Try a full write
+ EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error));
+ EXPECT_EQ(kSize, bytes);
+
+ // Try a write that should block
+ EXPECT_EQ(SR_BLOCK, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error));
+
+ // Try a full read
+ EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize));
+
+ // Try a read that should block
+ EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+
+ // Try a too-big write
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize * 2), bytes, error));
+ EXPECT_EQ(bytes, kSize);
+
+ // Try a too-big read
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize * 2), bytes, error));
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize));
+
+ // Try some small writes and reads
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+
+ // Try wraparound reads and writes in the following pattern
+ // WWWWWWWWWWWW.... 0123456789AB....
+ // RRRRRRRRXXXX.... ........89AB....
+ // WWWW....XXXXWWWW 4567....89AB0123
+ // XXXX....RRRRXXXX 4567........0123
+ // XXXXWWWWWWWWXXXX 4567012345670123
+ // RRRRXXXXXXXXRRRR ....01234567....
+ // ....RRRRRRRR.... ................
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error));
+ EXPECT_EQ(kSize * 3 / 4, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 4), bytes, error));
+ EXPECT_EQ(kSize / 4, bytes);
+ EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+
+ // Use GetWriteBuffer to reset the read_position for the next tests
+ buf.GetWriteBuffer(&bytes);
+ buf.ConsumeWriteBuffer(0);
+
+ // Try using GetReadData to do a full read
+ EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error));
+ q = buf.GetReadData(&bytes);
+ EXPECT_TRUE(nullptr != q);
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(q, in, kSize));
+ buf.ConsumeReadData(kSize);
+ EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+
+ // Try using GetReadData to do some small reads
+ EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error));
+ q = buf.GetReadData(&bytes);
+ EXPECT_TRUE(nullptr != q);
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(q, in, kSize / 2));
+ buf.ConsumeReadData(kSize / 2);
+ q = buf.GetReadData(&bytes);
+ EXPECT_TRUE(nullptr != q);
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(q, in + kSize / 2, kSize / 2));
+ buf.ConsumeReadData(kSize / 2);
+ EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+
+ // Try using GetReadData in a wraparound case
+ // WWWWWWWWWWWWWWWW 0123456789ABCDEF
+ // RRRRRRRRRRRRXXXX ............CDEF
+ // WWWWWWWW....XXXX 01234567....CDEF
+ // ............RRRR 01234567........
+ // RRRRRRRR........ ................
+ EXPECT_EQ(SR_SUCCESS, buf.Write(rtc::MakeArrayView(in, kSize), bytes, error));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ q = buf.GetReadData(&bytes);
+ EXPECT_TRUE(nullptr != q);
+ EXPECT_EQ(kSize / 4, bytes);
+ EXPECT_EQ(0, memcmp(q, in + kSize * 3 / 4, kSize / 4));
+ buf.ConsumeReadData(kSize / 4);
+ q = buf.GetReadData(&bytes);
+ EXPECT_TRUE(nullptr != q);
+ EXPECT_EQ(kSize / 2, bytes);
+ EXPECT_EQ(0, memcmp(q, in, kSize / 2));
+ buf.ConsumeReadData(kSize / 2);
+
+ // Use GetWriteBuffer to reset the read_position for the next tests
+ buf.GetWriteBuffer(&bytes);
+ buf.ConsumeWriteBuffer(0);
+
+ // Try using GetWriteBuffer to do a full write
+ p = buf.GetWriteBuffer(&bytes);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_EQ(kSize, bytes);
+ memcpy(p, in, kSize);
+ buf.ConsumeWriteBuffer(kSize);
+ EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize));
+
+ // Try using GetWriteBuffer to do some small writes
+ p = buf.GetWriteBuffer(&bytes);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_EQ(kSize, bytes);
+ memcpy(p, in, kSize / 2);
+ buf.ConsumeWriteBuffer(kSize / 2);
+ p = buf.GetWriteBuffer(&bytes);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_EQ(kSize / 2, bytes);
+ memcpy(p, in + kSize / 2, kSize / 2);
+ buf.ConsumeWriteBuffer(kSize / 2);
+ EXPECT_EQ(SR_SUCCESS, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+ EXPECT_EQ(kSize, bytes);
+ EXPECT_EQ(0, memcmp(in, out, kSize));
+
+ // Try using GetWriteBuffer in a wraparound case
+ // WWWWWWWWWWWW.... 0123456789AB....
+ // RRRRRRRRXXXX.... ........89AB....
+ // ........XXXXWWWW ........89AB0123
+ // WWWW....XXXXXXXX 4567....89AB0123
+ // RRRR....RRRRRRRR ................
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize * 3 / 4), bytes, error));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ p = buf.GetWriteBuffer(&bytes);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_EQ(kSize / 4, bytes);
+ memcpy(p, in, kSize / 4);
+ buf.ConsumeWriteBuffer(kSize / 4);
+ p = buf.GetWriteBuffer(&bytes);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_EQ(kSize / 2, bytes);
+ memcpy(p, in + kSize / 4, kSize / 4);
+ buf.ConsumeWriteBuffer(kSize / 4);
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize * 3 / 4), bytes, error));
+ EXPECT_EQ(kSize * 3 / 4, bytes);
+ EXPECT_EQ(0, memcmp(in + kSize / 2, out, kSize / 4));
+ EXPECT_EQ(0, memcmp(in, out + kSize / 4, kSize / 4));
+
+ // Check that the stream is now empty
+ EXPECT_EQ(SR_BLOCK, buf.Read(rtc::MakeArrayView(out, kSize), bytes, error));
+
+ // Write to the stream, close it, read the remaining bytes
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ buf.Close();
+ EXPECT_EQ(SS_CLOSED, buf.GetState());
+ EXPECT_EQ(SR_EOS, buf.Write(rtc::MakeArrayView(in, kSize / 2), bytes, error));
+ EXPECT_EQ(SR_SUCCESS,
+ buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+ EXPECT_EQ(0, memcmp(in, out, kSize / 2));
+ EXPECT_EQ(SR_EOS, buf.Read(rtc::MakeArrayView(out, kSize / 2), bytes, error));
+}
+
+TEST(FifoBufferTest, FullBufferCheck) {
+ rtc::AutoThread main_thread;
+ FifoBuffer buff(10);
+ buff.ConsumeWriteBuffer(10);
+
+ size_t free;
+ EXPECT_TRUE(buff.GetWriteBuffer(&free) != nullptr);
+ EXPECT_EQ(0U, free);
+}
+
+} // namespace rtc