<commit_before>#pragma once

#include <QStandardItemModel>
#include <QTimer>
#include <boost/noncopyable.hpp>
#include <pajlada/signals/signal.hpp>
#include <vector>

#include "debug/AssertInGuiThread.hpp"

namespace chatterino {

template <typename TVectorItem>
struct SignalVectorItemArgs {
    const TVectorItem &item;
    int index;
    void *caller;
};

template <typename TVectorItem>
class ReadOnlySignalVector : boost::noncopyable
{
public:
    ReadOnlySignalVector()
    {
        QObject::connect(&this->itemsChangedTimer, &QTimer::timeout,
                         [this] { this->delayedItemsChanged.invoke(); });
        this->itemsChangedTimer.setInterval(100);
        this->itemsChangedTimer.setSingleShot(true);
    }
    virtual ~ReadOnlySignalVector() = default;

    pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemInserted;
    pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemRemoved;
    pajlada::Signals::NoArgSignal delayedItemsChanged;

    const std::vector<TVectorItem> &getVector() const
    {
        assertInGuiThread();

        return this->vector;
    }

    void invokeDelayedItemsChanged()
    {
        assertInGuiThread();

        if (!this->itemsChangedTimer.isActive()) {
            itemsChangedTimer.start();
        }
    }

    virtual bool isSorted() const = 0;

protected:
    std::vector<TVectorItem> vector;
    QTimer itemsChangedTimer;
};

template <typename TVectorItem>
class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
{
public:
    // returns the actual index of the inserted item
    virtual int insertItem(const TVectorItem &item, int proposedIndex = -1, void *caller = 0) = 0;

    void removeItem(int index, void *caller = 0)
    {
        assertInGuiThread();
        assert(index >= 0 && index < this->vector.size());

        TVectorItem item = this->vector[index];
        this->vector.erase(this->vector.begin() + index);
        SignalVectorItemArgs<TVectorItem> args{item, index, caller};
        this->itemRemoved.invoke(args);

        this->invokeDelayedItemsChanged();
    }

    int appendItem(const TVectorItem &item, void *caller = 0)
    {
        return this->insertItem(item, -1, caller);
    }
};

template <typename TVectorItem>
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
{
public:
    virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = 0) override
    {
        assertInGuiThread();
        if (index == -1) {
            index = this->vector.size();
        } else {
            assert(index >= 0 && index <= this->vector.size());
        }

        this->vector.insert(this->vector.begin() + index, item);

        SignalVectorItemArgs<TVectorItem> args{item, index, caller};
        this->itemInserted.invoke(args);
        this->invokeDelayedItemsChanged();<commit_msg>replaced 0 with nullptr in signalvector<commit_after>#pragma once

#include <QStandardItemModel>
#include <QTimer>
#include <boost/noncopyable.hpp>
#include <pajlada/signals/signal.hpp>
#include <vector>

#include "debug/AssertInGuiThread.hpp"

namespace chatterino {

template <typename TVectorItem>
struct SignalVectorItemArgs {
    const TVectorItem &item;
    int index;
    void *caller;
};

template <typename TVectorItem>
class ReadOnlySignalVector : boost::noncopyable
{
public:
    ReadOnlySignalVector()
    {
        QObject::connect(&this->itemsChangedTimer, &QTimer::timeout,
                         [this] { this->delayedItemsChanged.invoke(); });
        this->itemsChangedTimer.setInterval(100);
        this->itemsChangedTimer.setSingleShot(true);
    }
    virtual ~ReadOnlySignalVector() = default;

    pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemInserted;
    pajlada::Signals::Signal<SignalVectorItemArgs<TVectorItem>> itemRemoved;
    pajlada::Signals::NoArgSignal delayedItemsChanged;

    const std::vector<TVectorItem> &getVector() const
    {
        assertInGuiThread();

        return this->vector;
    }

    void invokeDelayedItemsChanged()
    {
        assertInGuiThread();

        if (!this->itemsChangedTimer.isActive()) {
            itemsChangedTimer.start();
        }
    }

    virtual bool isSorted() const = 0;

protected:
    std::vector<TVectorItem> vector;
    QTimer itemsChangedTimer;
};

template <typename TVectorItem>
class BaseSignalVector : public ReadOnlySignalVector<TVectorItem>
{
public:
    // returns the actual index of the inserted item
    virtual int insertItem(const TVectorItem &item, int proposedIndex = -1,
                           void *caller = nullptr) = 0;

    void removeItem(int index, void *caller = nullptr)
    {
        assertInGuiThread();
        assert(index >= 0 && index < this->vector.size());

        TVectorItem item = this->vector[index];
        this->vector.erase(this->vector.begin() + index);
        SignalVectorItemArgs<TVectorItem> args{item, index, caller};
        this->itemRemoved.invoke(args);

        this->invokeDelayedItemsChanged();
    }

    int appendItem(const TVectorItem &item, void *caller = nullptr)
    {
        return this->insertItem(item, -1, caller);
    }
};

template <typename TVectorItem>
class UnsortedSignalVector : public BaseSignalVector<TVectorItem>
{
public:
    virtual int insertItem(const TVectorItem &item, int index = -1, void *caller = nullptr) override
    {
        assertInGuiThread();
        if (index == -1) {
            index = this->vector.size();
        } else {
            assert(index >= 0 && index <= this->vector.size());
        }

        this->vector.insert(this->vector.begin() + index, item);

        SignalVectorItemArgs<TVectorItem> args{item, index, caller};
        this->itemInserted.invoke(args);
        this->invokeDelayedItemsChanged();
{'fraction_non_alphanumeric': 0.1180952380952381, 'fraction_numerical': 0.004675324675324675, 'mean_word_length': 3.269031781226903, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2856260', 'n_tokens_mistral': 1715, 'n_tokens_neox': 1666, 'n_words': 354}