Implement base::RefCountedSharedMemory.

This base::RefCountedMemory subclass owns a base::SharedMemory instance.
Use this class to easily access data in shared memory via the
base::RefCountedMemory interface without having to copy it out to a
std::string or std::vector.

Use this in printing code to avoid a bunch of copying.

Change-Id: I275eacb3af0250d352ec909429d8563b28b1b57e
Reviewed-on: https://chromium-review.googlesource.com/978641
Commit-Queue: Lei Zhang <[email protected]>
Reviewed-by: Wei Li <[email protected]>
Reviewed-by: Rebekah Potter <[email protected]>
Reviewed-by: Reilly Grant <[email protected]>
Cr-Commit-Position: refs/heads/master@{#547048}
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
index be981e32..7999d90 100644
--- a/base/memory/ref_counted_memory.cc
+++ b/base/memory/ref_counted_memory.cc
@@ -4,6 +4,8 @@
 
 #include "base/memory/ref_counted_memory.h"
 
+#include <utility>
+
 #include "base/logging.h"
 
 namespace base {
@@ -80,4 +82,24 @@
   return data_.size();
 }
 
+RefCountedSharedMemory::RefCountedSharedMemory(
+    std::unique_ptr<SharedMemory> shm,
+    size_t size)
+    : shm_(std::move(shm)), size_(size) {
+  DCHECK(shm_);
+  DCHECK(shm_->memory());
+  DCHECK_GT(size_, 0U);
+  DCHECK_LE(size_, shm_->mapped_size());
+}
+
+RefCountedSharedMemory::~RefCountedSharedMemory() = default;
+
+const unsigned char* RefCountedSharedMemory::front() const {
+  return reinterpret_cast<const unsigned char*>(shm_->memory());
+}
+
+size_t RefCountedSharedMemory::size() const {
+  return size_;
+}
+
 }  //  namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
index 9d29922..82a3eeb1 100644
--- a/base/memory/ref_counted_memory.h
+++ b/base/memory/ref_counted_memory.h
@@ -7,12 +7,14 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/base_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
 
 namespace base {
 
@@ -136,6 +138,27 @@
   DISALLOW_COPY_AND_ASSIGN(RefCountedString);
 };
 
+// An implementation of RefCountedMemory, where the bytes are stored in shared
+// memory.
+class BASE_EXPORT RefCountedSharedMemory : public RefCountedMemory {
+ public:
+  // Constructs a RefCountedMemory object by taking ownership of an already
+  // mapped SharedMemory object.
+  RefCountedSharedMemory(std::unique_ptr<SharedMemory> shm, size_t size);
+
+  // RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+ private:
+  ~RefCountedSharedMemory() override;
+
+  const std::unique_ptr<SharedMemory> shm_;
+  const size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedSharedMemory);
+};
+
 }  // namespace base
 
 #endif  // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc
index 72046e52..43f7bbe 100644
--- a/base/memory/ref_counted_memory_unittest.cc
+++ b/base/memory/ref_counted_memory_unittest.cc
@@ -6,6 +6,8 @@
 
 #include <stdint.h>
 
+#include <utility>
+
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -70,6 +72,20 @@
   EXPECT_EQ('e', mem->front()[9]);
 }
 
+TEST(RefCountedMemoryUnitTest, RefCountedSharedMemory) {
+  static const char kData[] = "shm_dummy_data";
+  auto shm = std::make_unique<SharedMemory>();
+  ASSERT_TRUE(shm->CreateAndMapAnonymous(sizeof(kData)));
+  memcpy(shm->memory(), kData, sizeof(kData));
+
+  auto mem =
+      MakeRefCounted<RefCountedSharedMemory>(std::move(shm), sizeof(kData));
+  ASSERT_EQ(sizeof(kData), mem->size());
+  EXPECT_EQ('s', mem->front()[0]);
+  EXPECT_EQ('h', mem->front()[1]);
+  EXPECT_EQ('_', mem->front()[9]);
+}
+
 TEST(RefCountedMemoryUnitTest, Equals) {
   std::string s1("same");
   scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1);