// 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 #include #include 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 class BlockAllocator { using InternalVector = std::vector>; 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 TYPE* Create(ARGS&&... args) { static_assert( std::is_same::value || std::is_base_of::value, "TYPE does not derive from T"); auto uptr = std::make_unique(std::forward(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> objects_; }; } // namespace tint #endif // SRC_BLOCK_ALLOCATOR_H_