blob: 65b0bb195f850db78f5c06125cfcd30657e77288 [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/sliced_protobuf_input_stream.h"
#include <algorithm>
#include "perfetto/base/logging.h"
namespace perfetto {
SlicedProtobufInputStream::SlicedProtobufInputStream(const Slices* slices)
: slices_(slices), cur_slice_(slices_->begin()) {}
SlicedProtobufInputStream::~SlicedProtobufInputStream() = default;
bool SlicedProtobufInputStream::Next(const void** data, int* size) {
if (cur_slice_ == slices_->end())
return false;
PERFETTO_DCHECK(Validate());
*data = reinterpret_cast<const void*>(
reinterpret_cast<uintptr_t>(cur_slice_->start) + pos_in_cur_slice_);
*size = static_cast<int>(cur_slice_->size - pos_in_cur_slice_);
cur_slice_++;
pos_in_cur_slice_ = 0;
PERFETTO_DCHECK(Validate());
return true;
}
void SlicedProtobufInputStream::BackUp(int count) {
size_t n = static_cast<size_t>(count);
PERFETTO_DCHECK(Validate());
while (n) {
if (cur_slice_ == slices_->end() || pos_in_cur_slice_ == 0) {
if (cur_slice_ == slices_->begin()) {
// The protobuf library is violating its contract and backing up more
// bytes than available.
PERFETTO_DFATAL("Protobuf library backed up too many bytes.");
return;
}
cur_slice_--;
pos_in_cur_slice_ = cur_slice_->size;
continue;
}
const size_t decrement = std::min(n, pos_in_cur_slice_);
pos_in_cur_slice_ -= decrement;
n -= decrement;
}
PERFETTO_DCHECK(Validate());
}
bool SlicedProtobufInputStream::Skip(int count) {
PERFETTO_DCHECK(Validate());
size_t n = static_cast<size_t>(count);
while (n) {
PERFETTO_DCHECK(Validate());
if (cur_slice_ == slices_->end())
return false;
const size_t increment = std::min(n, cur_slice_->size - pos_in_cur_slice_);
pos_in_cur_slice_ += increment;
n -= increment;
if (pos_in_cur_slice_ >= cur_slice_->size) {
cur_slice_++;
pos_in_cur_slice_ = 0;
}
}
PERFETTO_DCHECK(Validate());
return true;
}
google::protobuf::int64 SlicedProtobufInputStream::ByteCount() const {
PERFETTO_DCHECK(Validate());
google::protobuf::int64 count = 0;
for (auto it = slices_->begin(); it != slices_->end(); it++) {
if (it == cur_slice_) {
count += static_cast<google::protobuf::int64>(pos_in_cur_slice_);
break;
}
count += static_cast<google::protobuf::int64>(it->size);
}
return count;
}
bool SlicedProtobufInputStream::Validate() const {
return ((cur_slice_ == slices_->end() && pos_in_cur_slice_ == 0) ||
pos_in_cur_slice_ < cur_slice_->size ||
(pos_in_cur_slice_ == 0 && cur_slice_->size == 0));
}
} // namespace perfetto