blob: 6b0022472b0bee18d7004956041cacf2958b6b4e [file] [log] [blame]
Josh Gaocd2a5292018-03-07 16:52:28 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
Anatol Pomazau45a25182019-08-08 14:37:59 -070019#include <string.h>
20
Josh Gaocd2a5292018-03-07 16:52:28 -080021#include <algorithm>
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070022#include <memory>
Josh Gaocd2a5292018-03-07 16:52:28 -080023#include <utility>
Josh Gao9f155db2018-04-03 14:37:11 -070024#include <vector>
Josh Gaocd2a5292018-03-07 16:52:28 -080025
26#include <android-base/logging.h>
27
Josh Gao9f155db2018-04-03 14:37:11 -070028#include "sysdeps/uio.h"
Josh Gaocd2a5292018-03-07 16:52:28 -080029
30// Essentially std::vector<char>, except without zero initialization or reallocation.
31struct Block {
32 using iterator = char*;
33
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070034 Block() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -080035
36 explicit Block(size_t size) { allocate(size); }
37
38 template <typename Iterator>
39 Block(Iterator begin, Iterator end) : Block(end - begin) {
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070040 std::copy(begin, end, data_.get());
Josh Gaocd2a5292018-03-07 16:52:28 -080041 }
42
43 Block(const Block& copy) = delete;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070044 Block(Block&& move) noexcept
45 : data_(std::exchange(move.data_, nullptr)),
46 capacity_(std::exchange(move.capacity_, 0)),
47 size_(std::exchange(move.size_, 0)) {}
Josh Gaocd2a5292018-03-07 16:52:28 -080048
49 Block& operator=(const Block& copy) = delete;
Chih-Hung Hsieh3c99c392018-09-25 11:16:22 -070050 Block& operator=(Block&& move) noexcept {
Josh Gaocd2a5292018-03-07 16:52:28 -080051 clear();
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070052 data_ = std::exchange(move.data_, nullptr);
53 capacity_ = std::exchange(move.capacity_, 0);
54 size_ = std::exchange(move.size_, 0);
Josh Gaocd2a5292018-03-07 16:52:28 -080055 return *this;
56 }
57
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -070058 ~Block() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -080059
60 void resize(size_t new_size) {
61 if (!data_) {
62 allocate(new_size);
63 } else {
64 CHECK_GE(capacity_, new_size);
65 size_ = new_size;
66 }
67 }
68
69 template <typename InputIt>
70 void assign(InputIt begin, InputIt end) {
71 clear();
72 allocate(end - begin);
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070073 std::copy(begin, end, data_.get());
Josh Gaocd2a5292018-03-07 16:52:28 -080074 }
75
76 void clear() {
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070077 data_.reset();
Josh Gaocd2a5292018-03-07 16:52:28 -080078 capacity_ = 0;
79 size_ = 0;
80 }
81
82 size_t capacity() const { return capacity_; }
83 size_t size() const { return size_; }
84 bool empty() const { return size() == 0; }
85
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070086 char* data() { return data_.get(); }
87 const char* data() const { return data_.get(); }
Josh Gaocd2a5292018-03-07 16:52:28 -080088
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -070089 char* begin() { return data_.get(); }
90 const char* begin() const { return data_.get(); }
Josh Gaocd2a5292018-03-07 16:52:28 -080091
92 char* end() { return data() + size_; }
93 const char* end() const { return data() + size_; }
94
95 char& operator[](size_t idx) { return data()[idx]; }
96 const char& operator[](size_t idx) const { return data()[idx]; }
97
98 bool operator==(const Block& rhs) const {
99 return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0;
100 }
101
102 private:
103 void allocate(size_t size) {
104 CHECK(data_ == nullptr);
105 CHECK_EQ(0ULL, capacity_);
106 CHECK_EQ(0ULL, size_);
107 if (size != 0) {
Josh Gao5b470822018-11-12 13:44:38 -0800108 // This isn't std::make_unique because that's equivalent to `new char[size]()`, which
109 // value-initializes the array instead of leaving it uninitialized. As an optimization,
110 // call new without parentheses to avoid this costly initialization.
111 data_.reset(new char[size]);
Josh Gaocd2a5292018-03-07 16:52:28 -0800112 capacity_ = size;
113 size_ = size;
114 }
115 }
116
Luis Hector Chavezb4edbdf2018-07-18 21:18:27 -0700117 std::unique_ptr<char[]> data_;
Josh Gaocd2a5292018-03-07 16:52:28 -0800118 size_t capacity_ = 0;
119 size_t size_ = 0;
120};
121
122struct amessage {
123 uint32_t command; /* command identifier constant */
124 uint32_t arg0; /* first argument */
125 uint32_t arg1; /* second argument */
126 uint32_t data_length; /* length of payload (0 is allowed) */
127 uint32_t data_check; /* checksum of data payload */
128 uint32_t magic; /* command ^ 0xffffffff */
129};
130
131struct apacket {
132 using payload_type = Block;
133 amessage msg;
134 payload_type payload;
135};
136
Josh Gao9f155db2018-04-03 14:37:11 -0700137struct IOVector {
138 using value_type = char;
139 using block_type = Block;
140 using size_type = size_t;
Josh Gaocd2a5292018-03-07 16:52:28 -0800141
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700142 IOVector() = default;
Josh Gaocd2a5292018-03-07 16:52:28 -0800143
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700144 explicit IOVector(block_type&& block) { append(std::move(block)); }
Josh Gaocd2a5292018-03-07 16:52:28 -0800145
Josh Gao9f155db2018-04-03 14:37:11 -0700146 IOVector(const IOVector& copy) = delete;
Chih-Hung Hsieh3c99c392018-09-25 11:16:22 -0700147 IOVector(IOVector&& move) noexcept : IOVector() { *this = std::move(move); }
Josh Gao9f155db2018-04-03 14:37:11 -0700148
149 IOVector& operator=(const IOVector& copy) = delete;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700150 IOVector& operator=(IOVector&& move) noexcept;
Josh Gao9f155db2018-04-03 14:37:11 -0700151
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700152 size_type size() const { return chain_length_ - begin_offset_; }
Josh Gaocd2a5292018-03-07 16:52:28 -0800153 bool empty() const { return size() == 0; }
154
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700155 // Return the last block so the caller can still reuse its allocated capacity
156 // or it can be simply ignored.
157 block_type clear();
158
159 void drop_front(size_type len);
Josh Gaocd2a5292018-03-07 16:52:28 -0800160
Josh Gao9f155db2018-04-03 14:37:11 -0700161 // Split the first |len| bytes out of this chain into its own.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700162 IOVector take_front(size_type len);
Josh Gaocd2a5292018-03-07 16:52:28 -0800163
Josh Gao9f155db2018-04-03 14:37:11 -0700164 // Add a nonempty block to the chain.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700165 void append(block_type&& block) {
166 if (block.size() == 0) {
Josh Gao15fa1332019-04-03 12:56:22 -0700167 return;
168 }
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700169 CHECK_NE(0ULL, block.size());
170 chain_length_ += block.size();
Josh Gao9f155db2018-04-03 14:37:11 -0700171 chain_.emplace_back(std::move(block));
172 }
Josh Gaocd2a5292018-03-07 16:52:28 -0800173
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700174 void trim_front();
Josh Gao9f155db2018-04-03 14:37:11 -0700175
176 private:
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700177 void trim_chain_front();
Josh Gao9f155db2018-04-03 14:37:11 -0700178
179 // Drop the front block from the chain, and update chain_length_ appropriately.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700180 void pop_front_block();
Josh Gao9f155db2018-04-03 14:37:11 -0700181
182 // Iterate over the blocks with a callback with an operator()(const char*, size_t).
183 template <typename Fn>
184 void iterate_blocks(Fn&& callback) const {
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700185 if (size() == 0) {
Josh Gao9f155db2018-04-03 14:37:11 -0700186 return;
187 }
188
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700189 for (size_t i = start_index_; i < chain_.size(); ++i) {
190 const auto& block = chain_[i];
191 const char* begin = block.data();
192 size_t length = block.size();
Josh Gao9f155db2018-04-03 14:37:11 -0700193
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700194 if (i == start_index_) {
195 CHECK_GE(block.size(), begin_offset_);
Josh Gao9f155db2018-04-03 14:37:11 -0700196 begin += begin_offset_;
197 length -= begin_offset_;
198 }
Josh Gao9f155db2018-04-03 14:37:11 -0700199 callback(begin, length);
200 }
201 }
202
203 public:
204 // Copy all of the blocks into a single block.
205 template <typename CollectionType = block_type>
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700206 CollectionType coalesce() const& {
Josh Gao9f155db2018-04-03 14:37:11 -0700207 CollectionType result;
208 if (size() == 0) {
209 return result;
210 }
211
212 result.resize(size());
213
214 size_t offset = 0;
215 iterate_blocks([&offset, &result](const char* data, size_t len) {
216 memcpy(&result[offset], data, len);
217 offset += len;
218 });
219
220 return result;
221 }
222
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700223 block_type coalesce() &&;
224
Josh Gao9f155db2018-04-03 14:37:11 -0700225 template <typename FunctionType>
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700226 auto coalesced(FunctionType&& f) const {
227 if (chain_.size() == start_index_ + 1) {
Josh Gao9f155db2018-04-03 14:37:11 -0700228 // If we only have one block, we can use it directly.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700229 return f(chain_[start_index_].data() + begin_offset_, size());
Josh Gao9f155db2018-04-03 14:37:11 -0700230 } else {
231 // Otherwise, copy to a single block.
232 auto data = coalesce();
233 return f(data.data(), data.size());
234 }
235 }
236
237 // Get a list of iovecs that can be used to write out all of the blocks.
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700238 std::vector<adb_iovec> iovecs() const;
Josh Gao9f155db2018-04-03 14:37:11 -0700239
240 private:
241 // Total length of all of the blocks in the chain.
242 size_t chain_length_ = 0;
243
Josh Gaocd2a5292018-03-07 16:52:28 -0800244 size_t begin_offset_ = 0;
Yurii Zubrytskyie5e6b0d2019-07-12 14:11:54 -0700245 size_t start_index_ = 0;
246 std::vector<block_type> chain_;
Josh Gaocd2a5292018-03-07 16:52:28 -0800247};