blob: 44de75c52b16c868898e5a35b5018b684956cb5a [file] [log] [blame]
// 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_