1 // Copyright 2021 The Tint Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef SRC_BLOCK_ALLOCATOR_H_ 16 #define SRC_BLOCK_ALLOCATOR_H_ 17 18 #include <memory> 19 #include <utility> 20 #include <vector> 21 22 namespace tint { 23 24 /// A container and allocator of objects of (or deriving from) the template type 25 /// `T`. 26 /// Objects are allocated by calling Create(), and are owned by the 27 /// BlockAllocator. When the BlockAllocator is destructed, all constructed 28 /// objects are automatically destructed and freed. 29 /// 30 /// Objects held by the BlockAllocator can be iterated over using a 31 /// View or ConstView. 32 template <typename T> 33 class BlockAllocator { 34 using InternalVector = std::vector<std::unique_ptr<T>>; 35 using InternalIterator = typename InternalVector::const_iterator; 36 37 public: 38 class View; 39 class ConstView; 40 41 /// Constructor 42 BlockAllocator() = default; 43 /// Move constructor 44 BlockAllocator(BlockAllocator&&) = default; 45 /// Move assignment operator 46 /// @return this BlockAllocator 47 BlockAllocator& operator=(BlockAllocator&&) = default; 48 49 /// An iterator for the objects owned by the BlockAllocator. 50 class Iterator { 51 public: 52 /// Equality operator 53 /// @param other the iterator to compare this iterator to 54 /// @returns true if this iterator is equal to other 55 bool operator==(const Iterator& other) const { return it_ == other.it_; } 56 /// Inequality operator 57 /// @param other the iterator to compare this iterator to 58 /// @returns true if this iterator is not equal to other 59 bool operator!=(const Iterator& other) const { return it_ != other.it_; } 60 /// Advances the iterator 61 /// @returns this iterator 62 Iterator& operator++() { 63 ++it_; 64 return *this; 65 } 66 /// @returns the pointer to the object at the current iterator position 67 T* operator*() const { return it_->get(); } 68 69 private: 70 friend View; // Keep internal iterator impl private. Iterator(InternalIterator it)71 explicit Iterator(InternalIterator it) : it_(it) {} 72 InternalIterator it_; 73 }; 74 75 /// A const iterator for the objects owned by the BlockAllocator. 76 class ConstIterator { 77 public: 78 /// Equality operator 79 /// @param other the iterator to compare this iterator to 80 /// @returns true if this iterator is equal to other 81 bool operator==(const ConstIterator& other) const { 82 return it_ == other.it_; 83 } 84 /// Inequality operator 85 /// @param other the iterator to compare this iterator to 86 /// @returns true if this iterator is not equal to other 87 bool operator!=(const ConstIterator& other) const { 88 return it_ != other.it_; 89 } 90 /// Advances the iterator 91 /// @returns this iterator 92 ConstIterator& operator++() { 93 ++it_; 94 return *this; 95 } 96 /// @returns the pointer to the object at the current iterator position 97 T* operator*() const { return it_->get(); } 98 99 private: 100 friend ConstView; // Keep internal iterator impl private. ConstIterator(InternalIterator it)101 explicit ConstIterator(InternalIterator it) : it_(it) {} 102 InternalIterator it_; 103 }; 104 105 /// View provides begin() and end() methods for looping over the objects owned 106 /// by the BlockAllocator. 107 class View { 108 public: 109 /// @returns an iterator to the beginning of the view begin()110 Iterator begin() const { return Iterator(allocator_->objects_.begin()); } 111 /// @returns an iterator to the end of the view end()112 Iterator end() const { return Iterator(allocator_->objects_.end()); } 113 114 private: 115 friend BlockAllocator; // For BlockAllocator::operator View() View(BlockAllocator const * allocator)116 explicit View(BlockAllocator const* allocator) : allocator_(allocator) {} 117 BlockAllocator const* const allocator_; 118 }; 119 120 /// ConstView provides begin() and end() methods for looping over the objects 121 /// owned by the BlockAllocator. 122 class ConstView { 123 public: 124 /// @returns an iterator to the beginning of the view begin()125 ConstIterator begin() const { 126 return ConstIterator(allocator_->objects_.begin()); 127 } 128 /// @returns an iterator to the end of the view end()129 ConstIterator end() const { 130 return ConstIterator(allocator_->objects_.end()); 131 } 132 133 private: 134 friend BlockAllocator; // For BlockAllocator::operator ConstView() ConstView(BlockAllocator const * allocator)135 explicit ConstView(BlockAllocator const* allocator) 136 : allocator_(allocator) {} 137 BlockAllocator const* const allocator_; 138 }; 139 140 /// @return a View of all objects owned by this BlockAllocator Objects()141 View Objects() { return View(this); } 142 /// @return a ConstView of all objects owned by this BlockAllocator Objects()143 ConstView Objects() const { return ConstView(this); } 144 145 /// Creates a new `TYPE` owned by the BlockAllocator. 146 /// When the BlockAllocator is destructed the object will be destructed and 147 /// freed. 148 /// @param args the arguments to pass to the type constructor 149 /// @returns the pointer to the constructed object 150 template <typename TYPE = T, typename... ARGS> Create(ARGS &&...args)151 TYPE* Create(ARGS&&... args) { 152 static_assert( 153 std::is_same<T, TYPE>::value || std::is_base_of<T, TYPE>::value, 154 "TYPE does not derive from T"); 155 auto uptr = std::make_unique<TYPE>(std::forward<ARGS>(args)...); 156 auto* ptr = uptr.get(); 157 objects_.emplace_back(std::move(uptr)); 158 return ptr; 159 } 160 161 private: 162 BlockAllocator(const BlockAllocator&) = delete; 163 BlockAllocator& operator=(const BlockAllocator&) = delete; 164 165 std::vector<std::unique_ptr<T>> objects_; 166 }; 167 168 } // namespace tint 169 170 #endif // SRC_BLOCK_ALLOCATOR_H_ 171