Add DecoderThread

This commit is contained in:
Nathanaël Restori 2014-08-20 13:38:44 +02:00
parent 368b7b42a8
commit 36a6956c79
5 changed files with 162 additions and 124 deletions

View File

@ -13,8 +13,10 @@ TEMPLATE = app
SOURCES += main.cpp\ SOURCES += main.cpp\
qbrainfuck.cpp qbrainfuck.cpp \
decoderthread.cpp
HEADERS += qbrainfuck.h HEADERS += qbrainfuck.h \
decoderthread.h
FORMS += qbrainfuck.ui FORMS += qbrainfuck.ui

112
decoderthread.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "decoderthread.h"
DecoderThread::DecoderThread(QObject *parent) :
QThread(parent)
{
}
DecoderThread::~DecoderThread()
{
wait();
}
void DecoderThread::decode(QByteArray program, QByteArray input)
{
this->program = program;
this->input = input;
start();
}
void DecoderThread::run()
{
char* program = new char[this->program.size() + 1];
strcpy(program, this->program.data());
int programLength = this->program.size();
char* input = new char[this->input.size() + 1];
strcpy(input, this->input.data());
int inputLength = this->program.size();
actualDecode(program, programLength, input, inputLength);
delete program;
delete input;
}
void DecoderThread::actualDecode(char* program, int programLength, char* input, int inputLength)
{
// Don't use QList or QByteArray, it's too slow
char memory[65536];
int ptr = 0;
QString text;
QMap<int,int> correspondingBraces;
QStack<int> loopStack;
int programIndex = 0;
int inputIndex = 0;
for (programIndex = 0; programIndex < programLength; ++programIndex) {
switch (program[programIndex]) {
case '[':
loopStack.push(programIndex);
break;
case ']':
if(loopStack.isEmpty()) {
emit errorMessage("Unmatched end of loop");
return;
}
int old_i = loopStack.pop();
correspondingBraces.insert(programIndex, old_i);
correspondingBraces.insert(old_i, programIndex);
break;
}
}
if(!loopStack.isEmpty()) {
emit errorMessage("Unmatched begin of loop");
return;
}
for (programIndex = 0; programIndex < programLength; ++programIndex) {
switch (program[programIndex]) {
case '>':
++ptr;
break;
case '<':
--ptr;
break;
case '+':
++memory[ptr];
break;
case '-':
--memory[ptr];
break;
case '.':
text += (QString(memory[ptr]));
if (memory[ptr] == '\n') {
emit programDecoded(text);
}
break;
case ',':
if (inputIndex < inputLength) {
memory[ptr] = input[inputIndex];
++inputIndex;
} else {
memory[ptr] = 0;
}
break;
case '[':
if (memory[ptr] == 0) {
programIndex = correspondingBraces.value(programIndex);
}
break;
case ']':
if (memory[ptr] != 0) {
programIndex = correspondingBraces.value(programIndex);
}
break;
}
}
emit programDecoded(text);
}

31
decoderthread.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef DECODERTHREAD_H
#define DECODERTHREAD_H
#include <QThread>
#include <QMap>
#include <QStack>
class DecoderThread : public QThread
{
Q_OBJECT
public:
explicit DecoderThread(QObject *parent = 0);
~DecoderThread();
void decode(QByteArray program, QByteArray input);
private:
QByteArray program;
QByteArray input;
void run();
void actualDecode(char* program, int programLength, char* input, int inputLength);
signals:
void programDecoded(QString text);
void errorMessage(QString text);
public slots:
};
#endif // DECODERTHREAD_H

View File

@ -6,6 +6,10 @@ QBrainfuck::QBrainfuck(QWidget *parent) :
ui(new Ui::QBrainfuck) ui(new Ui::QBrainfuck)
{ {
ui->setupUi(this); ui->setupUi(this);
decoder = new DecoderThread();
QObject::connect(decoder, &DecoderThread::programDecoded, this, &QBrainfuck::setText);
QObject::connect(decoder, &DecoderThread::errorMessage, this, &QBrainfuck::errorMessage);
} }
QBrainfuck::~QBrainfuck() QBrainfuck::~QBrainfuck()
@ -17,7 +21,6 @@ void QBrainfuck::on_encodeButton_clicked()
{ {
QByteArray text = ui->textTextEdit->document()->toPlainText().toLatin1(); QByteArray text = ui->textTextEdit->document()->toPlainText().toLatin1();
ui->programTextEdit->setPlainText(""); ui->programTextEdit->setPlainText("");
ui->debugTextEdit->setHtml("");
// First pass : find decades/steps // First pass : find decades/steps
QList<unsigned char> decades; // Store the decades for initial loop QList<unsigned char> decades; // Store the decades for initial loop
@ -26,9 +29,6 @@ void QBrainfuck::on_encodeButton_clicked()
memory.append(0); memory.append(0);
QList<unsigned char> steps; // Store the steps to construct the program QList<unsigned char> steps; // Store the steps to construct the program
QString debugNumbers;
QString debugChars;
QByteArray::const_iterator textIterator; QByteArray::const_iterator textIterator;
for (textIterator = text.constBegin(); textIterator != text.constEnd(); ++textIterator) { for (textIterator = text.constBegin(); textIterator != text.constEnd(); ++textIterator) {
int max_diff = ui->maxSignsSpinBox->value()+1; int max_diff = ui->maxSignsSpinBox->value()+1;
@ -52,10 +52,6 @@ void QBrainfuck::on_encodeButton_clicked()
decades.append(qRound(*textIterator/(float)ui->decadesSpinBox->value())*ui->decadesSpinBox->value()); decades.append(qRound(*textIterator/(float)ui->decadesSpinBox->value())*ui->decadesSpinBox->value());
memory.append(*textIterator); memory.append(*textIterator);
} }
// Add current char to debug (with corresponding ASCII value)
debugNumbers += formatNumber(*textIterator);
debugChars += "&nbsp;&nbsp;&nbsp;" + QString(*textIterator);
} }
qSort(decades); qSort(decades);
@ -63,8 +59,6 @@ void QBrainfuck::on_encodeButton_clicked()
// Second pass : write program // Second pass : write program
QString program = ""; QString program = "";
ui->debugTextEdit->insertHtml("# The message<br /><br />" + QString(text) + "<br /><br /># In ASCII<br /><br />" + debugNumbers + "<br />" + debugChars + "<br /><br /># The memory<br /><br />");
for (int i = 0; i < ui->decadesSpinBox->value(); ++i) { for (int i = 0; i < ui->decadesSpinBox->value(); ++i) {
program += "+"; program += "+";
} }
@ -83,20 +77,6 @@ void QBrainfuck::on_encodeButton_clicked()
} }
program += "-]"; program += "-]";
// Print initial loop to debug
QString debugText;
for (int multiplier = 0; multiplier <= ui->decadesSpinBox->value(); ++multiplier) {
debugText += "&nbsp;&nbsp;<b>" + formatNumber(ui->decadesSpinBox->value()-multiplier) + "</b>";
for (int i = 1; i < decades.length(); ++i) {
debugText += formatNumber(decades[i]/ui->decadesSpinBox->value()*multiplier);
}
debugText += "<br />";
}
debugText += "<br />";
ui->debugTextEdit->insertHtml(debugText);
int prev_ptr = 0; int prev_ptr = 0;
QList<unsigned char>::const_iterator stepsIterator; QList<unsigned char>::const_iterator stepsIterator;
@ -127,94 +107,20 @@ void QBrainfuck::on_encodeButton_clicked()
program += "."; program += ".";
prev_ptr = next_ptr; prev_ptr = next_ptr;
decades[next_ptr] = *textIterator; decades[next_ptr] = *textIterator;
// Print current memory and current letter
printMemory(decades, next_ptr, "&nbsp;" + QString(*textIterator));
++textIterator; ++textIterator;
} }
ui->programTextEdit->setPlainText(program); ui->programTextEdit->setPlainText(program);
ui->debugTextEdit->insertHtml("<br /><br /># The program<br /><br />" + program);
} }
void QBrainfuck::on_decodeButton_clicked() void QBrainfuck::on_decodeButton_clicked()
{ {
ui->textTextEdit->setPlainText(""); ui->textTextEdit->setPlainText("");
ui->debugTextEdit->setHtml("");
int ptr = 0;
QByteArray program = ui->programTextEdit->document()->toPlainText().toLatin1(); QByteArray program = ui->programTextEdit->document()->toPlainText().toLatin1();
QByteArray input = ui->inputLineEdit->text().toLatin1(); QByteArray input = ui->inputLineEdit->text().toLatin1();
QByteArray::const_iterator inputIterator = input.constBegin();
QList<unsigned char> memory; decoder->decode(program, input);
QMap<int,int> correspondingBraces;
QStack<int> loopStack;
memory.append(0);
for (int i = 0; i < program.size(); ++i) {
switch (program.at(i)) {
case '[':
loopStack.push(i);
break;
case ']':
if(loopStack.isEmpty()) {
QMessageBox::critical(this, "QBrainfuck error", "Error: Unmatched end of loop");
return;
}
int old_i = loopStack.pop();
correspondingBraces.insert(i, old_i);
correspondingBraces.insert(old_i, i);
break;
}
}
if(!loopStack.isEmpty()) {
QMessageBox::critical(this, "QBrainfuck error", "Error: Unmatched begin of loop");
return;
}
for (int i = 0; i < program.size(); ++i) {
switch (program.at(i)) {
case '>':
++ptr;
if(ptr == memory.size()) {
memory.append(0);
}
break;
case '<':
--ptr;
if (ptr < 0) {
QMessageBox::critical(this, "QBrainfuck error", "Error: Pointer went under 0");
return;
}
break;
case '+':
++memory[ptr];
break;
case '-':
--memory[ptr];
break;
case '.':
ui->textTextEdit->insertPlainText(QString(memory.at(ptr)));
break;
case ',':
memory[ptr] = *inputIterator;
++inputIterator;
break;
case '[':
if (memory.at(ptr) == 0) {
i = correspondingBraces.value(i);
}
break;
case ']':
if (memory.at(ptr) != 0) {
i = correspondingBraces.value(i);
}
break;
}
}
} }
void QBrainfuck::on_motifButton_clicked() void QBrainfuck::on_motifButton_clicked()
@ -333,26 +239,10 @@ void QBrainfuck::on_loadButton_clicked()
} }
} }
QString QBrainfuck::formatNumber(int number) void QBrainfuck::setText(QString text) {
{ ui->textTextEdit->setPlainText(text);
if (number < 10) {
return "&nbsp;&nbsp;&nbsp;" + QString().setNum(number);
} else if (number < 100) {
return "&nbsp;&nbsp;" + QString().setNum(number);
} else {
return "&nbsp;" + QString().setNum(number);
}
} }
void QBrainfuck::printMemory(QList<unsigned char> memory, int ptr, QString text) void QBrainfuck::errorMessage(QString message) {
{ QMessageBox::critical(this, "QBrainfuck error", "Error: " + message);
QString str;
for (int i = 0; i < memory.size(); ++i) {
if (i == ptr) {
str += "<b>" + formatNumber(memory[i]) + "</b>";
} else {
str += formatNumber(memory[i]);
}
}
ui->debugTextEdit->insertHtml(text + str + "<br />");
} }

View File

@ -7,6 +7,7 @@
#include <QJsonObject> #include <QJsonObject>
#include <QJsonDocument> #include <QJsonDocument>
#include <QStack> #include <QStack>
#include "decoderthread.h"
namespace Ui { namespace Ui {
class QBrainfuck; class QBrainfuck;
@ -39,11 +40,13 @@ private slots:
void on_loadButton_clicked(); void on_loadButton_clicked();
void setText(QString text);
void errorMessage(QString message);
private: private:
Ui::QBrainfuck *ui; Ui::QBrainfuck *ui;
DecoderThread *decoder;
QString formatNumber(int number);
void printMemory(QList<unsigned char> memory, int ptr, QString text);
}; };
#endif // QBRAINFUCK_H #endif // QBRAINFUCK_H