Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright (C) 2017 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 #include "src/tracing/core/sliced_protobuf_input_stream.h"
     18 
     19 #include <algorithm>
     20 
     21 #include "perfetto/base/logging.h"
     22 
     23 namespace perfetto {
     24 
     25 SlicedProtobufInputStream::SlicedProtobufInputStream(const Slices* slices)
     26     : slices_(slices), cur_slice_(slices_->begin()) {}
     27 
     28 SlicedProtobufInputStream::~SlicedProtobufInputStream() = default;
     29 
     30 bool SlicedProtobufInputStream::Next(const void** data, int* size) {
     31   if (cur_slice_ == slices_->end())
     32     return false;
     33 
     34   PERFETTO_DCHECK(Validate());
     35   *data = reinterpret_cast<const void*>(
     36       reinterpret_cast<uintptr_t>(cur_slice_->start) + pos_in_cur_slice_);
     37   *size = static_cast<int>(cur_slice_->size - pos_in_cur_slice_);
     38   cur_slice_++;
     39   pos_in_cur_slice_ = 0;
     40   PERFETTO_DCHECK(Validate());
     41 
     42   return true;
     43 }
     44 
     45 void SlicedProtobufInputStream::BackUp(int count) {
     46   size_t n = static_cast<size_t>(count);
     47   PERFETTO_DCHECK(Validate());
     48   while (n) {
     49     if (cur_slice_ == slices_->end() || pos_in_cur_slice_ == 0) {
     50       if (cur_slice_ == slices_->begin()) {
     51         // The protobuf library is violating its contract and backing up more
     52         // bytes than available.
     53         PERFETTO_DFATAL("Protobuf library backed up too many bytes.");
     54         return;
     55       }
     56       cur_slice_--;
     57       pos_in_cur_slice_ = cur_slice_->size;
     58       continue;
     59     }
     60 
     61     const size_t decrement = std::min(n, pos_in_cur_slice_);
     62     pos_in_cur_slice_ -= decrement;
     63     n -= decrement;
     64   }
     65   PERFETTO_DCHECK(Validate());
     66 }
     67 
     68 bool SlicedProtobufInputStream::Skip(int count) {
     69   PERFETTO_DCHECK(Validate());
     70   size_t n = static_cast<size_t>(count);
     71   while (n) {
     72     PERFETTO_DCHECK(Validate());
     73     if (cur_slice_ == slices_->end())
     74       return false;
     75 
     76     const size_t increment = std::min(n, cur_slice_->size - pos_in_cur_slice_);
     77     pos_in_cur_slice_ += increment;
     78     n -= increment;
     79 
     80     if (pos_in_cur_slice_ >= cur_slice_->size) {
     81       cur_slice_++;
     82       pos_in_cur_slice_ = 0;
     83     }
     84   }
     85   PERFETTO_DCHECK(Validate());
     86   return true;
     87 }
     88 
     89 google::protobuf::int64 SlicedProtobufInputStream::ByteCount() const {
     90   PERFETTO_DCHECK(Validate());
     91   google::protobuf::int64 count = 0;
     92   for (auto it = slices_->begin(); it != slices_->end(); it++) {
     93     if (it == cur_slice_) {
     94       count += static_cast<google::protobuf::int64>(pos_in_cur_slice_);
     95       break;
     96     }
     97     count += static_cast<google::protobuf::int64>(it->size);
     98   }
     99   return count;
    100 }
    101 
    102 bool SlicedProtobufInputStream::Validate() const {
    103   return ((cur_slice_ == slices_->end() && pos_in_cur_slice_ == 0) ||
    104           pos_in_cur_slice_ < cur_slice_->size ||
    105           (pos_in_cur_slice_ == 0 && cur_slice_->size == 0));
    106 }
    107 
    108 }  // namespace perfetto
    109