<commit_before>#include "zcm.h"
#include <zmq.h>

#include <unistd.h>
#include <dirent.h>

#include <cstring>
#include <cassert>
#include <cctype>
#include <cstdio>

#include <vector>
using std::vector;

#include <unordered_map>
using std::unordered_map;

#include <string>
using std::string;

#include <mutex>
#include <thread>
#include <iostream>

#define METADATA_PUB_ADDR "ipc:///tmp/zcm-metadata-pub"
#define METADATA_SUB_ADDR "ipc:///tmp/zcm-metadata-sub"
#define ZMQ_IO_THREADS 1

struct Sub
{
    zcm_callback_t *cb;
    void *usr;
    void *sock;
};

struct SubRegex
{
    string channelRegex;
    zcm_callback_t *cb;
    void *usr;
};

struct Pub
{
    void *sock;
};

struct zcm_t
{
    std::thread recvThread;

    // The mutex protects all data below it
    std::mutex mut;
    bool recvThreadStarted = false;
    bool running = true;

    void *ctx;
    unordered_map<string, Sub> subs;
    unordered_map<string, Pub> pubs;

    vector<SubRegex> subRegex;

    zcm_t()
    {
        ctx = zmq_init(ZMQ_IO_THREADS);
    }

    string getIPCAddress(const string& channel)
    {
        return "ipc:///tmp/zmq-channel-"+channel;
    }

    Sub *findSub(const string& channel)
    {
        auto it = subs.find(channel);
        if (it != subs.end())
            return &it->second;
        else
            return nullptr;
    }

    Pub *findPub(const string& channel)
    {
        auto it = pubs.find(channel);
        if (it != pubs.end())
            return &it->second;
        else
            return nullptr;
    }

    int publish(const string& channel, const char *data, size_t len)
    {
        std::unique_lock<std::mutex> lk(mut);

        Pub *pub = findPub(channel);
        if (!pub) {
            void *sock = zmq_socket(ctx, ZMQ_PUB);
            string address = getIPCAddress(channel);
            zmq_bind(sock, address.c_str());
            pubs.emplace(channel, Pub{sock});
            pub = findPub(channel);
            assert(pub);
        }

        int rc = zmq_send(pub->sock, data, len, 0);
        assert(rc == (int)len);
        return 0;
    }

    void searchForRegexSubs()
    {
        std::unique_lock<std::mutex> lk(mut);

        // TODO: actually implement regex, or remove it
        if (subRegex.size() == 0)
            return;
        for (auto& r : subRegex) {
            if (r.channelRegex != ".*") {
                static bool warned = false;
                if (!warned) {
                    fprintf(stderr, "Er: only .* (aka subscribe-all) is implemented\n");
                    warned = true;
                }
            }
        }
        SubRegex& srex = subRegex[0];

        const char *prefix = "zmq-channel-";
        size_t prefixLen = strlen(prefix);

        DIR *d;
        dirent *ent;

        if (!(d=opendir("/tmp/")))
            return;

        while ((ent=readdir(d)) != nullptr) {
            if (strncmp(ent->d_name, prefix, prefixLen) == 0) {
                string channel(ent->d_name + prefixLen);
                if (!findSub(channel))
                    subOneInternal(channel, srex.cb, srex.usr);
            }
        }

        closedir(d);
    }

    void recvMsgFromSock(const string& channel, void *sock)
    {
        const int BUFSZ = 1 << 20;
        char *buf = (char *) malloc(BUFSZ);

        int rc = zmq_recv(sock, buf, BUFSZ, 0);
        assert(0 < rc && rc < BUFSZ);

        // Dispatch
        {
            std::unique_lock<std::mutex> lk(mut);
            if (Sub *sub = findSub(channel)) {
                zcm_recv_buf_t rbuf;
                rbuf.data = buf;
                rbuf.len = rc;
                rbuf.utime = 0;
                rbuf.zcm = this;
                sub->cb(&rbuf, channel.c_str(), sub->usr);
            }
        }
    }

    void recvThreadFunc()
    {
        while (1) {
            searchForRegexSubs();

            // Build up a list of poll items
            vector<zmq_pollitem_t> pitems;
            vector<string> pchannels;
            {
                std::unique_lock<std::mutex> lk(mut);
                pitems.resize(subs.size());
                int i = 0;
                for (auto& elt : subs) {
                    auto& channel = elt.first;
                    auto& sub = elt.second;
                    auto *p = &pitems[i];
                    memset(p, 0, sizeof(*p));
                    p->socket = sub.sock;
                    p->events = ZMQ_POLLIN;
                    pchannels.emplace_back(channel);
                    i++;
                }
            }

            int rc = zmq_poll(pitems.data(), pitems.size(), 100);
            if (!running)
                break;
            if (rc >= 0) {
                for (size_t i = 0; i < pitems.size(); i++) {
                    auto& p = pitems[i];
                    if (p.revents != 0)
                        recvMsgFromSock(pchannels[i], p.socket);
                }
            }
        }
    }

    static bool isRegexChannel(const string& channel)
    {
        // These chars are considered regex
        auto isRegexChar = [](char c) {
            return c == '(' || c == ')' || c == '|' ||
                   c == '.' || c == '*' || c == '+';
        };

        for (auto& c : channel)
            if (isRegexChar(c))
                return true;

        return false;
    }

    void subOneInternal(const string& channel, zcm_callback_t *cb, void *usr)
    {
        assert(!findSub(channel));

        void *sock = zmq_socket(ctx, ZMQ_SUB);
        string address = getIPCAddress(channel);
        zmq_connect(sock, address.c_str());
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0);

        subs.emplace(channel, Sub{cb, usr, sock});
    }

    int subscribe(const string& channel, zcm_callback_t *cb, void *usr)
    {
        std::unique_lock<std::mutex> lk(mut);

        if (isRegexChannel(channel)) {
            subRegex.emplace_back(SubRegex{channel, cb, usr});
        } else {
            subOneInternal(channel, cb, usr);
        }

        if (!recvThreadStarted) {
            recvThread = std::thread{&zcm_t::recvThreadFunc, this};
            recvThreadStarted = true;
        }
        return 0;
    }
};

static void printBytes(const char *buf, size_t len)
{
    printf("printBytes:");
    for (size_t i = 0; i < len; i++) {
        char c = buf[i];
        printf(" 0x%02x", c&0xff);
        if (isalpha(c))
            printf("(%c)", c);
    }
    printf("\n");
}

zcm_t *zcm_create(void)
{
    return new zcm_t();
}

void zcm_destroy(zcm_t *zcm)
{
    // TODO: What is the "correct" method to shut-down ZMQ?
}

int zcm_publish(zcm_t *zcm, const char *channel, char *data, size_t len)
{
    return zcm->publish(channel, data, len);
}

int zcm_subscribe(zcm_t *zcm, const char *channel, zcm_callback_t *cb, void *usr)
{
    return zcm->subscribe(channel, cb, usr);
}
<commit_msg>fixed leak<commit_after>#include "zcm.h"
#include <zmq.h>

#include <unistd.h>
#include <dirent.h>

#include <cstring>
#include <cassert>
#include <cctype>
#include <cstdio>

#include <vector>
using std::vector;

#include <unordered_map>
using std::unordered_map;

#include <string>
using std::string;

#include <mutex>
#include <thread>
#include <iostream>

#define METADATA_PUB_ADDR "ipc:///tmp/zcm-metadata-pub"
#define METADATA_SUB_ADDR "ipc:///tmp/zcm-metadata-sub"
#define ZMQ_IO_THREADS 1

struct Sub
{
    zcm_callback_t *cb;
    void *usr;
    void *sock;
};

struct SubRegex
{
    string channelRegex;
    zcm_callback_t *cb;
    void *usr;
};

struct Pub
{
    void *sock;
};

struct zcm_t
{
    std::thread recvThread;

    // The mutex protects all data below it
    std::mutex mut;
    bool recvThreadStarted = false;
    static constexpr int RECVBUFSZ = 1 << 20;
    char recvbuf[RECVBUFSZ];
    bool running = true;

    void *ctx;
    unordered_map<string, Sub> subs;
    unordered_map<string, Pub> pubs;

    vector<SubRegex> subRegex;

    zcm_t()
    {
        ctx = zmq_init(ZMQ_IO_THREADS);
    }

    string getIPCAddress(const string& channel)
    {
        return "ipc:///tmp/zmq-channel-"+channel;
    }

    Sub *findSub(const string& channel)
    {
        auto it = subs.find(channel);
        if (it != subs.end())
            return &it->second;
        else
            return nullptr;
    }

    Pub *findPub(const string& channel)
    {
        auto it = pubs.find(channel);
        if (it != pubs.end())
            return &it->second;
        else
            return nullptr;
    }

    int publish(const string& channel, const char *data, size_t len)
    {
        std::unique_lock<std::mutex> lk(mut);

        Pub *pub = findPub(channel);
        if (!pub) {
            void *sock = zmq_socket(ctx, ZMQ_PUB);
            string address = getIPCAddress(channel);
            zmq_bind(sock, address.c_str());
            pubs.emplace(channel, Pub{sock});
            pub = findPub(channel);
            assert(pub);
        }

        int rc = zmq_send(pub->sock, data, len, 0);
        assert(rc == (int)len);
        return 0;
    }

    void searchForRegexSubs()
    {
        std::unique_lock<std::mutex> lk(mut);

        // TODO: actually implement regex, or remove it
        if (subRegex.size() == 0)
            return;
        for (auto& r : subRegex) {
            if (r.channelRegex != ".*") {
                static bool warned = false;
                if (!warned) {
                    fprintf(stderr, "Er: only .* (aka subscribe-all) is implemented\n");
                    warned = true;
                }
            }
        }
        SubRegex& srex = subRegex[0];

        const char *prefix = "zmq-channel-";
        size_t prefixLen = strlen(prefix);

        DIR *d;
        dirent *ent;

        if (!(d=opendir("/tmp/")))
            return;

        while ((ent=readdir(d)) != nullptr) {
            if (strncmp(ent->d_name, prefix, prefixLen) == 0) {
                string channel(ent->d_name + prefixLen);
                if (!findSub(channel))
                    subOneInternal(channel, srex.cb, srex.usr);
            }
        }

        closedir(d);
    }

    void recvMsgFromSock(const string& channel, void *sock)
    {
        int rc = zmq_recv(sock, recvbuf, RECVBUFSZ, 0);
        assert(0 < rc && rc < RECVBUFSZ);

        // Dispatch
        {
            std::unique_lock<std::mutex> lk(mut);
            if (Sub *sub = findSub(channel)) {
                zcm_recv_buf_t rbuf;
                rbuf.data = recvbuf;
                rbuf.len = rc;
                rbuf.utime = 0;
                rbuf.zcm = this;
                sub->cb(&rbuf, channel.c_str(), sub->usr);
            }
        }
    }

    void recvThreadFunc()
    {
        while (1) {
            searchForRegexSubs();

            // Build up a list of poll items
            vector<zmq_pollitem_t> pitems;
            vector<string> pchannels;
            {
                std::unique_lock<std::mutex> lk(mut);
                pitems.resize(subs.size());
                int i = 0;
                for (auto& elt : subs) {
                    auto& channel = elt.first;
                    auto& sub = elt.second;
                    auto *p = &pitems[i];
                    memset(p, 0, sizeof(*p));
                    p->socket = sub.sock;
                    p->events = ZMQ_POLLIN;
                    pchannels.emplace_back(channel);
                    i++;
                }
            }

            int rc = zmq_poll(pitems.data(), pitems.size(), 100);
            if (!running)
                break;
            if (rc >= 0) {
                for (size_t i = 0; i < pitems.size(); i++) {
                    auto& p = pitems[i];
                    if (p.revents != 0)
                        recvMsgFromSock(pchannels[i], p.socket);
                }
            }
        }
    }

    static bool isRegexChannel(const string& channel)
    {
        // These chars are considered regex
        auto isRegexChar = [](char c) {
            return c == '(' || c == ')' || c == '|' ||
                   c == '.' || c == '*' || c == '+';
        };

        for (auto& c : channel)
            if (isRegexChar(c))
                return true;

        return false;
    }

    void subOneInternal(const string& channel, zcm_callback_t *cb, void *usr)
    {
        assert(!findSub(channel));

        void *sock = zmq_socket(ctx, ZMQ_SUB);
        string address = getIPCAddress(channel);
        zmq_connect(sock, address.c_str());
        zmq_setsockopt(sock, ZMQ_SUBSCRIBE, "", 0);

        subs.emplace(channel, Sub{cb, usr, sock});
    }

    int subscribe(const string& channel, zcm_callback_t *cb, void *usr)
    {
        std::unique_lock<std::mutex> lk(mut);

        if (isRegexChannel(channel)) {
            subRegex.emplace_back(SubRegex{channel, cb, usr});
        } else {
            subOneInternal(channel, cb, usr);
        }

        if (!recvThreadStarted) {
            recvThread = std::thread{&zcm_t::recvThreadFunc, this};
            recvThreadStarted = true;
        }
        return 0;
    }
};

static void printBytes(const char *buf, size_t len)
{
    printf("printBytes:");
    for (size_t i = 0; i < len; i++) {
        char c = buf[i];
        printf(" 0x%02x", c&0xff);
        if (isalpha(c))
            printf("(%c)", c);
    }
    printf("\n");
}

zcm_t *zcm_create(void)
{
    return new zcm_t();
}

void zcm_destroy(zcm_t *zcm)
{
    // TODO: What is the "correct" method to shut-down ZMQ?
}

int zcm_publish(zcm_t *zcm, const char *channel, char *data, size_t len)
{
    return zcm->publish(channel, data, len);
}

int zcm_subscribe(zcm_t *zcm, const char *channel, zcm_callback_t *cb, void *usr)
{
    return zcm->subscribe(channel, cb, usr);
}
<|endoftext|>


<commit_before>/* predictionResultDialog.C
 *
 * Copyright (C) 2009 Marcel Schumann
 *
 * This file is part of QuEasy -- A Toolbox for Automated QSAR Model
 * Construction and Validation.
 * QuEasy 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.
 *
 * QuEasy 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 this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <predictionResultDialog.h>
#include <mainWindow.h>

#include <QtGui/QDialogButtonBox>
#include <QtGui/QFileDialog>
#include <QtGui/QLabel>
#include <QtGui/QGroupBox>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtGui/QScrollArea>
#include <QtGui/QHeaderView>

using namespace BALL::QSAR;

namespace BALL
{
	namespace VIEW
	{

		PredictionResultDialog::PredictionResultDialog(PredictionItem* item)
		{
			//return if there's no parent
			if (item == NULL)
			{
				return;
			}
			pred_item_ = item;

			QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok,Qt::Horizontal, this);
			QPushButton* print_button = new QPushButton("Save to File", buttons);

			QVBoxLayout* mainLayout = new QVBoxLayout();
			QVBoxLayout* resultGroupLayout = new QVBoxLayout();

			QGroupBox* resultGroup = new QGroupBox(tr("Predicted Activity Values"),this);

			file_name_ = item->name();
			results_ = item->results();

			QStringList labels;
			labels << "Compound";

			bool show_expected=0;
			const QSARData* test_data = 0;
			uint no_y=0;
			if(item->getTestData()!=0) no_y=item->getTestData()->getNoResponseVariables();
			else if(results_->size()==0) return; // no prediction=>nothing to be displayed

			if(no_y>=1)
			{
				show_expected=1;
				test_data = item->getTestData();
				if(no_y==1) labels<<"Prediction"<<"Expected";
				else
				{
					for(uint i=0; i<no_y;i++)
					{
						String p = "Prediction"+String(i);
						String e = "Expected"+String(i);
						labels<<p.c_str()<<e.c_str();
					}
				}
			}
			else
			{
				labels<<"Prediction";
			}

			compound_names_ = test_data->getSubstanceNames();

			table_ = new QTableWidget(results_->size(), 1+no_y*(1+show_expected), this);
			table_->verticalHeader()->hide();
			table_->setHorizontalHeaderLabels (labels);
			table_->setAlternatingRowColors(true);
			table_->setDragDropMode(QAbstractItemView::NoDragDrop);
			table_->setEditTriggers(QAbstractItemView::NoEditTriggers);
			table_->horizontalHeader()->setResizeMode(QHeaderView::Custom);

			if(((uint)results_->size()) == compound_names_->size())
			{
				int i = 0;
				for (list<Vector<double> >::const_iterator it = results_->begin(); it != results_->end(); it++)
				{
					QTableWidgetItem* name = new QTableWidgetItem(QString(compound_names_->at(i).c_str()));
    					table_->setItem(i, 0, name);
					vector<double>* e = 0;
					if(show_expected) e = test_data->getActivity(i);

					for(uint act=0; act<e->size(); act++)
					{
						QTableWidgetItem* pred = new QTableWidgetItem(QString((((String)(*it)(1+act)).c_str())));
						table_->setItem(i, 1+2*act, pred);

						if(show_expected)
						{
							QTableWidgetItem* expected = new QTableWidgetItem(QString(((String((*e)[act])).c_str())));
							table_->setItem(i, 2+2*act, expected);
						}
					}

					delete e;
					i++;
				}
			}

			QScrollArea* scrollArea = new QScrollArea(this);
			scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
			scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
			scrollArea->setFrameShape(QFrame::NoFrame);
			scrollArea->setWidget(table_);
			scrollArea->setWidgetResizable(true);

			resultGroupLayout->addWidget(scrollArea);
			resultGroup->setLayout(resultGroupLayout);

			mainLayout->addWidget(resultGroup);
			mainLayout->addWidget(buttons);
			setLayout(mainLayout);
			setWindowTitle("Predicted Activity Values for " + item->name());

			uint width = 0;
			for(int i=0; i<table_->columnCount();i++)
			{
				width+=table_->columnWidth(i);
			}
			width+=65;
			uint mainWindow_width = item->view()->data_scene->main_window->size().width();
			if(width<mainWindow_width) resize(width,450);
			else resize(mainWindow_width,450);
			table_->setSortingEnabled(1);

			connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
			connect(print_button, SIGNAL(clicked()), this, SLOT(saveToFile()));
		}

		PredictionResultDialog::~PredictionResultDialog()
		{
		}

		void PredictionResultDialog::saveToFile()
		{
			QString filename = QFileDialog::getSaveFileName(this, tr("Save File as"),file_name_ +"_prediction_results.txt",tr("text (*.txt)"));
			QFile file(filename);
			if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
			{
				return;
			}
			ofstream out(file.fileName().toStdString().c_str());

			uint no_rows=table_->rowCount();
			uint no_cols=table_->columnCount();
			bool use_selection = (table_->selectedItems().size()>1);

			list<int> selected_columns;
			list<int> selected_rows;
			list<int>::iterator col_it;
			list<int>::iterator row_it;
			if(use_selection)
			{
				// find selected columns
				QList<QTableWidgetSelectionRange> ranges = table_->selectedRanges();
				for(int i=0; i<(int)no_cols; i++)
				{
					for(QList<QTableWidgetSelectionRange>::iterator it=ranges.begin();it!=ranges.end();it++)
					{
						if(i<=it->rightColumn() && i>=it->leftColumn())
						{
							selected_columns.push_back(i);
							break;
						}
					}
				}
				col_it=selected_columns.begin();

				// find selected rows
				for(int i=0; i<(int)no_rows; i++)
				{
					for(QList<QTableWidgetSelectionRange>::iterator it=ranges.begin();it!=ranges.end();it++)
					{
						if(i<=it->bottomRow() && i>=it->topRow())
						{
							selected_rows.push_back(i);
							break;
						}
					}
				}
				row_it=selected_rows.begin();
			}

			// print table-header
			for(int i=0; i<(int)no_cols; i++)
			{
				bool write=0;
				if(use_selection)
				{
					if(col_it!=selected_columns.end() && *col_it==i)
					{
						write=1;
						col_it++;
					}
				}
				if(!use_selection || write) out<<table_->horizontalHeaderItem(i)->text().toStdString()<<"\t";

			}
			out<<endl;

			if(use_selection) col_it=selected_columns.begin();

			// print data
			for(int i=0; i<(int)no_rows; i++)
			{
				bool wrote_item=0;
				for(int j=0; j<(int)no_cols; j++)
				{
					if(!use_selection || table_->item(i,j)->isSelected())
					{
						out<<table_->item(i,j)->text().toStdString()<<"\t";
						wrote_item=1;
					}
					else if(col_it!=selected_columns.end() && *col_it==j && row_it!=selected_rows.end() && *row_it==i)
					{
						out<<"\t";
						col_it++;
					}
				}
				if(wrote_item)
				{
					out<<endl;
					if(use_selection)
					{
						row_it++;
						col_it=selected_columns.begin();
					}
				}
			}
		}
	}
}<commit_msg>Fixed displaying predictions without available expected values in PredictionResultDialog.<commit_after>/* predictionResultDialog.C
 *
 * Copyright (C) 2009 Marcel Schumann
 *
 * This file is part of QuEasy -- A Toolbox for Automated QSAR Model
 * Construction and Validation.
 * QuEasy 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.
 *
 * QuEasy 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 this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <predictionResultDialog.h>
#include <mainWindow.h>

#include <QtGui/QDialogButtonBox>
#include <QtGui/QFileDialog>
#include <QtGui/QLabel>
#include <QtGui/QGroupBox>
#include <QtGui/QHBoxLayout>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QtCore/QFile>
#include <QtCore/QTextStream>
#include <QtGui/QScrollArea>
#include <QtGui/QHeaderView>

using namespace BALL::QSAR;

namespace BALL
{
	namespace VIEW
	{

		PredictionResultDialog::PredictionResultDialog(PredictionItem* item)
		{
			//return if there's no parent
			if (item == NULL)
			{
				return;
			}
			pred_item_ = item;

			QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok,Qt::Horizontal, this);
			QPushButton* print_button = new QPushButton("Save to File", buttons);

			QVBoxLayout* mainLayout = new QVBoxLayout();
			QVBoxLayout* resultGroupLayout = new QVBoxLayout();

			QGroupBox* resultGroup = new QGroupBox(tr("Predicted Activity Values"),this);

			file_name_ = item->name();
			results_ = item->results();

			QStringList labels;
			labels << "Compound";

			bool show_expected=0;
			const QSARData* test_data = 0;
			if(item->getTestData()==0 || results_->size()==0) return; // no prediction=>nothing to be displayed

			test_data = item->getTestData();
			Size no_y=test_data->getNoResponseVariables();
			if(no_y>=1)
			{
				show_expected=1;
				if(no_y==1) labels<<"Prediction"<<"Expected";
				else
				{
					for(uint i=0; i<no_y;i++)
					{
						String p = "Prediction"+String(i);
						String e = "Expected"+String(i);
						labels<<p.c_str()<<e.c_str();
					}
				}
			}
			else
			{
				for(Size act=0; act<results_->front().getSize(); act++)
				{
					String p = "Prediction"+String(act);
					labels<<p.c_str();
				}
			}

			compound_names_ = test_data->getSubstanceNames();
			Size no_columns = 1;
			if(no_y>=1) no_columns+=2*no_y;
			else no_columns+=results_->front().getSize();
			table_ = new QTableWidget(results_->size(), no_columns, this);
			table_->verticalHeader()->hide();
			table_->setHorizontalHeaderLabels (labels);
			table_->setAlternatingRowColors(true);
			table_->setDragDropMode(QAbstractItemView::NoDragDrop);
			table_->setEditTriggers(QAbstractItemView::NoEditTriggers);

			if(results_->size()==compound_names_->size())
			{
				int i = 0;
				for (list<Vector<double> >::const_iterator it = results_->begin(); it != results_->end(); it++)
				{
					QTableWidgetItem* name = new QTableWidgetItem(QString(compound_names_->at(i).c_str()));
					table_->setItem(i, 0, name);
					vector<double>* e = 0;
					if(show_expected) e = test_data->getActivity(i);

					for(uint act=0; act<it->getSize(); act++)
					{
						QTableWidgetItem* pred = new QTableWidgetItem(QString((((String)(*it)(1+act)).c_str())));
						table_->setItem(i, 1+(1+show_expected)*act, pred);

						if(show_expected)
						{
							QTableWidgetItem* expected = new QTableWidgetItem(QString(((String((*e)[act])).c_str())));
							table_->setItem(i, 2+2*act, expected);
						}
					}

					delete e;
					i++;
				}
			}

			QScrollArea* scrollArea = new QScrollArea(this);
			scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
			scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
			scrollArea->setFrameShape(QFrame::NoFrame);
			scrollArea->setWidget(table_);
			scrollArea->setWidgetResizable(true);

			resultGroupLayout->addWidget(scrollArea);
			resultGroup->setLayout(resultGroupLayout);

			mainLayout->addWidget(resultGroup);
			mainLayout->addWidget(buttons);
			setLayout(mainLayout);
			setWindowTitle("Predicted Activity Values for " + item->name());
			table_->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents);

			uint width = 0;
			for(int i=0; i<table_->columnCount();i++)
			{
				width+=table_->columnWidth(i);
			}
			width+=65;
			uint mainWindow_width = item->view()->data_scene->main_window->size().width();
			if(width<mainWindow_width) resize(width,450);
			else resize(mainWindow_width,450);
			table_->setSortingEnabled(1);

			connect(buttons, SIGNAL(accepted()), this, SLOT(accept()));
			connect(print_button, SIGNAL(clicked()), this, SLOT(saveToFile()));
		}

		PredictionResultDialog::~PredictionResultDialog()
		{
		}

		void PredictionResultDialog::saveToFile()
		{
			QString filename = QFileDialog::getSaveFileName(this, tr("Save File as"),file_name_ +"_prediction_results.txt",tr("text (*.txt)"));
			QFile file(filename);
			if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
			{
				return;
			}
			ofstream out(file.fileName().toStdString().c_str());

			uint no_rows=table_->rowCount();
			uint no_cols=table_->columnCount();
			bool use_selection = (table_->selectedItems().size()>1);

			list<int> selected_columns;
			list<int> selected_rows;
			list<int>::iterator col_it;
			list<int>::iterator row_it;
			if(use_selection)
			{
				// find selected columns
				QList<QTableWidgetSelectionRange> ranges = table_->selectedRanges();
				for(int i=0; i<(int)no_cols; i++)
				{
					for(QList<QTableWidgetSelectionRange>::iterator it=ranges.begin();it!=ranges.end();it++)
					{
						if(i<=it->rightColumn() && i>=it->leftColumn())
						{
							selected_columns.push_back(i);
							break;
						}
					}
				}
				col_it=selected_columns.begin();

				// find selected rows
				for(int i=0; i<(int)no_rows; i++)
				{
					for(QList<QTableWidgetSelectionRange>::iterator it=ranges.begin();it!=ranges.end();it++)
					{
						if(i<=it->bottomRow() && i>=it->topRow())
						{
							selected_rows.push_back(i);
							break;
						}
					}
				}
				row_it=selected_rows.begin();
			}

			// print table-header
			for(int i=0; i<(int)no_cols; i++)
			{
				bool write=0;
				if(use_selection)
				{
					if(col_it!=selected_columns.end() && *col_it==i)
					{
						write=1;
						col_it++;
					}
				}
				if(!use_selection || write) out<<table_->horizontalHeaderItem(i)->text().toStdString()<<"\t";

			}
			out<<endl;

			if(use_selection) col_it=selected_columns.begin();

			// print data
			for(int i=0; i<(int)no_rows; i++)
			{
				bool wrote_item=0;
				for(int j=0; j<(int)no_cols; j++)
				{
					if(!use_selection || table_->item(i,j)->isSelected())
					{
						out<<table_->item(i,j)->text().toStdString()<<"\t";
						wrote_item=1;
					}
					else if(col_it!=selected_columns.end() && *col_it==j && row_it!=selected_rows.end() && *row_it==i)
					{
						out<<"\t";
						col_it++;
					}
				}
				if(wrote_item)
				{
					out<<endl;
					if(use_selection)
					{
						row_it++;
						col_it=selected_columns.begin();
					}
				}
			}
		}
	}
}<|endoftext|>


<commit_before>#include <Accelerometer_GY_521_mock.h>

int Accelerometer_GY_521_mock::_init_accelerometer_sensor(){

    size_t len = 0;
    char *update_string = NULL;

    logger.log(LOG_DEBUG, "Opening the file for Accelerometer values");
    //Opening the file (
    save_file = fopen(SAVE_ACCELEROMETER_FILENAME, "r");
    //Registering the update frequency
    if(save_file == NULL){
        logger.log(LOG_ERROR, "Failing to open %s", SAVE_ACCELEROMETER_FILENAME);
        return -1;
    }
    // If the first line is empty
    if(getline(&update_string, &len, save_file) == -1){
        logger.log(LOG_ERROR, "Gyroscope save file is empty");
        return -1;
    }

    // We test if the save file has been save with the same update frequency
    if(atoi(update_string) != update_frequency_ms){
        logger.log(LOG_ERROR, "Error the file has been recorded at %ims,  expecting %ims", atoi(update_string), update_frequency_ms);
        return -1;
    }
    logger.log(LOG_DEBUG, "Accelerometer successfully mocked");
    free(update_string);
    return 0;
}

int Accelerometer_GY_521_mock::_teardown_accelerometer_sensor(){
    int error_code = 0;
    if(fclose(save_file))
        error_code = -1;

    return error_code;
}

double Accelerometer_GY_521_mock::_get_x_acceleration(){
    double value = 0.0;
    load_from_file(&value, AXIS_X);
    return value;
}

double Accelerometer_GY_521_mock::_get_y_acceleration(){
    double value  = 0.0;
    load_from_file(&value, AXIS_Y);
    return value;
}

double Accelerometer_GY_521_mock::_get_z_acceleration(){
    double value = 0.0;
    load_from_file(&value, AXIS_Z);
    return value;
}

/**
 * Allow to load the values directly from a file
 * It can manage values refreshment when needed
 * this function can't be common between gyroscope and accelerometer values because of static values
 */
int Accelerometer_GY_521_mock::load_from_file(double *buffer, axis axis_desired){
    static bool x_new = true;
    static bool y_new = true;
    static bool z_new = true;
    static double x_value = 0.0;
    static double y_value = 0.0;
    static double z_value = 0.0;
    double values_array[3];
    char *values = NULL;
    size_t len;
    // If the value has already been fetched, we must triger a new line reading
    if( (axis_desired == AXIS_X && !x_new) || (axis_desired == AXIS_Y && !y_new) || (axis_desired == AXIS_Z && !z_new)){
        if(getline(&values, &len, save_file) == -1){
            free(values);
            logger.log(LOG_ERROR, "File %s empty", SAVE_ACCELEROMETER_FILENAME);
            return -1;
        }
        // We then get extract decimal values separated by space from the string
        int j=0;
        int previous_index = 0;
        for(int i=0; values[i] != '\0'; i++){
            // if we have found a separator;
            if(values[i] == ' '){
                values[i] = '\0';
                values_array[j] = atof(&values[previous_index]);
                j++;
                //The begining of the next value in the string
                previous_index = i+1;
            }
        }
        values_array[j] = atof(&values[previous_index]);
        x_value = values_array[0];
        y_value = values_array[1];
        z_value = values_array[2];
        x_new = true;
        y_new = true;
        z_new = true;
    }

    // We return the value demanded and turn the associated new flag to false
    switch (axis_desired){
        case AXIS_X:
            *buffer = x_value;
            x_new = false;
            break;
        case AXIS_Y:
            *buffer = y_value;
            y_new = false;
            break;
        case AXIS_Z:
            *buffer = z_value;
            z_new = false;
            break;
    }
    free(values);
    return 0;
}
<commit_msg>Modify error message when mocking is not at the right frequency<commit_after>#include <Accelerometer_GY_521_mock.h>

int Accelerometer_GY_521_mock::_init_accelerometer_sensor(){

    size_t len = 0;
    char *update_string = NULL;

    logger.log(LOG_DEBUG, "Opening the file for Accelerometer values");
    //Opening the file (
    save_file = fopen(SAVE_ACCELEROMETER_FILENAME, "r");
    //Registering the update frequency
    if(save_file == NULL){
        logger.log(LOG_ERROR, "Failing to open %s", SAVE_ACCELEROMETER_FILENAME);
        return -1;
    }
    // If the first line is empty
    if(getline(&update_string, &len, save_file) == -1){
        logger.log(LOG_ERROR, "Gyroscope save file is empty");
        return -1;
    }

    // We test if the save file has been save with the same update frequency
    if(atoi(update_string) != update_frequency_ms){
        logger.log(LOG_ERROR, "Error the file has been recorded at %ims, %ims is not a correct update value", atoi(update_string), update_frequency_ms);
        return -1;
    }
    logger.log(LOG_DEBUG, "Accelerometer successfully mocked");
    free(update_string);
    return 0;
}

int Accelerometer_GY_521_mock::_teardown_accelerometer_sensor(){
    int error_code = 0;
    if(fclose(save_file))
        error_code = -1;

    return error_code;
}

double Accelerometer_GY_521_mock::_get_x_acceleration(){
    double value = 0.0;
    load_from_file(&value, AXIS_X);
    return value;
}

double Accelerometer_GY_521_mock::_get_y_acceleration(){
    double value  = 0.0;
    load_from_file(&value, AXIS_Y);
    return value;
}

double Accelerometer_GY_521_mock::_get_z_acceleration(){
    double value = 0.0;
    load_from_file(&value, AXIS_Z);
    return value;
}

/**
 * Allow to load the values directly from a file
 * It can manage values refreshment when needed
 * this function can't be common between gyroscope and accelerometer values because of static values
 */
int Accelerometer_GY_521_mock::load_from_file(double *buffer, axis axis_desired){
    static bool x_new = true;
    static bool y_new = true;
    static bool z_new = true;
    static double x_value = 0.0;
    static double y_value = 0.0;
    static double z_value = 0.0;
    double values_array[3];
    char *values = NULL;
    size_t len;
    // If the value has already been fetched, we must triger a new line reading
    if( (axis_desired == AXIS_X && !x_new) || (axis_desired == AXIS_Y && !y_new) || (axis_desired == AXIS_Z && !z_new)){
        if(getline(&values, &len, save_file) == -1){
            free(values);
            logger.log(LOG_ERROR, "File %s empty", SAVE_ACCELEROMETER_FILENAME);
            return -1;
        }
        // We then get extract decimal values separated by space from the string
        int j=0;
        int previous_index = 0;
        for(int i=0; values[i] != '\0'; i++){
            // if we have found a separator;
            if(values[i] == ' '){
                values[i] = '\0';
                values_array[j] = atof(&values[previous_index]);
                j++;
                //The begining of the next value in the string
                previous_index = i+1;
            }
        }
        values_array[j] = atof(&values[previous_index]);
        x_value = values_array[0];
        y_value = values_array[1];
        z_value = values_array[2];
        x_new = true;
        y_new = true;
        z_new = true;
    }

    // We return the value demanded and turn the associated new flag to false
    switch (axis_desired){
        case AXIS_X:
            *buffer = x_value;
            x_new = false;
            break;
        case AXIS_Y:
            *buffer = y_value;
            y_new = false;
            break;
        case AXIS_Z:
            *buffer = z_value;
            z_new = false;
            break;
    }
    free(values);
    return 0;
}
<|endoftext|>


<commit_before>#include <yafraycore/ccthreads.h>
#include <iostream>
#include <stdexcept>

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

using namespace std;

namespace yafthreads {

mutex_t::mutex_t()
{
#if HAVE_PTHREAD
	int error=pthread_mutex_init(&m, NULL);
	switch(error)
	{
		case EINVAL: throw std::runtime_error("pthread_mutex_init error EINVAL"); break;
		case ENOMEM: throw std::runtime_error("pthread_mutex_init error ENOMEM"); break;
		case EAGAIN: throw std::runtime_error("pthread_mutex_init error EAGAIN"); break;
		default: break;
	}
#elif defined( WIN32_THREADS )
	winMutex = CreateMutex(0, FALSE, 0);
#endif
}

void mutex_t::lock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_lock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	WaitForSingleObject(winMutex, INFINITE);
#endif
}

void mutex_t::unlock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_unlock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	ReleaseMutex(winMutex);
#endif
}

mutex_t::~mutex_t()
{
#if HAVE_PTHREAD
	pthread_mutex_destroy(&m);
#elif defined( WIN32_THREADS )
	CloseHandle(winMutex);
#endif
}

/* condition object */

conditionVar_t::conditionVar_t()
{
#if HAVE_PTHREAD
	int error=pthread_mutex_init(&m, NULL);
	switch(error)
	{
		case EINVAL: throw std::runtime_error("pthread_mutex_init error EINVAL"); break;
		case ENOMEM: throw std::runtime_error("pthread_mutex_init error ENOMEM"); break;
		case EAGAIN: throw std::runtime_error("pthread_mutex_init error EAGAIN"); break;
		default: break;
	}
	error = pthread_cond_init (&c, NULL);
	if(error != 0)
	{
		throw std::runtime_error("pthread_cond_init error\n");
	}
#elif defined( WIN32_THREADS )
	condHandle = CreateEvent(0, FALSE, FALSE, "yafConditionSignal");
	winMutex = CreateMutex(0, FALSE, 0);
#endif
}

void conditionVar_t::lock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_lock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	WaitForSingleObject(winMutex, INFINITE);
#endif
}

void conditionVar_t::unlock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_unlock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	ReleaseMutex(winMutex);
#endif
}

void conditionVar_t::signal()
{
#if HAVE_PTHREAD
	if(pthread_cond_signal(&c))
	{
		throw std::runtime_error("Error condition signal");
	}
#elif defined( WIN32_THREADS )
	SetEvent(condHandle);
#endif
}

void conditionVar_t::wait()
{
#if HAVE_PTHREAD
	if(pthread_cond_wait(&c, &m))
	{
		throw std::runtime_error("Error condition wait");
	}
#elif defined( WIN32_THREADS )
	unlock();
	SignalObjectAndWait(condHandle, winMutex, INFINITE, FALSE);
#endif
}

conditionVar_t::~conditionVar_t()
{
#if HAVE_PTHREAD
	pthread_mutex_destroy(&m);
	pthread_cond_destroy(&c);
#elif defined( WIN32_THREADS )
	CloseHandle(condHandle);
	CloseHandle(winMutex);
#endif
}

#if HAVE_PTHREAD
void * wrapper(void *data)
{
	thread_t *obj=(thread_t *)data;
	obj->lock.lock();
	try{ obj->body(); }
	catch(std::exception &e)
	{
		std::cout << "exception occured: " << e.what() << std::endl;
	}
	obj->running=false;
	obj->lock.unlock();
	pthread_exit(0);
	return NULL;
}

void thread_t::run()
{
	lock.lock();
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
	pthread_create(&id,&attr,wrapper,this);
	running=true;
	lock.unlock();
}

void thread_t::wait()
{
	if(running)
		pthread_join(id,NULL);
	running=false;
}

thread_t::~thread_t()
{
	wait();
}
#elif defined( WIN32_THREADS )
DWORD WINAPI wrapper (void *data)
{
	thread_t *obj=(thread_t *)data;
	//obj->lock.lock();
	obj->body();
	//obj->lock.unlock();
	return 0;
}

void thread_t::run()
{
	//lock.lock();
	winThread = CreateThread(0, 0, wrapper, this, 0, &id);
	running = true;
	//lock.unlock();
}

void thread_t::wait()
{
	WaitForSingleObject(winThread, INFINITE);
	running = false;
}

thread_t::~thread_t()
{
	if(running) wait();
	CloseHandle(winThread);
}
#endif

} // yafthreads
<commit_msg>- Small fix on threading code: Unnecesary mutex locks slow thread creation on fast systems<commit_after>#include <yafraycore/ccthreads.h>
#include <iostream>
#include <stdexcept>

#ifdef __APPLE__
#include <AvailabilityMacros.h>
#endif

using namespace std;

namespace yafthreads {

mutex_t::mutex_t()
{
#if HAVE_PTHREAD
	int error=pthread_mutex_init(&m, NULL);
	switch(error)
	{
		case EINVAL: throw std::runtime_error("pthread_mutex_init error EINVAL"); break;
		case ENOMEM: throw std::runtime_error("pthread_mutex_init error ENOMEM"); break;
		case EAGAIN: throw std::runtime_error("pthread_mutex_init error EAGAIN"); break;
		default: break;
	}
#elif defined( WIN32_THREADS )
	winMutex = CreateMutex(0, FALSE, 0);
#endif
}

void mutex_t::lock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_lock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	WaitForSingleObject(winMutex, INFINITE);
#endif
}

void mutex_t::unlock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_unlock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	ReleaseMutex(winMutex);
#endif
}

mutex_t::~mutex_t()
{
#if HAVE_PTHREAD
	pthread_mutex_destroy(&m);
#elif defined( WIN32_THREADS )
	CloseHandle(winMutex);
#endif
}

/* condition object */

conditionVar_t::conditionVar_t()
{
#if HAVE_PTHREAD
	int error=pthread_mutex_init(&m, NULL);
	switch(error)
	{
		case EINVAL: throw std::runtime_error("pthread_mutex_init error EINVAL"); break;
		case ENOMEM: throw std::runtime_error("pthread_mutex_init error ENOMEM"); break;
		case EAGAIN: throw std::runtime_error("pthread_mutex_init error EAGAIN"); break;
		default: break;
	}
	error = pthread_cond_init (&c, NULL);
	if(error != 0)
	{
		throw std::runtime_error("pthread_cond_init error\n");
	}
#elif defined( WIN32_THREADS )
	condHandle = CreateEvent(0, FALSE, FALSE, "yafConditionSignal");
	winMutex = CreateMutex(0, FALSE, 0);
#endif
}

void conditionVar_t::lock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_lock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	WaitForSingleObject(winMutex, INFINITE);
#endif
}

void conditionVar_t::unlock()
{
#if HAVE_PTHREAD
	if(pthread_mutex_unlock(&m))
	{
		throw std::runtime_error("Error mutex lock");
	}
#elif defined( WIN32_THREADS )
	ReleaseMutex(winMutex);
#endif
}

void conditionVar_t::signal()
{
#if HAVE_PTHREAD
	if(pthread_cond_signal(&c))
	{
		throw std::runtime_error("Error condition signal");
	}
#elif defined( WIN32_THREADS )
	SetEvent(condHandle);
#endif
}

void conditionVar_t::wait()
{
#if HAVE_PTHREAD
	if(pthread_cond_wait(&c, &m))
	{
		throw std::runtime_error("Error condition wait");
	}
#elif defined( WIN32_THREADS )
	unlock();
	SignalObjectAndWait(condHandle, winMutex, INFINITE, FALSE);
#endif
}

conditionVar_t::~conditionVar_t()
{
#if HAVE_PTHREAD
	pthread_mutex_destroy(&m);
	pthread_cond_destroy(&c);
#elif defined( WIN32_THREADS )
	CloseHandle(condHandle);
	CloseHandle(winMutex);
#endif
}

#if HAVE_PTHREAD
void * wrapper(void *data)
{
	thread_t *obj=(thread_t *)data;
	//obj->lock.lock();
	try{ obj->body(); }
	catch(std::exception &e)
	{
		std::cout << "exception occured: " << e.what() << std::endl;
	}
	obj->running=false;
	//obj->lock.unlock();
	pthread_exit(0);
	return NULL;
}

void thread_t::run()
{
	//lock.lock();
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);
	pthread_create(&id,&attr,wrapper,this);
	running=true;
	//lock.unlock();
}

void thread_t::wait()
{
	//if(running)
		pthread_join(id,NULL);
	running=false;
}

thread_t::~thread_t()
{
	wait();
}
#elif defined( WIN32_THREADS )
DWORD WINAPI wrapper (void *data)
{
	thread_t *obj=(thread_t *)data;
	//obj->lock.lock();
	obj->body();
	//obj->lock.unlock();
	return 0;
}

void thread_t::run()
{
	//lock.lock();
	winThread = CreateThread(0, 0, wrapper, this, 0, &id);
	running = true;
	//lock.unlock();
}

void thread_t::wait()
{
	WaitForSingleObject(winThread, INFINITE);
	running = false;
}

thread_t::~thread_t()
{
	if(running) wait();
	CloseHandle(winThread);
}
#endif

} // yafthreads
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 * Copyright (c) 2021 Google LLC.
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Tests that compute shaders have a subgroup size that is uniform in
 * command scope.
 *//*--------------------------------------------------------------------*/

#include "deUniquePtr.hpp"

#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkImageWithMemory.hpp"
#include "vkBarrierUtil.hpp"

#include "vktTestCaseUtil.hpp"

using namespace vk;

namespace vkt
{
namespace subgroups
{
namespace
{
using std::vector;
using de::MovePtr;

class MultipleDispatchesUniformSubgroupSizeInstance : public TestInstance
{
public:
					MultipleDispatchesUniformSubgroupSizeInstance	(Context&	context);
	tcu::TestStatus	iterate											(void);
};

MultipleDispatchesUniformSubgroupSizeInstance::MultipleDispatchesUniformSubgroupSizeInstance	(Context&	context)
	:TestInstance																				(context)
{
}

tcu::TestStatus MultipleDispatchesUniformSubgroupSizeInstance::iterate (void)
{
	const DeviceInterface&				vk						= m_context.getDeviceInterface();
	const VkDevice						device					= m_context.getDevice();
	Allocator&							allocator				= m_context.getDefaultAllocator();
	const VkQueue						queue					= m_context.getUniversalQueue();
	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();

	const Move<VkCommandPool>			cmdPool					= createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
	const Move<VkCommandBuffer>			cmdBuffer				= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);

	Move<VkShaderModule>				computeShader			= createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0u);

	// The number of invocations in a workgroup.
	const deUint32						maxLocalSize			= m_context.getDeviceProperties().limits.maxComputeWorkGroupSize[0];

	// Create a storage buffer to hold the sizes of subgroups.
	const VkDeviceSize					bufferSize				= maxLocalSize * 2 * sizeof(deUint32);

	const VkBufferCreateInfo			resultBufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
	Move<VkBuffer>						resultBuffer			= createBuffer(vk, device, &resultBufferCreateInfo);
	MovePtr<Allocation>					resultBufferMemory		= allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);

	VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));

	// Build descriptors for the storage buffer
	const Unique<VkDescriptorPool>		descriptorPool			(DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
																						.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
	const auto							descriptorSetLayout1	(DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT)
																							 .build(vk, device));
	const VkDescriptorBufferInfo		resultInfo				= makeDescriptorBufferInfo(*resultBuffer, 0u,
																						   (VkDeviceSize) bufferSize - maxLocalSize * sizeof(deUint32));

	const VkDescriptorSetAllocateInfo	allocInfo				=
	{
		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,	// sType
		DE_NULL,										// pNext
		*descriptorPool,								// descriptorPool
		1u,												// descriptorSetCount
		&(*descriptorSetLayout1)						// pSetLayouts
	};

	Move<VkDescriptorSet>				descriptorSet			= allocateDescriptorSet(vk, device, &allocInfo);
	DescriptorSetUpdateBuilder			builder;

	builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, &resultInfo);
	builder.update(vk, device);

	// Compute pipeline
	const Move<VkPipelineLayout>		computePipelineLayout	= makePipelineLayout (vk, device, *descriptorSetLayout1);

	for (deUint32 localSize1 = 8; localSize1 < maxLocalSize + 1; localSize1 *= 2)
	{
		for (deUint32 localSize2 = 8; localSize2 < maxLocalSize + 1; localSize2 *= 2)
		{
			// On each iteration, change the number of invocations which might affect
			// the subgroup size if the driver doesn't behave as expected.
			const VkSpecializationMapEntry			entries					=
			{
				0u,					// deUint32 constantID;
				0u,					// deUint32 offset;
				sizeof(localSize1)	// size_t size;
			};
			const VkSpecializationInfo				specInfo				=
			{
				1,					// mapEntryCount
				&entries,			// pMapEntries
				sizeof(localSize1),	// dataSize
				&localSize1			// pData
			};
			const VkSpecializationInfo				specInfo2				=
			{
				1,					// mapEntryCount
				&entries,			// pMapEntries
				sizeof(localSize2),	// dataSize
				&localSize2			// pData
			};

			const VkPipelineShaderStageCreateInfo	shaderStageCreateInfo	=
			{
				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,					// sType
				DE_NULL,																// pNext
				VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT,	// flags
				VK_SHADER_STAGE_COMPUTE_BIT,											// stage
				*computeShader,															// module
				"main",																	// pName
				&specInfo,																// pSpecializationInfo
			};

			const VkPipelineShaderStageCreateInfo	shaderStageCreateInfo2	=
			{
				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,					// sType
				DE_NULL,																// pNext
				VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT,	// flags
				VK_SHADER_STAGE_COMPUTE_BIT,											// stage
				*computeShader,															// module
				"main",																	// pName
				&specInfo2,																// pSpecializationInfo
			};

			const VkComputePipelineCreateInfo		pipelineCreateInfo		=
			{
				VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	// sType
				DE_NULL,										// pNext
				0u,												// flags
				shaderStageCreateInfo,							// stage
				*computePipelineLayout,							// layout
				(VkPipeline) 0,									// basePipelineHandle
				0u,												// basePipelineIndex
			};

			const VkComputePipelineCreateInfo		pipelineCreateInfo2		=
			{
				VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	// sType
				DE_NULL,										// pNext
				0u,												// flags
				shaderStageCreateInfo2,							// stage
				*computePipelineLayout,							// layout
				(VkPipeline) 0,									// basePipelineHandle
				0u,												// basePipelineIndex
			};

			Move<VkPipeline>						computePipeline			= createComputePipeline(vk, device, (VkPipelineCache) 0u, &pipelineCreateInfo);
			Move<VkPipeline>						computePipeline2		= createComputePipeline(vk, device, (VkPipelineCache) 0u, &pipelineCreateInfo2);

			beginCommandBuffer(vk, *cmdBuffer);

			// Clears the values written on the previous iteration.
			vk.cmdFillBuffer(*cmdBuffer, *resultBuffer, 0u, VK_WHOLE_SIZE, 0);

			const deUint32							zero					= 0u;
			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &descriptorSet.get(), 1, &zero);
			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
			vk.cmdDispatch(*cmdBuffer, 1, 1, 1);

			const auto								barrier					= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, *resultBuffer, 0ull, bufferSize);
			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags) 0,
								  0, (const VkMemoryBarrier *) DE_NULL, 1, &barrier, 0, (const VkImageMemoryBarrier *) DE_NULL);

			const deUint32							offset					= static_cast<deUint32>(maxLocalSize * sizeof(deUint32));
			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &descriptorSet.get(), 1u, &offset);
			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline2);
			vk.cmdDispatch(*cmdBuffer, 1, 1, 1);

			endCommandBuffer(vk, *cmdBuffer);
			submitCommandsAndWait(vk, device, queue, *cmdBuffer);

			invalidateAlloc(vk, device, *resultBufferMemory);

			const deUint32							*res					= static_cast<const deUint32 *>(resultBufferMemory->getHostPtr());
			deUint32								size					= 0;

			// Search for the first nonzero size. Then go through the data of both pipelines and check that
			// the first nonzero size matches with other nonzero values.
			for (deUint32 i = 0; i < maxLocalSize; i++)
			{
				if (res[i] != 0)
				{
					size = res[i];
					break;
				}
			}

			// Subgroup size is guaranteed to be at least 1.
			DE_ASSERT(size > 0);

			for (deUint32 i = 0; i < maxLocalSize * 2; i++)
			{
				if (size != res[i] && res[i] != 0)
					return tcu::TestStatus::fail("Subgroup size not uniform in command scope. " + std::to_string(res[i]) + " != " + std::to_string(size));
			}
		}
	}

	return tcu::TestStatus::pass("pass");
}

class MultipleDispatchesUniformSubgroupSize : public TestCase
{
public:
						MultipleDispatchesUniformSubgroupSize (tcu::TestContext&	testCtx,
															   const std::string&	name,
															   const std::string&	description);

	void				initPrograms						  (SourceCollections&	programCollection) const;
	TestInstance*		createInstance						  (Context&				context) const;
	virtual void		checkSupport						  (Context&				context) const;

};

MultipleDispatchesUniformSubgroupSize::MultipleDispatchesUniformSubgroupSize (tcu::TestContext&	testCtx,
																			  const std::string&	name,
																			  const std::string&	description)
	: TestCase	(testCtx, name, description)
{
}

void MultipleDispatchesUniformSubgroupSize::checkSupport (Context& context) const
{
	const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures	= context.getSubgroupSizeControlFeatures();

	if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
		TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes");
}

void MultipleDispatchesUniformSubgroupSize::initPrograms (SourceCollections& programCollection) const
{
	std::ostringstream computeSrc;
	computeSrc
		<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
		<< "#extension GL_KHR_shader_subgroup_basic : enable\n"
		<< "#extension GL_KHR_shader_subgroup_vote : enable\n"
		<< "#extension GL_KHR_shader_subgroup_ballot : enable\n"
		<< "layout(std430, binding = 0) buffer Outputs { uint sizes[]; };\n"

		<< "layout(local_size_x_id = 0) in;\n"

		<< "void main()\n"
		<< "{\n"
		<< "    if (subgroupElect())\n"
		<< "    {\n"
		<< "        sizes[gl_WorkGroupID.x * gl_NumSubgroups + gl_SubgroupID] = gl_SubgroupSize;\n"
		<< "    }\n"
		<< "}\n";

	programCollection.glslSources.add("comp") << glu::ComputeSource(computeSrc.str())
	<< ShaderBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
}

TestInstance* MultipleDispatchesUniformSubgroupSize::createInstance (Context& context) const
{
	return new MultipleDispatchesUniformSubgroupSizeInstance(context);
}

} // anonymous ns

tcu::TestCaseGroup* createMultipleDispatchesUniformSubgroupSizeTests (tcu::TestContext& testCtx)
{
	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multiple_dispatches", "Multiple dispatches uniform subgroup size tests"));

	testGroup->addChild(new MultipleDispatchesUniformSubgroupSize(testCtx, "uniform_subgroup_size", ""));
	return testGroup.release();
}

} // compute
} // vkt
<commit_msg>Add missing barrier to fix multi-core issue<commit_after>/*------------------------------------------------------------------------
 * Vulkan Conformance Tests
 * ------------------------
 *
 * Copyright (c) 2021 Google LLC.
 *
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Tests that compute shaders have a subgroup size that is uniform in
 * command scope.
 *//*--------------------------------------------------------------------*/

#include "deUniquePtr.hpp"

#include "vkRef.hpp"
#include "vkRefUtil.hpp"
#include "vkPrograms.hpp"
#include "vkMemUtil.hpp"
#include "vkBuilderUtil.hpp"
#include "vkCmdUtil.hpp"
#include "vkObjUtil.hpp"
#include "vkTypeUtil.hpp"
#include "vkImageWithMemory.hpp"
#include "vkBarrierUtil.hpp"

#include "vktTestCaseUtil.hpp"

using namespace vk;

namespace vkt
{
namespace subgroups
{
namespace
{
using std::vector;
using de::MovePtr;

class MultipleDispatchesUniformSubgroupSizeInstance : public TestInstance
{
public:
					MultipleDispatchesUniformSubgroupSizeInstance	(Context&	context);
	tcu::TestStatus	iterate											(void);
};

MultipleDispatchesUniformSubgroupSizeInstance::MultipleDispatchesUniformSubgroupSizeInstance	(Context&	context)
	:TestInstance																				(context)
{
}

tcu::TestStatus MultipleDispatchesUniformSubgroupSizeInstance::iterate (void)
{
	const DeviceInterface&				vk						= m_context.getDeviceInterface();
	const VkDevice						device					= m_context.getDevice();
	Allocator&							allocator				= m_context.getDefaultAllocator();
	const VkQueue						queue					= m_context.getUniversalQueue();
	const deUint32						queueFamilyIndex		= m_context.getUniversalQueueFamilyIndex();

	const Move<VkCommandPool>			cmdPool					= createCommandPool(vk, device, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, queueFamilyIndex);
	const Move<VkCommandBuffer>			cmdBuffer				= allocateCommandBuffer(vk, device, *cmdPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY);

	Move<VkShaderModule>				computeShader			= createShaderModule (vk, device, m_context.getBinaryCollection().get("comp"), 0u);

	// The number of invocations in a workgroup.
	const deUint32						maxLocalSize			= m_context.getDeviceProperties().limits.maxComputeWorkGroupSize[0];

	// Create a storage buffer to hold the sizes of subgroups.
	const VkDeviceSize					bufferSize				= maxLocalSize * 2 * sizeof(deUint32);

	const VkBufferCreateInfo			resultBufferCreateInfo	= makeBufferCreateInfo(bufferSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
	Move<VkBuffer>						resultBuffer			= createBuffer(vk, device, &resultBufferCreateInfo);
	MovePtr<Allocation>					resultBufferMemory		= allocator.allocate(getBufferMemoryRequirements(vk, device, *resultBuffer), MemoryRequirement::HostVisible);

	VK_CHECK(vk.bindBufferMemory(device, *resultBuffer, resultBufferMemory->getMemory(), resultBufferMemory->getOffset()));

	// Build descriptors for the storage buffer
	const Unique<VkDescriptorPool>		descriptorPool			(DescriptorPoolBuilder().addType(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC)
																						.build(vk, device, VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, 1u));
	const auto							descriptorSetLayout1	(DescriptorSetLayoutBuilder().addSingleBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, VK_SHADER_STAGE_COMPUTE_BIT)
																							 .build(vk, device));
	const VkDescriptorBufferInfo		resultInfo				= makeDescriptorBufferInfo(*resultBuffer, 0u,
																						   (VkDeviceSize) bufferSize - maxLocalSize * sizeof(deUint32));

	const VkDescriptorSetAllocateInfo	allocInfo				=
	{
		VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,	// sType
		DE_NULL,										// pNext
		*descriptorPool,								// descriptorPool
		1u,												// descriptorSetCount
		&(*descriptorSetLayout1)						// pSetLayouts
	};

	Move<VkDescriptorSet>				descriptorSet			= allocateDescriptorSet(vk, device, &allocInfo);
	DescriptorSetUpdateBuilder			builder;

	builder.writeSingle(*descriptorSet, DescriptorSetUpdateBuilder::Location::binding(0u), VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, &resultInfo);
	builder.update(vk, device);

	// Compute pipeline
	const Move<VkPipelineLayout>		computePipelineLayout	= makePipelineLayout (vk, device, *descriptorSetLayout1);

	for (deUint32 localSize1 = 8; localSize1 < maxLocalSize + 1; localSize1 *= 2)
	{
		for (deUint32 localSize2 = 8; localSize2 < maxLocalSize + 1; localSize2 *= 2)
		{
			// On each iteration, change the number of invocations which might affect
			// the subgroup size if the driver doesn't behave as expected.
			const VkSpecializationMapEntry			entries					=
			{
				0u,					// deUint32 constantID;
				0u,					// deUint32 offset;
				sizeof(localSize1)	// size_t size;
			};
			const VkSpecializationInfo				specInfo				=
			{
				1,					// mapEntryCount
				&entries,			// pMapEntries
				sizeof(localSize1),	// dataSize
				&localSize1			// pData
			};
			const VkSpecializationInfo				specInfo2				=
			{
				1,					// mapEntryCount
				&entries,			// pMapEntries
				sizeof(localSize2),	// dataSize
				&localSize2			// pData
			};

			const VkPipelineShaderStageCreateInfo	shaderStageCreateInfo	=
			{
				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,					// sType
				DE_NULL,																// pNext
				VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT,	// flags
				VK_SHADER_STAGE_COMPUTE_BIT,											// stage
				*computeShader,															// module
				"main",																	// pName
				&specInfo,																// pSpecializationInfo
			};

			const VkPipelineShaderStageCreateInfo	shaderStageCreateInfo2	=
			{
				VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,					// sType
				DE_NULL,																// pNext
				VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT,	// flags
				VK_SHADER_STAGE_COMPUTE_BIT,											// stage
				*computeShader,															// module
				"main",																	// pName
				&specInfo2,																// pSpecializationInfo
			};

			const VkComputePipelineCreateInfo		pipelineCreateInfo		=
			{
				VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	// sType
				DE_NULL,										// pNext
				0u,												// flags
				shaderStageCreateInfo,							// stage
				*computePipelineLayout,							// layout
				(VkPipeline) 0,									// basePipelineHandle
				0u,												// basePipelineIndex
			};

			const VkComputePipelineCreateInfo		pipelineCreateInfo2		=
			{
				VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,	// sType
				DE_NULL,										// pNext
				0u,												// flags
				shaderStageCreateInfo2,							// stage
				*computePipelineLayout,							// layout
				(VkPipeline) 0,									// basePipelineHandle
				0u,												// basePipelineIndex
			};

			Move<VkPipeline>						computePipeline			= createComputePipeline(vk, device, (VkPipelineCache) 0u, &pipelineCreateInfo);
			Move<VkPipeline>						computePipeline2		= createComputePipeline(vk, device, (VkPipelineCache) 0u, &pipelineCreateInfo2);

			beginCommandBuffer(vk, *cmdBuffer);

			// Clears the values written on the previous iteration.
			vk.cmdFillBuffer(*cmdBuffer, *resultBuffer, 0u, VK_WHOLE_SIZE, 0);

			const auto								fillBarrier				= makeBufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, *resultBuffer, 0ull, bufferSize);
			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags) 0,
								  0, (const VkMemoryBarrier *) DE_NULL, 1, &fillBarrier, 0, (const VkImageMemoryBarrier *) DE_NULL);

			const deUint32							zero					= 0u;
			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &descriptorSet.get(), 1, &zero);
			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline);
			vk.cmdDispatch(*cmdBuffer, 1, 1, 1);

			const auto								barrier					= makeBufferMemoryBarrier(VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_WRITE_BIT, *resultBuffer, 0ull, bufferSize);
			vk.cmdPipelineBarrier(*cmdBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, (VkDependencyFlags) 0,
								  0, (const VkMemoryBarrier *) DE_NULL, 1, &barrier, 0, (const VkImageMemoryBarrier *) DE_NULL);

			const deUint32							offset					= static_cast<deUint32>(maxLocalSize * sizeof(deUint32));
			vk.cmdBindDescriptorSets(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipelineLayout, 0u, 1u, &descriptorSet.get(), 1u, &offset);
			vk.cmdBindPipeline(*cmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, *computePipeline2);
			vk.cmdDispatch(*cmdBuffer, 1, 1, 1);

			endCommandBuffer(vk, *cmdBuffer);
			submitCommandsAndWait(vk, device, queue, *cmdBuffer);

			invalidateAlloc(vk, device, *resultBufferMemory);

			const deUint32							*res					= static_cast<const deUint32 *>(resultBufferMemory->getHostPtr());
			deUint32								size					= 0;

			// Search for the first nonzero size. Then go through the data of both pipelines and check that
			// the first nonzero size matches with other nonzero values.
			for (deUint32 i = 0; i < maxLocalSize; i++)
			{
				if (res[i] != 0)
				{
					size = res[i];
					break;
				}
			}

			// Subgroup size is guaranteed to be at least 1.
			DE_ASSERT(size > 0);

			for (deUint32 i = 0; i < maxLocalSize * 2; i++)
			{
				if (size != res[i] && res[i] != 0)
					return tcu::TestStatus::fail("Subgroup size not uniform in command scope. " + std::to_string(res[i]) + " != " + std::to_string(size));
			}
		}
	}

	return tcu::TestStatus::pass("pass");
}

class MultipleDispatchesUniformSubgroupSize : public TestCase
{
public:
						MultipleDispatchesUniformSubgroupSize (tcu::TestContext&	testCtx,
															   const std::string&	name,
															   const std::string&	description);

	void				initPrograms						  (SourceCollections&	programCollection) const;
	TestInstance*		createInstance						  (Context&				context) const;
	virtual void		checkSupport						  (Context&				context) const;

};

MultipleDispatchesUniformSubgroupSize::MultipleDispatchesUniformSubgroupSize (tcu::TestContext&	testCtx,
																			  const std::string&	name,
																			  const std::string&	description)
	: TestCase	(testCtx, name, description)
{
}

void MultipleDispatchesUniformSubgroupSize::checkSupport (Context& context) const
{
	const VkPhysicalDeviceSubgroupSizeControlFeaturesEXT&	subgroupSizeControlFeatures	= context.getSubgroupSizeControlFeatures();

	if (subgroupSizeControlFeatures.subgroupSizeControl == DE_FALSE)
		TCU_THROW(NotSupportedError, "Device does not support varying subgroup sizes");
}

void MultipleDispatchesUniformSubgroupSize::initPrograms (SourceCollections& programCollection) const
{
	std::ostringstream computeSrc;
	computeSrc
		<< glu::getGLSLVersionDeclaration(glu::GLSL_VERSION_450) << "\n"
		<< "#extension GL_KHR_shader_subgroup_basic : enable\n"
		<< "#extension GL_KHR_shader_subgroup_vote : enable\n"
		<< "#extension GL_KHR_shader_subgroup_ballot : enable\n"
		<< "layout(std430, binding = 0) buffer Outputs { uint sizes[]; };\n"

		<< "layout(local_size_x_id = 0) in;\n"

		<< "void main()\n"
		<< "{\n"
		<< "    if (subgroupElect())\n"
		<< "    {\n"
		<< "        sizes[gl_WorkGroupID.x * gl_NumSubgroups + gl_SubgroupID] = gl_SubgroupSize;\n"
		<< "    }\n"
		<< "}\n";

	programCollection.glslSources.add("comp") << glu::ComputeSource(computeSrc.str())
	<< ShaderBuildOptions(programCollection.usedVulkanVersion, SPIRV_VERSION_1_3, 0u);
}

TestInstance* MultipleDispatchesUniformSubgroupSize::createInstance (Context& context) const
{
	return new MultipleDispatchesUniformSubgroupSizeInstance(context);
}

} // anonymous ns

tcu::TestCaseGroup* createMultipleDispatchesUniformSubgroupSizeTests (tcu::TestContext& testCtx)
{
	de::MovePtr<tcu::TestCaseGroup> testGroup(new tcu::TestCaseGroup(testCtx, "multiple_dispatches", "Multiple dispatches uniform subgroup size tests"));

	testGroup->addChild(new MultipleDispatchesUniformSubgroupSize(testCtx, "uniform_subgroup_size", ""));
	return testGroup.release();
}

} // compute
} // vkt
<|endoftext|>


<commit_before>/**
 * @file linear_regression.cpp
 * @author James Cline
 *
 * Implementation of simple linear regression.
 */
#include "linear_regression.hpp"

using namespace mlpack;
using namespace mlpack::regression;

LinearRegression::LinearRegression(arma::mat& predictors,
                                   const arma::colvec& responses)
{
  /*
   * We want to calculate the a_i coefficients of:
   * \sum_{i=0}^n (a_i * x_i^i)
   * In order to get the intercept value, we will add a row of ones.
   */

  // We store the number of rows of the predictors.
  // Reminder: Armadillo stores the data transposed from how we think of it,
  //           that is, columns are actually rows (see: column major order).
  size_t nCols = predictors.n_cols;

  // Here we add the row of ones to the predictors.
  arma::rowvec ones;
  ones.ones(nCols);
  predictors.insert_rows(0, ones);

  // We set the parameters to the correct size and initialize them to zero.
  parameters.zeros(nCols);

  // We compute the QR decomposition of the predictors.
  // We transpose the predictors because they are in column major order.
  arma::mat Q, R;
  arma::qr(Q, R, arma::trans(predictors));

  // We compute the parameters, B, like so:
  // R * B = Q^T * responses
  // B = Q^T * responses * R^-1
  arma::solve(parameters, R, arma::trans(Q) * responses);

  // We now remove the row of ones we added so the user's data is unmodified.
  predictors.shed_row(0);
}

LinearRegression::LinearRegression(const std::string& filename)
{
  data::Load(filename, parameters, true);
}

LinearRegression::LinearRegression(const LinearRegression& linearRegression)
{
  parameters = linearRegression.parameters;
}

void LinearRegression::Predict(const arma::mat& points, arma::vec& predictions)
{
  // We get the number of columns and rows of the dataset.
  const size_t nCols = points.n_cols;
  const size_t nRows = points.n_rows;

  // We want to be sure we have the correct number of dimensions in the dataset.
  Log::Assert(points.n_rows == parameters.n_rows - 1);

  // Get the predictions, but this ignores the intercept value (parameters[0]).
  predictions = arma::trans(arma::trans(
      parameters.subvec(1, parameters.n_elem - 1)) * points);

  // Now add the intercept.
  predictions += parameters(0);
}

//! Compute the L2 squared error on the given predictors and responses.
double LinearRegression::ComputeError(const arma::mat& predictors,
                                      const arma::vec& responses) const
{
  // Get the number of columns and rows of the dataset.
  const size_t nCols = predictors.n_cols;
  const size_t nRows = predictors.n_rows;

  // Ensure that we have the correct number of dimensions in the dataset.
  if (nRows != parameters.n_rows - 1)
  {
    Log::Fatal << "The test data must have the same number of columns as the "
        "training file." << std::endl;
  }

  // Calculate the differences between actual responses and predicted responses.
  // We must also add the intercept (parameters(0)) to the predictions.
  arma::vec temp = responses - arma::trans(
      (arma::trans(parameters.subvec(1, parameters.n_elem - 1)) * predictors) +
      parameters(0));

  const double cost = arma::dot(temp, temp) / nCols;

  return cost;
}
<commit_msg>Fix warning, add const.<commit_after>/**
 * @file linear_regression.cpp
 * @author James Cline
 *
 * Implementation of simple linear regression.
 */
#include "linear_regression.hpp"

using namespace mlpack;
using namespace mlpack::regression;

LinearRegression::LinearRegression(arma::mat& predictors,
                                   const arma::colvec& responses)
{
  /*
   * We want to calculate the a_i coefficients of:
   * \sum_{i=0}^n (a_i * x_i^i)
   * In order to get the intercept value, we will add a row of ones.
   */

  // We store the number of rows of the predictors.
  // Reminder: Armadillo stores the data transposed from how we think of it,
  //           that is, columns are actually rows (see: column major order).
  const size_t nCols = predictors.n_cols;

  // Here we add the row of ones to the predictors.
  arma::rowvec ones;
  ones.ones(nCols);
  predictors.insert_rows(0, ones);

  // We set the parameters to the correct size and initialize them to zero.
  parameters.zeros(nCols);

  // We compute the QR decomposition of the predictors.
  // We transpose the predictors because they are in column major order.
  arma::mat Q, R;
  arma::qr(Q, R, arma::trans(predictors));

  // We compute the parameters, B, like so:
  // R * B = Q^T * responses
  // B = Q^T * responses * R^-1
  arma::solve(parameters, R, arma::trans(Q) * responses);

  // We now remove the row of ones we added so the user's data is unmodified.
  predictors.shed_row(0);
}

LinearRegression::LinearRegression(const std::string& filename)
{
  data::Load(filename, parameters, true);
}

LinearRegression::LinearRegression(const LinearRegression& linearRegression)
{
  parameters = linearRegression.parameters;
}

void LinearRegression::Predict(const arma::mat& points, arma::vec& predictions)
{
  // We want to be sure we have the correct number of dimensions in the dataset.
  Log::Assert(points.n_rows == parameters.n_rows - 1);

  // Get the predictions, but this ignores the intercept value (parameters[0]).
  predictions = arma::trans(arma::trans(
      parameters.subvec(1, parameters.n_elem - 1)) * points);

  // Now add the intercept.
  predictions += parameters(0);
}

//! Compute the L2 squared error on the given predictors and responses.
double LinearRegression::ComputeError(const arma::mat& predictors,
                                      const arma::vec& responses) const
{
  // Get the number of columns and rows of the dataset.
  const size_t nCols = predictors.n_cols;
  const size_t nRows = predictors.n_rows;

  // Ensure that we have the correct number of dimensions in the dataset.
  if (nRows != parameters.n_rows - 1)
  {
    Log::Fatal << "The test data must have the same number of columns as the "
        "training file." << std::endl;
  }

  // Calculate the differences between actual responses and predicted responses.
  // We must also add the intercept (parameters(0)) to the predictions.
  arma::vec temp = responses - arma::trans(
      (arma::trans(parameters.subvec(1, parameters.n_elem - 1)) * predictors) +
      parameters(0));

  const double cost = arma::dot(temp, temp) / nCols;

  return cost;
}
<|endoftext|>


<commit_before>/*
    irccontact.cpp - IRC Contact

    Copyright (c) 2002      by Nick Betcher <nbetcher@kde.org>

    Kopete    (c) 2002      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program 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 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kdebug.h>
#include <klocale.h>
#include <qregexp.h>

#include <qtimer.h>
#include <qtextcodec.h>

#include "ircaccount.h"

#include "kopetemetacontact.h"
#include "kopeteview.h"
#include "ircusercontact.h"
#include "irccontact.h"
#include "ircprotocol.h"
#include "ircservercontact.h"
#include "irccontactmanager.h"
#include "ksparser.h"

IRCContact::IRCContact(IRCContactManager *contactManager, const QString &nick, KopeteMetaContact *metac, const QString& icon)
	: KopeteContact(contactManager->account(), nick, metac, icon),
	  m_protocol(static_cast<IRCProtocol *>(protocol())),
	  m_account(contactManager->account()),
	  m_engine(contactManager->engine()),
	  m_metaContact(metac),
	  m_nickName(nick),
	  m_msgManager(0L),
	  m_isConnected(false)
{
	// Contact list display name
	setDisplayName(m_nickName);

	// IRCContactManager stuff
	QObject::connect(contactManager, SIGNAL(privateMessage(IRCContact *, IRCContact *, const QString &)),
			this, SLOT(privateMessage(IRCContact *, IRCContact *, const QString &)));

	QObject::connect(contactManager, SIGNAL(action(IRCContact *, IRCContact *, const QString &)),
			this, SLOT(action(IRCContact *, IRCContact *, const QString &)));

	// KopeteMessageManagerFactory stuff
	mMyself.append( static_cast<KopeteContact*>( this ) );

	// KIRC stuff
	QObject::connect(m_engine, SIGNAL(incomingNickChange(const QString &, const QString &)),
			this, SLOT( slotNewNickChange(const QString&, const QString&)));
	QObject::connect(m_engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
			this, SLOT(slotNewNickChange(const QString &, const QString &)));
	QObject::connect(m_engine, SIGNAL(incomingQuitIRC(const QString &, const QString &)),
			this, SLOT( slotUserDisconnected(const QString&, const QString&)));

	QObject::connect(m_engine, SIGNAL(statusChanged(KIRC::EngineStatus)),
			this, SLOT(updateStatus()));

	m_engine->setCodec( m_nickName, codec() );
}

IRCContact::~IRCContact()
{
//	kdDebug(14120) << k_funcinfo << mNickName << endl;
	if(metaContact() && metaContact()->isTemporary() && !isChatting())
		metaContact()->deleteLater();
}

bool IRCContact::isReachable()
{
	if ( onlineStatus().status() != KopeteOnlineStatus::Offline && onlineStatus().status() != KopeteOnlineStatus::Unknown )
		return true;

	return false;
}

void IRCContact::privateMessage(IRCContact *, IRCContact *, const QString &)
{
}

void IRCContact::action(IRCContact *, IRCContact *, const QString &)
{
}

void IRCContact::setCodec( const QTextCodec *codec )
{
	m_engine->setCodec( m_nickName, codec );
	metaContact()->setPluginData( m_protocol, QString::fromLatin1("Codec"), QString::number(codec->mibEnum()) );
}

const QTextCodec *IRCContact::codec()
{
	QString codecId = metaContact()->pluginData( m_protocol, QString::fromLatin1("Codec") );
	QTextCodec *codec = m_account->codec();

	if( !codecId.isEmpty() )
	{
		bool test = true;
		uint mib = codecId.toInt(&test);
		if( test )
			codec = QTextCodec::codecForMib( mib );
		else
			codec = QTextCodec::codecForName( codecId.latin1() );
	}

	if( !codec )
		return m_engine->codec();

	return codec;
}

KopeteMessageManager *IRCContact::manager(bool canCreate)
{
	if( canCreate && !m_msgManager )
	{
		if(m_engine->status() == KIRC::Disconnected)
			m_account->connect();

		m_msgManager = KopeteMessageManagerFactory::factory()->create( m_account->myself(), mMyself, m_account->protocol());
		m_msgManager->setDisplayName(caption());
		m_isConnected = true;
		QObject::connect( m_msgManager, SIGNAL(messageSent(KopeteMessage&, KopeteMessageManager *)),
			this, SLOT(slotSendMsg(KopeteMessage&, KopeteMessageManager *)));
		QObject::connect( m_msgManager, SIGNAL(closing(KopeteMessageManager*)),
			this, SLOT(messageManagerDestroyed()));

		QTimer::singleShot( 0, this, SLOT( initConversation() ) );
	}

	return m_msgManager;
}

void IRCContact::messageManagerDestroyed()
{
	m_msgManager = 0L;
	m_isConnected = false;

	if( metaContact()->isTemporary() && !isChatting() )
		deleteLater();
}

void IRCContact::slotUserDisconnected(const QString &user, const QString &reason)
{
	if( m_isConnected )
	{
		QString nickname = user.section('!', 0, 0);
		KopeteContact *c = locateUser( nickname );
		if ( c )
		{
			manager()->removeContact( c, i18n("Quit: \"%1\" ").arg(reason) );
			c->setOnlineStatus( m_protocol->m_UserStatusOffline );
		}
	}
}

void IRCContact::slotNewNickChange(const QString &oldnickname, const QString &newnickname)
{
	//kdDebug(14120) << k_funcinfo << oldnickname << " >> " << newnickname << ", " << m_nickName << endl;

	IRCContact *user = static_cast<IRCContact*>( locateUser(oldnickname) );
	if( user )
	{
		user->setNickName( newnickname );
		//If tracking name changes....
		user->setDisplayName( newnickname );

		//If the user is in our contact list, then change the notify list nickname
		if( !user->metaContact()->isTemporary() )
		{
			m_account->contactManager()->removeFromNotifyList( oldnickname );
			m_account->contactManager()->addToNotifyList( newnickname );
		}
	}
}

void IRCContact::slotSendMsg(KopeteMessage &message, KopeteMessageManager *)
{
	QString htmlString = message.escapedBody();

	if( htmlString.find( QString::fromLatin1(" -1 )
	{
		QRegExp findTags( QString::fromLatin1("(.*)") );
		findTags.setMinimal( true );
		int pos = 0;

		while ( pos >= 0 )
		{
			pos = findTags.search( htmlString );
			if ( pos > -1 )
			{
				QString styleHTML = findTags.cap(1);
				QString replacement = findTags.cap(2);
				QStringList styleAttrs = QStringList::split( ';', styleHTML );

				for( QStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair )
				{
					QString attribute = (*attrPair).section(':',0,0);
					QString value = (*attrPair).section(':',1);

					if( attribute == QString::fromLatin1("color") )
					{
						int ircColor = KSParser::colorForHTML( value );
						if( ircColor > -1 )
							replacement.prepend( QString( QChar(0x03) ).append( QString::number(ircColor) ) ).append( QChar( 0x03 ) );
					}
					else if( attribute == QString::fromLatin1("font-weight") && value == QString::fromLatin1("600") )
						replacement.prepend( QChar(0x02) ).append( QChar(0x02) );
					else if( attribute == QString::fromLatin1("text-decoration")  && value == QString::fromLatin1("underline") )
						replacement.prepend( QChar(31) ).append( QChar(31) );
				}

				QRegExp rx( QString::fromLatin1(".*" ).arg( styleHTML ) );
				rx.setMinimal( true );
				htmlString.replace( rx, replacement );
			}
		}
	}

	htmlString = KopeteMessage::unescape( htmlString );

	if( htmlString.find( '\n' ) > -1 )
	{
		QStringList messages = QStringList::split( '\n', htmlString );

		for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it )
		{
			KopeteMessage msg(message.from(), message.to(), *it, message.direction(),
				KopeteMessage::RichText, message.type() );

			m_engine->messageContact(m_nickName, *it );

			msg.setBg( QColor() );
			msg.setFg( QColor() );

			appendMessage(msg);
			manager()->messageSucceeded();
		}
	}
	else
	{
		m_engine->messageContact(m_nickName, htmlString );

		message.setBg( QColor() );
		message.setFg( QColor() );

		appendMessage(message);
		manager()->messageSucceeded();
	}
}

KopeteContact *IRCContact::locateUser( const QString &nick )
{
	//kdDebug(14120) << k_funcinfo << "Find nick " << nick << endl;
	if( m_isConnected )
	{
		if( nick == m_account->mySelf()->nickName() )
			return m_account->mySelf();
		else
		{
			KopeteContactPtrList mMembers = manager()->members();
			for( KopeteContact *it = mMembers.first(); it; it = mMembers.next() )
			{
				if( static_cast<IRCContact*>(it)->nickName() == nick )
					return it;
			}
		}
	}

	return 0L;
}

bool IRCContact::isChatting( KopeteMessageManager *avoid ) const
{
	QIntDict<KopeteMessageManager> sessions = KopeteMessageManagerFactory::factory()->sessions();
	for ( QIntDictIterator<KopeteMessageManager> it( sessions ); it.current() ; ++it )
	{
		if( it.current() != avoid && it.current()->account() == m_account &&
			it.current()->members().contains(this) )
		{
			return true;
		}
	}

	return false;
}

void IRCContact::slotDeleteContact()
{
	kdDebug(14120) << k_funcinfo << m_nickName << endl;
	if( !isChatting() )
	{
		kdDebug(14120) << k_funcinfo << "will delete " << m_nickName << endl;
		KopeteContact::slotDeleteContact();
	}
}

void IRCContact::appendMessage( KopeteMessage &msg )
{
	manager()->appendMessage(msg);
}

KopeteView *IRCContact::view()
{
	if( m_msgManager )
		return manager()->view(false);
	return 0L;
}

#include "irccontact.moc"
<commit_msg>Fix crash bug when deleting a user you're chatting with<commit_after>/*
    irccontact.cpp - IRC Contact

    Copyright (c) 2002      by Nick Betcher <nbetcher@kde.org>

    Kopete    (c) 2002      by the Kopete developers <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program 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 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include <kdebug.h>
#include <klocale.h>
#include <qregexp.h>

#include <qtimer.h>
#include <qtextcodec.h>

#include "ircaccount.h"

#include "kopetemetacontact.h"
#include "kopeteview.h"
#include "ircusercontact.h"
#include "irccontact.h"
#include "ircprotocol.h"
#include "ircservercontact.h"
#include "irccontactmanager.h"
#include "ksparser.h"

IRCContact::IRCContact(IRCContactManager *contactManager, const QString &nick, KopeteMetaContact *metac, const QString& icon)
	: KopeteContact(contactManager->account(), nick, metac, icon),
	  m_protocol(static_cast<IRCProtocol *>(protocol())),
	  m_account(contactManager->account()),
	  m_engine(contactManager->engine()),
	  m_metaContact(metac),
	  m_nickName(nick),
	  m_msgManager(0L),
	  m_isConnected(false)
{
	// Contact list display name
	setDisplayName(m_nickName);

	// IRCContactManager stuff
	QObject::connect(contactManager, SIGNAL(privateMessage(IRCContact *, IRCContact *, const QString &)),
			this, SLOT(privateMessage(IRCContact *, IRCContact *, const QString &)));

	QObject::connect(contactManager, SIGNAL(action(IRCContact *, IRCContact *, const QString &)),
			this, SLOT(action(IRCContact *, IRCContact *, const QString &)));

	// KopeteMessageManagerFactory stuff
	mMyself.append( static_cast<KopeteContact*>( this ) );

	// KIRC stuff
	QObject::connect(m_engine, SIGNAL(incomingNickChange(const QString &, const QString &)),
			this, SLOT( slotNewNickChange(const QString&, const QString&)));
	QObject::connect(m_engine, SIGNAL(successfullyChangedNick(const QString &, const QString &)),
			this, SLOT(slotNewNickChange(const QString &, const QString &)));
	QObject::connect(m_engine, SIGNAL(incomingQuitIRC(const QString &, const QString &)),
			this, SLOT( slotUserDisconnected(const QString&, const QString&)));

	QObject::connect(m_engine, SIGNAL(statusChanged(KIRC::EngineStatus)),
			this, SLOT(updateStatus()));

	m_engine->setCodec( m_nickName, codec() );
}

IRCContact::~IRCContact()
{
//	kdDebug(14120) << k_funcinfo << mNickName << endl;
	if(metaContact() && metaContact()->isTemporary() && !isChatting())
		metaContact()->deleteLater();
}

bool IRCContact::isReachable()
{
	if ( onlineStatus().status() != KopeteOnlineStatus::Offline && onlineStatus().status() != KopeteOnlineStatus::Unknown )
		return true;

	return false;
}

void IRCContact::privateMessage(IRCContact *, IRCContact *, const QString &)
{
}

void IRCContact::action(IRCContact *, IRCContact *, const QString &)
{
}

void IRCContact::setCodec( const QTextCodec *codec )
{
	m_engine->setCodec( m_nickName, codec );
	metaContact()->setPluginData( m_protocol, QString::fromLatin1("Codec"), QString::number(codec->mibEnum()) );
}

const QTextCodec *IRCContact::codec()
{
	QString codecId = metaContact()->pluginData( m_protocol, QString::fromLatin1("Codec") );
	QTextCodec *codec = m_account->codec();

	if( !codecId.isEmpty() )
	{
		bool test = true;
		uint mib = codecId.toInt(&test);
		if( test )
			codec = QTextCodec::codecForMib( mib );
		else
			codec = QTextCodec::codecForName( codecId.latin1() );
	}

	if( !codec )
		return m_engine->codec();

	return codec;
}

KopeteMessageManager *IRCContact::manager(bool canCreate)
{
	if( canCreate && !m_msgManager )
	{
		if(m_engine->status() == KIRC::Disconnected)
			m_account->connect();

		m_msgManager = KopeteMessageManagerFactory::factory()->create( m_account->myself(), mMyself, m_account->protocol());
		m_msgManager->setDisplayName(caption());
		m_isConnected = true;
		QObject::connect( m_msgManager, SIGNAL(messageSent(KopeteMessage&, KopeteMessageManager *)),
			this, SLOT(slotSendMsg(KopeteMessage&, KopeteMessageManager *)));
		QObject::connect( m_msgManager, SIGNAL(closing(KopeteMessageManager*)),
			this, SLOT(messageManagerDestroyed()));

		QTimer::singleShot( 0, this, SLOT( initConversation() ) );
	}

	return m_msgManager;
}

void IRCContact::messageManagerDestroyed()
{
	m_msgManager = 0L;
	m_isConnected = false;

	if( metaContact()->isTemporary() && !isChatting() )
		deleteLater();
}

void IRCContact::slotUserDisconnected(const QString &user, const QString &reason)
{
	if( m_isConnected )
	{
		QString nickname = user.section('!', 0, 0);
		KopeteContact *c = locateUser( nickname );
		if ( c )
		{
			manager()->removeContact( c, i18n("Quit: \"%1\" ").arg(reason) );
			c->setOnlineStatus( m_protocol->m_UserStatusOffline );
		}
	}
}

void IRCContact::slotNewNickChange(const QString &oldnickname, const QString &newnickname)
{
	//kdDebug(14120) << k_funcinfo << oldnickname << " >> " << newnickname << ", " << m_nickName << endl;

	IRCContact *user = static_cast<IRCContact*>( locateUser(oldnickname) );
	if( user )
	{
		user->setNickName( newnickname );
		//If tracking name changes....
		user->setDisplayName( newnickname );

		//If the user is in our contact list, then change the notify list nickname
		if( !user->metaContact()->isTemporary() )
		{
			m_account->contactManager()->removeFromNotifyList( oldnickname );
			m_account->contactManager()->addToNotifyList( newnickname );
		}
	}
}

void IRCContact::slotSendMsg(KopeteMessage &message, KopeteMessageManager *)
{
	QString htmlString = message.escapedBody();

	if( htmlString.find( QString::fromLatin1(" -1 )
	{
		QRegExp findTags( QString::fromLatin1("(.*)") );
		findTags.setMinimal( true );
		int pos = 0;

		while ( pos >= 0 )
		{
			pos = findTags.search( htmlString );
			if ( pos > -1 )
			{
				QString styleHTML = findTags.cap(1);
				QString replacement = findTags.cap(2);
				QStringList styleAttrs = QStringList::split( ';', styleHTML );

				for( QStringList::Iterator attrPair = styleAttrs.begin(); attrPair != styleAttrs.end(); ++attrPair )
				{
					QString attribute = (*attrPair).section(':',0,0);
					QString value = (*attrPair).section(':',1);

					if( attribute == QString::fromLatin1("color") )
					{
						int ircColor = KSParser::colorForHTML( value );
						if( ircColor > -1 )
							replacement.prepend( QString( QChar(0x03) ).append( QString::number(ircColor) ) ).append( QChar( 0x03 ) );
					}
					else if( attribute == QString::fromLatin1("font-weight") && value == QString::fromLatin1("600") )
						replacement.prepend( QChar(0x02) ).append( QChar(0x02) );
					else if( attribute == QString::fromLatin1("text-decoration")  && value == QString::fromLatin1("underline") )
						replacement.prepend( QChar(31) ).append( QChar(31) );
				}

				QRegExp rx( QString::fromLatin1(".*" ).arg( styleHTML ) );
				rx.setMinimal( true );
				htmlString.replace( rx, replacement );
			}
		}
	}

	htmlString = KopeteMessage::unescape( htmlString );

	if( htmlString.find( '\n' ) > -1 )
	{
		QStringList messages = QStringList::split( '\n', htmlString );

		for( QStringList::Iterator it = messages.begin(); it != messages.end(); ++it )
		{
			KopeteMessage msg(message.from(), message.to(), *it, message.direction(),
				KopeteMessage::RichText, message.type() );

			m_engine->messageContact(m_nickName, *it );

			msg.setBg( QColor() );
			msg.setFg( QColor() );

			appendMessage(msg);
			manager()->messageSucceeded();
		}
	}
	else
	{
		m_engine->messageContact(m_nickName, htmlString );

		message.setBg( QColor() );
		message.setFg( QColor() );

		appendMessage(message);
		manager()->messageSucceeded();
	}
}

KopeteContact *IRCContact::locateUser( const QString &nick )
{
	//kdDebug(14120) << k_funcinfo << "Find nick " << nick << endl;
	if( m_isConnected )
	{
		if( nick == m_account->mySelf()->nickName() )
			return m_account->mySelf();
		else
		{
			KopeteContactPtrList mMembers = manager()->members();
			for( KopeteContact *it = mMembers.first(); it; it = mMembers.next() )
			{
				if( static_cast<IRCContact*>(it)->nickName() == nick )
					return it;
			}
		}
	}

	return 0L;
}

bool IRCContact::isChatting( KopeteMessageManager *avoid ) const
{
	QIntDict<KopeteMessageManager> sessions = KopeteMessageManagerFactory::factory()->sessions();
	for ( QIntDictIterator<KopeteMessageManager> it( sessions ); it.current() ; ++it )
	{
		if( it.current() != avoid && it.current()->account() == m_account &&
			it.current()->members().contains(this) )
		{
			return true;
		}
	}

	return false;
}

void IRCContact::slotDeleteContact()
{
	kdDebug(14120) << k_funcinfo << m_nickName << endl;

	if( manager(false) )
		delete manager();

	if( !isChatting() )
	{
		kdDebug(14120) << k_funcinfo << "will delete " << m_nickName << endl;
		KopeteContact::slotDeleteContact();
	}
	else
	{
		metaContact()->removeContact( this );
		KopeteMetaContact *m = new KopeteMetaContact();
		m->setTemporary( true );
		setMetaContact( m );
	}
}

void IRCContact::appendMessage( KopeteMessage &msg )
{
	manager()->appendMessage(msg);
}

KopeteView *IRCContact::view()
{
	if( m_msgManager )
		return manager()->view(false);
	return 0L;
}

#include "irccontact.moc"
<|endoftext|>