| // Copyright 2021 The Tint Authors. |
| // |
| // 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_BLOCK_ALLOCATOR_H_ |
| #define SRC_BLOCK_ALLOCATOR_H_ |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| namespace tint { |
| |
| /// A container and allocator of objects of (or deriving from) the template type |
| /// `T`. |
| /// Objects are allocated by calling Create(), and are owned by the |
| /// BlockAllocator. When the BlockAllocator is destructed, all constructed |
| /// objects are automatically destructed and freed. |
| /// |
| /// Objects held by the BlockAllocator can be iterated over using a |
| /// View or ConstView. |
| template <typename T> |
| class BlockAllocator { |
| using InternalVector = std::vector<std::unique_ptr<T>>; |
| using InternalIterator = typename InternalVector::const_iterator; |
| |
| public: |
| class View; |
| class ConstView; |
| |
| /// Constructor |
| BlockAllocator() = default; |
| /// Move constructor |
| BlockAllocator(BlockAllocator&&) = default; |
| /// Move assignment operator |
| /// @return this BlockAllocator |
| BlockAllocator& operator=(BlockAllocator&&) = default; |
| |
| /// An iterator for the objects owned by the BlockAllocator. |
| class Iterator { |
| public: |
| /// Equality operator |
| /// @param other the iterator to compare this iterator to |
| /// @returns true if this iterator is equal to other |
| bool operator==(const Iterator& other) const { return it_ == other.it_; } |
| /// Inequality operator |
| /// @param other the iterator to compare this iterator to |
| /// @returns true if this iterator is not equal to other |
| bool operator!=(const Iterator& other) const { return it_ != other.it_; } |
| /// Advances the iterator |
| /// @returns this iterator |
| Iterator& operator++() { |
| ++it_; |
| return *this; |
| } |
| /// @returns the pointer to the object at the current iterator position |
| T* operator*() const { return it_->get(); } |
| |
| private: |
| friend View; // Keep internal iterator impl private. |
| explicit Iterator(InternalIterator it) : it_(it) {} |
| InternalIterator it_; |
| }; |
| |
| /// A const iterator for the objects owned by the BlockAllocator. |
| class ConstIterator { |
| public: |
| /// Equality operator |
| /// @param other the iterator to compare this iterator to |
| /// @returns true if this iterator is equal to other |
| bool operator==(const ConstIterator& other) const { |
| return it_ == other.it_; |
| } |
| /// Inequality operator |
| /// @param other the iterator to compare this iterator to |
| /// @returns true if this iterator is not equal to other |
| bool operator!=(const ConstIterator& other) const { |
| return it_ != other.it_; |
| } |
| /// Advances the iterator |
| /// @returns this iterator |
| ConstIterator& operator++() { |
| ++it_; |
| return *this; |
| } |
| /// @returns the pointer to the object at the current iterator position |
| T* operator*() const { return it_->get(); } |
| |
| private: |
| friend ConstView; // Keep internal iterator impl private. |
| explicit ConstIterator(InternalIterator it) : it_(it) {} |
| InternalIterator it_; |
| }; |
| |
| /// View provides begin() and end() methods for looping over the objects owned |
| /// by the BlockAllocator. |
| class View { |
| public: |
| /// @returns an iterator to the beginning of the view |
| Iterator begin() const { return Iterator(allocator_->objects_.begin()); } |
| /// @returns an iterator to the end of the view |
| Iterator end() const { return Iterator(allocator_->objects_.end()); } |
| |
| private: |
| friend BlockAllocator; // For BlockAllocator::operator View() |
| explicit View(BlockAllocator const* allocator) : allocator_(allocator) {} |
| BlockAllocator const* const allocator_; |
| }; |
| |
| /// ConstView provides begin() and end() methods for looping over the objects |
| /// owned by the BlockAllocator. |
| class ConstView { |
| public: |
| /// @returns an iterator to the beginning of the view |
| ConstIterator begin() const { |
| return ConstIterator(allocator_->objects_.begin()); |
| } |
| /// @returns an iterator to the end of the view |
| ConstIterator end() const { |
| return ConstIterator(allocator_->objects_.end()); |
| } |
| |
| private: |
| friend BlockAllocator; // For BlockAllocator::operator ConstView() |
| explicit ConstView(BlockAllocator const* allocator) |
| : allocator_(allocator) {} |
| BlockAllocator const* const allocator_; |
| }; |
| |
| /// @return a View of all objects owned by this BlockAllocator |
| View Objects() { return View(this); } |
| /// @return a ConstView of all objects owned by this BlockAllocator |
| ConstView Objects() const { return ConstView(this); } |
| |
| /// Creates a new `TYPE` owned by the BlockAllocator. |
| /// When the BlockAllocator is destructed the object will be destructed and |
| /// freed. |
| /// @param args the arguments to pass to the type constructor |
| /// @returns the pointer to the constructed object |
| template <typename TYPE = T, typename... ARGS> |
| TYPE* Create(ARGS&&... args) { |
| static_assert( |
| std::is_same<T, TYPE>::value || std::is_base_of<T, TYPE>::value, |
| "TYPE does not derive from T"); |
| auto uptr = std::make_unique<TYPE>(std::forward<ARGS>(args)...); |
| auto* ptr = uptr.get(); |
| objects_.emplace_back(std::move(uptr)); |
| return ptr; |
| } |
| |
| private: |
| BlockAllocator(const BlockAllocator&) = delete; |
| BlockAllocator& operator=(const BlockAllocator&) = delete; |
| |
| std::vector<std::unique_ptr<T>> objects_; |
| }; |
| |
| } // namespace tint |
| |
| #endif // SRC_BLOCK_ALLOCATOR_H_ |