| /* | |
| * Copyright (C) 2025 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. | |
| */ | |
| #ifndef SRC_TRACE_PROCESSOR_DATAFRAME_IMPL_SLAB_H_ | |
| #define SRC_TRACE_PROCESSOR_DATAFRAME_IMPL_SLAB_H_ | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <type_traits> | |
| #include "perfetto/ext/base/utils.h" | |
| #include "perfetto/public/compiler.h" | |
| namespace perfetto::trace_processor::dataframe::impl { | |
| namespace internal { | |
| static constexpr bool IsPowerOfTwo(size_t n) { | |
| return (n & (n - 1)) == 0; | |
| } | |
| } // namespace internal | |
| // A memory-aligned contiguous block of trivially constructible and destructible | |
| // elements. Basically just a thin wrapper around a std::unique_ptr and a size | |
| // but with enforced alignment and additional compile-time checks. | |
| // | |
| // This class enforces several important constraints: | |
| // - Elements must be trivially constructible and destructible | |
| // | |
| // Usage example: | |
| // auto slab = Slab<float>::Alloc(1024); // Allocates space for 1024 floats | |
| // for (size_t i = 0; i < slab.size(); ++i) { | |
| // slab[i] = static_cast<float>(i); | |
| // } | |
| template <typename T> | |
| class Slab { | |
| public: | |
| static_assert(std::is_trivially_constructible_v<T>, | |
| "Slab elements must be trivially constructible"); | |
| static_assert(std::is_trivially_destructible_v<T>, | |
| "Slab elements must be trivially destructible"); | |
| using value_type = T; | |
| using const_iterator = const T*; | |
| // Default constructor creates an empty slab. | |
| Slab() = default; | |
| // Move operations are supported. | |
| constexpr Slab(Slab&&) = default; | |
| constexpr Slab& operator=(Slab&&) = default; | |
| // Copy operations are deleted to avoid accidental copies. | |
| Slab(const Slab&) = delete; | |
| Slab& operator=(const Slab&) = delete; | |
| // Allocates a new slab with the specified number of elements. | |
| // | |
| // size: Number of elements to allocate space for. | |
| // Returns a new Slab object with the requested capacity. | |
| static Slab<T> Alloc(uint64_t size) { | |
| return Slab( | |
| static_cast<T*>(base::AlignedAlloc(alignof(T), size * sizeof(T))), | |
| size); | |
| } | |
| // Returns a pointer to the underlying data. | |
| PERFETTO_ALWAYS_INLINE const T* data() const { return data_.get(); } | |
| PERFETTO_ALWAYS_INLINE T* data() { return data_.get(); } | |
| // Returns the number of elements in the slab. | |
| PERFETTO_ALWAYS_INLINE uint64_t size() const { return size_; } | |
| // Returns iterators for range-based for loops. | |
| PERFETTO_ALWAYS_INLINE T* begin() const { return data_.get(); } | |
| PERFETTO_ALWAYS_INLINE T* end() const { return data_.get() + size_; } | |
| // Provides indexed access to elements. | |
| PERFETTO_ALWAYS_INLINE T& operator[](uint64_t i) const { | |
| return data_.get()[i]; | |
| } | |
| private: | |
| // Constructor used by Alloc. | |
| Slab(T* data, uint64_t size) : data_(data), size_(size) {} | |
| // Aligned unique pointer that holds the allocated memory. | |
| base::AlignedUniquePtr<T> data_; | |
| // Number of elements in the slab. | |
| uint64_t size_ = 0; | |
| }; | |
| } // namespace perfetto::trace_processor::dataframe::impl | |
| #endif // SRC_TRACE_PROCESSOR_DATAFRAME_IMPL_SLAB_H_ |