/* * Copyright (C) 2014 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef UBUNTUGESTURES_POOL_H #define UBUNTUGESTURES_POOL_H #include #include "UbuntuGesturesGlobal.h" /* An object pool. Avoids unnecessary creations/initializations and deletions/destructions of items. Useful in a scenario where items are created and destroyed very frequently but the total number of items at any given time remains small. They're stored in a unordered fashion. To be used in Pool, ItemType needs to have the following methods: - ItemType(); A constructor that takes no parameters. An object contructed with it must return false if isValid() is called. - bool isValid() const; Returns wheter the object holds a valid , "filled" state or is empty. Used by Pool to check if the slot occupied by this object is actually available. - void reset(); Resets the object to its initial, empty, state. After calling this method, isValid() must return false. */ template class Pool { public: Pool() : m_lastUsedIndex(-1) { } class Iterator { public: Iterator() : index(-1), item(nullptr) {} Iterator(int index, ItemType *item) : index(index), item(item) {} ItemType *operator->() const { return item; } ItemType &operator*() const { return *item; } ItemType &value() const { return *item; } Iterator &operator= (const Iterator& other) { index = other.index; item = other.item; // by convention, always return *this return *this; } operator bool() const { return item != nullptr; } int index; ItemType *item; }; ItemType &getEmptySlot() { Q_ASSERT(m_lastUsedIndex < m_slots.size()); // Look for an in-between vacancy first for (int i = 0; i < m_lastUsedIndex; ++i) { ItemType &item = m_slots[i]; if (!item.isValid()) { return item; } } ++m_lastUsedIndex; if (m_lastUsedIndex >= m_slots.size()) { m_slots.resize(m_lastUsedIndex + 1); } return m_slots[m_lastUsedIndex]; } void freeSlot(Iterator &iterator) { m_slots[iterator.index].reset(); if (iterator.index == m_lastUsedIndex) { do { --m_lastUsedIndex; } while (m_lastUsedIndex >= 0 && !m_slots.at(m_lastUsedIndex).isValid()); } } // Iterates through all valid items (i.e. the occupied slots) // calling the given function, with the option of ending the loop early. // // bool Func(Iterator& item) // // Returning true means it wants to continue the "for" loop, false // terminates the loop. template void forEach(Func func) { Iterator it; for (it.index = 0; it.index <= m_lastUsedIndex; ++it.index) { it.item = &m_slots[it.index]; if (!it.item->isValid()) continue; if (!func(it)) break; } } bool isEmpty() const { return m_lastUsedIndex == -1; } private: QVector m_slots; int m_lastUsedIndex; }; #endif // UBUNTUGESTURES_POOL_H