blob: 1dbd10b7d7644592012c921d182b9cd7dcde8d98 [file] [log] [blame]
/*
* Copyright (C) 2024 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/trace_processor/util/file_buffer.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <optional>
#include "perfetto/base/logging.h"
#include "perfetto/trace_processor/trace_blob.h"
#include "perfetto/trace_processor/trace_blob_view.h"
namespace perfetto::trace_processor::util {
void FileBuffer::PushBack(TraceBlobView data) {
if (data.size() == 0) {
return;
}
const size_t size = data.size();
data_.emplace_back(Entry{end_offset_, std::move(data)});
end_offset_ += size;
}
bool FileBuffer::PopFrontUntil(const size_t target_offset) {
PERFETTO_CHECK(file_offset() <= target_offset);
while (!data_.empty()) {
Entry& entry = data_.front();
if (target_offset == entry.file_offset) {
return true;
}
const size_t bytes_to_pop = target_offset - entry.file_offset;
if (entry.data.size() > bytes_to_pop) {
entry.data =
entry.data.slice_off(bytes_to_pop, entry.data.size() - bytes_to_pop);
entry.file_offset += bytes_to_pop;
return true;
}
data_.pop_front();
}
return target_offset == end_offset_;
}
std::optional<TraceBlobView> FileBuffer::SliceOff(size_t start_offset,
size_t length) const {
if (length == 0) {
return TraceBlobView();
}
if (start_offset + length > end_offset_) {
return std::nullopt;
}
Iterator it = FindEntryWithOffset(start_offset);
if (it == end()) {
return std::nullopt;
}
const size_t offset_from_entry_start = start_offset - it->file_offset;
const size_t bytes_in_entry = it->data.size() - offset_from_entry_start;
TraceBlobView first_blob = it->data.slice_off(
offset_from_entry_start, std::min(bytes_in_entry, length));
if (first_blob.size() == length) {
return std::move(first_blob);
}
auto buffer = TraceBlob::Allocate(length);
uint8_t* ptr = buffer.data();
memcpy(ptr, first_blob.data(), first_blob.size());
ptr += first_blob.size();
length -= first_blob.size();
++it;
while (length != 0) {
PERFETTO_DCHECK(it != end());
const size_t bytes_to_copy = std::min(length, it->data.size());
memcpy(ptr, it->data.data(), bytes_to_copy);
ptr += bytes_to_copy;
length -= bytes_to_copy;
++it;
}
return TraceBlobView(std::move(buffer));
}
FileBuffer::Iterator FileBuffer::FindEntryWithOffset(size_t offset) const {
if (offset >= end_offset_) {
return end();
}
auto it = std::upper_bound(
data_.begin(), data_.end(), offset,
[](size_t offset, const Entry& rhs) { return offset < rhs.file_offset; });
// This can only happen if too much data was popped.
PERFETTO_CHECK(it != data_.begin());
return std::prev(it);
}
} // namespace perfetto::trace_processor::util