15.1.182. tablet_qt/lib/containers.h

/*
    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS 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, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS 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 CamCOPS. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include <QVector>


namespace containers
{

// ============================================================================
// Force a QVector to be a certain size, by removing items at the end or by
// adding default items.
// ============================================================================

template<typename T>
void forceVectorSize(QVector<T>& vec,
                     int new_size,
                     const T& default_value = T())
{
    int old_size = vec.size();
    // Remove surplus
    for (int i = old_size; i > new_size; --i) {
        vec.pop_back();
    }
    // Add new
    for (int i = old_size; i < new_size; ++i) {
        vec.append(default_value);
    }
}


// ============================================================================
// subtract(a, b) -> items in a, in order, that are not in b
// ============================================================================
// - works for QVector, QList

template<typename ContainerType>
ContainerType subtract(const ContainerType& first, const ContainerType& second)
{
    ContainerType difference;
    for (auto first_item : first) {
        if (!second.contains(first_item)) {
            difference.append(first_item);
        }
    }
    return difference;
}


// ============================================================================
// setSubtract(a, b) -> items in a, in order, that are not in b, eliminating
//                      duplicates in a
// ============================================================================
// - works for QVector, QList

template<typename ContainerType>
ContainerType setSubtract(const ContainerType& first,
                          const ContainerType& second)
{
    ContainerType difference;
    for (auto first_item : first) {
        if (!second.contains(first_item) && !difference.contains(first_item)) {
            difference.append(first_item);
        }
    }
    return difference;
}



// ============================================================================
// at(a, indices) -> container of items in "a" at locations "indices"
//                 = generalization of "at" for multiple indices
// ============================================================================
/*
Example:

    QVector<QString> v{"zero", "one", "two", "three", "four"};
    QVector<QString> v2 = at(v, {1, 3});
    assert(v2 == QVector<QString>{"one", "three"});
*/

template<typename ContainerType>
ContainerType at(const ContainerType& vec, const QVector<int>& indices)
{
    ContainerType subset;
    for (int index : indices) {
        subset.append(vec.at(index));
    }
    return subset;
}


// ============================================================================
// containsAll(a, b) -> does a contain all elements of b?
// ============================================================================

template<typename ContainerType>
bool containsAll(const ContainerType& a, const ContainerType& b)
{
    // Does a contain all elements of b?
    for (auto b_element : b) {
        if (!a.contains(b_element)) {
            return false;
        }
    }
    return true;
}


// ============================================================================
// rotateSequence(a, n) -> container of elements of a, rotated
// ... e.g. if a is {1, 2, 3, 4}, then rotateSequence(a, 2) is {3, 4, 1, 2}
// ============================================================================

template<typename ContainerType>
ContainerType rotateSequence(const ContainerType& v, int n_rotate)
{
    int size = v.size();
    n_rotate = n_rotate % size;  // don't do unnecessary work
    if (n_rotate <= 0) {
        return v;
    }
    ContainerType newvec(size);
    int new_index;
    for (int old_index = 0; old_index < size; ++old_index) {
        new_index = (old_index + n_rotate) % size;
        newvec[new_index] = v.at(old_index);
    }
    return newvec;
}


// ============================================================================
// rotateSequenceInPlace(a, n) -> in-place version of rotateSequence()
// ============================================================================

template<typename ContainerType>
void rotateSequenceInPlace(ContainerType& v, int n_rotate)
{
    v = rotateSequence(v, n_rotate);
}


}  // namespace containers