<commit_before>#include "structurizator.h"

#include <QQueue>

using namespace generatorBase;
using namespace myUtils;

Structurizator::Structurizator(QObject *parent)
	: QObject(parent)
	, mVerticesNumber(1)
	, mStartVertex(-1)
	, mMaxPostOrderTime(-1)
{
}

IntermediateNode *Structurizator::performStructurization(const QSet<qReal::Id> &verticesIds, int startVertex
															, const QMap<int, QSet<int> > &followers, const QMap<qReal::Id, int> &vertexNumber
															, int verticesNumber)
{
	for (const qReal::Id &id : verticesIds) {
		mInitialIds.insert(id);
		mMapIdToInt[id] = vertexNumber[id];
		mVertices.insert(vertexNumber[id]);
	}

	mVerticesNumber = verticesNumber;

	mStartVertex = startVertex;

	for (const int v : followers.keys()) {
		for (const int u : followers[v]) {
			mFollowers[v].push_back(u);
			mPredecessors[u].push_back(v);
		}
	}

	// post order
	calculatePostOrder();

	calculateDominators();

	createInitialNodesForIds();

	bool somethingChanged = true;
	while (somethingChanged) {
		somethingChanged = false;

		int t = 0;
		while (t <= mMaxPostOrderTime && mVertices.size() > 1) {

			if (!checkAllStructures()) {
				bool flag = checkAllStructures();
			}
			Q_ASSERT(checkAllStructures());
			int v = mPostOrder.key(t);
			if (!v) {
				qDebug() << "Problem! time = " << t;
			}

			QSet<int> reachUnder;
			QSet<QPair<int, int> > edgesToRemove = {};
			QMap<QString, int> verticesRoles;
			if (isBlock(v, edgesToRemove, verticesRoles)) {
				reduceBlock(edgesToRemove, verticesRoles);
				qDebug() << "Block";
			} else if (isSwitch(v, edgesToRemove, verticesRoles)) {
				reduceSwitch(edgesToRemove, verticesRoles);
				qDebug() << "Switch";
			} else if (isIfThenElse(v, edgesToRemove, verticesRoles)) {
				reduceIfThenElse(edgesToRemove, verticesRoles);
				qDebug() << "If then else";
			} else if (isIfThen(v, edgesToRemove, verticesRoles)) {
				reduceIfThen(edgesToRemove, verticesRoles);
				qDebug() << "If then";
			} else if (isInfiniteLoop(v, edgesToRemove, verticesRoles)) {
				reduceInfiniteLoop(edgesToRemove, verticesRoles);
				qDebug() << "Infinite loop";
			} else if (isWhileLoop(v, edgesToRemove, verticesRoles)) {
				reduceWhileLoop(edgesToRemove, verticesRoles);
				qDebug() << "While loop";

			} else if (isHeadOfCycle(v, reachUnder)) {

				int minTime = -1;
				for (const int vertex : reachUnder) {
					if (minTime == -1 || minTime > mPostOrder[vertex]) {
						minTime = mPostOrder[vertex];
					}
				}

				QMap<int, QSet<int> > nodesWithExits;
				int commonExit = -1;
				bool isCycle = isCycleWithBreaks(reachUnder, nodesWithExits, commonExit);
				if (!isCycle) {
					t++;
					continue;
				}

				qDebug() << "Cycle with breaks";
				reduceConditionsWithBreaks(v, nodesWithExits, commonExit);
				t = minTime;
				somethingChanged = true;
				continue;
			}
<commit_msg>Support for irreducible loops without breaks<commit_after>#include "structurizator.h"

#include <QQueue>

using namespace generatorBase;
using namespace myUtils;

Structurizator::Structurizator(QObject *parent)
	: QObject(parent)
	, mVerticesNumber(1)
	, mStartVertex(-1)
	, mMaxPostOrderTime(-1)
{
}

IntermediateNode *Structurizator::performStructurization(const QSet<qReal::Id> &verticesIds, int startVertex
															, const QMap<int, QSet<int> > &followers, const QMap<qReal::Id, int> &vertexNumber
															, int verticesNumber)
{
	for (const qReal::Id &id : verticesIds) {
		mInitialIds.insert(id);
		mMapIdToInt[id] = vertexNumber[id];
		mVertices.insert(vertexNumber[id]);
	}

	mVerticesNumber = verticesNumber;

	mStartVertex = startVertex;

	for (const int v : followers.keys()) {
		for (const int u : followers[v]) {
			mFollowers[v].push_back(u);
			mPredecessors[u].push_back(v);
		}
	}

	// post order
	calculatePostOrder();

	calculateDominators();

	createInitialNodesForIds();

	bool somethingChanged = true;
	while (somethingChanged) {
		somethingChanged = false;

		int t = 0;
		while (t <= mMaxPostOrderTime && mVertices.size() > 1) {

			if (!checkAllStructures()) {
				bool flag = checkAllStructures();
			}
			Q_ASSERT(checkAllStructures());
			int v = mPostOrder.key(t);
			if (!v) {
				qDebug() << "Problem! time = " << t;
			}

			QSet<int> reachUnder;
			QSet<QPair<int, int> > edgesToRemove = {};
			QMap<QString, int> verticesRoles;
			if (isBlock(v, edgesToRemove, verticesRoles)) {
				reduceBlock(edgesToRemove, verticesRoles);
				qDebug() << "Block";
			} else if (isSwitch(v, edgesToRemove, verticesRoles)) {
				reduceSwitch(edgesToRemove, verticesRoles);
				qDebug() << "Switch";
			} else if (isIfThenElse(v, edgesToRemove, verticesRoles)) {
				reduceIfThenElse(edgesToRemove, verticesRoles);
				qDebug() << "If then else";
			} else if (isIfThen(v, edgesToRemove, verticesRoles)) {
				reduceIfThen(edgesToRemove, verticesRoles);
				qDebug() << "If then";
			} else if (isInfiniteLoop(v, edgesToRemove, verticesRoles)) {
				reduceInfiniteLoop(edgesToRemove, verticesRoles);
				qDebug() << "Infinite loop";
			} else if (isWhileLoop(v, edgesToRemove, verticesRoles)) {
				reduceWhileLoop(edgesToRemove, verticesRoles);
				qDebug() << "While loop";

			} else if (isHeadOfCycle(v, reachUnder)) {

				int minTime = -1;
				for (const int vertex : reachUnder) {
					if (minTime == -1 || minTime > mPostOrder[vertex]) {
						minTime = mPostOrder[vertex];
					}
				}

				QMap<int, QSet<int> > nodesWithExits;
				int commonExit = -1;
				bool isCycle = isCycleWithBreaks(reachUnder, nodesWithExits, commonExit);
				if (!isCycle) {
					t++;
					continue;
				}

				if (nodesWithExits.size() > 0) {
					qDebug() << "Cycle with breaks";
					reduceConditionsWithBreaks(v, nodesWithExits, commonExit);
					t = minTime;
					somethingChanged = true;
					continue;
				}
			}

{'fraction_non_alphanumeric': 0.134207348628601, 'fraction_numerical': 0.002932551319648094, 'mean_word_length': 3.9555555555555557, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 30, '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': '936326', 'n_tokens_mistral': 2376, 'n_tokens_neox': 1975, 'n_words': 416}