1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/public/cpp/base/big_buffer.h"
6
7 #include "base/logging.h"
8
9 namespace mojo_base {
10
11 namespace internal {
12
13 BigBufferSharedMemoryRegion::BigBufferSharedMemoryRegion() = default;
14
BigBufferSharedMemoryRegion(mojo::ScopedSharedBufferHandle buffer_handle,size_t size)15 BigBufferSharedMemoryRegion::BigBufferSharedMemoryRegion(
16 mojo::ScopedSharedBufferHandle buffer_handle,
17 size_t size)
18 : size_(size),
19 buffer_handle_(std::move(buffer_handle)),
20 buffer_mapping_(buffer_handle_->Map(size)) {}
21
22 BigBufferSharedMemoryRegion::BigBufferSharedMemoryRegion(
23 BigBufferSharedMemoryRegion&& other) = default;
24
25 BigBufferSharedMemoryRegion::~BigBufferSharedMemoryRegion() = default;
26
27 BigBufferSharedMemoryRegion& BigBufferSharedMemoryRegion::operator=(
28 BigBufferSharedMemoryRegion&& other) = default;
29
TakeBufferHandle()30 mojo::ScopedSharedBufferHandle BigBufferSharedMemoryRegion::TakeBufferHandle() {
31 DCHECK(buffer_handle_.is_valid());
32 buffer_mapping_.reset();
33 return std::move(buffer_handle_);
34 }
35
36 } // namespace internal
37
38 // static
39 constexpr size_t BigBuffer::kMaxInlineBytes;
40
BigBuffer()41 BigBuffer::BigBuffer() : storage_type_(StorageType::kBytes) {}
42
43 BigBuffer::BigBuffer(BigBuffer&& other) = default;
44
BigBuffer(base::span<const uint8_t> data)45 BigBuffer::BigBuffer(base::span<const uint8_t> data) {
46 *this = BigBufferView::ToBigBuffer(BigBufferView(data));
47 }
48
BigBuffer(const std::vector<uint8_t> & data)49 BigBuffer::BigBuffer(const std::vector<uint8_t>& data)
50 : BigBuffer(base::make_span(data)) {}
51
BigBuffer(internal::BigBufferSharedMemoryRegion shared_memory)52 BigBuffer::BigBuffer(internal::BigBufferSharedMemoryRegion shared_memory)
53 : storage_type_(StorageType::kSharedMemory),
54 shared_memory_(std::move(shared_memory)) {}
55
56 BigBuffer::~BigBuffer() = default;
57
58 BigBuffer& BigBuffer::operator=(BigBuffer&& other) = default;
59
data()60 uint8_t* BigBuffer::data() {
61 return const_cast<uint8_t*>(const_cast<const BigBuffer*>(this)->data());
62 }
63
data() const64 const uint8_t* BigBuffer::data() const {
65 switch (storage_type_) {
66 case StorageType::kBytes:
67 return bytes_.data();
68 case StorageType::kSharedMemory:
69 DCHECK(shared_memory_->buffer_mapping_);
70 return static_cast<const uint8_t*>(
71 const_cast<const void*>(shared_memory_->buffer_mapping_.get()));
72 default:
73 NOTREACHED();
74 return nullptr;
75 }
76 }
77
size() const78 size_t BigBuffer::size() const {
79 switch (storage_type_) {
80 case StorageType::kBytes:
81 return bytes_.size();
82 case StorageType::kSharedMemory:
83 return shared_memory_->size();
84 default:
85 NOTREACHED();
86 return 0;
87 }
88 }
89
90 BigBufferView::BigBufferView() = default;
91
92 BigBufferView::BigBufferView(BigBufferView&& other) = default;
93
BigBufferView(base::span<const uint8_t> bytes)94 BigBufferView::BigBufferView(base::span<const uint8_t> bytes) {
95 if (bytes.size() > BigBuffer::kMaxInlineBytes) {
96 auto buffer = mojo::SharedBufferHandle::Create(bytes.size());
97 if (buffer.is_valid()) {
98 storage_type_ = BigBuffer::StorageType::kSharedMemory;
99 shared_memory_.emplace(std::move(buffer), bytes.size());
100 std::copy(bytes.begin(), bytes.end(),
101 static_cast<uint8_t*>(shared_memory_->buffer_mapping_.get()));
102 return;
103 }
104 }
105
106 // Either the data is small enough or shared memory allocation failed. Either
107 // way we fall back to directly referencing the input bytes.
108 storage_type_ = BigBuffer::StorageType::kBytes;
109 bytes_ = bytes;
110 }
111
112 BigBufferView::~BigBufferView() = default;
113
114 BigBufferView& BigBufferView::operator=(BigBufferView&& other) = default;
115
SetBytes(base::span<const uint8_t> bytes)116 void BigBufferView::SetBytes(base::span<const uint8_t> bytes) {
117 DCHECK(bytes_.empty());
118 DCHECK(!shared_memory_);
119 storage_type_ = BigBuffer::StorageType::kBytes;
120 bytes_ = bytes;
121 }
122
SetSharedMemory(internal::BigBufferSharedMemoryRegion shared_memory)123 void BigBufferView::SetSharedMemory(
124 internal::BigBufferSharedMemoryRegion shared_memory) {
125 DCHECK(bytes_.empty());
126 DCHECK(!shared_memory_);
127 storage_type_ = BigBuffer::StorageType::kSharedMemory;
128 shared_memory_ = std::move(shared_memory);
129 }
130
data() const131 base::span<const uint8_t> BigBufferView::data() const {
132 if (storage_type_ == BigBuffer::StorageType::kBytes) {
133 return bytes_;
134 } else {
135 DCHECK(shared_memory_.has_value());
136 return base::make_span(static_cast<const uint8_t*>(const_cast<const void*>(
137 shared_memory_->memory())),
138 shared_memory_->size());
139 }
140 }
141
142 // static
ToBigBuffer(BigBufferView view)143 BigBuffer BigBufferView::ToBigBuffer(BigBufferView view) {
144 BigBuffer buffer;
145 buffer.storage_type_ = view.storage_type_;
146 if (view.storage_type_ == BigBuffer::StorageType::kBytes) {
147 std::copy(view.bytes_.begin(), view.bytes_.end(),
148 std::back_inserter(buffer.bytes_));
149 } else {
150 buffer.shared_memory_ = std::move(*view.shared_memory_);
151 }
152 return buffer;
153 }
154
155 } // namespace mojo_base
156