blob: 34e9206c80ab046d873d55d615a670c5709bc358 [file] [log] [blame]
#ifndef AOS_CONTAINERS_SIZED_ARRAY_H_
#define AOS_CONTAINERS_SIZED_ARRAY_H_
#include <array>
namespace aos {
// An array along with a variable size. This is a simple variable-size container
// with a fixed maximum size.
//
// Note that it default-constructs N T instances at construction time. This
// simplifies the internal bookkeeping a lot (I believe this can be
// all-constexpr in C++17), but makes it a poor choice for complex T.
template <typename T, size_t N>
class SizedArray {
private:
using array = std::array<T, N>;
public:
using value_type = typename array::value_type;
using size_type = typename array::size_type;
using difference_type = typename array::difference_type;
using reference = typename array::reference;
using const_reference = typename array::const_reference;
using pointer = typename array::pointer;
using const_pointer = typename array::const_pointer;
using iterator = typename array::iterator;
using const_iterator = typename array::const_iterator;
using reverse_iterator = typename array::reverse_iterator;
using const_reverse_iterator = typename array::const_reverse_iterator;
constexpr SizedArray() = default;
SizedArray(const SizedArray &) = default;
SizedArray(SizedArray &&) = default;
SizedArray &operator=(const SizedArray &) = default;
SizedArray &operator=(SizedArray &&) = default;
bool operator==(const SizedArray &other) const {
if (other.size() != size()) {
return false;
}
for (size_t i = 0; i < size(); ++i) {
if (other[i] != (*this)[i]) {
return false;
}
}
return true;
}
bool operator!=(const SizedArray &other) const {
return !(*this == other);
}
reference at(size_t i) {
check_index(i);
return array_.at(i);
}
const_reference at(size_t i) const {
check_index(i);
return array_.at(i);
}
reference operator[](size_t i) { return array_[i]; }
const_reference operator[](size_t i) const { return array_[i]; }
reference front() { return array_.front(); }
const_reference front() const { return array_.front(); }
reference back() { return array_[size_ - 1]; }
const_reference back() const { return array_[size_ - 1]; }
T *data() { return array_.data(); }
const T *data() const { return array_.data(); }
iterator begin() { return array_.begin(); }
const_iterator begin() const { return array_.begin(); }
const_iterator cbegin() const { return array_.cbegin(); }
iterator end() { return array_.begin() + size_; }
const_iterator end() const { return array_.begin() + size_; }
const_iterator cend() const { return array_.cbegin() + size_; }
reverse_iterator rbegin() { return array_.rend() - size_; }
const_reverse_iterator rbegin() const { return array_.rend() - size_; }
const_reverse_iterator crbegin() const { return array_.crend() - size_; }
reverse_iterator rend() { return array_.rend(); }
const_reverse_iterator rend() const { return array_.rend(); }
const_reverse_iterator crend() const { return array_.crend(); }
bool empty() const { return size_ == 0; }
bool full() const { return size() == max_size(); }
size_t size() const { return size_; }
constexpr size_t max_size() const { return array_.max_size(); }
void push_back(const T &t) {
array_.at(size_) = t;
++size_;
}
void push_back(T &&t) {
array_.at(size_) = std::move(t);
++size_;
}
void pop_back() {
if (empty()) {
__builtin_trap();
}
--size_;
}
void clear() { size_ = 0; }
// These allow access to the underlying storage. The data here may be outside
// the current logical extents of the container.
const array &backing_array() const { return array_; }
array *mutable_backing_array() { return &array_; }
void set_size(size_t size) { size_ = size; }
private:
void check_index(size_t i) const {
if (i >= size_) {
__builtin_trap();
}
}
array array_;
size_t size_ = 0;
};
} // namespace aos
#endif // AOS_CONTAINERS_SIZED_ARRAY_H_