<commit_before>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include "core/clever.h"
#include "core/value.h"
#include "modules/std/concurrent/module.h"
#include "modules/std/concurrent/thread.h"
#include "modules/std/core/function.h"
#include "types/type.h"

namespace clever { namespace packages { namespace std {

static inline void* ThreadHandler(void* ThreadArgument){
	ThreadData* intern = static_cast<ThreadData*>(ThreadArgument);

	::std::cout << "Hello From ThreadHandler" << ::std::endl;

	return intern;
}

void Thread::dump(const void* data) const
{
	dump(data, ::std::cout);
}

void Thread::dump(const void* data, ::std::ostream& out) const
{
	Value::DataValue* dvalue =
		static_cast<Value::DataValue*>(const_cast<void*>(data));
	if (dvalue) {

	}
}

void* Thread::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	ThreadData* intern = new ThreadData;
	if (intern) {

		intern->thread = new pthread_t;
		intern->lock = new pthread_mutex_t;
		intern->entry = NULL;

		if (intern->lock) {
			if (pthread_mutex_init(intern->lock, NULL) != 0) {
				clever_error("Thread.new failed to initialize a lock for the Thread");
			}
		}

		if (args->size()) {

			Value* point = args->at(0);

			/** there's something very wrong here **/
			if (point->getType() == CLEVER_FUNC_TYPE) {
				intern->entry = static_cast<Function*>(point->getObj());
			} else {
				clever_error("Thread.new was expecting a Function and got something else at %@", point);
			}
		} else {
			clever_error("Thread.new was expecting a Function entry point and recieved no arguments");
		}
	}
	return intern;
}

void Thread::deallocData(void* data)
{
	ThreadData* intern = static_cast<ThreadData*>(data);
	if (intern) {

		if (intern->lock) {
			if (pthread_mutex_destroy(intern->lock) != 0) {
				clever_error("Thread.delete experienced an error destroying the Thread's lock");
			}

			delete intern->lock;
		}

		delete intern->thread;
		delete intern;
	}
}

CLEVER_METHOD(Thread::start)
{
	ThreadData* intern = CLEVER_GET_OBJECT(ThreadData*, CLEVER_THIS());

	if (!intern) {
		//CLEVER_THROW(eventually)
		return;
	}

	if (intern->entry != NULL) {
		/** @TODO(krakjoe) pthread attributes **/

		if (pthread_mutex_lock(intern->lock) == 0) {
			result->setBool(
				(pthread_create(intern->thread, NULL, ThreadHandler, intern) == 0)
			);
			pthread_mutex_unlock(intern->lock);
		} else {
			/* report fatality */
			result->setBool(false);
		}
	} else {
		result->setBool(false);
	}
}

CLEVER_TYPE_INIT(Thread::init)
{
	addMethod(new Function("start",    (MethodPtr)&Thread::start));
}

}}} // clever::packages::std
<commit_msg>- CS, nesting--<commit_after>/**
 * Clever programming language
 * Copyright (c) Clever Team
 *
 * This file is distributed under the MIT license. See LICENSE for details.
 */

#include "core/clever.h"
#include "core/value.h"
#include "modules/std/concurrent/module.h"
#include "modules/std/concurrent/thread.h"
#include "modules/std/core/function.h"
#include "types/type.h"

namespace clever { namespace packages { namespace std {

static inline void* ThreadHandler(void* ThreadArgument)
{
	ThreadData* intern = static_cast<ThreadData*>(ThreadArgument);

	::std::cout << "Hello From ThreadHandler" << ::std::endl;

	return intern;
}

void Thread::dump(const void* data) const
{
	dump(data, ::std::cout);
}

void Thread::dump(const void* data, ::std::ostream& out) const
{
	Value::DataValue* dvalue =
		static_cast<Value::DataValue*>(const_cast<void*>(data));
	if (dvalue) {

	}
}

void* Thread::allocData(CLEVER_TYPE_CTOR_ARGS) const
{
	ThreadData* intern = new ThreadData;

	intern->thread = new pthread_t;
	intern->lock = new pthread_mutex_t;
	intern->entry = NULL;

	if (intern->lock) {
		if (pthread_mutex_init(intern->lock, NULL) != 0) {
			clever_error("Thread.new failed to initialize a lock for the Thread");
		}
	}

	if (args->size()) {
		Value* point = args->at(0);

		/** there's something very wrong here **/
		if (point->getType() == CLEVER_FUNC_TYPE) {
			intern->entry = static_cast<Function*>(point->getObj());
		} else {
			clever_error("Thread.new was expecting a Function and got something else at %@", point);
		}
	} else {
		clever_error("Thread.new was expecting a Function entry point and recieved no arguments");
	}
	return intern;
}

void Thread::deallocData(void* data)
{
	ThreadData* intern = static_cast<ThreadData*>(data);

	if (!intern) {
		return;
	}

	if (intern->lock) {
		if (pthread_mutex_destroy(intern->lock) != 0) {
			clever_error("Thread.delete experienced an error destroying the Thread's lock");
		}
		delete intern->lock;
	}

	delete intern->thread;
	delete intern;
}

CLEVER_METHOD(Thread::start)
{
	ThreadData* intern = CLEVER_GET_OBJECT(ThreadData*, CLEVER_THIS());

	if (!intern) {
		//CLEVER_THROW(eventually)
		return;
	}

	if (intern->entry != NULL) {
		/** @TODO(krakjoe) pthread attributes **/

		if (pthread_mutex_lock(intern->lock) == 0) {
			result->setBool(
				(pthread_create(intern->thread, NULL, ThreadHandler, intern) == 0)
			);
			pthread_mutex_unlock(intern->lock);
		} else {
			/* report fatality */
			result->setBool(false);
		}
	} else {
		result->setBool(false);
	}
}

CLEVER_TYPE_INIT(Thread::init)
{
	addMethod(new Function("start",    (MethodPtr)&Thread::start));
}

}}} // clever::packages::std
<|endoftext|>


<commit_before>//================================================================================
//
//	The MIT License (MIT)
//
//	Copyright (c) 2014 Konstantinos Sofokleous
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//
//================================================================================

//#define SLOG_DISABLE 0
//#define SLOG_DISABLE_INFO 0
#include <slog/slog.h>

int main(int argc, char* argv[])
{
	slog::logconfig::parse(argc, argv);

	{
		slog::filelogdevice keep_this_instance_around("logoutput.log", true);

		slog::info();
		slog::info() << "---------------- NEW RUN ----------------";
		slog::info() << "slog version " << slog::getmajorversion() << "." << slog::getminorversion() << "." << slog::getpatchversion();

		slog::error() << "major error: failed to say hello to world";
		slog::warn() << "warning: this should be yellow";
		slog::info() << "fyi: life is full of meaningless little lines";
		slog::verbose() << "verbosity: also known as 'it goes to eleven'";
	}

	slog::debug() << "major debug reporting for duty... this log wont make in the log file";

	return 0;
}<commit_msg>added some more tests<commit_after>//================================================================================
//
//	The MIT License (MIT)
//
//	Copyright (c) 2014 Konstantinos Sofokleous
//
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//
//================================================================================

//#define SLOG_DISABLE 0
//#define SLOG_DISABLE_INFO 0
#include <slog/slog.h>

void compare_file_contents(const char* filename, std::string contents, std::string errorstring)
{
	std::ifstream file(filename);
	if (file.bad())
		throw std::runtime_error(strobj() << "compare_file_contents :: file '" << filename << "'");

	std::string value;
	file >> value;

	if (value.compare(contents) != 0)
		throw std::runtime_error(strobj() << errorstring);
}

/// --- tests

void emptylog(int argc, char* argv[])
{
	const char logfilename[] = "emptylog.test.log";
	if (_unlink(logfilename) != 0 && (errno != ENOENT))
		throw std::runtime_error(strobj() << "emptylog :: failed to delete file '" << logfilename << "'");

	{
		slog::filelogdevice logfile(logfilename, true);
		slog::info::type.enabled = false;
		slog::info() << "test";
		slog::info::type.enabled = true;
	}

	compare_file_contents(logfilename, "", "type.enabled = false; failed not to write to log file");
}

void simple_log_line(int argc, char* argv[])
{
	const char thisline[] = "this simple line";

	auto prevtime = slog::logconfig::timestamps;
	auto prevprintlogtype = slog::logconfig::print_logtype;
	slog::logconfig::timestamps = false;
	slog::logconfig::print_logtype = false;

	slog::logconfig::set_default_console_print([&thisline](const slog::logtype& type, const std::string& line)
	{
		if (line.compare(thisline) != 0)
			throw std::runtime_error(strobj() << "simple_log_line :: failed compose a simple log line with all prefixes removed");
	});

	slog::info() << thisline;

	slog::logconfig::timestamps = prevtime;
	slog::logconfig::print_logtype = prevprintlogtype;
	slog::logconfig::set_default_console_print(nullptr);
}

void default_verbose_debug_off(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() > 0)
			throw std::runtime_error(strobj() << "default_verbose_debug_off :: default state of verbose and debug is not disabled");
	});

	slog::debug() << "testing";
	slog::verbose() << "testing again";

	slog::logconfig::set_default_console_print(nullptr);
}

void empty_lines_should_print(int argc, char* argv[])
{
	slog::logconfig::set_default_console_print([](const slog::logtype& type, const std::string& line)
	{
		if (line.length() == 0)
			throw std::runtime_error(strobj() << "empty_lines_should_print :: empty info line printed nothing");
	});

	slog::info();

	slog::logconfig::set_default_console_print(nullptr);
}

// -------------------------------------------------------------------------------------

#include <iostream>

int main(int argc, char* argv[])
{
	try
	{
		emptylog(argc, argv);
		simple_log_line(argc, argv);
		default_verbose_debug_off(argc, argv);
		empty_lines_should_print(argc, argv);

		slog::logconfig::parse(argc, argv);

		{
			slog::filelogdevice keep_this_instance_around("logoutput.log", true);

			slog::info();
			slog::info() << "---------------- NEW RUN ----------------";
			slog::info() << "slog version " << slog::getmajorversion() << "." << slog::getminorversion() << "." << slog::getpatchversion();

			slog::error() << "major error: failed to say hello to world";
			slog::warn() << "warning: this should be yellow";
			slog::info() << "fyi: life is full of meaningless little lines";
			slog::verbose() << "verbosity: also known as 'it goes to eleven'";
			slog::success() << "success: you only see this when you get lucky";
		}

		slog::debug() << "major debug reporting for duty... this log wont make in the log file";
	}
	catch (std::exception& e)
	{
		std::cerr << "Test failed: " << e.what() << std::endl;
		return -1;
	}

	std::cout << "All tests succeeded" << std::endl;

	return 0;
}<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Flacon - audio File Encoder
 * https://github.com/flacon/flacon
 *
 * Copyright: 2017
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "tools.h"

#include <QTest>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <QCryptographicHash>
#include <QIODevice>
#include <QBuffer>
#include <QDebug>
#include "../settings.h"
#include "../cue.h"
#include "../disk.h"
#include "../converter/decoder.h"

class HashDevice: public QIODevice {
public:
    HashDevice(QCryptographicHash::Algorithm method, QObject *parent = nullptr):
        QIODevice(parent),
        mHash(method),
        mInHeader(true)
    {
    }

    QByteArray result() const { return mHash.result(); }

protected:
    qint64 readData(char*, qint64) { return -1; }

    qint64 writeData(const char *data, qint64 len)
    {
        if (mInHeader)
        {
            mBuf.append(data, len);
            int n = mBuf.indexOf("data");
            if (n > -1 && n < mBuf.length() - 8)
            {
                mInHeader = false;
                mHash.addData(mBuf.data() + n + 8, mBuf.length() - n - 8);
            }
            return len;
        }

        mHash.addData(data, len);
        return len;
    }

private:
    QByteArray mBuf;
    QCryptographicHash mHash;
    bool mInHeader;
};

/************************************************
 *
 ************************************************/
QString calcAudioHash(const QString &fileName)
{
    Decoder decoder;
    try
    {
        decoder.open(fileName);
    }
    catch (FlaconError &err)
    {
        FAIL(QString("Can't open input file '%1': %2").arg(fileName, err.what()).toLocal8Bit());
        return "";
    }

    if (!decoder.audioFormat())
    {
        FAIL("Unknown format");
        decoder.close();
        return "";
    }

    HashDevice hash(QCryptographicHash::Md5);
    hash.open(QIODevice::WriteOnly);
    decoder.extract(CueTime(), CueTime(), &hash);
    decoder.close();

    return hash.result().toHex();
}

/************************************************
 *
 ************************************************/
TestCueFile::TestCueFile(const QString &fileName):
    mFileName(fileName)
{
}

/************************************************
 *
 ************************************************/
void TestCueFile::setWavFile(const QString &value)
{
    mWavFile = value;
}

/************************************************
 *
 ************************************************/
void TestCueFile::addTrack(const QString &index0, const QString &index1)
{
    mTracks << TestCueTrack(index0, index1);
}

/************************************************
 *
 ************************************************/
void TestCueFile::addTrack(const QString &index1)
{
    addTrack("", index1);
}

/************************************************
 *
 ************************************************/
void TestCueFile::write()
{
    QFile f(mFileName);
    if (!f.open(QFile::WriteOnly | QFile::Truncate))
        QFAIL(QString("Can't create cue file '%1': %2").arg(mFileName).arg(f.errorString()).toLocal8Bit());

    QTextStream cue(&f);

    cue << QString("FILE \"%1\" WAVE\n").arg(mWavFile);
    for (int i=0; i < mTracks.count(); ++i)
    {
        TestCueTrack track = mTracks.at(i);

        cue << QString("\nTRACK %1 AUDIO\n").arg(i + 1);
        if (track.index0 != "")
            cue << QString("  INDEX 00 %1\n").arg(track.index0);

        if (track.index1 != "")
            cue << QString("  INDEX 01 %1\n").arg(track.index1);
    }

    f.close();
}

/************************************************
 *
 ************************************************/
bool compareAudioHash(const QString &file1, const QString &expected)
{
    if (calcAudioHash(file1) != expected)
    {
        FAIL(QString("Compared hases are not the same for:\n"
                     "    [%1] %2\n"
                     "    [%3] %4\n")

                    .arg(calcAudioHash(file1))
                    .arg(file1)

                    .arg(expected)
                    .arg("expected")

                    .toLocal8Bit());
        return false;
    }
    return true;
}

/************************************************
 *
 ************************************************/
void writeHexString(const QString &str, QIODevice *out)
{
    for (QString line : str.split('\n'))
    {
        for (int i=0;  i<line.length()-1;)
        {
            // Skip comments
            if (line.at(i) == '/')
                break;

            if (line.at(i).isSpace())
            {
                ++i;
                continue;
            }

            union {
                quint16 n16;
                char b;
            };

            bool ok;
            n16 = line.mid(i, 2).toShort(&ok, 16);
            if (!ok)
                throw QString("Incorrect HEX data at %1:\n%2").arg(i).arg(line);

            out->write(&b, 1);
            i+=2;
        }
    }
}

/************************************************
 *
 ************************************************/
QByteArray writeHexString(const QString &str)
{
    QBuffer data;
    data.open(QBuffer::ReadWrite);
    writeHexString(str, &data);
    return data.buffer();
}

/************************************************
 *
 ************************************************/
static void writeTestWavData(QIODevice *device, quint64 dataSize)
{
    static const int BUF_SIZE = 1024 * 1024;

    quint32 x=123456789, y=362436069, z=521288629;
    union {
        quint32 t;
        char    bytes[4];
    };

    QByteArray buf;

    buf.reserve(4 * 1024 * 1024);
    buf.reserve(BUF_SIZE);
    for (uint i=0; i<(dataSize/ sizeof(quint32)); ++i)
    {
        // xorshf96 ...................
        x ^= x << 16;
        x ^= x >> 5;
        x ^= x << 1;

        t = x;
        x = y;
        y = z;
        z = t ^ x ^ y;
        // xorshf96 ...................

        buf.append(bytes, 4);
        if (buf.size() >= BUF_SIZE)
        {
            device->write(buf);
            buf.resize(0);
        }
    }

    device->write(buf);
}

/************************************************
 *
 ************************************************/
void createWavFile(const QString &fileName, const QString &header, const int duration)
{
    QBuffer wavHdr;
    wavHdr.open(QBuffer::ReadWrite);
    writeHexString(header, &wavHdr);

    if (duration) {
        quint32 bitsPerSample =
                (quint8(wavHdr.buffer()[28]) << 0) +
                (quint8(wavHdr.buffer()[29]) <<  8) +
                (quint8(wavHdr.buffer()[30]) << 16) +
                (quint8(wavHdr.buffer()[31]) << 24);

        quint32 ckSize = bitsPerSample * duration + wavHdr.buffer().size() - 8 + 8;
        wavHdr.buffer()[4] = quint8(ckSize >>  0);
        wavHdr.buffer()[5] = quint8(ckSize >>  8);
        wavHdr.buffer()[6] = quint8(ckSize >> 16);
        wavHdr.buffer()[7] = quint8(ckSize >> 24);
    }

    // See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
    quint32 ckSize =
            (quint8(wavHdr.buffer()[4]) <<  0) +
            (quint8(wavHdr.buffer()[5]) <<  8) +
            (quint8(wavHdr.buffer()[6]) << 16) +
            (quint8(wavHdr.buffer()[7]) << 24);

    quint32 dataSize = ckSize - wavHdr.size();

    QFile file(fileName);

    if (file.exists() && file.size() == ckSize + 8)
        return;

    if (!file.open(QFile::WriteOnly | QFile::Truncate))
        QFAIL(QString("Can't create file '%1': %2").arg(fileName, file.errorString()).toLocal8Bit());

    file.write(wavHdr.buffer());
    file.write("data", 4);
    char buf[4];
    buf[0] = quint8(dataSize);
    buf[1] = quint8(dataSize >> 8);
    buf[2] = quint8(dataSize >> 16);
    buf[3] = quint8(dataSize >> 24);
    file.write(buf, 4);

    writeTestWavData(&file, dataSize);
    file.close();
}

/************************************************
 *
 ************************************************/
void encodeAudioFile(const QString &wavFileName, const QString &outFileName)
{
    if (QFileInfo(outFileName).exists())
        return;

    QString program;
    QStringList args;

    QString ext = QFileInfo(outFileName).suffix();

    if(ext == "ape")
    {
        program = "mac";
        args << wavFileName;
        args << outFileName;
        args << "-c2000";

    }

    else if(ext == "flac")
    {
        program = "flac";
        args << "--silent";
        args << "--force";
        args << "-o" << outFileName;
        args << wavFileName;
    }

    else if(ext == "wv")
    {
        program = "wavpack";
        args << wavFileName;
        args << "-y";
        args << "-q";
        args << "-o" << outFileName;
    }

    else if(ext == "tta")
    {
        program = "ttaenc";
        args << "-o" << outFileName;
        args << "-e";
        args << wavFileName;
        args << "/";
    }

    else
    {
        QFAIL(QString("Can't create file '%1': unknown file format").arg(outFileName).toLocal8Bit());
    }

    QProcess proc;
    proc.start(program, args);
    proc.waitForFinished(3 * 60 * 10000);
    if (proc.exitStatus() != 0)
        QFAIL(QString("Can't encode to file '%1':").arg(outFileName).toLocal8Bit() + proc.readAllStandardError());

    if (!QFileInfo(outFileName).isFile())
        QFAIL(QString("Can't encode to file '%1' (file don't exists'):").arg(outFileName).toLocal8Bit() + proc.readAllStandardError());
}

/************************************************
 *
 ************************************************/
void testFail(const QString &message, const char *file, int line)
{
    QTest::qFail(message.toLocal8Bit().data(), file, line);
}

/************************************************
 *
 ************************************************/
Disk *loadFromCue(const QString &cueFile)
{
    try
    {
        QVector<CueDisk> cue = CueReader().load(cueFile);
        Disk *res = new Disk();
        res->loadFromCue(cue.first());
        return res;
    }
    catch (FlaconError &err)
    {
        FAIL(err.what());
    }
    return nullptr;
}

<commit_msg>Accurate encoder error handling in tests.<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Flacon - audio File Encoder
 * https://github.com/flacon/flacon
 *
 * Copyright: 2017
 *   Alexander Sokoloff <sokoloff.a@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "tools.h"

#include <QTest>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QProcess>
#include <QCryptographicHash>
#include <QIODevice>
#include <QBuffer>
#include <QDebug>
#include "../settings.h"
#include "../cue.h"
#include "../disk.h"
#include "../converter/decoder.h"

class HashDevice: public QIODevice {
public:
    HashDevice(QCryptographicHash::Algorithm method, QObject *parent = nullptr):
        QIODevice(parent),
        mHash(method),
        mInHeader(true)
    {
    }

    QByteArray result() const { return mHash.result(); }

protected:
    qint64 readData(char*, qint64) { return -1; }

    qint64 writeData(const char *data, qint64 len)
    {
        if (mInHeader)
        {
            mBuf.append(data, len);
            int n = mBuf.indexOf("data");
            if (n > -1 && n < mBuf.length() - 8)
            {
                mInHeader = false;
                mHash.addData(mBuf.data() + n + 8, mBuf.length() - n - 8);
            }
            return len;
        }

        mHash.addData(data, len);
        return len;
    }

private:
    QByteArray mBuf;
    QCryptographicHash mHash;
    bool mInHeader;
};

/************************************************
 *
 ************************************************/
QString calcAudioHash(const QString &fileName)
{
    Decoder decoder;
    try
    {
        decoder.open(fileName);
    }
    catch (FlaconError &err)
    {
        FAIL(QString("Can't open input file '%1': %2").arg(fileName, err.what()).toLocal8Bit());
        return "";
    }

    if (!decoder.audioFormat())
    {
        FAIL("Unknown format");
        decoder.close();
        return "";
    }

    HashDevice hash(QCryptographicHash::Md5);
    hash.open(QIODevice::WriteOnly);
    decoder.extract(CueTime(), CueTime(), &hash);
    decoder.close();

    return hash.result().toHex();
}

/************************************************
 *
 ************************************************/
TestCueFile::TestCueFile(const QString &fileName):
    mFileName(fileName)
{
}

/************************************************
 *
 ************************************************/
void TestCueFile::setWavFile(const QString &value)
{
    mWavFile = value;
}

/************************************************
 *
 ************************************************/
void TestCueFile::addTrack(const QString &index0, const QString &index1)
{
    mTracks << TestCueTrack(index0, index1);
}

/************************************************
 *
 ************************************************/
void TestCueFile::addTrack(const QString &index1)
{
    addTrack("", index1);
}

/************************************************
 *
 ************************************************/
void TestCueFile::write()
{
    QFile f(mFileName);
    if (!f.open(QFile::WriteOnly | QFile::Truncate))
        QFAIL(QString("Can't create cue file '%1': %2").arg(mFileName).arg(f.errorString()).toLocal8Bit());

    QTextStream cue(&f);

    cue << QString("FILE \"%1\" WAVE\n").arg(mWavFile);
    for (int i=0; i < mTracks.count(); ++i)
    {
        TestCueTrack track = mTracks.at(i);

        cue << QString("\nTRACK %1 AUDIO\n").arg(i + 1);
        if (track.index0 != "")
            cue << QString("  INDEX 00 %1\n").arg(track.index0);

        if (track.index1 != "")
            cue << QString("  INDEX 01 %1\n").arg(track.index1);
    }

    f.close();
}

/************************************************
 *
 ************************************************/
bool compareAudioHash(const QString &file1, const QString &expected)
{
    if (calcAudioHash(file1) != expected)
    {
        FAIL(QString("Compared hases are not the same for:\n"
                     "    [%1] %2\n"
                     "    [%3] %4\n")

                    .arg(calcAudioHash(file1))
                    .arg(file1)

                    .arg(expected)
                    .arg("expected")

                    .toLocal8Bit());
        return false;
    }
    return true;
}

/************************************************
 *
 ************************************************/
void writeHexString(const QString &str, QIODevice *out)
{
    for (QString line : str.split('\n'))
    {
        for (int i=0;  i<line.length()-1;)
        {
            // Skip comments
            if (line.at(i) == '/')
                break;

            if (line.at(i).isSpace())
            {
                ++i;
                continue;
            }

            union {
                quint16 n16;
                char b;
            };

            bool ok;
            n16 = line.mid(i, 2).toShort(&ok, 16);
            if (!ok)
                throw QString("Incorrect HEX data at %1:\n%2").arg(i).arg(line);

            out->write(&b, 1);
            i+=2;
        }
    }
}

/************************************************
 *
 ************************************************/
QByteArray writeHexString(const QString &str)
{
    QBuffer data;
    data.open(QBuffer::ReadWrite);
    writeHexString(str, &data);
    return data.buffer();
}

/************************************************
 *
 ************************************************/
static void writeTestWavData(QIODevice *device, quint64 dataSize)
{
    static const int BUF_SIZE = 1024 * 1024;

    quint32 x=123456789, y=362436069, z=521288629;
    union {
        quint32 t;
        char    bytes[4];
    };

    QByteArray buf;

    buf.reserve(4 * 1024 * 1024);
    buf.reserve(BUF_SIZE);
    for (uint i=0; i<(dataSize/ sizeof(quint32)); ++i)
    {
        // xorshf96 ...................
        x ^= x << 16;
        x ^= x >> 5;
        x ^= x << 1;

        t = x;
        x = y;
        y = z;
        z = t ^ x ^ y;
        // xorshf96 ...................

        buf.append(bytes, 4);
        if (buf.size() >= BUF_SIZE)
        {
            device->write(buf);
            buf.resize(0);
        }
    }

    device->write(buf);
}

/************************************************
 *
 ************************************************/
void createWavFile(const QString &fileName, const QString &header, const int duration)
{
    QBuffer wavHdr;
    wavHdr.open(QBuffer::ReadWrite);
    writeHexString(header, &wavHdr);

    if (duration) {
        quint32 bitsPerSample =
                (quint8(wavHdr.buffer()[28]) << 0) +
                (quint8(wavHdr.buffer()[29]) <<  8) +
                (quint8(wavHdr.buffer()[30]) << 16) +
                (quint8(wavHdr.buffer()[31]) << 24);

        quint32 ckSize = bitsPerSample * duration + wavHdr.buffer().size() - 8 + 8;
        wavHdr.buffer()[4] = quint8(ckSize >>  0);
        wavHdr.buffer()[5] = quint8(ckSize >>  8);
        wavHdr.buffer()[6] = quint8(ckSize >> 16);
        wavHdr.buffer()[7] = quint8(ckSize >> 24);
    }

    // See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
    quint32 ckSize =
            (quint8(wavHdr.buffer()[4]) <<  0) +
            (quint8(wavHdr.buffer()[5]) <<  8) +
            (quint8(wavHdr.buffer()[6]) << 16) +
            (quint8(wavHdr.buffer()[7]) << 24);

    quint32 dataSize = ckSize - wavHdr.size();

    QFile file(fileName);

    if (file.exists() && file.size() == ckSize + 8)
        return;

    if (!file.open(QFile::WriteOnly | QFile::Truncate))
        QFAIL(QString("Can't create file '%1': %2").arg(fileName, file.errorString()).toLocal8Bit());

    file.write(wavHdr.buffer());
    file.write("data", 4);
    char buf[4];
    buf[0] = quint8(dataSize);
    buf[1] = quint8(dataSize >> 8);
    buf[2] = quint8(dataSize >> 16);
    buf[3] = quint8(dataSize >> 24);
    file.write(buf, 4);

    writeTestWavData(&file, dataSize);
    file.close();
}

/************************************************
 *
 ************************************************/
void encodeAudioFile(const QString &wavFileName, const QString &outFileName)
{
    if (QFileInfo(outFileName).exists() && QFileInfo(outFileName).size() > 1024)
        return;

    QString program;
    QStringList args;

    QString ext = QFileInfo(outFileName).suffix();

    if(ext == "ape")
    {
        program = "mac";
        args << wavFileName;
        args << outFileName;
        args << "-c2000";

    }

    else if(ext == "flac")
    {
        program = "flac";
        args << "--silent";
        args << "--force";
        args << "-o" << outFileName;
        args << wavFileName;
    }

    else if(ext == "wv")
    {
        program = "wavpack";
        args << wavFileName;
        args << "-y";
        args << "-q";
        args << "-o" << outFileName;
    }

    else if(ext == "tta")
    {
        program = "ttaenc";
        args << "-o" << outFileName;
        args << "-e";
        args << wavFileName;
        args << "/";
    }

    else
    {
        QFAIL(QString("Can't create file '%1': unknown file format").arg(outFileName).toLocal8Bit());
    }

    bool ok = true;
    QProcess proc;
    proc.start(program, args);
    ok = proc.waitForStarted(3 * 1000);
    ok = ok && proc.waitForFinished(3 * 60 * 100) ;
    ok = ok && (proc.exitStatus() == 0);

    if (!ok)
    {
        QFAIL(QString("Can't encode %1 %2:")
              .arg(program)
              .arg(args.join(" "))
              .toLocal8Bit()
              + proc.readAllStandardError());
    }

    if (!QFileInfo(outFileName).isFile())
    {
        QFAIL(QString("Can't encode to file '%1' (file don't exists'):")
              .arg(outFileName).toLocal8Bit()
              + proc.readAllStandardError());
    }
}

/************************************************
 *
 ************************************************/
void testFail(const QString &message, const char *file, int line)
{
    QTest::qFail(message.toLocal8Bit().data(), file, line);
}

/************************************************
 *
 ************************************************/
Disk *loadFromCue(const QString &cueFile)
{
    try
    {
        QVector<CueDisk> cue = CueReader().load(cueFile);
        Disk *res = new Disk();
        res->loadFromCue(cue.first());
        return res;
    }
    catch (FlaconError &err)
    {
        FAIL(err.what());
    }
    return nullptr;
}

<|endoftext|>


<commit_before><commit_msg>Planning: change FallbackSpeed params<commit_after><|endoftext|>


<commit_before>//
//  game.cpp
//  tetris
//
//  Created by Xhacker Liu on 2/13/14.
//  Copyright (c) 2014 Xhacker. All rights reserved.
//

#include "Game.h"
#include "constants.h"
#include <sys/time.h>
#include <unistd.h>

Game *Game::singleton = NULL;

void Game::run(int argc, char **argv)
{
    singleton = this;

    timeval t;
    gettimeofday(&t, NULL);
    srand((unsigned)(t.tv_sec * 1000 + t.tv_usec));

    tetromino.game = singleton;
    tetromino.board = &board;

    glutInit(&argc, argv);
#ifdef __APPLE__
    glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_RGBA | GLUT_DOUBLE);
#else
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
#endif
    glutInitWindowSize(340, 600);
    glutCreateWindow("Xetris!");

#ifndef __APPLE__
    glewInit();
#endif

    reset();
    init();

    glutDisplayFunc(display);
    glutSpecialFunc(keyboard);
    glutIdleFunc(idle);

    glutMainLoop();
}

void Game::init()
{
    vec2 points[kTotalPoints];
    for (int i = 0; i < kNumOfHLines; ++i) {
        points[i * 2    ] = vec2(-W, -H + BLOCK_H * i);
        points[i * 2 + 1] = vec2( W, -H + BLOCK_H * i);
    }
    for (int i = 0; i < kNumOfVLines; ++i) {
        points[kNumOfHPoints + i * 2    ] = vec2(-W + BLOCK_W * i, -H);
        points[kNumOfHPoints + i * 2 + 1] = vec2(-W + BLOCK_W * i,  H);
    }

    vec4 colors[kTotalPoints];
    for (int i = 0; i < kNumOfHPoints + kNumOfVPoints; ++i) {
        colors[i] = vec4(0.93, 0.93, 0.93, 1.0);
    }

    GLuint vaoID;
    glGenVertexArrays(1, &vaoID);
    glBindVertexArray(vaoID);

    GLuint vboID;
    glGenBuffers(1, &vboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors), points, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, kTotalPoints * sizeof(vec2), sizeof(colors), colors);

    GLuint program = InitShader("vshader.glsl", "fshader.glsl");
    GLuint vPosition = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    GLuint vColor = glGetAttribLocation(program, "vColor");
    glEnableVertexAttribArray(vColor);
    glVertexAttribPointer(vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(points)));

    glClearColor(1.0, 1.0, 1.0, 1.0);
}

void Game::reset()
{
    tetromino.interval = kDefaultInterval;
    tetromino.reset();
    board.reset();
    is_game_over = false;
}

void Game::display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glEnable(GL_CULL_FACE);

    // draw grids
    glDrawArrays(GL_LINES, 0, kNumOfHPoints + kNumOfVPoints);

    // draw current tetromino
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDrawArrays(GL_TRIANGLE_STRIP, kBeginTetrominoPoints, kNumOfTetrominoPoints);

    // draw bottom blocks
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDrawArrays(GL_TRIANGLE_STRIP, kBeginBoardPoints, singleton->board.num_of_points);

    glutSwapBuffers();
}

void Game::keyboard(int key, int x, int y)
{
    switch (key) {
        case GLUT_KEY_LEFT:
            singleton->tetromino.left();
            break;
        case GLUT_KEY_RIGHT:
            singleton->tetromino.right();
            break;
        case GLUT_KEY_UP:
            singleton->tetromino.rotate();
            break;
        case GLUT_KEY_DOWN:
            singleton->tetromino.down();
            break;
        case 'w': case 'W':
            singleton->tetromino.up();
            break;
        case 'r': case 'R':
            singleton->reset();
            break;
        case 'q': case 'Q':
        case kKeyCodeESC: case kKeyCodeESC2:
            exit(EXIT_SUCCESS);
            break;
    }
}

void Game::idle()
{
    if (!singleton->is_game_over) {
        singleton->tetromino.write_buffer();
        singleton->board.write_buffer();

        glutPostRedisplay();
    }
    usleep(20);
}

void Game::game_over()
{
    is_game_over = true;
}
<commit_msg>Fix segfault. Remain other issues.<commit_after>//
//  game.cpp
//  tetris
//
//  Created by Xhacker Liu on 2/13/14.
//  Copyright (c) 2014 Xhacker. All rights reserved.
//

#include "Game.h"
#include "constants.h"
#include <sys/time.h>
#include <unistd.h>

Game *Game::singleton = NULL;

void Game::run(int argc, char **argv)
{
    singleton = this;

    timeval t;
    gettimeofday(&t, NULL);
    srand((unsigned)(t.tv_sec * 1000 + t.tv_usec));

    tetromino.game = singleton;
    tetromino.board = &board;

    glutInit(&argc, argv);
#ifdef __APPLE__
    glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_RGBA | GLUT_DOUBLE);
#else
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
#endif
    glutInitWindowSize(340, 600);
    glutCreateWindow("Xetris!");

#ifndef __APPLE__
    glewInit();
#endif

    reset();
    init();

    glutDisplayFunc(display);
    glutSpecialFunc(keyboard);
    glutIdleFunc(idle);

    glutMainLoop();
}

void Game::init()
{
    vec2 points[kTotalPoints];
    for (int i = 0; i < kNumOfHLines; ++i) {
        points[i * 2    ] = vec2(-W, -H + BLOCK_H * i);
        points[i * 2 + 1] = vec2( W, -H + BLOCK_H * i);
    }
    for (int i = 0; i < kNumOfVLines; ++i) {
        points[kNumOfHPoints + i * 2    ] = vec2(-W + BLOCK_W * i, -H);
        points[kNumOfHPoints + i * 2 + 1] = vec2(-W + BLOCK_W * i,  H);
    }

    vec4 colors[kTotalPoints];
    for (int i = 0; i < kNumOfHPoints + kNumOfVPoints; ++i) {
        colors[i] = vec4(0.93, 0.93, 0.93, 1.0);
    }

    GLuint vaoID;
    glGenVertexArrays(1, &vaoID);
    glBindVertexArray(vaoID);

    GLuint vboID;
    glGenBuffers(1, &vboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points) + sizeof(colors), NULL, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, 0, kTotalPoints * sizeof(vec2), points);
    glBufferSubData(GL_ARRAY_BUFFER, kTotalPoints * sizeof(vec2), sizeof(colors), colors);

    GLuint program = InitShader("vshader.glsl", "fshader.glsl");
    GLuint vPosition = glGetAttribLocation(program, "vPosition");
    glEnableVertexAttribArray(vPosition);
    glVertexAttribPointer(vPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));

    GLuint vColor = glGetAttribLocation(program, "vColor");
    glEnableVertexAttribArray(vColor);
    glVertexAttribPointer(vColor, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(points)));

    glClearColor(1.0, 1.0, 1.0, 1.0);
}

void Game::reset()
{
    tetromino.interval = kDefaultInterval;
    tetromino.reset();
    board.reset();
    is_game_over = false;
}

void Game::display()
{
    glClear(GL_COLOR_BUFFER_BIT);

    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glEnable(GL_CULL_FACE);

    // draw grids
    glDrawArrays(GL_LINES, 0, kNumOfHPoints + kNumOfVPoints);

    // draw current tetromino
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDrawArrays(GL_TRIANGLE_STRIP, kBeginTetrominoPoints, kNumOfTetrominoPoints);

    // draw bottom blocks
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDrawArrays(GL_TRIANGLE_STRIP, kBeginBoardPoints, singleton->board.num_of_points);

    glutSwapBuffers();
}

void Game::keyboard(int key, int x, int y)
{
    switch (key) {
        case GLUT_KEY_LEFT:
            singleton->tetromino.left();
            break;
        case GLUT_KEY_RIGHT:
            singleton->tetromino.right();
            break;
        case GLUT_KEY_UP:
            singleton->tetromino.rotate();
            break;
        case GLUT_KEY_DOWN:
            singleton->tetromino.down();
            break;
        case 'w': case 'W':
            singleton->tetromino.up();
            break;
        case 'r': case 'R':
            singleton->reset();
            break;
        case 'q': case 'Q':
        case kKeyCodeESC: case kKeyCodeESC2:
            exit(EXIT_SUCCESS);
            break;
    }
}

void Game::idle()
{
    if (!singleton->is_game_over) {
        singleton->tetromino.write_buffer();
        singleton->board.write_buffer();

        glutPostRedisplay();
    }
    usleep(20);
}

void Game::game_over()
{
    is_game_over = true;
}
<|endoftext|>


<commit_before>#define BOOST_TEST_MODULE NiftyMulticutTest

#include <boost/test/unit_test.hpp>

#include <iostream>
#include <random>

#include "nifty/tools/runtime_check.hxx"
#include "nifty/graph/undirected_list_graph.hxx"
#include "nifty/graph/optimization/multicut/multicut_objective.hxx"
#include "nifty/graph/optimization/multicut/multicut_ilp.hxx"

#ifdef WITH_GUROBI
#include "nifty/ilp_backend/gurobi.hxx"
#endif

#ifdef WITH_CPLEX
#include "nifty/ilp_backend/cplex.hxx"
#endif

#ifdef WITH_GLPK
#include "nifty/ilp_backend/glpk.hxx"
#endif

BOOST_AUTO_TEST_CASE(RandomizedMulticutTest)
{
    // rand gen
    //std::random_device rd();
    std::mt19937 gen(42);//rd());
    std::uniform_real_distribution<> dis(-1.0, 1.0);

    typedef double WeightType;
    typedef nifty::graph::UndirectedGraph<> Graph;
    typedef nifty::graph::MulticutObjective<Graph, WeightType> Objective;
    typedef nifty::graph::MulticutVerboseVisitor<Objective> VerboseVisitor;

    // create a grid graph
    const size_t s = 15;
    Graph g(s*s);
    for(auto y=0; y<s; ++y)
    for(auto x=0; x<s; ++x){
        auto u = x + y*s;
        if(x+1 < s){
            auto v = x + 1 + y * s;
            g.insertEdge(u, v);
        }
        if(y+1 < s){
            auto v = x + (y + 1) * s;
            g.insertEdge(u, v);
        }
    }

    // create an objective
    Objective objective(g);
    auto & weights = objective.weights();

    // fill the objective with values
    for(auto e : g.edges())
        weights[e] =  dis(gen);

    // optimize gurobi
    #ifdef WITH_GUROBI
    {
        std::cout<<"opt gurobi \n";
        typedef nifty::ilp_backend::Gurobi IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif

    #ifdef WITH_CPLEX
    {
        std::cout<<"opt cplex \n";
        typedef nifty::ilp_backend::Cplex IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif

    #ifdef WITH_GLPK
    {
        std::cout<<"opt glpk \n";
        typedef nifty::ilp_backend::Glpk IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif
}

BOOST_AUTO_TEST_CASE(SimpleMulticutTest)
{
    // rand gen
    //std::random_device rd();
    std::mt19937 gen(42);//rd());
    std::uniform_real_distribution<> dis(-1.0, 1.0);

    typedef double WeightType;
    typedef nifty::graph::UndirectedGraph<> Graph;
    typedef nifty::graph::MulticutObjective<Graph, WeightType> Objective;
    typedef nifty::graph::MulticutVerboseVisitor<Objective> VerboseVisitor;

    // create a grid graph
    const size_t sx = 8;
    const size_t sy = 13;
    auto node = [&](uint64_t x, uint64_t y){
        return x + y*sx;
    };
    Graph g(sx*sy);
    for(auto y=0; y<sy; ++y)
    for(auto x=0; x<sx; ++x){
        auto u = node(x, y);
        if(x+1 < sx){
            auto v = node(x+1, y);
            g.insertEdge(u, v);
        }
        if(y+1 < sy){
            auto v = node(x, y+1);
            g.insertEdge(u, v);
        }
    }

    // create an objective
    Objective objective(g);
    auto & weights = objective.weights();

    // fill the objective with values
    for(auto e : g.edges())
        weights[e] =  10.0;

    auto yPos = std::vector<int>({0, 2, 4, 8, 10,11, 12});
    for(auto y : yPos){
        auto e = g.findEdge( node(3, y), node(4, y)  );
        NIFTY_ASSERT_OP(e,!=,-1);
        weights[e] = -10.0;
    }

    typename Graph::EdgeMap<uint16_t> shouldSolution(g,0);
    for(size_t y=0; y<sy; ++y){
        auto e = g.findEdge( node(3, y), node(3+1, y)  );
        shouldSolution[e] = 1;
    }

    // optimize gurobi
    #ifdef WITH_GUROBI
    {
        std::cout<<"opt gurobi \n";
        typedef nifty::ilp_backend::Gurobi IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;

        typedef typename Solver::NodeLabels NodeLabels;
        Solver solver(objective);

        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif

    // optimize cplex
    #ifdef WITH_CPLEX
    {
        std::cout<<"opt cplex \n";
        typedef nifty::ilp_backend::Cplex IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;

        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif

    // optimize cplex
    #ifdef WITH_GLPK
    {
        std::cout<<"opt glpk \n";
        typedef nifty::ilp_backend::Glpk IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;

        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif
}
<commit_msg>minor fix<commit_after>#define BOOST_TEST_MODULE NiftyMulticutTest

#include <boost/test/unit_test.hpp>

#include <iostream>
#include <random>

#include "nifty/tools/runtime_check.hxx"
#include "nifty/graph/undirected_list_graph.hxx"
#include "nifty/graph/optimization/multicut/multicut_objective.hxx"
#include "nifty/graph/optimization/multicut/multicut_ilp.hxx"

#ifdef WITH_GUROBI
#include "nifty/ilp_backend/gurobi.hxx"
#endif

#ifdef WITH_CPLEX
#include "nifty/ilp_backend/cplex.hxx"
#endif

#ifdef WITH_GLPK
#include "nifty/ilp_backend/glpk.hxx"
#endif

BOOST_AUTO_TEST_CASE(RandomizedMulticutTest)
{
    // rand gen
    //std::random_device rd();
    std::mt19937 gen(42);//rd());
    std::uniform_real_distribution<> dis(-1.0, 1.0);

    typedef double WeightType;
    typedef nifty::graph::UndirectedGraph<> Graph;
    typedef nifty::graph::optimization::multicut::MulticutObjective<Graph, WeightType> Objective;
    typedef nifty::graph::optimization::multicut::MulticutVerboseVisitor<Objective> VerboseVisitor;

    // create a grid graph
    const size_t s = 15;
    Graph g(s*s);
    for(auto y=0; y<s; ++y)
    for(auto x=0; x<s; ++x){
        auto u = x + y*s;
        if(x+1 < s){
            auto v = x + 1 + y * s;
            g.insertEdge(u, v);
        }
        if(y+1 < s){
            auto v = x + (y + 1) * s;
            g.insertEdge(u, v);
        }
    }

    // create an objective
    Objective objective(g);
    auto & weights = objective.weights();

    // fill the objective with values
    for(auto e : g.edges())
        weights[e] =  dis(gen);

    // optimize gurobi
    #ifdef WITH_GUROBI
    {
        std::cout<<"opt gurobi \n";
        typedef nifty::ilp_backend::Gurobi IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif

    #ifdef WITH_CPLEX
    {
        std::cout<<"opt cplex \n";
        typedef nifty::ilp_backend::Cplex IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif

    #ifdef WITH_GLPK
    {
        std::cout<<"opt glpk \n";
        typedef nifty::ilp_backend::Glpk IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;
        // optimize
        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint8_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
    }
    #endif
}

BOOST_AUTO_TEST_CASE(SimpleMulticutTest)
{
    // rand gen
    //std::random_device rd();
    std::mt19937 gen(42);//rd());
    std::uniform_real_distribution<> dis(-1.0, 1.0);

    typedef double WeightType;
    typedef nifty::graph::UndirectedGraph<> Graph;
    typedef nifty::graph::optimization::multicut::MulticutObjective<Graph, WeightType> Objective;
    typedef nifty::graph::optimization::multicut::MulticutVerboseVisitor<Objective> VerboseVisitor;

    // create a grid graph
    const size_t sx = 8;
    const size_t sy = 13;
    auto node = [&](uint64_t x, uint64_t y){
        return x + y*sx;
    };
    Graph g(sx*sy);
    for(auto y=0; y<sy; ++y)
    for(auto x=0; x<sx; ++x){
        auto u = node(x, y);
        if(x+1 < sx){
            auto v = node(x+1, y);
            g.insertEdge(u, v);
        }
        if(y+1 < sy){
            auto v = node(x, y+1);
            g.insertEdge(u, v);
        }
    }

    // create an objective
    Objective objective(g);
    auto & weights = objective.weights();

    // fill the objective with values
    for(auto e : g.edges())
        weights[e] =  10.0;

    auto yPos = std::vector<int>({0, 2, 4, 8, 10,11, 12});
    for(auto y : yPos){
        auto e = g.findEdge( node(3, y), node(4, y)  );
        NIFTY_ASSERT_OP(e,!=,-1);
        weights[e] = -10.0;
    }

    typename Graph::EdgeMap<uint16_t> shouldSolution(g,0);
    for(size_t y=0; y<sy; ++y){
        auto e = g.findEdge( node(3, y), node(3+1, y)  );
        shouldSolution[e] = 1;
    }

    // optimize gurobi
    #ifdef WITH_GUROBI
    {
        std::cout<<"opt gurobi \n";
        typedef nifty::ilp_backend::Gurobi IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;

        typedef typename Solver::NodeLabels NodeLabels;
        Solver solver(objective);

        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);
        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif

    // optimize cplex
    #ifdef WITH_CPLEX
    {
        std::cout<<"opt cplex \n";
        typedef nifty::ilp_backend::Cplex IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;

        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif

    // optimize cplex
    #ifdef WITH_GLPK
    {
        std::cout<<"opt glpk \n";
        typedef nifty::ilp_backend::Glpk IlpSolver;
        typedef nifty::graph::optimization::multicut::MulticutIlp<Objective, IlpSolver> Solver;
        typedef typename Solver::NodeLabels NodeLabels;

        Solver solver(objective);
        nifty::graph::graph_maps::EdgeMap<Graph, uint16_t> outputEdgeLabels(g,0);

        VerboseVisitor visitor;
        NodeLabels nodeLabels(g, 0);
        solver.optimize(nodeLabels, &visitor);
        g.nodeLabelsToEdgeLabels(nodeLabels, outputEdgeLabels);

        for(auto e : g.edges()){
            NIFTY_TEST_OP(shouldSolution[e],==,outputEdgeLabels[e]);
        }
    }
    #endif
}
<|endoftext|>


<commit_before>/*
 *  VHDL code generation for LPM devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  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.
 *
 *  This program 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, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cassert>

/*
 * Return the base of a part select.
 */
static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_expr *off;
   ivl_nexus_t base = ivl_lpm_data(lpm, 1);
   if (base != NULL)
      off = nexus_to_var_ref(scope, base);
   else
      off = new vhdl_const_int(ivl_lpm_base(lpm));

   // Array indexes must be integers
   vhdl_type integer(VHDL_TYPE_INTEGER);
   return off->cast(&integer);
}

vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0));
   if (NULL == out) {
      vhdl_type *type =
         vhdl_type::type_for(ivl_lpm_width(lpm),
                             ivl_lpm_signed(lpm) != 0);
      string name("LPM");
      name += ivl_lpm_basename(lpm);
      name += "_Out";

      if (!scope->have_declared(name)) {
         scope->add_decl
            (new vhdl_signal_decl(name.c_str(), new vhdl_type(*type)));
      }

      out = new vhdl_var_ref(name.c_str(), type);
   }

   if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) {
      vhdl_expr *off = part_select_base(scope, lpm);
      assert(off);

      out->set_slice(off, ivl_lpm_width(lpm) - 1);
   }

   return out;
}

static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_type *result_type =
      vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
   vhdl_binop_expr *expr =
      new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);

   for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e);
   }

   return expr;
}

static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
   unsigned out_width = ivl_lpm_width(lpm);
   vhdl_type *result_type =
      vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0);
   vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);

   for (int i = 0; i < 2; i++) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e->cast(result_type));
   }

   if (op == VHDL_BINOP_MULT) {
      // Need to resize the output to the desired size,
      // as this does not happen automatically in VHDL

      vhdl_fcall *resize =
         new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
      resize->add_expr(expr);
      resize->add_expr(new vhdl_const_int(out_width));

      return resize;
   }
   else
      return expr;
}

static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
   vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean());

   for (int i = 0; i < 2; i++) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e);
   }

   return expr;
}

static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (NULL == selfrom)
      return NULL;

   vhdl_expr *off = part_select_base(scope, lpm);;
   if (NULL == off)
      return NULL;

   selfrom->set_slice(off, ivl_lpm_width(lpm) - 1);
   return selfrom;
}

static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
}

static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL);

   for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
      vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == ref)
         return NULL;

      fcall->add_expr(ref);
   }

   return fcall;
}

static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
                                     const char *rfunc, bool invert)
{
   vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic());

   vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (NULL == ref)
      return NULL;

   fcall->add_expr(ref);

   if (invert)
      return new vhdl_unaryop_expr
         (VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic());
   else
      return fcall;
}

static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (ref)
      return ref->resize(ivl_lpm_width(lpm));
   else
      return NULL;
}

static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   ivl_signal_t array = ivl_lpm_array(lpm);
   if (!seen_signal_before(array))
      return NULL;

   const char *renamed = get_renamed_signal(array).c_str();

   vhdl_decl *adecl = scope->get_decl(renamed);
   assert(adecl);

   vhdl_type *atype = new vhdl_type(*adecl->get_type());

   vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
   if (NULL == select)
      return NULL;

   vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
   vhdl_type integer(VHDL_TYPE_INTEGER);
   ref->set_slice(select->cast(&integer));

   return ref;
}

static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
                                    vhdl_binop_t shift_op)
{
   vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
   if (!lhs || !rhs)
      return NULL;

   // The RHS must be an integer
   vhdl_type integer(VHDL_TYPE_INTEGER);
   vhdl_expr *r_cast = rhs->cast(&integer);

   vhdl_type *rtype = new vhdl_type(*lhs->get_type());
   return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype);
}

static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   switch (ivl_lpm_type(lpm)) {
   case IVL_LPM_ADD:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD);
   case IVL_LPM_SUB:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB);
   case IVL_LPM_MULT:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT);
   case IVL_LPM_CONCAT:
      return concat_lpm_to_expr(scope, lpm);
   case IVL_LPM_CMP_GE:
      return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ);
   case IVL_LPM_CMP_EEQ:
      return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ);
   case IVL_LPM_PART_VP:
      return part_select_vp_lpm_to_expr(scope, lpm);
   case IVL_LPM_PART_PV:
      return part_select_pv_lpm_to_expr(scope, lpm);
   case IVL_LPM_UFUNC:
      return ufunc_lpm_to_expr(scope, lpm);
   case IVL_LPM_RE_AND:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false);
   case IVL_LPM_RE_NAND:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true);
   case IVL_LPM_RE_NOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", true);
   case IVL_LPM_RE_OR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", false);
   case IVL_LPM_RE_XOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false);
   case IVL_LPM_RE_XNOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false);
   case IVL_LPM_SIGN_EXT:
      return sign_extend_lpm_to_expr(scope, lpm);
   case IVL_LPM_ARRAY:
      return array_lpm_to_expr(scope, lpm);
   case IVL_LPM_SHIFTL:
      return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL);
   case IVL_LPM_SHIFTR:
      return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR);
   default:
      error("Unsupported LPM type: %d", ivl_lpm_type(lpm));
      return NULL;
   }
}

int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
{
   vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
   if (NULL == f)
      return 0;

   vhdl_var_ref *out = lpm_output(arch->get_scope(), lpm);
   arch->add_stmt(new vhdl_cassign_stmt(out, f));

   return 0;
}

<commit_msg>Add IVL_LPM_CMP_EQ<commit_after>/*
 *  VHDL code generation for LPM devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  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.
 *
 *  This program 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, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cassert>

/*
 * Return the base of a part select.
 */
static vhdl_expr *part_select_base(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_expr *off;
   ivl_nexus_t base = ivl_lpm_data(lpm, 1);
   if (base != NULL)
      off = nexus_to_var_ref(scope, base);
   else
      off = new vhdl_const_int(ivl_lpm_base(lpm));

   // Array indexes must be integers
   vhdl_type integer(VHDL_TYPE_INTEGER);
   return off->cast(&integer);
}

vhdl_var_ref *lpm_output(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_var_ref *out = nexus_to_var_ref(scope, ivl_lpm_q(lpm, 0));
   if (NULL == out) {
      vhdl_type *type =
         vhdl_type::type_for(ivl_lpm_width(lpm),
                             ivl_lpm_signed(lpm) != 0);
      string name("LPM");
      name += ivl_lpm_basename(lpm);
      name += "_Out";

      if (!scope->have_declared(name)) {
         scope->add_decl
            (new vhdl_signal_decl(name.c_str(), new vhdl_type(*type)));
      }

      out = new vhdl_var_ref(name.c_str(), type);
   }

   if (ivl_lpm_type(lpm) == IVL_LPM_PART_PV) {
      vhdl_expr *off = part_select_base(scope, lpm);
      assert(off);

      out->set_slice(off, ivl_lpm_width(lpm) - 1);
   }

   return out;
}

static vhdl_expr *concat_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_type *result_type =
      vhdl_type::type_for(ivl_lpm_width(lpm), ivl_lpm_signed(lpm) != 0);
   vhdl_binop_expr *expr =
      new vhdl_binop_expr(VHDL_BINOP_CONCAT, result_type);

   for (int i = ivl_lpm_selects(lpm) - 1; i >= 0; i--) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e);
   }

   return expr;
}

static vhdl_expr *binop_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
   unsigned out_width = ivl_lpm_width(lpm);
   vhdl_type *result_type =
      vhdl_type::type_for(out_width, ivl_lpm_signed(lpm) != 0);
   vhdl_binop_expr *expr = new vhdl_binop_expr(op, result_type);

   for (int i = 0; i < 2; i++) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e->cast(result_type));
   }

   if (op == VHDL_BINOP_MULT) {
      // Need to resize the output to the desired size,
      // as this does not happen automatically in VHDL

      vhdl_fcall *resize =
         new vhdl_fcall("Resize", vhdl_type::nsigned(out_width));
      resize->add_expr(expr);
      resize->add_expr(new vhdl_const_int(out_width));

      return resize;
   }
   else
      return expr;
}

static vhdl_expr *rel_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm, vhdl_binop_t op)
{
   vhdl_binop_expr *expr = new vhdl_binop_expr(op, vhdl_type::boolean());

   for (int i = 0; i < 2; i++) {
      vhdl_expr *e = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == e)
         return NULL;

      expr->add_expr(e);
   }

   return expr;
}

static vhdl_expr *part_select_vp_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_var_ref *selfrom = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (NULL == selfrom)
      return NULL;

   vhdl_expr *off = part_select_base(scope, lpm);;
   if (NULL == off)
      return NULL;

   selfrom->set_slice(off, ivl_lpm_width(lpm) - 1);
   return selfrom;
}

static vhdl_expr *part_select_pv_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   return nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
}

static vhdl_expr *ufunc_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_fcall *fcall = new vhdl_fcall(ivl_lpm_basename(lpm), NULL);

   for (unsigned i = 0; i < ivl_lpm_size(lpm); i++) {
      vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, i));
      if (NULL == ref)
         return NULL;

      fcall->add_expr(ref);
   }

   return fcall;
}

static vhdl_expr *reduction_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
                                     const char *rfunc, bool invert)
{
   vhdl_fcall *fcall = new vhdl_fcall(rfunc, vhdl_type::std_logic());

   vhdl_var_ref *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (NULL == ref)
      return NULL;

   fcall->add_expr(ref);

   if (invert)
      return new vhdl_unaryop_expr
         (VHDL_UNARYOP_NOT, fcall, vhdl_type::std_logic());
   else
      return fcall;
}

static vhdl_expr *sign_extend_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   vhdl_expr *ref = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   if (ref)
      return ref->resize(ivl_lpm_width(lpm));
   else
      return NULL;
}

static vhdl_expr *array_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   ivl_signal_t array = ivl_lpm_array(lpm);
   if (!seen_signal_before(array))
      return NULL;

   const char *renamed = get_renamed_signal(array).c_str();

   vhdl_decl *adecl = scope->get_decl(renamed);
   assert(adecl);

   vhdl_type *atype = new vhdl_type(*adecl->get_type());

   vhdl_expr *select = nexus_to_var_ref(scope, ivl_lpm_select(lpm));
   if (NULL == select)
      return NULL;

   vhdl_var_ref *ref = new vhdl_var_ref(renamed, atype);
   vhdl_type integer(VHDL_TYPE_INTEGER);
   ref->set_slice(select->cast(&integer));

   return ref;
}

static vhdl_expr *shift_lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm,
                                    vhdl_binop_t shift_op)
{
   vhdl_expr *lhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 0));
   vhdl_expr *rhs = nexus_to_var_ref(scope, ivl_lpm_data(lpm, 1));
   if (!lhs || !rhs)
      return NULL;

   // The RHS must be an integer
   vhdl_type integer(VHDL_TYPE_INTEGER);
   vhdl_expr *r_cast = rhs->cast(&integer);

   vhdl_type *rtype = new vhdl_type(*lhs->get_type());
   return new vhdl_binop_expr(lhs, shift_op, r_cast, rtype);
}

static vhdl_expr *lpm_to_expr(vhdl_scope *scope, ivl_lpm_t lpm)
{
   switch (ivl_lpm_type(lpm)) {
   case IVL_LPM_ADD:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_ADD);
   case IVL_LPM_SUB:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_SUB);
   case IVL_LPM_MULT:
      return binop_lpm_to_expr(scope, lpm, VHDL_BINOP_MULT);
   case IVL_LPM_CONCAT:
      return concat_lpm_to_expr(scope, lpm);
   case IVL_LPM_CMP_GE:
      return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_GEQ);
   case IVL_LPM_CMP_EQ:
   case IVL_LPM_CMP_EEQ:
      return rel_lpm_to_expr(scope, lpm, VHDL_BINOP_EQ);
   case IVL_LPM_PART_VP:
      return part_select_vp_lpm_to_expr(scope, lpm);
   case IVL_LPM_PART_PV:
      return part_select_pv_lpm_to_expr(scope, lpm);
   case IVL_LPM_UFUNC:
      return ufunc_lpm_to_expr(scope, lpm);
   case IVL_LPM_RE_AND:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", false);
   case IVL_LPM_RE_NAND:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_AND", true);
   case IVL_LPM_RE_NOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", true);
   case IVL_LPM_RE_OR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_OR", false);
   case IVL_LPM_RE_XOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_XOR", false);
   case IVL_LPM_RE_XNOR:
      return reduction_lpm_to_expr(scope, lpm, "Reduce_XNOR", false);
   case IVL_LPM_SIGN_EXT:
      return sign_extend_lpm_to_expr(scope, lpm);
   case IVL_LPM_ARRAY:
      return array_lpm_to_expr(scope, lpm);
   case IVL_LPM_SHIFTL:
      return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SL);
   case IVL_LPM_SHIFTR:
      return shift_lpm_to_expr(scope, lpm, VHDL_BINOP_SR);
   default:
      error("Unsupported LPM type: %d", ivl_lpm_type(lpm));
      return NULL;
   }
}

int draw_lpm(vhdl_arch *arch, ivl_lpm_t lpm)
{
   vhdl_expr *f = lpm_to_expr(arch->get_scope(), lpm);
   if (NULL == f)
      return 0;

   vhdl_var_ref *out = lpm_output(arch->get_scope(), lpm);
   arch->add_stmt(new vhdl_cassign_stmt(out, f));

   return 0;
}

<|endoftext|>


<commit_before>/* Copyright (C) 2003 MySQL AB

   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.

   This program 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, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <random.h>
#include <getarg.h>

struct Parameter {
  const char * name;
  unsigned value;
  unsigned min;
  unsigned max;
};

#define P_OPER    0
#define P_RANGE   1
#define P_ROWS    2
#define P_LOOPS   3
#define P_CREATE  4
#define P_LOAD    5

#define P_MAX 6

/**
 * operation
 * 0 - serial pk
 * 1 - batch pk
 * 2 - serial uniq
 * 3 - batch uniq
 * 4 - index eq
 * 5 - range scan
 * 6 - ordered range scan
 * 7 - interpreted scan
 */
static const char * g_ops[] = {
  "serial pk",
  "batch pk",
  "serial uniq index access",
  "batch uniq index access",
  "index eq-bound",
  "index range",
  "index ordered",
  "interpreted scan"
};

#define P_OP_TYPES 8
static Uint64 g_times[P_OP_TYPES];

static
Parameter
g_paramters[] = {
  { "operation",   0, 0, 6 }, // 0
  { "range",    1000, 1, ~0 },// 1 no of rows to read
  { "size",  1000000, 1, ~0 },// 2 rows in tables
  { "iterations",  3, 1, ~0 },// 3
  { "create_drop", 0, 0, 1 }, // 4
  { "data",        0, 0, 1 }  // 5
};

static Ndb* g_ndb = 0;
static const NdbDictionary::Table * g_tab;
static const NdbDictionary::Index * g_i_unique;
static const NdbDictionary::Index * g_i_ordered;
static char g_table[256];
static char g_unique[256];
static char g_ordered[256];
static char g_buffer[2*1024*1024];

int create_table();
int load_table();
int run_read();
int clear_table();
int drop_table();
void print_result();

int
main(int argc, const char** argv){
  int verbose = 1;
  int optind = 0;

  struct getargs args[1+P_MAX] = {
    { "verbose", 'v', arg_flag, &verbose, "Print verbose status", "verbose" }
  };
  const int num_args = 1 + P_MAX;
  for(int i = 0; i<P_MAX; i++){
    args[i+1].long_name = g_paramters[i].name;
    args[i+1].short_name = * g_paramters[i].name;
    args[i+1].type = arg_integer;
    args[i+1].value = &g_paramters[i].value;
    BaseString tmp;
    tmp.assfmt("min: %d max: %d", g_paramters[i].min, g_paramters[i].max);
    args[i+1].help = strdup(tmp.c_str());
    args[i+1].arg_help = 0;
  }

  if(getarg(args, num_args, argc, argv, &optind)) {
    arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ...");
    return NDBT_WRONGARGS;
  }

  myRandom48Init(NdbTick_CurrentMillisecond());

  g_ndb = new Ndb("TEST_DB");
  if(g_ndb->init() != 0){
    g_err << "init() failed" << endl;
    goto error;
  }
  if(g_ndb->waitUntilReady() != 0){
    g_err << "Wait until ready failed" << endl;
    goto error;
  }
  for(int i = optind; i<argc; i++){
    const char * T = argv[i];
    g_info << "Testing " << T << endl;
    snprintf(g_table, sizeof(g_table), T);
    snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T);
    snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T);
    if(create_table())
      goto error;
    if(load_table())
      goto error;
    for(int l = 0; l<g_paramters[P_LOOPS].value; l++){
      for(int j = 0; j<P_OP_TYPES; j++){
	g_paramters[P_OPER].value = j;
	if(run_read())
	  goto error;
      }
    }
    print_result();
  }

  if(g_ndb) delete g_ndb;
  return NDBT_OK;
error:
  if(g_ndb) delete g_ndb;
  return NDBT_FAILED;
}

int
create_table(){
  NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
  assert(dict);
  if(g_paramters[P_CREATE].value){
    const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_table);
    assert(pTab);
    NdbDictionary::Table copy = * pTab;
    copy.setLogging(false);
    if(dict->createTable(copy) != 0){
      g_err << "Failed to create table: " << g_table << endl;
      return -1;
    }

    NdbDictionary::Index x(g_ordered);
    x.setTable(g_table);
    x.setType(NdbDictionary::Index::OrderedIndex);
    x.setLogging(false);
    for (unsigned k = 0; k < copy.getNoOfColumns(); k++){
      if(copy.getColumn(k)->getPrimaryKey()){
	x.addColumn(copy.getColumn(k)->getName());
      }
    }

    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }

    x.setName(g_unique);
    x.setType(NdbDictionary::Index::UniqueHashIndex);
    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }
  }
  g_tab = dict->getTable(g_table);
  g_i_unique = dict->getIndex(g_unique, g_table);
  g_i_ordered = dict->getIndex(g_ordered, g_table);
  assert(g_tab);
  assert(g_i_unique);
  assert(g_i_ordered);
  return 0;
}

int
drop_table(){
  if(!g_paramters[P_CREATE].value)
    return 0;
  if(g_ndb->getDictionary()->dropTable(g_tab->getName()) != 0){
    g_err << "Failed to drop table: " << g_tab->getName() << endl;
    return -1;
  }
  g_tab = 0;
  return 0;
}

int
load_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;

  int rows = g_paramters[P_ROWS].value;
  HugoTransactions hugoTrans(* g_tab);
  if (hugoTrans.loadTable(g_ndb, rows)){
    g_err.println("Failed to load %s with %d rows", g_tab->getName(), rows);
    return -1;
  }
  return 0;
}

int
clear_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;
  int rows = g_paramters[P_ROWS].value;

  UtilTransactions utilTrans(* g_tab);
  if (utilTrans.clearTable(g_ndb,  rows) != 0){
    g_err.println("Failed to clear table %s", g_tab->getName());
    return -1;
  }
  return 0;
}

inline
void err(NdbError e){
  ndbout << e << endl;
}

static
void
do_work(){
  int sz = 10 * 1024;
  int pos= rand() % (sizeof(g_buffer) - sz);
  memset(g_buffer+pos, rand(), sz);
}

int
run_read(){
  int iter = g_paramters[P_LOOPS].value;
  NDB_TICKS start1, stop;
  int sum_time= 0;

  const Uint32 rows = g_paramters[P_ROWS].value;
  const Uint32 range = g_paramters[P_RANGE].value;

  start1 = NdbTick_CurrentMillisecond();
  NdbConnection * pTrans = g_ndb->startTransaction();
  if(!pTrans){
    g_err << "Failed to start transaction" << endl;
    err(g_ndb->getNdbError());
    return -1;
  }

  NdbOperation * pOp;
  NdbScanOperation * pSp;
  NdbIndexOperation * pUp;
  NdbIndexScanOperation * pIp;
  NdbResultSet * rs = (NdbResultSet*)~0;

  Uint32 start_row = rand() % (rows - range);
  Uint32 stop_row = start_row + range;

  /**
   * 0 - serial pk
   * 1 - batch pk
   * 2 - serial uniq
   * 3 - batch uniq
   * 4 - index eq
   * 5 - range scan
   * 6 - interpreted scan
   */
  int check = 0;
  void* res = (void*)~0;
  const Uint32 pk = 0;
  Uint32 cnt = 0;
  for(; start_row < stop_row; start_row++){
    switch(g_paramters[P_OPER].value){
    case 0:
      pOp = pTrans->getNdbOperation(g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 1:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbOperation(g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 2:
      pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 3:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 4:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundEQ, &start_row);
      break;
    case 5:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 6:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 7:
      pOp = pSp = pTrans->getNdbScanOperation(g_table);
      rs = pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      NdbScanFilter filter(pOp) ;
      filter.begin(NdbScanFilter::AND);
      filter.ge(pk, start_row);
      filter.lt(pk, stop_row);
      filter.end();
      start_row = stop_row;
      break;
    }

    assert(res);
    if(check != 0){
      ndbout << pOp->getNdbError() << endl;
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    assert(rs);

    for(int j = 0; j<g_tab->getNoOfColumns(); j++){
      res = pOp->getValue(j);
      assert(res);
    }

    check = pTrans->execute(NoCommit);
    if(check != 0){
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    if(g_paramters[P_OPER].value >= 4){
      while((check = rs->nextResult(true)) == 0){
	do_work();
	cnt++;
      }

      if(check == -1){
	err(pTrans->getNdbError());
	return -1;
      }
      assert(check == 1);
      rs->close();
    } else {
      if(start_row != stop_row)
	do_work();
      else
	for(int j = 0; j<range; j++)
	  do_work();
    }
  }
  assert(g_paramters[P_OPER].value < 4 || (cnt == range));

  pTrans->close();

  stop = NdbTick_CurrentMillisecond();
  g_times[g_paramters[P_OPER].value] += (stop - start1);
  return 0;
}

void
print_result(){
  for(int i = 0; i<P_OP_TYPES; i++){
    g_err.println("%s avg: %u us/row", g_ops[i],
		  (1000*g_times[i])/g_paramters[P_RANGE].value);
  }
}
<commit_msg>removed faked do_work<commit_after>/* Copyright (C) 2003 MySQL AB

   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.

   This program 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, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include <NDBT.hpp>
#include <NDBT_Test.hpp>
#include <HugoTransactions.hpp>
#include <UtilTransactions.hpp>
#include <random.h>
#include <getarg.h>

struct Parameter {
  const char * name;
  unsigned value;
  unsigned min;
  unsigned max;
};

#define P_OPER    0
#define P_RANGE   1
#define P_ROWS    2
#define P_LOOPS   3
#define P_CREATE  4
#define P_LOAD    5

#define P_MAX 6

/**
 * operation
 * 0 - serial pk
 * 1 - batch pk
 * 2 - serial uniq
 * 3 - batch uniq
 * 4 - index eq
 * 5 - range scan
 * 6 - ordered range scan
 * 7 - interpreted scan
 */
static const char * g_ops[] = {
  "serial pk",
  "batch pk",
  "serial uniq index access",
  "batch uniq index access",
  "index eq-bound",
  "index range",
  "index ordered",
  "interpreted scan"
};

#define P_OP_TYPES 8
static Uint64 g_times[P_OP_TYPES];

static
Parameter
g_paramters[] = {
  { "operation",   0, 0, 6 }, // 0
  { "range",    1000, 1, ~0 },// 1 no of rows to read
  { "size",  1000000, 1, ~0 },// 2 rows in tables
  { "iterations",  3, 1, ~0 },// 3
  { "create_drop", 0, 0, 1 }, // 4
  { "data",        0, 0, 1 }  // 5
};

static Ndb* g_ndb = 0;
static const NdbDictionary::Table * g_tab;
static const NdbDictionary::Index * g_i_unique;
static const NdbDictionary::Index * g_i_ordered;
static char g_table[256];
static char g_unique[256];
static char g_ordered[256];
static char g_buffer[2*1024*1024];

int create_table();
int load_table();
int run_read();
int clear_table();
int drop_table();
void print_result();

int
main(int argc, const char** argv){
  int verbose = 1;
  int optind = 0;

  struct getargs args[1+P_MAX] = {
    { "verbose", 'v', arg_flag, &verbose, "Print verbose status", "verbose" }
  };
  const int num_args = 1 + P_MAX;
  for(int i = 0; i<P_MAX; i++){
    args[i+1].long_name = g_paramters[i].name;
    args[i+1].short_name = * g_paramters[i].name;
    args[i+1].type = arg_integer;
    args[i+1].value = &g_paramters[i].value;
    BaseString tmp;
    tmp.assfmt("min: %d max: %d", g_paramters[i].min, g_paramters[i].max);
    args[i+1].help = strdup(tmp.c_str());
    args[i+1].arg_help = 0;
  }

  if(getarg(args, num_args, argc, argv, &optind)) {
    arg_printusage(args, num_args, argv[0], "tabname1 tabname2 ...");
    return NDBT_WRONGARGS;
  }

  myRandom48Init(NdbTick_CurrentMillisecond());

  g_ndb = new Ndb("TEST_DB");
  if(g_ndb->init() != 0){
    g_err << "init() failed" << endl;
    goto error;
  }
  if(g_ndb->waitUntilReady() != 0){
    g_err << "Wait until ready failed" << endl;
    goto error;
  }
  for(int i = optind; i<argc; i++){
    const char * T = argv[i];
    g_info << "Testing " << T << endl;
    snprintf(g_table, sizeof(g_table), T);
    snprintf(g_ordered, sizeof(g_ordered), "IDX_O_%s", T);
    snprintf(g_unique, sizeof(g_unique), "IDX_U_%s", T);
    if(create_table())
      goto error;
    if(load_table())
      goto error;
    for(int l = 0; l<g_paramters[P_LOOPS].value; l++){
      for(int j = 0; j<P_OP_TYPES; j++){
	g_paramters[P_OPER].value = j;
	if(run_read())
	  goto error;
      }
    }
    print_result();
  }

  if(g_ndb) delete g_ndb;
  return NDBT_OK;
error:
  if(g_ndb) delete g_ndb;
  return NDBT_FAILED;
}

int
create_table(){
  NdbDictionary::Dictionary* dict = g_ndb->getDictionary();
  assert(dict);
  if(g_paramters[P_CREATE].value){
    const NdbDictionary::Table * pTab = NDBT_Tables::getTable(g_table);
    assert(pTab);
    NdbDictionary::Table copy = * pTab;
    copy.setLogging(false);
    if(dict->createTable(copy) != 0){
      g_err << "Failed to create table: " << g_table << endl;
      return -1;
    }

    NdbDictionary::Index x(g_ordered);
    x.setTable(g_table);
    x.setType(NdbDictionary::Index::OrderedIndex);
    x.setLogging(false);
    for (unsigned k = 0; k < copy.getNoOfColumns(); k++){
      if(copy.getColumn(k)->getPrimaryKey()){
	x.addColumn(copy.getColumn(k)->getName());
      }
    }

    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }

    x.setName(g_unique);
    x.setType(NdbDictionary::Index::UniqueHashIndex);
    if(dict->createIndex(x) != 0){
      g_err << "Failed to create index: " << endl;
      return -1;
    }
  }
  g_tab = dict->getTable(g_table);
  g_i_unique = dict->getIndex(g_unique, g_table);
  g_i_ordered = dict->getIndex(g_ordered, g_table);
  assert(g_tab);
  assert(g_i_unique);
  assert(g_i_ordered);
  return 0;
}

int
drop_table(){
  if(!g_paramters[P_CREATE].value)
    return 0;
  if(g_ndb->getDictionary()->dropTable(g_tab->getName()) != 0){
    g_err << "Failed to drop table: " << g_tab->getName() << endl;
    return -1;
  }
  g_tab = 0;
  return 0;
}

int
load_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;

  int rows = g_paramters[P_ROWS].value;
  HugoTransactions hugoTrans(* g_tab);
  if (hugoTrans.loadTable(g_ndb, rows)){
    g_err.println("Failed to load %s with %d rows", g_tab->getName(), rows);
    return -1;
  }
  return 0;
}

int
clear_table(){
  if(!g_paramters[P_LOAD].value)
    return 0;
  int rows = g_paramters[P_ROWS].value;

  UtilTransactions utilTrans(* g_tab);
  if (utilTrans.clearTable(g_ndb,  rows) != 0){
    g_err.println("Failed to clear table %s", g_tab->getName());
    return -1;
  }
  return 0;
}

inline
void err(NdbError e){
  ndbout << e << endl;
}

int
run_read(){
  int iter = g_paramters[P_LOOPS].value;
  NDB_TICKS start1, stop;
  int sum_time= 0;

  const Uint32 rows = g_paramters[P_ROWS].value;
  const Uint32 range = g_paramters[P_RANGE].value;

  start1 = NdbTick_CurrentMillisecond();
  NdbConnection * pTrans = g_ndb->startTransaction();
  if(!pTrans){
    g_err << "Failed to start transaction" << endl;
    err(g_ndb->getNdbError());
    return -1;
  }

  NdbOperation * pOp;
  NdbScanOperation * pSp;
  NdbIndexOperation * pUp;
  NdbIndexScanOperation * pIp;
  NdbResultSet * rs = (NdbResultSet*)~0;

  Uint32 start_row = rand() % (rows - range);
  Uint32 stop_row = start_row + range;

  /**
   * 0 - serial pk
   * 1 - batch pk
   * 2 - serial uniq
   * 3 - batch uniq
   * 4 - index eq
   * 5 - range scan
   * 6 - interpreted scan
   */
  int check = 0;
  void* res = (void*)~0;
  const Uint32 pk = 0;
  Uint32 cnt = 0;
  for(; start_row < stop_row; start_row++){
    switch(g_paramters[P_OPER].value){
    case 0:
      pOp = pTrans->getNdbOperation(g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 1:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbOperation(g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 2:
      pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
      check = pOp->readTuple();
      check = pOp->equal(pk, start_row);
      break;
    case 3:
      for(; start_row<stop_row; start_row++){
	pOp = pTrans->getNdbIndexOperation(g_unique, g_table);
	check = pOp->readTuple();
	check = pOp->equal(pk, start_row);
	for(int j = 0; j<g_tab->getNoOfColumns(); j++){
	  res = pOp->getValue(j);
	  assert(res);
	}
      }
      break;
    case 4:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundEQ, &start_row);
      break;
    case 5:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 6:
      pOp = pIp = pTrans->getNdbIndexScanOperation(g_ordered,g_table);
      rs = pIp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0, true);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundLE, &start_row);
      check = pIp->setBound(pk, NdbIndexScanOperation::BoundGT, &stop_row);
      start_row = stop_row;
      break;
    case 7:
      pOp = pSp = pTrans->getNdbScanOperation(g_table);
      rs = pSp->readTuples(NdbScanOperation::LM_CommittedRead, 0, 0);
      NdbScanFilter filter(pOp) ;
      filter.begin(NdbScanFilter::AND);
      filter.ge(pk, start_row);
      filter.lt(pk, stop_row);
      filter.end();
      start_row = stop_row;
      break;
    }

    assert(res);
    if(check != 0){
      ndbout << pOp->getNdbError() << endl;
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    assert(rs);

    for(int j = 0; j<g_tab->getNoOfColumns(); j++){
      res = pOp->getValue(j);
      assert(res);
    }

    check = pTrans->execute(NoCommit);
    if(check != 0){
      ndbout << pTrans->getNdbError() << endl;
    }
    assert(check == 0);
    if(g_paramters[P_OPER].value >= 4){
      while((check = rs->nextResult(true)) == 0){
	cnt++;
      }

      if(check == -1){
	err(pTrans->getNdbError());
	return -1;
      }
      assert(check == 1);
      rs->close();
    }
  }
  assert(g_paramters[P_OPER].value < 4 || (cnt == range));

  pTrans->close();

  stop = NdbTick_CurrentMillisecond();
  g_times[g_paramters[P_OPER].value] += (stop - start1);
  return 0;
}

void
print_result(){
  for(int i = 0; i<P_OP_TYPES; i++){
    g_err.println("%s avg: %u us/row", g_ops[i],
		  (1000*g_times[i])/g_paramters[P_RANGE].value);
  }
}
<|endoftext|>


<commit_before>/*
 * This software is distributed under BSD 3-clause license (see LICENSE file).
 *
 * Authors: Giovanni De Toni
 *
 */

#include <shogun/io/visitors/ToStringVisitor.h>
#include <shogun/lib/observers/ObservedValueTemplated.h>
#include <shogun/lib/observers/ParameterObserverLogger.h>
#include <shogun/lib/type_case.h>

using namespace shogun;

CParameterObserverLogger::CParameterObserverLogger()
{
}

CParameterObserverLogger::CParameterObserverLogger(
    std::vector<std::string>& parameters)
    : ParameterObserver(parameters)
{
}

CParameterObserverLogger::~CParameterObserverLogger()
{
}

void CParameterObserverLogger::on_error(std::exception_ptr ptr)
{
}

void CParameterObserverLogger::on_complete()
{
}

void CParameterObserverLogger::on_next_impl(const TimedObservedValue& value)
{

	auto name = value.first->get<std::string>("name");
	auto any_val = value.first->get_any();

	std::stringstream stream;
	ToStringVisitor visitor(&stream);

	if (any_val.visitable())
	{
		any_val.visit(&visitor);
	} else {
		stream << "{function}";
	}

	SG_PRINT(
			"[%lu] Received a value called \"%s\" which contains: %s\n",
			convert_to_millis(value.second), name.c_str(),
			stream.str().c_str());
}
<commit_msg>Replace ParameterObserverLogger message with a shorter version.<commit_after>/*
 * This software is distributed under BSD 3-clause license (see LICENSE file).
 *
 * Authors: Giovanni De Toni
 *
 */

#include <shogun/io/visitors/ToStringVisitor.h>
#include <shogun/lib/observers/ObservedValueTemplated.h>
#include <shogun/lib/observers/ParameterObserverLogger.h>
#include <shogun/lib/type_case.h>

using namespace shogun;

CParameterObserverLogger::CParameterObserverLogger()
{
}

CParameterObserverLogger::CParameterObserverLogger(
    std::vector<std::string>& parameters)
    : ParameterObserver(parameters)
{
}

CParameterObserverLogger::~CParameterObserverLogger()
{
}

void CParameterObserverLogger::on_error(std::exception_ptr ptr)
{
}

void CParameterObserverLogger::on_complete()
{
}

void CParameterObserverLogger::on_next_impl(const TimedObservedValue& value)
{

	auto name = value.first->get<std::string>("name");
	auto any_val = value.first->get_any();

	std::stringstream stream;
	ToStringVisitor visitor(&stream);

	if (any_val.visitable())
	{
		any_val.visit(&visitor);
	} else {
		stream << "{function}";
	}

	SG_PRINT(
			"[%lu] \"%s\"=%s\n",
			convert_to_millis(value.second), name.c_str(),
			stream.str().c_str());
}
<|endoftext|>