<commit_before>#include <QCoreApplication>
#include <QString>
#include <QRegularExpression>
#include <QDebug>

void testRegexp()
{
    QString s = "v=0/t=1/title = hello world/Message=How are you?/Foo3=bar4";
    QRegularExpression re("(?<key>[A-Za-z][A-Za-z0-9_]*)\\s*=\\s*(?<val>[^/]+)");
    QRegularExpressionMatchIterator i = re.globalMatch(s);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        QString key = match.captured("key");
        QString val = match.captured("val");
        qDebug() << "match: " << key << "=" << val;
    }
}

/*
RF,Kpa,230,C,30,OK*4F
RR,Kpa,230,C,30,OK*4F
LR,Kpa,230,C,30,OK*4F
LF,Kpa,230,C,30,OK*4F
*/
void test2()
{
    QRegularExpression re("(?<pos>[LR][RF]),"
                          "(?<punit>(Kpa|Psi|Bar)),"
                          "(?<press>\\d+\\.?\\d*),"
                          "(?<tunit>(C|F)),"
                          "(?<temp>\\d+),"
                          "(?<batt>(OK|LOW))");
    QString s = "RF,Kpa,230,C,30,OK*4F";
    QRegularExpressionMatch match = re.match(s);
    if (match.hasMatch()) {
        QString pos = match.captured("pos");
        QString punit = match.captured("punit");
        QString press = match.captured("press");
        QString tunit = match.captured("tunit");
        QString temp = match.captured("temp");
        QString batt = match.captured("batt");
        qDebug() << pos << punit << press << tunit << temp << batt;
    }
}

int main(int argc, char *argv[])
{
//    QCoreApplication a(argc, argv);

    testRegexp();
    test2();

    //return a.exec();
    return 0;
}

<commit_msg>update retest, add test3()<commit_after>#include <QCoreApplication>
#include <QString>
#include <QRegularExpression>
#include <QDebug>

void testRegexp()
{
    QString s = "v=0/t=1/title = hello world/Message=How are you?/Foo3=bar4";
    QRegularExpression re("(?<key>[A-Za-z][A-Za-z0-9_]*)\\s*=\\s*(?<val>[^/]+)");
    QRegularExpressionMatchIterator i = re.globalMatch(s);
    while (i.hasNext()) {
        QRegularExpressionMatch match = i.next();
        QString key = match.captured("key");
        QString val = match.captured("val");
        qDebug() << "match: " << key << "=" << val;
    }
}

/*
RF,Kpa,230,C,30,OK*4F
RR,Kpa,230,C,30,OK*4F
LR,Kpa,230,C,30,OK*4F
LF,Kpa,230,C,30,OK*4F
*/
void test2()
{
    QRegularExpression re("(?<pos>[LR][RF]),"
                          "(?<punit>(Kpa|Psi|Bar)),"
                          "(?<press>\\d+\\.?\\d*),"
                          "(?<tunit>(C|F)),"
                          "(?<temp>\\d+),"
                          "(?<batt>(OK|LOW))");
    QString s = "RF,Kpa,230,C,30,OK*4F";
    QRegularExpressionMatch match = re.match(s);
    if (match.hasMatch()) {
        QString pos = match.captured("pos");
        QString punit = match.captured("punit");
        QString press = match.captured("press");
        QString tunit = match.captured("tunit");
        QString temp = match.captured("temp");
        QString batt = match.captured("batt");
        qDebug() << pos << punit << press << tunit << temp << batt;
    }
}

void test3()
{
    char s[] =
"system: CIS002-0.01.001.201609082206\x0a"
"uboot: 40\x0a"
"mcu:201608030004\x0a"
"lcd:201609130008\x0a"
"board id:2\x0a";

    QRegularExpression re("(?<sys>system: [A-Za-z0-9.-]+)");
    QRegularExpressionMatch match = re.match(s);
    if (match.hasMatch()) {
        QString pos = match.captured("sys");
        qDebug() << pos;
    }
}

int main(int argc, char *argv[])
{
//    QCoreApplication a(argc, argv);

    //testRegexp();
    //test2();
    test3();

    //return a.exec();
    return 0;
}

<|endoftext|>


<commit_before>#include "raven_sqlite.h"

#include <cstdio>
#include <stdarg.h>

using std::string;
using std::vector;
using std::wstring;

#ifdef _mingw_
#include <cstring>
#define vswprintf_s vsnwprintf
#define vsprintf_s vsnprintf
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif

namespace raven
{
	namespace sqlite
	{

		/**

		Open database file UTF16

		@param[in] fname

		*/
		void cDB::Open(const wchar_t *fname)
		{
			if (db)
			{
				myError = "ERROR: db already open";
				return;
			}
			int ret = sqlite3_open16(fname, &db);
			if (ret)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			if (!db)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			myError = 0;
		}
		/**

		Open database file UTF8

		@param[in] fname

		*/
		void cDB::Open(const char *fname)
		{
			if (db)
			{
				myError = "ERROR: db already open";
				return;
			}
			int ret = sqlite3_open(fname, &db);
			if (ret)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			if (!db)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			myError = 0;
		}

		void cDB::Close()
		{
			if (db)
				sqlite3_close(db);
			db = 0;
		}

		cDB::~cDB()
		{
			Close();
		}

		int cDB::Query(const wchar_t *f, ...)
		{
			if (!db)
			{
				myError = "ERROR: db not open";
				return -1;
			}

			va_list _Arglist;
			va_start(_Arglist, f);
			int r;

			// clear results
			myResult.clear();
			myError = 0;

			// format query
			r = vswprintf_s(queryformatted, 999, f, _Arglist);
			va_end(_Arglist);
			if (r < 1)
			{
				myError = "Query string too long for buffer";
				return -1;
			}

			// submit query - just one
			sqlite3_stmt *st = 0;
			int ret;
			void const *tail = 0;
			ret = sqlite3_prepare16_v2(db, queryformatted, -1, &st, &tail);
			if (ret != SQLITE_OK)
			{
				// error in query - provide human readable msg
				int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
				myError = (char *)sqlite3_malloc(nErrMsg);
				if (myError)
				{
					memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
				}
				else
				{
					myError = "out of memory";
				}
				return -1;
			}

			if (sqlite3_step(st) != SQLITE_ROW)
			{
				// no data returned, so finalize
				sqlite3_finalize(st);
				return 0;
			}

			// check for some results
			if (!st)
				return 0;
			myColCount = sqlite3_column_count(st);
			if (!myColCount)
			{
				return 0;
			}

			int row_count = 0;
			// loop over rows returned
			do
			{
				// loop over columns
				for (int kcol = 0; kcol < myColCount; kcol++)
				{
					// check for null value
					if (sqlite3_column_type(st, kcol) == SQLITE_NULL)
						myResult.push_back(wstring(L""));
					else
						myResult.push_back(wstring((wchar_t *)sqlite3_column_text16(st, kcol)));
				}
				row_count++;
			} while (sqlite3_step(st) == SQLITE_ROW);

			// clean up
			sqlite3_finalize(st);

			return row_count;
		}
		int cDB::Query(const char *f, ...)
		{
			if (!db)
			{
				myError = "ERROR: db not open";
				return -1;
			}

			va_list _Arglist;
			va_start(_Arglist, f);
			int r;

			// clear results
			myResultA.clear();
			myError = 0;

			// format query
			r = vsprintf_s(queryformattedA, 1999, f, _Arglist);
			va_end(_Arglist);
			if (r < 1)
			{
				myError = "Query string too long for buffer";
				return -1;
			}

			// submit query - just one
			sqlite3_stmt *st = 0;
			int ret;
			char const *tail = 0;
			ret = sqlite3_prepare_v2(db, queryformattedA, -1, &st, &tail);
			if (ret != SQLITE_OK)
			{
				// error in query - provide human readable msg
				int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
				myError = (char *)sqlite3_malloc(nErrMsg);
				if (myError)
				{
					memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
				}
				else
				{
					myError = "out of memory";
				}
				return -1;
			}

			if (sqlite3_step(st) != SQLITE_ROW)
			{
				// no data returned, so finalize
				sqlite3_finalize(st);
				return 0;
			}

			// check for some results
			if (!st)
				return 0;
			myColCount = sqlite3_column_count(st);
			if (!myColCount)
			{
				return 0;
			}

			int row_count = 0;
			// loop over rows returned
			do
			{
				// loop over columns
				for (int kcol = 0; kcol < myColCount; kcol++)
				{
					// check for null value
					if (sqlite3_column_type(st, kcol) == SQLITE_NULL)
						myResultA.push_back(string(""));
					else
						myResultA.push_back(string((char *)sqlite3_column_text(st, kcol)));
				}
				row_count++;
			} while (sqlite3_step(st) == SQLITE_ROW);

			// clean up
			sqlite3_finalize(st);

			return row_count;
		}
		sqlite3_stmt *cDB::Prepare(
			const std::string &f)
		{
			stmt = 0;
			const char *tail = 0;
			int ret = sqlite3_prepare_v2(
				db,
				f.c_str(),
				-1,
				&stmt,
				&tail);
			if (ret != SQLITE_OK)
			{
				stmt = 0;
				decodeError();
				return stmt;
			}
			return stmt;
		}
		int cDB::Bind(int index, int value)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_int(stmt, index, value))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, double value)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_double(stmt, index, value))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, void *p, int size)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_blob(stmt, index, p, size, SQLITE_STATIC))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, const std::string &str)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_text(stmt, index, str.c_str(), str.length(), SQLITE_STATIC))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		void cDB::decodeError()
		{
			int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
			myError = (char *)sqlite3_malloc(nErrMsg);
			if (myError)
			{
				memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
			}
			else
			{
				myError = "out of memory";
			}
		}
	}
}
<commit_msg>Add missing  include<commit_after>#include "raven_sqlite.h"

#include <cstdio>
#include <stdarg.h>
#include <cstring>

using std::string;
using std::vector;
using std::wstring;

#ifdef _mingw_
#include <cstring>
#define vswprintf_s vsnwprintf
#define vsprintf_s vsnprintf
#pragma GCC diagnostic ignored "-Wwrite-strings"
#endif

namespace raven
{
	namespace sqlite
	{

		/**

		Open database file UTF16

		@param[in] fname

		*/
		void cDB::Open(const wchar_t *fname)
		{
			if (db)
			{
				myError = "ERROR: db already open";
				return;
			}
			int ret = sqlite3_open16(fname, &db);
			if (ret)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			if (!db)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			myError = 0;
		}
		/**

		Open database file UTF8

		@param[in] fname

		*/
		void cDB::Open(const char *fname)
		{
			if (db)
			{
				myError = "ERROR: db already open";
				return;
			}
			int ret = sqlite3_open(fname, &db);
			if (ret)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			if (!db)
			{
				myError = "ERROR: failed to open db";
				return;
			}
			myError = 0;
		}

		void cDB::Close()
		{
			if (db)
				sqlite3_close(db);
			db = 0;
		}

		cDB::~cDB()
		{
			Close();
		}

		int cDB::Query(const wchar_t *f, ...)
		{
			if (!db)
			{
				myError = "ERROR: db not open";
				return -1;
			}

			va_list _Arglist;
			va_start(_Arglist, f);
			int r;

			// clear results
			myResult.clear();
			myError = 0;

			// format query
			r = vswprintf_s(queryformatted, 999, f, _Arglist);
			va_end(_Arglist);
			if (r < 1)
			{
				myError = "Query string too long for buffer";
				return -1;
			}

			// submit query - just one
			sqlite3_stmt *st = 0;
			int ret;
			void const *tail = 0;
			ret = sqlite3_prepare16_v2(db, queryformatted, -1, &st, &tail);
			if (ret != SQLITE_OK)
			{
				// error in query - provide human readable msg
				int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
				myError = (char *)sqlite3_malloc(nErrMsg);
				if (myError)
				{
					memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
				}
				else
				{
					myError = "out of memory";
				}
				return -1;
			}

			if (sqlite3_step(st) != SQLITE_ROW)
			{
				// no data returned, so finalize
				sqlite3_finalize(st);
				return 0;
			}

			// check for some results
			if (!st)
				return 0;
			myColCount = sqlite3_column_count(st);
			if (!myColCount)
			{
				return 0;
			}

			int row_count = 0;
			// loop over rows returned
			do
			{
				// loop over columns
				for (int kcol = 0; kcol < myColCount; kcol++)
				{
					// check for null value
					if (sqlite3_column_type(st, kcol) == SQLITE_NULL)
						myResult.push_back(wstring(L""));
					else
						myResult.push_back(wstring((wchar_t *)sqlite3_column_text16(st, kcol)));
				}
				row_count++;
			} while (sqlite3_step(st) == SQLITE_ROW);

			// clean up
			sqlite3_finalize(st);

			return row_count;
		}
		int cDB::Query(const char *f, ...)
		{
			if (!db)
			{
				myError = "ERROR: db not open";
				return -1;
			}

			va_list _Arglist;
			va_start(_Arglist, f);
			int r;

			// clear results
			myResultA.clear();
			myError = 0;

			// format query
			r = vsprintf_s(queryformattedA, 1999, f, _Arglist);
			va_end(_Arglist);
			if (r < 1)
			{
				myError = "Query string too long for buffer";
				return -1;
			}

			// submit query - just one
			sqlite3_stmt *st = 0;
			int ret;
			char const *tail = 0;
			ret = sqlite3_prepare_v2(db, queryformattedA, -1, &st, &tail);
			if (ret != SQLITE_OK)
			{
				// error in query - provide human readable msg
				int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
				myError = (char *)sqlite3_malloc(nErrMsg);
				if (myError)
				{
					memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
				}
				else
				{
					myError = "out of memory";
				}
				return -1;
			}

			if (sqlite3_step(st) != SQLITE_ROW)
			{
				// no data returned, so finalize
				sqlite3_finalize(st);
				return 0;
			}

			// check for some results
			if (!st)
				return 0;
			myColCount = sqlite3_column_count(st);
			if (!myColCount)
			{
				return 0;
			}

			int row_count = 0;
			// loop over rows returned
			do
			{
				// loop over columns
				for (int kcol = 0; kcol < myColCount; kcol++)
				{
					// check for null value
					if (sqlite3_column_type(st, kcol) == SQLITE_NULL)
						myResultA.push_back(string(""));
					else
						myResultA.push_back(string((char *)sqlite3_column_text(st, kcol)));
				}
				row_count++;
			} while (sqlite3_step(st) == SQLITE_ROW);

			// clean up
			sqlite3_finalize(st);

			return row_count;
		}
		sqlite3_stmt *cDB::Prepare(
			const std::string &f)
		{
			stmt = 0;
			const char *tail = 0;
			int ret = sqlite3_prepare_v2(
				db,
				f.c_str(),
				-1,
				&stmt,
				&tail);
			if (ret != SQLITE_OK)
			{
				stmt = 0;
				decodeError();
				return stmt;
			}
			return stmt;
		}
		int cDB::Bind(int index, int value)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_int(stmt, index, value))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, double value)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_double(stmt, index, value))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, void *p, int size)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_blob(stmt, index, p, size, SQLITE_STATIC))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		int cDB::Bind(int index, const std::string &str)
		{
			if (!stmt)
			{
				myError = "no compiled statement";
				return -1;
			}
			if (sqlite3_bind_text(stmt, index, str.c_str(), str.length(), SQLITE_STATIC))
			{
				decodeError();
				return -1;
			}
			return 0;
		}
		void cDB::decodeError()
		{
			int nErrMsg = 1 + (int)strlen(sqlite3_errmsg(db));
			myError = (char *)sqlite3_malloc(nErrMsg);
			if (myError)
			{
				memcpy((void *)myError, sqlite3_errmsg(db), nErrMsg);
			}
			else
			{
				myError = "out of memory";
			}
		}
	}
}
<|endoftext|>


<commit_before>/**
 Copyright 2015 Joachim Wolff
 Master Project
 Tutors: Milad Miladi, Fabrizio Costa
 Summer semester 2015

 Chair of Bioinformatics
 Department of Computer Science
 Faculty of Engineering
 Albert-Ludwig-University Freiburg im Breisgau
**/

#include <iostream>
#include <iterator>
#include <algorithm>
#include <utility>

#ifdef OPENMP
#include <omp.h>
#endif

#include "minHash.h"

class sort_map {
  public:
    size_t key;
    size_t val;
};

bool mapSortDescByValue(const sort_map& a, const sort_map& b) {
        return a.val > b.val;
};

MinHash::MinHash(size_t pNumberOfHashFunctions, size_t pBlockSize,
                    size_t pNumberOfCores, size_t pChunkSize,
                    size_t pMaxBinSize,
                    size_t pSizeOfNeighborhood, size_t pMinimalBlocksInCommon,
                    size_t pExcessFactor, size_t pMaximalNumberOfHashCollisions) {

    numberOfHashFunctions = pNumberOfHashFunctions;
    blockSize = pBlockSize;
    numberOfCores = pNumberOfCores;
    chunkSize = pChunkSize;
    maxBinSize = pMaxBinSize;
    sizeOfNeighborhood = pSizeOfNeighborhood;
    minimalBlocksInCommon = pMinimalBlocksInCommon;
    excessFactor = pExcessFactor;
    maximalNumberOfHashCollisions = pMaximalNumberOfHashCollisions;
    inverseIndex = new std::vector<umapVector >();
    signatureStorage = new umap_pair_vector();
    size_t inverseIndexSize = ceil(((float) numberOfHashFunctions / (float) blockSize)+1);
    inverseIndex->resize(inverseIndexSize);
}

MinHash::~MinHash() {
    delete signatureStorage;
    delete inverseIndex;
}
 // compute the signature for one instance
vsize_t MinHash::computeSignature(const vsize_t& featureVector) {

    vsize_t signatureHash;
    signatureHash.reserve(numberOfHashFunctions);

    for(size_t j = 0; j < numberOfHashFunctions; ++j) {
        size_t minHashValue = MAX_VALUE;
        for (size_t i = 0; i < featureVector.size(); ++i) {
            size_t hashValue = _size_tHashSimple((featureVector[i] +1) * (j+1) * A, MAX_VALUE);
            if (hashValue < minHashValue) {
                minHashValue = hashValue;
            }
        }
        signatureHash[j] = minHashValue;
    }
    // reduce number of hash values by a factor of blockSize
    size_t k = 0;
    vsize_t signature;
    signature.reserve((numberOfHashFunctions / blockSize) + 1);
    while (k < (numberOfHashFunctions)) {
        // use computed hash value as a seed for the next computation
        size_t signatureBlockValue = signatureHash[k];
        for (size_t j = 0; j < blockSize; ++j) {
            signatureBlockValue = _size_tHashSimple((signatureHash[k+j]) * signatureBlockValue * A, MAX_VALUE);
        }
        signature.push_back(signatureBlockValue);
        k += blockSize;
    }
    return signature;
}
umap_pair_vector* MinHash::computeSignatureMap(const umapVector& instanceFeatureVector) {
    mDoubleElementsQuery = 0;
    const size_t sizeOfInstances = instanceFeatureVector.size();
    umap_pair_vector* instanceSignature = new umap_pair_vector();
    (*instanceSignature).reserve(sizeOfInstances);
    if (chunkSize <= 0) {
        chunkSize = ceil(instanceFeatureVector.size() / static_cast<float>(numberOfCores));
    }
#ifdef OPENMP
    omp_set_dynamic(0);
#endif

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for(size_t index = 0; index < instanceFeatureVector.size(); ++index) {

        auto instanceId = instanceFeatureVector.begin();
        std::advance(instanceId, index);

        // compute unique id
        size_t signatureId = 0;
        for (auto itFeatures = instanceId->second.begin(); itFeatures != instanceId->second.end(); ++itFeatures) {
                signatureId = _size_tHashSimple((*itFeatures +1) * (signatureId+1) * A, MAX_VALUE);
        }
        auto signatureIt = (*signatureStorage).find(signatureId);
        if (signatureIt != (*signatureStorage).end() && !(instanceSignature->find(signatureId) == instanceSignature->end())) {
#pragma omp critical
            {
                instanceSignature->operator[](signatureId) = (*signatureStorage)[signatureId];
                mDoubleElementsQuery += (*signatureStorage)[signatureId].first.size();
            }
            continue;
        }
        // for every hash function: compute the hash values of all features and take the minimum of these
        // as the hash value for one hash function --> h_j(x) = argmin (x_i of x) f_j(x_i)
        vsize_t signature = computeSignature(instanceId->second);
#pragma omp critical
        {
            if (instanceSignature->find(signatureId) == instanceSignature->end()) {
                vsize_t doubleInstanceVector(1);
                doubleInstanceVector[0] = instanceId->first;
                instanceSignature->operator[](signatureId) = std::make_pair (doubleInstanceVector, signature);
                // signatureStorage->operator[](signatureId) = std::make_pair (doubleInstanceVector, signature);
            } else {
                // std::cout << "Same unique id!MAP " << instanceId->first << ": " << signatureId << std::endl;
                instanceSignature->operator[](signatureId).first.push_back(instanceId->first);
                // signatureStorage->operator[](signatureId).first.push_back(instanceId->first);
                mDoubleElementsQuery += 1;
                // std::cout << "Size of double elementsMAP: " << instanceSignature->operator[](signatureId).first.size() << std::endl;
            }
            // }
            // instanceSignature->operator[](signatureId) = std::make_pair (instanceId->first, signature);
            // signatureStorage->operator[](signatureId) = std::make_pair (instanceId->first, signature);
        }
    }
    return instanceSignature;
}
void MinHash::computeInverseIndex(const umapVector& instanceFeatureVector) {
    mDoubleElementsStorage = 0;
    size_t inverseIndexSize = ceil(((float) numberOfHashFunctions / (float) blockSize)+1);
    inverseIndex->resize(inverseIndexSize);

    if (chunkSize <= 0) {
        chunkSize = ceil(instanceFeatureVector.size() / static_cast<float>(numberOfCores));
    }
#ifdef OPENMP
    omp_set_dynamic(0);
#endif

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for(size_t index = 0; index < instanceFeatureVector.size(); ++index) {

        auto instanceId = instanceFeatureVector.begin();
        std::advance(instanceId, index);

        vmSize_tSize_t hashStorage;
        vsize_t signatureHash(numberOfHashFunctions);
        // for every hash function: compute the hash values of all features and take the minimum of these
        // as the hash value for one hash function --> h_j(x) = argmin (x_i of x) f_j(x_i)
        vsize_t signature = computeSignature(instanceId->second);
        // std::cout << "Size of sigantue at creation: " << signature.size() << std::endl;
        size_t signatureId = 0;
        for (auto itFeatures = instanceId->second.begin(); itFeatures != instanceId->second.end(); ++itFeatures) {
            signatureId = _size_tHashSimple((*itFeatures +1) * (signatureId+1) * A, MAX_VALUE);
        }

        // insert in inverse index
#pragma omp critical
        {
            if (signatureStorage->find(signatureId) == signatureStorage->end()) {
                vsize_t doubleInstanceVector(1);
                doubleInstanceVector[0] = instanceId->first;
                signatureStorage->operator[](signatureId) = std::make_pair (doubleInstanceVector, signature);
            } else {
                // std::cout << "Same unique id! " << instanceId->first << ": " << signatureId << std::endl;
                 signatureStorage->operator[](signatureId).first.push_back(instanceId->first);
                 mDoubleElementsStorage += 1;
                // std::cout << "Size of double elements: " << signatureStorage->operator[](signatureId).first.size() << std::endl;
            }
            // signatureStorage->operator[](signatureId) = std::make_pair (instanceId->first, signature);

            for (size_t j = 0; j < signature.size(); ++j) {
                auto itHashValue_InstanceVector = inverseIndex->operator[](j).find(signature[j]);
                // if for hash function h_i() the given hash values is already stored
                if (itHashValue_InstanceVector != inverseIndex->operator[](j).end()) {
                    // insert the instance id if not too many collisions (maxBinSize)
                    if (itHashValue_InstanceVector->second.size() < maxBinSize) {
                        // insert only if there wasn't any collisions in the past
                        if (itHashValue_InstanceVector->second.size() > 0) {
                            itHashValue_InstanceVector->second.push_back(instanceId->first);
                        }
                    } else {
                        // too many collisions: delete stored ids. empty vector is interpreted as an error code
                        // for too many collisions
                        itHashValue_InstanceVector->second.clear();
                    }
                } else {
                    // given hash value for the specific hash function was not avaible: insert new hash value
                    vsize_t instanceIdVector;
                    instanceIdVector.push_back(instanceId->first);
                    inverseIndex->operator[](j)[signature[j]] = instanceIdVector;
                }
            }
        }
    }
}

std::pair<vvsize_t , vvfloat > MinHash::computeNeighbors(const umap_pair_vector* signaturesMap, const size_t doubleElements) {

#ifdef OPENMP
    omp_set_dynamic(0);
#endif
    std::pair<vvsize_t , vvfloat > returnVector;
    vvsize_t neighbors;
    vvfloat distances;
    // std::cout << "Double elements: " << doubleElements << std::endl;
    neighbors.resize((*signaturesMap).size()+doubleElements);
    distances.resize((*signaturesMap).size()+doubleElements);
    if (chunkSize <= 0) {
        chunkSize = ceil((*inverseIndex).size() / static_cast<float>(numberOfCores));
    }

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for (size_t i = 0; i < (*signaturesMap).size(); ++i) {
        umap_pair_vector::const_iterator instanceId = (*signaturesMap).begin();
        std::advance(instanceId, i);

        std::unordered_map<size_t, size_t> neighborhood;
        const vsize_t signature = instanceId->second.second;
        // std::cout << "size of signature: " << signature.size() << std::endl;
        for (size_t j = 0; j < signature.size(); ++j) {
            size_t hashID = signature[j];
            // std::cout << "HashID: " << hashID << std::endl;
            if (hashID != 0 && hashID != MAX_VALUE) {
                size_t collisionSize = 0;
                umapVector::const_iterator instances = inverseIndex->at(j).find(hashID);
                if (instances != inverseIndex->at(j).end()) {
                    collisionSize = instances->second.size();
                } else {
                    continue;
                }

                if (collisionSize < maxBinSize && collisionSize > 0) {
                    // std::cout << "Collision!" << std::endl;
                    // std::cout << "instances->second.size()" << instances->second.size() << std::endl;
                    for (size_t k = 0; k < instances->second.size(); ++k) {
                        neighborhood[instances->second.at(k)] += 1;
                    }
                }
            }
        }

        std::vector< sort_map > neighborhoodVectorForSorting;

        for (auto it = neighborhood.begin(); it != neighborhood.end(); ++it) {
            sort_map mapForSorting;
            mapForSorting.key = (*it).first;
            mapForSorting.val = (*it).second;
            neighborhoodVectorForSorting.push_back(mapForSorting);
        }
        std::sort(neighborhoodVectorForSorting.begin(), neighborhoodVectorForSorting.end(), mapSortDescByValue);
        vsize_t neighborhoodVector;
        std::vector<float> distanceVector;

        size_t sizeOfNeighborhoodAdjusted = std::min(static_cast<size_t>(sizeOfNeighborhood * excessFactor), neighborhoodVectorForSorting.size());
        size_t count = 0;

        for (auto it = neighborhoodVectorForSorting.begin();
                it != neighborhoodVectorForSorting.end(); ++it) {
            neighborhoodVector.push_back((*it).key);
            distanceVector.push_back(1 - ((*it).val / maximalNumberOfHashCollisions));
            ++count;
            if (count == sizeOfNeighborhoodAdjusted) {
                break;
            }
        }

#pragma omp critical
        {
            if (instanceId->first == 743329093) {
            // std::cout << "Size of double elements!!!!: " << instanceId->second.first.size() << std::endl;
            }
            for (size_t j = 0; j < instanceId->second.first.size(); ++j) {
                neighbors[instanceId->second.first[j]] = neighborhoodVector;
                distances[instanceId->second.first[j]] = distanceVector;
            }
        }
    }
    // std::cout << "267" << std::endl;
    returnVector.first = neighbors;
    returnVector.second = distances;
    return returnVector;
}<commit_msg>Bug fix<commit_after>/**
 Copyright 2015 Joachim Wolff
 Master Project
 Tutors: Milad Miladi, Fabrizio Costa
 Summer semester 2015

 Chair of Bioinformatics
 Department of Computer Science
 Faculty of Engineering
 Albert-Ludwig-University Freiburg im Breisgau
**/

#include <iostream>
#include <iterator>
#include <algorithm>
#include <utility>

#ifdef OPENMP
#include <omp.h>
#endif

#include "minHash.h"

class sort_map {
  public:
    size_t key;
    size_t val;
};

bool mapSortDescByValue(const sort_map& a, const sort_map& b) {
        return a.val > b.val;
};

MinHash::MinHash(size_t pNumberOfHashFunctions, size_t pBlockSize,
                    size_t pNumberOfCores, size_t pChunkSize,
                    size_t pMaxBinSize,
                    size_t pSizeOfNeighborhood, size_t pMinimalBlocksInCommon,
                    size_t pExcessFactor, size_t pMaximalNumberOfHashCollisions) {

    numberOfHashFunctions = pNumberOfHashFunctions;
    blockSize = pBlockSize;
    numberOfCores = pNumberOfCores;
    chunkSize = pChunkSize;
    maxBinSize = pMaxBinSize;
    sizeOfNeighborhood = pSizeOfNeighborhood;
    minimalBlocksInCommon = pMinimalBlocksInCommon;
    excessFactor = pExcessFactor;
    maximalNumberOfHashCollisions = pMaximalNumberOfHashCollisions;
    inverseIndex = new std::vector<umapVector >();
    signatureStorage = new umap_pair_vector();
    size_t inverseIndexSize = ceil(((float) numberOfHashFunctions / (float) blockSize)+1);
    inverseIndex->resize(inverseIndexSize);
}

MinHash::~MinHash() {
    delete signatureStorage;
    delete inverseIndex;
}
 // compute the signature for one instance
vsize_t MinHash::computeSignature(const vsize_t& featureVector) {

    vsize_t signatureHash;
    signatureHash.reserve(numberOfHashFunctions);

    for(size_t j = 0; j < numberOfHashFunctions; ++j) {
        size_t minHashValue = MAX_VALUE;
        for (size_t i = 0; i < featureVector.size(); ++i) {
            size_t hashValue = _size_tHashSimple((featureVector[i] +1) * (j+1) * A, MAX_VALUE);
            if (hashValue < minHashValue) {
                minHashValue = hashValue;
            }
        }
        signatureHash[j] = minHashValue;
    }
    // reduce number of hash values by a factor of blockSize
    size_t k = 0;
    vsize_t signature;
    signature.reserve((numberOfHashFunctions / blockSize) + 1);
    while (k < (numberOfHashFunctions)) {
        // use computed hash value as a seed for the next computation
        size_t signatureBlockValue = signatureHash[k];
        for (size_t j = 0; j < blockSize; ++j) {
            signatureBlockValue = _size_tHashSimple((signatureHash[k+j]) * signatureBlockValue * A, MAX_VALUE);
        }
        signature.push_back(signatureBlockValue);
        k += blockSize;
    }
    return signature;
}
umap_pair_vector* MinHash::computeSignatureMap(const umapVector& instanceFeatureVector) {
    mDoubleElementsQuery = 0;
    const size_t sizeOfInstances = instanceFeatureVector.size();
    umap_pair_vector* instanceSignature = new umap_pair_vector();
    (*instanceSignature).reserve(sizeOfInstances);
    if (chunkSize <= 0) {
        chunkSize = ceil(instanceFeatureVector.size() / static_cast<float>(numberOfCores));
    }
#ifdef OPENMP
    omp_set_dynamic(0);
#endif

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for(size_t index = 0; index < instanceFeatureVector.size(); ++index) {

        auto instanceId = instanceFeatureVector.begin();
        std::advance(instanceId, index);

        // compute unique id
        size_t signatureId = 0;
        for (auto itFeatures = instanceId->second.begin(); itFeatures != instanceId->second.end(); ++itFeatures) {
                signatureId = _size_tHashSimple((*itFeatures +1) * (signatureId+1) * A, MAX_VALUE);
        }
        auto signatureIt = (*signatureStorage).find(signatureId);
        if (signatureIt != (*signatureStorage).end() && !(instanceSignature->find(signatureId) == instanceSignature->end())) {
#pragma omp critical
            {
                instanceSignature->operator[](signatureId) = (*signatureStorage)[signatureId];
                mDoubleElementsQuery += (*signatureStorage)[signatureId].first.size();
            }
            continue;
        }
        // for every hash function: compute the hash values of all features and take the minimum of these
        // as the hash value for one hash function --> h_j(x) = argmin (x_i of x) f_j(x_i)
        vsize_t signature = computeSignature(instanceId->second);
#pragma omp critical
        {
            if (instanceSignature->find(signatureId) == instanceSignature->end()) {
                vsize_t doubleInstanceVector(1);
                doubleInstanceVector[0] = instanceId->first;
                instanceSignature->operator[](signatureId) = std::make_pair (doubleInstanceVector, signature);
            } else {
                instanceSignature->operator[](signatureId).first.push_back(instanceId->first);
                mDoubleElementsQuery += 1;
            }
        }
    }
    return instanceSignature;
}
void MinHash::computeInverseIndex(const umapVector& instanceFeatureVector) {
    mDoubleElementsStorage = 0;
    size_t inverseIndexSize = ceil(((float) numberOfHashFunctions / (float) blockSize)+1);
    inverseIndex->resize(inverseIndexSize);

    if (chunkSize <= 0) {
        chunkSize = ceil(instanceFeatureVector.size() / static_cast<float>(numberOfCores));
    }
#ifdef OPENMP
    omp_set_dynamic(0);
#endif

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for(size_t index = 0; index < instanceFeatureVector.size(); ++index) {

        auto instanceId = instanceFeatureVector.begin();
        std::advance(instanceId, index);

        vmSize_tSize_t hashStorage;
        vsize_t signatureHash(numberOfHashFunctions);
        // for every hash function: compute the hash values of all features and take the minimum of these
        // as the hash value for one hash function --> h_j(x) = argmin (x_i of x) f_j(x_i)
        vsize_t signature = computeSignature(instanceId->second);
        size_t signatureId = 0;
        for (auto itFeatures = instanceId->second.begin(); itFeatures != instanceId->second.end(); ++itFeatures) {
            signatureId = _size_tHashSimple((*itFeatures +1) * (signatureId+1) * A, MAX_VALUE);
        }

        // insert in inverse index
#pragma omp critical
        {
            if (signatureStorage->find(signatureId) == signatureStorage->end()) {
                vsize_t doubleInstanceVector(1);
                doubleInstanceVector[0] = instanceId->first;
                signatureStorage->operator[](signatureId) = std::make_pair (doubleInstanceVector, signature);
            } else {
                 signatureStorage->operator[](signatureId).first.push_back(instanceId->first);
                 mDoubleElementsStorage += 1;
            }
            for (size_t j = 0; j < signature.size(); ++j) {
                auto itHashValue_InstanceVector = inverseIndex->operator[](j).find(signature[j]);
                // if for hash function h_i() the given hash values is already stored
                if (itHashValue_InstanceVector != inverseIndex->operator[](j).end()) {
                    // insert the instance id if not too many collisions (maxBinSize)
                    if (itHashValue_InstanceVector->second.size() < maxBinSize) {
                        // insert only if there wasn't any collisions in the past
                        if (itHashValue_InstanceVector->second.size() > 0) {
                            itHashValue_InstanceVector->second.push_back(instanceId->first);
                        }
                    } else {
                        // too many collisions: delete stored ids. empty vector is interpreted as an error code
                        // for too many collisions
                        itHashValue_InstanceVector->second.clear();
                    }
                } else {
                    // given hash value for the specific hash function was not avaible: insert new hash value
                    vsize_t instanceIdVector;
                    instanceIdVector.push_back(instanceId->first);
                    inverseIndex->operator[](j)[signature[j]] = instanceIdVector;
                }
            }
        }
    }
}

std::pair<vvsize_t , vvfloat > MinHash::computeNeighbors(const umap_pair_vector* signaturesMap, const size_t doubleElements) {

#ifdef OPENMP
    omp_set_dynamic(0);
#endif
    std::pair<vvsize_t , vvfloat > returnVector;
    vvsize_t neighbors;
    vvfloat distances;
    neighbors.resize((*signaturesMap).size()+doubleElements);
    distances.resize((*signaturesMap).size()+doubleElements);
    if (chunkSize <= 0) {
        chunkSize = ceil((*inverseIndex).size() / static_cast<float>(numberOfCores));
    }

#pragma omp parallel for schedule(static, chunkSize) num_threads(numberOfCores)
    for (size_t i = 0; i < (*signaturesMap).size(); ++i) {
        umap_pair_vector::const_iterator instanceId = (*signaturesMap).begin();
        std::advance(instanceId, i);

        std::unordered_map<size_t, size_t> neighborhood;
        const vsize_t signature = instanceId->second.second;
        for (size_t j = 0; j < signature.size(); ++j) {
            size_t hashID = signature[j];
            if (hashID != 0 && hashID != MAX_VALUE) {
                size_t collisionSize = 0;
                umapVector::const_iterator instances = inverseIndex->at(j).find(hashID);
                if (instances != inverseIndex->at(j).end()) {
                    collisionSize = instances->second.size();
                } else {
                    continue;
                }

                if (collisionSize < maxBinSize && collisionSize > 0) {
                    for (size_t k = 0; k < instances->second.size(); ++k) {
                        neighborhood[instances->second.at(k)] += 1;
                    }
                }
            }
        }

        std::vector< sort_map > neighborhoodVectorForSorting;

        for (auto it = neighborhood.begin(); it != neighborhood.end(); ++it) {
            sort_map mapForSorting;
            mapForSorting.key = (*it).first;
            mapForSorting.val = (*it).second;
            neighborhoodVectorForSorting.push_back(mapForSorting);
        }
        std::sort(neighborhoodVectorForSorting.begin(), neighborhoodVectorForSorting.end(), mapSortDescByValue);
        vsize_t neighborhoodVector;
        std::vector<float> distanceVector;

        size_t sizeOfNeighborhoodAdjusted = std::min(static_cast<size_t>(sizeOfNeighborhood * excessFactor), neighborhoodVectorForSorting.size());
        size_t count = 0;

        for (auto it = neighborhoodVectorForSorting.begin();
                it != neighborhoodVectorForSorting.end(); ++it) {
            neighborhoodVector.push_back((*it).key);
            distanceVector.push_back(1 - ((*it).val / maximalNumberOfHashCollisions));
            ++count;
            if (count == sizeOfNeighborhoodAdjusted) {
                break;
            }
        }

#pragma omp critical
        {
            for (size_t j = 0; j < instanceId->second.first.size(); ++j) {
                neighbors[instanceId->second.first[j]] = neighborhoodVector;
                distances[instanceId->second.first[j]] = distanceVector;
            }
        }
    }
    returnVector.first = neighbors;
    returnVector.second = distances;
    return returnVector;
}<|endoftext|>


<commit_before>//===- GVNPRE.cpp - Eliminate redundant values and expressions ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs a hybrid of global value numbering and partial redundancy
// elimination, known as GVN-PRE.  It performs partial redundancy elimination on
// values, rather than lexical expressions, allowing a more comprehensive view
// the optimization.  It replaces redundant values with uses of earlier
// occurences of the same value.  While this is beneficial in that it eliminates
// unneeded computation, it also increases register pressure by creating large
// live ranges, and should be used with caution on platforms that a very
// sensitive to register pressure.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "gvnpre"
#include "llvm/Value.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <map>
#include <set>
#include <cstdio>
using namespace llvm;

namespace {

  class VISIBILITY_HIDDEN GVNPRE : public FunctionPass {
    bool runOnFunction(Function &F);
  public:
    static char ID; // Pass identification, replacement for typeid
    GVNPRE() : FunctionPass((intptr_t)&ID) { nextValueNumber = 0; }

  private:
    uint32_t nextValueNumber;

    struct Expression {
      char opcode;
      Value* value;
      uint32_t lhs;
      uint32_t rhs;

      bool operator<(const Expression& other) const {
        if (opcode < other.opcode)
          return true;
        else if (other.opcode < opcode)
          return false;

        if (opcode == 0) {
          if (value < other.value)
            return true;
          else
            return false;
        } else {
          if (lhs < other.lhs)
            return true;
          else if (other.lhs < lhs)
            return true;
          else if (rhs < other.rhs)
            return true;
          else
            return false;
        }
      }

      bool operator==(const Expression& other) const {
        if (opcode != other.opcode)
          return false;

        if (value != other.value)
          return false;

        if (lhs != other.lhs)
          return false;

        if (rhs != other.rhs)
          return false;

        return true;
      }
    };

    typedef std::map<Expression, uint32_t> ValueTable;

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<DominatorTree>();
      AU.addRequired<PostDominatorTree>();
    }

    // Helper fuctions
    // FIXME: eliminate or document these better
    void dump(ValueTable& VN, std::set<Expression>& s);
    void clean(ValueTable VN, std::set<Expression>& set);
    Expression add(ValueTable& VN, std::set<Expression>& MS, Instruction* V);
    ValueTable::iterator lookup(ValueTable& VN, Value* V);
    Expression buildExpression(ValueTable& VN, Value* V);
    std::set<Expression>::iterator find_leader(ValueTable VN,
                                               std::set<Expression>& vals,
                                               uint32_t v);
    void phi_translate(ValueTable& VN,
                       std::set<Expression>& anticIn, BasicBlock* B,
                       std::set<Expression>& out);

    // For a given block, calculate the generated expressions, temporaries,
    // and the AVAIL_OUT set
    void CalculateAvailOut(ValueTable& VN, std::set<Expression>& MS,
                       DominatorTree::Node* DI,
                       std::set<Expression>& currExps,
                       std::set<PHINode*>& currPhis,
                       std::set<Expression>& currTemps,
                       std::set<Expression>& currAvail,
                       std::map<BasicBlock*, std::set<Expression> > availOut);

  };

  char GVNPRE::ID = 0;

}

FunctionPass *llvm::createGVNPREPass() { return new GVNPRE(); }

RegisterPass<GVNPRE> X("gvnpre",
                       "Global Value Numbering/Partial Redundancy Elimination");

// Given a Value, build an Expression to represent it
GVNPRE::Expression GVNPRE::buildExpression(ValueTable& VN, Value* V) {
  if (Instruction* I = dyn_cast<Instruction>(V)) {
    Expression e;

    switch (I->getOpcode()) {
    case 7:
      e.opcode = 1; // ADD
      break;
    case 8:
      e.opcode = 2; // SUB
      break;
    case 9:
      e.opcode = 3; // MUL
      break;
    case 10:
      e.opcode = 4; // UDIV
      break;
    case 11:
      e.opcode = 5; // SDIV
      break;
    case 12:
      e.opcode = 6; // FDIV
      break;
    case 13:
      e.opcode = 7; // UREM
      break;
    case 14:
      e.opcode = 8; // SREM
      break;
    case 15:
      e.opcode = 9; // FREM
      break;
    default:
     e.opcode = 0; // OPAQUE
     e.lhs = 0;
     e.rhs = 0;
     e.value = V;
     return e;
    }

    e.value = 0;

    ValueTable::iterator lhs = lookup(VN, I->getOperand(0));
    if (lhs == VN.end()) {
      Expression lhsExp = buildExpression(VN, I->getOperand(0));
      VN.insert(std::make_pair(lhsExp, nextValueNumber));
      e.lhs = nextValueNumber;
      nextValueNumber++;
    } else
      e.lhs = lhs->second;
    ValueTable::iterator rhs = lookup(VN, I->getOperand(1));
    if (rhs == VN.end()) {
      Expression rhsExp = buildExpression(VN, I->getOperand(1));
      VN.insert(std::make_pair(rhsExp, nextValueNumber));
      e.rhs = nextValueNumber;
      nextValueNumber++;
    } else
      e.rhs = rhs->second;

    return e;
  } else {
    Expression e;
    e.opcode = 0;
    e.value = V;
    e.lhs = 0;
    e.rhs = 0;

    return e;
  }
}

GVNPRE::Expression GVNPRE::add(ValueTable& VN, std::set<Expression>& MS,
                               Instruction* V) {
  Expression e = buildExpression(VN, V);
  if (VN.insert(std::make_pair(e, nextValueNumber)).second)
    nextValueNumber++;
  if (e.opcode != 0 || (e.opcode == 0 && isa<PHINode>(e.value)))
    MS.insert(e);
  return e;
}

GVNPRE::ValueTable::iterator GVNPRE::lookup(ValueTable& VN, Value* V) {
  Expression e = buildExpression(VN, V);
  return VN.find(e);
}

std::set<GVNPRE::Expression>::iterator GVNPRE::find_leader(GVNPRE::ValueTable VN,
                           std::set<GVNPRE::Expression>& vals,
                           uint32_t v) {
  for (std::set<Expression>::iterator I = vals.begin(), E = vals.end();
       I != E; ++I)
    if (VN[*I] == v)
      return I;

  return vals.end();
}

void GVNPRE::phi_translate(GVNPRE::ValueTable& VN,
                           std::set<GVNPRE::Expression>& anticIn, BasicBlock* B,
                           std::set<GVNPRE::Expression>& out) {
  BasicBlock* succ = B->getTerminator()->getSuccessor(0);

  for (std::set<Expression>::iterator I = anticIn.begin(), E = anticIn.end();
       I != E; ++I) {
    if (I->opcode == 0) {
      Value *v = I->value;
      if (PHINode* p = dyn_cast<PHINode>(v))
        if (p->getParent() == succ) {
          out.insert(buildExpression(VN, p->getIncomingValueForBlock(B)));
          continue;
        }
    }
    //out.insert(*I);
  }
}

// Remove all expressions whose operands are not themselves in the set
void GVNPRE::clean(GVNPRE::ValueTable VN, std::set<GVNPRE::Expression>& set) {
  unsigned size = set.size();
  unsigned old = 0;

  while (size != old) {
    old = size;

    std::vector<Expression> worklist(set.begin(), set.end());
    while (!worklist.empty()) {
      Expression e = worklist.back();
      worklist.pop_back();

      if (e.opcode == 0) // OPAQUE
        continue;

      bool lhsValid = false;
      for (std::set<Expression>::iterator I = set.begin(), E = set.end();
           I != E; ++I)
        if (VN[*I] == e.lhs);
          lhsValid = true;

      bool rhsValid = false;
      for (std::set<Expression>::iterator I = set.begin(), E = set.end();
           I != E; ++I)
        if (VN[*I] == e.rhs);
          rhsValid = true;

      if (!lhsValid || !rhsValid)
        set.erase(e);
    }

    size = set.size();
  }
}

void GVNPRE::dump(GVNPRE::ValueTable& VN, std::set<GVNPRE::Expression>& s) {
  printf("{ ");
  for (std::set<Expression>::iterator I = s.begin(), E = s.end(); I != E; ++I) {
    printf("(%d, %s, value.%d, value.%d) ", I->opcode, I->value == 0 ? "0" : I->value->getName().c_str(), I->lhs, I->rhs);
  }
  printf("}\n\n");
}

void GVNPRE::CalculateAvailOut(GVNPRE::ValueTable& VN, std::set<Expression>& MS,
                       DominatorTree::Node* DI,
                       std::set<Expression>& currExps,
                       std::set<PHINode*>& currPhis,
                       std::set<Expression>& currTemps,
                       std::set<Expression>& currAvail,
                       std::map<BasicBlock*, std::set<Expression> > availOut) {

  BasicBlock* BB = DI->getBlock();

  // A block inherits AVAIL_OUT from its dominator
  if (DI->getIDom() != 0)
  currAvail.insert(availOut[DI->getIDom()->getBlock()].begin(),
                   availOut[DI->getIDom()->getBlock()].end());

 for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
      BI != BE; ++BI) {

    // Handle PHI nodes...
    if (PHINode* p = dyn_cast<PHINode>(BI)) {
      add(VN, MS, p);
      currPhis.insert(p);

    // Handle binary ops...
    } else if (BinaryOperator* BO = dyn_cast<BinaryOperator>(BI)) {
      Expression leftValue = buildExpression(VN, BO->getOperand(0));
      Expression rightValue = buildExpression(VN, BO->getOperand(1));

      Expression e = add(VN, MS, BO);

      currExps.insert(leftValue);
      currExps.insert(rightValue);
      currExps.insert(e);

      currTemps.insert(e);

    // Handle unsupported ops
    } else {
      Expression e = add(VN, MS, BI);
      currTemps.insert(e);
    }

    currAvail.insert(buildExpression(VN, BI));
  }
}

bool GVNPRE::runOnFunction(Function &F) {
  ValueTable VN;
  std::set<Expression> maximalSet;

  std::map<BasicBlock*, std::set<Expression> > generatedExpressions;
  std::map<BasicBlock*, std::set<PHINode*> > generatedPhis;
  std::map<BasicBlock*, std::set<Expression> > generatedTemporaries;
  std::map<BasicBlock*, std::set<Expression> > availableOut;
  std::map<BasicBlock*, std::set<Expression> > anticipatedIn;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  // First Phase of BuildSets - calculate AVAIL_OUT

  // Top-down walk of the dominator tree
  for (df_iterator<DominatorTree::Node*> DI = df_begin(DT.getRootNode()),
         E = df_end(DT.getRootNode()); DI != E; ++DI) {

    // Get the sets to update for this block
    std::set<Expression>& currExps = generatedExpressions[DI->getBlock()];
    std::set<PHINode*>& currPhis = generatedPhis[DI->getBlock()];
    std::set<Expression>& currTemps = generatedTemporaries[DI->getBlock()];
    std::set<Expression>& currAvail = availableOut[DI->getBlock()];

    CalculateAvailOut(VN, maximalSet, *DI, currExps, currPhis,
                      currTemps, currAvail, availableOut);
  }

  PostDominatorTree &PDT = getAnalysis<PostDominatorTree>();

  // Second Phase of BuildSets - calculate ANTIC_IN

  bool changed = true;
  unsigned iterations = 0;
  while (changed) {
    changed = false;
    std::set<Expression> anticOut;

    // Top-down walk of the postdominator tree
    for (df_iterator<PostDominatorTree::Node*> PDI =
         df_begin(PDT.getRootNode()), E = df_end(DT.getRootNode());
         PDI != E; ++PDI) {
      BasicBlock* BB = PDI->getBlock();

      std::set<Expression>& anticIn = anticipatedIn[BB];
      std::set<Expression> old (anticIn.begin(), anticIn.end());

      if (BB->getTerminator()->getNumSuccessors() == 1) {
         phi_translate(VN, maximalSet, BB, anticOut);
      } else if (BB->getTerminator()->getNumSuccessors() > 1) {
        for (unsigned i = 0; i < BB->getTerminator()->getNumSuccessors(); ++i) {
          BasicBlock* currSucc = BB->getTerminator()->getSuccessor(i);
          std::set<Expression> temp;
          if (i == 0)
            temp.insert(maximalSet.begin(), maximalSet.end());
          else
            temp.insert(anticIn.begin(), anticIn.end());

          anticIn.clear();
          std::insert_iterator<std::set<Expression> >  ai_ins(anticIn,
                                                       anticIn.begin());

          std::set_difference(anticipatedIn[currSucc].begin(),
                              anticipatedIn[currSucc].end(),
                              temp.begin(),
                              temp.end(),
                              ai_ins);
        }
      }

      std::set<Expression> S;
      std::insert_iterator<std::set<Expression> >  s_ins(S, S.begin());
      std::set_union(anticOut.begin(), anticOut.end(),
                     generatedExpressions[BB].begin(),
                     generatedExpressions[BB].end(),
                     s_ins);

      anticIn.clear();
      std::insert_iterator<std::set<Expression> >  antic_ins(anticIn,
                                                             anticIn.begin());
      std::set_difference(S.begin(), S.end(),
                          generatedTemporaries[BB].begin(),
                          generatedTemporaries[BB].end(),
                          antic_ins);

      clean(VN, anticIn);

      if (old != anticIn)
        changed = true;

      anticOut.clear();
    }
    iterations++;
  }

  printf("Iterations: %d\n", iterations);

  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
    printf("Name: ");
    printf(I->getName().c_str());
    printf("\nTMP_GEN: ");
    dump(VN, generatedTemporaries[I]);
    printf("\nEXP_GEN: ");
    dump(VN, generatedExpressions[I]);
    //printf("\nANTIC_OUT: ");
    //dump(VN, anticipatedOut[I]);
    printf("\nANTIC_IN: \n");
    dump(VN, anticipatedIn[I]);
    printf("\n");
  }

  return false;
}
<commit_msg>Comment debug code out that I accidentally uncommented last time.<commit_after>//===- GVNPRE.cpp - Eliminate redundant values and expressions ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs a hybrid of global value numbering and partial redundancy
// elimination, known as GVN-PRE.  It performs partial redundancy elimination on
// values, rather than lexical expressions, allowing a more comprehensive view
// the optimization.  It replaces redundant values with uses of earlier
// occurences of the same value.  While this is beneficial in that it eliminates
// unneeded computation, it also increases register pressure by creating large
// live ranges, and should be used with caution on platforms that a very
// sensitive to register pressure.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "gvnpre"
#include "llvm/Value.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
#include <map>
#include <set>
#include <cstdio>
using namespace llvm;

namespace {

  class VISIBILITY_HIDDEN GVNPRE : public FunctionPass {
    bool runOnFunction(Function &F);
  public:
    static char ID; // Pass identification, replacement for typeid
    GVNPRE() : FunctionPass((intptr_t)&ID) { nextValueNumber = 0; }

  private:
    uint32_t nextValueNumber;

    struct Expression {
      char opcode;
      Value* value;
      uint32_t lhs;
      uint32_t rhs;

      bool operator<(const Expression& other) const {
        if (opcode < other.opcode)
          return true;
        else if (other.opcode < opcode)
          return false;

        if (opcode == 0) {
          if (value < other.value)
            return true;
          else
            return false;
        } else {
          if (lhs < other.lhs)
            return true;
          else if (other.lhs < lhs)
            return true;
          else if (rhs < other.rhs)
            return true;
          else
            return false;
        }
      }

      bool operator==(const Expression& other) const {
        if (opcode != other.opcode)
          return false;

        if (value != other.value)
          return false;

        if (lhs != other.lhs)
          return false;

        if (rhs != other.rhs)
          return false;

        return true;
      }
    };

    typedef std::map<Expression, uint32_t> ValueTable;

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<DominatorTree>();
      AU.addRequired<PostDominatorTree>();
    }

    // Helper fuctions
    // FIXME: eliminate or document these better
    void dump(ValueTable& VN, std::set<Expression>& s);
    void clean(ValueTable VN, std::set<Expression>& set);
    Expression add(ValueTable& VN, std::set<Expression>& MS, Instruction* V);
    ValueTable::iterator lookup(ValueTable& VN, Value* V);
    Expression buildExpression(ValueTable& VN, Value* V);
    std::set<Expression>::iterator find_leader(ValueTable VN,
                                               std::set<Expression>& vals,
                                               uint32_t v);
    void phi_translate(ValueTable& VN,
                       std::set<Expression>& anticIn, BasicBlock* B,
                       std::set<Expression>& out);

    // For a given block, calculate the generated expressions, temporaries,
    // and the AVAIL_OUT set
    void CalculateAvailOut(ValueTable& VN, std::set<Expression>& MS,
                       DominatorTree::Node* DI,
                       std::set<Expression>& currExps,
                       std::set<PHINode*>& currPhis,
                       std::set<Expression>& currTemps,
                       std::set<Expression>& currAvail,
                       std::map<BasicBlock*, std::set<Expression> > availOut);

  };

  char GVNPRE::ID = 0;

}

FunctionPass *llvm::createGVNPREPass() { return new GVNPRE(); }

RegisterPass<GVNPRE> X("gvnpre",
                       "Global Value Numbering/Partial Redundancy Elimination");

// Given a Value, build an Expression to represent it
GVNPRE::Expression GVNPRE::buildExpression(ValueTable& VN, Value* V) {
  if (Instruction* I = dyn_cast<Instruction>(V)) {
    Expression e;

    switch (I->getOpcode()) {
    case 7:
      e.opcode = 1; // ADD
      break;
    case 8:
      e.opcode = 2; // SUB
      break;
    case 9:
      e.opcode = 3; // MUL
      break;
    case 10:
      e.opcode = 4; // UDIV
      break;
    case 11:
      e.opcode = 5; // SDIV
      break;
    case 12:
      e.opcode = 6; // FDIV
      break;
    case 13:
      e.opcode = 7; // UREM
      break;
    case 14:
      e.opcode = 8; // SREM
      break;
    case 15:
      e.opcode = 9; // FREM
      break;
    default:
     e.opcode = 0; // OPAQUE
     e.lhs = 0;
     e.rhs = 0;
     e.value = V;
     return e;
    }

    e.value = 0;

    ValueTable::iterator lhs = lookup(VN, I->getOperand(0));
    if (lhs == VN.end()) {
      Expression lhsExp = buildExpression(VN, I->getOperand(0));
      VN.insert(std::make_pair(lhsExp, nextValueNumber));
      e.lhs = nextValueNumber;
      nextValueNumber++;
    } else
      e.lhs = lhs->second;
    ValueTable::iterator rhs = lookup(VN, I->getOperand(1));
    if (rhs == VN.end()) {
      Expression rhsExp = buildExpression(VN, I->getOperand(1));
      VN.insert(std::make_pair(rhsExp, nextValueNumber));
      e.rhs = nextValueNumber;
      nextValueNumber++;
    } else
      e.rhs = rhs->second;

    return e;
  } else {
    Expression e;
    e.opcode = 0;
    e.value = V;
    e.lhs = 0;
    e.rhs = 0;

    return e;
  }
}

GVNPRE::Expression GVNPRE::add(ValueTable& VN, std::set<Expression>& MS,
                               Instruction* V) {
  Expression e = buildExpression(VN, V);
  if (VN.insert(std::make_pair(e, nextValueNumber)).second)
    nextValueNumber++;
  if (e.opcode != 0 || (e.opcode == 0 && isa<PHINode>(e.value)))
    MS.insert(e);
  return e;
}

GVNPRE::ValueTable::iterator GVNPRE::lookup(ValueTable& VN, Value* V) {
  Expression e = buildExpression(VN, V);
  return VN.find(e);
}

std::set<GVNPRE::Expression>::iterator GVNPRE::find_leader(GVNPRE::ValueTable VN,
                           std::set<GVNPRE::Expression>& vals,
                           uint32_t v) {
  for (std::set<Expression>::iterator I = vals.begin(), E = vals.end();
       I != E; ++I)
    if (VN[*I] == v)
      return I;

  return vals.end();
}

void GVNPRE::phi_translate(GVNPRE::ValueTable& VN,
                           std::set<GVNPRE::Expression>& anticIn, BasicBlock* B,
                           std::set<GVNPRE::Expression>& out) {
  BasicBlock* succ = B->getTerminator()->getSuccessor(0);

  for (std::set<Expression>::iterator I = anticIn.begin(), E = anticIn.end();
       I != E; ++I) {
    if (I->opcode == 0) {
      Value *v = I->value;
      if (PHINode* p = dyn_cast<PHINode>(v))
        if (p->getParent() == succ) {
          out.insert(buildExpression(VN, p->getIncomingValueForBlock(B)));
          continue;
        }
    }
    //out.insert(*I);
  }
}

// Remove all expressions whose operands are not themselves in the set
void GVNPRE::clean(GVNPRE::ValueTable VN, std::set<GVNPRE::Expression>& set) {
  unsigned size = set.size();
  unsigned old = 0;

  while (size != old) {
    old = size;

    std::vector<Expression> worklist(set.begin(), set.end());
    while (!worklist.empty()) {
      Expression e = worklist.back();
      worklist.pop_back();

      if (e.opcode == 0) // OPAQUE
        continue;

      bool lhsValid = false;
      for (std::set<Expression>::iterator I = set.begin(), E = set.end();
           I != E; ++I)
        if (VN[*I] == e.lhs);
          lhsValid = true;

      bool rhsValid = false;
      for (std::set<Expression>::iterator I = set.begin(), E = set.end();
           I != E; ++I)
        if (VN[*I] == e.rhs);
          rhsValid = true;

      if (!lhsValid || !rhsValid)
        set.erase(e);
    }

    size = set.size();
  }
}

void GVNPRE::dump(GVNPRE::ValueTable& VN, std::set<GVNPRE::Expression>& s) {
  printf("{ ");
  for (std::set<Expression>::iterator I = s.begin(), E = s.end(); I != E; ++I) {
    printf("(%d, %s, value.%d, value.%d) ", I->opcode, I->value == 0 ? "0" : I->value->getName().c_str(), I->lhs, I->rhs);
  }
  printf("}\n\n");
}

void GVNPRE::CalculateAvailOut(GVNPRE::ValueTable& VN, std::set<Expression>& MS,
                       DominatorTree::Node* DI,
                       std::set<Expression>& currExps,
                       std::set<PHINode*>& currPhis,
                       std::set<Expression>& currTemps,
                       std::set<Expression>& currAvail,
                       std::map<BasicBlock*, std::set<Expression> > availOut) {

  BasicBlock* BB = DI->getBlock();

  // A block inherits AVAIL_OUT from its dominator
  if (DI->getIDom() != 0)
  currAvail.insert(availOut[DI->getIDom()->getBlock()].begin(),
                   availOut[DI->getIDom()->getBlock()].end());

 for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
      BI != BE; ++BI) {

    // Handle PHI nodes...
    if (PHINode* p = dyn_cast<PHINode>(BI)) {
      add(VN, MS, p);
      currPhis.insert(p);

    // Handle binary ops...
    } else if (BinaryOperator* BO = dyn_cast<BinaryOperator>(BI)) {
      Expression leftValue = buildExpression(VN, BO->getOperand(0));
      Expression rightValue = buildExpression(VN, BO->getOperand(1));

      Expression e = add(VN, MS, BO);

      currExps.insert(leftValue);
      currExps.insert(rightValue);
      currExps.insert(e);

      currTemps.insert(e);

    // Handle unsupported ops
    } else {
      Expression e = add(VN, MS, BI);
      currTemps.insert(e);
    }

    currAvail.insert(buildExpression(VN, BI));
  }
}

bool GVNPRE::runOnFunction(Function &F) {
  ValueTable VN;
  std::set<Expression> maximalSet;

  std::map<BasicBlock*, std::set<Expression> > generatedExpressions;
  std::map<BasicBlock*, std::set<PHINode*> > generatedPhis;
  std::map<BasicBlock*, std::set<Expression> > generatedTemporaries;
  std::map<BasicBlock*, std::set<Expression> > availableOut;
  std::map<BasicBlock*, std::set<Expression> > anticipatedIn;

  DominatorTree &DT = getAnalysis<DominatorTree>();

  // First Phase of BuildSets - calculate AVAIL_OUT

  // Top-down walk of the dominator tree
  for (df_iterator<DominatorTree::Node*> DI = df_begin(DT.getRootNode()),
         E = df_end(DT.getRootNode()); DI != E; ++DI) {

    // Get the sets to update for this block
    std::set<Expression>& currExps = generatedExpressions[DI->getBlock()];
    std::set<PHINode*>& currPhis = generatedPhis[DI->getBlock()];
    std::set<Expression>& currTemps = generatedTemporaries[DI->getBlock()];
    std::set<Expression>& currAvail = availableOut[DI->getBlock()];

    CalculateAvailOut(VN, maximalSet, *DI, currExps, currPhis,
                      currTemps, currAvail, availableOut);
  }

  PostDominatorTree &PDT = getAnalysis<PostDominatorTree>();

  // Second Phase of BuildSets - calculate ANTIC_IN

  bool changed = true;
  unsigned iterations = 0;
  while (changed) {
    changed = false;
    std::set<Expression> anticOut;

    // Top-down walk of the postdominator tree
    for (df_iterator<PostDominatorTree::Node*> PDI =
         df_begin(PDT.getRootNode()), E = df_end(DT.getRootNode());
         PDI != E; ++PDI) {
      BasicBlock* BB = PDI->getBlock();

      std::set<Expression>& anticIn = anticipatedIn[BB];
      std::set<Expression> old (anticIn.begin(), anticIn.end());

      if (BB->getTerminator()->getNumSuccessors() == 1) {
         phi_translate(VN, maximalSet, BB, anticOut);
      } else if (BB->getTerminator()->getNumSuccessors() > 1) {
        for (unsigned i = 0; i < BB->getTerminator()->getNumSuccessors(); ++i) {
          BasicBlock* currSucc = BB->getTerminator()->getSuccessor(i);
          std::set<Expression> temp;
          if (i == 0)
            temp.insert(maximalSet.begin(), maximalSet.end());
          else
            temp.insert(anticIn.begin(), anticIn.end());

          anticIn.clear();
          std::insert_iterator<std::set<Expression> >  ai_ins(anticIn,
                                                       anticIn.begin());

          std::set_difference(anticipatedIn[currSucc].begin(),
                              anticipatedIn[currSucc].end(),
                              temp.begin(),
                              temp.end(),
                              ai_ins);
        }
      }

      std::set<Expression> S;
      std::insert_iterator<std::set<Expression> >  s_ins(S, S.begin());
      std::set_union(anticOut.begin(), anticOut.end(),
                     generatedExpressions[BB].begin(),
                     generatedExpressions[BB].end(),
                     s_ins);

      anticIn.clear();
      std::insert_iterator<std::set<Expression> >  antic_ins(anticIn,
                                                             anticIn.begin());
      std::set_difference(S.begin(), S.end(),
                          generatedTemporaries[BB].begin(),
                          generatedTemporaries[BB].end(),
                          antic_ins);

      clean(VN, anticIn);

      if (old != anticIn)
        changed = true;

      anticOut.clear();
    }
    iterations++;
  }

  /*printf("Iterations: %d\n", iterations);

  for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I) {
    printf("Name: ");
    printf(I->getName().c_str());
    printf("\nTMP_GEN: ");
    dump(VN, generatedTemporaries[I]);
    printf("\nEXP_GEN: ");
    dump(VN, generatedExpressions[I]);
    //printf("\nANTIC_OUT: ");
    //dump(VN, anticipatedOut[I]);
    printf("\nANTIC_IN: \n");
    dump(VN, anticipatedIn[I]);
    printf("\n");
  }*/

  return false;
}
<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/physical_shape_layer.h"

#include "flutter/flow/paint_utils.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"

namespace flow {

const SkScalar kLightHeight = 600;
const SkScalar kLightRadius = 800;

PhysicalShapeLayer::PhysicalShapeLayer(Clip clip_behavior)
    : isRect_(false), clip_behavior_(clip_behavior) {}

PhysicalShapeLayer::~PhysicalShapeLayer() = default;

void PhysicalShapeLayer::set_path(const SkPath& path) {
  path_ = path;
  isRect_ = false;
  SkRect rect;
  if (path.isRect(&rect)) {
    isRect_ = true;
    frameRRect_ = SkRRect::MakeRect(rect);
  } else if (path.isRRect(&frameRRect_)) {
    isRect_ = frameRRect_.isRect();
  } else if (path.isOval(&rect)) {
    // isRRect returns false for ovals, so we need to explicitly check isOval
    // as well.
    frameRRect_ = SkRRect::MakeOval(rect);
  } else {
    // Scenic currently doesn't provide an easy way to create shapes from
    // arbitrary paths.
    // For shapes that cannot be represented as a rounded rectangle we
    // default to use the bounding rectangle.
    // TODO(amirh): fix this once we have a way to create a Scenic shape from
    // an SkPath.
    frameRRect_ = SkRRect::MakeRect(path.getBounds());
  }
}

void PhysicalShapeLayer::Preroll(PrerollContext* context,
                                 const SkMatrix& matrix) {
  SkRect child_paint_bounds;
  PrerollChildren(context, matrix, &child_paint_bounds);

  if (elevation_ == 0) {
    set_paint_bounds(path_.getBounds());
  } else {
#if defined(OS_FUCHSIA)
    // Let the system compositor draw all shadows for us.
    set_needs_system_composite(true);
#else
    // Add some margin to the paint bounds to leave space for the shadow.
    // We fill this whole region and clip children to it so we don't need to
    // join the child paint bounds.
    // The offset is calculated as follows:

    //                   .--                            (kLightRadius = 800)
    //                 -----                            (light)
    //                   |                              (kLightHeight = 600)
    //             -------------                        (layer)
    //                   |
    //                   |                              (elevation)
    //                   |
    // ------------------------------------------------ (canvas)
    //  -----------                                     (extent of shadow)
    //
    // E = lx        }           x = (r + w/2)/h
    //                } =>
    // r + w/2 = hx  }           E = (l/h)(r + w/2)
    //
    // Where: E = extent of shadow
    //        l = elevation of layer
    //        r = radius of the light source
    //        w = width of the layer
    //        h = light height
    //        x = multiplier for elevation to extent
    SkRect bounds(path_.getBounds());
    double ex = (kLightRadius * device_pixel_ratio_ + bounds.width() * 0.5) /
                kLightHeight;
    double ey = (kLightRadius * device_pixel_ratio_ + bounds.height() * 0.5) /
                kLightHeight;
    bounds.outset(elevation_ * ex, elevation_ * ey);
    set_paint_bounds(bounds);
#endif  // defined(OS_FUCHSIA)
  }
}

#if defined(OS_FUCHSIA)

void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
  FML_DCHECK(needs_system_composite());

  // Retained rendering: speedup by reusing a retained entity node if possible.
  // When an entity node is reused, no paint layer is added to the frame so we
  // won't call PhysicalShapeLayer::Paint.
  LayerRasterCacheKey key(this, context.Matrix());
  if (context.HasRetainedNode(key)) {
    const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
    FML_DCHECK(context.top_entity());
    FML_DCHECK(retained_node.session() == context.session());
    context.top_entity()->entity_node().AddChild(retained_node);
    return;
  }

  // If we can't find an existing retained surface, create one.
  SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_,
                                  this);
  for (auto& layer : layers()) {
    if (layer->needs_painting()) {
      frame.AddPaintLayer(layer.get());
    }
  }

  UpdateSceneChildren(context);
}

#endif  // defined(OS_FUCHSIA)

void PhysicalShapeLayer::Paint(PaintContext& context) const {
  TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
  FML_DCHECK(needs_painting());

  if (elevation_ != 0) {
    DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
               SkColorGetA(color_) != 0xff, device_pixel_ratio_);
  }

  // Call drawPath without clip if possible for better performance.
  SkPaint paint;
  paint.setColor(color_);
  if (clip_behavior_ != Clip::antiAliasWithSaveLayer) {
    context.leaf_nodes_canvas->drawPath(path_, paint);
  }

  int saveCount = context.internal_nodes_canvas->save();
  switch (clip_behavior_) {
    case Clip::hardEdge:
      context.internal_nodes_canvas->clipPath(path_, false);
      break;
    case Clip::antiAlias:
      context.internal_nodes_canvas->clipPath(path_, true);
      break;
    case Clip::antiAliasWithSaveLayer:
      context.internal_nodes_canvas->clipPath(path_, true);
      context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
      break;
    case Clip::none:
      break;
  }

  if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
    // If we want to avoid the bleeding edge artifact
    // (https://github.com/flutter/flutter/issues/18057#issue-328003931)
    // using saveLayer, we have to call drawPaint instead of drawPath as
    // anti-aliased drawPath will always have such artifacts.
    context.leaf_nodes_canvas->drawPaint(paint);
  }

  PaintChildren(context);

  context.internal_nodes_canvas->restoreToCount(saveCount);
}

void PhysicalShapeLayer::DrawShadow(SkCanvas* canvas,
                                    const SkPath& path,
                                    SkColor color,
                                    float elevation,
                                    bool transparentOccluder,
                                    SkScalar dpr) {
  const SkScalar kAmbientAlpha = 0.039f;
  const SkScalar kSpotAlpha = 0.25f;

  SkShadowFlags flags = transparentOccluder
                            ? SkShadowFlags::kTransparentOccluder_ShadowFlag
                            : SkShadowFlags::kNone_ShadowFlag;
  const SkRect& bounds = path.getBounds();
  SkScalar shadow_x = (bounds.left() + bounds.right()) / 2;
  SkScalar shadow_y = bounds.top() - 600.0f;
  SkColor inAmbient = SkColorSetA(color, kAmbientAlpha * SkColorGetA(color));
  SkColor inSpot = SkColorSetA(color, kSpotAlpha * SkColorGetA(color));
  SkColor ambientColor, spotColor;
  SkShadowUtils::ComputeTonalColors(inAmbient, inSpot, &ambientColor,
                                    &spotColor);
  SkShadowUtils::DrawShadow(
      canvas, path, SkPoint3::Make(0, 0, dpr * elevation),
      SkPoint3::Make(shadow_x, shadow_y, dpr * kLightHeight),
      dpr * kLightRadius, ambientColor, spotColor, flags);
}

}  // namespace flow
<commit_msg>Improve shadow doc in PhysicalShapeLayer (#8114)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "flutter/flow/layers/physical_shape_layer.h"

#include "flutter/flow/paint_utils.h"
#include "third_party/skia/include/utils/SkShadowUtils.h"

namespace flow {

const SkScalar kLightHeight = 600;
const SkScalar kLightRadius = 800;

PhysicalShapeLayer::PhysicalShapeLayer(Clip clip_behavior)
    : isRect_(false), clip_behavior_(clip_behavior) {}

PhysicalShapeLayer::~PhysicalShapeLayer() = default;

void PhysicalShapeLayer::set_path(const SkPath& path) {
  path_ = path;
  isRect_ = false;
  SkRect rect;
  if (path.isRect(&rect)) {
    isRect_ = true;
    frameRRect_ = SkRRect::MakeRect(rect);
  } else if (path.isRRect(&frameRRect_)) {
    isRect_ = frameRRect_.isRect();
  } else if (path.isOval(&rect)) {
    // isRRect returns false for ovals, so we need to explicitly check isOval
    // as well.
    frameRRect_ = SkRRect::MakeOval(rect);
  } else {
    // Scenic currently doesn't provide an easy way to create shapes from
    // arbitrary paths.
    // For shapes that cannot be represented as a rounded rectangle we
    // default to use the bounding rectangle.
    // TODO(amirh): fix this once we have a way to create a Scenic shape from
    // an SkPath.
    frameRRect_ = SkRRect::MakeRect(path.getBounds());
  }
}

void PhysicalShapeLayer::Preroll(PrerollContext* context,
                                 const SkMatrix& matrix) {
  SkRect child_paint_bounds;
  PrerollChildren(context, matrix, &child_paint_bounds);

  if (elevation_ == 0) {
    set_paint_bounds(path_.getBounds());
  } else {
#if defined(OS_FUCHSIA)
    // Let the system compositor draw all shadows for us.
    set_needs_system_composite(true);
#else
    // Add some margin to the paint bounds to leave space for the shadow.
    // We fill this whole region and clip children to it so we don't need to
    // join the child paint bounds.
    // The offset is calculated as follows:

    //                   .---                           (kLightRadius)
    //                -------/                          (light)
    //                   |  /
    //                   | /
    //                   |/
    //                   |O
    //                  /|                              (kLightHeight)
    //                 / |
    //                /  |
    //               /   |
    //              /    |
    //             -------------                        (layer)
    //            /|     |
    //           / |     |                              (elevation)
    //        A /  |     |B
    // ------------------------------------------------ (canvas)
    //          ---                                     (extent of shadow)
    //
    // E = lt        }           t = (r + w/2)/h
    //                } =>
    // r + w/2 = ht  }           E = (l/h)(r + w/2)
    //
    // Where: E = extent of shadow
    //        l = elevation of layer
    //        r = radius of the light source
    //        w = width of the layer
    //        h = light height
    //        t = tangent of AOB, i.e., multiplier for elevation to extent
    SkRect bounds(path_.getBounds());
    // tangent for x
    double tx = (kLightRadius * device_pixel_ratio_ + bounds.width() * 0.5) /
                kLightHeight;
    // tangent for y
    double ty = (kLightRadius * device_pixel_ratio_ + bounds.height() * 0.5) /
                kLightHeight;
    bounds.outset(elevation_ * tx, elevation_ * ty);
    set_paint_bounds(bounds);
#endif  // defined(OS_FUCHSIA)
  }
}

#if defined(OS_FUCHSIA)

void PhysicalShapeLayer::UpdateScene(SceneUpdateContext& context) {
  FML_DCHECK(needs_system_composite());

  // Retained rendering: speedup by reusing a retained entity node if possible.
  // When an entity node is reused, no paint layer is added to the frame so we
  // won't call PhysicalShapeLayer::Paint.
  LayerRasterCacheKey key(this, context.Matrix());
  if (context.HasRetainedNode(key)) {
    const scenic::EntityNode& retained_node = context.GetRetainedNode(key);
    FML_DCHECK(context.top_entity());
    FML_DCHECK(retained_node.session() == context.session());
    context.top_entity()->entity_node().AddChild(retained_node);
    return;
  }

  // If we can't find an existing retained surface, create one.
  SceneUpdateContext::Frame frame(context, frameRRect_, color_, elevation_,
                                  this);
  for (auto& layer : layers()) {
    if (layer->needs_painting()) {
      frame.AddPaintLayer(layer.get());
    }
  }

  UpdateSceneChildren(context);
}

#endif  // defined(OS_FUCHSIA)

void PhysicalShapeLayer::Paint(PaintContext& context) const {
  TRACE_EVENT0("flutter", "PhysicalShapeLayer::Paint");
  FML_DCHECK(needs_painting());

  if (elevation_ != 0) {
    DrawShadow(context.leaf_nodes_canvas, path_, shadow_color_, elevation_,
               SkColorGetA(color_) != 0xff, device_pixel_ratio_);
  }

  // Call drawPath without clip if possible for better performance.
  SkPaint paint;
  paint.setColor(color_);
  if (clip_behavior_ != Clip::antiAliasWithSaveLayer) {
    context.leaf_nodes_canvas->drawPath(path_, paint);
  }

  int saveCount = context.internal_nodes_canvas->save();
  switch (clip_behavior_) {
    case Clip::hardEdge:
      context.internal_nodes_canvas->clipPath(path_, false);
      break;
    case Clip::antiAlias:
      context.internal_nodes_canvas->clipPath(path_, true);
      break;
    case Clip::antiAliasWithSaveLayer:
      context.internal_nodes_canvas->clipPath(path_, true);
      context.internal_nodes_canvas->saveLayer(paint_bounds(), nullptr);
      break;
    case Clip::none:
      break;
  }

  if (clip_behavior_ == Clip::antiAliasWithSaveLayer) {
    // If we want to avoid the bleeding edge artifact
    // (https://github.com/flutter/flutter/issues/18057#issue-328003931)
    // using saveLayer, we have to call drawPaint instead of drawPath as
    // anti-aliased drawPath will always have such artifacts.
    context.leaf_nodes_canvas->drawPaint(paint);
  }

  PaintChildren(context);

  context.internal_nodes_canvas->restoreToCount(saveCount);
}

void PhysicalShapeLayer::DrawShadow(SkCanvas* canvas,
                                    const SkPath& path,
                                    SkColor color,
                                    float elevation,
                                    bool transparentOccluder,
                                    SkScalar dpr) {
  const SkScalar kAmbientAlpha = 0.039f;
  const SkScalar kSpotAlpha = 0.25f;

  SkShadowFlags flags = transparentOccluder
                            ? SkShadowFlags::kTransparentOccluder_ShadowFlag
                            : SkShadowFlags::kNone_ShadowFlag;
  const SkRect& bounds = path.getBounds();
  SkScalar shadow_x = (bounds.left() + bounds.right()) / 2;
  SkScalar shadow_y = bounds.top() - 600.0f;
  SkColor inAmbient = SkColorSetA(color, kAmbientAlpha * SkColorGetA(color));
  SkColor inSpot = SkColorSetA(color, kSpotAlpha * SkColorGetA(color));
  SkColor ambientColor, spotColor;
  SkShadowUtils::ComputeTonalColors(inAmbient, inSpot, &ambientColor,
                                    &spotColor);
  SkShadowUtils::DrawShadow(
      canvas, path, SkPoint3::Make(0, 0, dpr * elevation),
      SkPoint3::Make(shadow_x, shadow_y, dpr * kLightHeight),
      dpr * kLightRadius, ambientColor, spotColor, flags);
}

}  // namespace flow
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS dr43 (1.18.42); FILE MERGED 2005/12/02 14:53:58 nn 1.18.42.1: #i56873# check if AutoStyles exists<commit_after><|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "Test.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkMathPriv.h"
#include "SkRandom.h"
#include "SkUnPreMultiply.h"

static void test_premul(skiatest::Reporter* reporter) {
    for (int a = 0; a <= 255; a++) {
        for (int x = 0; x <= 255; x++) {
            SkColor c0 = SkColorSetARGB(a, x, x, x);
            SkPMColor p0 = SkPreMultiplyColor(c0);

            SkColor c1 = SkUnPreMultiply::PMColorToColor(p0);
            SkPMColor p1 = SkPreMultiplyColor(c1);

            // we can't promise that c0 == c1, since c0 -> p0 is a many to one
            // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1
            REPORTER_ASSERT(reporter, p0 == p1);

            {
                int ax = SkMulDiv255Ceiling(x, a);
                REPORTER_ASSERT(reporter, ax <= a);
            }
        }
    }
}

/**
  This test fails: SkFourByteInterp does *not* preserve opaque destinations.
  SkAlpha255To256 implemented as (alpha + 1) is faster than
  (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out.
*/
/*
static void test_interp(skiatest::Reporter* reporter) {
    SkRandom r;

    U8CPU a0 = 0;
    U8CPU a255 = 255;
    for (int i = 0; i < 200; i++) {
        SkColor colorSrc = r.nextU();
        SkColor colorDst = r.nextU();
        SkPMColor src = SkPreMultiplyColor(colorSrc);
        SkPMColor dst = SkPreMultiplyColor(colorDst);

        REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst);
        REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src);
    }
}
*/

static void test_fast_interp(skiatest::Reporter* reporter) {
    SkRandom r;

    U8CPU a0 = 0;
    U8CPU a255 = 255;
    for (int i = 0; i < 200; i++) {
        SkColor colorSrc = r.nextU();
        SkColor colorDst = r.nextU();
        SkPMColor src = SkPreMultiplyColor(colorSrc);
        SkPMColor dst = SkPreMultiplyColor(colorDst);

        REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst);
        REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src);
    }
}

static void TestColor(skiatest::Reporter* reporter) {
    test_premul(reporter);
    //test_interp(reporter);
    test_fast_interp(reporter);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("Color", ColorTestClass, TestColor)
<commit_msg>add experimental test for different 8888->565 blends (disabled)<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "Test.h"
#include "SkColor.h"
#include "SkColorPriv.h"
#include "SkMathPriv.h"
#include "SkRandom.h"
#include "SkUnPreMultiply.h"

#define GetPackedR16As32(packed)    (SkGetPackedR16(dc) << (8 - SK_R16_BITS))
#define GetPackedG16As32(packed)    (SkGetPackedG16(dc) << (8 - SK_G16_BITS))
#define GetPackedB16As32(packed)    (SkGetPackedB16(dc) << (8 - SK_B16_BITS))

static bool S32A_D565_Blend_0(SkPMColor sc, uint16_t dc, U8CPU alpha) {
    unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
    unsigned dr = SkMulS16(SkPacked32ToR16(sc), alpha) + SkMulS16(SkGetPackedR16(dc), dst_scale);
    unsigned dg = SkMulS16(SkPacked32ToG16(sc), alpha) + SkMulS16(SkGetPackedG16(dc), dst_scale);

    unsigned rr = SkDiv255Round(dr);
    unsigned rg = SkDiv255Round(dg);

    if (rr <= 31 && rg <= 63) {
        return true;
    }
    return false;
}

static bool S32A_D565_Blend_01(SkPMColor sc, uint16_t dc, U8CPU alpha) {
    unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
    unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(SkGetPackedR16(dc) << 3, dst_scale);
    unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(SkGetPackedG16(dc) << 2, dst_scale);

    unsigned rr = SkDiv255Round(dr) >> 3;
    unsigned rg = SkDiv255Round(dg) >> 2;

    if (rr <= 31 && rg <= 63) {
        return true;
    }
    return false;
}

static bool S32A_D565_Blend_02(SkPMColor sc, uint16_t dc, U8CPU alpha) {
    unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
    unsigned dr = SkMulS16(SkGetPackedR32(sc), alpha) + SkMulS16(GetPackedR16As32(dc), dst_scale);
    unsigned dg = SkMulS16(SkGetPackedG32(sc), alpha) + SkMulS16(GetPackedG16As32(dc), dst_scale);
    unsigned db = SkMulS16(SkGetPackedB32(sc), alpha) + SkMulS16(GetPackedB16As32(dc), dst_scale);
    int rc = SkPack888ToRGB16(SkDiv255Round(dr),
                              SkDiv255Round(dg),
                              SkDiv255Round(db));

    unsigned rr = SkGetPackedR16(rc);
    unsigned rg = SkGetPackedG16(rc);

    if (rr <= 31 && rg <= 63) {
        return true;
    }
    return false;
}

static bool S32A_D565_Blend_1(SkPMColor sc, uint16_t dc, U8CPU alpha) {
    unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
    unsigned dr = (SkMulS16(SkGetPackedR32(sc), alpha) >> 3) + SkMulS16(SkGetPackedR16(dc), dst_scale);
    unsigned dg = (SkMulS16(SkGetPackedG32(sc), alpha) >> 2) + SkMulS16(SkGetPackedG16(dc), dst_scale);

    unsigned rr = SkDiv255Round(dr);
    unsigned rg = SkDiv255Round(dg);

    if (rr <= 31 && rg <= 63) {
        return true;
    }
    return false;
}

static int SkDiv65025Round(int x) {
    return (x + 65025/2) / 65025;
//    return x / 65025;
}
static bool S32A_D565_Blend_2(SkPMColor sc, uint16_t dc, U8CPU alpha) {
    unsigned dst_scale = 255*255 - SkGetPackedA32(sc) * alpha;
    alpha *= 255;
    unsigned dr = (SkGetPackedR32(sc) >> 3) * alpha + SkGetPackedR16(dc) * dst_scale;
    unsigned dg = (SkGetPackedG32(sc) >> 2) * alpha + SkGetPackedG16(dc) * dst_scale;

    unsigned rr = SkDiv65025Round(dr);
    unsigned rg = SkDiv65025Round(dg);

    if (rr <= 31 && rg <= 63) {
        return true;
    }
    return false;
}

static void test_565blend(skiatest::Reporter* reporter) {
    int total_failures = 0;
    for (int global_alpha = 0; global_alpha <= 255; ++global_alpha) {
        int failures = 0;
        int total = 0;
        for (int src_a = 0; src_a <= 255; ++src_a) {
            for (int src_c = 0; src_c <= src_a; ++src_c) {
                SkPMColor sc = SkPackARGB32(src_a, src_c, src_c, src_c);
                for (int dst_r = 0; dst_r <= 31; ++dst_r) {
                    for (int dst_g = 0; dst_g <= 63; ++dst_g) {
                        uint16_t dc = SkPackRGB16(dst_r, dst_g, dst_r);
                        failures += !S32A_D565_Blend_0(sc, dc, global_alpha);
                        total += 1;
                    }
                }
            }
        }
        SkDebugf("global_alpha=%d failures=%d total=%d %g\n", global_alpha, failures, total, failures * 100.0 / total);
        total_failures += failures;
    }
    SkDebugf("total failures %d\n", total_failures);
}

static void test_premul(skiatest::Reporter* reporter) {
    for (int a = 0; a <= 255; a++) {
        for (int x = 0; x <= 255; x++) {
            SkColor c0 = SkColorSetARGB(a, x, x, x);
            SkPMColor p0 = SkPreMultiplyColor(c0);

            SkColor c1 = SkUnPreMultiply::PMColorToColor(p0);
            SkPMColor p1 = SkPreMultiplyColor(c1);

            // we can't promise that c0 == c1, since c0 -> p0 is a many to one
            // function, however, we can promise that p0 -> c1 -> p1 : p0 == p1
            REPORTER_ASSERT(reporter, p0 == p1);

            {
                int ax = SkMulDiv255Ceiling(x, a);
                REPORTER_ASSERT(reporter, ax <= a);
            }
        }
    }
}

/**
  This test fails: SkFourByteInterp does *not* preserve opaque destinations.
  SkAlpha255To256 implemented as (alpha + 1) is faster than
  (alpha + (alpha >> 7)), but inaccurate, and Skia intends to phase it out.
*/
/*
static void test_interp(skiatest::Reporter* reporter) {
    SkRandom r;

    U8CPU a0 = 0;
    U8CPU a255 = 255;
    for (int i = 0; i < 200; i++) {
        SkColor colorSrc = r.nextU();
        SkColor colorDst = r.nextU();
        SkPMColor src = SkPreMultiplyColor(colorSrc);
        SkPMColor dst = SkPreMultiplyColor(colorDst);

        REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a0) == dst);
        REPORTER_ASSERT(reporter, SkFourByteInterp(src, dst, a255) == src);
    }
}
*/

static void test_fast_interp(skiatest::Reporter* reporter) {
    SkRandom r;

    U8CPU a0 = 0;
    U8CPU a255 = 255;
    for (int i = 0; i < 200; i++) {
        SkColor colorSrc = r.nextU();
        SkColor colorDst = r.nextU();
        SkPMColor src = SkPreMultiplyColor(colorSrc);
        SkPMColor dst = SkPreMultiplyColor(colorDst);

        REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a0) == dst);
        REPORTER_ASSERT(reporter, SkFastFourByteInterp(src, dst, a255) == src);
    }
}

static void TestColor(skiatest::Reporter* reporter) {
    test_premul(reporter);
    //test_interp(reporter);
    test_fast_interp(reporter);
//    test_565blend(reporter);
}

#include "TestClassDef.h"
DEFINE_TESTCLASS("Color", ColorTestClass, TestColor)
<|endoftext|>