<commit_before>/*
单词消除游戏总体介绍：
    单词消除游戏由两类参与者组成，闯关者（即游戏玩家），出题者（为游戏增加游戏中
使用单词）。游戏规则为，游戏每一轮，程序会根据该关卡难度，显示一个单词，一定时间
后单词消失。闯关者需要在相应地方输入刚刚显示并消失的单词，如果闯关者输入正确（即
闯关者输入的单词与刚刚显示的单词完全一致，包含大小写）则为通过。一关可以由一轮或
者多轮组成。
题目一
    闯关者属性要求必须含有：闯关者姓名、已闯关关卡数、闯关者经验值、闯关者等级，
若有需要可以自行添加其他属性。出题者属性要求必须含有：出题者姓名、出题者出题数
目，等级，若有需要可以自行添加其余属性。具体功能包括：

    *实现闯关者，出题者本地的注册，登录。
  *程序支持多人注册，同一时间只有一人可以登录。
  *任何角色均可查询所有闯关者，出题者，按照属性查找相应闯关者，出题者。
  *可以根据闯关者闯过关卡数，经验，等级等对闯关者排名，根据出题者出题数目，
     等级对出题者排名。

    要求：
  **采用面向对象的方式，使用类设计。
  **在设计类时请注意类的继承关系，关注闯关者，出题者的关联（闯关者与出题者有共
      同的基类）。
  **使用文件或者数据库作为存储对象，自行设计设计文件格式，或者数据库表结构。
  **在题目的要求下自行扩展功能，功能扩展适当者酌情加分。

 */

#include <iostream>
#include <vector>
#include <windows.h>
using namespace std;

class Game {
private:
    int level;
    static vector<string> wordList;//被添加的单词列表
public:
    Game(int l = 0) {level = l;}
    ~Game(){}
    static vector<string> getWordList()
    {
        return wordList;
    }
    void Display();
};
vector<string> Game::wordList = {};

void Game::Display()
{
    cout << wordList[level];
    Sleep(2000);
    cout << "                   \r";
    string answer;
    cin >> answer;
    if (wordList[level] == answer) {
        cout << "答案正确,闯关成功" << endl;
        level++;
    }
}

class TestBuilder;
class Player;
class User {
private:
    string name;
    string password;
public:
    User(const string& n, const string& p): name(n), password(p) {}
    ~User(){}
    string getName(){return name;}
    string getPassword(){return password;}
    virtual void Register(){}
    virtual void Login(){}
};

class Player: public User {
private:
    int playerLevel;
    int experience;
    int grades;
    bool isLogin;
    static vector<Player> playerList;//已注册的玩家列表
public:
    Player(const string& n, const string& p, int e = 0, int l = 0, int g = 0, bool isL = 0): User(n, p)
    {
        playerLevel = l;
        experience = e;
        grades = g;
        isLogin = isL;
    }
    ~Player(){}
    static vector<Player> getList()
    {
    	return playerList;
	}
    void Register(string n,string p);
    void Login(string n,string p);
    void SearchPlayer(string name);
    void RankPlayersByGrades();
    void RankPlayersByExperience();
};
vector<Player> Player::playerList={};
void Player::Register(string& n,string& p)
{
    Player player(n,p);
    playerList.push_back(player);
}
void Player::Login(string& n,string& p)
{
    for(int i=0;i<(int)playerList.size();i++){
        if(playerList[i].getName()==n&&playerList[i].getPassword()==p)
            cout<<"玩家登录成功"<<endl;
    }
}
void SearchPlayer(const string& name)
{

}
void Player::RankPlayersByGrades()
{

}
void Player::RankPlayersByExperience()
{

}

class TestBuilder: public User {
private:
    int problemsNumbers;
    int grades;
    bool isLogin;
    static vector<TestBuilder> testBuilderList;//已注册的玩家列表
public:
    TestBuilder(const string& n, const string& p, int pNum = 0, int g = 0, bool isL = 0): User(n, p)
    {
        problemsNumbers = pNum;
        grades = g;
        isLogin = isL;
    }
    ~TestBuilder(){}
    void Register(string n,string p);
    void Login(string n,string p);
    void SearchTestBuilder();
    void RankPlayersByGrades();
    void RankPlayersByExperience();
    void AddWord();
};
vector<TestBuilder> TestBuilder::testBuilderList={};
void TestBuilder::Register(string n,string p)
{
    TestBuilder t(n,p);
    testBuilderList.push_back(t);
}
void TestBuilder::Login(string& n,string& p)
{
    for(int i=0;i<(int)testBuilderList.size();i++){
        if(testBuilderList[i].getName()==n&&testBuilderList[i].getPassword()==p)
            cout<<"管理者登录成功"<<endl;
    }
}
void TestBuilder::SearchTestBuilder()
{

}
void TestBuilder::RankPlayersByExperience()
{

}
void TestBuilder::RankPlayersByGrades()
{

}
void TestBuilder::AddWord()
{
    string s;
    Game::getWordList().push_back(s);
}

int main()
{
    int choice = 1;
    while (choice != 0) {
        cout << "\n\n\n\n" << "              *************************" << endl;
        cout <<  "                欢 迎 进入 单 词 消 除 游 戏 系 统 ! " << endl;
        cout <<  "\n                                 1  用户注册" << endl;
        cout <<  "\n                                 2  玩家登陆" << endl;
        cout <<  "\n                                 3  出题者登陆" << endl;
        cout <<  "\n                                 4  开始游戏" << endl;
        cout <<  "\n                                 5  出题" << endl;
        cout <<  "\n                                 6  继续游戏" << endl;
        cout <<  "\n                                 7  查询" << endl;
        cout <<  "\n                                 8  排行榜" << endl;
        cout <<  "\n                                 0  退出游戏" << endl;
        cout <<  "              **************************************" << endl;
        do {
            cin >> choice;
            if (choice < 0 || choice > 8)
                cout << "输入错误，请重新输入!" << endl;
            else
                break;
        } while (1);
        switch (choice) {
        case 0:

            break;
        case 1:

            break;
        case 2:

            break;
        case 3:

            break;
        case 4:

            break;
        case 5:

            break;
        case 6:

            break;
        case 7:

            break;
        case 8:

            break;
        }

    }
    return 0;
}
<commit_msg>20170416_commited,the first version is completed roughly.<commit_after>/*
单词消除游戏总体介绍：
    单词消除游戏由两类参与者组成，闯关者（即游戏玩家），出题者（为游戏增加游戏中
使用单词）。游戏规则为，游戏每一轮，程序会根据该关卡难度，显示一个单词，一定时间
后单词消失。闯关者需要在相应地方输入刚刚显示并消失的单词，如果闯关者输入正确（即
闯关者输入的单词与刚刚显示的单词完全一致，包含大小写）则为通过。一关可以由一轮或
者多轮组成。
题目一
    闯关者属性要求必须含有：闯关者姓名、已闯关关卡数、闯关者经验值、闯关者等级，
若有需要可以自行添加其他属性。出题者属性要求必须含有：出题者姓名、出题者出题数
目，等级，若有需要可以自行添加其余属性。具体功能包括：

    *实现闯关者，出题者本地的注册，登录。
  *程序支持多人注册，同一时间只有一人可以登录。
  *任何角色均可查询所有闯关者，出题者，按照属性查找相应闯关者，出题者。
  *可以根据闯关者闯过关卡数，经验，等级等对闯关者排名，根据出题者出题数目，
     等级对出题者排名。

    要求：
  **采用面向对象的方式，使用类设计。
  **在设计类时请注意类的继承关系，关注闯关者，出题者的关联（闯关者与出题者有共
      同的基类）。
  **使用文件或者数据库作为存储对象，自行设计设计文件格式，或者数据库表结构。
  **在题目的要求下自行扩展功能，功能扩展适当者酌情加分。

 */
#include <iostream>
#include <stdlib.h>
#include <vector>
#include <string>
#include <algorithm>
#include <fstream>
#include <iomanip>
#include <windows.h>
using namespace std;

/**
 * Game.h
 */
class Game {
private:
    int level;
    static vector<string> wordList;//被添加的单词列表
public:
    Game(int l = 0) {level = l;}
    ~Game() {}
    static vector<string>& getWordList() { return wordList; }
    bool Display();
    static void InitFromFile();
};
/**
 * Game.cpp
 */
vector<string> Game::wordList = {};
bool Game::Display()
{
    cout << "This the " << level + 1 << "th level : "
         << "There are " << wordList.size() << " levels totally" << endl;
    if ((unsigned)level < wordList.size()) {
        cout << wordList[level];
        Sleep(2000);
        cout << "\r                   \r";
        string answer;
        cin >> answer;
        if (wordList[level] == answer) {
            cout << "Your answer is right." << endl;
            level++;
            return true;
        }
        else {
            cout << "Your answer is wrong." << endl;
            return false;
        }
    }
    else {
        cout << "Congratulations! You have reached the last level." << endl;
        return false;
    }
}
void Game::InitFromFile()
{
    string w;
    ifstream infile("wordList.txt");
    if (!infile) {
        cout << "File wordList.txt open failed!" << endl;
        abort();
    }
    while (!infile.eof())
    {
        infile >> w;
        wordList.push_back(w);
    }
    infile.close();
}
/**
 * User.h
 */
class User {
private:
    string name;
    string password;
public:
    User(const string& n, const string& p): name(n), password(p) {}
    ~User() {}
    string getName() {return name;}
    string getPassword() {return password;}
    virtual void Register() {}
    virtual int Login() {return false;}
};
/**
 * Player.h
 */
class Player: public User {
private:
    int playerLevel;
    int experience;
    int gainedGrades;
    static bool isLogin;
    static vector<Player> playerList;//registered player list
public:
    Player(const string& n, const string& p, int e = 0, int l = 0, int g = 0): User(n, p)
    {
        playerLevel = l;
        experience = e;
        gainedGrades = g;
    }
    ~Player() {}
    static vector<Player>& getList() {return playerList;}
    void Register();
    int Login();
    int getGrades() {return gainedGrades;}
    int getExperience() {return experience;}
    void quitLogin() {isLogin = false;}
    void addLevel() {playerLevel++;}
    void addExperience() {experience++;}
    void addGainedGrades() {gainedGrades++;}
    void SearchPlayer(string& name);
    void SearchTestBuilder(string& name);
    void RankPlayersByGrades();
    void RankPlayersByExperience();
    static void InitFromFile();
};
/**
 * TestBuilder.h
 */
class TestBuilder: public User {
private:
    int problemsNumbers;
    int testBuilderLevel;
    static bool isLogin;
    static vector<TestBuilder> testBuilderList;//registered player list
public:
    TestBuilder(const string& n, const string& p, int pNum = 0, int g = 0): User(n, p)
    {
        problemsNumbers = pNum;
        testBuilderLevel = g;
    }
    ~TestBuilder() {}
    static vector<TestBuilder>& getTestBuilderList() {return testBuilderList;}
    void Register();
    int Login();
    void quitLogin() {isLogin = false;}
    void addProblemsNumbers() {problemsNumbers++;}
    void addTestBuilderLevel() {testBuilderLevel++;}
    void SearchTestBuilder(const string& name);
    void SearchPlayer(const string& name);
    int getProNum() {return problemsNumbers;}
    void RankPlayersByProNum();
    int getTesterLevel() {return testBuilderLevel;}
    void RankPlayersByTesterLevel();
    void AddWord();
    static void InitFromFile();
};
/**
 * Player.cpp
 */
bool Player::isLogin = 0;
vector<Player> Player::playerList = {};
void Player::Register()
{
    ofstream outfile("playerList.txt", ios::out | ios::app);
    outfile << endl << this->getName() << "      " << this->getPassword();
    if (!outfile) {
        cout << "File playerList.txt open failed!" << endl;
        abort();
    }
    outfile.close();
    playerList.push_back(*this);
    cout << "Player successfully registers!" << endl;
}
int Player::Login()
{
    if (isLogin)
        return -2;
    for (int i = 0; i < (int)playerList.size(); i++)
        if (playerList[i].getName() == this->getName() && playerList[i].getPassword() == this->getPassword()) {
            cout << "Player successfully logins!" << endl;
            isLogin = true;
            return i;
        }
    cout << "Player-login failed!" << endl;
    return -1;
}
void Player::SearchPlayer(string& name)
{
    vector<Player> v = Player::getList();
    for (unsigned int i = 0; i < v.size(); i++)
        if (v[i].getName() == name) {
            cout << "It is the " << i + 1 << "th player" << endl;
            return;
        }
    cout << "It is not exited in the playerList." << endl;
}
void Player::SearchTestBuilder(string& name)
{
    vector<TestBuilder> v = TestBuilder::getTestBuilderList();
    for (unsigned int i = 0; i < v.size(); i++)
        if (v[i].getName() == name) {
            cout << "It is the " << i + 1 << "th tester" << endl;
            return;
        }
    cout << "It is not exited in the testBuilderList." << endl;
}
bool sortByGrades(Player a, Player b)
{
    return a.getGrades() > b.getGrades();
}
void Player::RankPlayersByGrades()
{
    vector<Player> v = Player::getList();
    sort(v.begin(), v.end(), sortByGrades);
    for (unsigned int i = 0; i < v.size(); i++)
        cout << i + 1 << "th   " << v[i].getName()
             << " with gainedGrades is: " << v[i].getGrades() << endl;
}
bool sortByExperience(Player a, Player b)
{
    return a.getExperience() > b.getExperience();
}
void Player::RankPlayersByExperience()
{
    vector<Player> v = Player::getList();
    sort(v.begin(), v.end(), sortByGrades);
    for (unsigned int i = 0; i < v.size(); i++)
        cout << i << "th   " << v[i].getName()
             << " with experience is: " << v[i].getExperience() << endl;
}
void Player::InitFromFile()
{
    string n, s;
    ifstream infile("playerList.txt");
    if (!infile) {
        cout << "File playerList.txt open failed!" << endl;
        abort();
    }
    while (!infile.eof())
    {
        infile >> n;
        infile >> s;
        Player player(n, s);
        playerList.push_back(player);
    }
    infile.close();
}
/**
 * TestBuilder.cpp
 */
vector<TestBuilder> TestBuilder::testBuilderList = {};
bool TestBuilder::isLogin = 0;
void TestBuilder::Register()
{
    ofstream outfile("testerList.txt", ios::out | ios::app);
    outfile << endl << this->getName() << "      " << this->getPassword();
    if (!outfile) {
        cout << "File testerList.txt open failed!" << endl;
        abort();
    }
    outfile.close();
    testBuilderList.push_back(*this);
    cout << "Tester successfully registers!" << endl;
}
int TestBuilder::Login()
{
    if (isLogin)
        return -2;
    for (int i = 0; i < (int)testBuilderList.size(); i++)
        if (testBuilderList[i].getName() == this->getName() && testBuilderList[i].getPassword() == this->getPassword()) {
            cout << "Tester successfully logins!" << endl;
            isLogin = true;
            return i;
        }
    cout << "Tester-login failed!" << endl;
    return -1;
}
void TestBuilder::SearchTestBuilder(const string& name)
{
    vector<TestBuilder> v = TestBuilder::getTestBuilderList();
    for (unsigned int i = 0; i < v.size(); i++)
        if (v[i].getName() == name) {
            cout << "It is the " << i + 1 << "th tester" << endl;
            return;
        }
    cout << "It is not exited in the testBuilderList." << endl;
}
void TestBuilder::SearchPlayer(const string& name)
{
    vector<Player> v = Player::getList();
    for (unsigned int i = 0; i < v.size(); i++)
        if (v[i].getName() == name) {
            cout << "It is the " << i + 1 << "th player" << endl;
            return;
        }
    cout << "It is not exited in the playerList." << endl;
}
bool sortByProNum(TestBuilder a, TestBuilder b)
{
    return a.getProNum() > b.getProNum();
}
void TestBuilder::RankPlayersByProNum()
{
    vector<TestBuilder> v = TestBuilder::getTestBuilderList();
    sort(v.begin(), v.end(), sortByProNum);
    for (unsigned int i = 0; i < v.size(); i++)
        cout << i + 1 << "th   " << v[i].getName()
             << " with problemsNumbers is: " << v[i].getProNum() << endl;
}
bool sortByLevel(TestBuilder a, TestBuilder b)
{
    return a.getTesterLevel() > b.getTesterLevel();
}
void TestBuilder::RankPlayersByTesterLevel()
{
    vector<TestBuilder> v = TestBuilder::getTestBuilderList();
    sort(v.begin(), v.end(), sortByLevel);
    for (unsigned int i = 0; i < v.size(); i++)
        cout << i + 1 << "th   " << v[i].getName()
             << " with testBuilderLevel is: " << v[i].getTesterLevel() << endl;
}
void TestBuilder::AddWord()
{
    string s;
    cout << "Please input newly added word: ";
    cin >> s;
    Game::getWordList().push_back(s);
}
void TestBuilder::InitFromFile()
{
    string n, s;
    ifstream infile("testerList.txt");
    if (!infile) {
        cout << "File testerList.txt open failed!" << endl;
        abort();
    }
    while (!infile.eof())
    {
        infile >> n;
        infile >> s;
        TestBuilder tester(n, s);
        testBuilderList.push_back(tester);
    }
    infile.close();
}

int main()
{

    int choice = 1;
    Game::InitFromFile();
    Player::InitFromFile();
    TestBuilder::InitFromFile();
    while (choice != 0) {
        cout << "\n\n\n\n" << "              *************************" << endl;
        //cout <<  "                欢 迎 进入 单 词 消 除 游 戏 系 统 ! " << endl;
        cout <<  "               Welcome to word elemination system ! " << endl;
        cout <<  "\n                                 1  regi-用户注册" << endl;
        cout <<  "\n                                 2  plogin-玩家登陆" << endl;
        cout <<  "\n                                 3  tlogin-出题者登陆" << endl;
        cout <<  "\n                                 0  quit-退出系统" << endl;
        cout <<  "              **************************************" << endl;
        do {
            cin >> choice;
            if (choice < 0 || choice > 8)
                cout << "Input is wrong，please input again!" << endl;
            else
                break;
        } while (1);
        switch (choice) {
        case 1: {
            cout << "Please set your username:" << endl;
            string name;
            cin >> name;
            cout << "Please set your account password:" << endl;
            string password;
            cin >> password;
            if (name[0] == 't') {
                TestBuilder tester(name, password);
                tester.Register();
            }
            else {
                Player player(name, password);
                player.Register();
            }
        }
        break;
        /**
         * player operation page
         */
        case 2: {
            cout << "Please input username:";
            string name;
            cin >> name;
            cout << "Please input password:";
            string password;
            cin >> password;
            Player player(name, password);
            int pos = player.Login();
            if (pos != -2) {
                while (pos == -1) {
                    cout << "Username or password is wrong,please input them again:" << endl;
                    cout << "Please input username:";
                    string name;
                    cin >> name;
                    cout << "Please input password:";
                    string password;
                    cin >> password;
                    Player player(name, password);
                    pos = player.Login();
                }
                Player& tempPlayer = (Player&)Player::getList()[pos];
                int playerChoice = 1;
                Game game;
                while (playerChoice != 0) {
                    cout << "\n\n\n\n" << "      *************************" << endl;
                    //cout <<  "                  欢 迎 进 入 游 戏 界 面 ! " << endl;
                    cout <<  "                Welcome to playing page ! " << endl;
                    cout <<  "\n                 1  select the difficulty of the game-请选择难度游戏难度" << endl;
                    cout <<  "\n                 2  start the game -开始游戏" << endl;
                    cout <<  "\n                 3  next level -下一关" << endl;
                    //cout <<  "\n                 4  currentLevel" << endl;
                    cout <<  "\n                 4  search user -查询" << endl;
                    cout <<  "\n                 5  rank playerList -排行榜" << endl;
                    cout <<  "\n                 0  quit playing page -退出游戏界面" << endl;
                    cout <<  "              ************************" << endl;
                    do {
                        cin >> playerChoice;
                        if (playerChoice < 0 || playerChoice > 5)
                            cout << "Input is wrong，please input again!" << endl;
                        else
                            break;
                    } while (1);
                    switch (playerChoice) {
                    case 1:

                        break;
                    case 2:
                        if (game.Display()) {
                            tempPlayer.addGainedGrades();
                            tempPlayer.addLevel();
                        }
                        tempPlayer.addExperience();

                        break;
                    case 3:
                        if (game.Display()) {
                            tempPlayer.addGainedGrades();
                            tempPlayer.addLevel();
                        }
                        tempPlayer.addExperience();

                        break;
                    case 4: {
                        cout << "Please choose the way to search user:" << endl;
                        string name;
                        cin >> name;
                        tempPlayer.SearchPlayer(name);
                        tempPlayer.SearchTestBuilder(name);
                    }
                    break;
                    case 5: {
                        cout << "      Please choose the characters to rank the Player list:\n"
                             << "              a gainedGrades  \n"
                             << "              b experience    \n";
                        char rankChoice;
                        cin >> rankChoice;
                        if (rankChoice == 'a')
                            tempPlayer.RankPlayersByGrades();
                        else
                            tempPlayer.RankPlayersByExperience();
                    }
                    break;
                    }
                }
                tempPlayer.quitLogin();
            }
            else
                cout << "There is others online. Please wait for a while.";
        }
        break;
        /**
         * tester operation page
         */
        case 3: {
            cout << "Please input username:";
            string name;
            cin >> name;
            cout << "Please input password:";
            string password;
            cin >> password;
            TestBuilder tester(name, password);
            int pos = tester.Login();
            if (pos != -2) {
                while (pos == -1) {
                    cout << "Username or password is wrong,please input them again:" << endl;
                    cout << "Please input username again:";
                    string name;
                    cin >> name;
                    cout << "Please input password again:";
                    string password;
                    cin >> password;
                    TestBuilder tester(name, password);
                    pos = tester.Login();
                }
                TestBuilder& tempTester = (TestBuilder&)TestBuilder::getTestBuilderList()[pos];
                tempTester.addTestBuilderLevel();
                int testerChoice = 1;
                while (testerChoice != 0) {
                    cout << "\n\n\n\n" << "      *************************" << endl;
                    //cout <<  "                  欢 迎 进 入 管 理 界 面 ! " << endl;
                    cout <<  "                Welcome to management page ! " << endl;
                    cout <<  "\n                 1  build new tester case-出题" << endl;
                    cout <<  "\n                 2  search user -查询" << endl;
                    cout <<  "\n                 3  rank testBuilderList -排行榜" << endl;
                    cout <<  "\n                 0  quit management page -退出管理界面" << endl;
                    cout <<  "              ************************" << endl;
                    do {
                        cin >> testerChoice;
                        if (testerChoice < 0 || testerChoice > 3)
                            cout << "Input is wrong，please input again!" << endl;
                        else
                            break;
                    } while (1);
                    switch (testerChoice) {
                    case 1:
                        tempTester.AddWord();
                        tempTester.addProblemsNumbers();
                        break;
                    case 2: {
                        cout << "Please input the name to search user:" << endl;
                        string name;
                        cin >> name;
                        tempTester.SearchPlayer(name);
                        tempTester.SearchTestBuilder(name);
                    }

                    break;
                    case 3: {
                        cout << "      Please choose the characters to rank the Tester list:\n"
                             << "              a problemsNumbers  \n"
                             << "              b testBuilderLevel    \n";
                        char rankChoice;
                        cin >> rankChoice;
                        if (rankChoice == 'a')
                            tempTester.RankPlayersByProNum();
                        else
                            tempTester.RankPlayersByTesterLevel();
                    }
                    break;
                    }
                }
                tempTester.quitLogin();
            }
            else
                cout << "There is others online. Please wait for a while.";
        }
        break;
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>02bbd311-ad5c-11e7-bbf3-ac87a332f658<commit_msg>My Backup<commit_after>0375728f-ad5c-11e7-9a17-ac87a332f658<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <string>
using namespace std;

vector<uint8_t> LoadFile(const char* path)
{
    vector<uint8_t> result;

    if (path && *path)
    {
        ifstream fin(path, ifstream::binary);

        if (fin)
        {
            fin.seekg(0, ios::end);
            result.resize(fin.tellg());
            fin.seekg(0, ios::beg);
            fin.read((char*)result.data(), result.size());
            fin.close();
        }
    }

    return move(result);
}

template<typename T>
inline const T Get(const void* target)
{
    return *reinterpret_cast<const T*>(target);
}

template<typename T>
const T Read(const uint8_t*& target)
{
    const T result = Get<T>(target);
    target += sizeof(T);
    return result;
}

template<typename T>
const T EndianSwap(const T value)
{
    const uint8_t* oldBytes = reinterpret_cast<const uint8_t*>(&value);
    uint8_t newBytes[sizeof(T)];

    const size_t LastIndex = sizeof(T) - 1;
    for (size_t i = 0; i < sizeof(T); ++i)
        newBytes[i] = oldBytes[LastIndex - i];

    return *reinterpret_cast<const T*>(newBytes);
}

string ReadString(const uint8_t*& data)
{
    size_t length = EndianSwap(Get<uint16_t>(data));
    const char* block = (const char*)(data + 2);
    data += length + 2;
    return string(block, length);
}

void Dump(const vector<uint8_t>& data, ostream& out)
{
    const char* worldLabels[] = {
        "WorldX",
        "WorldY",
        "WorldXa",
        "WorldYa",
        "WorldZa"
    };

    const uint8_t* current = data.data();
    for (int i = 0; i < 5; ++i)
    {
        out << worldLabels[i]
            << " : "
            << EndianSwap(Read<int>(current))
            << '\n';
    }

    current += 5; // unknown block

    const char* positionLabels[] = {
        "x offset",
        "y offset",
        "X",
        "Y",
        "Z"
    };

    for (int i = 0; i < 5; ++i)
    {
        out << positionLabels[i]
            << " : "
            << Read<float>(current)
            << '\n';
    }

    out << "Player Direction : " << EndianSwap(Read<int>(current)) << '\n';

    int controlByte = Read<uint8_t>(current);
    out << "Control Byte : " << controlByte << '\n';

    if (controlByte)
    {
        auto playerTableLength = EndianSwap(Read<int>(current));
        out << "Player Table Length : " << playerTableLength << '\n';

        for (decltype(playerTableLength) i = 0; i < playerTableLength; ++i)
        {
            int type = Read<uint8_t>(current);
            out << "  Type : " << type << '\n';

            if (type == 0)
            {
                string name = ReadString(current);

                out << "    Name : " << name << '\n';

                // I'm probably not doing this step correctly.
                // Every string was followed by a 01, so I improvised.
                int subtype = Read<uint8_t>(current);

                if (subtype == 1)
                {
                    out << "    Value : "
                        //<< Read<int64_t>(current)
                        << EndianSwap(Read<double>(current))
                        << '\n';
                }
            }
        }
    }

    controlByte = Read<uint8_t>(current);
    out << "Control Byte : " << controlByte << '\n';

    if (controlByte)
    {
        auto playerId = EndianSwap(Read<int>(current));
        out << "  Player ID : " << playerId << '\n';

        const char* stringLabels[] = {
            "Forename",
            "Surname",
            "Legs",
            "Torso",
            "Head",
            "Top",
            "Bottoms",
            "Shoes",
            "Shoespal",
            "Bottomspal",
            "Toppal",
            "Skinpal",
            "Hair"
        };

        for (int i = 0; i < 13; ++i)
        {
            out << "  "
                << stringLabels[i]
                << " : "
                << ReadString(current) << '\n';
        }

        out << "  Grender : " << EndianSwap(Read<int>(current)) << '\n';
        out << "  Profession : " << ReadString(current) << '\n';

        const char* floatLabels[] = {
            "Hair Color R",
            "Hair Color G",
            "Hair Color B",
            "Top Color R",
            "Top Color G",
            "Top Color B",
            "Trouser Color R",
            "Trouser Color G",
            "Trouser Color B"
        };

        for (int i = 0; i < 9; ++i)
        {
            out << "  "
                << floatLabels[i]
                << " : "
                //<< Read<float>(current)
                << EndianSwap(Read<float>(current))
                << '\n';
        }

        //current += 16; // Not sure what's missing.
        for (int i = 0; i < 4; ++i)
        {
            out << "  Unknown : "
                << EndianSwap(Read<float>(current))
                << '\n';
        }
    }

    out << "Inventory Type : " << ReadString(current) << '\n';
    out << "InvExplored : " << (int)Read<uint8_t>(current) << '\n';

    int inventoryCount = EndianSwap(Read<int16_t>(current));
    out << "InvCount : " << inventoryCount << '\n';

    for (int i = 0; i < inventoryCount; ++i)
    {
        out << "  Item : " << ReadString(current) << '\n';
        out << "  Uses? : " << EndianSwap(Read<int>(current)) << '\n';
        break; // Avoid bad things for now. XD
    }
}

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        cerr << "Y U NO SPECIFY INPUT FILES\n";
        return 1;
    }

    for (int i = 1; i < argc; ++i)
    {
        vector<uint8_t> data = LoadFile(argv[i]);

        if (data.size() > 0)
        {
            Dump(data, cout);
        }
        else
        {
            cerr << "failed: " << argv[i] << '\n';
        }
    }

    return 0;
}
<commit_msg>Changed Read<T> to default to reversing byte order.<commit_after>#include <iostream>
#include <fstream>
#include <vector>
#include <cstdint>
#include <string>
using namespace std;

vector<uint8_t> LoadFile(const char* path)
{
    vector<uint8_t> result;

    if (path && *path)
    {
        ifstream fin(path, ifstream::binary);

        if (fin)
        {
            fin.seekg(0, ios::end);
            result.resize(fin.tellg());
            fin.seekg(0, ios::beg);
            fin.read((char*)result.data(), result.size());
            fin.close();
        }
    }

    return move(result);
}

template<typename T>
inline const T Get(const void* target)
{
    return *reinterpret_cast<const T*>(target);
}

template<typename T>
const T EndianSwap(const T value)
{
    const uint8_t* oldBytes = reinterpret_cast<const uint8_t*>(&value);
    uint8_t newBytes[sizeof(T)];

    const size_t LastIndex = sizeof(T) - 1;
    for (size_t i = 0; i < sizeof(T); ++i)
        newBytes[i] = oldBytes[LastIndex - i];

    return *reinterpret_cast<const T*>(newBytes);
}

template<typename T>
const T ReadRaw(const uint8_t*& target)
{
    const T result = Get<T>(target);
    target += sizeof(T);
    return result;
}

template<typename T>
const T Read(const uint8_t*& target)
{
    return EndianSwap(ReadRaw<T>(target));
}

string ReadString(const uint8_t*& data)
{
    size_t length = EndianSwap(Get<uint16_t>(data));
    const char* block = (const char*)(data + 2);
    data += length + 2;
    return string(block, length);
}

void Dump(const vector<uint8_t>& data, ostream& out)
{
    const char* worldLabels[] = {
        "WorldX",
        "WorldY",
        "WorldXa",
        "WorldYa",
        "WorldZa"
    };

    const uint8_t* current = data.data();
    for (int i = 0; i < 5; ++i)
    {
        out << worldLabels[i]
            << " : "
            << Read<int>(current)
            << '\n';
    }

    current += 5; // unknown block

    const char* positionLabels[] = {
        "x offset",
        "y offset",
        "X",
        "Y",
        "Z"
    };

    for (int i = 0; i < 5; ++i)
    {
        out << positionLabels[i]
            << " : "
            << Read<float>(current)
            << '\n';
    }

    out << "Player Direction : " << EndianSwap(Read<int>(current)) << '\n';

    int controlByte = Read<uint8_t>(current);
    out << "Control Byte : " << controlByte << '\n';

    if (controlByte)
    {
        auto playerTableLength = Read<int>(current);
        out << "Player Table Length : " << playerTableLength << '\n';

        for (decltype(playerTableLength) i = 0; i < playerTableLength; ++i)
        {
            int type = Read<uint8_t>(current);
            out << "  Type : " << type << '\n';

            if (type == 0)
            {
                string name = ReadString(current);

                out << "    Name : " << name << '\n';

                // I'm probably not doing this step correctly.
                // Every string was followed by a 01, so I improvised.
                int subtype = Read<uint8_t>(current);

                if (subtype == 1)
                {
                    out << "    Value : "
                        //<< Read<int64_t>(current)
                        << Read<double>(current)
                        << '\n';
                }
            }
        }
    }

    controlByte = Read<uint8_t>(current);
    out << "Control Byte : " << controlByte << '\n';

    if (controlByte)
    {
        auto playerId = Read<int>(current);
        out << "  Player ID : " << playerId << '\n';

        const char* stringLabels[] = {
            "Forename",
            "Surname",
            "Legs",
            "Torso",
            "Head",
            "Top",
            "Bottoms",
            "Shoes",
            "Shoespal",
            "Bottomspal",
            "Toppal",
            "Skinpal",
            "Hair"
        };

        for (int i = 0; i < 13; ++i)
        {
            out << "  "
                << stringLabels[i]
                << " : "
                << ReadString(current) << '\n';
        }

        out << "  Grender : " << Read<int>(current) << '\n';
        out << "  Profession : " << ReadString(current) << '\n';

        const char* floatLabels[] = {
            "Hair Color R",
            "Hair Color G",
            "Hair Color B",
            "Top Color R",
            "Top Color G",
            "Top Color B",
            "Trouser Color R",
            "Trouser Color G",
            "Trouser Color B"
        };

        for (int i = 0; i < 9; ++i)
        {
            out << "  "
                << floatLabels[i]
                << " : "
                //<< Read<float>(current)
                << Read<float>(current)
                << '\n';
        }

        //current += 16; // Not sure what's missing.
        for (int i = 0; i < 4; ++i)
        {
            out << "  Unknown : "
                << Read<float>(current)
                << '\n';
        }
    }

    out << "Inventory Type : " << ReadString(current) << '\n';
    out << "InvExplored : " << (int)Read<uint8_t>(current) << '\n';

    int inventoryCount = Read<int16_t>(current);
    out << "InvCount : " << inventoryCount << '\n';

    for (int i = 0; i < inventoryCount; ++i)
    {
        out << "  Item : " << ReadString(current) << '\n';
        out << "  Uses? : " << Read<int>(current) << '\n';
        break; // Avoid bad things for now. XD
    }
}

int main(int argc, char** argv)
{
    if (argc < 2)
    {
        cerr << "Y U NO SPECIFY INPUT FILES\n";
        return 1;
    }

    for (int i = 1; i < argc; ++i)
    {
        vector<uint8_t> data = LoadFile(argv[i]);

        if (data.size() > 0)
        {
            Dump(data, cout);
        }
        else
        {
            cerr << "failed: " << argv[i] << '\n';
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "problems/xor.hpp"

int main() {
    XorTest x;

    x.test(x.run());

    return 0;
}
<commit_msg>Remove empty lines<commit_after>#include "problems/xor.hpp"

int main() {
    XorTest x;
    x.test(x.run());
    return 0;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <stdint.h>
#include <time.h>

#include <array>
#include <random>

constexpr int W = 256;
constexpr int H = 382;
constexpr int SZ = W * H;

const auto monalisa = []{
  std::array<uint8_t, SZ> ret;
  FILE *f = fopen("mona_small_gray.raw", "rb");
  fread(ret.data(), SZ, 1, f);
  fclose(f);
  return ret;
}();

constexpr size_t SPEC_CNT = 300;
constexpr size_t BEST_CNT = 2;

thread_local std::mt19937 gen{0};
//thread_local std::mt19937 gen{std::random_device{}()};

template<typename T>
T random(T min, T max) {
  return std::uniform_int_distribution<T>{min, max}(gen);
}

uint8_t specimen[SPEC_CNT][SZ];
size_t best_spec[BEST_CNT][SZ];
size_t best[BEST_CNT];
int step = 0;

void dump_best() {
  if (step % 10 != 0) {
    return;
  }

  printf("   Dumping step %i\r", step); fflush(stdout);
  for (size_t i = 0; i < 1; i++) {
    char fname[256] = {0};
    sprintf(fname, "out/best_%.6i_%.2i.raw", step, i);
    FILE *f = fopen(fname, "wb");
    fwrite(specimen[best[i]], SZ, 1, f);
    fclose(f);
  }
}

void mutate() {
  for (size_t i = 0; i < SPEC_CNT; i++) {
    int x = random<int>(0, W - 2);
    int y = random<int>(0, H - 2);
    int w = random<int>(1, W - x - 1);
    int h = random<int>(1, H - y - 1);
    int c = random<uint8_t>(0, 255);

    for (int n = y; n < y + h; n++) {
      for (int m = x; m < x + w; m++) {
        specimen[i][n * W + m] =
          (specimen[i][n * W + m] + c) >> 1;
      }
    }
  }
}

double score_me(uint8_t *sp) {
  double sc = 0.0;
  for (size_t j = 0; j < H; j++) {
    for (size_t i = 0; i < W; i++) {
      double a = sp[j * W + i];
      double b = monalisa[j * W + i];
      sc += (a - b) * (a - b);
    }
  }

  return sc;
}

struct scores_st {
  double score;
  size_t idx;
};

int score_sort_fnc(const void *a, const void *b) {
  const scores_st *sa = (const scores_st*)a;
  const scores_st *sb = (const scores_st*)b;

  if (sa->score > sb->score) {
    return 1;
  }

  if (sa->score < sb->score) {
    return -1;
  }

  return 0;
}

void score() {
  static scores_st scores[SPEC_CNT];

  for (size_t i = 0; i < SPEC_CNT; i++) {
    scores[i].idx = i;
    scores[i].score = score_me(specimen[i]);
  }

  qsort(scores, SPEC_CNT, sizeof(scores_st), score_sort_fnc);

  for (size_t i = 0; i < BEST_CNT; i++) {
    best[i] = scores[i].idx;
    //printf("%i %i %f\n", i, best[i], scores[i].score);
  }
}

void cross() {
  for (size_t i = 0; i < BEST_CNT; i++) {
    memcpy(best_spec[i], specimen[best[i]], SZ);
  }

  for (size_t i = BEST_CNT; i < SPEC_CNT; i++) {
    memcpy(specimen[i], best_spec[i % BEST_CNT], SZ);
  }
}

int main(void) {
  // srand(time(NULL));

  for (;; step++) {
    //puts("Stage 1");
    mutate();

    //puts("Stage 2");
    score();

    // Dump best.
    //puts("Stage 3");
    cross();
    dump_best();

    ///break;
  }

  return 0;
}

<commit_msg>qsort -> std::sort<commit_after>#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <stdint.h>
#include <time.h>

#include <algorithm>
#include <array>
#include <random>

constexpr int W = 256;
constexpr int H = 382;
constexpr int SZ = W * H;

const auto monalisa = []{
  std::array<uint8_t, SZ> ret;
  FILE *f = fopen("mona_small_gray.raw", "rb");
  fread(ret.data(), SZ, 1, f);
  fclose(f);
  return ret;
}();

constexpr size_t SPEC_CNT = 300;
constexpr size_t BEST_CNT = 2;

thread_local std::mt19937 gen{0};
//thread_local std::mt19937 gen{std::random_device{}()};

template<typename T>
T random(T min, T max) {
  return std::uniform_int_distribution<T>{min, max}(gen);
}

uint8_t specimen[SPEC_CNT][SZ];
size_t best_spec[BEST_CNT][SZ];
size_t best[BEST_CNT];
int step = 0;

void dump_best() {
  if (step % 10 != 0) {
    return;
  }

  printf("   Dumping step %i\r", step); fflush(stdout);
  for (size_t i = 0; i < 1; i++) {
    char fname[256] = {0};
    sprintf(fname, "out/best_%.6i_%.2i.raw", step, i);
    FILE *f = fopen(fname, "wb");
    fwrite(specimen[best[i]], SZ, 1, f);
    fclose(f);
  }
}

void mutate() {
  for (size_t i = 0; i < SPEC_CNT; i++) {
    int x = random<int>(0, W - 2);
    int y = random<int>(0, H - 2);
    int w = random<int>(1, W - x - 1);
    int h = random<int>(1, H - y - 1);
    int c = random<uint8_t>(0, 255);

    for (int n = y; n < y + h; n++) {
      for (int m = x; m < x + w; m++) {
        specimen[i][n * W + m] =
          (specimen[i][n * W + m] + c) >> 1;
      }
    }
  }
}

double score_me(uint8_t *sp) {
  double sc = 0.0;
  for (size_t j = 0; j < H; j++) {
    for (size_t i = 0; i < W; i++) {
      double a = sp[j * W + i];
      double b = monalisa[j * W + i];
      sc += (a - b) * (a - b);
    }
  }

  return sc;
}

struct scores_st {
  double score;
  size_t idx;
};

void score() {
  static scores_st scores[SPEC_CNT];

  for (size_t i = 0; i < SPEC_CNT; i++) {
    scores[i].idx = i;
    scores[i].score = score_me(specimen[i]);
  }

  std::sort(std::begin(scores), std::end(scores), [](auto const& l, auto const& r){
    return l.score < r.score;
  });

  for (size_t i = 0; i < BEST_CNT; i++) {
    best[i] = scores[i].idx;
    //printf("%i %i %f\n", i, best[i], scores[i].score);
  }
}

void cross() {
  for (size_t i = 0; i < BEST_CNT; i++) {
    memcpy(best_spec[i], specimen[best[i]], SZ);
  }

  for (size_t i = BEST_CNT; i < SPEC_CNT; i++) {
    memcpy(specimen[i], best_spec[i % BEST_CNT], SZ);
  }
}

int main(void) {
  // srand(time(NULL));

  for (;; step++) {
    //puts("Stage 1");
    mutate();

    //puts("Stage 2");
    score();

    // Dump best.
    //puts("Stage 3");
    cross();
    dump_best();

    ///break;
  }

  return 0;
}

<|endoftext|>


<commit_before>#include <random>
#include "Common.h"
#include "RLP.h"
#include "PatriciaTree.h"
#include "VirtualMachine.h"
using namespace std;
using namespace eth;

std::string randomWord()
{
	static std::mt19937_64 s_eng(0);
	std::string ret(uniform_int_distribution<int>(4, 10)(s_eng), ' ');
	char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
	uniform_int_distribution<int> d(0, sizeof(n) - 2);
	for (char& c: ret)
		c = n[d(s_eng)];
	return ret;
}

int main()
{
	{
		Trie t;
		t.insert("dog", "puppy");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		assert(t.at("dog") == "puppy");
		t.insert("doe", "reindeer");
		assert(t.sha256() == hash256({{"dog", "puppy"}, {"doe", "reindeer"}}));
		assert(t.at("doe") == "reindeer");
		assert(t.at("dog") == "puppy");
		t.insert("dogglesworth", "cat");
		assert(t.sha256() == hash256({{"doe", "reindeer"}, {"dog", "puppy"}, {"dogglesworth", "cat"}}));
		assert(t.at("doe") == "reindeer");
		assert(t.at("dog") == "puppy");
		assert(t.at("dogglesworth") == "cat");
		t.remove("dogglesworth");
		t.remove("doe");
		assert(t.at("doe").empty());
		assert(t.at("dogglesworth").empty());
		assert(t.at("dog") == "puppy");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		t.insert("horse", "stallion");
		t.insert("do", "verb");
		t.insert("doge", "coin");
		assert(t.sha256() == hash256({{"dog", "puppy"}, {"horse", "stallion"}, {"do", "verb"}, {"doge", "coin"}}));
		assert(t.at("doge") == "coin");
		assert(t.at("do") == "verb");
		assert(t.at("horse") == "stallion");
		assert(t.at("dog") == "puppy");
		t.remove("horse");
		t.remove("do");
		t.remove("doge");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		assert(t.at("dog") == "puppy");
		t.remove("dog");

		for (int a = 0; a < 20; ++a)
		{
			StringMap m;
			for (int i = 0; i < 20; ++i)
			{
				auto k = randomWord();
				auto v = toString(i);
				m.insert(make_pair(k, v));
				t.insert(k, v);
				assert(hash256(m) == t.sha256());
			}
			while (!m.empty())
			{
				auto k = m.begin()->first;
				t.remove(k);
				m.erase(k);
				assert(hash256(m) == t.sha256());
			}
		}
	}

	// int of value 15
	assert(RLP("\x0f") == 15);
	assert(rlp(15) == "\x0f");

	// 3-character string
	assert(RLP("\x43""dog") == "dog");
	assert(rlp("dog") == "\x43""dog");

	// 2-item list
	RLP twoItemList("\x82\x0f\x43""dog");
	assert(twoItemList.itemCount() == 2 && twoItemList[0] == 15 && twoItemList[1] == "dog");
	assert(rlpList(15, "dog") == "\x82\x0f\x43""dog");

	// 1-byte (8-bit) int
	assert(RLP("\x18\x45") == 69);
	assert(rlp(69) == "\x18\x45");

	// 2-byte (16-bit) int
	assert(RLP("\x19\x01\x01") == 257);
	assert(rlp(257) == "\x19\x01\x01");

	// 32-byte (256-bit) int
	assert(RLP("\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"));
	assert(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) == "\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");

	// 33-byte (264-bit) int
	assert(RLP("\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"));
	assert(rlp(bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")) == "\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");

	// 56-character string.
	assert(RLP("\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit");
	assert(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit");

	/*
	 * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1
	 * [0,0,1,2,3,4,5]   0x10012345
	 * [0,1,2,3,4,5]     0x00012345
	 * [1,2,3,4,5]       0x112345
	 * [0,0,1,2,3,4]     0x00001234
	 * [0,1,2,3,4]       0x101234
	 * [1,2,3,4]         0x001234
	 * [0,0,1,2,3,4,5,T] 0x30012345
	 * [0,0,1,2,3,4,T]   0x20001234
	 * [0,1,2,3,4,5,T]   0x20012345
	 * [1,2,3,4,5,T]     0x312345
	 * [1,2,3,4,T]       0x201234
	 */
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, false)) == "10012345");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, false)) == "00012345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, false)) == "112345");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, false)) == "00001234");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4}, false)) == "101234");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4}, false)) == "001234");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, true)) == "30012345");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, true)) == "20001234");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, true)) == "20012345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, true)) == "312345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4}, true)) == "201234");

	return 0;
}

<commit_msg>Codebase cleanups - renaming files.<commit_after>#include <random>
#include "Common.h"
#include "RLP.h"
#include "Trie.h"
#include "VirtualMachine.h"
using namespace std;
using namespace eth;

std::string randomWord()
{
	static std::mt19937_64 s_eng(0);
	std::string ret(uniform_int_distribution<int>(4, 10)(s_eng), ' ');
	char const n[] = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
	uniform_int_distribution<int> d(0, sizeof(n) - 2);
	for (char& c: ret)
		c = n[d(s_eng)];
	return ret;
}

int main()
{
	{
		Trie t;
		t.insert("dog", "puppy");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		assert(t.at("dog") == "puppy");
		t.insert("doe", "reindeer");
		assert(t.sha256() == hash256({{"dog", "puppy"}, {"doe", "reindeer"}}));
		assert(t.at("doe") == "reindeer");
		assert(t.at("dog") == "puppy");
		t.insert("dogglesworth", "cat");
		assert(t.sha256() == hash256({{"doe", "reindeer"}, {"dog", "puppy"}, {"dogglesworth", "cat"}}));
		assert(t.at("doe") == "reindeer");
		assert(t.at("dog") == "puppy");
		assert(t.at("dogglesworth") == "cat");
		t.remove("dogglesworth");
		t.remove("doe");
		assert(t.at("doe").empty());
		assert(t.at("dogglesworth").empty());
		assert(t.at("dog") == "puppy");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		t.insert("horse", "stallion");
		t.insert("do", "verb");
		t.insert("doge", "coin");
		assert(t.sha256() == hash256({{"dog", "puppy"}, {"horse", "stallion"}, {"do", "verb"}, {"doge", "coin"}}));
		assert(t.at("doge") == "coin");
		assert(t.at("do") == "verb");
		assert(t.at("horse") == "stallion");
		assert(t.at("dog") == "puppy");
		t.remove("horse");
		t.remove("do");
		t.remove("doge");
		assert(t.sha256() == hash256({{"dog", "puppy"}}));
		assert(t.at("dog") == "puppy");
		t.remove("dog");

		for (int a = 0; a < 20; ++a)
		{
			StringMap m;
			for (int i = 0; i < 20; ++i)
			{
				auto k = randomWord();
				auto v = toString(i);
				m.insert(make_pair(k, v));
				t.insert(k, v);
				assert(hash256(m) == t.sha256());
			}
			while (!m.empty())
			{
				auto k = m.begin()->first;
				t.remove(k);
				m.erase(k);
				assert(hash256(m) == t.sha256());
			}
		}
	}

	// int of value 15
	assert(RLP("\x0f") == 15);
	assert(rlp(15) == "\x0f");

	// 3-character string
	assert(RLP("\x43""dog") == "dog");
	assert(rlp("dog") == "\x43""dog");

	// 2-item list
	RLP twoItemList("\x82\x0f\x43""dog");
	assert(twoItemList.itemCount() == 2 && twoItemList[0] == 15 && twoItemList[1] == "dog");
	assert(rlpList(15, "dog") == "\x82\x0f\x43""dog");

	// 1-byte (8-bit) int
	assert(RLP("\x18\x45") == 69);
	assert(rlp(69) == "\x18\x45");

	// 2-byte (16-bit) int
	assert(RLP("\x19\x01\x01") == 257);
	assert(rlp(257) == "\x19\x01\x01");

	// 32-byte (256-bit) int
	assert(RLP("\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"));
	assert(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) == "\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");

	// 33-byte (264-bit) int
	assert(RLP("\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"));
	assert(rlp(bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")) == "\x38\x21\x20\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");

	// 56-character string.
	assert(RLP("\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit");
	assert(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit");

	/*
	 * Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1
	 * [0,0,1,2,3,4,5]   0x10012345
	 * [0,1,2,3,4,5]     0x00012345
	 * [1,2,3,4,5]       0x112345
	 * [0,0,1,2,3,4]     0x00001234
	 * [0,1,2,3,4]       0x101234
	 * [1,2,3,4]         0x001234
	 * [0,0,1,2,3,4,5,T] 0x30012345
	 * [0,0,1,2,3,4,T]   0x20001234
	 * [0,1,2,3,4,5,T]   0x20012345
	 * [1,2,3,4,5,T]     0x312345
	 * [1,2,3,4,T]       0x201234
	 */
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, false)) == "10012345");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, false)) == "00012345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, false)) == "112345");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, false)) == "00001234");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4}, false)) == "101234");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4}, false)) == "001234");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, true)) == "30012345");
	assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, true)) == "20001234");
	assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, true)) == "20012345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, true)) == "312345");
	assert(asHex(hexPrefixEncode({1, 2, 3, 4}, true)) == "201234");

	return 0;
}

<|endoftext|>


<commit_before>//
//  main.cpp
//  C++ClassBST
//
//  Basic BST class implementation with insert, search, remove, recursive inorder print,
//  and iterative inorder print.
//
//  The data type of value in the leaf struct is templateized.
//
//  Created by Christopher Gleeson on 12/21/15.
//  Copyright © 2015 Christopher Gleeson. All rights reserved.
//

#include <iostream>
#include <stack>
#include <cassert>
#include <exception>
#include "BST.hpp"

int main(int argc, const char * argv[]){
    //create a tree object
    BST<int> *myTree;

    try {
        myTree = new BST<int>;
    } catch (std::bad_alloc& exc) {
        std::cerr << "ERROR: could not allocate storage.  Terminating!\n";
        std::terminate();
    }

    //print the empty tree
    myTree->print_tree_inorder();

    //add some elements
    myTree->insert(8);
    myTree->insert(4);
    myTree->insert(2);
    myTree->insert(-1);
    myTree->insert(12);
    myTree->insert(14);
    myTree->insert(-16);
    myTree->insert(3);
    myTree->insert(5);
    myTree->insert(10);

    //print the tree recursively
    std::cout << "Print of tree, inorder, recursive:\n";
    myTree->print_tree_inorder();

    //print the tree iteratively
    std::cout << "Print of tree, inorder, iterative:\n";
    myTree->print_tree_it_inorder();

    //search for a node
    std::cout << "Searching for node with value 4, expect success.\n";
    int skey = 4;
    bool result = myTree->search(skey);
    if(!result){
        std::cout << "Searched for key of " << skey << ", key NOT found!\n";
    }else{
        std::cout << "Found key of " << skey << " successfully!\n";
    }
    std::cout << "Searching for node with value 13, expect failure.\n";
    skey = 13;
    result = myTree->search(skey);
    if(!result){
        std::cout << "Searched for key of " << skey << ", key NOT found!\n";
    }else{
        std::cout << "Found key of " << skey << " successfully!\n";
    }

    //test inorder predecessor
    std::cout << "Testing checks for inorder predecessor, 8,4,2,12 expect pass, 14 expect fail.\n";
    myTree->inorder_predecessor(8);
    myTree->inorder_predecessor(4);
    myTree->inorder_predecessor(2);
    myTree->inorder_predecessor(12);
    myTree->inorder_predecessor(14);

    //test find parent
    std::cout << "Testing find parent for node with value 4, expect to find parent with value 8.\n";
    myTree->locate_parent(4);

    //test deletion
    std::cout << "Testing node deletion of node with value 14, expect success.\n";
    myTree->remove(14);
    myTree->print_tree_inorder();

    std::cout << "Destroying tree.\n";
    delete myTree;
    return 0;
}

<commit_msg>updated comments.<commit_after>//
//  main.cpp
//  C++ClassBST
//
//  Tester for the BST class implemented in BST.hpp.
//
//
//  Created by Christopher Gleeson on 12/21/15.
//  Copyright © 2015 Christopher Gleeson. All rights reserved.
//

#include <iostream>
#include <stack>
#include <cassert>
#include <exception>
#include "BST.hpp"

int main(int argc, const char * argv[]){
    //create a tree object
    BST<int> *myTree;

    try {
        myTree = new BST<int>;
    } catch (std::bad_alloc& exc) {
        std::cerr << "ERROR: could not allocate storage.  Terminating!\n";
        std::terminate();
    }

    //print the empty tree
    myTree->print_tree_inorder();

    //add some elements
    myTree->insert(8);
    myTree->insert(4);
    myTree->insert(2);
    myTree->insert(-1);
    myTree->insert(12);
    myTree->insert(14);
    myTree->insert(-16);
    myTree->insert(3);
    myTree->insert(5);
    myTree->insert(10);

    //print the tree recursively
    std::cout << "Print of tree, inorder, recursive:\n";
    myTree->print_tree_inorder();

    //print the tree iteratively
    std::cout << "Print of tree, inorder, iterative:\n";
    myTree->print_tree_it_inorder();

    //search for a node
    std::cout << "Searching for node with value 4, expect success.\n";
    int skey = 4;
    bool result = myTree->search(skey);
    if(!result){
        std::cout << "Searched for key of " << skey << ", key NOT found!\n";
    }else{
        std::cout << "Found key of " << skey << " successfully!\n";
    }
    std::cout << "Searching for node with value 13, expect failure.\n";
    skey = 13;
    result = myTree->search(skey);
    if(!result){
        std::cout << "Searched for key of " << skey << ", key NOT found!\n";
    }else{
        std::cout << "Found key of " << skey << " successfully!\n";
    }

    //test inorder predecessor
    std::cout << "Testing checks for inorder predecessor, 8,4,2,12 expect pass, 14 expect fail.\n";
    myTree->inorder_predecessor(8);
    myTree->inorder_predecessor(4);
    myTree->inorder_predecessor(2);
    myTree->inorder_predecessor(12);
    myTree->inorder_predecessor(14);

    //test find parent
    std::cout << "Testing find parent for node with value 4, expect to find parent with value 8.\n";
    myTree->locate_parent(4);

    //test deletion
    std::cout << "Testing node deletion of node with value 14, expect success.\n";
    myTree->remove(14);
    myTree->print_tree_inorder();

    std::cout << "Destroying tree.\n";
    delete myTree;
    return 0;
}

<|endoftext|>


<commit_before>#include "eval.h"
#include <sstream>

namespace Akumuli {
namespace QP {

class ParseError : public std::exception {
    const std::string message_;

public:
    ParseError(const char* msg)
        : message_(msg)
    {
    }

    ParseError(std::string msg)
        : message_(std::move(msg))
    {
    }

    const char* what() const noexcept override {
        return message_.c_str();
    }
};

class ExpressionNode {
public:
    virtual ~ExpressionNode() = default;
    virtual double eval(MutableSample& mut) = 0;
};

class ConstantNode : public ExpressionNode {
    const double cval_;
public:
    ConstantNode(double value)
        : cval_(value)
    {
    }

    double eval(MutableSample&) override {
        return cval_;
    }
};

class ValueNode : public ExpressionNode {
    int ixval_;
public:
    ValueNode(int ixval)
        : ixval_(ixval)
    {
    }

    double eval(MutableSample& mut) override {
        return *mut[static_cast<u32>(ixval_)];
    }
};

enum class ExpressionOperator {
    UNKNOWN,
    SUM,
    MUL,
};

std::ostream& operator << (std::ostream& s, ExpressionOperator op) {
    switch (op) {
    case ExpressionOperator::MUL:
        s << "*";
        break;
    case ExpressionOperator::SUM:
        s << "+";
        break;
    case ExpressionOperator::UNKNOWN:
        s << "_unknown_";
        break;
    }
    return s;
}

std::istream& operator >> (std::istream& s, ExpressionOperator& op) {
    char b;
    s.read(&b, 1);
    switch (b) {
    case '*':
        op = ExpressionOperator::MUL;
        break;
    case '+':
        op = ExpressionOperator::SUM;
        break;
    default:
        op = ExpressionOperator::UNKNOWN;
        break;
    }
    return s;
}

class OperatorNode : public ExpressionNode {
    ExpressionOperator op_;
    std::vector<std::unique_ptr<ExpressionNode>> children_;
    std::vector<double> args_;
public:
    OperatorNode(ExpressionOperator op, std::vector<std::unique_ptr<ExpressionNode>>&& args)
        : op_(op)
        , children_(std::move(args))
        , args_(children_.size())
    {
    }

    double eval(MutableSample& mut) override {
        std::transform(children_.begin(), children_.end(), args_.begin(),
                       [&mut](std::unique_ptr<ExpressionNode>& node) {
                           return node->eval(mut);
                       });
        switch(op_) {
        case ExpressionOperator::MUL:
            return std::accumulate(args_.begin(), args_.end(), 1.0, [](double a, double b) {
                return a * b;
            });
        case ExpressionOperator::SUM:
            return std::accumulate(args_.begin(), args_.end(), 0.0, [](double a, double b) {
                return a + b;
            });
        case ExpressionOperator::UNKNOWN:
            break;
        }
        return NAN;
    }
};

/**
 * Function call expression node.
 * Base interface:
 * - double apply(It begin, It end);
 * - bool check_arity(size_t n, string* errormsg);
 * - static const char* func_name
 * - static const char* func_help
 */
template<class Base>
struct FunctionCallNode : ExpressionNode, Base
{
    std::vector<std::unique_ptr<ExpressionNode>> children_;
    std::vector<double> args_;

    FunctionCallNode(ExpressionOperator op, std::vector<std::unique_ptr<ExpressionNode>>&& args)
        : children_(std::move(args))
        , args_(children_.size())
    {
        std::string errormsg;
        if (!static_cast<Base*>(this)->check_arity(children_.size(), &errormsg)) {
            ParseError err("function " + Base::func_name + " error: " + errormsg);
            BOOST_THROW_EXCEPTION(err);
        }
    }

    double eval(MutableSample& mut) override {
        std::transform(children_.begin(), children_.end(), args_.begin(),
                       [&mut](std::unique_ptr<ExpressionNode>& node) {
                           return node->eval(mut);
                       });
        return static_cast<Base*>(this)->apply(args_.begin(), args_.end());
    }
};

struct BuiltInFunctions {
    struct Min {
        template<class It>
        double apply(It begin, It end) {
            return std::min_element(begin, end);
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 0) {
                *error = "function require at least one parameter";
                return false;
            }
            return true;
        }
        constexpr static const char* func_name = "min";
    };

    struct Max {
        template<class It>
        double apply(It begin, It end) {
            return std::max_element(begin, end);
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 0) {
                *error = "function require at least one parameter";
                return false;
            }
            return true;
        }
        constexpr static const char* func_name = "max";
    };

    struct Abs {
        template<class It>
        double apply(It begin, It end) {
            return std::abs(*begin);
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 1) {
                return true;
            }
            *error = "single argument expected";
            return false;
        }
        constexpr static const char* func_name = "abs";
    };
};

typedef boost::property_tree::ptree PTree;
static const int DEPTH_LIMIT = 10;

template<class LookupFn>
std::unique_ptr<ExpressionNode> buildNode(int depth, const PTree& node, const LookupFn& lookup) {
    if (depth == DEPTH_LIMIT) {
        ParseError err("expression depth limit exceded");
        BOOST_THROW_EXCEPTION(err);
    }
    // Expect array of: [op, arg1, arg2, ...,argN]
    // i-th arg can be a node in which case recursive call
    // have to be made.
    std::string op;
    std::vector<std::unique_ptr<ExpressionNode>> args;
    for (auto it = node.begin(); it != node.end(); it++) {
        if (it == node.begin()) {
            // Parse operator
            if (!it->first.empty()) {
                // Expect value here
                ParseError err("operator or function expected");
                BOOST_THROW_EXCEPTION(err);
            }
            else {
                op = it->second.data();
            }
        }
        else {
            // Parse arguments
            auto value = it->second.data();
            if (value.empty()) {
                // Build sub-node
                auto arg = buildNode(depth + 1, it->second, lookup);
                args.push_back(std::move(arg));
            }
            else {
                std::unique_ptr<ExpressionNode> node;
                std::stringstream str(value);
                double xs;
                str >> xs;
                if (!str.fail()) {
                    node.reset(new ConstantNode(xs));
                }
                else {
                    auto ix = lookup(value);
                    if (ix < 0) {
                        // Field can't be found
                        ParseError err("unknown field '" + value + "'");
                        BOOST_THROW_EXCEPTION(err);
                    }
                    node.reset(new ValueNode(ix));
                }
                args.push_back(std::move(node));
            }
        }
    }
    std::unique_ptr<ExpressionNode> res;
    std::stringstream sop(op);
    ExpressionOperator exop;
    sop >> exop;
    if (exop == ExpressionOperator::UNKNOWN) {
        ParseError err("unknown operator '" + op + "'");
        BOOST_THROW_EXCEPTION(err);
    }
    res.reset(new OperatorNode(exop, std::move(args)));
    return res;
}

// ----
// Eval
// ----

static std::unordered_map<std::string, int> buildNameToIndexMapping(const QP::ReshapeRequest& req)
{
    std::unordered_map<std::string, int> result;
    const int ncol = static_cast<int>(req.select.columns.size());
    for(int ix = 0; ix < ncol; ix++) {
        if (req.select.columns[ix].ids.empty()) {
            continue;
        }
        auto idcol = req.select.columns[ix].ids.front();
        auto rawstr = req.select.matcher->id2str(idcol);
        // copy metric name from the begining until the ' ' or ':'
        std::string sname(rawstr.first, rawstr.first + rawstr.second);
        auto it = std::find_if(sname.begin(), sname.end(), [](char c) {
            return std::isspace(c) || c == ':';
        });
        result[std::string(sname.begin(), it)] = ix;
    }
    return result;
}

Eval::Eval(const boost::property_tree::ptree& ptree, const ReshapeRequest& req, std::shared_ptr<Node> next)
    : next_(next)
{
    auto const& expr = ptree.get_child_optional("expr");
    if (expr) {
        std::unordered_map<std::string, int> lazyInitMap;
        bool initialized = false;
        auto lookupFn = [&](const std::string& fld) {
            if (!initialized) {
                initialized = true;
                lazyInitMap = buildNameToIndexMapping(req);
            }
            auto it = lazyInitMap.find(fld);
            if (it == lazyInitMap.end()) {
                return -1;
            }
            return it->second;
        };
        expr_ = buildNode(0, *expr, lookupFn);
    }
}

Eval::Eval(const boost::property_tree::ptree& expr, const ReshapeRequest& req, std::shared_ptr<Node> next, bool)
    : next_(next)
{
    std::unordered_map<std::string, int> lazyInitMap;
    bool initialized = false;
    auto lookupFn = [&](const std::string& fld) {
        if (!initialized) {
            initialized = true;
            lazyInitMap = buildNameToIndexMapping(req);
        }
        auto it = lazyInitMap.find(fld);
        if (it == lazyInitMap.end()) {
            return -1;
        }
        return it->second;
    };
    expr_ = buildNode(0, expr, lookupFn);
}

void Eval::complete() {
    next_->complete();
}

bool Eval::put(MutableSample &mut) {
    double val = expr_->eval(mut);
    mut.collapse();
    if (std::isnormal(val)) {
        *mut[0] = val;
        return next_->put(mut);
    }
    return true;
}

void Eval::set_error(aku_Status status) {
    next_->set_error(status);
}

int Eval::get_requirements() const {
    return TERMINAL;
}

static QueryParserToken<Eval> scale_token("eval");

}}  // namespace
<commit_msg>Working on function call mechanism<commit_after>#include "eval.h"
#include <sstream>
#include <unordered_map>
#include <functional>

namespace Akumuli {
namespace QP {

class ParseError : public std::exception {
    const std::string message_;

public:
    ParseError(const char* msg)
        : message_(msg)
    {
    }

    ParseError(std::string msg)
        : message_(std::move(msg))
    {
    }

    const char* what() const noexcept override {
        return message_.c_str();
    }
};

class ExpressionNode {
public:
    virtual ~ExpressionNode() = default;
    virtual double eval(MutableSample& mut) = 0;
};

class ConstantNode : public ExpressionNode {
    const double cval_;
public:
    ConstantNode(double value)
        : cval_(value)
    {
    }

    double eval(MutableSample&) override {
        return cval_;
    }
};

class ValueNode : public ExpressionNode {
    int ixval_;
public:
    ValueNode(int ixval)
        : ixval_(ixval)
    {
    }

    double eval(MutableSample& mut) override {
        return *mut[static_cast<u32>(ixval_)];
    }
};

enum class ExpressionOperator {
    UNKNOWN,
    SUM,
    MUL,
};

std::ostream& operator << (std::ostream& s, ExpressionOperator op) {
    switch (op) {
    case ExpressionOperator::MUL:
        s << "*";
        break;
    case ExpressionOperator::SUM:
        s << "+";
        break;
    case ExpressionOperator::UNKNOWN:
        s << "_unknown_";
        break;
    }
    return s;
}

std::istream& operator >> (std::istream& s, ExpressionOperator& op) {
    char b;
    s.read(&b, 1);
    switch (b) {
    case '*':
        op = ExpressionOperator::MUL;
        break;
    case '+':
        op = ExpressionOperator::SUM;
        break;
    default:
        op = ExpressionOperator::UNKNOWN;
        break;
    }
    return s;
}

class OperatorNode : public ExpressionNode {
    ExpressionOperator op_;
    std::vector<std::unique_ptr<ExpressionNode>> children_;
    std::vector<double> args_;
public:
    OperatorNode(ExpressionOperator op, std::vector<std::unique_ptr<ExpressionNode>>&& args)
        : op_(op)
        , children_(std::move(args))
        , args_(children_.size())
    {
    }

    double eval(MutableSample& mut) override {
        std::transform(children_.begin(), children_.end(), args_.begin(),
                       [&mut](std::unique_ptr<ExpressionNode>& node) {
                           return node->eval(mut);
                       });
        switch(op_) {
        case ExpressionOperator::MUL:
            return std::accumulate(args_.begin(), args_.end(), 1.0, [](double a, double b) {
                return a * b;
            });
        case ExpressionOperator::SUM:
            return std::accumulate(args_.begin(), args_.end(), 0.0, [](double a, double b) {
                return a + b;
            });
        case ExpressionOperator::UNKNOWN:
            break;
        }
        return NAN;
    }
};

struct FunctionCallRegistry {
    typedef std::unique_ptr<ExpressionNode> NodeT;
    typedef std::function<NodeT (std::vector<NodeT>&&)> CtorT;

private:
    std::unordered_map<std::string, CtorT> registry_;
    FunctionCallRegistry() = default;

public:
    static FunctionCallRegistry& get() {
        static FunctionCallRegistry s_registry;
        return s_registry;
    }

    void add(std::string name, CtorT&& ctor) {
        registry_[std::move(name)] = ctor;
    }

    NodeT create(const std::string& fname, std::vector<NodeT>&& args) {
        NodeT res;
        auto it = registry_.find(fname);
        if (it == registry_.end()) {
            return res;
        }
        return it->second(std::move(args));
    }
};

/**
 * Function call expression node.
 * Base interface:
 * - double apply(It begin, It end);
 * - bool check_arity(size_t n, string* errormsg);
 * - static const char* func_name
 */
template<class Base>
struct FunctionCallNode : ExpressionNode, Base
{
    typedef FunctionCallNode<Base> NodeT;

    std::vector<std::unique_ptr<ExpressionNode>> children_;
    std::vector<double> args_;

    FunctionCallNode(FunctionCallNode const&) = delete;
    FunctionCallNode& operator = (FunctionCallNode const&) = delete;

    template<class ArgT>
    FunctionCallNode(ArgT&& args)
        : children_(std::forward<ArgT>(args))
        , args_(children_.size())
    {
        std::string errormsg;
        if (!static_cast<Base*>(this)->check_arity(children_.size(), &errormsg)) {
            ParseError err(std::string("function ") + Base::func_name + " error: " + errormsg);
            BOOST_THROW_EXCEPTION(err);
        }
    }

    double eval(MutableSample& mut) override {
        std::transform(children_.begin(), children_.end(), args_.begin(),
                       [&mut](std::unique_ptr<ExpressionNode>& node) {
                           return node->eval(mut);
                       });
        return static_cast<Base*>(this)->apply(args_.begin(), args_.end());
    }

    static std::unique_ptr<NodeT> create_node(std::vector<std::unique_ptr<ExpressionNode>>&& args) {
        std::unique_ptr<NodeT> result;
        result.reset(new NodeT(std::move(args)));
        return result;
    }

private:
    struct RegistryToken {
        RegistryToken() {
            FunctionCallRegistry::get().add(Base::func_name, &create_node);
        }
    };

    static RegistryToken regtoken_;
};

struct BuiltInFunctions {
    struct Min {
        template<class It>
        double apply(It begin, It end) {
            auto it = std::min_element(begin, end);
            if (it != end) {
                return *it;
            }
            return NAN;
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 0) {
                *error = "function require at least one parameter";
                return false;
            }
            return true;
        }
        constexpr static const char* func_name = "min";
    };

    struct Max {
        template<class It>
        double apply(It begin, It end) {
            auto it = std::max_element(begin, end);
            if (it != end) {
                return *it;
            }
            return NAN;
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 0) {
                *error = "function require at least one parameter";
                return false;
            }
            return true;
        }
        constexpr static const char* func_name = "max";
    };

    struct Abs {
        template<class It>
        double apply(It begin, It end) {
            return std::abs(*begin);
        }
        bool check_arity(size_t n, std::string* error) const {
            if (n == 1) {
                return true;
            }
            *error = "single argument expected";
            return false;
        }
        constexpr static const char* func_name = "abs";
    };
};

template struct FunctionCallNode<BuiltInFunctions::Max>;
template struct FunctionCallNode<BuiltInFunctions::Min>;
template struct FunctionCallNode<BuiltInFunctions::Abs>;

typedef boost::property_tree::ptree PTree;
static const int DEPTH_LIMIT = 10;

template<class LookupFn>
std::unique_ptr<ExpressionNode> buildNode(int depth, const PTree& node, const LookupFn& lookup) {
    if (depth == DEPTH_LIMIT) {
        ParseError err("expression depth limit exceded");
        BOOST_THROW_EXCEPTION(err);
    }
    // Expect array of: [op, arg1, arg2, ...,argN]
    // i-th arg can be a node in which case recursive call
    // have to be made.
    std::string op;
    std::vector<std::unique_ptr<ExpressionNode>> args;
    for (auto it = node.begin(); it != node.end(); it++) {
        if (it == node.begin()) {
            // Parse operator
            if (!it->first.empty()) {
                // Expect value here
                ParseError err("operator or function expected");
                BOOST_THROW_EXCEPTION(err);
            }
            else {
                op = it->second.data();
            }
        }
        else {
            // Parse arguments
            auto value = it->second.data();
            if (value.empty()) {
                // Build sub-node
                auto arg = buildNode(depth + 1, it->second, lookup);
                args.push_back(std::move(arg));
            }
            else {
                std::unique_ptr<ExpressionNode> node;
                std::stringstream str(value);
                double xs;
                str >> xs;
                if (!str.fail()) {
                    node.reset(new ConstantNode(xs));
                }
                else {
                    auto ix = lookup(value);
                    if (ix < 0) {
                        // Field can't be found
                        ParseError err("unknown field '" + value + "'");
                        BOOST_THROW_EXCEPTION(err);
                    }
                    node.reset(new ValueNode(ix));
                }
                args.push_back(std::move(node));
            }
        }
    }
    std::unique_ptr<ExpressionNode> res;
    std::stringstream sop(op);
    ExpressionOperator exop;
    sop >> exop;
    if (exop == ExpressionOperator::UNKNOWN) {
        ParseError err("unknown operator '" + op + "'");
        BOOST_THROW_EXCEPTION(err);
    }
    res.reset(new OperatorNode(exop, std::move(args)));
    return res;
}

// ----
// Eval
// ----

static std::unordered_map<std::string, int> buildNameToIndexMapping(const QP::ReshapeRequest& req)
{
    std::unordered_map<std::string, int> result;
    const int ncol = static_cast<int>(req.select.columns.size());
    for(int ix = 0; ix < ncol; ix++) {
        if (req.select.columns[ix].ids.empty()) {
            continue;
        }
        auto idcol = req.select.columns[ix].ids.front();
        auto rawstr = req.select.matcher->id2str(idcol);
        // copy metric name from the begining until the ' ' or ':'
        std::string sname(rawstr.first, rawstr.first + rawstr.second);
        auto it = std::find_if(sname.begin(), sname.end(), [](char c) {
            return std::isspace(c) || c == ':';
        });
        result[std::string(sname.begin(), it)] = ix;
    }
    return result;
}

Eval::Eval(const boost::property_tree::ptree& ptree, const ReshapeRequest& req, std::shared_ptr<Node> next)
    : next_(next)
{
    auto const& expr = ptree.get_child_optional("expr");
    if (expr) {
        std::unordered_map<std::string, int> lazyInitMap;
        bool initialized = false;
        auto lookupFn = [&](const std::string& fld) {
            if (!initialized) {
                initialized = true;
                lazyInitMap = buildNameToIndexMapping(req);
            }
            auto it = lazyInitMap.find(fld);
            if (it == lazyInitMap.end()) {
                return -1;
            }
            return it->second;
        };
        expr_ = buildNode(0, *expr, lookupFn);
    }
}

Eval::Eval(const boost::property_tree::ptree& expr, const ReshapeRequest& req, std::shared_ptr<Node> next, bool)
    : next_(next)
{
    std::unordered_map<std::string, int> lazyInitMap;
    bool initialized = false;
    auto lookupFn = [&](const std::string& fld) {
        if (!initialized) {
            initialized = true;
            lazyInitMap = buildNameToIndexMapping(req);
        }
        auto it = lazyInitMap.find(fld);
        if (it == lazyInitMap.end()) {
            return -1;
        }
        return it->second;
    };
    expr_ = buildNode(0, expr, lookupFn);
}

void Eval::complete() {
    next_->complete();
}

bool Eval::put(MutableSample &mut) {
    double val = expr_->eval(mut);
    mut.collapse();
    if (std::isnormal(val)) {
        *mut[0] = val;
        return next_->put(mut);
    }
    return true;
}

void Eval::set_error(aku_Status status) {
    next_->set_error(status);
}

int Eval::get_requirements() const {
    return TERMINAL;
}

static QueryParserToken<Eval> scale_token("eval");

}}  // namespace
<|endoftext|>


<commit_before>#ifndef ARABICA_XPATH_VARIABLE_HPP
#define ARABICA_XPATH_VARIABLE_HPP

#include "xpath_value.hpp"
#include "xpath_execution_context.hpp"
#include "xpath_variable_resolver.hpp"

namespace Arabica
{
namespace XPath
{

template<class string_type, class string_adaptor>
class Variable : public XPathExpression_impl<string_type, string_adaptor>
{
public:
  Variable(const string_type& namespace_uri,
           const string_type& name) :
    namespace_uri_(namespace_uri),
    name_(name)
  {
  } // Variable

  virtual ValueType type() const { return ANY; }

  virtual XPathValue<string_type, string_adaptor> evaluate(const DOM::Node<string_type, string_adaptor>& context,
                                              const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    return executionContext.variableResolver().resolveVariable(namespace_uri_, name_);
  } // evaluate

private:
  const string_type namespace_uri_;
  const string_type name_;
}; // class Variable

} // namespace XPath
} // namespace Arabica

#endif
<commit_msg>fixed unused param warning<commit_after>#ifndef ARABICA_XPATH_VARIABLE_HPP
#define ARABICA_XPATH_VARIABLE_HPP

#include "xpath_value.hpp"
#include "xpath_execution_context.hpp"
#include "xpath_variable_resolver.hpp"

namespace Arabica
{
namespace XPath
{

template<class string_type, class string_adaptor>
class Variable : public XPathExpression_impl<string_type, string_adaptor>
{
public:
  Variable(const string_type& namespace_uri,
           const string_type& name) :
    namespace_uri_(namespace_uri),
    name_(name)
  {
  } // Variable

  virtual ValueType type() const { return ANY; }

  virtual XPathValue<string_type, string_adaptor> evaluate(const DOM::Node<string_type, string_adaptor>& /* context */,
                                              const ExecutionContext<string_type, string_adaptor>& executionContext) const
  {
    return executionContext.variableResolver().resolveVariable(namespace_uri_, name_);
  } // evaluate

private:
  const string_type namespace_uri_;
  const string_type name_;
}; // class Variable

} // namespace XPath
} // namespace Arabica

#endif
<|endoftext|>


<commit_before>#ifndef IM_STR_DETAIL_REF_CNT_BUF_H
#define IM_STR_DETAIL_REF_CNT_BUF_H

#include <atomic>
#include <cassert>
#include <cstdint>
#include <new>     // placement new
#include <utility> // std::move

#ifndef IM_STR_USE_ALLOC
	#if __has_include( <memory_resource>)
		#include <memory_resource>
		#define IM_STR_USE_ALLOC 1
	#endif
#else
	#define IM_STR_USE_ALLOC 0
#endif

namespace mba::detail {

#ifdef IM_STR_DEBUG_HOOKS
inline namespace debug_version {
struct Stats {
	std::atomic_uint64_t total_cnt_accesses {0};
	std::atomic_uint64_t total_allocs {0};
	std::atomic_uint64_t current_allocs {0};
	std::atomic_uint64_t inc_ref_cnt {0};
	std::atomic_uint64_t dec_ref_cnt {0};

	void inc_ref()
	{
		total_cnt_accesses.fetch_add( 1, std::memory_order_relaxed );
		inc_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
	}

	void dec_ref()
	{
		total_cnt_accesses.fetch_add( 1, std::memory_order_relaxed );
		dec_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
	}

	void alloc()
	{
		total_allocs.fetch_add( 1, std::memory_order_relaxed );
		current_allocs.fetch_add( 1, std::memory_order_relaxed );
	}

	void dealloc() { current_allocs.fetch_sub( 1, std::memory_order_relaxed ); }

	std::uint64_t get_total_cnt_accesses() const { return total_cnt_accesses.load( std::memory_order_relaxed ); };
	std::uint64_t get_total_allocs() const { return total_allocs.load( std::memory_order_relaxed ); };
	std::uint64_t get_current_allocs() const { return current_allocs.load( std::memory_order_relaxed ); };
	std::uint64_t get_inc_ref_cnt() const { return inc_ref_cnt.load( std::memory_order_relaxed ); };
	std::uint64_t get_dec_ref_cnt() const { return dec_ref_cnt.load( std::memory_order_relaxed ); };

	constexpr Stats() noexcept = default;
	Stats( const Stats& other )
		: total_cnt_accesses( other.total_cnt_accesses.load( std::memory_order_relaxed ) )
		, total_allocs( other.total_allocs.load( std::memory_order_relaxed ) )
		, current_allocs( other.current_allocs.load( std::memory_order_relaxed ) )
		, inc_ref_cnt( other.inc_ref_cnt.load( std::memory_order_relaxed ) )
		, dec_ref_cnt( other.dec_ref_cnt.load( std::memory_order_relaxed ) )
	{
	}

	void reset()
	{
		total_cnt_accesses = 0;
		total_allocs       = 0;
		current_allocs     = 0;
		inc_ref_cnt        = 0;
		dec_ref_cnt        = 0;
	}
};
#else
struct Stats {
	constexpr Stats() noexcept = default;

	constexpr void inc_ref() noexcept {}
	constexpr void dec_ref() noexcept {}
	constexpr void alloc() noexcept {}
	constexpr void dealloc() noexcept {}
	constexpr void reset() {};
};
#endif

static Stats& stats()
{
	static Stats stats {};
	return stats;
}

constexpr struct defer_ref_cnt_tag_t {
} defer_ref_cnt_tag;

// Note: std::exchange is not constexpr in c++17
template<class T, class U = T>
constexpr T c_expr_exchange( T& obj, U&& new_value )
{
	T old_value = std::move( obj );
	obj         = std::forward<U>( new_value );
	return old_value;
}

inline constexpr std::size_t c_expr_max( std::size_t l, std::size_t r )
{
	return l > r ? l : r;
}
inline constexpr std::size_t c_expr_aligned_offset( std::size_t alignment, std::size_t min )
{
	if( alignment >= min ) {
		return alignment;
	} else {
		return min + ( alignment - min % alignment );
	}
}

struct AllocResult;

/**
 * Note: Almost all of the member functions are labled constexpr.
 * However, they can only be used in a constexpr context of the
 * handle is default constructed (i.e. _cnt == nullptr)
 */
class atomic_ref_cnt_buffer {
	using Cnt_t     = std::atomic_int;
	using size_type = int;

public:
#if IM_STR_USE_ALLOC
	using alloc_t     = std::pmr::memory_resource;
	using alloc_ptr_t = alloc_t*;
#else
	using alloc_ptr_t = std::nullptr_t;
#endif
	/*#### Constructors and special member functions ######*/
	static AllocResult allocate_null_terminated_char_buffer( int size, alloc_ptr_t = nullptr );

	constexpr atomic_ref_cnt_buffer() noexcept = default;
	constexpr atomic_ref_cnt_buffer( const atomic_ref_cnt_buffer& other, defer_ref_cnt_tag_t ) noexcept
		: _cnt {other._cnt}
	{
	}

	constexpr atomic_ref_cnt_buffer( const atomic_ref_cnt_buffer& other ) noexcept
		: _cnt {other._cnt}
	{
		_incref();
	}
	constexpr atomic_ref_cnt_buffer( atomic_ref_cnt_buffer&& other ) noexcept
		: _cnt {c_expr_exchange( other._cnt, nullptr )}
	{
	}

	constexpr atomic_ref_cnt_buffer& operator=( const atomic_ref_cnt_buffer& other ) noexcept
	{
		// inc before dec to protect against dropping in self assignment
		other._incref();
		_decref();
		_cnt = other._cnt;
		return *this;
	}
	constexpr atomic_ref_cnt_buffer& operator=( atomic_ref_cnt_buffer&& other ) noexcept
	{
		assert( ( ( _cnt == nullptr ) || ( this != &other ) ) && "Move assignment to self is not allowed, if cnt!=0" );
		_decref();
		_cnt = c_expr_exchange( other._cnt, nullptr );
		return *this;
	}

	~atomic_ref_cnt_buffer() { _decref(); }

	friend constexpr void swap( atomic_ref_cnt_buffer& l, atomic_ref_cnt_buffer& r ) noexcept
	{
		// TODO: C++20 		std::swap( l._cnt, r._cnt );  (not yet constexpr)
		auto tmp = l._cnt;
		l._cnt   = r._cnt;
		r._cnt   = tmp;
	}
	/*#### API ######*/

	constexpr int add_ref_cnt( int cnt ) const
	{
		if( !_cnt ) {
			return 0;
		} else {
			stats().inc_ref();
			return _cnt->fetch_add( cnt, std::memory_order_relaxed ) + cnt;
		}
	}

	friend constexpr bool operator==( const atomic_ref_cnt_buffer& l, std::nullptr_t ) { return l._cnt == nullptr; }
	friend constexpr bool operator==( std::nullptr_t, const atomic_ref_cnt_buffer& r ) { return r._cnt == nullptr; }
	friend constexpr bool operator!=( const atomic_ref_cnt_buffer& l, std::nullptr_t ) { return l._cnt != nullptr; }
	friend constexpr bool operator!=( std::nullptr_t, const atomic_ref_cnt_buffer& r ) { return r._cnt != nullptr; }

private:
	struct Header {
		Cnt_t       ref_cnt;
		size_type   size;
		alloc_ptr_t alloc;
	};

	// This is used in allocate_null_terminated_char_buffer
	constexpr explicit atomic_ref_cnt_buffer( Header& buffer ) noexcept
		: _cnt( &( buffer.ref_cnt ) )
	{
	}

	static void dealloc_buffer( Header* ptr );

	constexpr void _decref() const noexcept
	{
		if( _cnt ) {
			stats().dec_ref();
			if( _cnt->fetch_sub( 1 ) == 1 ) {
				Header* header = static_cast<Header*>( static_cast<void*>( _cnt ) );
				dealloc_buffer( header );
			}
		}
	}

	constexpr void _incref() const noexcept
	{
		if( _cnt ) {
			stats().inc_ref();
			_cnt->fetch_add( 1, std::memory_order_relaxed );
		}
	}

	Cnt_t* _cnt = nullptr;

	static constexpr auto alignment = alignof( Header );
};

struct AllocResult {
	char*                 data;
	atomic_ref_cnt_buffer handle;
};

inline AllocResult atomic_ref_cnt_buffer::allocate_null_terminated_char_buffer( size_type size, alloc_ptr_t resource )
{
	assert( size >= 0 );
	stats().alloc();

	const auto total_size       = sizeof( Header ) + size + 1;

#if IM_STR_USE_ALLOC
	const bool bool_use_default = resource == nullptr;
	char* const start = (char*)( bool_use_default                //
									 ? std::malloc( total_size ) //
									 : resource->allocate( total_size, alignment ) );
#else
	char* const start = (char*)std::malloc( total_size );
#endif

	auto* const header_ptr = new( start ) Header {Cnt_t {1}, size_type {size}, resource};

	auto* const data_ptr = start + sizeof( Header ); // Start of string
	data_ptr[size]       = '\0';                     // zero terminate

	return {data_ptr, atomic_ref_cnt_buffer {*header_ptr}};
}

inline void atomic_ref_cnt_buffer::dealloc_buffer( Header* header )
{
	stats().dealloc();

#if IM_STR_USE_ALLOC
	alloc_ptr_t alloc = header->alloc;
	if( alloc == nullptr ) {
		std::free( header );
	} else {
		size_type size = header->size;
		alloc->deallocate( header, size, alignment );
	}
#else
	std::free( header );
#endif
}

#ifdef IM_STR_DEBUG_HOOKS
} // inline namespace debug_version
#endif

} // namespace mba::detail

#endif
<commit_msg>[im_str] Add missing cstdlib header<commit_after>#ifndef IM_STR_DETAIL_REF_CNT_BUF_H
#define IM_STR_DETAIL_REF_CNT_BUF_H

#include <atomic>
#include <cassert>
#include <cstdint>
#include <new>     // placement new
#include <utility> // std::move
#include <cstdlib>

#ifndef IM_STR_USE_ALLOC
	#if __has_include( <memory_resource>)
		#include <memory_resource>
		#define IM_STR_USE_ALLOC 1
	#endif
#else
	#define IM_STR_USE_ALLOC 0
#endif

namespace mba::detail {

#ifdef IM_STR_DEBUG_HOOKS
inline namespace debug_version {
struct Stats {
	std::atomic_uint64_t total_cnt_accesses {0};
	std::atomic_uint64_t total_allocs {0};
	std::atomic_uint64_t current_allocs {0};
	std::atomic_uint64_t inc_ref_cnt {0};
	std::atomic_uint64_t dec_ref_cnt {0};

	void inc_ref()
	{
		total_cnt_accesses.fetch_add( 1, std::memory_order_relaxed );
		inc_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
	}

	void dec_ref()
	{
		total_cnt_accesses.fetch_add( 1, std::memory_order_relaxed );
		dec_ref_cnt.fetch_add( 1, std::memory_order_relaxed );
	}

	void alloc()
	{
		total_allocs.fetch_add( 1, std::memory_order_relaxed );
		current_allocs.fetch_add( 1, std::memory_order_relaxed );
	}

	void dealloc() { current_allocs.fetch_sub( 1, std::memory_order_relaxed ); }

	std::uint64_t get_total_cnt_accesses() const { return total_cnt_accesses.load( std::memory_order_relaxed ); };
	std::uint64_t get_total_allocs() const { return total_allocs.load( std::memory_order_relaxed ); };
	std::uint64_t get_current_allocs() const { return current_allocs.load( std::memory_order_relaxed ); };
	std::uint64_t get_inc_ref_cnt() const { return inc_ref_cnt.load( std::memory_order_relaxed ); };
	std::uint64_t get_dec_ref_cnt() const { return dec_ref_cnt.load( std::memory_order_relaxed ); };

	constexpr Stats() noexcept = default;
	Stats( const Stats& other )
		: total_cnt_accesses( other.total_cnt_accesses.load( std::memory_order_relaxed ) )
		, total_allocs( other.total_allocs.load( std::memory_order_relaxed ) )
		, current_allocs( other.current_allocs.load( std::memory_order_relaxed ) )
		, inc_ref_cnt( other.inc_ref_cnt.load( std::memory_order_relaxed ) )
		, dec_ref_cnt( other.dec_ref_cnt.load( std::memory_order_relaxed ) )
	{
	}

	void reset()
	{
		total_cnt_accesses = 0;
		total_allocs       = 0;
		current_allocs     = 0;
		inc_ref_cnt        = 0;
		dec_ref_cnt        = 0;
	}
};
#else
struct Stats {
	constexpr Stats() noexcept = default;

	constexpr void inc_ref() noexcept {}
	constexpr void dec_ref() noexcept {}
	constexpr void alloc() noexcept {}
	constexpr void dealloc() noexcept {}
	constexpr void reset() {};
};
#endif

static Stats& stats()
{
	static Stats stats {};
	return stats;
}

constexpr struct defer_ref_cnt_tag_t {
} defer_ref_cnt_tag;

// Note: std::exchange is not constexpr in c++17
template<class T, class U = T>
constexpr T c_expr_exchange( T& obj, U&& new_value )
{
	T old_value = std::move( obj );
	obj         = std::forward<U>( new_value );
	return old_value;
}

inline constexpr std::size_t c_expr_max( std::size_t l, std::size_t r )
{
	return l > r ? l : r;
}
inline constexpr std::size_t c_expr_aligned_offset( std::size_t alignment, std::size_t min )
{
	if( alignment >= min ) {
		return alignment;
	} else {
		return min + ( alignment - min % alignment );
	}
}

struct AllocResult;

/**
 * Note: Almost all of the member functions are labled constexpr.
 * However, they can only be used in a constexpr context of the
 * handle is default constructed (i.e. _cnt == nullptr)
 */
class atomic_ref_cnt_buffer {
	using Cnt_t     = std::atomic_int;
	using size_type = int;

public:
#if IM_STR_USE_ALLOC
	using alloc_t     = std::pmr::memory_resource;
	using alloc_ptr_t = alloc_t*;
#else
	using alloc_ptr_t = std::nullptr_t;
#endif
	/*#### Constructors and special member functions ######*/
	static AllocResult allocate_null_terminated_char_buffer( int size, alloc_ptr_t = nullptr );

	constexpr atomic_ref_cnt_buffer() noexcept = default;
	constexpr atomic_ref_cnt_buffer( const atomic_ref_cnt_buffer& other, defer_ref_cnt_tag_t ) noexcept
		: _cnt {other._cnt}
	{
	}

	constexpr atomic_ref_cnt_buffer( const atomic_ref_cnt_buffer& other ) noexcept
		: _cnt {other._cnt}
	{
		_incref();
	}
	constexpr atomic_ref_cnt_buffer( atomic_ref_cnt_buffer&& other ) noexcept
		: _cnt {c_expr_exchange( other._cnt, nullptr )}
	{
	}

	constexpr atomic_ref_cnt_buffer& operator=( const atomic_ref_cnt_buffer& other ) noexcept
	{
		// inc before dec to protect against dropping in self assignment
		other._incref();
		_decref();
		_cnt = other._cnt;
		return *this;
	}
	constexpr atomic_ref_cnt_buffer& operator=( atomic_ref_cnt_buffer&& other ) noexcept
	{
		assert( ( ( _cnt == nullptr ) || ( this != &other ) ) && "Move assignment to self is not allowed, if cnt!=0" );
		_decref();
		_cnt = c_expr_exchange( other._cnt, nullptr );
		return *this;
	}

	~atomic_ref_cnt_buffer() { _decref(); }

	friend constexpr void swap( atomic_ref_cnt_buffer& l, atomic_ref_cnt_buffer& r ) noexcept
	{
		// TODO: C++20 		std::swap( l._cnt, r._cnt );  (not yet constexpr)
		auto tmp = l._cnt;
		l._cnt   = r._cnt;
		r._cnt   = tmp;
	}
	/*#### API ######*/

	constexpr int add_ref_cnt( int cnt ) const
	{
		if( !_cnt ) {
			return 0;
		} else {
			stats().inc_ref();
			return _cnt->fetch_add( cnt, std::memory_order_relaxed ) + cnt;
		}
	}

	friend constexpr bool operator==( const atomic_ref_cnt_buffer& l, std::nullptr_t ) { return l._cnt == nullptr; }
	friend constexpr bool operator==( std::nullptr_t, const atomic_ref_cnt_buffer& r ) { return r._cnt == nullptr; }
	friend constexpr bool operator!=( const atomic_ref_cnt_buffer& l, std::nullptr_t ) { return l._cnt != nullptr; }
	friend constexpr bool operator!=( std::nullptr_t, const atomic_ref_cnt_buffer& r ) { return r._cnt != nullptr; }

private:
	struct Header {
		Cnt_t       ref_cnt;
		size_type   size;
		alloc_ptr_t alloc;
	};

	// This is used in allocate_null_terminated_char_buffer
	constexpr explicit atomic_ref_cnt_buffer( Header& buffer ) noexcept
		: _cnt( &( buffer.ref_cnt ) )
	{
	}

	static void dealloc_buffer( Header* ptr );

	constexpr void _decref() const noexcept
	{
		if( _cnt ) {
			stats().dec_ref();
			if( _cnt->fetch_sub( 1 ) == 1 ) {
				Header* header = static_cast<Header*>( static_cast<void*>( _cnt ) );
				dealloc_buffer( header );
			}
		}
	}

	constexpr void _incref() const noexcept
	{
		if( _cnt ) {
			stats().inc_ref();
			_cnt->fetch_add( 1, std::memory_order_relaxed );
		}
	}

	Cnt_t* _cnt = nullptr;

	static constexpr auto alignment = alignof( Header );
};

struct AllocResult {
	char*                 data;
	atomic_ref_cnt_buffer handle;
};

inline AllocResult atomic_ref_cnt_buffer::allocate_null_terminated_char_buffer( size_type size, alloc_ptr_t resource )
{
	assert( size >= 0 );
	stats().alloc();

	const auto total_size       = sizeof( Header ) + size + 1;

#if IM_STR_USE_ALLOC
	const bool bool_use_default = resource == nullptr;
	char* const start = (char*)( bool_use_default                //
									 ? std::malloc( total_size ) //
									 : resource->allocate( total_size, alignment ) );
#else
	char* const start = (char*)std::malloc( total_size );
#endif

	auto* const header_ptr = new( start ) Header {Cnt_t {1}, size_type {size}, resource};

	auto* const data_ptr = start + sizeof( Header ); // Start of string
	data_ptr[size]       = '\0';                     // zero terminate

	return {data_ptr, atomic_ref_cnt_buffer {*header_ptr}};
}

inline void atomic_ref_cnt_buffer::dealloc_buffer( Header* header )
{
	stats().dealloc();

#if IM_STR_USE_ALLOC
	alloc_ptr_t alloc = header->alloc;
	if( alloc == nullptr ) {
		std::free( header );
	} else {
		size_type size = header->size;
		alloc->deallocate( header, size, alignment );
	}
#else
	std::free( header );
#endif
}

#ifdef IM_STR_DEBUG_HOOKS
} // inline namespace debug_version
#endif

} // namespace mba::detail

#endif
<|endoftext|>