<commit_before>#include "../include/File.h"
#include <vector>
#include <ctype.h>
#include <locale>
using namespace std;

const string tok = ";";
const string vars = "var";
const string consts = "const";
const string minitok = ",";
const string equals = "=";
const string affct = ":=";
const string plusLut = "+";
const string minusLut = "-";
const string multiplyLut = "*";
const string divideLut = "/";
const string paro = "(";
const string parf = ")";

File::File()
{
    //ctor
}

void File::setPath(string link)
{
    path = link;
}

File::~File()
{

}

void File::openParse()
{
	ifstream myfile;
	myfile.open (path.c_str());
	if (myfile.is_open())
	  {
		string ligne; //variable contenant chaque ligne lue

        //cette boucle s'arrête dès qu'une erreur de lecture survient
        while ( getline( myfile, ligne ) )
        {
            if(ligne != "")
            {
                    vector<string> array;
                stringstream ss(ligne);
                string temp;
                while (ss >> temp)
                {
                // Tant que le mot n'a pas été consommé entièrement
                    if(cleanWord(temp))
                    {
                        array.push_back(temp);
                    }
                    else
                    {
                       Dismantle(&array,&temp);
                    }
		}
                parsedFiles.push_back(array);
			}
        }
	    myfile.close();
		cleaning();
		ParsingTest();
	  }
	else
	{
		throw 0;
	}
}

vector<string> File::getContinueParsedFile()
{
	vector<string> continueParsedFile;
	for(unsigned int i=0; i<parsedFiles.size(); i++)
	{
		for(unsigned int j=0; j<parsedFiles[i].size(); j++)
		{
			continueParsedFile.push_back(parsedFiles[i][j]);
		}
	}
	return continueParsedFile;
}

vector<vector<string> > File::getParsedFiles()
{
	return parsedFiles;
}

void File::ParsingTest()
{
	for (unsigned int i = 0;i<parsedFiles.size();i++)
	{
		for (unsigned int j=0;j<parsedFiles[i].size();j++)
		{
			if (parsedFiles[i][j] != "")
				cout << parsedFiles[i][j] << endl;
			else
				cout << "NULL" << endl;
		}
	}
}

void File::cleaning()
{
	for (unsigned int i = 0;i<parsedFiles.size();i++)
	{
		for (unsigned int j=0;j<parsedFiles[i].size();j++)
		{
			if (parsedFiles[i][j] == "")
			parsedFiles[i].erase(parsedFiles[i].begin()+j);
		}
	}
}

void File::Dismantle(vector<string>* array,string* temp)
{
	if((*temp).find(affct)!=string::npos)
	{
		size_t found = (*temp).find(affct);
		if((*temp).substr(0,found) != "" && (*temp).substr(0,found)!=affct)
		{
			(*array).push_back((*temp).substr(0,found));
		}
		(*array).push_back(affct);
		string remaining;
		remaining = (*temp).substr(found+2);
		if (remaining != "")
		{
			Dismantle(array,&remaining);
		}
	}
	else
	{
		size_t found = (*temp).find_first_of("+-*/=(),;");
		if (found != std::string::npos)
		{
			string flush = "";
			for(size_t found = 0;found<(*temp).size();found++)
			{
				if(!isalpha((*temp)[found])&&!isdigit((*temp)[found]))
				{
					if(flush!="")
					{
						(*array).push_back(flush);
					}
					flush ="";
					(*array).push_back(string(1,(*temp)[found]));
				}
				else
				{
					flush +=(*temp)[found];
				}
			}
			// On flush ce qui reste
			(*array).push_back(flush);
		}
		else
		{
			 (*array).push_back((*temp));
		}
	}
}

bool File::cleanWord(string tested)
{
    if (tested.find_first_of("+-*/=(),;") != string::npos || tested.find(affct) != string::npos )
    {
        return false;
    }
    return true;
}

<commit_msg>file.cpp no test<commit_after>#include "../include/File.h"
#include <vector>
#include <ctype.h>
#include <locale>
using namespace std;

const string tok = ";";
const string vars = "var";
const string consts = "const";
const string minitok = ",";
const string equals = "=";
const string affct = ":=";
const string plusLut = "+";
const string minusLut = "-";
const string multiplyLut = "*";
const string divideLut = "/";
const string paro = "(";
const string parf = ")";

File::File()
{
    //ctor
}

void File::setPath(string link)
{
    path = link;
}

File::~File()
{

}

void File::openParse()
{
	ifstream myfile;
	myfile.open (path.c_str());
	if (myfile.is_open())
	  {
		string ligne; //variable contenant chaque ligne lue

        //cette boucle s'arrête dès qu'une erreur de lecture survient
        while ( getline( myfile, ligne ) )
        {
            if(ligne != "")
            {
                    vector<string> array;
                stringstream ss(ligne);
                string temp;
                while (ss >> temp)
                {
                // Tant que le mot n'a pas été consommé entièrement
                    if(cleanWord(temp))
                    {
                        array.push_back(temp);
                    }
                    else
                    {
                       Dismantle(&array,&temp);
                    }
		}
                parsedFiles.push_back(array);
			}
        }
	    myfile.close();
		cleaning();
		// FOR TEST PURPOSE ParsingTest();
	  }
	else
	{
		throw 0;
	}
}

vector<string> File::getContinueParsedFile()
{
	vector<string> continueParsedFile;
	for(unsigned int i=0; i<parsedFiles.size(); i++)
	{
		for(unsigned int j=0; j<parsedFiles[i].size(); j++)
		{
			continueParsedFile.push_back(parsedFiles[i][j]);
		}
	}
	return continueParsedFile;
}

vector<vector<string> > File::getParsedFiles()
{
	return parsedFiles;
}

void File::ParsingTest()
{
	for (unsigned int i = 0;i<parsedFiles.size();i++)
	{
		for (unsigned int j=0;j<parsedFiles[i].size();j++)
		{
			if (parsedFiles[i][j] != "")
				cout << parsedFiles[i][j] << endl;
			else
				cout << "NULL" << endl;
		}
	}
}

void File::cleaning()
{
	for (unsigned int i = 0;i<parsedFiles.size();i++)
	{
		for (unsigned int j=0;j<parsedFiles[i].size();j++)
		{
			if (parsedFiles[i][j] == "")
			parsedFiles[i].erase(parsedFiles[i].begin()+j);
		}
	}
}

void File::Dismantle(vector<string>* array,string* temp)
{
	if((*temp).find(affct)!=string::npos)
	{
		size_t found = (*temp).find(affct);
		if((*temp).substr(0,found) != "" && (*temp).substr(0,found)!=affct)
		{
			(*array).push_back((*temp).substr(0,found));
		}
		(*array).push_back(affct);
		string remaining;
		remaining = (*temp).substr(found+2);
		if (remaining != "")
		{
			Dismantle(array,&remaining);
		}
	}
	else
	{
		size_t found = (*temp).find_first_of("+-*/=(),;");
		if (found != std::string::npos)
		{
			string flush = "";
			for(size_t found = 0;found<(*temp).size();found++)
			{
				if(!isalpha((*temp)[found])&&!isdigit((*temp)[found]))
				{
					if(flush!="")
					{
						(*array).push_back(flush);
					}
					flush ="";
					(*array).push_back(string(1,(*temp)[found]));
				}
				else
				{
					flush +=(*temp)[found];
				}
			}
			// On flush ce qui reste
			(*array).push_back(flush);
		}
		else
		{
			 (*array).push_back((*temp));
		}
	}
}

bool File::cleanWord(string tested)
{
    if (tested.find_first_of("+-*/=(),;") != string::npos || tested.find(affct) != string::npos )
    {
        return false;
    }
    return true;
}

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @file lnav_util.cc
 *
 * Dumping ground for useful functions with no other home.
 */

#include "config.h"

#include <stdio.h>
#include <ctype.h>

#include "lnav_util.hh"
#include "base/opt_util.hh"
#include "base/result.h"
#include "ansi_scrubber.hh"
#include "fmt/format.h"

using namespace std;

std::string time_ago(time_t last_time, bool convert_local)
{
    time_t      delta, current_time = time(nullptr);
    const char *fmt;
    char        buffer[64];
    int         amount;

    if (convert_local) {
        current_time = convert_log_time_to_local(current_time);
    }

    delta = current_time - last_time;
    if (delta < 0) {
        return "in the future";
    }
    else if (delta < 60) {
        return "just now";
    }
    else if (delta < (60 * 2)) {
        return "one minute ago";
    }
    else if (delta < (60 * 60)) {
        fmt    = "%d minutes ago";
        amount = delta / 60;
    }
    else if (delta < (2 * 60 * 60)) {
        return "one hour ago";
    }
    else if (delta < (24 * 60 * 60)) {
        fmt    = "%d hours ago";
        amount = delta / (60 * 60);
    }
    else if (delta < (2 * 24 * 60 * 60)) {
        return "one day ago";
    }
    else if (delta < (365 * 24 * 60 * 60)) {
        fmt    = "%d days ago";
        amount = delta / (24 * 60 * 60);
    }
    else if (delta < (2 * 365 * 24 * 60 * 60)) {
        return "over a year ago";
    }
    else {
        fmt = "over %d years ago";
        amount = delta / (365 * 24 * 60 * 60);
    }

    snprintf(buffer, sizeof(buffer), fmt, amount);

    return std::string(buffer);
}

std::string precise_time_ago(const struct timeval &tv, bool convert_local)
{
    struct timeval now, diff;

    gettimeofday(&now, nullptr);
    if (convert_local) {
        now.tv_sec = convert_log_time_to_local(now.tv_sec);
    }

    timersub(&now, &tv, &diff);
    if (diff.tv_sec < 0) {
        return time_ago(tv.tv_sec);
    }
    else if (diff.tv_sec <= 1) {
        return "a second ago";
    }
    else if (diff.tv_sec < (10 * 60)) {
        char buf[64];

        if (diff.tv_sec < 60) {
            snprintf(buf, sizeof(buf),
                     "%2ld seconds ago",
                     diff.tv_sec);
        }
        else {
            time_t seconds = diff.tv_sec % 60;
            time_t minutes = diff.tv_sec / 60;

            snprintf(buf, sizeof(buf),
                     "%2ld minute%s and %2ld second%s ago",
                     minutes,
                     minutes > 1 ? "s" : "",
                     seconds,
                     seconds == 1 ? "" : "s");
        }

        return string(buf);
    }
    else {
        return time_ago(tv.tv_sec, convert_local);
    }
}

bool change_to_parent_dir()
{
    bool retval = false;
    char cwd[3] = "";

    if (getcwd(cwd, sizeof(cwd)) == nullptr) {
        /* perror("getcwd"); */
    }
    if (strcmp(cwd, "/") != 0) {
        if (chdir("..") == -1) {
            perror("chdir('..')");
        }
        else {
            retval = true;
        }
    }

    return retval;
}

template<typename T>
size_t strtonum(T &num_out, const char *string, size_t len)
{
    size_t retval = 0;
    T sign = 1;

    num_out = 0;

    for (; retval < len && isspace(string[retval]); retval++);
    for (; retval < len && string[retval] == '-'; retval++) {
        sign *= -1;
    }
    for (; retval < len && string[retval] == '+'; retval++);
    for (; retval < len && isdigit(string[retval]); retval++) {
        num_out *= 10;
        num_out += string[retval] - '0';
    }

    return retval;
}

template
size_t strtonum<long long>(long long &num_out, const char *string, size_t len);

template
size_t strtonum<long>(long &num_out, const char *string, size_t len);

template
size_t strtonum<int>(int &num_out, const char *string, size_t len);

string build_path(const vector<ghc::filesystem::path> &paths)
{
    string retval;

    for (const auto &path : paths) {
        if (path.empty()) {
            continue;
        }
        if (!retval.empty()) {
            retval += ":";
        }
        retval += path.string();
    }
    auto env_path = getenv_opt("PATH");
    if (env_path) {
        retval += ":" + string(*env_path);
    }
    return retval;
}

bool read_file(const ghc::filesystem::path &filename, string &out)
{
    std::ifstream sql_file(filename.string());

    if (sql_file) {
        out.assign((std::istreambuf_iterator<char>(sql_file)),
                   std::istreambuf_iterator<char>());
        return true;
    }

    return false;
}

Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
{
    auto pattern_str = pattern.string();
    char pattern_copy[pattern_str.size() + 1];
    int fd;

    strcpy(pattern_copy, pattern_str.c_str());
    if ((fd = mkstemp(pattern_copy)) == -1) {
        return Err(fmt::format("unable to create temporary file: {} -- {}",
                               pattern.string(), strerror(errno)));
    }

    return Ok(make_pair(ghc::filesystem::path(pattern_copy), fd));
}

bool is_dev_null(const struct stat &st)
{
    struct stat null_stat;

    stat("/dev/null", &null_stat);

    return st.st_dev == null_stat.st_dev &&
           st.st_ino == null_stat.st_ino;
}

bool is_dev_null(int fd)
{
    struct stat fd_stat;

    fstat(fd, &fd_stat);
    return is_dev_null(fd_stat);
}

std::string ok_prefix(std::string msg)
{
    if (msg.empty()) {
        return msg;
    }

    return std::string(ANSI_COLOR(COLOR_GREEN) "\u2714" ANSI_NORM " ") + msg;
}

std::string err_prefix(const std::string msg)
{
    if (msg.empty()) {
        return msg;
    }

    return std::string(ANSI_COLOR(COLOR_RED) "\u2718" ANSI_NORM " ") + msg;
}

Result<std::string, std::string> err_to_ok(const std::string msg)
{
    return Ok(err_prefix(msg));
}
<commit_msg>[lnav_util] fix ok/error msg rendering<commit_after>/**
 * Copyright (c) 2013, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @file lnav_util.cc
 *
 * Dumping ground for useful functions with no other home.
 */

#include "config.h"

#include <stdio.h>
#include <ctype.h>

#include "lnav_util.hh"
#include "base/opt_util.hh"
#include "base/result.h"
#include "ansi_scrubber.hh"
#include "fmt/format.h"
#include "view_curses.hh"

using namespace std;

std::string time_ago(time_t last_time, bool convert_local)
{
    time_t      delta, current_time = time(nullptr);
    const char *fmt;
    char        buffer[64];
    int         amount;

    if (convert_local) {
        current_time = convert_log_time_to_local(current_time);
    }

    delta = current_time - last_time;
    if (delta < 0) {
        return "in the future";
    }
    else if (delta < 60) {
        return "just now";
    }
    else if (delta < (60 * 2)) {
        return "one minute ago";
    }
    else if (delta < (60 * 60)) {
        fmt    = "%d minutes ago";
        amount = delta / 60;
    }
    else if (delta < (2 * 60 * 60)) {
        return "one hour ago";
    }
    else if (delta < (24 * 60 * 60)) {
        fmt    = "%d hours ago";
        amount = delta / (60 * 60);
    }
    else if (delta < (2 * 24 * 60 * 60)) {
        return "one day ago";
    }
    else if (delta < (365 * 24 * 60 * 60)) {
        fmt    = "%d days ago";
        amount = delta / (24 * 60 * 60);
    }
    else if (delta < (2 * 365 * 24 * 60 * 60)) {
        return "over a year ago";
    }
    else {
        fmt = "over %d years ago";
        amount = delta / (365 * 24 * 60 * 60);
    }

    snprintf(buffer, sizeof(buffer), fmt, amount);

    return std::string(buffer);
}

std::string precise_time_ago(const struct timeval &tv, bool convert_local)
{
    struct timeval now, diff;

    gettimeofday(&now, nullptr);
    if (convert_local) {
        now.tv_sec = convert_log_time_to_local(now.tv_sec);
    }

    timersub(&now, &tv, &diff);
    if (diff.tv_sec < 0) {
        return time_ago(tv.tv_sec);
    }
    else if (diff.tv_sec <= 1) {
        return "a second ago";
    }
    else if (diff.tv_sec < (10 * 60)) {
        char buf[64];

        if (diff.tv_sec < 60) {
            snprintf(buf, sizeof(buf),
                     "%2ld seconds ago",
                     diff.tv_sec);
        }
        else {
            time_t seconds = diff.tv_sec % 60;
            time_t minutes = diff.tv_sec / 60;

            snprintf(buf, sizeof(buf),
                     "%2ld minute%s and %2ld second%s ago",
                     minutes,
                     minutes > 1 ? "s" : "",
                     seconds,
                     seconds == 1 ? "" : "s");
        }

        return string(buf);
    }
    else {
        return time_ago(tv.tv_sec, convert_local);
    }
}

bool change_to_parent_dir()
{
    bool retval = false;
    char cwd[3] = "";

    if (getcwd(cwd, sizeof(cwd)) == nullptr) {
        /* perror("getcwd"); */
    }
    if (strcmp(cwd, "/") != 0) {
        if (chdir("..") == -1) {
            perror("chdir('..')");
        }
        else {
            retval = true;
        }
    }

    return retval;
}

template<typename T>
size_t strtonum(T &num_out, const char *string, size_t len)
{
    size_t retval = 0;
    T sign = 1;

    num_out = 0;

    for (; retval < len && isspace(string[retval]); retval++);
    for (; retval < len && string[retval] == '-'; retval++) {
        sign *= -1;
    }
    for (; retval < len && string[retval] == '+'; retval++);
    for (; retval < len && isdigit(string[retval]); retval++) {
        num_out *= 10;
        num_out += string[retval] - '0';
    }

    return retval;
}

template
size_t strtonum<long long>(long long &num_out, const char *string, size_t len);

template
size_t strtonum<long>(long &num_out, const char *string, size_t len);

template
size_t strtonum<int>(int &num_out, const char *string, size_t len);

string build_path(const vector<ghc::filesystem::path> &paths)
{
    string retval;

    for (const auto &path : paths) {
        if (path.empty()) {
            continue;
        }
        if (!retval.empty()) {
            retval += ":";
        }
        retval += path.string();
    }
    auto env_path = getenv_opt("PATH");
    if (env_path) {
        retval += ":" + string(*env_path);
    }
    return retval;
}

bool read_file(const ghc::filesystem::path &filename, string &out)
{
    std::ifstream sql_file(filename.string());

    if (sql_file) {
        out.assign((std::istreambuf_iterator<char>(sql_file)),
                   std::istreambuf_iterator<char>());
        return true;
    }

    return false;
}

Result<std::pair<ghc::filesystem::path, int>, std::string>
open_temp_file(const ghc::filesystem::path &pattern)
{
    auto pattern_str = pattern.string();
    char pattern_copy[pattern_str.size() + 1];
    int fd;

    strcpy(pattern_copy, pattern_str.c_str());
    if ((fd = mkstemp(pattern_copy)) == -1) {
        return Err(fmt::format("unable to create temporary file: {} -- {}",
                               pattern.string(), strerror(errno)));
    }

    return Ok(make_pair(ghc::filesystem::path(pattern_copy), fd));
}

bool is_dev_null(const struct stat &st)
{
    struct stat null_stat;

    stat("/dev/null", &null_stat);

    return st.st_dev == null_stat.st_dev &&
           st.st_ino == null_stat.st_ino;
}

bool is_dev_null(int fd)
{
    struct stat fd_stat;

    fstat(fd, &fd_stat);
    return is_dev_null(fd_stat);
}

std::string ok_prefix(std::string msg)
{
    if (msg.empty()) {
        return msg;
    }

    return std::string(ANSI_COLOR(COLOR_GREEN) "\u2714" ANSI_NORM " ") + msg;
}

std::string err_prefix(const std::string msg)
{
    if (msg.empty()) {
        return msg;
    }

    return std::string(ANSI_COLOR(COLOR_RED) "\u2718" ANSI_NORM " ") + msg;
}

Result<std::string, std::string> err_to_ok(const std::string msg)
{
    return Ok(err_prefix(msg));
}
<|endoftext|>


<commit_before>//  A small, simple heap manager based (loosely) on the startup heap
//  based on the startup heap manager from FreeBSD.
//
//  Manages a fixed-size memory pool, supports malloc and free only.
//  No support for realloc.
//
//  Allocates chunks in multiples of four bytes, with a four byte header
//  for each chunk. The overhead of each chunk is kept low by keeping pointers
//  as two byte offsets within the heap, rather than (4 or 8 byte) pointers.

namespace {

static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER;

class mutexor {
public:
    mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); }
    ~mutexor () { pthread_mutex_unlock ( mtx_ ); }
private:
    mutexor ( const mutexor &rhs );
    mutexor & operator = ( const mutexor &rhs );
    pthread_mutex_t *mtx_;
    };

#define HEAP_SIZE   512
char heap [ HEAP_SIZE ];

typedef unsigned short heap_offset;
typedef unsigned short heap_size;

struct heap_node {
    heap_offset next_node;  // offset into heap
    heap_size   len;        // size in units of "sizeof(heap_node)"
};

static const heap_node *list_end = (heap_node *) ( &heap [ HEAP_SIZE ] );   // one past the end of the heap
static heap_node *freelist = NULL;

heap_node *node_from_offset ( const heap_offset offset ) throw()
    { return (heap_node *) ( heap + ( offset * sizeof (heap_node))); }

heap_offset offset_from_node ( const heap_node *ptr )    throw()
    { return (((char *) ptr ) - heap)  / sizeof (heap_node); }

void init_heap () throw() {
    freelist = (heap_node *) heap;
    freelist->next_node = offset_from_node ( list_end );
    freelist->len = HEAP_SIZE / sizeof (heap_node);
    }

//  How big a chunk we allocate
size_t alloc_size (size_t len) throw()
    { return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; }

bool is_fallback_ptr ( void *ptr ) throw()
    { return ptr >= heap && ptr < ( heap + HEAP_SIZE ); }

void *fallback_malloc(size_t len) throw() {
    heap_node *p, *prev;
    const size_t nelems = alloc_size ( len );
    mutexor mtx ( &heap_mutex );

    if ( NULL == freelist )
        init_heap ();

//  Walk the free list, looking for a "big enough" chunk
    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset ( p->next_node)) {

        if (p->len > nelems) {  //  chunk is larger, shorten, and return the tail
            heap_node *q;

            p->len -= nelems;
            q = p + p->len;
            q->next_node = 0;
            q->len = nelems;
            return (void *) (q + 1);
        }

        if (p->len == nelems) { // exact size match
            if (prev == 0)
                freelist = node_from_offset(p->next_node);
            else
                prev->next_node = p->next_node;
            p->next_node = 0;
            return (void *) (p + 1);
        }
    }
    return NULL;    // couldn't find a spot big enough
}

//  Return the start of the next block
heap_node *after ( struct heap_node *p ) throw() { return p + p->len; }

void fallback_free (void *ptr) throw() {
    struct heap_node *cp = ((struct heap_node *) ptr) - 1;      // retrieve the chunk
    struct heap_node *p, *prev;

    mutexor mtx ( &heap_mutex );

#ifdef DEBUG_FALLBACK_MALLOC
        std::cout << "Freeing item at " << offset_from_node ( cp ) << " of size " << cp->len << std::endl;
#endif

    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset (p->next_node)) {
#ifdef DEBUG_FALLBACK_MALLOC
        std::cout << "  p, cp, after (p), after(cp) "
            << offset_from_node ( p ) << ' '
            << offset_from_node ( cp ) << ' '
            << offset_from_node ( after ( p )) << ' '
            << offset_from_node ( after ( cp )) << std::endl;
#endif
        if ( after ( p ) == cp ) {
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Appending onto chunk at " << offset_from_node ( p ) << std::endl;
#endif
            p->len += cp->len;  // make the free heap_node larger
            return;
            }
        else if ( after ( cp ) == p ) { // there's a free heap_node right after
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Appending free chunk at " << offset_from_node ( p ) << std::endl;
#endif
            cp->len += p->len;
            if ( prev == 0 ) {
                freelist = cp;
                cp->next_node = p->next_node;
                }
            else
                prev->next_node = offset_from_node(cp);
            return;
            }
        }
//  Nothing to merge with, add it to the start of the free list
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Making new free list entry " << offset_from_node ( cp ) << std::endl;
#endif
    cp->next_node = offset_from_node ( freelist );
    freelist = cp;
}

#ifdef INSTRUMENT_FALLBACK_MALLOC
size_t print_free_list () {
    struct heap_node *p, *prev;
    heap_size total_free = 0;
    if ( NULL == freelist )
        init_heap ();

    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset (p->next_node)) {
        std::cout << ( prev == 0 ? "" : "  ")  << "Offset: " << offset_from_node ( p )
                << "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
        total_free += p->len;
        }
    std::cout << "Total Free space: " << total_free << std::endl;
    return total_free;
    }
#endif
}
<commit_msg>Added copyright header<commit_after>//===------------------------ fallback_malloc.cpp -------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
//  This file implements the a small heap for allocation of exception
//  in the situation where malloc fails.
//  http://www.codesourcery.com/public/cxx-abi/abi-eh.html (section 2.4.2)
//
//===----------------------------------------------------------------------===//

//  A small, simple heap manager based (loosely) on the startup heap
//  based on the startup heap manager from FreeBSD.
//
//  Manages a fixed-size memory pool, supports malloc and free only.
//  No support for realloc.
//
//  Allocates chunks in multiples of four bytes, with a four byte header
//  for each chunk. The overhead of each chunk is kept low by keeping pointers
//  as two byte offsets within the heap, rather than (4 or 8 byte) pointers.

namespace {

static pthread_mutex_t heap_mutex = PTHREAD_MUTEX_INITIALIZER;

class mutexor {
public:
    mutexor ( pthread_mutex_t *m ) : mtx_(m) { pthread_mutex_lock ( mtx_ ); }
    ~mutexor () { pthread_mutex_unlock ( mtx_ ); }
private:
    mutexor ( const mutexor &rhs );
    mutexor & operator = ( const mutexor &rhs );
    pthread_mutex_t *mtx_;
    };

#define HEAP_SIZE   512
char heap [ HEAP_SIZE ];

typedef unsigned short heap_offset;
typedef unsigned short heap_size;

struct heap_node {
    heap_offset next_node;  // offset into heap
    heap_size   len;        // size in units of "sizeof(heap_node)"
};

static const heap_node *list_end = (heap_node *) ( &heap [ HEAP_SIZE ] );   // one past the end of the heap
static heap_node *freelist = NULL;

heap_node *node_from_offset ( const heap_offset offset ) throw()
    { return (heap_node *) ( heap + ( offset * sizeof (heap_node))); }

heap_offset offset_from_node ( const heap_node *ptr )    throw()
    { return (((char *) ptr ) - heap)  / sizeof (heap_node); }

void init_heap () throw() {
    freelist = (heap_node *) heap;
    freelist->next_node = offset_from_node ( list_end );
    freelist->len = HEAP_SIZE / sizeof (heap_node);
    }

//  How big a chunk we allocate
size_t alloc_size (size_t len) throw()
    { return (len + sizeof(heap_node) - 1) / sizeof(heap_node) + 1; }

bool is_fallback_ptr ( void *ptr ) throw()
    { return ptr >= heap && ptr < ( heap + HEAP_SIZE ); }

void *fallback_malloc(size_t len) throw() {
    heap_node *p, *prev;
    const size_t nelems = alloc_size ( len );
    mutexor mtx ( &heap_mutex );

    if ( NULL == freelist )
        init_heap ();

//  Walk the free list, looking for a "big enough" chunk
    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset ( p->next_node)) {

        if (p->len > nelems) {  //  chunk is larger, shorten, and return the tail
            heap_node *q;

            p->len -= nelems;
            q = p + p->len;
            q->next_node = 0;
            q->len = nelems;
            return (void *) (q + 1);
        }

        if (p->len == nelems) { // exact size match
            if (prev == 0)
                freelist = node_from_offset(p->next_node);
            else
                prev->next_node = p->next_node;
            p->next_node = 0;
            return (void *) (p + 1);
        }
    }
    return NULL;    // couldn't find a spot big enough
}

//  Return the start of the next block
heap_node *after ( struct heap_node *p ) throw() { return p + p->len; }

void fallback_free (void *ptr) throw() {
    struct heap_node *cp = ((struct heap_node *) ptr) - 1;      // retrieve the chunk
    struct heap_node *p, *prev;

    mutexor mtx ( &heap_mutex );

#ifdef DEBUG_FALLBACK_MALLOC
        std::cout << "Freeing item at " << offset_from_node ( cp ) << " of size " << cp->len << std::endl;
#endif

    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset (p->next_node)) {
#ifdef DEBUG_FALLBACK_MALLOC
        std::cout << "  p, cp, after (p), after(cp) "
            << offset_from_node ( p ) << ' '
            << offset_from_node ( cp ) << ' '
            << offset_from_node ( after ( p )) << ' '
            << offset_from_node ( after ( cp )) << std::endl;
#endif
        if ( after ( p ) == cp ) {
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Appending onto chunk at " << offset_from_node ( p ) << std::endl;
#endif
            p->len += cp->len;  // make the free heap_node larger
            return;
            }
        else if ( after ( cp ) == p ) { // there's a free heap_node right after
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Appending free chunk at " << offset_from_node ( p ) << std::endl;
#endif
            cp->len += p->len;
            if ( prev == 0 ) {
                freelist = cp;
                cp->next_node = p->next_node;
                }
            else
                prev->next_node = offset_from_node(cp);
            return;
            }
        }
//  Nothing to merge with, add it to the start of the free list
#ifdef DEBUG_FALLBACK_MALLOC
            std::cout << "  Making new free list entry " << offset_from_node ( cp ) << std::endl;
#endif
    cp->next_node = offset_from_node ( freelist );
    freelist = cp;
}

#ifdef INSTRUMENT_FALLBACK_MALLOC
size_t print_free_list () {
    struct heap_node *p, *prev;
    heap_size total_free = 0;
    if ( NULL == freelist )
        init_heap ();

    for (p = freelist, prev = 0;
            p && p != list_end;     prev = p, p = node_from_offset (p->next_node)) {
        std::cout << ( prev == 0 ? "" : "  ")  << "Offset: " << offset_from_node ( p )
                << "\tsize: " << p->len << " Next: " << p->next_node << std::endl;
        total_free += p->len;
        }
    std::cout << "Total Free space: " << total_free << std::endl;
    return total_free;
    }
#endif
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <sstream>
#include "../../main/models/combination/RandomChoosingCombinedModel.h"
#include "../../main/models/combination/RandomChoosingCombinedModelExpertUpdater.h"

namespace {
class DummyModel : public Model {
  public:
    void add(RecDat*){ add_counter_++; }
    int add_counter_ = 0;
    double prediction(RecDat*){ return my_prediction_; }
    double my_prediction_ = 0.5;
    void read(istream&){ read_counter_++; }
    int read_counter_ = 0;
    void write(ostream&){ write_counter_++; }
    int write_counter_ = 0;
};
class TestRandomChoosingCombinedModel : public ::testing::Test {
  public:
    DummyModel model1, model2, model3;
    vector<RecDat*> rec_dats;
    ExperimentEnvironment experiment_environment;
    OnlineExperimentParameters experiment_parameters;
    TestRandomChoosingCombinedModel(){}
    virtual ~TestRandomChoosingCombinedModel(){}
    virtual void SetUp(){
      model1.my_prediction_ = 1;
      model2.my_prediction_ = 2;
      model3.my_prediction_ = 3;
      experiment_parameters.random_seed = 231243;
      experiment_environment.set_parameters(&experiment_parameters);
    }
    RecDat* create_rec_dat(int user, int item, double time, double score){
      RecDat* rec_dat = new RecDat;
      rec_dat -> user = user;
      rec_dat -> item = item;
      rec_dat -> time = time;
      rec_dat -> id = rec_dats.size();
      rec_dat -> category = 0;
      rec_dat -> score = score;
      rec_dats.push_back(rec_dat);
      return rec_dat;
    }
    virtual void TearDown(){
      for (vector<RecDat*>::iterator it = rec_dats.begin();it!=rec_dats.end();it++){
        delete *it;
      }
    }
};
class DummyEvaluator : public Evaluator {
  public:
    double get_score(RecDat*){ return my_score_; }
    double my_score_ = 0.5;
};
class TestRandomChoosingCombinedModelExpertUpdater : public ::testing::Test {
  public:
    DummyModel model1, model2, model3;
    vector<RecDat*> rec_dats;
    ExperimentEnvironment experiment_environment;
    OnlineExperimentParameters experiment_parameters;
    TestRandomChoosingCombinedModelExpertUpdater(){}
    virtual ~TestRandomChoosingCombinedModelExpertUpdater(){}
    virtual void SetUp(){
      model1.my_prediction_ = 1;
      model2.my_prediction_ = 2;
      model3.my_prediction_ = 3;
      experiment_parameters.random_seed = 231243;
      experiment_environment.set_parameters(&experiment_parameters);
    }
    RecDat* create_rec_dat(int user, int item, double time, double score){
      RecDat* rec_dat = new RecDat;
      rec_dat -> user = user;
      rec_dat -> item = item;
      rec_dat -> time = time;
      rec_dat -> id = rec_dats.size();
      rec_dat -> category = 0;
      rec_dat -> score = score;
      rec_dats.push_back(rec_dat);
      return rec_dat;
    }
    virtual void TearDown(){
      for (vector<RecDat*>::iterator it = rec_dats.begin();it!=rec_dats.end();it++){
        delete *it;
      }
    }
};

} //namespace

TEST_F(TestRandomChoosingCombinedModelExpertUpdater, weights){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  RandomChoosingCombinedModelExpertUpdaterParameters updater_params;
  updater_params.eta=0.1;
  updater_params.loss_type="other";
  RandomChoosingCombinedModelExpertUpdater updater(&updater_params);
  updater.set_model(&model);
  vector<Evaluator*> evaluators;
  for(int i=0;i++;i<3){ evaluators.push_back(new DummyEvaluator); }
  updater.set_evaluators(evaluators);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(updater.initialize());
  EXPECT_TRUE(model.self_test());
  EXPECT_TRUE(updater.self_test());
}

TEST_F(TestRandomChoosingCombinedModel, add){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  model.add(create_rec_dat(1,2,10.0,1));
  EXPECT_EQ(1,model1.add_counter_);
  EXPECT_EQ(1,model2.add_counter_);
  EXPECT_EQ(1,model3.add_counter_);
  model.add(create_rec_dat(2,2,10.0,1));
  EXPECT_EQ(2,model1.add_counter_);
  EXPECT_EQ(2,model2.add_counter_);
  EXPECT_EQ(2,model3.add_counter_);
  model.add(create_rec_dat(2,3,10.0,1));
  EXPECT_EQ(3,model1.add_counter_);
  EXPECT_EQ(3,model2.add_counter_);
  EXPECT_EQ(3,model3.add_counter_);
}
TEST_F(TestRandomChoosingCombinedModel, prediction_id_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //id change -> generate new model, p of model eq = 0.33
  int last_model = 0;
  int eq = 0;
  int all = 1000;
  for(int i=0;i<all;i++){
    int pred = model.prediction(create_rec_dat(2,3,10.0,1));
    if(pred==last_model) eq++;
    last_model = pred;
  }
  EXPECT_NEAR(all/3,eq,25);
}

TEST_F(TestRandomChoosingCombinedModel, prediction_user_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //user change -> generate new model, p of model eq = 0.33
  int last_model = 0;
  int eq = 0;
  int all = 1000;
  RecDat* rec_dat = create_rec_dat(2,3,10.0,1);
  for(int i=0;i<all;i++){
    rec_dat->user = i;
    int pred = model.prediction(rec_dat);
    if(pred==last_model) eq++;
    last_model = pred;
  }
  EXPECT_NEAR(all/3,eq,25);
}

TEST_F(TestRandomChoosingCombinedModel, prediction_item_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //item change -> do not generate new model
  int last_model = 0;
  int eq = 0;
  int all = 10;
  for(int j=0;j<10;j++){
    RecDat* rec_dat = create_rec_dat(2,3,10.0,1);
    for(int i=0;i<all;i++){
      rec_dat->item = i;
      int pred = model.prediction(rec_dat);
      if(pred==last_model) eq++;
      last_model = pred;
    }
    EXPECT_EQ(all-1,eq);
    eq = 0;
    last_model = 0;
  }
}

TEST_F(TestRandomChoosingCombinedModel, prediction_distribution){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  int all = 10000;
  vector<int> experienced_distribution(3);
  //distribution: 0.1 0.7 0.2
  vector<double> expected_distribution = {0.1,0.7,0.2};
  model.distribution_ = expected_distribution;
  //id change -> generate new model
  for(int i=0;i<all;i++){
    uint pred = model.prediction(create_rec_dat(2,3,10.0,1))-1;
    ASSERT_LT(pred,3);
    experienced_distribution[pred]++;
  }
  for(int i=0;i<expected_distribution.size();i++){
    EXPECT_NEAR(expected_distribution[i], (double)experienced_distribution[i]/all,0.05);
  }

  experienced_distribution.clear();
  experienced_distribution.resize(3,0);
  //distribution: 0.3 0.3 0.1 (->0.3 0.3 0.4)
  model.distribution_ = {0.3,0.3,0.1};
  expected_distribution = {0.3,0.3,0.4};
  //id change -> generate new model

  for(int i=0;i<all;i++){
    uint pred = model.prediction(create_rec_dat(2,3,10.0,1))-1;
    ASSERT_LT(pred,3);
    experienced_distribution[pred]++;
  }
  for(int i=0;i<expected_distribution.size();i++){
    EXPECT_NEAR(expected_distribution[i], (double)experienced_distribution[i]/all,0.05);
  }

}
TEST_F(TestRandomChoosingCombinedModel, read_write){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  stringstream ss;
  model.write(ss);
  EXPECT_EQ(1,model1.write_counter_);
  EXPECT_EQ(1,model2.write_counter_);
  EXPECT_EQ(1,model3.write_counter_);
  model.read(ss);
  EXPECT_EQ(1,model1.read_counter_);
  EXPECT_EQ(1,model2.read_counter_);
  EXPECT_EQ(1,model3.read_counter_);
}

int main (int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Exp: test ok, failing<commit_after>#include <gtest/gtest.h>
#include <sstream>
#include "../../main/models/combination/RandomChoosingCombinedModel.h"
#include "../../main/models/combination/RandomChoosingCombinedModelExpertUpdater.h"

namespace {
class DummyModel : public Model {
  public:
    void add(RecDat*){ add_counter_++; }
    int add_counter_ = 0;
    double prediction(RecDat*){ return my_prediction_; }
    double my_prediction_ = 0.5;
    void read(istream&){ read_counter_++; }
    int read_counter_ = 0;
    void write(ostream&){ write_counter_++; }
    int write_counter_ = 0;
};
class TestRandomChoosingCombinedModel : public ::testing::Test {
  public:
    DummyModel model1, model2, model3;
    vector<RecDat*> rec_dats;
    ExperimentEnvironment experiment_environment;
    OnlineExperimentParameters experiment_parameters;
    TestRandomChoosingCombinedModel(){}
    virtual ~TestRandomChoosingCombinedModel(){}
    virtual void SetUp(){
      model1.my_prediction_ = 1;
      model2.my_prediction_ = 2;
      model3.my_prediction_ = 3;
      experiment_parameters.random_seed = 231243;
      experiment_environment.set_parameters(&experiment_parameters);
    }
    RecDat* create_rec_dat(int user, int item, double time, double score){
      RecDat* rec_dat = new RecDat;
      rec_dat -> user = user;
      rec_dat -> item = item;
      rec_dat -> time = time;
      rec_dat -> id = rec_dats.size();
      rec_dat -> category = 0;
      rec_dat -> score = score;
      rec_dats.push_back(rec_dat);
      return rec_dat;
    }
    virtual void TearDown(){
      for (vector<RecDat*>::iterator it = rec_dats.begin();it!=rec_dats.end();it++){
        delete *it;
      }
    }
};
class DummyEvaluator : public Evaluator {
  public:
    double get_score(RecDat*){ return my_score_; }
    double my_score_ = 0.5;
};
class TestRandomChoosingCombinedModelExpertUpdater : public ::testing::Test {
  public:
    DummyModel model1, model2, model3;
    vector<RecDat*> rec_dats;
    ExperimentEnvironment experiment_environment;
    OnlineExperimentParameters experiment_parameters;
    TestRandomChoosingCombinedModelExpertUpdater(){}
    virtual ~TestRandomChoosingCombinedModelExpertUpdater(){}
    virtual void SetUp(){
      model1.my_prediction_ = 1;
      model2.my_prediction_ = 2;
      model3.my_prediction_ = 3;
      experiment_parameters.random_seed = 231243;
      experiment_environment.set_parameters(&experiment_parameters);
    }
    RecDat* create_rec_dat(int user, int item, double time, double score){
      RecDat* rec_dat = new RecDat;
      rec_dat -> user = user;
      rec_dat -> item = item;
      rec_dat -> time = time;
      rec_dat -> id = rec_dats.size();
      rec_dat -> category = 0;
      rec_dat -> score = score;
      rec_dats.push_back(rec_dat);
      return rec_dat;
    }
    virtual void TearDown(){
      for (vector<RecDat*>::iterator it = rec_dats.begin();it!=rec_dats.end();it++){
        delete *it;
      }
    }
};

} //namespace

TEST_F(TestRandomChoosingCombinedModelExpertUpdater, weights){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  RandomChoosingCombinedModelExpertUpdaterParameters updater_params;
  updater_params.eta=0.1;
  updater_params.loss_type="other";
  RandomChoosingCombinedModelExpertUpdater updater(&updater_params);
  updater.set_model(&model);
  vector<Evaluator*> evaluators;
  for(int i=0;i<3;i++){
    DummyEvaluator* evaluator = new DummyEvaluator;
    evaluator->my_score_ = i+1;
    evaluators.push_back(evaluator);
  }
  updater.set_evaluators(evaluators);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(updater.initialize());
  EXPECT_TRUE(model.self_test());
  EXPECT_TRUE(updater.self_test());
  updater.update(create_rec_dat(1,2,10.0,1));
  updater.update(create_rec_dat(1,3,10.0,1));
  updater.update(create_rec_dat(1,4,10.0,1));
  updater.update(create_rec_dat(1,5,10.0,1));
  vector<int> predictions(4);
  for(int i=0;i<1000;i++){
    double prediction = model.prediction(create_rec_dat(1,5,10.0,1));
    EXPECT_LT(prediction,4.0);
    EXPECT_GE(prediction,0.0);
    predictions[prediction]++;
  }
  EXPECT_GT(predictions[1],predictions[2]);
  EXPECT_GT(predictions[2],predictions[3]);
  for(auto pred:predictions){ cerr << pred << " "; }
  cerr << endl;
}

TEST_F(TestRandomChoosingCombinedModel, add){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  model.add(create_rec_dat(1,2,10.0,1));
  EXPECT_EQ(1,model1.add_counter_);
  EXPECT_EQ(1,model2.add_counter_);
  EXPECT_EQ(1,model3.add_counter_);
  model.add(create_rec_dat(2,2,10.0,1));
  EXPECT_EQ(2,model1.add_counter_);
  EXPECT_EQ(2,model2.add_counter_);
  EXPECT_EQ(2,model3.add_counter_);
  model.add(create_rec_dat(2,3,10.0,1));
  EXPECT_EQ(3,model1.add_counter_);
  EXPECT_EQ(3,model2.add_counter_);
  EXPECT_EQ(3,model3.add_counter_);
}
TEST_F(TestRandomChoosingCombinedModel, prediction_id_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //id change -> generate new model, p of model eq = 0.33
  int last_model = 0;
  int eq = 0;
  int all = 1000;
  for(int i=0;i<all;i++){
    int pred = model.prediction(create_rec_dat(2,3,10.0,1));
    if(pred==last_model) eq++;
    last_model = pred;
  }
  EXPECT_NEAR(all/3,eq,25);
}

TEST_F(TestRandomChoosingCombinedModel, prediction_user_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //user change -> generate new model, p of model eq = 0.33
  int last_model = 0;
  int eq = 0;
  int all = 1000;
  RecDat* rec_dat = create_rec_dat(2,3,10.0,1);
  for(int i=0;i<all;i++){
    rec_dat->user = i;
    int pred = model.prediction(rec_dat);
    if(pred==last_model) eq++;
    last_model = pred;
  }
  EXPECT_NEAR(all/3,eq,25);
}

TEST_F(TestRandomChoosingCombinedModel, prediction_item_change){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  //initial distribution: 0.33 0.33 0.33
  //item change -> do not generate new model
  int last_model = 0;
  int eq = 0;
  int all = 10;
  for(int j=0;j<10;j++){
    RecDat* rec_dat = create_rec_dat(2,3,10.0,1);
    for(int i=0;i<all;i++){
      rec_dat->item = i;
      int pred = model.prediction(rec_dat);
      if(pred==last_model) eq++;
      last_model = pred;
    }
    EXPECT_EQ(all-1,eq);
    eq = 0;
    last_model = 0;
  }
}

TEST_F(TestRandomChoosingCombinedModel, prediction_distribution){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  int all = 10000;
  vector<int> experienced_distribution(3);
  //distribution: 0.1 0.7 0.2
  vector<double> expected_distribution = {0.1,0.7,0.2};
  model.distribution_ = expected_distribution;
  //id change -> generate new model
  for(int i=0;i<all;i++){
    uint pred = model.prediction(create_rec_dat(2,3,10.0,1))-1;
    ASSERT_LT(pred,3);
    experienced_distribution[pred]++;
  }
  for(int i=0;i<expected_distribution.size();i++){
    EXPECT_NEAR(expected_distribution[i], (double)experienced_distribution[i]/all,0.05);
  }

  experienced_distribution.clear();
  experienced_distribution.resize(3,0);
  //distribution: 0.3 0.3 0.1 (->0.3 0.3 0.4)
  model.distribution_ = {0.3,0.3,0.1};
  expected_distribution = {0.3,0.3,0.4};
  //id change -> generate new model

  for(int i=0;i<all;i++){
    uint pred = model.prediction(create_rec_dat(2,3,10.0,1))-1;
    ASSERT_LT(pred,3);
    experienced_distribution[pred]++;
  }
  for(uint i=0;i<expected_distribution.size();i++){
    EXPECT_NEAR(expected_distribution[i], (double)experienced_distribution[i]/all,0.05);
  }

}
TEST_F(TestRandomChoosingCombinedModel, read_write){
  RandomChoosingCombinedModelParameters params;
  RandomChoosingCombinedModel model(&params);
  model.add_model(&model1);
  model.add_model(&model2);
  model.add_model(&model3);
  model.set_experiment_environment(&experiment_environment);
  EXPECT_TRUE(model.initialize());
  EXPECT_TRUE(model.self_test());
  stringstream ss;
  model.write(ss);
  EXPECT_EQ(1,model1.write_counter_);
  EXPECT_EQ(1,model2.write_counter_);
  EXPECT_EQ(1,model3.write_counter_);
  model.read(ss);
  EXPECT_EQ(1,model1.read_counter_);
  EXPECT_EQ(1,model2.read_counter_);
  EXPECT_EQ(1,model3.read_counter_);
}

int main (int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>

#include <iostream>

#include <boost/interprocess/sync/file_lock.hpp>
#include <glog/logging.h>
#include <libconfig.h++>

#include "zmq.hpp"

#include "Utils.h"
#include "StatsHttpd.h"
#include "RedisConnection.h"

using namespace std;
using namespace libconfig;

std::shared_ptr<StatsServer> gStatsServer = nullptr;

void handler(int sig) {
  if (gStatsServer) {
    gStatsServer->stop();
  }
}

void usage() {
  fprintf(stderr, "Usage:\n\tstatshttpd -c \"statshttpd.cfg\" -l \"log_dir\"\n");
}

std::shared_ptr<StatsServer> newStatsServer(const string &chainType, const char *kafkaBrokers,
                                            const char *kafkaShareTopic, const char *kafkaCommonEventsTopic,
                                            const string &httpdHost, unsigned short httpdPort,
                                            const MysqlConnectInfo *poolDBInfo, const RedisConnectInfo *redisInfo,
                                            const uint32_t redisConcurrency, const string &redisKeyPrefix, const int redisKeyExpire,
                                            const int redisPublishPolicy, const int redisIndexPolicy,
                                            const time_t kFlushDBInterval, const string &fileLastFlushTime,
                                            const int dupShareTrackingHeight)
{
  if (chainType == "BTC") {
    return std::make_shared<StatsServerBitcoin>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
                                                httpdHost, httpdPort, poolDBInfo, redisInfo,
                                                redisConcurrency, redisKeyPrefix, redisKeyExpire,
                                                redisPublishPolicy, redisIndexPolicy,
                                                kFlushDBInterval, fileLastFlushTime, nullptr);
  }
  else if (chainType == "ETH") {
    return std::make_shared<StatsServerEth>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
                                            httpdHost, httpdPort, poolDBInfo, redisInfo,
                                            redisConcurrency, redisKeyPrefix, redisKeyExpire,
                                            redisPublishPolicy, redisIndexPolicy,
                                            kFlushDBInterval, fileLastFlushTime,
                                            std::make_shared<DuplicateShareCheckerEth>(dupShareTrackingHeight));
  }
  else if (chainType == "BTM") {
    return std::make_shared<StatsServerBytom>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
                                            httpdHost, httpdPort, poolDBInfo,
                                            kFlushDBInterval, fileLastFlushTime,
                                            std::make_shared<DuplicateShareCheckerBytom>(dupShareTrackingHeight));
  }
  else {
    LOG(FATAL) << "newStatsServer: unknown chain type " << chainType;
    return nullptr;
  }
}

int main(int argc, char **argv) {
  char *optLogDir = NULL;
  char *optConf   = NULL;
  int c;

  if (argc <= 1) {
    usage();
    return 1;
  }
  while ((c = getopt(argc, argv, "c:l:h")) != -1) {
    switch (c) {
      case 'c':
        optConf = optarg;
        break;
      case 'l':
        optLogDir = optarg;
        break;
      case 'h': default:
        usage();
        exit(0);
    }
  }

  // Initialize Google's logging library.
  google::InitGoogleLogging(argv[0]);
  FLAGS_log_dir         = string(optLogDir);
  // Log messages at a level >= this flag are automatically sent to
  // stderr in addition to log files.
  FLAGS_stderrthreshold = 3;    // 3: FATAL
  FLAGS_max_log_size    = 100;  // max log file size 100 MB
  FLAGS_logbuflevel     = -1;   // don't buffer logs
  FLAGS_stop_logging_if_full_disk = true;

  // Read the file. If there is an error, report it and exit.
  libconfig::Config cfg;
  try
  {
    cfg.readFile(optConf);
  } catch(const FileIOException &fioex) {
    std::cerr << "I/O error while reading file." << std::endl;
    return(EXIT_FAILURE);
  } catch(const ParseException &pex) {
    std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
    << " - " << pex.getError() << std::endl;
    return(EXIT_FAILURE);
  }

  // lock cfg file:
  //    you can't run more than one process with the same config file
  boost::interprocess::file_lock pidFileLock(optConf);
  if (pidFileLock.try_lock() == false) {
    LOG(FATAL) << "lock cfg file fail";
    return(EXIT_FAILURE);
  }

  signal(SIGTERM, handler);
  signal(SIGINT,  handler);

  try {
    bool useMysql = true;
    cfg.lookupValue("statshttpd.use_mysql", useMysql);
    bool useRedis = false;
    cfg.lookupValue("statshttpd.use_redis", useRedis);

    MysqlConnectInfo *poolDBInfo = nullptr;
    if (useMysql) {
      int32_t poolDBPort = 3306;
      cfg.lookupValue("pooldb.port", poolDBPort);
      poolDBInfo = new MysqlConnectInfo(cfg.lookup("pooldb.host"), poolDBPort,
                                        cfg.lookup("pooldb.username"),
                                        cfg.lookup("pooldb.password"),
                                        cfg.lookup("pooldb.dbname"));
    }

    RedisConnectInfo *redisInfo = nullptr;
    string redisKeyPrefix;
    int redisKeyExpire = 0;
    int redisPublishPolicy = 0;
    int redisIndexPolicy = 0;
    uint32_t redisConcurrency = 1;

    if (useRedis) {
      int32_t redisPort = 6379;
      cfg.lookupValue("redis.port", redisPort);
      redisInfo = new RedisConnectInfo(cfg.lookup("redis.host"), redisPort, cfg.lookup("redis.password"));

      cfg.lookupValue("redis.key_prefix", redisKeyPrefix);
      cfg.lookupValue("redis.key_expire", redisKeyExpire);
      cfg.lookupValue("redis.publish_policy", redisPublishPolicy);
      cfg.lookupValue("redis.index_policy", redisIndexPolicy);
      cfg.lookupValue("redis.concurrency", redisConcurrency);
    }

    string fileLastFlushTime;

    int32_t port = 8080;
    int32_t flushInterval = 20;
    int32_t dupShareTrackingHeight = 3;
    cfg.lookupValue("statshttpd.port", port);
    cfg.lookupValue("statshttpd.flush_db_interval", flushInterval);
    cfg.lookupValue("statshttpd.file_last_flush_time", fileLastFlushTime);
    cfg.lookupValue("dup_share_checker.tracking_height_number", dupShareTrackingHeight);
    gStatsServer = newStatsServer(cfg.lookup("statshttpd.chain_type"),
                                  cfg.lookup("kafka.brokers").c_str(),
                                  cfg.lookup("statshttpd.share_topic").c_str(),
                                  cfg.lookup("statshttpd.common_events_topic").c_str(),
                                  cfg.lookup("statshttpd.ip").c_str(),
                                  (unsigned short)port, poolDBInfo,
                                  redisInfo, redisConcurrency, redisKeyPrefix,
                                  redisKeyExpire, redisPublishPolicy, redisIndexPolicy,
                                  (time_t)flushInterval, fileLastFlushTime,
                                  dupShareTrackingHeight);
    if (gStatsServer->init()) {
    	gStatsServer->run();
    }
  }
  catch (std::exception & e) {
    LOG(FATAL) << "exception: " << e.what();
    return 1;
  }

  google::ShutdownGoogleLogging();
  return 0;
}
<commit_msg>Temporary fix compile error<commit_after>/*
 The MIT License (MIT)

 Copyright (c) [2016] [BTC.COM]

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <err.h>
#include <errno.h>
#include <unistd.h>

#include <iostream>

#include <boost/interprocess/sync/file_lock.hpp>
#include <glog/logging.h>
#include <libconfig.h++>

#include "zmq.hpp"

#include "Utils.h"
#include "StatsHttpd.h"
#include "RedisConnection.h"

using namespace std;
using namespace libconfig;

std::shared_ptr<StatsServer> gStatsServer = nullptr;

void handler(int sig) {
  if (gStatsServer) {
    gStatsServer->stop();
  }
}

void usage() {
  fprintf(stderr, "Usage:\n\tstatshttpd -c \"statshttpd.cfg\" -l \"log_dir\"\n");
}

std::shared_ptr<StatsServer> newStatsServer(const string &chainType, const char *kafkaBrokers,
                                            const char *kafkaShareTopic, const char *kafkaCommonEventsTopic,
                                            const string &httpdHost, unsigned short httpdPort,
                                            const MysqlConnectInfo *poolDBInfo, const RedisConnectInfo *redisInfo,
                                            const uint32_t redisConcurrency, const string &redisKeyPrefix, const int redisKeyExpire,
                                            const int redisPublishPolicy, const int redisIndexPolicy,
                                            const time_t kFlushDBInterval, const string &fileLastFlushTime,
                                            const int dupShareTrackingHeight)
{
  if (chainType == "BTC") {
    return std::make_shared<StatsServerBitcoin>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
                                                httpdHost, httpdPort, poolDBInfo, redisInfo,
                                                redisConcurrency, redisKeyPrefix, redisKeyExpire,
                                                redisPublishPolicy, redisIndexPolicy,
                                                kFlushDBInterval, fileLastFlushTime, nullptr);
  }
  else if (chainType == "ETH") {
    return std::make_shared<StatsServerEth>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
                                            httpdHost, httpdPort, poolDBInfo, redisInfo,
                                            redisConcurrency, redisKeyPrefix, redisKeyExpire,
                                            redisPublishPolicy, redisIndexPolicy,
                                            kFlushDBInterval, fileLastFlushTime,
                                            std::make_shared<DuplicateShareCheckerEth>(dupShareTrackingHeight));
  }
  // else if (chainType == "BTM") {
  //   return std::make_shared<StatsServerBytom>(kafkaBrokers, kafkaShareTopic, kafkaCommonEventsTopic,
  //                                           httpdHost, httpdPort, poolDBInfo,
  //                                           kFlushDBInterval, fileLastFlushTime,
  //                                           std::make_shared<DuplicateShareCheckerBytom>(dupShareTrackingHeight));
  // }
  else {
    LOG(FATAL) << "newStatsServer: unknown chain type " << chainType;
    return nullptr;
  }
}

int main(int argc, char **argv) {
  char *optLogDir = NULL;
  char *optConf   = NULL;
  int c;

  if (argc <= 1) {
    usage();
    return 1;
  }
  while ((c = getopt(argc, argv, "c:l:h")) != -1) {
    switch (c) {
      case 'c':
        optConf = optarg;
        break;
      case 'l':
        optLogDir = optarg;
        break;
      case 'h': default:
        usage();
        exit(0);
    }
  }

  // Initialize Google's logging library.
  google::InitGoogleLogging(argv[0]);
  FLAGS_log_dir         = string(optLogDir);
  // Log messages at a level >= this flag are automatically sent to
  // stderr in addition to log files.
  FLAGS_stderrthreshold = 3;    // 3: FATAL
  FLAGS_max_log_size    = 100;  // max log file size 100 MB
  FLAGS_logbuflevel     = -1;   // don't buffer logs
  FLAGS_stop_logging_if_full_disk = true;

  // Read the file. If there is an error, report it and exit.
  libconfig::Config cfg;
  try
  {
    cfg.readFile(optConf);
  } catch(const FileIOException &fioex) {
    std::cerr << "I/O error while reading file." << std::endl;
    return(EXIT_FAILURE);
  } catch(const ParseException &pex) {
    std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
    << " - " << pex.getError() << std::endl;
    return(EXIT_FAILURE);
  }

  // lock cfg file:
  //    you can't run more than one process with the same config file
  boost::interprocess::file_lock pidFileLock(optConf);
  if (pidFileLock.try_lock() == false) {
    LOG(FATAL) << "lock cfg file fail";
    return(EXIT_FAILURE);
  }

  signal(SIGTERM, handler);
  signal(SIGINT,  handler);

  try {
    bool useMysql = true;
    cfg.lookupValue("statshttpd.use_mysql", useMysql);
    bool useRedis = false;
    cfg.lookupValue("statshttpd.use_redis", useRedis);

    MysqlConnectInfo *poolDBInfo = nullptr;
    if (useMysql) {
      int32_t poolDBPort = 3306;
      cfg.lookupValue("pooldb.port", poolDBPort);
      poolDBInfo = new MysqlConnectInfo(cfg.lookup("pooldb.host"), poolDBPort,
                                        cfg.lookup("pooldb.username"),
                                        cfg.lookup("pooldb.password"),
                                        cfg.lookup("pooldb.dbname"));
    }

    RedisConnectInfo *redisInfo = nullptr;
    string redisKeyPrefix;
    int redisKeyExpire = 0;
    int redisPublishPolicy = 0;
    int redisIndexPolicy = 0;
    uint32_t redisConcurrency = 1;

    if (useRedis) {
      int32_t redisPort = 6379;
      cfg.lookupValue("redis.port", redisPort);
      redisInfo = new RedisConnectInfo(cfg.lookup("redis.host"), redisPort, cfg.lookup("redis.password"));

      cfg.lookupValue("redis.key_prefix", redisKeyPrefix);
      cfg.lookupValue("redis.key_expire", redisKeyExpire);
      cfg.lookupValue("redis.publish_policy", redisPublishPolicy);
      cfg.lookupValue("redis.index_policy", redisIndexPolicy);
      cfg.lookupValue("redis.concurrency", redisConcurrency);
    }

    string fileLastFlushTime;

    int32_t port = 8080;
    int32_t flushInterval = 20;
    int32_t dupShareTrackingHeight = 3;
    cfg.lookupValue("statshttpd.port", port);
    cfg.lookupValue("statshttpd.flush_db_interval", flushInterval);
    cfg.lookupValue("statshttpd.file_last_flush_time", fileLastFlushTime);
    cfg.lookupValue("dup_share_checker.tracking_height_number", dupShareTrackingHeight);
    gStatsServer = newStatsServer(cfg.lookup("statshttpd.chain_type"),
                                  cfg.lookup("kafka.brokers").c_str(),
                                  cfg.lookup("statshttpd.share_topic").c_str(),
                                  cfg.lookup("statshttpd.common_events_topic").c_str(),
                                  cfg.lookup("statshttpd.ip").c_str(),
                                  (unsigned short)port, poolDBInfo,
                                  redisInfo, redisConcurrency, redisKeyPrefix,
                                  redisKeyExpire, redisPublishPolicy, redisIndexPolicy,
                                  (time_t)flushInterval, fileLastFlushTime,
                                  dupShareTrackingHeight);
    if (gStatsServer->init()) {
    	gStatsServer->run();
    }
  }
  catch (std::exception & e) {
    LOG(FATAL) << "exception: " << e.what();
    return 1;
  }

  google::ShutdownGoogleLogging();
  return 0;
}
<|endoftext|>


<commit_before>
#include <gtest/gtest.h>

#include <aerial_autonomy/common/conversions.h>
#include <aerial_autonomy/controller_connectors/rpyt_relative_pose_visual_servoing_connector.h>
#include <aerial_autonomy/controllers/rpyt_based_relative_pose_controller.h>
#include <aerial_autonomy/tests/test_utils.h>
#include <aerial_autonomy/trackers/simple_tracker.h>
#include <chrono>
#include <quad_simulator_parser/quad_simulator.h>
#include <thread>

/**
* @brief Namespace for UAV Simulator Hardware
*/
using namespace quad_simulator;

using namespace test_utils;

class RPYTRelativePoseVisualConnectorTests : public ::testing::Test {
public:
  RPYTRelativePoseVisualConnectorTests()
      : goal_tolerance_position_(0.05), goal_tolerance_velocity_(0.1),
        goal_tolerance_yaw_(0.05), goal_tolerance_yaw_rate_(0.05),
        tracking_offset_transform_(
            tf::createQuaternionFromRPY(0, M_PI / 3, M_PI / 2),
            tf::Vector3(0, 0, 0)),
        thrust_gain_estimator_(0.18) {
    RPYTBasedRelativePoseControllerConfig config;
    auto velocity_relative_pose_config =
        config.mutable_velocity_based_relative_pose_controller_config();
    auto position_controller_config =
        velocity_relative_pose_config
            ->mutable_velocity_based_position_controller_config();
    position_controller_config->set_position_gain(1.0);
    position_controller_config->set_max_velocity(1.0);
    position_controller_config->set_yaw_gain(1.0);
    position_controller_config->set_max_yaw_rate(1.0);
    position_controller_config->set_yaw_i_gain(0.0);
    position_controller_config->set_position_i_gain(0.0);
    position_controller_config->set_position_saturation_value(0.0);
    position_controller_config->set_yaw_saturation_value(0.0);
    position_controller_config->mutable_position_controller_config()
        ->set_goal_yaw_tolerance(goal_tolerance_yaw_);
    auto position_tolerance =
        position_controller_config->mutable_position_controller_config()
            ->mutable_goal_position_tolerance();
    position_tolerance->set_x(goal_tolerance_position_);
    position_tolerance->set_y(goal_tolerance_position_);
    position_tolerance->set_z(goal_tolerance_position_);
    auto rpyt_velocity_controller_config =
        config.mutable_rpyt_based_velocity_controller_config();
    rpyt_velocity_controller_config->mutable_velocity_controller_config()
        ->set_goal_yaw_tolerance(goal_tolerance_yaw_);
    auto goal_velocity_tolerance =
        rpyt_velocity_controller_config->mutable_velocity_controller_config()
            ->mutable_goal_velocity_tolerance();
    goal_velocity_tolerance->set_vx(goal_tolerance_velocity_);
    goal_velocity_tolerance->set_vy(goal_tolerance_velocity_);
    goal_velocity_tolerance->set_vz(goal_tolerance_velocity_);
    tf::Transform camera_transform = tf::Transform::getIdentity();
    simple_tracker_.reset(new SimpleTracker(drone_hardware_, camera_transform));
    controller_.reset(new RPYTBasedRelativePoseController(
        config, std::chrono::milliseconds(20)));
    visual_servoing_connector_.reset(
        new RPYTRelativePoseVisualServoingConnector(
            *simple_tracker_, drone_hardware_, *controller_,
            thrust_gain_estimator_, camera_transform,
            tracking_offset_transform_));
    drone_hardware_.usePerfectTime();
  }

  static void SetUpTestCase() {
    // Configure logging
    LogConfig log_config;
    log_config.set_directory("/tmp/data");
    Log::instance().configure(log_config);
    DataStreamConfig data_config;
    data_config.set_stream_id("rpyt_relative_pose_visual_servoing_connector");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("velocity_based_position_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("rpyt_based_velocity_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("velocity_based_relative_pose_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("thrust_gain_estimator");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("tracking_vector_estimator");
    Log::instance().addDataStream(data_config);
  }

  void runUntilConvergence(const tf::Transform &tracked_pose,
                           const PositionYaw &goal_relative_pose) {
    simple_tracker_->setTargetPoseGlobalFrame(tracked_pose);
    simple_tracker_->setTrackingIsValid(true);
    tf::Transform gravity_aligned_tracked_pose =
        tracked_pose * tracking_offset_transform_;
    double roll, pitch, yaw;
    gravity_aligned_tracked_pose.getBasis().getRPY(roll, pitch, yaw);
    gravity_aligned_tracked_pose.getBasis().setRPY(0, 0, yaw);
    // Fly quadrotor which sets the altitude to 0.5
    drone_hardware_.setBatteryPercent(60);
    drone_hardware_.takeoff();
    // Set goal
    tf::Transform goal_relative_pose_tf;
    conversions::positionYawToTf(goal_relative_pose, goal_relative_pose_tf);
    visual_servoing_connector_->setGoal(goal_relative_pose);
    // Run controller until inactive
    auto runController = [&]() {
      visual_servoing_connector_->run();
      return visual_servoing_connector_->getStatus() ==
             ControllerStatus::Active;
    };
    ASSERT_FALSE(test_utils::waitUntilFalse()(
        runController, std::chrono::seconds(1), std::chrono::milliseconds(0)));
    // Check position is the goal position
    parsernode::common::quaddata sensor_data;
    drone_hardware_.getquaddata(sensor_data);
    tf::Transform quad_transform(
        tf::createQuaternionFromRPY(0, 0, sensor_data.rpydata.z),
        tf::Vector3(sensor_data.localpos.x, sensor_data.localpos.y,
                    sensor_data.localpos.z));
    ASSERT_TF_NEAR(quad_transform,
                   gravity_aligned_tracked_pose * goal_relative_pose_tf,
                   goal_tolerance_yaw_);
    ASSERT_EQ(visual_servoing_connector_->getStatus(),
              ControllerStatus::Completed);
    ASSERT_NEAR(thrust_gain_estimator_.getThrustGain(), 0.16, 1e-4);
  }

  QuadSimulator drone_hardware_;
  std::unique_ptr<RPYTBasedRelativePoseController> controller_;
  std::unique_ptr<SimpleTracker> simple_tracker_;
  std::unique_ptr<RPYTRelativePoseVisualServoingConnector>
      visual_servoing_connector_;
  double goal_tolerance_position_;
  double goal_tolerance_velocity_;
  double goal_tolerance_yaw_;
  double goal_tolerance_yaw_rate_;
  tf::Transform tracking_offset_transform_;
  ThrustGainEstimator thrust_gain_estimator_;
};

TEST_F(RPYTRelativePoseVisualConnectorTests, Constructor) {}

TEST_F(RPYTRelativePoseVisualConnectorTests, CriticalRun) {
  visual_servoing_connector_->setGoal(PositionYaw());
  // make tracking invalid:
  simple_tracker_->setTrackingIsValid(false);
  // Run connector
  visual_servoing_connector_->run();
  ASSERT_EQ(visual_servoing_connector_->getStatus(),
            ControllerStatus::Critical);
}

TEST_F(RPYTRelativePoseVisualConnectorTests, RunUntilConvergence) {
  // set tracking goal
  tf::Transform tracked_pose(tf::createQuaternionFromRPY(0, 0, -0.1),
                             tf::Vector3(2, -0.5, 0.5));
  PositionYaw goal_relative_pose(1, 0, 0, 0.5);
  runUntilConvergence(tracked_pose, goal_relative_pose);
}

TEST_F(RPYTRelativePoseVisualConnectorTests,
       RunUntilConvergenceNonZeroRollPitch) {
  // set tracking goal
  tf::Transform tracked_pose(tf::createQuaternionFromRPY(0.4, -0.6, -0.5),
                             tf::Vector3(2, -0.5, 0.5));
  PositionYaw goal_relative_pose(1, -1.5, 2, 0.5);
  runUntilConvergence(tracked_pose, goal_relative_pose);
}

TEST_F(RPYTRelativePoseVisualConnectorTests, TestViewingAngle) {
  tf::Transform object_pose_cam(tf::createQuaternionFromRPY(M_PI / 2, 0, 0),
                                tf::Vector3(1, 0, 0));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam),
              M_PI / 2, 1e-8);
  object_pose_cam.setOrigin(tf::Vector3(0, 0, 1));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam), 0,
              1e-8);
  object_pose_cam.setOrigin(tf::Vector3(0, 1, 1));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam),
              M_PI / 4, 1e-8);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Fix test<commit_after>
#include <gtest/gtest.h>

#include <aerial_autonomy/common/conversions.h>
#include <aerial_autonomy/controller_connectors/rpyt_relative_pose_visual_servoing_connector.h>
#include <aerial_autonomy/controllers/rpyt_based_relative_pose_controller.h>
#include <aerial_autonomy/tests/test_utils.h>
#include <aerial_autonomy/trackers/simple_tracker.h>
#include <chrono>
#include <quad_simulator_parser/quad_simulator.h>
#include <thread>

/**
* @brief Namespace for UAV Simulator Hardware
*/
using namespace quad_simulator;

using namespace test_utils;

class RPYTRelativePoseVisualConnectorTests : public ::testing::Test {
public:
  RPYTRelativePoseVisualConnectorTests()
      : goal_tolerance_position_(0.1), goal_tolerance_velocity_(0.1),
        goal_tolerance_yaw_(0.1), goal_tolerance_yaw_rate_(0.05),
        tracking_offset_transform_(
            tf::createQuaternionFromRPY(0, M_PI / 3, 0.2),
            tf::Vector3(0, 0, 0)),
        thrust_gain_estimator_(0.18) {
    RPYTBasedRelativePoseControllerConfig config;
    auto velocity_relative_pose_config =
        config.mutable_velocity_based_relative_pose_controller_config();
    auto position_controller_config =
        velocity_relative_pose_config
            ->mutable_velocity_based_position_controller_config();
    position_controller_config->set_position_gain(1.0);
    position_controller_config->set_max_velocity(1.0);
    position_controller_config->set_yaw_gain(1.0);
    position_controller_config->set_max_yaw_rate(1.0);
    position_controller_config->set_yaw_i_gain(0.0);
    position_controller_config->set_position_i_gain(0.0);
    position_controller_config->set_position_saturation_value(0.0);
    position_controller_config->set_yaw_saturation_value(0.0);
    position_controller_config->mutable_position_controller_config()
        ->set_goal_yaw_tolerance(goal_tolerance_yaw_);
    auto position_tolerance =
        position_controller_config->mutable_position_controller_config()
            ->mutable_goal_position_tolerance();
    position_tolerance->set_x(goal_tolerance_position_);
    position_tolerance->set_y(goal_tolerance_position_);
    position_tolerance->set_z(goal_tolerance_position_);
    auto rpyt_velocity_controller_config =
        config.mutable_rpyt_based_velocity_controller_config();
    rpyt_velocity_controller_config->mutable_velocity_controller_config()
        ->set_goal_yaw_tolerance(goal_tolerance_yaw_);
    auto goal_velocity_tolerance =
        rpyt_velocity_controller_config->mutable_velocity_controller_config()
            ->mutable_goal_velocity_tolerance();
    goal_velocity_tolerance->set_vx(goal_tolerance_velocity_);
    goal_velocity_tolerance->set_vy(goal_tolerance_velocity_);
    goal_velocity_tolerance->set_vz(goal_tolerance_velocity_);
    tf::Transform camera_transform = tf::Transform::getIdentity();
    simple_tracker_.reset(new SimpleTracker(drone_hardware_, camera_transform));
    controller_.reset(new RPYTBasedRelativePoseController(
        config, std::chrono::milliseconds(20)));
    visual_servoing_connector_.reset(
        new RPYTRelativePoseVisualServoingConnector(
            *simple_tracker_, drone_hardware_, *controller_,
            thrust_gain_estimator_, camera_transform,
            tracking_offset_transform_));
    drone_hardware_.usePerfectTime();
  }

  static void SetUpTestCase() {
    // Configure logging
    LogConfig log_config;
    log_config.set_directory("/tmp/data");
    Log::instance().configure(log_config);
    DataStreamConfig data_config;
    data_config.set_stream_id("rpyt_relative_pose_visual_servoing_connector");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("velocity_based_position_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("rpyt_based_velocity_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("velocity_based_relative_pose_controller");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("thrust_gain_estimator");
    Log::instance().addDataStream(data_config);
    data_config.set_stream_id("tracking_vector_estimator");
    Log::instance().addDataStream(data_config);
  }

  void runUntilConvergence(const tf::Transform &tracked_pose,
                           const PositionYaw &goal_relative_pose) {
    simple_tracker_->setTargetPoseGlobalFrame(tracked_pose);
    simple_tracker_->setTrackingIsValid(true);
    tf::Transform gravity_aligned_tracked_pose =
        tracked_pose * tracking_offset_transform_;
    double roll, pitch, yaw;
    gravity_aligned_tracked_pose.getBasis().getRPY(roll, pitch, yaw);
    gravity_aligned_tracked_pose.getBasis().setRPY(0, 0, yaw);
    // Fly quadrotor which sets the altitude to 0.5
    drone_hardware_.setBatteryPercent(60);
    drone_hardware_.takeoff();
    // Set goal
    tf::Transform goal_relative_pose_tf;
    conversions::positionYawToTf(goal_relative_pose, goal_relative_pose_tf);
    visual_servoing_connector_->setGoal(goal_relative_pose);
    // Run controller until inactive
    auto runController = [&]() {
      visual_servoing_connector_->run();
      return visual_servoing_connector_->getStatus() ==
             ControllerStatus::Active;
    };
    ASSERT_FALSE(test_utils::waitUntilFalse()(
        runController, std::chrono::seconds(1), std::chrono::milliseconds(0)));
    // Check position is the goal position
    parsernode::common::quaddata sensor_data;
    drone_hardware_.getquaddata(sensor_data);
    tf::Transform quad_transform(
        tf::createQuaternionFromRPY(0, 0, sensor_data.rpydata.z),
        tf::Vector3(sensor_data.localpos.x, sensor_data.localpos.y,
                    sensor_data.localpos.z));
    ASSERT_TF_NEAR(quad_transform,
                   gravity_aligned_tracked_pose * goal_relative_pose_tf,
                   goal_tolerance_yaw_);
    ASSERT_EQ(visual_servoing_connector_->getStatus(),
              ControllerStatus::Completed);
    ASSERT_NEAR(thrust_gain_estimator_.getThrustGain(), 0.16, 1e-4);
  }

  QuadSimulator drone_hardware_;
  std::unique_ptr<RPYTBasedRelativePoseController> controller_;
  std::unique_ptr<SimpleTracker> simple_tracker_;
  std::unique_ptr<RPYTRelativePoseVisualServoingConnector>
      visual_servoing_connector_;
  double goal_tolerance_position_;
  double goal_tolerance_velocity_;
  double goal_tolerance_yaw_;
  double goal_tolerance_yaw_rate_;
  tf::Transform tracking_offset_transform_;
  ThrustGainEstimator thrust_gain_estimator_;
};

TEST_F(RPYTRelativePoseVisualConnectorTests, Constructor) {}

TEST_F(RPYTRelativePoseVisualConnectorTests, CriticalRun) {
  visual_servoing_connector_->setGoal(PositionYaw());
  // make tracking invalid:
  simple_tracker_->setTrackingIsValid(false);
  // Run connector
  visual_servoing_connector_->run();
  ASSERT_EQ(visual_servoing_connector_->getStatus(),
            ControllerStatus::Critical);
}

TEST_F(RPYTRelativePoseVisualConnectorTests, RunUntilConvergence) {
  // set tracking goal
  tf::Transform tracked_pose(tf::createQuaternionFromRPY(0, 0, -0.1),
                             tf::Vector3(2, -0.5, 0.5));
  PositionYaw goal_relative_pose(1, 0, 0, 0.5);
  runUntilConvergence(tracked_pose, goal_relative_pose);
}

TEST_F(RPYTRelativePoseVisualConnectorTests,
       RunUntilConvergenceNonZeroRollPitch) {
  // set tracking goal
  tf::Transform tracked_pose(tf::createQuaternionFromRPY(0.4, -0.6, -0.5),
                             tf::Vector3(2, -0.5, 0.5));
  PositionYaw goal_relative_pose(1, -1.5, 2, 0.5);
  runUntilConvergence(tracked_pose, goal_relative_pose);
}

TEST_F(RPYTRelativePoseVisualConnectorTests, TestViewingAngle) {
  tf::Transform object_pose_cam(tf::createQuaternionFromRPY(M_PI / 2, 0, 0),
                                tf::Vector3(1, 0, 0));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam),
              M_PI / 2, 1e-8);
  object_pose_cam.setOrigin(tf::Vector3(0, 0, 1));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam), 0,
              1e-8);
  object_pose_cam.setOrigin(tf::Vector3(0, 1, 1));
  ASSERT_NEAR(visual_servoing_connector_->getViewingAngle(object_pose_cam),
              M_PI / 4, 1e-8);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>