// Copyright (C) 2018-2020 Jakub Melka // // This file is part of PdfForQt. // // PdfForQt is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // PdfForQt 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 Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with PDFForQt. If not, see . #ifndef PDFFLATMAP_H #define PDFFLATMAP_H #include #include #include namespace pdf { /// This class behaves like std::set, but have "flat" part, and if size of the set /// is small (smaller than \p FlatSize), then no memory allocation is needed. This /// container supports inserting, deleting and searching for the object presence. template class PDFFlatMap { public: constexpr inline PDFFlatMap(); /// Inserts a key in the container. Checks, if key is already present /// in the container, in this case no insertion occurs. /// \param key Key to be inserted void insert(const Key& key); /// Erases a key in the container, if it is in the set /// \param key Key to be erased void erase(const Key& key); /// Searchs for a given key. If it is found, true is returned, false otherwise. /// \param key Key to be searched bool search(const Key& key) const; /// Returns size of the container std::size_t size() const; /// Returns true, if container is empty bool empty() const; private: /// Flat part of the set std::array m_flat; /// This iterator points to first empty position, or it is /// the last iterator (pointing to the end of the array). typename std::array::iterator m_flatEmptyPosition; std::set m_overflowContainer; }; template constexpr PDFFlatMap::PDFFlatMap() : m_flat(), m_flatEmptyPosition(m_flat.begin()), m_overflowContainer() { } template void PDFFlatMap::insert(const Key& key) { if (!search(key)) { // Try to insert key in the flat part, if possible (we are not at end of the array) if (m_flatEmptyPosition != m_flat.end()) { *m_flatEmptyPosition++ = key; } else { m_overflowContainer.insert(key); } } } template void PDFFlatMap::erase(const Key& key) { // First we must check, if the key is present in the flat part. If yes, then remove key // from the flat part and try to move one item from the overflow part to the flat part, if possible. // Otherwise check overflow part. m_flatEmptyPosition = std::remove_if(m_flat.begin(), m_flatEmptyPosition, [&key](const Key& otherKey) { return key == otherKey; }); m_overflowContainer.erase(key); if (!m_overflowContainer.empty() && m_flatEmptyPosition != m_flat.end()) { *m_flatEmptyPosition++ = *m_overflowContainer.begin(); m_overflowContainer.erase(m_overflowContainer.begin()); } } template bool PDFFlatMap::search(const Key& key) const { return std::find::const_iterator, Key>(m_flat.begin(), m_flatEmptyPosition, key) != m_flatEmptyPosition || static_cast(m_overflowContainer.count(key)); } template std::size_t PDFFlatMap::size() const { return std::distance::const_iterator>(m_flat.begin(), m_flatEmptyPosition) + m_overflowContainer.size(); } template bool PDFFlatMap::empty() const { return size() == 0; } } // namespace pdf #endif // PDFFLATMAP_H