diff --git a/src/blackmisc/mapbuilder.h b/src/blackmisc/mapbuilder.h new file mode 100644 index 000000000..b92560eeb --- /dev/null +++ b/src/blackmisc/mapbuilder.h @@ -0,0 +1,74 @@ +/* Copyright (C) 2021 + * swift project Community / Contributors + * + * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level + * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, + * or distributed except according to the terms contained in the LICENSE file. + */ + +//! \file + +#ifndef BLACKMISC_MAPBUILDER_H +#define BLACKMISC_MAPBUILDER_H + +#include "blackmisc/blackmiscexport.h" +#include "blackmisc/range.h" +#include +#include +#include +#include +#include +#include + +namespace BlackMisc +{ + /*! + * Build a QMap more efficiently when calling insert() in a for loop. + */ + template + class CMapBuilder + { + public: + //! Add an key/value pair to the map. Runs in amortized constant time. + template + void insert(Ts &&... keyAndValue) { m_list.push_back(std::make_pair(std::forward(keyAndValue)...)); } + + //! True if no pairs have been inserted. + bool isEmpty() const { return m_list.isEmpty(); } + + //! Return a container with unique keys. Runs in log-linear time. + //! @{ + operator QMap() const & { return convertToMap(sortAndDeduplicate(m_list)); } + operator QMap() && { return convertToMap(sortAndDeduplicate(std::move(m_list))); } + operator QHash() const & { return convertTo(sortAndDeduplicate(m_list)); } + operator QHash() && { return convertTo(sortAndDeduplicate(std::move(m_list))); } + operator std::map() const & { return convertTo(sortAndDeduplicate(m_list)); } + operator std::map() && { return convertTo(sortAndDeduplicate(std::move(m_list))); } + //! @} + + private: + QList> m_list; + + static QList> sortAndDeduplicate(QList> list) + { + std::sort(list.begin(), list.end(), [](auto &&a, auto &&b) { return std::less<>()(a.first, b.first); }); + list.erase(std::unique(list.begin(), list.end(), [](auto &&a, auto &&b) { return a.first == b.first; }), list.end()); + return list; + } + + template