Issue #114 Add CSetBuilder and CMapBuilder

This commit is contained in:
Mat Sutcliffe
2021-08-26 22:18:35 +01:00
parent c88f9d21c6
commit f0db8b567f
3 changed files with 156 additions and 0 deletions

View File

@@ -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 <QMap>
#include <QHash>
#include <QList>
#include <algorithm>
#include <iterator>
#include <map>
namespace BlackMisc
{
/*!
* Build a QMap more efficiently when calling insert() in a for loop.
*/
template <typename K, typename V>
class CMapBuilder
{
public:
//! Add an key/value pair to the map. Runs in amortized constant time.
template <typename... Ts>
void insert(Ts &&... keyAndValue) { m_list.push_back(std::make_pair(std::forward<Ts>(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<K, V>() const & { return convertToMap(sortAndDeduplicate(m_list)); }
operator QMap<K, V>() && { return convertToMap(sortAndDeduplicate(std::move(m_list))); }
operator QHash<K, V>() const & { return convertTo<QHash>(sortAndDeduplicate(m_list)); }
operator QHash<K, V>() && { return convertTo<QHash>(sortAndDeduplicate(std::move(m_list))); }
operator std::map<K, V>() const & { return convertTo<std::map>(sortAndDeduplicate(m_list)); }
operator std::map<K, V>() && { return convertTo<std::map>(sortAndDeduplicate(std::move(m_list))); }
//! @}
private:
QList<std::pair<K, V>> m_list;
static QList<std::pair<K, V>> sortAndDeduplicate(QList<std::pair<K, V>> 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 <template <typename...> class C>
static C<K, V> convertTo(QList<std::pair<K, V>> &&list)
{
return C<K, V>(std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()));
}
static QMap<K, V> convertToMap(QList<std::pair<K, V>> &&list)
{
QMap<K, V> map;
for (auto &pair : makeRange(list).reverse()) { map.insert(map.cbegin(), std::move(pair.first), std::move(pair.second)); }
return map;
}
};
}
#endif

View File

@@ -65,6 +65,10 @@ namespace BlackMisc
//! By QList of type T.
CSequence(const QList<T> &list) : m_impl(list.toVector()) {}
//! Range constructor.
template <typename It>
CSequence(It first, It last) : m_impl(first, last) {}
//! Copy constructor.
CSequence(const CSequence &other) = default;

View File

@@ -0,0 +1,78 @@
/* 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_SETBUILDER_H
#define BLACKMISC_SETBUILDER_H
#include "blackmisc/blackmiscexport.h"
#include <QSet>
#include <QList>
#include <QVector>
#include <QStringList>
#include <algorithm>
#include <iterator>
#include <vector>
#include <set>
namespace BlackMisc
{
/*!
* Build a QSet more efficiently when calling insert() in a for loop.
*/
template <typename T>
class CSetBuilder
{
public:
//! Add an element to the set. Runs in amortized constant time.
//! @{
void insert(const T &value) { m_list.push_back(value); }
void insert(T &&value) { m_list.push_back(std::move(value)); }
//! @}
//! True if no elements have been inserted.
bool isEmpty() const { return m_list.isEmpty(); }
//! Return a container of unique elements. Runs in log-linear time.
//! @{
operator QList<T>() const & { return sortAndDeduplicate(m_list); }
operator QList<T>() && { return sortAndDeduplicate(std::move(m_list)); }
operator QSet<T>() const & { return convertTo<QSet>(sortAndDeduplicate(m_list)); }
operator QSet<T>() && { return convertTo<QSet>(sortAndDeduplicate(std::move(m_list))); }
operator std::set<T>() const & { return convertTo<std::set>(sortAndDeduplicate(m_list)); }
operator std::set<T>() && { return convertTo<std::set>(sortAndDeduplicate(std::move(m_list))); }
operator QVector<T>() const & { return convertTo<QVector>(sortAndDeduplicate(m_list)); }
operator QVector<T>() && { return convertTo<QVector>(sortAndDeduplicate(std::move(m_list))); }
operator std::vector<T>() const & { return convertTo<std::vector>(sortAndDeduplicate(m_list)); }
operator std::vector<T>() && { return convertTo<std::vector>(sortAndDeduplicate(std::move(m_list))); }
template <typename U = T, typename = std::enable_if_t<std::is_same_v<U, QString>>>
operator QStringList() const & { return sortAndDeduplicate(m_list); }
template <typename U = T, typename = std::enable_if_t<std::is_same_v<U, QString>>>
operator QStringList() && { return sortAndDeduplicate(std::move(m_list)); }
//! @}
private:
QList<T> m_list;
static QList<T> sortAndDeduplicate(QList<T> list)
{
std::sort(list.begin(), list.end());
list.erase(std::unique(list.begin(), list.end()), list.end());
return list;
}
template <template <typename...> class C>
static C<T> convertTo(QList<T> &&list)
{
return C<T>(std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()));
}
};
}
#endif