// Copyright 2018 The Dawn 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 COMMON_SERIALSTORAGE_H_ #define COMMON_SERIALSTORAGE_H_ #include "common/Assert.h" #include #include template struct SerialStorageTraits {}; template class SerialStorage { protected: using Serial = typename SerialStorageTraits::Serial; using Value = typename SerialStorageTraits::Value; using Storage = typename SerialStorageTraits::Storage; using StorageIterator = typename SerialStorageTraits::StorageIterator; using ConstStorageIterator = typename SerialStorageTraits::ConstStorageIterator; public: class Iterator { public: Iterator(StorageIterator start); Iterator& operator++(); bool operator==(const Iterator& other) const; bool operator!=(const Iterator& other) const; Value& operator*() const; private: StorageIterator mStorageIterator; // Special case the mSerialIterator when it should be equal to mStorageIterator.begin() // otherwise we could ask mStorageIterator.begin() when mStorageIterator is mStorage.end() // which is invalid. mStorageIterator.begin() is tagged with a nullptr. Value* mSerialIterator; }; class ConstIterator { public: ConstIterator(ConstStorageIterator start); ConstIterator& operator++(); bool operator==(const ConstIterator& other) const; bool operator!=(const ConstIterator& other) const; const Value& operator*() const; private: ConstStorageIterator mStorageIterator; const Value* mSerialIterator; }; class BeginEnd { public: BeginEnd(StorageIterator start, StorageIterator end); Iterator begin() const; Iterator end() const; private: StorageIterator mStartIt; StorageIterator mEndIt; }; class ConstBeginEnd { public: ConstBeginEnd(ConstStorageIterator start, ConstStorageIterator end); ConstIterator begin() const; ConstIterator end() const; private: ConstStorageIterator mStartIt; ConstStorageIterator mEndIt; }; // Derived classes may specialize constraits for elements stored // Ex.) SerialQueue enforces that the serial must be given in (not strictly) // increasing order template void Enqueue(Params&&... args, Serial serial) { Derived::Enqueue(std::forward(args)..., serial); } bool Empty() const; // 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); } ConstBeginEnd IterateAll() const; ConstBeginEnd IterateUpTo(Serial serial) const; BeginEnd IterateAll(); BeginEnd IterateUpTo(Serial serial); void Clear(); void ClearUpTo(Serial serial); Serial FirstSerial() const; Serial LastSerial() const; protected: // Returns the first StorageIterator that a serial bigger than serial. ConstStorageIterator FindUpTo(Serial serial) const; StorageIterator FindUpTo(Serial serial); Storage mStorage; }; // SerialStorage template bool SerialStorage::Empty() const { return mStorage.empty(); } template typename SerialStorage::ConstBeginEnd SerialStorage::IterateAll() const { return {mStorage.begin(), mStorage.end()}; } template typename SerialStorage::ConstBeginEnd SerialStorage::IterateUpTo( Serial serial) const { return {mStorage.begin(), FindUpTo(serial)}; } template typename SerialStorage::BeginEnd SerialStorage::IterateAll() { return {mStorage.begin(), mStorage.end()}; } template typename SerialStorage::BeginEnd SerialStorage::IterateUpTo(Serial serial) { return {mStorage.begin(), FindUpTo(serial)}; } template void SerialStorage::Clear() { mStorage.clear(); } template void SerialStorage::ClearUpTo(Serial serial) { mStorage.erase(mStorage.begin(), FindUpTo(serial)); } template typename SerialStorage::Serial SerialStorage::FirstSerial() const { DAWN_ASSERT(!Empty()); return mStorage.begin()->first; } template typename SerialStorage::Serial SerialStorage::LastSerial() const { DAWN_ASSERT(!Empty()); return mStorage.back().first; } template typename SerialStorage::ConstStorageIterator SerialStorage::FindUpTo( Serial serial) const { auto it = mStorage.begin(); while (it != mStorage.end() && it->first <= serial) { it++; } return it; } template typename SerialStorage::StorageIterator SerialStorage::FindUpTo(Serial serial) { auto it = mStorage.begin(); while (it != mStorage.end() && it->first <= serial) { it++; } return it; } // SerialStorage::BeginEnd template SerialStorage::BeginEnd::BeginEnd(typename SerialStorage::StorageIterator start, typename SerialStorage::StorageIterator end) : mStartIt(start), mEndIt(end) { } template typename SerialStorage::Iterator SerialStorage::BeginEnd::begin() const { return {mStartIt}; } template typename SerialStorage::Iterator SerialStorage::BeginEnd::end() const { return {mEndIt}; } // SerialStorage::Iterator template SerialStorage::Iterator::Iterator(typename SerialStorage::StorageIterator start) : mStorageIterator(start), mSerialIterator(nullptr) { } template typename SerialStorage::Iterator& SerialStorage::Iterator::operator++() { Value* vectorData = mStorageIterator->second.data(); if (mSerialIterator == nullptr) { mSerialIterator = vectorData + 1; } else { mSerialIterator++; } if (mSerialIterator >= vectorData + mStorageIterator->second.size()) { mSerialIterator = nullptr; mStorageIterator++; } return *this; } template bool SerialStorage::Iterator::operator==( const typename SerialStorage::Iterator& other) const { return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator; } template bool SerialStorage::Iterator::operator!=( const typename SerialStorage::Iterator& other) const { return !(*this == other); } template typename SerialStorage::Value& SerialStorage::Iterator::operator*() const { if (mSerialIterator == nullptr) { return *mStorageIterator->second.begin(); } return *mSerialIterator; } // SerialStorage::ConstBeginEnd template SerialStorage::ConstBeginEnd::ConstBeginEnd( typename SerialStorage::ConstStorageIterator start, typename SerialStorage::ConstStorageIterator end) : mStartIt(start), mEndIt(end) { } template typename SerialStorage::ConstIterator SerialStorage::ConstBeginEnd::begin() const { return {mStartIt}; } template typename SerialStorage::ConstIterator SerialStorage::ConstBeginEnd::end() const { return {mEndIt}; } // SerialStorage::ConstIterator template SerialStorage::ConstIterator::ConstIterator( typename SerialStorage::ConstStorageIterator start) : mStorageIterator(start), mSerialIterator(nullptr) { } template typename SerialStorage::ConstIterator& SerialStorage::ConstIterator::operator++() { const Value* vectorData = mStorageIterator->second.data(); if (mSerialIterator == nullptr) { mSerialIterator = vectorData + 1; } else { mSerialIterator++; } if (mSerialIterator >= vectorData + mStorageIterator->second.size()) { mSerialIterator = nullptr; mStorageIterator++; } return *this; } template bool SerialStorage::ConstIterator::operator==( const typename SerialStorage::ConstIterator& other) const { return other.mStorageIterator == mStorageIterator && other.mSerialIterator == mSerialIterator; } template bool SerialStorage::ConstIterator::operator!=( const typename SerialStorage::ConstIterator& other) const { return !(*this == other); } template const typename SerialStorage::Value& SerialStorage::ConstIterator::operator*() const { if (mSerialIterator == nullptr) { return *mStorageIterator->second.begin(); } return *mSerialIterator; } #endif // COMMON_SERIALSTORAGE_H_