From 54c60d9a18d103011a12939c5029dd35a8e9e200 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 22 Aug 2024 21:44:06 +0200 Subject: Start on file chooser, page stack --- include/SafeVector.hpp | 127 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 include/SafeVector.hpp (limited to 'include/SafeVector.hpp') diff --git a/include/SafeVector.hpp b/include/SafeVector.hpp new file mode 100644 index 0000000..cea9cb9 --- /dev/null +++ b/include/SafeVector.hpp @@ -0,0 +1,127 @@ +#pragma once + +#include +#include +#include + +// A vector that can be modified while iterating +template +class SafeVector { +public: + using PointerType = typename std::pointer_traits::element_type*; + + void push_back(T item) { + data.push_back(std::move(item)); + } + + // Safe to call when vector is empty + void pop_back() { + if(!data.empty()) + data.pop_back(); + } + + // Might not remove the data immediately if inside for_each loop. + // In that case the item is remove at the end of the loop. + void remove(PointerType item_to_remove) { + if(for_each_depth == 0) + remove_item(item_to_remove); + else + remove_queue.push_back(item_to_remove); + } + + // Safe to call when vector is empty, in which case it returns nullptr + T* back() { + if(data.empty()) + return nullptr; + else + return &data.back(); + } + + void clear() { + data.clear(); + remove_queue.clear(); + } + + // Return true from |callback| to continue. This function returns false if |callback| returned false + bool for_each(std::function callback) { + bool result = true; + ++for_each_depth; + + for(size_t i = 0; i < data.size(); ++i) { + result = callback(data[i]); + if(!result) + break; + } + + --for_each_depth; + if(for_each_depth == 0) { + for(PointerType item_to_remove : remove_queue) { + remove_item(item_to_remove); + } + remove_queue.clear(); + } + + return result; + } + + // Return true from |callback| to continue. This function returns false if |callback| returned false + bool for_each_reverse(std::function callback) { + bool result = true; + ++for_each_depth; + + int i = (int)data.size() - 1; + while(true) { + // pop_back can be called while iterating so handle that case + if(i >= (int)data.size()) + i = (int)data.size() - 1; + + if(i < 0) + break; + + result = callback(data[i]); + if(!result) + break; + + --i; + } + + --for_each_depth; + if(for_each_depth == 0) { + for(PointerType item_to_remove : remove_queue) { + remove_item(item_to_remove); + } + remove_queue.clear(); + } + + return result; + } + + T& operator[](size_t index) { + return data[index]; + } + + const T& operator[](size_t index) const { + return data[index]; + } + + size_t size() const { + return data.size(); + } + + bool empty() const { + return data.empty(); + } +private: + void remove_item(PointerType item_to_remove) { + for(auto it = data.begin(), end = data.end(); it != end; ++it) { + if(&*(*it) == item_to_remove) { + data.erase(it); + return; + } + } + } +private: + std::vector data; + std::vector remove_queue; + int for_each_depth = 0; +}; \ No newline at end of file -- cgit v1.2.3