1

Vector: Add lazy init and size checking

This commit is contained in:
2022-12-08 15:35:20 +01:00
parent 84a3fb86f4
commit 0ef9e81d50

View File

@ -12,7 +12,9 @@
namespace Container { namespace Container {
/** /**
* This class implements a dynamically allocated array list. * This class implements a dynamically allocated array list with
* runtime bounds checking and iterator support.
* The buffer is allocated lazily and can grow in size (shrinking is not implemented).
* *
* @tparam T The type of the held objects * @tparam T The type of the held objects
*/ */
@ -22,13 +24,7 @@ public:
using iterator = ContinuousIterator<T>; using iterator = ContinuousIterator<T>;
public: public:
explicit Vector(bool lazy = false) { Vector() = default;
if (!lazy) {
// I added this as a workaround, the scheduler can't initialize the queues right
// away because when the scheduler is started the allocator is not ready
init();
}
};
// Initialize like this: bse::vector<int> vec {1, 2, 3, 4, 5}; // Initialize like this: bse::vector<int> vec {1, 2, 3, 4, 5};
/** /**
@ -98,23 +94,39 @@ public:
} }
// Iterator // Iterator
iterator begin() { return iterator(&buf[0]); } iterator begin() {
initIfNecessary();
return iterator(&buf[0]);
}
iterator begin() const { return iterator(&buf[0]); } iterator begin() const {
initIfNecessary();
return iterator(&buf[0]);
}
iterator end() { return iterator(&buf[size()]); } iterator end() {
initIfNecessary();
return iterator(&buf[size()]);
}
iterator end() const { return iterator(&buf[size()]); } iterator end() const {
initIfNecessary();
return iterator(&buf[size()]);
}
// Add elements // Add elements
// https://en.cppreference.com/w/cpp/container/vector/push_back // https://en.cppreference.com/w/cpp/container/vector/push_back
void push_back(const T &copy) { void push_back(const T &copy) {
initIfNecessary();
buf[size()] = copy; buf[size()] = copy;
++sz; ++sz;
min_expand(); min_expand();
} }
void push_back(T &&move) { void push_back(T &&move) {
initIfNecessary();
buf[size()] = std::move(move); buf[size()] = std::move(move);
++sz; ++sz;
min_expand(); min_expand();
@ -123,6 +135,11 @@ public:
// https://en.cppreference.com/w/cpp/container/vector/insert // https://en.cppreference.com/w/cpp/container/vector/insert
// The element will be inserted before the pos iterator, pos can be the end() iterator // The element will be inserted before the pos iterator, pos can be the end() iterator
iterator insert(iterator pos, const T &copy) { iterator insert(iterator pos, const T &copy) {
if (pos > end()) {
// TODO: Exception
}
initIfNecessary();
std::size_t idx = distance(begin(), pos); // begin() does init if necessary std::size_t idx = distance(begin(), pos); // begin() does init if necessary
copy_right(idx); // nothing will be done if pos == end() copy_right(idx); // nothing will be done if pos == end()
buf[idx] = copy; buf[idx] = copy;
@ -132,6 +149,11 @@ public:
} }
iterator insert(iterator pos, T &&move) { iterator insert(iterator pos, T &&move) {
if (pos > end()) {
// TODO: Exception
}
initIfNecessary();
std::size_t idx = distance(begin(), pos); // begin() does init if necessary std::size_t idx = distance(begin(), pos); // begin() does init if necessary
copy_right(idx); copy_right(idx);
buf[idx] = std::move(move); buf[idx] = std::move(move);
@ -144,6 +166,9 @@ public:
// https://en.cppreference.com/w/cpp/container/vector/erase // https://en.cppreference.com/w/cpp/container/vector/erase
// Returns the iterator after the removed element, pos can't be end() iterator // Returns the iterator after the removed element, pos can't be end() iterator
iterator erase(iterator pos) { iterator erase(iterator pos) {
if (sz == 0 || pos >= end()) {
// TODO: Exception
}
std::size_t idx = distance(begin(), pos); std::size_t idx = distance(begin(), pos);
copy_left(idx); copy_left(idx);
--sz; --sz;
@ -153,26 +178,44 @@ public:
// Access // Access
T &front() { T &front() {
if (sz == 0) {
// TODO: Exception
}
return buf[0]; return buf[0];
} }
const T &front() const { const T &front() const {
if (sz == 0) {
// TODO: Exception
}
return buf[0]; return buf[0];
} }
T &back() { T &back() {
if (sz == 0) {
// TODO: Exception
}
return buf[sz - 1]; return buf[sz - 1];
} }
const T &back() const { const T &back() const {
if (sz == 0) {
// TODO: Exception
}
return buf[sz - 1]; return buf[sz - 1];
} }
T &operator[](std::size_t pos) { T &operator[](std::size_t pos) {
if (pos >= sz) {
// TODO: Exception
}
return buf[pos]; return buf[pos];
} }
const T &operator[](std::size_t pos) const { const T &operator[](std::size_t pos) const {
if (pos >= sz) {
// TODO: Exception
}
return buf[pos]; return buf[pos];
} }
@ -196,7 +239,7 @@ public:
// The first reserve could allocate double if cap != default_cap // The first reserve could allocate double if cap != default_cap
if (buf == nullptr) { if (buf == nullptr) {
// Directly init with correct size // Directly init with correct size
init(cap); initIfNecessary(cap);
return; return;
} }
@ -221,12 +264,13 @@ private:
std::size_t buf_cap = 0; // The current capacity of the buffer std::size_t buf_cap = 0; // The current capacity of the buffer
private: private:
void init(std::size_t cap = Vector::default_cap) { void initIfNecessary(std::size_t cap = Vector::default_cap) {
if (buf != nullptr) { if (buf != nullptr) {
return; return;
} }
buf = new T[cap]; buf = new T[cap];
buf_cap = cap; buf_cap = cap;
sz = 0;
} }
[[nodiscard]] std::size_t get_rem_cap() const { [[nodiscard]] std::size_t get_rem_cap() const {
@ -237,7 +281,7 @@ private:
void min_expand() { void min_expand() {
// Init if necessary // Init if necessary
if (buf == nullptr) { if (buf == nullptr) {
init(); initIfNecessary();
return; // Dont have to realloc after init return; // Dont have to realloc after init
} }