blob: 6415e17dde7f371a39479693500b0d5692c53697 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/tracing/core/chunked_protobuf_input_stream.h"
#include <algorithm>
#include "perfetto/base/logging.h"
namespace perfetto {
ChunkedProtobufInputStream::ChunkedProtobufInputStream(
const ChunkSequence* chunks)
: chunks_(chunks), cur_chunk_(chunks_->begin()) {}
ChunkedProtobufInputStream::~ChunkedProtobufInputStream() = default;
bool ChunkedProtobufInputStream::Next(const void** data, int* size) {
if (cur_chunk_ == chunks_->end())
return false;
PERFETTO_DCHECK(Validate());
*data = reinterpret_cast<const void*>(
reinterpret_cast<uintptr_t>(cur_chunk_->start) + pos_in_cur_chunk_);
*size = static_cast<int>(cur_chunk_->size - pos_in_cur_chunk_);
cur_chunk_++;
pos_in_cur_chunk_ = 0;
PERFETTO_DCHECK(Validate());
return true;
}
void ChunkedProtobufInputStream::BackUp(int count) {
size_t n = static_cast<size_t>(count);
PERFETTO_DCHECK(Validate());
while (n) {
if (cur_chunk_ == chunks_->end() || pos_in_cur_chunk_ == 0) {
if (cur_chunk_ == chunks_->begin()) {
// The protobuf library is violating its contract and backing up more
// bytes than available.
PERFETTO_DCHECK(false);
return;
}
cur_chunk_--;
pos_in_cur_chunk_ = cur_chunk_->size;
continue;
}
const size_t decrement = std::min(n, pos_in_cur_chunk_);
pos_in_cur_chunk_ -= decrement;
n -= decrement;
}
PERFETTO_DCHECK(Validate());
}
bool ChunkedProtobufInputStream::Skip(int count) {
PERFETTO_DCHECK(Validate());
size_t n = static_cast<size_t>(count);
while (n) {
PERFETTO_DCHECK(Validate());
if (cur_chunk_ == chunks_->end())
return false;
const size_t increment = std::min(n, cur_chunk_->size - pos_in_cur_chunk_);
pos_in_cur_chunk_ += increment;
n -= increment;
if (pos_in_cur_chunk_ >= cur_chunk_->size) {
cur_chunk_++;
pos_in_cur_chunk_ = 0;
}
}
PERFETTO_DCHECK(Validate());
return true;
}
google::protobuf::int64 ChunkedProtobufInputStream::ByteCount() const {
PERFETTO_DCHECK(Validate());
google::protobuf::int64 count = 0;
for (auto it = chunks_->begin(); it != chunks_->end(); it++) {
if (it == cur_chunk_) {
count += static_cast<google::protobuf::int64>(pos_in_cur_chunk_);
break;
}
count += static_cast<google::protobuf::int64>(it->size);
}
return count;
}
bool ChunkedProtobufInputStream::Validate() const {
return ((cur_chunk_ == chunks_->end() && pos_in_cur_chunk_ == 0) ||
pos_in_cur_chunk_ < cur_chunk_->size ||
(pos_in_cur_chunk_ == 0 && cur_chunk_->size == 0));
}
} // namespace perfetto