diff --git a/src/backend/common/SerialQueue.h b/src/backend/common/SerialQueue.h index 23f6634e91..09dcbfceb4 100644 --- a/src/backend/common/SerialQueue.h +++ b/src/backend/common/SerialQueue.h @@ -27,7 +27,8 @@ namespace backend { private: using SerialPair = std::pair>; using Storage = std::vector; - using StorageIterator = typename Storage::const_iterator; + using StorageIterator = typename Storage::iterator; + using ConstStorageIterator = typename Storage::const_iterator; public: class Iterator { @@ -37,13 +38,27 @@ namespace backend { bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; - const T& operator*() const; + T& operator*() const; private: StorageIterator storageIterator; // Special case the serialIterator when it should be equal to storageIterator.begin() // otherwise we could ask storageIterator.begin() when storageIterator is storage.end() // which is invalid. storageIterator.begin() is tagged with a nullptr. + T* serialIterator; + }; + + class ConstIterator { + public: + ConstIterator(ConstStorageIterator start); + ConstIterator& operator++(); + + bool operator==(const ConstIterator& other) const; + bool operator!=(const ConstIterator& other) const; + const T& operator*() const; + + private: + ConstStorageIterator storageIterator; const T* serialIterator; }; @@ -59,6 +74,18 @@ namespace backend { StorageIterator endIt; }; + class ConstBeginEnd { + public: + ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end); + + ConstIterator begin() const; + ConstIterator end() const; + + private: + ConstStorageIterator startIt; + ConstStorageIterator endIt; + }; + // The serial must be given in (not strictly) increasing order. void Enqueue(const T& value, Serial serial); void Enqueue(T&& value, Serial serial); @@ -70,8 +97,10 @@ namespace backend { // The UpTo variants of Iterate and Clear affect all values associated to a serial // that is smaller OR EQUAL to the given serial. Iterating is done like so: // for (const T& value : queue.IterateAll()) { stuff(T); } - BeginEnd IterateAll() const; - BeginEnd IterateUpTo(Serial serial) const; + ConstBeginEnd IterateAll() const; + ConstBeginEnd IterateUpTo(Serial serial) const; + BeginEnd IterateAll(); + BeginEnd IterateUpTo(Serial serial); void Clear(); void ClearUpTo(Serial serial); @@ -80,7 +109,8 @@ namespace backend { private: // Returns the first StorageIterator that a serial bigger than serial. - StorageIterator FindUpTo(Serial serial) const; + ConstStorageIterator FindUpTo(Serial serial) const; + StorageIterator FindUpTo(Serial serial); Storage storage; }; @@ -93,7 +123,7 @@ namespace backend { if (Empty() || storage.back().first < serial) { storage.emplace_back(SerialPair(serial, {})); } - storage.back().second.push_back(value); + storage.back().second.emplace_back(value); } template @@ -103,7 +133,7 @@ namespace backend { if (Empty() || storage.back().first < serial) { storage.emplace_back(SerialPair(serial, {})); } - storage.back().second.push_back(value); + storage.back().second.emplace_back(value); } template @@ -126,12 +156,22 @@ namespace backend { } template - typename SerialQueue::BeginEnd SerialQueue::IterateAll() const { + typename SerialQueue::ConstBeginEnd SerialQueue::IterateAll() const { return {storage.begin(), storage.end()}; } template - typename SerialQueue::BeginEnd SerialQueue::IterateUpTo(Serial serial) const { + typename SerialQueue::ConstBeginEnd SerialQueue::IterateUpTo(Serial serial) const { + return {storage.begin(), FindUpTo(serial)}; + } + + template + typename SerialQueue::BeginEnd SerialQueue::IterateAll() { + return {storage.begin(), storage.end()}; + } + + template + typename SerialQueue::BeginEnd SerialQueue::IterateUpTo(Serial serial) { return {storage.begin(), FindUpTo(serial)}; } @@ -152,7 +192,16 @@ namespace backend { } template - typename SerialQueue::StorageIterator SerialQueue::FindUpTo(Serial serial) const { + typename SerialQueue::ConstStorageIterator SerialQueue::FindUpTo(Serial serial) const { + auto it = storage.begin(); + while (it != storage.end() && it->first <= serial) { + it ++; + } + return it; + } + + template + typename SerialQueue::StorageIterator SerialQueue::FindUpTo(Serial serial) { auto it = storage.begin(); while (it != storage.end() && it->first <= serial) { it ++; @@ -186,7 +235,7 @@ namespace backend { template typename SerialQueue::Iterator& SerialQueue::Iterator::operator++() { - const T* vectorData = storageIterator->second.data(); + T* vectorData = storageIterator->second.data(); if (serialIterator == nullptr) { serialIterator = vectorData + 1; @@ -213,13 +262,72 @@ namespace backend { } template - const T& SerialQueue::Iterator::operator*() const { + T& SerialQueue::Iterator::operator*() const { if (serialIterator == nullptr) { return *storageIterator->second.begin(); } return *serialIterator; } + // SerialQueue::ConstBeginEnd + + template + SerialQueue::ConstBeginEnd::ConstBeginEnd(typename SerialQueue::ConstStorageIterator start, typename SerialQueue::ConstStorageIterator end) + : startIt(start), endIt(end) { + } + + template + typename SerialQueue::ConstIterator SerialQueue::ConstBeginEnd::begin() const { + return {startIt}; + } + + template + typename SerialQueue::ConstIterator SerialQueue::ConstBeginEnd::end() const { + return {endIt}; + } + + // SerialQueue::ConstIterator + + template + SerialQueue::ConstIterator::ConstIterator(typename SerialQueue::ConstStorageIterator start) + : storageIterator(start), serialIterator(nullptr) { + } + + template + typename SerialQueue::ConstIterator& SerialQueue::ConstIterator::operator++() { + const T* vectorData = storageIterator->second.data(); + + if (serialIterator == nullptr) { + serialIterator = vectorData + 1; + } else { + serialIterator ++; + } + + if (serialIterator >= vectorData + storageIterator->second.size()) { + serialIterator = nullptr; + storageIterator ++; + } + + return *this; + } + + template + bool SerialQueue::ConstIterator::operator==(const typename SerialQueue::ConstIterator& other) const { + return other.storageIterator == storageIterator && other.serialIterator == serialIterator; + } + + template + bool SerialQueue::ConstIterator::operator!=(const typename SerialQueue::ConstIterator& other) const { + return !(*this == other); + } + + template + const T& SerialQueue::ConstIterator::operator*() const { + if (serialIterator == nullptr) { + return *storageIterator->second.begin(); + } + return *serialIterator; + } } #endif // BACKEND_COMMON_SERIALQUEUE_H_