/**************************************************************************** ** ** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz ** Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo ** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #if 0 #pragma qt_sync_skip_header_check #pragma qt_sync_stop_processing #endif #ifndef QCONTAINERTOOLS_IMPL_H #define QCONTAINERTOOLS_IMPL_H #include #include #include #include #include QT_BEGIN_NAMESPACE namespace QtPrivate { template void q_uninitialized_relocate_n(T* first, N n, T* out) { if constexpr (QTypeInfo::isRelocatable) { if (n != N(0)) { // even if N == 0, out == nullptr or first == nullptr are UB for memmove() std::memmove(static_cast(out), static_cast(first), n * sizeof(T)); } } else { std::uninitialized_move_n(first, n, out); if constexpr (QTypeInfo::isComplex) std::destroy_n(first, n); } } template using IfIsInputIterator = typename std::enable_if< std::is_convertible::iterator_category, std::input_iterator_tag>::value, bool>::type; template using IfIsForwardIterator = typename std::enable_if< std::is_convertible::iterator_category, std::forward_iterator_tag>::value, bool>::type; template using IfIsNotForwardIterator = typename std::enable_if< !std::is_convertible::iterator_category, std::forward_iterator_tag>::value, bool>::type; template = true> void reserveIfForwardIterator(Container *, InputIterator, InputIterator) { } template = true> void reserveIfForwardIterator(Container *c, ForwardIterator f, ForwardIterator l) { c->reserve(static_cast(std::distance(f, l))); } template > struct AssociativeIteratorHasKeyAndValue : std::false_type { }; template struct AssociativeIteratorHasKeyAndValue< Iterator, std::void_t().key()), decltype(std::declval().value())> > : std::true_type { }; template , typename = std::void_t<>> struct AssociativeIteratorHasFirstAndSecond : std::false_type { }; template struct AssociativeIteratorHasFirstAndSecond< Iterator, std::void_t()->first), decltype(std::declval()->second)> > : std::true_type { }; template using IfAssociativeIteratorHasKeyAndValue = typename std::enable_if::value, bool>::type; template using IfAssociativeIteratorHasFirstAndSecond = typename std::enable_if::value, bool>::type; template using IfIsNotSame = typename std::enable_if::value, bool>::type; template using IfIsNotConvertible = typename std::enable_if::value, bool>::type; template auto sequential_erase(Container &c, const T &t) { // avoid a detach in case there is nothing to remove const auto cbegin = c.cbegin(); const auto cend = c.cend(); const auto t_it = std::find(cbegin, cend, t); auto result = std::distance(cbegin, t_it); if (result == c.size()) return result - result; // `0` of the right type const auto e = c.end(); const auto it = std::remove(std::next(c.begin(), result), e, t); result = std::distance(it, e); c.erase(it, e); return result; } template auto sequential_erase_with_copy(Container &c, const T &t) { using CopyProxy = std::conditional_t, T, const T &>; const T &tCopy = CopyProxy(t); return sequential_erase(c, tCopy); } template auto sequential_erase_one(Container &c, const T &t) { const auto cend = c.cend(); const auto it = std::find(c.cbegin(), cend, t); if (it == cend) return false; c.erase(it); return true; } template auto sequential_erase_if(Container &c, Predicate &pred) { // avoid a detach in case there is nothing to remove const auto cbegin = c.cbegin(); const auto cend = c.cend(); const auto t_it = std::find_if(cbegin, cend, pred); auto result = std::distance(cbegin, t_it); if (result == c.size()) return result - result; // `0` of the right type const auto e = c.end(); const auto it = std::remove_if(std::next(c.begin(), result), e, pred); result = std::distance(it, e); c.erase(it, e); return result; } template qsizetype qset_erase_if(QSet &set, Predicate &pred) { qsizetype result = 0; auto it = set.begin(); const auto e = set.end(); while (it != e) { if (pred(*it)) { ++result; it = set.erase(it); } else { ++it; } } return result; } // Prerequisite: F is invocable on ArgTypes template struct is_invoke_result_explicitly_convertible : std::is_constructible> {}; // is_invocable_r checks for implicit conversions, but we need to check // for explicit conversions in remove_if. So, roll our own trait. template constexpr bool is_invocable_explicit_r_v = std::conjunction_v< std::is_invocable, is_invoke_result_explicitly_convertible >; template auto associative_erase_if(Container &c, Predicate &pred) { // we support predicates callable with either Container::iterator // or with std::pair using Iterator = typename Container::iterator; using Key = typename Container::key_type; using Value = typename Container::mapped_type; using KeyValuePair = std::pair; typename Container::size_type result = 0; auto it = c.begin(); const auto e = c.end(); while (it != e) { if constexpr (is_invocable_explicit_r_v) { if (pred(it)) { it = c.erase(it); ++result; } else { ++it; } } else if constexpr (is_invocable_explicit_r_v) { KeyValuePair p(it.key(), it.value()); if (pred(std::move(p))) { it = c.erase(it); ++result; } else { ++it; } } else { static_assert(sizeof(Container) == 0, "Predicate has an incompatible signature"); } } return result; } } // namespace QtPrivate QT_END_NAMESPACE #endif // QCONTAINERTOOLS_IMPL_H