<commit_before>#include "localgame.h"
#include "dice.h"
#include "board.h"
#include "subjectblock.h"
#include <iostream>
#include <QDebug>
#include <QtGlobal>
#include <QMessageBox>

using namespace std;
using namespace LocalGameState;

LocalGame::LocalGame(){
    m_state = ROLL_DICE;
    player_queue = new PlayerQueue;
}

//Singleton methods
LocalGame * LocalGame::m_inst = NULL;

LocalGame * LocalGame::getInst(){
    if(m_inst == NULL){
        m_inst = new LocalGame;
    }

    return m_inst;
}

void LocalGame::delInst(){
    if(m_inst != NULL){
        delete m_inst;
        m_inst = NULL;
    }
}

void LocalGame::addPlayer(Player *new_player){
    player_queue->push(new_player);
    nPlayers++;
    emit new_player->disable();
    connect(new_player,SIGNAL(playerArrived(Player*)),this,SLOT(playerEvent(Player*)));
}

void LocalGame::init(Board * board, Dice * dice){
    m_current_player = player_queue->next();
    Q_CHECK_PTR(m_current_player);
    emit m_current_player->activate();
    m_board = board;
    m_dice = dice;
    nPlayers = 0;
    connect(m_dice,SIGNAL(diceRolled(Dice*)),this,SLOT(diceEvent(Dice*)));
}

Board* LocalGame::getBoard(){
    return m_board;
}

void LocalGame::setBoard(Board *board){
    m_board = board;
}

Dice* LocalGame::getDice(){
    return m_dice;
}

void LocalGame::setDice(Dice * dice){
    m_dice = dice;
}

Player* LocalGame::getCurrentPlayer(){
    return m_current_player;
}

LocalGameState::State LocalGame::getGameState(){
    return m_state;
}

void LocalGame::setGameState(State new_state){
    m_state = new_state;
}

void LocalGame::turnOver(){
    //switch current player to next player and change state
    if(m_current_player->checkWinStatus()){
        //TODO: need to emit signal to notify gameover
        winner = m_current_player;
        qDebug() << "winner! player:" << winner->getId();
        m_state = GAME_OVER;
        return;
    }
    if(m_current_player->isBankrupt()){
        nPlayers--;
        if(nPlayers == 1) {
            winner = player_queue->next();
            qDebug() << "winner! player:" << winner->getId();
            m_state = GAME_OVER;
            return;
        }
    }
    //should never happen
    Q_ASSERT(nPlayers != 1);
    //update current Player if dice is not double
    emit m_current_player->disable();
    if(!Dice::getInst()->isDouble()){
        do {
            m_current_player = player_queue->next();
        } while(m_current_player->isBankrupt());
    }
    emit m_current_player->activate();
    m_state = ROLL_DICE;
}

void LocalGame::diceEvent(Dice * dice){
    qDebug() << "dice event caught by localgame";
    if(m_state == ROLL_DICE){
        if(m_current_player->isMobile()){
            m_current_player->walkBy(dice->getValue());
        }
        else{
            if(dice->isDouble()){
                m_current_player->setMobile(true);
                m_current_player->walkBy(dice->getValue());
            }
            else{
                m_current_player->escapeAttempt(); //decreases one immobile penalty
                turnOver();
            }
        }
    }
}

void LocalGame::blockEvent(Block *block){
    qDebug() << "block event caught:" << block->getPosition();
    QMessageBox warn_box;
    warn_box.setStandardButtons(QMessageBox::Ok);
    warn_box.setDefaultButton(QMessageBox::Ok);
    if(m_state == JUMP_PLAYER){
        m_current_player->jumpTo(block->getPosition());
    }
    //drink event
    if(m_state == EVENT_DRINK){
        if (block->getPosition() != 20 && block->getPosition() != 4){
            //not a valid location to jump.
            warn_box.setWindowTitle(QString("이벤트: 음주"));
            warn_box.setText(QString("불금칸으로만 갈 수 있어요!"));
            warn_box.exec();
        }
        else{
            m_current_player->jumpTo(block->getPosition());
        }
    }
    //take subject event
    if(m_state == EVENT_TAKE_SUBJECT){
        if(block->getType() == BlockType::SUBJECT){
            m_current_player->addBlock(block);
            SubjectBlock * subj = dynamic_cast<SubjectBlock*>(block);
            subj->decideGrade();
            LocalGame::getInst()->turnOver();
        }
        else{
            warn_box.setWindowTitle("이벤트: 과목 수강");
            warn_box.setText("과목 블럭을 선택해 주세요!");
            warn_box.exec();
        }
    }

    if(m_state == EVENT_LOSE_SUBJECT){
        if(block->getType() == BlockType::SUBJECT){
            m_current_player->removeBlock(block);
            LocalGame::getInst()->turnOver();
        }
        else{
            warn_box.setWindowTitle("이벤트: 과목 포기");
            warn_box.setText("과목 블럭을 선택해 주세요!");
            warn_box.exec();
        }
    }
}

void LocalGame::playerEvent(Player *player){
    qDebug() << "signal emmited by Player" << player->getId();
    if(m_state == PLAYER_MOVING){
        qDebug() << "Player in block!";
        int position = player->getPosition();
        Block * cur_block = m_board->getBlock(position);
        cur_block->enter(player);
    }
}

void LocalGame::boardEvent(Board *board){

}
<commit_msg>Eventblock,Localgame: subjectblock take/lose event cheat blocked<commit_after>#include "localgame.h"
#include "dice.h"
#include "board.h"
#include "subjectblock.h"
#include <iostream>
#include <QDebug>
#include <QtGlobal>
#include <QMessageBox>

using namespace std;
using namespace LocalGameState;

LocalGame::LocalGame(){
    m_state = ROLL_DICE;
    player_queue = new PlayerQueue;
}

//Singleton methods
LocalGame * LocalGame::m_inst = NULL;

LocalGame * LocalGame::getInst(){
    if(m_inst == NULL){
        m_inst = new LocalGame;
    }

    return m_inst;
}

void LocalGame::delInst(){
    if(m_inst != NULL){
        delete m_inst;
        m_inst = NULL;
    }
}

void LocalGame::addPlayer(Player *new_player){
    player_queue->push(new_player);
    nPlayers++;
    emit new_player->disable();
    connect(new_player,SIGNAL(playerArrived(Player*)),this,SLOT(playerEvent(Player*)));
}

void LocalGame::init(Board * board, Dice * dice){
    m_current_player = player_queue->next();
    Q_CHECK_PTR(m_current_player);
    emit m_current_player->activate();
    m_board = board;
    m_dice = dice;
    nPlayers = 0;
    connect(m_dice,SIGNAL(diceRolled(Dice*)),this,SLOT(diceEvent(Dice*)));
}

Board* LocalGame::getBoard(){
    return m_board;
}

void LocalGame::setBoard(Board *board){
    m_board = board;
}

Dice* LocalGame::getDice(){
    return m_dice;
}

void LocalGame::setDice(Dice * dice){
    m_dice = dice;
}

Player* LocalGame::getCurrentPlayer(){
    return m_current_player;
}

LocalGameState::State LocalGame::getGameState(){
    return m_state;
}

void LocalGame::setGameState(State new_state){
    m_state = new_state;
}

void LocalGame::turnOver(){
    //switch current player to next player and change state
    if(m_current_player->checkWinStatus()){
        //TODO: need to emit signal to notify gameover
        winner = m_current_player;
        qDebug() << "winner! player:" << winner->getId();
        m_state = GAME_OVER;
        return;
    }
    if(m_current_player->isBankrupt()){
        nPlayers--;
        if(nPlayers == 1) {
            winner = player_queue->next();
            qDebug() << "winner! player:" << winner->getId();
            m_state = GAME_OVER;
            return;
        }
    }
    //should never happen
    Q_ASSERT(nPlayers != 1);
    //update current Player if dice is not double
    emit m_current_player->disable();
    if(!Dice::getInst()->isDouble()){
        do {
            m_current_player = player_queue->next();
        } while(m_current_player->isBankrupt());
    }
    emit m_current_player->activate();
    m_state = ROLL_DICE;
}

void LocalGame::diceEvent(Dice * dice){
    qDebug() << "dice event caught by localgame";
    if(m_state == ROLL_DICE){
        if(m_current_player->isMobile()){
            m_current_player->walkBy(dice->getValue());
        }
        else{
            if(dice->isDouble()){
                m_current_player->setMobile(true);
                m_current_player->walkBy(dice->getValue());
            }
            else{
                m_current_player->escapeAttempt(); //decreases one immobile penalty
                turnOver();
            }
        }
    }
}

void LocalGame::blockEvent(Block *block){
    qDebug() << "block event caught:" << block->getPosition();
    QMessageBox warn_box;
    warn_box.setStandardButtons(QMessageBox::Ok);
    warn_box.setDefaultButton(QMessageBox::Ok);
    if(m_state == JUMP_PLAYER){
        m_current_player->jumpTo(block->getPosition());
    }
    //drink event
    if(m_state == EVENT_DRINK){
        warn_box.setWindowTitle(QString("이벤트: 음주"));
        if (block->getPosition() != 20 && block->getPosition() != 4){
            //not a valid location to jump.
            warn_box.setText(QString("불금칸으로만 갈 수 있어요!"));
            warn_box.exec();
        }
        else
            m_current_player->jumpTo(block->getPosition());
    }

    //take subject event
    if(m_state == EVENT_TAKE_SUBJECT){
        warn_box.setWindowTitle(QString("이벤트: 과목 수강"));
        if(block->getType() == BlockType::SUBJECT){
            SubjectBlock * subject_block = dynamic_cast<SubjectBlock*>(block);
            if(subject_block->getOwner() != NULL){
                warn_box.setText(QString("아무도 수강하지 않은 블록을 선택해 주세요!"));
                warn_box.exec();
            }
            else {
                m_current_player->addBlock(block);
                subject_block->decideGrade();
                LocalGame::getInst()->turnOver();
            }
        }
        else{
            warn_box.setText("과목 블럭을 선택해 주세요!");
            warn_box.exec();
        }
    }

    if(m_state == EVENT_LOSE_SUBJECT){
        warn_box.setWindowTitle(QString("이벤트: 과목 포기"));
        if(block->getType() == BlockType::SUBJECT){
            SubjectBlock * subject_block = dynamic_cast<SubjectBlock*>(block);
            if(subject_block->getOwner() != m_current_player){

                warn_box.setText(QString("자신이 수강한 과목을 선택해 주세요!"));
                warn_box.exec();
            }
            else {
                m_current_player->removeBlock(block);
                LocalGame::getInst()->turnOver();
            }
        }
        else {
            warn_box.setText("과목 블럭을 선택해 주세요!");
            warn_box.exec();
        }
    }
}

void LocalGame::playerEvent(Player *player){
    if(m_state == PLAYER_MOVING){
        qDebug() << "Player in block!";
        int position = player->getPosition();
        Block * cur_block = m_board->getBlock(position);
        cur_block->enter(player);
    }
}

void LocalGame::boardEvent(Board *board){

}
<|endoftext|>


<commit_before>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int bit_mode_8 {8};
  constexpr unsigned int channels_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  if (bits == bit_mode_8)
    {
      if (master_length <= (channels_16 - 1) * thr) {
        thr = (master_length + channels_16 - 1) / channels_16;
      }
    }
  else
    {
      if (master_length <= (channels_8 - 1) * thr) {
        thr = (master_length + channels_8 - 1) / channels_8;
      }
    }

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<commit_msg>mark parameter as const when possible<commit_after>/*
    SWARM

    Copyright (C) 2012-2022 Torbjorn Rognes and Frederic Mahe

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Contact: Torbjorn Rognes <torognes@ifi.uio.no>,
    Department of Informatics, University of Oslo,
    PO Box 1080 Blindern, NO-0316 Oslo, Norway
*/

#include "swarm.h"
#include "db.h"
#include "search8.h"
#include "search16.h"
#include "threads.h"

static pthread_mutex_t scan_mutex;

static ThreadRunner * search_threads = nullptr;

struct search_data
{
  BYTE ** qtable;
  WORD ** qtable_w;

  BYTE * dprofile;
  WORD * dprofile_w;

  BYTE * hearray;

  uint64_t * dir_array;

  uint64_t target_count;
  uint64_t target_index;
};

static struct search_data * sd;
static uint64_t master_next;
static uint64_t master_length;
static uint64_t remainingchunks;
static uint64_t * master_targets;
static uint64_t * master_scores;
static uint64_t * master_diffs;
static uint64_t * master_alignlengths;
static int master_bits;
static uint64_t dirbufferbytes;

queryinfo_t query;
uint64_t longestdbsequence;

void search_alloc(struct search_data * sdp)
{
  constexpr unsigned int one_kilobyte {1024};
  constexpr unsigned int nt_per_uint64 {32};
  constexpr unsigned int bytes_per_uint64 {8};

  dirbufferbytes =
    bytes_per_uint64 * longestdbsequence * ((longestdbsequence + 3) / 4) * 4;
  sdp->qtable = new BYTE*[longestdbsequence];
  sdp->qtable_w = new WORD*[longestdbsequence];
  sdp->dprofile = new BYTE[2 * one_kilobyte];  // 4 * 16 * 32
  sdp->dprofile_w = new WORD[2 * one_kilobyte];  // 4 * 2 * 8 * 32
  sdp->hearray = new BYTE[longestdbsequence * nt_per_uint64] { };
  sdp->dir_array = new uint64_t[dirbufferbytes] { };
}

void search_free(struct search_data * sdp)
{
  delete [] sdp->qtable;
  sdp->qtable = nullptr;
  delete [] sdp->qtable_w;
  sdp->qtable_w = nullptr;
  delete [] sdp->dprofile;
  sdp->dprofile = nullptr;
  delete [] sdp->dprofile_w;
  sdp->dprofile_w = nullptr;
  delete [] sdp->hearray;
  sdp->hearray = nullptr;
  delete [] sdp->dir_array;
  sdp->dir_array = nullptr;
}

void search_init(struct search_data * sdp)
{
  constexpr int byte_multiplier {64};
  constexpr int word_multiplier {32};

  for(auto i = 0U; i < query.len; i++)
  {
    int nt_value {nt_extract(query.seq, i) + 1};   // 1,  2,   3, or   4
    int byte_offset {byte_multiplier * nt_value};  // 1, 64, 128, or 192
    int word_offset {word_multiplier * nt_value};  // 1, 32,  64, or 128

    sdp->qtable[i]   = sdp->dprofile   + byte_offset;
    sdp->qtable_w[i] = sdp->dprofile_w + word_offset;
  }
}

void search_chunk(struct search_data * sdp, const int64_t bits)
{
  constexpr unsigned int bit_mode_16 {16};
  if (sdp->target_count == 0) {
    return;
  }

 if (bits == bit_mode_16)
   {
    search16(sdp->qtable_w,
             static_cast<WORD>(penalty_gapopen),
             static_cast<WORD>(penalty_gapextend),
             static_cast<WORD*>(score_matrix_16),
             sdp->dprofile_w,
             reinterpret_cast<WORD*>(sdp->hearray),
             sdp->target_count,
             master_targets + sdp->target_index,
             master_scores + sdp->target_index,
             master_diffs + sdp->target_index,
             master_alignlengths + sdp->target_index,
             static_cast<uint64_t>(query.len),
             dirbufferbytes / sizeof(uint64_t),
             sdp->dir_array,
             longestdbsequence);
   }
 else {
    search8(sdp->qtable,
            static_cast<BYTE>(penalty_gapopen),
            static_cast<BYTE>(penalty_gapextend),
            static_cast<BYTE*>(score_matrix_8),
            sdp->dprofile,
            sdp->hearray,
            sdp->target_count,
            master_targets + sdp->target_index,
            master_scores + sdp->target_index,
            master_diffs + sdp->target_index,
            master_alignlengths + sdp->target_index,
            static_cast<uint64_t>(query.len),
            dirbufferbytes / sizeof(uint64_t),
            sdp->dir_array,
            longestdbsequence);
 }
}

auto search_getwork(uint64_t * countref, uint64_t * firstref) -> bool
{
  // * countref = how many sequences to search
  // * firstref = index into master_targets/scores/diffs where thread should start

  bool status {false};

  pthread_mutex_lock(&scan_mutex);

  if (master_next < master_length)
    {
      uint64_t chunksize =
        ((master_length - master_next + remainingchunks - 1) / remainingchunks);

      * countref = chunksize;
      * firstref = master_next;

      master_next += chunksize;
      remainingchunks--;
      status = true;
    }

  pthread_mutex_unlock(&scan_mutex);

  return status;
}

void search_worker_core(int64_t t)
{
  search_init(sd + t);
  while(search_getwork(& sd[t].target_count, & sd[t].target_index)) {
    search_chunk(sd + t, master_bits);
  }
}

void search_do(uint64_t query_no,
               uint64_t listlength,
               uint64_t * targets,
               uint64_t * scores,
               uint64_t * diffs,
               uint64_t * alignlengths,
               int bits)
{
  // constexpr unsigned int bit_mode_16 {16};
  constexpr unsigned int channels_8 {8};
  constexpr unsigned int bit_mode_8 {8};
  constexpr unsigned int channels_16 {16};
  query.qno = query_no;
  unsigned int query_len = 0;
  db_getsequenceandlength(query_no, &query.seq, &query_len);
  query.len = query_len;

  master_next = 0;
  master_length = listlength;
  master_targets = targets;
  master_scores = scores;
  master_diffs = diffs;
  master_alignlengths = alignlengths;
  master_bits = bits;

  auto thr = static_cast<uint64_t>(opt_threads);

  if (bits == bit_mode_8)
    {
      if (master_length <= (channels_16 - 1) * thr) {
        thr = (master_length + channels_16 - 1) / channels_16;
      }
    }
  else
    {
      if (master_length <= (channels_8 - 1) * thr) {
        thr = (master_length + channels_8 - 1) / channels_8;
      }
    }

  remainingchunks = thr;

  if (thr == 1) {
    search_worker_core(0);
  }
  else {
    search_threads->run();
  }
}

void search_begin()
{
  longestdbsequence = db_getlongestsequence();

  sd = new struct search_data[static_cast<uint64_t>(opt_threads)];

  for(auto t = 0LL; t < opt_threads; t++) {
    search_alloc(sd+t);
  }

  pthread_mutex_init(& scan_mutex, nullptr);

  /* start threads */

  search_threads
    = new ThreadRunner(static_cast<int>(opt_threads), search_worker_core);
}

void search_end()
{
  /* finish and clean up worker threads */

  delete search_threads;
  search_threads = nullptr;

  pthread_mutex_destroy(& scan_mutex);

  for(auto t = 0LL; t < opt_threads; t++) {
    search_free(sd+t);
  }
  delete [] sd;
  sd = nullptr;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2016, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <conwrap/ConcurrentQueue.hpp>
#include <conwrap/Epoch.hpp>
#include <conwrap/HandlerWrapper.hpp>
#include <conwrap/Processor.hpp>
#include <conwrap/Provider.hpp>
#include <conwrap/Task.hpp>
#include <conwrap/TaskProxy.hpp>
#include <memory>
#include <thread>

namespace conwrap
{
	// forward declaration
	template <typename ResourceType>
	class ProcessorQueue;
	template <typename ResourceType>
	class ProcessorQueueProxy;

	namespace internal
	{
		template <typename ResourceType>
		class ProcessorQueueImpl : public Processor<ResourceType>
		{
			// friend declaration
			template <typename> friend class conwrap::ProcessorQueue;
			template <typename> friend class conwrap::ProcessorQueueProxy;

			public:
				ProcessorQueueImpl(std::unique_ptr<ResourceType> r)
				: resourcePtr(std::move(r))
				, nextEpoch(1)
				, currentEpoch(0) {}

				virtual ~ProcessorQueueImpl() {}

				virtual void flush() override
				{
					// figuring out next epoch value
					auto currentEpoch = this->process([&]() -> auto
					{
						return getNextEpoch();
					}).getResult();

					// waiting for all 'child' handlers to be processed
					while (childExists(currentEpoch))
					{
						// TODO: insert flush handler after the last child instead of adding at the end of the queue
						this->process([=] {}).wait();
					}
				}

				virtual ResourceType* getResource() override
				{
					return resourcePtr.get();
				}

			protected:
				bool childExists(conwrap::Epoch currentEpoch)
				{
					auto found = false;

					for (auto& h : queue)
					{
						auto epoch = h.getEpoch();
						if (h.getProxy() && 0 < epoch && epoch < currentEpoch)
						{
							found = true;
							break;
						}
					}
					return found;
				}

				inline auto getNextEpoch()
				{
					return nextEpoch;
				}

				virtual Provider<ResourceType, Task>* getProvider() override
				{
					return providerPtr.get();
				}

				inline Provider<ResourceType, TaskProxy>* getProviderProxy()
				{
					return providerProxyPtr.get();
				}

				virtual void post(HandlerWrapper handlerWrapper) override
				{
					queue.push(handlerWrapper);
				}

				inline void setProvider(Provider<ResourceType, Task> t)
				{
					providerPtr = std::make_unique<Provider<ResourceType, Task>>(t);
				}

				inline void setProviderProxy(Provider<ResourceType, TaskProxy> t)
				{
					providerProxyPtr = std::make_unique<Provider<ResourceType, TaskProxy>>(t);
				}

				void start()
				{
					{
						std::lock_guard<std::mutex> guard(threadLock);

						if (!thread.joinable())
						{
							thread = std::thread([&]
							{
								for(finished = false; !(queue.empty() && finished);)
								{
									// waiting for a handler
									auto handler = queue.front();

									// setting current epoch to be used for submitted tasks via processor proxy
									currentEpoch = handler.getEpoch();

									// executing handler
									handler();

									// removing executed item
									queue.pop();
								}
							});
						}
					}
				}

				void stop()
				{
					{
						std::lock_guard<std::mutex> guard(threadLock);

						if (thread.joinable())
						{
							this->process([&]
							{
								finished = true;
							});

							// waiting until consumer finsihes all pending handlers
							thread.join();
						}
					}
				}

				virtual HandlerWrapper wrapHandler(std::function<void()> handler) override
				{
					return wrapHandler(handler, false);
				}

				virtual HandlerWrapper wrapHandler(std::function<void()> handler, bool proxy) override
				{
					// TODO: MAX case must be handled
					return HandlerWrapper(handler, proxy, (proxy ? currentEpoch : nextEpoch++));
				}

			private:
				std::unique_ptr<ResourceType>                      resourcePtr;
				std::unique_ptr<Provider<ResourceType, Task>>      providerPtr;
				std::unique_ptr<Provider<ResourceType, TaskProxy>> providerProxyPtr;
				ConcurrentQueue<HandlerWrapper>                    queue;
				std::thread                                        thread;
				std::mutex                                         threadLock;
				bool                                               finished;
				conwrap::Epoch                                     nextEpoch;
				conwrap::Epoch                                     currentEpoch;
		};
	}
}
<commit_msg>Minor change<commit_after>/*
 * Copyright 2016, Andrej Kislovskij
 *
 * This is PUBLIC DOMAIN software so use at your own risk as it comes
 * with no warranties. This code is yours to share, use and modify without
 * any restrictions or obligations.
 *
 * For more information see conwrap/LICENSE or refer refer to http://unlicense.org
 *
 * Author: gimesketvirtadieni at gmail dot com (Andrej Kislovskij)
 */

#pragma once

#include <conwrap/ConcurrentQueue.hpp>
#include <conwrap/Epoch.hpp>
#include <conwrap/HandlerWrapper.hpp>
#include <conwrap/Processor.hpp>
#include <conwrap/Provider.hpp>
#include <conwrap/Task.hpp>
#include <conwrap/TaskProxy.hpp>
#include <memory>
#include <thread>

namespace conwrap
{
	// forward declaration
	template <typename ResourceType>
	class ProcessorQueue;
	template <typename ResourceType>
	class ProcessorQueueProxy;

	namespace internal
	{
		template <typename ResourceType>
		class ProcessorQueueImpl : public Processor<ResourceType>
		{
			// friend declaration
			template <typename> friend class conwrap::ProcessorQueue;
			template <typename> friend class conwrap::ProcessorQueueProxy;

			public:
				ProcessorQueueImpl(std::unique_ptr<ResourceType> r)
				: resourcePtr(std::move(r))
				, nextEpoch(1)
				, currentEpoch(0) {}

				virtual ~ProcessorQueueImpl() {}

				virtual void flush() override
				{
					// figuring out next epoch value
					auto currentEpoch = this->process([&]() -> auto
					{
						return getNextEpoch();
					}).getResult();

					// waiting for all 'child' handlers to be processed
					while (childExists(currentEpoch))
					{
						// TODO: insert flush handler after the last child instead of adding at the end of the queue
						this->process([=] {}).wait();
					}
				}

				virtual ResourceType* getResource() override
				{
					return resourcePtr.get();
				}

			protected:
				bool childExists(conwrap::Epoch currentEpoch)
				{
					auto found = false;

					for (auto& h : queue)
					{
						auto epoch = h.getEpoch();
						if (h.getProxy() && 0 < epoch && epoch < currentEpoch)
						{
							found = true;
							break;
						}
					}
					return found;
				}

				inline auto getNextEpoch()
				{
					return nextEpoch;
				}

				virtual Provider<ResourceType, Task>* getProvider() override
				{
					return providerPtr.get();
				}

				inline Provider<ResourceType, TaskProxy>* getProviderProxy()
				{
					return providerProxyPtr.get();
				}

				virtual void post(HandlerWrapper handlerWrapper) override
				{
					queue.push(handlerWrapper);
				}

				inline void setProvider(Provider<ResourceType, Task> t)
				{
					providerPtr = std::make_unique<Provider<ResourceType, Task>>(t);
				}

				inline void setProviderProxy(Provider<ResourceType, TaskProxy> t)
				{
					providerProxyPtr = std::make_unique<Provider<ResourceType, TaskProxy>>(t);
				}

				void start()
				{
					{
						std::lock_guard<std::mutex> guard(threadLock);

						if (!thread.joinable())
						{
							thread = std::thread([&]
							{
								for(finished = false; !(queue.empty() && finished);)
								{
									// waiting for a handler
									auto handler = queue.front();

									// setting current epoch to be used for submitted tasks via processor proxy
									currentEpoch = handler.getEpoch();

									// executing handler
									handler();

									// removing executed item
									queue.pop();
								}
							});
						}
					}
				}

				void stop()
				{
					{
						std::lock_guard<std::mutex> guard(threadLock);

						if (thread.joinable())
						{
							this->process([&]
							{
								finished = true;
							});

							// waiting until consumer finsihes all pending handlers
							thread.join();
						}
					}
				}

				virtual HandlerWrapper wrapHandler(std::function<void()> handler) override
				{
					return wrapHandler(handler, false);
				}

				virtual HandlerWrapper wrapHandler(std::function<void()> handler, bool proxy) override
				{
					return HandlerWrapper(handler, proxy, (proxy ? currentEpoch : nextEpoch++));
				}

			private:
				std::unique_ptr<ResourceType>                      resourcePtr;
				std::unique_ptr<Provider<ResourceType, Task>>      providerPtr;
				std::unique_ptr<Provider<ResourceType, TaskProxy>> providerProxyPtr;
				ConcurrentQueue<HandlerWrapper>                    queue;
				std::thread                                        thread;
				std::mutex                                         threadLock;
				bool                                               finished;
				conwrap::Epoch                                     nextEpoch;
				conwrap::Epoch                                     currentEpoch;
		};
	}
}
<|endoftext|>


<commit_before>#ifndef SPLITTER_CUT_HPP
#define SPLITTER_CUT_HPP

#include <geos/io/WKTWriter.h>
#include <osmium/handler/progress.hpp>
#include <osmium/output.hpp>
#include "geometryreader.hpp"
#include "growing_bitset.hpp"

// information about a single extract
class ExtractInfo {

public:
    enum ExtractMode {
        LOCATOR = 1,
        BOUNDS = 2
    };

    std::string name;
    geos::algorithm::locate::IndexedPointInAreaLocator *locator;
    Osmium::OSM::Bounds bounds;
    Osmium::Output::Base *writer;
    ExtractMode mode;

    ExtractInfo(std::string name) : locator(NULL), writer(NULL) {
        this->name = name;
    }

    ~ExtractInfo() {
        if(locator) delete locator;
        if(writer) delete writer;
    }

    bool contains(const shared_ptr<Osmium::OSM::Node const>& node) {
        if(mode == BOUNDS) {
            return
                (node->lon() > bounds.bl().lon()) &&
                (node->lat() > bounds.bl().lat()) &&
                (node->lon() < bounds.tr().lon()) &&
                (node->lat() < bounds.tr().lat());
        }
        else if(mode == LOCATOR) {
            // BOUNDARY 1
            // EXTERIOR 2
            // INTERIOR 0

            geos::geom::Coordinate c = geos::geom::Coordinate(node->lon(), node->lat(), DoubleNotANumber);
            return (0 == locator->locate(&c));
        }

        return false;
    }
};

// information about the cutting algorithm
template <class TExtractInfo>
class CutInfo {

protected:
    ~CutInfo() {
        for(int i=0, l = extracts.size(); i<l; i++) {
            extracts[i]->writer->final();
            delete extracts[i];
        }
    }

public:
    std::vector<TExtractInfo*> extracts;

    TExtractInfo *addExtract(std::string name, double minlon, double minlat, double maxlon, double maxlat) {
        fprintf(stderr, "opening writer for %s\n", name.c_str());
        Osmium::OSMFile outfile(name);
        Osmium::Output::Base *writer = Osmium::Output::Factory::instance().create_output(outfile);

        const Osmium::OSM::Position min(minlat, minlon);
        const Osmium::OSM::Position max(maxlat, maxlon);

        Osmium::OSM::Bounds bounds;
        bounds.extend(min).extend(max);

        Osmium::OSM::Meta meta(bounds);
        writer->init(meta);

        TExtractInfo *ex = new TExtractInfo(name);
        ex->writer = writer;
        ex->bounds = bounds;
        ex->mode = ExtractInfo::BOUNDS;

        extracts.push_back(ex);
        return ex;
    }

    TExtractInfo *addExtract(std::string name, geos::geom::Geometry *poly) {
        fprintf(stderr, "opening writer for %s\n", name.c_str());
        Osmium::OSMFile outfile(name);
        Osmium::Output::Base *writer = Osmium::Output::Factory::instance().create_output(outfile);

        const geos::geom::Envelope *env = poly->getEnvelopeInternal();
        const Osmium::OSM::Position min(env->getMinX(), env->getMinY());
        const Osmium::OSM::Position max(env->getMaxX(), env->getMaxY());

        Osmium::OSM::Bounds bounds;
        bounds.extend(min).extend(max);

        Osmium::OSM::Meta meta(bounds);
        writer->init(meta);

        TExtractInfo *ex = new TExtractInfo(name);
        ex->writer = writer;
        ex->locator = new geos::algorithm::locate::IndexedPointInAreaLocator(*poly);
        ex->mode = ExtractInfo::LOCATOR;

        Osmium::Geometry::geos_geometry_factory()->destroyGeometry(poly);

        extracts.push_back(ex);
        return ex;
    }
};

template <class TCutInfo>
class Cut : public Osmium::Handler::Base {

protected:

    Osmium::Handler::Progress pg;
    TCutInfo *info;

public:

    bool debug;
    Cut(TCutInfo *info) : info(info) {}
};

#endif // SPLITTER_CUT_HPP

<commit_msg>Adapt to osmium api change: bounds.bl is now bounds.bottom_left, etc<commit_after>#ifndef SPLITTER_CUT_HPP
#define SPLITTER_CUT_HPP

#include <geos/io/WKTWriter.h>
#include <osmium/handler/progress.hpp>
#include <osmium/output.hpp>
#include "geometryreader.hpp"
#include "growing_bitset.hpp"

// information about a single extract
class ExtractInfo {

public:
    enum ExtractMode {
        LOCATOR = 1,
        BOUNDS = 2
    };

    std::string name;
    geos::algorithm::locate::IndexedPointInAreaLocator *locator;
    Osmium::OSM::Bounds bounds;
    Osmium::Output::Base *writer;
    ExtractMode mode;

    ExtractInfo(std::string name) : locator(NULL), writer(NULL) {
        this->name = name;
    }

    ~ExtractInfo() {
        if(locator) delete locator;
        if(writer) delete writer;
    }

    bool contains(const shared_ptr<Osmium::OSM::Node const>& node) {
        if(mode == BOUNDS) {
            return
                (node->lon() > bounds.bottom_left().lon()) &&
                (node->lat() > bounds.bottom_left().lat()) &&
                (node->lon() < bounds.top_right().lon()) &&
                (node->lat() < bounds.top_right().lat());
        }
        else if(mode == LOCATOR) {
            // BOUNDARY 1
            // EXTERIOR 2
            // INTERIOR 0

            geos::geom::Coordinate c = geos::geom::Coordinate(node->lon(), node->lat(), DoubleNotANumber);
            return (0 == locator->locate(&c));
        }

        return false;
    }
};

// information about the cutting algorithm
template <class TExtractInfo>
class CutInfo {

protected:
    ~CutInfo() {
        for(int i=0, l = extracts.size(); i<l; i++) {
            extracts[i]->writer->final();
            delete extracts[i];
        }
    }

public:
    std::vector<TExtractInfo*> extracts;

    TExtractInfo *addExtract(std::string name, double minlon, double minlat, double maxlon, double maxlat) {
        fprintf(stderr, "opening writer for %s\n", name.c_str());
        Osmium::OSMFile outfile(name);
        Osmium::Output::Base *writer = Osmium::Output::Factory::instance().create_output(outfile);

        const Osmium::OSM::Position min(minlat, minlon);
        const Osmium::OSM::Position max(maxlat, maxlon);

        Osmium::OSM::Bounds bounds;
        bounds.extend(min).extend(max);

        Osmium::OSM::Meta meta(bounds);
        writer->init(meta);

        TExtractInfo *ex = new TExtractInfo(name);
        ex->writer = writer;
        ex->bounds = bounds;
        ex->mode = ExtractInfo::BOUNDS;

        extracts.push_back(ex);
        return ex;
    }

    TExtractInfo *addExtract(std::string name, geos::geom::Geometry *poly) {
        fprintf(stderr, "opening writer for %s\n", name.c_str());
        Osmium::OSMFile outfile(name);
        Osmium::Output::Base *writer = Osmium::Output::Factory::instance().create_output(outfile);

        const geos::geom::Envelope *env = poly->getEnvelopeInternal();
        const Osmium::OSM::Position min(env->getMinX(), env->getMinY());
        const Osmium::OSM::Position max(env->getMaxX(), env->getMaxY());

        Osmium::OSM::Bounds bounds;
        bounds.extend(min).extend(max);

        Osmium::OSM::Meta meta(bounds);
        writer->init(meta);

        TExtractInfo *ex = new TExtractInfo(name);
        ex->writer = writer;
        ex->locator = new geos::algorithm::locate::IndexedPointInAreaLocator(*poly);
        ex->mode = ExtractInfo::LOCATOR;

        Osmium::Geometry::geos_geometry_factory()->destroyGeometry(poly);

        extracts.push_back(ex);
        return ex;
    }
};

template <class TCutInfo>
class Cut : public Osmium::Handler::Base {

protected:

    Osmium::Handler::Progress pg;
    TCutInfo *info;

public:

    bool debug;
    Cut(TCutInfo *info) : info(info) {}
};

#endif // SPLITTER_CUT_HPP

<|endoftext|>


<commit_before>#ifndef GNR_MANY_HPP
# define GNR_MANY_HPP
# pragma once

#include <cstddef>

#include <tuple>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace detail
{

namespace many
{

enum TupleValue { Scalar, Reference, Class };

template <std::size_t I,
  class T,
  TupleValue = std::is_class<T>{} ?
    TupleValue::Class :
    std::is_reference<T>{} ?
      TupleValue::Reference :
      TupleValue::Scalar
>
struct tuple_base
{
  T value;

  tuple_base() = default;

  template <typename A>
  constexpr tuple_base(A&& value) : value{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base&&) = default;
  tuple_base(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
};

template <std::size_t I, class T>
struct tuple_base<I, T, TupleValue::Reference>
{
  T value;

  tuple_base() = delete;

  template <typename A>
  constexpr tuple_base(A&& value) : value{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base&&) = default;
  tuple_base(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
};

template <std::size_t I, class T>
struct tuple_base<I, T, TupleValue::Class> : T
{
  tuple_base() = default;

  template <typename A>
  constexpr tuple_base(A&& value) : T{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base&&) = default;
  tuple_base(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
};

template <std::size_t I, class T, enum detail::many::TupleValue E>
auto& get(tuple_base<I, T, E> const& obj) noexcept
{
  return obj.value;
}

template <std::size_t I, class T>
auto get(tuple_base<I, T, TupleValue::Class>& obj) noexcept -> T&
{
  return obj;
}

template <std::size_t I, class T>
auto get(tuple_base<I, T, TupleValue::Class> const& obj) noexcept -> T const&
{
  return obj;
}

template <typename ...>
struct many_impl;

template <std::size_t... Is, typename ...Types>
struct many_impl<std::index_sequence<Is...>, Types...> :
  tuple_base<Is, Types>...
{
  many_impl() = default;
  ~many_impl() = default;
  many_impl(many_impl&&) = default;
  many_impl(many_impl const&) = default;
  many_impl& operator=(many_impl&&) = default;
  many_impl& operator=(many_impl const&) = default;

#if !__cpp_aggregate_bases
  template<typename ...U>
  constexpr many_impl(U&& ...u) :
    tuple_base<Is, Types>{std::forward<U>(u)}...
  {
  }
#endif
};

}

}

template <typename ...Types>
struct many : detail::many::many_impl<
  std::make_index_sequence<sizeof...(Types)>,
  Types...
>
{
  many() = default;
  ~many() = default;
  many(many&&) = default;
  many(many const&) = default;
  many& operator=(many&&) = default;
  many& operator=(many const&) = default;

#if !__cpp_aggregate_bases
  template <class... U>
  constexpr many(U&& ...u) : many::many_impl{std::forward<U>(u)...}
  {
  }
#endif
};

}

namespace std
{

template <typename ...Types>
class tuple_size<gnr::many<Types...>> :
  public std::integral_constant<size_t, sizeof...(Types)>
{
};

template <size_t I, class ...Types>
class tuple_element<I, gnr::many<Types...>>
{
public:
  using type = tuple_element_t<I, tuple<Types...>>;
};

template <size_t I, typename ...Types>
auto& get(gnr::many<Types...>& m) noexcept
{
  return gnr::detail::many::get<I>(m);
}

template <size_t I, typename ...Types>
auto& get(gnr::many<Types...> const& m) noexcept
{
  return gnr::detail::many::get<I>(m);
}

template<size_t I, typename ...Types>
auto& get(gnr::many<Types...>&& m) noexcept
{
  // m is now a lvalue
  return gnr::detail::many::get<I>(m);
}

template<size_t I, typename ...Types>
auto& get(gnr::many<Types...> const&& m) noexcept
{
  // m is now a lvalue
  return gnr::detail::many::get<I>(m);
}

}

#endif // GNR_MANY_HPP
<commit_msg>some fixes<commit_after>#ifndef GNR_MANY_HPP
# define GNR_MANY_HPP
# pragma once

#include <cstddef>

#include <tuple>

#include <type_traits>

#include <utility>

namespace gnr
{

namespace detail
{

namespace many
{

enum TupleValue { Scalar, Reference, Class };

template <std::size_t I,
  class T,
  TupleValue = std::is_class<T>{} ?
    TupleValue::Class :
    std::is_reference<T>{} ?
      TupleValue::Reference :
      TupleValue::Scalar
>
struct tuple_base
{
  T value;

  tuple_base() = default;

  template <typename A>
  constexpr tuple_base(A&& value) : value{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base const&) = default;
  tuple_base(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
};

template <std::size_t I, class T>
struct tuple_base<I, T, TupleValue::Reference>
{
  T value;

  tuple_base() = delete;

  template <typename A>
  constexpr tuple_base(A&& value) : value{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base const&) = default;
  tuple_base(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
};

template <std::size_t I, class T>
struct tuple_base<I, T, TupleValue::Class> : T
{
  tuple_base() = default;

  template <typename A>
  constexpr tuple_base(A&& value) : T{std::forward<A>(value)}
  {
  }

  tuple_base(tuple_base const&) = default;
  tuple_base(tuple_base&&) = default;
  tuple_base& operator=(tuple_base const&) = default;
  tuple_base& operator=(tuple_base&&) = default;
};

template <std::size_t I, class T, enum detail::many::TupleValue E>
auto& get(tuple_base<I, T, E> const& obj) noexcept
{
  return obj.value;
}

template <std::size_t I, class T>
auto get(tuple_base<I, T, TupleValue::Class>& obj) noexcept -> T&
{
  return obj;
}

template <std::size_t I, class T>
auto get(tuple_base<I, T, TupleValue::Class> const& obj) noexcept -> T const&
{
  return obj;
}

template <typename ...>
struct many_impl;

template <std::size_t... Is, typename ...Types>
struct many_impl<std::index_sequence<Is...>, Types...> :
  tuple_base<Is, Types>...
{
  many_impl() = default;
  ~many_impl() = default;
  many_impl(many_impl&&) = default;
  many_impl(many_impl const&) = default;
  many_impl& operator=(many_impl&&) = default;
  many_impl& operator=(many_impl const&) = default;

#if !__cpp_aggregate_bases
  template<typename ...U>
  constexpr many_impl(U&& ...u) :
    tuple_base<Is, Types>{std::forward<U>(u)}...
  {
  }
#endif
};

}

}

template <typename ...Types>
struct many : detail::many::many_impl<
  std::make_index_sequence<sizeof...(Types)>,
  Types...
>
{
  many() = default;
  ~many() = default;
  many(many&&) = default;
  many(many const&) = default;
  many& operator=(many&&) = default;
  many& operator=(many const&) = default;

#if !__cpp_aggregate_bases
  template <class... U>
  constexpr many(U&& ...u) : many::many_impl{std::forward<U>(u)...}
  {
  }
#endif
};

}

namespace std
{

template <typename ...Types>
class tuple_size<gnr::many<Types...>> :
  public std::integral_constant<size_t, sizeof...(Types)>
{
};

template <size_t I, class ...Types>
class tuple_element<I, gnr::many<Types...>>
{
public:
  using type = tuple_element_t<I, tuple<Types...>>;
};

template <size_t I, typename ...Types>
auto& get(gnr::many<Types...>& m) noexcept
{
  return gnr::detail::many::get<I>(m);
}

template <size_t I, typename ...Types>
auto& get(gnr::many<Types...> const& m) noexcept
{
  return gnr::detail::many::get<I>(m);
}

template<size_t I, typename ...Types>
auto& get(gnr::many<Types...>&& m) noexcept
{
  // m is now a lvalue
  return gnr::detail::many::get<I>(m);
}

template<size_t I, typename ...Types>
auto& get(gnr::many<Types...> const&& m) noexcept
{
  // m is now a lvalue
  return gnr::detail::many::get<I>(m);
}

}

#endif // GNR_MANY_HPP
<|endoftext|>


<commit_before>#include <bashclass/BBashHelper.h>
#include <bashclass/BGenerateCode.h>
#include <bashclass/BTypes.h>
#include <bashclass/BException.h>
#include <bashclass/BGlobal.h>
#include <bashclass/BVariableChainAccess.h>
#include <bashclass/BFunctionChainCall.h>
#include <iostream>
#include <bashclass/BArithOperation.h>
#include <bashclass/BVariableAssign.h>
#include <bashclass/BVariableAccess.h>
#include <bashclass/BThisAccess.h>
#include <bashclass/BTokenUse.h>

// Constants
std::string FUNCTION_THIS = "_this_";
std::string FUNCTION_RETURN = "_return_";
std::string RESULT = "_result_";
std::string EXPRESSION = "_expression_";

// Delcare function (when necessary)
std::string _expressionToCode(std::shared_ptr<BScope> scope, std::shared_ptr<IBExpression> expression,
                              std::stringstream &ss);
/**
 * Indent generated code
 * @param parent
 * @param ss
 */
void _indent(std::shared_ptr<BScope> parent, std::stringstream& ss) {
    if(!parent) {
        throw BException("Parent scope should not be empty");
    }

    auto closestClass = parent->findClosestClass();
    while (parent != BGlobal::getInstance() && parent != closestClass) {
        ss << "\t";
        parent = parent->getParentScope();
    }
}

/**
 * Generate a unique result key/variable per element call
 * @param number
 * @return unique result string
 */
std::string _generateResultKey(unsigned int number) {
    return RESULT + std::to_string(number);
}

/**
 * Generate a unique expression key/variable per expression
 * @param number
 * @return unqieu expression string
 */
std::string _generateExpressionKey(unsigned int number) {
    return EXPRESSION + std::to_string(number);
}

/**
 * Generate code for a variable chain access that is a member and is placed first in the chain
 * @param variableChainAccess
 * @param ss
 */
void _varChainAccess_member_first(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getParentScope()->findClosestClass()->getLabel().str()
       << "[" << FUNCTION_THIS << "," << variableChainAccess->getVariable()->getLabel().str() << "]";
}

/**
 * Generate code for a variable chain access that is a member and is placed in the middle of the chain
 * @param variableChainAccess
 * @param prevTypeLabel
 * @param prevResult
 * @param ss
 */
void _varChainAccess_member_middle(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::string prevTypeLabel,
                            std::string prevResult, std::stringstream &ss) {
    ss << prevTypeLabel << "[" << prevResult << "," << variableChainAccess->getVariable()->getLabel().str() << "]" ;
}

/**
 * Generate code for a variable chain access that is a member and is placed last in the chain
 * @param variableChainAccess
 * @param prevResult
 * @param ss
 */
void _varChainAccess_member_last(std::shared_ptr<BVariableChainAccess> variableChainAccess,
                          std::string prevResult, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getParentScope()->findClosestClass()->getLabel().str()
       << "[" << prevResult << "," << variableChainAccess->getVariable()->getLabel().str() << "]";
}

/**
 * Generate code for a variable call that is not a member
 * @param variableChainAccess
 * @param ss
 */
void _varChainAccess_nonMember(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getLabel().str();
}

/**
 * Generate code for a chain call
 * @param chainCall
 * @return multi-line code representing a chain call
 */
void _chainToCode(std::shared_ptr<BScope> scope, std::shared_ptr<BChain> chain, size_t from, size_t to,
                  std::map<std::shared_ptr<IBChainable>, std::string> &returnMap, std::stringstream &ss) {

    // Assign a unique key for each result
    static unsigned int uniqueId = 0;

    // Start processing the calls
    for (size_t i = from; i <= to; i++) {

        // Cast element
        auto variableChainAccess = std::dynamic_pointer_cast<BVariableChainAccess>((*chain)[i]);
        auto functionChainCall = std::dynamic_pointer_cast<BFunctionChainCall>((*chain)[i]);
        auto thisChainAccess = std::dynamic_pointer_cast<BThisChainAccess>((*chain)[i]);

        // Add indentation
        _indent(scope, ss);

        if (variableChainAccess) {

            // Generate new key for this variable
            std::string newKey = _generateResultKey(uniqueId++);
            returnMap[variableChainAccess] = newKey;
            ss << newKey << "=";

            if(i == 0) {
                if(variableChainAccess->getVariable()->isClassMember()) {
                    _varChainAccess_member_first(variableChainAccess, ss);
                } else {
                    _varChainAccess_nonMember(variableChainAccess, ss);
                }
            } else {
                _varChainAccess_member_middle(variableChainAccess, (*chain)[i-1]->getTypeScope()->getLabel().str(),
                                       returnMap[(*chain)[i-1]], ss);
            }
            ss << std::endl;

        } else if (functionChainCall) {

            // Start processing the arguments
            std::vector<std::string> argumentsValues;
            auto arguments = functionChainCall->getArguments();
            for(size_t argIndex=0; argIndex < arguments.size(); argIndex++){
                ss << std::endl;
                argumentsValues.push_back(_expressionToCode(scope, arguments[argIndex], ss));
            }

            // Write the function call
            _indent(scope, ss);
            ss << functionChainCall->getFunction()->getLabel().str();

            // Write arguments
            for(size_t argIndex=0; argIndex < arguments.size(); argIndex++) {
                ss << " " << argumentsValues[argIndex];
            }

            // Write the reference from previous or this when applicable
            if(i == 0) {
                if(functionChainCall->getFunction()->isClassMember()) {
                    ss << " " << FUNCTION_THIS;
                }
            } else {
                ss << " " << returnMap[(*chain)[i-1]];
            }

            // Write the return variable if required
            if(functionChainCall->getFunction()->requiresReturn()) {
                std::string newKey = _generateResultKey(uniqueId++);
                returnMap[functionChainCall] = newKey;
                ss << " " << newKey;
            }
            ss << std::endl;
        } else if(thisChainAccess) {
            std::string newKey = _generateResultKey(uniqueId++);
            returnMap[thisChainAccess] = newKey;
            ss  << newKey << "=" << FUNCTION_THIS << std::endl;
        } else {
            throw BException("Cannot generate code for an unrecognized element call");
        }
    }
}

std::string _expressionToCode(std::shared_ptr<BScope> scope, std::shared_ptr<IBExpression> expression,
                              std::stringstream &ss) {
    auto thisAccess = std::dynamic_pointer_cast<BThisAccess>(expression);
    auto variableAccess = std::dynamic_pointer_cast<BVariableAccess>(expression);
    auto functionCall = std::dynamic_pointer_cast<BFunctionCall>(expression);
    auto tokenUse = std::dynamic_pointer_cast<BTokenUse>(expression);
    auto arithOperation = std::dynamic_pointer_cast<BArithOperation>(expression);

    // Assign a unique key for each expression
    static unsigned int uniqueId = 0;

    if(thisAccess) {
        return FUNCTION_THIS;
    }

    if(variableAccess) {

        // Process chain
        std::map<std::shared_ptr<IBChainable>, std::string> returnMap;
        _chainToCode(scope, variableAccess->getChain(), 0, variableAccess->getChain()->size()-1, returnMap, ss);

        // Get the variable key of the last element
        return returnMap[variableAccess->last()];
    }

    if(functionCall) {

        // Process chain
        std::map<std::shared_ptr<IBChainable>, std::string> returnMap;
        _chainToCode(scope, functionCall->getChain(), 0, functionCall->getChain()->size()-1, returnMap, ss);

        // Get the variable key of the last element
        return returnMap[functionCall->last()];
    }

    if(tokenUse) {
        return tokenUse->getLexicalToken()->getValue();
    }

    auto leftStr = _expressionToCode(scope, arithOperation->getLeftOperand(), ss);
    auto rightStr = _expressionToCode(scope, arithOperation->getRightOperand(), ss);
    _indent(scope, ss);
    std::string newKey = _generateExpressionKey(uniqueId++);
    ss << newKey << "=" << leftStr + " " + arithOperation->getOperator()->getValue() + " " + rightStr << std::endl;
    return newKey;
}

void BBashHelper::header() {
    BGenerateCode::get().writePreCode();
}

void BBashHelper::footer() {
    BGenerateCode::get().writePostCode();
}

void BBashHelper::declareClass(std::shared_ptr<BClass> classScope) {
    std::stringstream ss;
    ss << "declare -A " << classScope->getLabel().str() << "=()" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::uniqueCounter(std::shared_ptr<BClass> classScope) {
    std::stringstream ss;
    ss << "_" << classScope->getName()->getValue() << "_=0" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createGlobalVar(std::shared_ptr<BVariable> variable, std::string defaultValue) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Create global variable" << std::endl;

    ss << variable->getLabel().str() << "=" << defaultValue << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createLocalVar(std::shared_ptr<BVariable> variable, std::string defaultValue) {
    std::stringstream ss;
    ss << std::endl;
    _indent(variable->getParentScope(),ss);
    ss << "# Create local variable" << std::endl;

    _indent(variable->getParentScope(), ss);
    ss << "local " << variable->getLabel().str() << "=" << defaultValue << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::bash(std::shared_ptr<ecc::LexicalToken> token) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Run BASH code" << std::endl;

    if(token->getName() == BType::TYPE_NAME_BASH_INLINE) {
        ss << token->getValue().substr(2,token->getValue().length()-2);
    } else if(token->getName() == BType::TYPE_NAME_BASH_SUB || token->getName() == BType::TYPE_NAME_BASH_BLOCK) {
        ss << token->getValue().substr(2, token->getValue().length()-4);
    } else {
        throw BException("Bash code can only be generated by bash lexical tokens");
    }
    ss << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createFunction(std::shared_ptr<BFunction> function) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Create function" << std::endl;

    ss << "function " << function->getLabel().str() << "() {" << std::endl;
    // Create parameters
    int paramPos = 1;
    for(auto param : function->findAllParameters()) {
        _indent(param->getParentScope(), ss);
        ss << "local " << param->getLabel().str() << "=\"$" << paramPos++ << "\"" << std::endl;
    }

    // Generate 'this' if function is a class member
    if(function->isClassMember()) {
        _indent(function, ss);
        ss << "local " << FUNCTION_THIS << "=$" << paramPos++ << std::endl;
    }

    // Generate return reference if function requires a return statement
    if(function->requiresReturn()) {
        _indent(function, ss);
        ss << "declare -n " << FUNCTION_RETURN << "=$" << paramPos++ << std::endl;
    }

    BGenerateCode::get().write(ss);
}

void BBashHelper::closeFunction(std::shared_ptr<BFunction> function) {
    std::stringstream ss;
    _indent(function->getParentScope(), ss);
    ss << "}" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::assignVariable(std::shared_ptr<BVariableAssign> variableAssign) {
    std::stringstream ss;

    std::shared_ptr<BVariableAccess> variableAccess = variableAssign->getVariableAccess();
    std::shared_ptr<BChain> variableAccessChain = variableAccess->getChain();

    // Store return values in unique keys in a map
    std::map<std::shared_ptr<IBChainable>, std::string> returnMap;

    // Start converting the expression
    ss << std::endl;
    _indent(variableAssign->getParentScope(), ss);
    ss << "# Evaluating expression" << std::endl;
    std::string expression = _expressionToCode(variableAssign->getParentScope(), variableAssign->getExpression(), ss);

    // Convert chain to code
    ss << std::endl;
    _indent(variableAssign->getParentScope(), ss);
    ss << "# Assign variable" << std::endl;

    if(variableAccessChain->size() >= 2) {
        _chainToCode(variableAssign->getParentScope(), variableAccessChain, 0, variableAccessChain->size()-2,
                     returnMap, ss);
    }

    // Add the last assignment statement
    _indent(variableAssign->getParentScope(), ss);
    if(variableAccess->last()->getVariable()->isClassMember()) {
        if(variableAccessChain->size() == 1) {
            _varChainAccess_member_first(variableAccess->last(), ss);
        } else {
            _varChainAccess_member_last(variableAccess->last(),
                                        returnMap[(*variableAccessChain)[variableAccessChain->size()-2]], ss);
        }
    } else {
        _varChainAccess_nonMember(variableAccess->last(), ss);
    }
    ss << "=" << expression;
    ss << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::functionExec(std::shared_ptr<BFunctionCall> functionCall) {
    std::stringstream ss;

    // Store return values in unique keys in a map
    std::map<std::shared_ptr<IBChainable>, std::string> returnMap;

    // Convert chain to code
    ss << std::endl;
    _indent(functionCall->getParentScope(), ss);
    ss << "# Execute a function" << std::endl;
    _chainToCode(functionCall->last()->getFunction(), functionCall->getChain(), 0, functionCall->getChain()->size()-1,
                 returnMap, ss);
    ss << std::endl;
    BGenerateCode::get().write(ss);
}<commit_msg>Added bash var symbols<commit_after>#include <bashclass/BBashHelper.h>
#include <bashclass/BGenerateCode.h>
#include <bashclass/BTypes.h>
#include <bashclass/BException.h>
#include <bashclass/BGlobal.h>
#include <bashclass/BVariableChainAccess.h>
#include <bashclass/BFunctionChainCall.h>
#include <iostream>
#include <bashclass/BArithOperation.h>
#include <bashclass/BVariableAssign.h>
#include <bashclass/BVariableAccess.h>
#include <bashclass/BThisAccess.h>
#include <bashclass/BTokenUse.h>

// Constants
std::string FUNCTION_THIS = "_this_";
std::string FUNCTION_RETURN = "_return_";
std::string RESULT = "_result_";
std::string EXPRESSION = "_expression_";

// Delcare function (when necessary)
std::string _expressionToCode(std::shared_ptr<BScope> scope, std::shared_ptr<IBExpression> expression,
                              std::stringstream &ss);
/**
 * Indent generated code
 * @param parent
 * @param ss
 */
void _indent(std::shared_ptr<BScope> parent, std::stringstream& ss) {
    if(!parent) {
        throw BException("Parent scope should not be empty");
    }

    auto closestClass = parent->findClosestClass();
    while (parent != BGlobal::getInstance() && parent != closestClass) {
        ss << "\t";
        parent = parent->getParentScope();
    }
}

/**
 * Generate a unique result key/variable per element call
 * @param number
 * @return unique result string
 */
std::string _generateResultKey(unsigned int number) {
    return RESULT + std::to_string(number);
}

/**
 * Generate a unique expression key/variable per expression
 * @param number
 * @return unqieu expression string
 */
std::string _generateExpressionKey(unsigned int number) {
    return EXPRESSION + std::to_string(number);
}

/**
 * Generate code for a variable chain access that is a member and is placed first in the chain
 * @param variableChainAccess
 * @param ss
 */
void _varChainAccess_member_first(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getParentScope()->findClosestClass()->getLabel().str()
       << "[${" << FUNCTION_THIS << "},\"" << variableChainAccess->getVariable()->getLabel().str() << "\"]";
}

/**
 * Generate code for a variable chain access that is a member and is placed in the middle of the chain
 * @param variableChainAccess
 * @param prevTypeLabel
 * @param prevResult
 * @param ss
 */
void _varChainAccess_member_middle(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::string prevTypeLabel,
                            std::string prevResult, std::stringstream &ss) {
    ss << prevTypeLabel << "[${" << prevResult << "},\"" << variableChainAccess->getVariable()->getLabel().str() << "\"]" ;
}

/**
 * Generate code for a variable chain access that is a member and is placed last in the chain
 * @param variableChainAccess
 * @param prevResult
 * @param ss
 */
void _varChainAccess_member_last(std::shared_ptr<BVariableChainAccess> variableChainAccess,
                          std::string prevResult, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getParentScope()->findClosestClass()->getLabel().str()
       << "[${" << prevResult << "},\"" << variableChainAccess->getVariable()->getLabel().str() << "\"]";
}

/**
 * Generate code for a variable call that is not a member
 * @param variableChainAccess
 * @param ss
 */
void _varChainAccess_nonMember(std::shared_ptr<BVariableChainAccess> variableChainAccess, std::stringstream &ss) {
    ss << variableChainAccess->getVariable()->getLabel().str();
}

/**
 * Generate code for a chain call
 * @param chainCall
 * @return multi-line code representing a chain call
 */
void _chainToCode(std::shared_ptr<BScope> scope, std::shared_ptr<BChain> chain, size_t from, size_t to,
                  std::map<std::shared_ptr<IBChainable>, std::string> &returnMap, std::stringstream &ss) {

    // Assign a unique key for each result
    static unsigned int uniqueId = 0;

    // Start processing the calls
    for (size_t i = from; i <= to; i++) {

        // Cast element
        auto variableChainAccess = std::dynamic_pointer_cast<BVariableChainAccess>((*chain)[i]);
        auto functionChainCall = std::dynamic_pointer_cast<BFunctionChainCall>((*chain)[i]);
        auto thisChainAccess = std::dynamic_pointer_cast<BThisChainAccess>((*chain)[i]);

        if (variableChainAccess) {

            // Add indentation
            _indent(scope, ss);

            // Generate new key for this variable
            std::string newKey = _generateResultKey(uniqueId++);
            returnMap[variableChainAccess] = newKey;
            ss << newKey << "=${";

            if(i == 0) {
                if(variableChainAccess->getVariable()->isClassMember()) {
                    _varChainAccess_member_first(variableChainAccess, ss);
                } else {
                    _varChainAccess_nonMember(variableChainAccess, ss);
                }
            } else {
                _varChainAccess_member_middle(variableChainAccess, (*chain)[i-1]->getTypeScope()->getLabel().str(),
                                       returnMap[(*chain)[i-1]], ss);
            }
            ss << "}" << std::endl;

        } else if (functionChainCall) {

            // Start processing the arguments
            std::vector<std::string> argumentsValues;
            auto arguments = functionChainCall->getArguments();
            for(size_t argIndex=0; argIndex < arguments.size(); argIndex++){
                argumentsValues.push_back(_expressionToCode(scope, arguments[argIndex], ss));
            }

            // Write the function call
            _indent(scope, ss);
            ss << functionChainCall->getFunction()->getLabel().str();

            // Write arguments
            for(size_t argIndex=0; argIndex < arguments.size(); argIndex++) {
                ss << " " << argumentsValues[argIndex];
            }

            // Write the reference from previous or this when applicable
            if(i == 0) {
                if(functionChainCall->getFunction()->isClassMember()) {
                    ss << " " << FUNCTION_THIS;
                }
            } else {
                ss << " " << returnMap[(*chain)[i-1]];
            }

            // Write the return variable if required
            if(functionChainCall->getFunction()->requiresReturn()) {
                std::string newKey = _generateResultKey(uniqueId++);
                returnMap[functionChainCall] = newKey;
                ss << " " << newKey;
            }
            ss << std::endl;
        } else if(thisChainAccess) {
            _indent(scope, ss);
            std::string newKey = _generateResultKey(uniqueId++);
            returnMap[thisChainAccess] = newKey;
            ss  << newKey << "=${" << FUNCTION_THIS << "}" << std::endl;
        } else {
            throw BException("Cannot generate code for an unrecognized element call");
        }
    }
}

std::string _expressionToCode(std::shared_ptr<BScope> scope, std::shared_ptr<IBExpression> expression,
                              std::stringstream &ss) {
    auto thisAccess = std::dynamic_pointer_cast<BThisAccess>(expression);
    auto variableAccess = std::dynamic_pointer_cast<BVariableAccess>(expression);
    auto functionCall = std::dynamic_pointer_cast<BFunctionCall>(expression);
    auto tokenUse = std::dynamic_pointer_cast<BTokenUse>(expression);
    auto arithOperation = std::dynamic_pointer_cast<BArithOperation>(expression);

    // Assign a unique key for each expression
    static unsigned int uniqueId = 0;

    if(thisAccess) {
        return "${" + FUNCTION_THIS + "}";
    }

    if(variableAccess) {

        // Process chain
        std::map<std::shared_ptr<IBChainable>, std::string> returnMap;
        _chainToCode(scope, variableAccess->getChain(), 0, variableAccess->getChain()->size()-1, returnMap, ss);

        // Get the variable key of the last element
        return "${" + returnMap[variableAccess->last()] + "}";
    }

    if(functionCall) {

        // Process chain
        std::map<std::shared_ptr<IBChainable>, std::string> returnMap;
        _chainToCode(scope, functionCall->getChain(), 0, functionCall->getChain()->size()-1, returnMap, ss);

        // Get the variable key of the last element
        return "${" + returnMap[functionCall->last()] + "}";
    }

    if(tokenUse) {
        return tokenUse->getLexicalToken()->getValue();
    }

    auto leftStr = _expressionToCode(scope, arithOperation->getLeftOperand(), ss);
    auto rightStr = _expressionToCode(scope, arithOperation->getRightOperand(), ss);
    _indent(scope, ss);
    std::string newKey = _generateExpressionKey(uniqueId++);
    ss << newKey << "=$((" << leftStr + " " + arithOperation->getOperator()->getValue() + " " + rightStr << "))"
       << std::endl;
    return "${" + newKey + "}";
}

void BBashHelper::header() {
    BGenerateCode::get().writePreCode();
}

void BBashHelper::footer() {
    BGenerateCode::get().writePostCode();
}

void BBashHelper::declareClass(std::shared_ptr<BClass> classScope) {
    std::stringstream ss;
    ss << "declare -A " << classScope->getLabel().str() << "=()" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::uniqueCounter(std::shared_ptr<BClass> classScope) {
    std::stringstream ss;
    ss << "_" << classScope->getName()->getValue() << "_=0" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createGlobalVar(std::shared_ptr<BVariable> variable, std::string defaultValue) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Create global variable" << std::endl;

    ss << variable->getLabel().str() << "=TODO" << defaultValue << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createLocalVar(std::shared_ptr<BVariable> variable, std::string defaultValue) {
    std::stringstream ss;
    ss << std::endl;
    _indent(variable->getParentScope(),ss);
    ss << "# Create local variable" << std::endl;

    _indent(variable->getParentScope(), ss);
    ss << "local " << variable->getLabel().str() << "=TODO" << defaultValue << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::bash(std::shared_ptr<ecc::LexicalToken> token) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Run BASH code" << std::endl;

    if(token->getName() == BType::TYPE_NAME_BASH_INLINE) {
        ss << token->getValue().substr(2,token->getValue().length()-2);
    } else if(token->getName() == BType::TYPE_NAME_BASH_SUB || token->getName() == BType::TYPE_NAME_BASH_BLOCK) {
        ss << token->getValue().substr(2, token->getValue().length()-4);
    } else {
        throw BException("Bash code can only be generated by bash lexical tokens");
    }
    ss << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::createFunction(std::shared_ptr<BFunction> function) {
    std::stringstream ss;
    ss << std::endl;
    ss << "# Create function" << std::endl;

    ss << "function " << function->getLabel().str() << "() {" << std::endl;
    // Create parameters
    int paramPos = 1;
    for(auto param : function->findAllParameters()) {
        _indent(param->getParentScope(), ss);
        ss << "local " << param->getLabel().str() << "=\"$" << paramPos++ << "\"" << std::endl;
    }

    // Generate 'this' if function is a class member
    if(function->isClassMember()) {
        _indent(function, ss);
        ss << "local " << FUNCTION_THIS << "=$" << paramPos++ << std::endl;
    }

    // Generate return reference if function requires a return statement
    if(function->requiresReturn()) {
        _indent(function, ss);
        ss << "declare -n " << FUNCTION_RETURN << "=$" << paramPos++ << std::endl;
    }

    BGenerateCode::get().write(ss);
}

void BBashHelper::closeFunction(std::shared_ptr<BFunction> function) {
    std::stringstream ss;
    _indent(function->getParentScope(), ss);
    ss << "}" << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::assignVariable(std::shared_ptr<BVariableAssign> variableAssign) {
    std::stringstream ss;

    std::shared_ptr<BVariableAccess> variableAccess = variableAssign->getVariableAccess();
    std::shared_ptr<BChain> variableAccessChain = variableAccess->getChain();

    // Store return values in unique keys in a map
    std::map<std::shared_ptr<IBChainable>, std::string> returnMap;

    // Add bash comments
    ss << std::endl;
    _indent(variableAssign->getParentScope(), ss);
    ss << "# Assign variable" << std::endl;

    // Start converting the expression
    std::string expression = _expressionToCode(variableAssign->getParentScope(), variableAssign->getExpression(), ss);

    // Convert chain to code
    if(variableAccessChain->size() >= 2) {
        _chainToCode(variableAssign->getParentScope(), variableAccessChain, 0, variableAccessChain->size()-2,
                     returnMap, ss);
    }

    // Add the last assignment statement
    _indent(variableAssign->getParentScope(), ss);
    if(variableAccess->last()->getVariable()->isClassMember()) {
        if(variableAccessChain->size() == 1) {
            _varChainAccess_member_first(variableAccess->last(), ss);
        } else {
            _varChainAccess_member_last(variableAccess->last(),
                                        returnMap[(*variableAccessChain)[variableAccessChain->size()-2]], ss);
        }
    } else {
        _varChainAccess_nonMember(variableAccess->last(), ss);
    }
    ss << "=" << expression << std::endl;
    BGenerateCode::get().write(ss);
}

void BBashHelper::functionExec(std::shared_ptr<BFunctionCall> functionCall) {
    std::stringstream ss;

    // Store return values in unique keys in a map
    std::map<std::shared_ptr<IBChainable>, std::string> returnMap;

    // Convert chain to code
    ss << std::endl;
    _indent(functionCall->getParentScope(), ss);
    ss << "# Execute a function" << std::endl;
    _chainToCode(functionCall->last()->getFunction(), functionCall->getChain(), 0, functionCall->getChain()->size()-1,
                 returnMap, ss);
    ss << std::endl;
    BGenerateCode::get().write(ss);
}<|endoftext|>