<commit_before>#include <iostream>
#include <cstdio>
#include <cassert>
#include <ctime>

#include "driver_program.h"
#include "fast_random.h"

void Populate(pqxx::connection &conn, const DriverConfig &config) {

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  std::cout << ">>>>> Populate table \'employee\'. " << std::endl
            << "   -- Build index? : " << config.with_index_ << std::endl
            << "   -- Table size   : " << table_size << std::endl;

  pqxx::work txn(conn);

  txn.exec("DROP TABLE IF EXISTS employee;");
  txn.exec("CREATE TABLE employee(id INT, name VARCHAR(100));");

  if (config.with_index_ == true) {
    txn.exec("CREATE INDEX emp_index ON employee(id)");
  }

  for (size_t i = 0; i < table_size; ++i) {
    txn.exec("INSERT INTO employee VALUES (" + std::to_string(i) + ", 'a');");
  }
  txn.commit();
}

void ProcessClient(pqxx::connection &conn, const DriverConfig &config) {

  srand(time(NULL));

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  FastRandom fast_rand;

  ZipfDistribution zipf(table_size, config.zipf_theta_);

  std::cout << ">>>>> Process transactions via client interface. " << std::endl
            << "   -- With prepared statement? : " << config.with_prep_stmt_ << std::endl
            << "   -- Table size               : " << table_size << std::endl
            << "   -- Operation count          : " << config.operation_count_ << std::endl
            << "   -- Update ratio             : " << config.update_ratio_ << std::endl
            << "   -- Zipf theta               : " << config.zipf_theta_ << std::endl;

  pqxx::work txn(conn);

  if (config.with_prep_stmt_ == true) {

    conn.prepare("read", "SELECT name FROM employee WHERE id=$1");
    conn.prepare("write", "UPDATE employee SET name = 'z' WHERE id=$1");

    for (size_t i = 0; i < config.operation_count_; ++i) {

      size_t key = zipf.GetNextNumber() - 1;

      if (fast_rand.next_uniform() < config.update_ratio_) {
        // update
        txn.prepared("write")(key).exec();
      } else {
        // select
        pqxx::result R = txn.prepared("read")(key).exec();
        printf("key = %lu, txn result set size = %lu\n", key, R.size());
      }
    }
  } else {
    for (size_t i = 0; i < config.operation_count_; ++i) {

      size_t key = zipf.GetNextNumber() - 1;

      if (fast_rand.next_uniform() < config.update_ratio_) {
        // update
        txn.exec("UPDATE employee SET name = 'z' WHERE id=" + std::to_string(key) + ";");
      } else {
        // select
        pqxx::result R = txn.exec("SELECT name FROM employee WHERE id=" + std::to_string(key) + ";");
        printf("key = %lu, txn result set size = %lu\n", key, R.size());
      }
    }
  }
  txn.commit();
}

void ProcessProcedure(pqxx::connection &conn, const DriverConfig &config) {

  srand(time(NULL));

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  std::cout << ">>>>> Process transactions via stored procedure. "
            << "   -- Table size      : " << table_size << std::endl
            << "   -- Operation count : " << config.operation_count_ << std::endl
            << "   -- Update ratio    : " << config.update_ratio_ << std::endl
            << "   -- Zipf theta      : " << config.zipf_theta_ << std::endl;

  FastRandom fast_rand;

  size_t read_count = 0;
  bool *is_update = new bool[config.operation_count_];
  for (size_t i = 0; i < config.operation_count_; ++i) {
    if (fast_rand.next_uniform() < config.update_ratio_) {
      is_update[i] = true;
    } else {
      is_update[i] = false;
      ++read_count;
    }
  }

  ZipfDistribution zipf(table_size, config.zipf_theta_);

  std::string func_str("CREATE OR REPLACE FUNCTION ycsb(");

  if (read_count == 0) {
    for (size_t i = 0; i < config.operation_count_ - 1; ++i) {
      func_str += "val" + std::to_string(i) + " integer, ";
    }
    func_str +=  "val" + std::to_string(config.operation_count_ - 1) + " integer) ";
  } else {
    for (size_t i = 0; i < config.operation_count_; ++i) {
      func_str += "val" + std::to_string(i) + " integer, ";
    }
    for (size_t i = 0; i < read_count - 1; ++i) {
      func_str += "ref" + std::to_string(i) + " refcursor, ";
    }
    func_str += "ref" + std::to_string(read_count - 1) + " refcursor) ";
  }

  func_str += "RETURNS ";

  if (read_count == 0) {
    func_str += "void ";
  } else if (read_count == 1) {
    func_str += "refcursor ";
  } else {
    func_str += "SETOF refcursor ";
  }

  func_str += "AS $$ ";

  func_str += "BEGIN ";

  size_t curr_read_count = 0;
  for (size_t i = 0; i < config.operation_count_; ++i) {
    if (is_update[i] == true) {
      // is update
      func_str += "UPDATE employee SET name = 'z' WHERE id=val" + std::to_string(i) + ";";
    } else {
      // is read
      if (read_count == 1) {
        func_str += "OPEN ref" + std::to_string(curr_read_count) + " FOR SELECT name FROM employee where id = val" + std::to_string(i) + "; RETURN ref" + std::to_string(curr_read_count) + ";";
        ++curr_read_count;
      } else {
        func_str += "OPEN ref" + std::to_string(curr_read_count) + " FOR SELECT name FROM employee where id = val" + std::to_string(i) + "; RETURN NEXT ref" + std::to_string(curr_read_count) + ";";
        ++curr_read_count;
      }
    }
  }
  func_str += " END; $$ LANGUAGE PLPGSQL;";

  std::cout << ">>>>>>>>>>>>>>>" << std::endl;
  for (size_t i = 0; i < config.operation_count_; ++i) {
    std::cout << is_update[i] << " ";
  }
  std::cout << std::endl;
  std::cout << "<<<<<<<<<<<<<<<" << std::endl;

  pqxx::nontransaction nontxn0(conn);

  nontxn0.exec(func_str.c_str());

  nontxn0.commit();

  pqxx::work txn(conn);

  std::string txn_str = "SELECT ycsb(";
  if (read_count == 0) {
    for (size_t i = 0; i < config.operation_count_ - 1; ++i) {
      size_t key = zipf.GetNextNumber() - 1;
      txn_str += std::to_string(key) + ", ";
    }
    size_t key = zipf.GetNextNumber() - 1;
    txn_str += std::to_string(key) + ");";
  } else {
    for (size_t i = 0; i < config.operation_count_; ++i) {
      size_t key = zipf.GetNextNumber() - 1;
      txn_str += std::to_string(key) + ", ";
    }
    for (size_t i = 0; i < read_count - 1; ++i) {
      txn_str += "'ref" + std::to_string(i) + "', ";
    }
    txn_str += "'ref" + std::to_string(read_count - 1) + "');";
  }

  std::cout << txn_str << std::endl;

  txn.exec(txn_str.c_str());

  for (size_t i = 0; i < read_count; ++i) {
    std::string select_str = "FETCH ALL FROM ref" + std::to_string(i) + ";";
    pqxx::result R = txn.exec(select_str.c_str());

    std::cout << "txn result set size = " << R.size() << std::endl;

    for (size_t i = 0; i < R.size(); ++i) {
      std::cout << R[i][0].as<std::string>() << std::endl;
    }
  }

  txn.commit();

  pqxx::nontransaction nontxn1(conn);

  nontxn1.exec("DROP FUNCTION ycsb;");

  nontxn1.commit();

  delete[] is_update;
  is_update = nullptr;

}

void Scan(pqxx::connection &conn) {

  pqxx::work txn(conn);

  std::cout << ">>>>> Scan table." << std::endl;

  pqxx::result R = txn.exec("SELECT * FROM employee;");

  printf("txn result set size = %lu\n", R.size());

  for (size_t i = 0; i < R.size(); ++i) {
    int id = R[i][0].as<int>();
    std::string name = R[i][1].as<std::string>();
    std::cout << "id = " << id << ", " << name << std::endl;
  }

  txn.commit();
}

<commit_msg>driver program<commit_after>#include <iostream>
#include <cstdio>
#include <cassert>
#include <ctime>

#include "driver_program.h"
#include "fast_random.h"

const int repeat_count = 10;

void Populate(pqxx::connection &conn, const DriverConfig &config) {

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  std::cout << ">>>>> Populate table \'employee\'. " << std::endl
            << "   -- Build index? : " << config.with_index_ << std::endl
            << "   -- Table size   : " << table_size << std::endl;

  pqxx::work txn(conn);

  txn.exec("DROP TABLE IF EXISTS employee;");
  txn.exec("CREATE TABLE employee(id INT, name VARCHAR(100));");

  if (config.with_index_ == true) {
    txn.exec("CREATE INDEX emp_index ON employee(id)");
  }

  for (size_t i = 0; i < table_size; ++i) {
    txn.exec("INSERT INTO employee VALUES (" + std::to_string(i) + ", 'a');");
  }
  txn.commit();
}

void ProcessClient(pqxx::connection &conn, const DriverConfig &config) {

  srand(time(NULL));

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  FastRandom fast_rand;

  ZipfDistribution zipf(table_size, config.zipf_theta_);

  std::cout << ">>>>> Process transactions via client interface. " << std::endl
            << "   -- With prepared statement? : " << config.with_prep_stmt_ << std::endl
            << "   -- Table size               : " << table_size << std::endl
            << "   -- Operation count          : " << config.operation_count_ << std::endl
            << "   -- Update ratio             : " << config.update_ratio_ << std::endl
            << "   -- Zipf theta               : " << config.zipf_theta_ << std::endl;

  if (config.with_prep_stmt_ == true) {

    conn.prepare("read", "SELECT name FROM employee WHERE id=$1");
    conn.prepare("write", "UPDATE employee SET name = 'z' WHERE id=$1");

    for (size_t t = 0; t < repeat_count; ++t) {

      pqxx::work txn(conn);

      for (size_t i = 0; i < config.operation_count_; ++i) {

        size_t key = zipf.GetNextNumber() - 1;

        if (fast_rand.next_uniform() < config.update_ratio_) {
          // update
          txn.prepared("write")(key).exec();
        } else {
          // select
          pqxx::result R = txn.prepared("read")(key).exec();
          printf("key = %lu, txn result set size = %lu\n", key, R.size());
        }
      }

      txn.commit();
    }

  } else {

    for (size_t t = 0; t < repeat_count; ++t) {

      pqxx::work txn(conn);

      for (size_t i = 0; i < config.operation_count_; ++i) {

        size_t key = zipf.GetNextNumber() - 1;

        if (fast_rand.next_uniform() < config.update_ratio_) {
          // update
          txn.exec("UPDATE employee SET name = 'z' WHERE id=" + std::to_string(key) + ";");
        } else {
          // select
          pqxx::result R = txn.exec("SELECT name FROM employee WHERE id=" + std::to_string(key) + ";");
          printf("key = %lu, txn result set size = %lu\n", key, R.size());
        }
      }

      txn.commit();
    }

  }

}

void ProcessProcedure(pqxx::connection &conn, const DriverConfig &config) {

  srand(time(NULL));

  size_t table_size = config.default_table_size_ * config.scale_factor_;

  std::cout << ">>>>> Process transactions via stored procedure. "
            << "   -- Table size      : " << table_size << std::endl
            << "   -- Operation count : " << config.operation_count_ << std::endl
            << "   -- Update ratio    : " << config.update_ratio_ << std::endl
            << "   -- Zipf theta      : " << config.zipf_theta_ << std::endl;

  FastRandom fast_rand;

  size_t read_count = 0;
  bool *is_update = new bool[config.operation_count_];
  for (size_t i = 0; i < config.operation_count_; ++i) {
    if (fast_rand.next_uniform() < config.update_ratio_) {
      is_update[i] = true;
    } else {
      is_update[i] = false;
      ++read_count;
    }
  }

  ZipfDistribution zipf(table_size, config.zipf_theta_);

  std::string func_str("CREATE OR REPLACE FUNCTION ycsb(");

  if (read_count == 0) {
    for (size_t i = 0; i < config.operation_count_ - 1; ++i) {
      func_str += "val" + std::to_string(i) + " integer, ";
    }
    func_str +=  "val" + std::to_string(config.operation_count_ - 1) + " integer) ";
  } else {
    for (size_t i = 0; i < config.operation_count_; ++i) {
      func_str += "val" + std::to_string(i) + " integer, ";
    }
    for (size_t i = 0; i < read_count - 1; ++i) {
      func_str += "ref" + std::to_string(i) + " refcursor, ";
    }
    func_str += "ref" + std::to_string(read_count - 1) + " refcursor) ";
  }

  func_str += "RETURNS ";

  if (read_count == 0) {
    func_str += "void ";
  } else if (read_count == 1) {
    func_str += "refcursor ";
  } else {
    func_str += "SETOF refcursor ";
  }

  func_str += "AS $$ ";

  func_str += "BEGIN ";

  size_t curr_read_count = 0;
  for (size_t i = 0; i < config.operation_count_; ++i) {
    if (is_update[i] == true) {
      // is update
      func_str += "UPDATE employee SET name = 'z' WHERE id=val" + std::to_string(i) + ";";
    } else {
      // is read
      if (read_count == 1) {
        func_str += "OPEN ref" + std::to_string(curr_read_count) +
                    " FOR SELECT name FROM employee where id = val" +
                    std::to_string(i) + "; RETURN ref" + std::to_string(curr_read_count) + ";";
        ++curr_read_count;
      } else {
        func_str += "OPEN ref" + std::to_string(curr_read_count) +
                    " FOR SELECT name FROM employee where id = val" +
                    std::to_string(i) + "; RETURN NEXT ref" + std::to_string(curr_read_count) + ";";
        ++curr_read_count;
      }
    }
  }
  func_str += " END; $$ LANGUAGE PLPGSQL;";

  std::cout << ">>>>>>>>>>>>>>>" << std::endl;
  for (size_t i = 0; i < config.operation_count_; ++i) {
    std::cout << is_update[i] << " ";
  }
  std::cout << std::endl;
  std::cout << "<<<<<<<<<<<<<<<" << std::endl;

  pqxx::nontransaction nontxn0(conn);

  nontxn0.exec(func_str.c_str());

  nontxn0.commit();

  for (size_t t = 0; t < repeat_count; ++t) {

    pqxx::work txn(conn);

    std::string txn_str = "SELECT ycsb(";
    if (read_count == 0) {
      for (size_t i = 0; i < config.operation_count_ - 1; ++i) {
        size_t key = zipf.GetNextNumber() - 1;
        txn_str += std::to_string(key) + ", ";
      }
      size_t key = zipf.GetNextNumber() - 1;
      txn_str += std::to_string(key) + ");";
    } else {
      for (size_t i = 0; i < config.operation_count_; ++i) {
        size_t key = zipf.GetNextNumber() - 1;
        txn_str += std::to_string(key) + ", ";
      }
      for (size_t i = 0; i < read_count - 1; ++i) {
        txn_str += "'ref" + std::to_string(i) + "', ";
      }
      txn_str += "'ref" + std::to_string(read_count - 1) + "');";
    }

    std::cout << txn_str << std::endl;

    txn.exec(txn_str.c_str());

    for (size_t i = 0; i < read_count; ++i) {
      std::string select_str = "FETCH ALL FROM ref" + std::to_string(i) + ";";
      pqxx::result R = txn.exec(select_str.c_str());

      std::cout << "txn result set size = " << R.size() << std::endl;

      for (size_t i = 0; i < R.size(); ++i) {
        std::cout << R[i][0].as<std::string>() << std::endl;
      }
    }

    txn.commit();

  }

  pqxx::nontransaction nontxn1(conn);

  nontxn1.exec("DROP FUNCTION ycsb;");

  nontxn1.commit();

  delete[] is_update;
  is_update = nullptr;

}

void Scan(pqxx::connection &conn) {

  pqxx::work txn(conn);

  std::cout << ">>>>> Scan table." << std::endl;

  pqxx::result R = txn.exec("SELECT * FROM employee;");

  printf("txn result set size = %lu\n", R.size());

  for (size_t i = 0; i < R.size(); ++i) {
    int id = R[i][0].as<int>();
    std::string name = R[i][1].as<std::string>();
    std::cout << "id = " << id << ", " << name << std::endl;
  }

  txn.commit();
}

<|endoftext|>


<commit_before>#include "Assembler.h"
#include "ErrorPrinter.h"
#include "StringLibrary.h"

Assembler::Assembler(string outFileName) : scanner(outFileName,this) {
	outputFileName = outFileName;
	positionCount = 0;
	lineCount = 1;
	successAssemble = true;
	sectionFlags = None;
}

Assembler::~Assembler() {
}

int Assembler::GetLine() {
	return lineCount;
}

int Assembler::ExecuteDirective(string directiveName, DirectiveInfo const * info, vector<string> operands) {
	int positionSkip = 0;
	int opsize = operands.size();

	if ((info->operandCount != -1 && info->operandCount != opsize) || (info->operandCount == -1 && opsize != 0 && opsize != 1)) {
		ShowError("Diretiva invalida: Quantidade de operandos errada.",Syntatic);
		return 0;
	}

	if (directiveName  == "section") {
		positionSkip = ExecuteSection(operands);
	} else if (directiveName == "space") {
		if (opsize == 0) {
			positionSkip = 1;
		} else {
			auto argument = operands[0];
			int toReturn;

			if (TryStringToInt(argument, &toReturn)) {
				return toReturn;
			} else {
				ShowError("Operando Invalido:" + argument, Syntatic);
			}
		}
	} else {
		positionSkip = info->size;
	}
	return positionSkip;
}

void Assembler::Assemble() {
	firstPass();
}

void Assembler::firstPass() {
	while (scanner.CanRead()) {
		auto dto = scanner.GetNextTokens();
		if (dto.Operacao=="") {
			if (!dto.isEmpty) {
				successAssemble = false;
			}
			lineCount++;
			continue;
		}

		if (dto.Rotulo != "") {
			auto symbol = TableManager::GetSymbol(dto.Rotulo);
			if (symbol != nullptr) {
				ShowError("Simbolo " + dto.Rotulo + "redefinido", ErrorType::Syntatic);
			} else {
				TableManager::InsertSymbol(dto.Rotulo, SymbolInfo(positionCount,false));
			}
		}

		auto instruction = TableManager::GetInstruction(dto.Operacao);
		if (instruction != nullptr) {
			positionCount += instruction->operandCount + 1;
		} else {
			auto directive = TableManager::GetDirective(dto.Operacao);
			if (directive != nullptr) {
				positionCount += ExecuteDirective(dto.Operacao, directive,dto.Operandos); // IMPLEMENTAR
			} else {
				ShowError("Operacao" + dto.Operacao + "nao identificada", ErrorType::Syntatic);
			}
		}
		lineCount++;
	}
	TableManager::Diagnostic_PrintSymbols();
}

void Assembler::ShowError(string message, ErrorType type) {
	successAssemble = false;
	ErrorPrinter::ShowError(type, scanner.GetFileName(), lineCount, message);
}

int Assembler::ExecuteSection(vector<string> operands) {
	if (operands[0] == "text") {
		if (sectionFlags & Text) {
			ShowError("SECTION TEXT ja definida", ErrorType::Syntatic);
			return 0;
		}
		sectionFlags = Text;
	} else if (operands[0] == "data") {

		if (sectionFlags & Data) {
			ShowError("SECTION DATA ja definida", ErrorType::Syntatic);
			return 0;
		}

		if (!(sectionFlags & Text)) {
			ShowError("SECTION DATA definida antes de SECTION TEXT", ErrorType::Syntatic);
			return 0;
		}

		sectionFlags = sectionFlags | Data;
	} else {
		ShowError("Diretiva Invalida: SECTION nao indentificada.", Syntatic);
	}
	return 0;
}

bool Assembler::TryStringToInt(string s, int* result) {
	if (StringLibrary::IsInteger(s)) {
		*result = std::stoi(s, nullptr);
		return true;
	} else if (StringLibrary::IsHexadecimal(s)) {
		*result = StringLibrary::ConvertHexaToInt(s);
		return true;
	} else {
		return false;
	}
}
<commit_msg>Plano do ligador<commit_after>#include "Assembler.h"
#include "ErrorPrinter.h"
#include "StringLibrary.h"

Assembler::Assembler(string outFileName) : scanner(outFileName,this) {
	outputFileName = outFileName;
	positionCount = 0;
	lineCount = 1;
	successAssemble = true;
	sectionFlags = None;
}

Assembler::~Assembler() {
}

int Assembler::GetLine() {
	return lineCount;
}

int Assembler::ExecuteDirective(string directiveName, DirectiveInfo const * info, vector<string> operands) {
	int positionSkip = 0;
	int opsize = operands.size();

	if ((info->operandCount != -1 && info->operandCount != opsize) || (info->operandCount == -1 && opsize != 0 && opsize != 1)) {
		ShowError("Diretiva invalida: Quantidade de operandos errada.",Syntatic);
		return 0;
	}

	if (directiveName  == "section") {
		positionSkip = ExecuteSection(operands);
	} else if (directiveName == "space") {
		if (opsize == 0) {
			positionSkip = 1;
		} else {
			auto argument = operands[0];
			int toReturn;

			if (TryStringToInt(argument, &toReturn)) {
				return toReturn;
			} else {
				ShowError("Operando Invalido:" + argument, Syntatic);
			}
		}
	} else if (directiveName == "extern") {
		// Insere o rotulo passado na tabela de simbolos com o valor 0
		// e com a flag externa setada
	} else if (directiveName == "public") {
		//insere o operando na tabela de definicoes
	} else if (directiveName == "begin" || directiveName == "end") {

	} else {
		positionSkip = info->size;
	}
	return positionSkip;
}

void Assembler::Assemble() {
	firstPass();
}

void Assembler::firstPass() {
	while (scanner.CanRead()) {
		auto dto = scanner.GetNextTokens();
		if (dto.Operacao=="") {
			if (!dto.isEmpty) {
				successAssemble = false;
			}
			lineCount++;
			continue;
		}

		if (dto.Rotulo != "") {
			auto symbol = TableManager::GetSymbol(dto.Rotulo);
			if (symbol != nullptr) {
				ShowError("Simbolo " + dto.Rotulo + "redefinido", ErrorType::Syntatic);
			} else {
				TableManager::InsertSymbol(dto.Rotulo, SymbolInfo(positionCount,false));
			}
		}

		auto instruction = TableManager::GetInstruction(dto.Operacao);
		if (instruction != nullptr) {
			positionCount += instruction->operandCount + 1;
		} else {
			auto directive = TableManager::GetDirective(dto.Operacao);
			if (directive != nullptr) {
				positionCount += ExecuteDirective(dto.Operacao, directive,dto.Operandos); // IMPLEMENTAR
			} else {
				ShowError("Operacao" + dto.Operacao + "nao identificada", ErrorType::Syntatic);
			}
		}
		lineCount++;
	}
	//preenche a tabela de definicoes com os valores dos simbolos
	//publicos calculados na tabela de simbolos
	TableManager::Diagnostic_PrintSymbols();
}

void Assembler::ShowError(string message, ErrorType type) {
	successAssemble = false;
	ErrorPrinter::ShowError(type, scanner.GetFileName(), lineCount, message);
}

int Assembler::ExecuteSection(vector<string> operands) {
	if (operands[0] == "text") {
		if (sectionFlags & Text) {
			ShowError("SECTION TEXT ja definida", ErrorType::Syntatic);
			return 0;
		}
		sectionFlags = Text;
	} else if (operands[0] == "data") {

		if (sectionFlags & Data) {
			ShowError("SECTION DATA ja definida", ErrorType::Syntatic);
			return 0;
		}

		if (!(sectionFlags & Text)) {
			ShowError("SECTION DATA definida antes de SECTION TEXT", ErrorType::Syntatic);
			return 0;
		}

		sectionFlags = sectionFlags | Data;
	} else {
		ShowError("Diretiva Invalida: SECTION nao indentificada.", Syntatic);
	}
	return 0;
}

bool Assembler::TryStringToInt(string s, int* result) {
	if (StringLibrary::IsInteger(s)) {
		*result = std::stoi(s, nullptr);
		return true;
	} else if (StringLibrary::IsHexadecimal(s)) {
		*result = StringLibrary::ConvertHexaToInt(s);
		return true;
	} else {
		return false;
	}
}
<|endoftext|>


<commit_before>#include "GeneralUtils.h"

#include <sstream>

namespace carto {

    long long GeneralUtils::IntPow(int x, unsigned int p) {
        if (p == 0) return 1;
        if (p == 1) return x;

        long long tmp = IntPow(x, p/2);
        if (p % 2 == 0) {
            return tmp * tmp;
        } else {
            return x * tmp * tmp;
        }
    }

    unsigned int GeneralUtils::UpperPow2(unsigned int n) {
        unsigned int p = 1;
        while (p < n) {
            p <<= 1;
        }
        return p;
    }

    bool GeneralUtils::IsPow2(unsigned int n) {
        return (n != 0) && ((n & (n - 1)) == 0);
    }

    void GeneralUtils::ReplaceSubstrings(std::string& base, const std::string& search, const std::string& replace) {
        for (std::size_t pos = 0;; pos += replace.length()) {
            pos = base.find(search, pos);
            if (pos == std::string::npos) {
                break;
            }
            base.erase(pos, search.length());
            base.insert(pos, replace);
        }
    }

    std::string GeneralUtils::ReplaceTags(const std::string& base, const std::map<std::string, std::string>& tagValues, const std::string& startTag, const std::string& endTag, bool keepUnknownTags) {
        std::string output;
        std::string::size_type pos = 0;
        while (pos < base.size()) {
            std::string::size_type startPos = base.find(startTag, pos);
            if (startPos == std::string::npos) {
                break;
            }
            std::string::size_type endPos = base.find(endTag, startPos + startTag.size());
            if (endPos == std::string::npos) {
                break;
            }
            output += base.substr(pos, startPos - pos);
            std::string tag = base.substr(startPos + startTag.size(), endPos - startPos - startTag.size());
            auto it = tagValues.find(tag);
            if (it != tagValues.end()) {
                output += it->second;
            } else if (keepUnknownTags) {
                output += base.substr(startPos, endPos + endTag.size() - startPos);
            }
            pos = endPos + endTag.size();
        }
        output += base.substr(pos);
        return output;
    }

    std::vector<std::string>& GeneralUtils::Split(const std::string& str, char delim, std::vector<std::string>& elems) {
        std::stringstream ss(str);
        std::string item;
        while (std::getline(ss, item, delim)) {
            elems.push_back(item);
        }
        return elems;
    }

    std::vector<std::string> GeneralUtils::Split(const std::string& str, char delim) {
        std::vector<std::string> elems;
        Split(str, delim, elems);
        return elems;
    }

    std::string GeneralUtils::Join(const std::vector<std::string>& strs, char delim) {
        std::string str;
        for (std::size_t i = 0; i < strs.size(); i++) {
            if (i > 0) {
                str += delim;
            }
            str += strs[i];
        }
        return str;
    }

    GeneralUtils::GeneralUtils() {
    }

}
<commit_msg>Cleanup<commit_after>#include "GeneralUtils.h"

#include <sstream>

namespace carto {

    long long GeneralUtils::IntPow(int x, unsigned int p) {
        if (p == 0) return 1;
        if (p == 1) return x;

        long long tmp = IntPow(x, p/2);
        if (p % 2 == 0) {
            return tmp * tmp;
        } else {
            return x * tmp * tmp;
        }
    }

    unsigned int GeneralUtils::UpperPow2(unsigned int n) {
        unsigned int p = 1;
        while (p < n) {
            p <<= 1;
        }
        return p;
    }

    bool GeneralUtils::IsPow2(unsigned int n) {
        return (n != 0) && ((n & (n - 1)) == 0);
    }

    void GeneralUtils::ReplaceSubstrings(std::string& base, const std::string& search, const std::string& replace) {
        std::string::size_type pos = 0;
        while (pos < base.size()) {
            pos = base.find(search, pos);
            if (pos == std::string::npos) {
                break;
            }
            base.erase(pos, search.size());
            base.insert(pos, replace);
            pos += replace.size();
        }
    }

    std::string GeneralUtils::ReplaceTags(const std::string& base, const std::map<std::string, std::string>& tagValues, const std::string& startTag, const std::string& endTag, bool keepUnknownTags) {
        std::string output;
        std::string::size_type pos = 0;
        while (pos < base.size()) {
            std::string::size_type startPos = base.find(startTag, pos);
            if (startPos == std::string::npos) {
                break;
            }
            std::string::size_type endPos = base.find(endTag, startPos + startTag.size());
            if (endPos == std::string::npos) {
                break;
            }
            output += base.substr(pos, startPos - pos);
            std::string tag = base.substr(startPos + startTag.size(), endPos - startPos - startTag.size());
            auto it = tagValues.find(tag);
            if (it != tagValues.end()) {
                output += it->second;
            } else if (keepUnknownTags) {
                output += base.substr(startPos, endPos + endTag.size() - startPos);
            }
            pos = endPos + endTag.size();
        }
        output += base.substr(pos);
        return output;
    }

    std::vector<std::string>& GeneralUtils::Split(const std::string& str, char delim, std::vector<std::string>& elems) {
        std::stringstream ss(str);
        std::string item;
        while (std::getline(ss, item, delim)) {
            elems.push_back(item);
        }
        return elems;
    }

    std::vector<std::string> GeneralUtils::Split(const std::string& str, char delim) {
        std::vector<std::string> elems;
        Split(str, delim, elems);
        return elems;
    }

    std::string GeneralUtils::Join(const std::vector<std::string>& strs, char delim) {
        std::string str;
        for (std::size_t i = 0; i < strs.size(); i++) {
            if (i > 0) {
                str += delim;
            }
            str += strs[i];
        }
        return str;
    }

    GeneralUtils::GeneralUtils() {
    }

}
<|endoftext|>


<commit_before>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2017 Igor Mironchik

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

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

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

#ifndef ARGS__CMD_LINE_HPP__INCLUDED
#define ARGS__CMD_LINE_HPP__INCLUDED

// Args include.
#include "utils.hpp"
#include "context.hpp"
#include "arg_iface.hpp"
#include "exceptions.hpp"
#include "command.hpp"
#include "types.hpp"

// C++ include.
#include <vector>
#include <algorithm>

namespace Args {

//
// CmdLine
//

/*!
	CmdLine is class that holds all rguments and parse
	command line arguments in the correspondence with holded
	arguments.
*/
class CmdLine final {
public:
	//! Command line options.
	enum CmdLineOpts {
		//! No special options.
		Empty = 0,
		//! Command should be defined.
		CommandIsRequired = 1
	}; // enum CmdLineOpts

#ifdef ARGS_WSTRING_BUILD
	CmdLine( int argc, const Char * const * argv,
		CmdLineOpts opt = Empty );
#else
	CmdLine( int argc, const char * const * argv,
		CmdLineOpts opt = Empty );
#endif

	//! Add argument. \note Developer should handle lifetime of the argument.
	void addArg( ArgIface * arg );

	//! Add argument. \note Developer should handle lifetime of the argument.
	void addArg( ArgIface & arg );

	//! Parse arguments.
	void parse();

	//! \return Argument for the given name.
	ArgIface * findArgument( const String & name );

	//! \return All arguments.
	const std::vector< ArgIface* > & arguments() const;

private:
	//! Check correctness of the arguments before parsing.
	void checkCorrectnessBeforeParsing() const;
	//! Check correctness of the arguments after parsing.
	void checkCorrectnessAfterParsing() const;

private:
	DISABLE_COPY( CmdLine )

	// Context.
	Context m_context;
	//! Arguments.
	std::vector< ArgIface* > m_args;
	//! Current command.
	Command * m_command;
	//! Option.
	CmdLineOpts m_opt;
}; // class CmdLine

//
// makeContext
//

//! Make context from the argc and argv.
static inline ContextInternal
#ifdef ARGS_WSTRING_BUILD
	makeContext( int argc, const Char * const * argv )
#else
	makeContext( int argc, const char * const * argv )
#endif
{
	ContextInternal context;

	// We skip first argv because of it's executable name.
	for( int i = 1; i < argc; ++i )
		context.push_back( argv[ i ] );

	return context;
} // makeContext

//
// CmdLine
//

inline
#ifdef ARGS_WSTRING_BUILD
	CmdLine::CmdLine( int argc, const Char * const * argv, CmdLineOpts opt )
#else
	CmdLine::CmdLine( int argc, const char * const * argv, CmdLineOpts opt )
#endif
	:	m_context( makeContext( argc, argv ) )
	,	m_command( nullptr )
	,	m_opt( opt )
{
}

inline void
CmdLine::addArg( ArgIface * arg )
{
	if( arg )
	{
		if( std::find( m_args.begin(), m_args.end(), arg ) == m_args.end() )
		{
			arg->setCmdLine( this );

			m_args.push_back( arg );
		}
		else
			throw BaseException( String( SL( "Argument \"" ) ) +
				arg->name() + SL( "\" already in the command line parser." ) );
	}
	else
		throw BaseException( String( SL( "Attempt to add nullptr to the "
			"command line as argument." ) ) );
}

inline void
CmdLine::addArg( ArgIface & arg )
{
	addArg( &arg );
}

inline void
CmdLine::parse()
{
	checkCorrectnessBeforeParsing();

	while( !m_context.atEnd() )
	{
		String word = *m_context.next();

		const String::size_type eqIt = word.find( '=' );

		if( eqIt != String::npos )
		{
			const String value = word.substr( eqIt + 1 );

			if( !value.empty() )
				m_context.prepend( value );

			word = word.substr( 0, eqIt );
		}

		if( details::isArgument( word ) )
		{
			auto * arg = findArgument( word );

			if( arg )
				arg->process( m_context );
			else
				throw BaseException( String( SL( "Unknown argument \"" ) ) +
					word + SL( "\"." ) );
		}
		else if( details::isFlag( word ) )
		{
			for( String::size_type i = 1, length = word.length(); i < length; ++i )
			{
				const String flag = String( SL( "-" ) ) +

#ifdef ARGS_QSTRING_BUILD
					String( word[ i ] );
#else
					String( 1, word[ i ] );
#endif

				auto * arg = findArgument( flag );

				if( !arg )
					throw BaseException( String( SL( "Unknown argument \"" ) ) +
						flag + SL( "\"." ) );

				if( i < length - 1 && arg->isWithValue() )
					throw BaseException( String( SL( "Only last argument in "
						"flags combo can have value. Flags combo is\"" ) ) +
						word + SL( "\"." ) );
				else
					arg->process( m_context );
			}
		}
		// Command?
		else
		{
			auto * tmp = findArgument( word );

			if( tmp )
			{
				Command * cmd = dynamic_cast< Command* > ( tmp );

				if( cmd )
				{
					if( m_command )
						throw BaseException( String( SL( "Only one command can be "
							"specified. But you entered \"" ) ) + m_command->name() +
							SL( "\" and \"" ) + cmd->name() + SL( "\"." ) );
					else
					{
						m_command = cmd;

						m_command->process( m_context );
					}
				}
				// Argument is as a command
				else
					tmp->process( m_context );
			}
			else
				throw BaseException( String( SL( "Unknown argument \"" ) ) +
					word + SL( "\"." ) );
		}
	}

	checkCorrectnessAfterParsing();
}

inline const std::vector< ArgIface* > &
CmdLine::arguments() const
{
	return m_args;
}

inline void
CmdLine::checkCorrectnessBeforeParsing() const
{
	StringList flags;
	StringList names;

	std::vector< ArgIface* > cmds;

	std::for_each( m_args.cbegin(), m_args.cend(),
		[ &cmds, &flags, &names ] ( ArgIface * arg )
		{
			if( dynamic_cast< Command* > ( arg ) )
				cmds.push_back( arg );
			else
				arg->checkCorrectnessBeforeParsing( flags, names );
		}
	);

	std::for_each( cmds.cbegin(), cmds.cend(),
		[ &flags, &names ] ( ArgIface * arg )
			{ arg->checkCorrectnessBeforeParsing( flags, names ); }
	);
}

inline void
CmdLine::checkCorrectnessAfterParsing() const
{
	std::for_each( m_args.begin(), m_args.end(),
		[] ( ArgIface * arg )
			{ arg->checkCorrectnessAfterParsing(); }
	);

	if( m_opt == CommandIsRequired && !m_command )
		throw BaseException( SL( "Not specified command." ) );
}

inline ArgIface *
CmdLine::findArgument( const String & name )
{
	auto it = std::find_if( m_args.begin(),
		m_args.end(), [ &name ] ( ArgIface * arg ) -> bool
			{ return ( arg->findArgument( name ) != nullptr ); } );

	if( it != m_args.end() )
	{
		Command * tmp = dynamic_cast< Command* > ( *it );

		if( tmp )
			return tmp;
		else
			return (*it)->findArgument( name );
	}
	else if( m_command )
	{
		ArgIface * tmp = m_command->findChild( name );

		if( tmp )
			return tmp;
	}

	return nullptr;
}

} /* namespace Args */

#endif // ARGS__CMD_LINE_HPP__INCLUDED
<commit_msg>Added messages about misspelled arguments and theirs possible replacements.<commit_after>
/*!
	\file

	\author Igor Mironchik (igor.mironchik at gmail dot com).

	Copyright (c) 2013-2017 Igor Mironchik

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

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

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

#ifndef ARGS__CMD_LINE_HPP__INCLUDED
#define ARGS__CMD_LINE_HPP__INCLUDED

// Args include.
#include "utils.hpp"
#include "context.hpp"
#include "arg_iface.hpp"
#include "exceptions.hpp"
#include "command.hpp"
#include "types.hpp"

// C++ include.
#include <vector>
#include <algorithm>

namespace Args {

namespace details {

//
// formatCorrectNamesString
//

//! \return Prepared for priniting string of correct names.
String formatCorrectNamesString( const StringList & names )
{
	if( !names.empty() )
	{
		String res;

		bool first = true;

		for( const auto & name : names )
		{
			if( !first )
				res.append( SL( " or " ) );

			res.append( name );

			first = false;
		}

		return res;
	}
	else
		return String();
}

} /* namespace details */

//
// CmdLine
//

/*!
	CmdLine is class that holds all rguments and parse
	command line arguments in the correspondence with holded
	arguments.
*/
class CmdLine final {
public:
	//! Command line options.
	enum CmdLineOpts {
		//! No special options.
		Empty = 0,
		//! Command should be defined.
		CommandIsRequired = 1
	}; // enum CmdLineOpts

#ifdef ARGS_WSTRING_BUILD
	CmdLine( int argc, const Char * const * argv,
		CmdLineOpts opt = Empty );
#else
	CmdLine( int argc, const char * const * argv,
		CmdLineOpts opt = Empty );
#endif

	//! Add argument. \note Developer should handle lifetime of the argument.
	void addArg( ArgIface * arg );

	//! Add argument. \note Developer should handle lifetime of the argument.
	void addArg( ArgIface & arg );

	//! Parse arguments.
	void parse();

	//! \return Argument for the given name.
	ArgIface * findArgument( const String & name );

	//! \return All arguments.
	const std::vector< ArgIface* > & arguments() const;

	//! \return Is given name a misspelled name of the argument.
	bool isMisspelledName(
		//! Name to check (misspelled).
		const String & name,
		//! List of possible names for the given misspelled name.
		StringList & possibleNames ) const
	{
		bool ret = false;

		std::for_each( arguments().cbegin(), arguments().cend(),
			[ & ] ( const auto & arg )
			{
				if( arg->isMisspelledName( name, possibleNames ) )
					ret = true;
			} );

		return ret;
	}

private:
	//! Check correctness of the arguments before parsing.
	void checkCorrectnessBeforeParsing() const;
	//! Check correctness of the arguments after parsing.
	void checkCorrectnessAfterParsing() const;
	//! Print information about unknown argument.
	void printInfoAboutUnknownArgument( const String & word )
	{
		StringList correctNames;

		if( isMisspelledName( word, correctNames ) )
		{
			const String names = details::formatCorrectNamesString(
				correctNames );

			throw BaseException( String( SL( "Unknown argument \"" ) ) +
				word + SL( "\".\n\nProbably you mean " ) + names +
				SL( "." ) );
		}
		else
			throw BaseException( String( SL( "Unknown argument \"" ) ) +
				word + SL( "\"." ) );
	}

private:
	DISABLE_COPY( CmdLine )

	// Context.
	Context m_context;
	//! Arguments.
	std::vector< ArgIface* > m_args;
	//! Current command.
	Command * m_command;
	//! Option.
	CmdLineOpts m_opt;
}; // class CmdLine

//
// makeContext
//

//! Make context from the argc and argv.
static inline ContextInternal
#ifdef ARGS_WSTRING_BUILD
	makeContext( int argc, const Char * const * argv )
#else
	makeContext( int argc, const char * const * argv )
#endif
{
	ContextInternal context;

	// We skip first argv because of it's executable name.
	for( int i = 1; i < argc; ++i )
		context.push_back( argv[ i ] );

	return context;
} // makeContext

//
// CmdLine
//

inline
#ifdef ARGS_WSTRING_BUILD
	CmdLine::CmdLine( int argc, const Char * const * argv, CmdLineOpts opt )
#else
	CmdLine::CmdLine( int argc, const char * const * argv, CmdLineOpts opt )
#endif
	:	m_context( makeContext( argc, argv ) )
	,	m_command( nullptr )
	,	m_opt( opt )
{
}

inline void
CmdLine::addArg( ArgIface * arg )
{
	if( arg )
	{
		if( std::find( m_args.begin(), m_args.end(), arg ) == m_args.end() )
		{
			arg->setCmdLine( this );

			m_args.push_back( arg );
		}
		else
			throw BaseException( String( SL( "Argument \"" ) ) +
				arg->name() + SL( "\" already in the command line parser." ) );
	}
	else
		throw BaseException( String( SL( "Attempt to add nullptr to the "
			"command line as argument." ) ) );
}

inline void
CmdLine::addArg( ArgIface & arg )
{
	addArg( &arg );
}

inline void
CmdLine::parse()
{
	checkCorrectnessBeforeParsing();

	while( !m_context.atEnd() )
	{
		String word = *m_context.next();

		const String::size_type eqIt = word.find( '=' );

		if( eqIt != String::npos )
		{
			const String value = word.substr( eqIt + 1 );

			if( !value.empty() )
				m_context.prepend( value );

			word = word.substr( 0, eqIt );
		}

		if( details::isArgument( word ) )
		{
			auto * arg = findArgument( word );

			if( arg )
				arg->process( m_context );
			else
				printInfoAboutUnknownArgument( word );
		}
		else if( details::isFlag( word ) )
		{
			for( String::size_type i = 1, length = word.length(); i < length; ++i )
			{
				const String flag = String( SL( "-" ) ) +

#ifdef ARGS_QSTRING_BUILD
					String( word[ i ] );
#else
					String( 1, word[ i ] );
#endif

				auto * arg = findArgument( flag );

				if( !arg )
					throw BaseException( String( SL( "Unknown argument \"" ) ) +
						flag + SL( "\"." ) );

				if( i < length - 1 && arg->isWithValue() )
					throw BaseException( String( SL( "Only last argument in "
						"flags combo can be with value. Flags combo is \"" ) ) +
						word + SL( "\"." ) );
				else
					arg->process( m_context );
			}
		}
		// Command?
		else
		{
			auto * tmp = findArgument( word );

			if( tmp )
			{
				Command * cmd = dynamic_cast< Command* > ( tmp );

				if( cmd )
				{
					if( m_command )
						throw BaseException( String( SL( "Only one command can be "
							"specified. But you entered \"" ) ) + m_command->name() +
							SL( "\" and \"" ) + cmd->name() + SL( "\"." ) );
					else
					{
						m_command = cmd;

						m_command->process( m_context );
					}
				}
				// Argument is as a command
				else
					tmp->process( m_context );
			}
			else
				printInfoAboutUnknownArgument( word );
		}
	}

	checkCorrectnessAfterParsing();
}

inline const std::vector< ArgIface* > &
CmdLine::arguments() const
{
	return m_args;
}

inline void
CmdLine::checkCorrectnessBeforeParsing() const
{
	StringList flags;
	StringList names;

	std::vector< ArgIface* > cmds;

	std::for_each( m_args.cbegin(), m_args.cend(),
		[ &cmds, &flags, &names ] ( ArgIface * arg )
		{
			if( dynamic_cast< Command* > ( arg ) )
				cmds.push_back( arg );
			else
				arg->checkCorrectnessBeforeParsing( flags, names );
		}
	);

	std::for_each( cmds.cbegin(), cmds.cend(),
		[ &flags, &names ] ( ArgIface * arg )
			{ arg->checkCorrectnessBeforeParsing( flags, names ); }
	);
}

inline void
CmdLine::checkCorrectnessAfterParsing() const
{
	std::for_each( m_args.begin(), m_args.end(),
		[] ( ArgIface * arg )
			{ arg->checkCorrectnessAfterParsing(); }
	);

	if( m_opt == CommandIsRequired && !m_command )
		throw BaseException( SL( "Not specified command." ) );
}

inline ArgIface *
CmdLine::findArgument( const String & name )
{
	auto it = std::find_if( m_args.begin(),
		m_args.end(), [ &name ] ( ArgIface * arg ) -> bool
			{ return ( arg->findArgument( name ) != nullptr ); } );

	if( it != m_args.end() )
	{
		Command * tmp = dynamic_cast< Command* > ( *it );

		if( tmp )
			return tmp;
		else
			return (*it)->findArgument( name );
	}
	else if( m_command )
	{
		ArgIface * tmp = m_command->findChild( name );

		if( tmp )
			return tmp;
	}

	return nullptr;
}

} /* namespace Args */

#endif // ARGS__CMD_LINE_HPP__INCLUDED
<|endoftext|>


<commit_before>#include "ngraph.h"
#include <PCU.h>
#include <unordered_set>
#include <vector>
#include <engpar_support.h>
namespace agi {
  typedef std::unordered_set<GraphVertex*> VertexVector;
  //TODO: Make a vector by using a "tag" on the edges to detect added or not
  typedef std::unordered_set<GraphEdge*> EdgeVector;
  void Ngraph::updateGhostOwners(Migration* plan) {
    PCU_Comm_Begin();
    Migration::iterator itr;
    for (itr = plan->begin();itr!=plan->end();itr++) {
      GraphVertex* v = itr->first;
      part_t toSend = itr->second;
      GraphIterator* gitr = adjacent(v);
      GraphVertex* other;
      while ((other=iterate(gitr))) {
        part_t own = owner(other);
        if (own!=PCU_Comm_Self()) {
          gid_t gid = globalID(v);
          PCU_COMM_PACK(own,gid);
          PCU_COMM_PACK(own,toSend);
        }
      }
    }
    PCU_Comm_Send();
    while (PCU_Comm_Receive()) {
      gid_t gid;
      part_t own;
      PCU_COMM_UNPACK(gid);
      PCU_COMM_UNPACK(own);
      lid_t lid = vtx_mapping[gid];
      if (lid>=num_local_verts) {
        assert(lid>=num_local_verts);
        owners[lid-num_local_verts]=own;
      }
    }
  }
  /*
    Finds the vertices and edges that need to be communicated
    Also stores the local vertices and edges that will be owned
    on this part after migration
  */
  void getAffected(Ngraph* g, Migration* plan, VertexVector& verts,
                   EdgeVector* edges) {
    verts.reserve(plan->size());
    Migration::iterator itr;
    for (itr = plan->begin();itr!=plan->end();itr++) {
      GraphVertex* v = itr->first;
      part_t toSend = itr->second;
      if (toSend!=PCU_Comm_Self()) {
        verts.insert(v);
      }
    }

    //For each edge type
    for (etype t = 0;t<g->numEdgeTypes();t++) {
      //edges[t].reserve(verts.size());
      VertexVector::iterator itr;
      //loop through the vertices being sent
      for (itr = verts.begin();itr!=verts.end();itr++) {
        GraphIterator* gitr =g->adjacent(*itr);
        GraphEdge* e;
        GraphEdge* old=NULL;
        GraphVertex* v;
        while ((v = g->iterate(gitr))) {
          e=g->edge(gitr);
          if (old==NULL||e!=old)
            edges[t].insert(e);
        }
      }
    }
  }

  void addVertices(Ngraph* g, std::vector<gid_t>& ownedVerts,
                   VertexVector& verts, std::vector<wgt_t>& weights,
                   std::vector<part_t>& originalOwners) {
    VertexIterator* vitr = g->begin();
    GraphVertex* v;
    while ((v = g->iterate(vitr))) {
      if (verts.find(v)==verts.end()) {
        ownedVerts.push_back(g->globalID(v));
        weights.push_back(g->weight(v));
        originalOwners.push_back(g->originalOwner(v));
      }
    }
  }
  void addEdges(Ngraph* g, Migration* plan, std::vector<gid_t>& ownedEdges,
                std::vector<wgt_t>& edgeWeights,
                std::vector<lid_t>& degrees,std::vector<gid_t>& pins,
                std::unordered_map<gid_t,part_t>& ghost_owners,
                std::unordered_set<gid_t>& addedEdges,
                etype t) {
    VertexIterator* itr = g->begin();
    GraphVertex* v;
    while ((v = g->iterate(itr))) {
      if (plan->find(v)!=plan->end())
        continue;
      GraphVertex* other;
      GraphIterator* gitr = g->adjacent(v,t);
      GraphEdge* e,*old = NULL;
      while ((other = g->iterate(gitr))) {
        e=g->edge(gitr);
        if (addedEdges.find(g->globalID(e))!=addedEdges.end())
          continue;
        if (old==NULL||e!=old) {
          if (old&&g->isHyper())
            addedEdges.insert(g->globalID(old));
          if (g->isHyper()) {
            ownedEdges.push_back(g->globalID(e));
            edgeWeights.push_back(g->weight(e));
            degrees.push_back(g->degree(e));
          }
          else {
            ownedEdges.push_back(g->localID(e));
            edgeWeights.push_back(g->weight(e));
            pins.push_back(g->globalID(v));
            degrees.push_back(2);
          }
        }
        old=e;
        gid_t other_gid = g->globalID(other);
        pins.push_back(other_gid);
        part_t owner = g->owner(other);
        if (plan->find(other)!=plan->end())
          owner = plan->find(other)->second;
        if (owner!=PCU_Comm_Self())
          ghost_owners[other_gid] = owner;
      }
      addedEdges.insert(g->globalID(old));
    }
  }

  void Ngraph::sendVertex(GraphVertex* vtx, part_t toSend) {
    gid_t gid = globalID(vtx);
    wgt_t w = weight(vtx);
    part_t old_owner = originalOwner(vtx);
    PCU_COMM_PACK(toSend,gid);
    PCU_COMM_PACK(toSend,w);
    PCU_COMM_PACK(toSend,old_owner);
  }

  void Ngraph::recvVertex(std::vector<gid_t>& recv,
                          std::vector<wgt_t>& wgts,
                          std::vector<part_t>& old_owners) {
    gid_t gid;
    PCU_COMM_UNPACK(gid);
    wgt_t w;
    PCU_COMM_UNPACK(w);
    part_t old_owner;
    PCU_COMM_UNPACK(old_owner);
    recv.push_back(gid);
    wgts.push_back(w);
    old_owners.push_back(old_owner);
  }

  void Ngraph::sendEdges(Migration* plan, EdgeVector& affectedEdges) {
    EdgeVector::iterator eitr;
    for (eitr = affectedEdges.begin();eitr!=affectedEdges.end();
         eitr++) {
      GraphEdge* e = *eitr;
      gid_t* pin;
      part_t* pin_owners;
      lid_t deg=0;
      gid_t id;
      wgt_t eweight = weight(e);
      std::unordered_set<part_t> residence;
      if (isHyperGraph) {
        id = globalID(e);
        pin = new gid_t[degree(e)];
        pin_owners = new part_t[degree(e)];
        agi::PinIterator* pitr = this->pins(e);
        agi::GraphVertex* vtx;
        for (lid_t i=0;i<degree(e);i++) {
          vtx = iterate(pitr);
          part_t o = owner(vtx);

          if (plan->find(vtx)!=plan->end())
            o= plan->find(vtx)->second;
          pin_owners[deg]=o;
          pin[deg++] = globalID(vtx);
          residence.insert(o);
        }
        destroy(pitr);
      }
      else {
        id = localID(e);
        pin = new gid_t[2];
        pin_owners = new part_t[2];
        GraphVertex* source = u(e);
        pin_owners[deg] = owner(source);
        pin[deg++] = globalID(source);
        GraphVertex* dest = v(e);
        part_t o = owner(dest);
        if (plan->find(dest)!=plan->end())
          o= plan->find(dest)->second;
        pin_owners[deg] = o;
        pin[deg++] = globalID(dest);
        Migration::iterator mitr = plan->find(source);
        pin_owners[0] = mitr->second;
        assert(mitr!=plan->end());
        residence.insert(mitr->second);
      }
      std::unordered_set<part_t>::iterator sitr;
      for (sitr=residence.begin();sitr!=residence.end();sitr++) {
        PCU_COMM_PACK(*sitr,id);
        PCU_COMM_PACK(*sitr,eweight);
        PCU_COMM_PACK(*sitr,deg);
        PCU_Comm_Pack(*sitr,pin,deg*sizeof(gid_t));
        PCU_Comm_Pack(*sitr,pin_owners,deg*sizeof(part_t));

      }
      delete [] pin;
      delete [] pin_owners;
    }

  }

  void Ngraph::recvEdges(std::unordered_set<gid_t>& addedEdges,
                         std::vector<gid_t>& ownedEdges, std::vector<wgt_t>& edgeWeights,
                         std::vector<lid_t>& degrees, std::vector<gid_t>& pins,
                         std::unordered_map<gid_t,part_t>& ghost_owners,
                         etype t) {
    while (PCU_Comm_Receive()) {
      gid_t id;
      wgt_t eweight;
      lid_t deg;
      PCU_COMM_UNPACK(id);
      PCU_COMM_UNPACK(eweight);
      PCU_COMM_UNPACK(deg);
      gid_t* pin = new gid_t[deg];
      part_t* pin_owners = new part_t[deg];
      PCU_Comm_Unpack(pin,deg*sizeof(gid_t));
      PCU_Comm_Unpack(pin_owners,deg*sizeof(part_t));
      if (isHyperGraph) {
        if (addedEdges.find(id)!=addedEdges.end())
          continue;
      }
      addedEdges.insert(id);
      edge_mapping[t][id]=0;
      ownedEdges.push_back(id);
      edgeWeights.push_back(eweight);
      degrees.push_back(deg);
      for (lid_t i=0;i<deg;i++) {
        pins.push_back(pin[i]);
        if (pin_owners[i]!=PCU_Comm_Self())
          ghost_owners[pin[i]]=pin_owners[i];
      }
      delete [] pin;
      delete [] pin_owners;
    }

  }
  void Ngraph::migrate(Migration* plan) {
    int nt = num_types;
    updateGhostOwners(plan);
    VertexVector affectedVerts;
    EdgeVector* affectedEdges = new EdgeVector[nt];
    std::vector<gid_t> ownedVerts;
    std::vector<wgt_t> vertWeights;
    std::vector<part_t> old_owners;
    ownedVerts.reserve(num_local_verts);
    vertWeights.reserve(num_local_verts);

    std::vector<gid_t>* ownedEdges = new std::vector<gid_t>[nt];
    std::vector<wgt_t>* edgeWeights = new std::vector<wgt_t>[nt];
    std::vector<lid_t>* degrees = new std::vector<lid_t>[nt];
    std::vector<gid_t>* pins = new std::vector<gid_t>[nt];
    std::unordered_map<gid_t,part_t> ghost_owners;

    getAffected(this,plan,affectedVerts,affectedEdges);
    addVertices(this,ownedVerts,affectedVerts,vertWeights,old_owners);
    std::unordered_set<gid_t>* addedEdges = new std::unordered_set<gid_t>[nt];
    for (etype i=0;i<nt;i++)
      addEdges(this,plan,ownedEdges[i],edgeWeights[i],degrees[i],pins[i],
               ghost_owners,addedEdges[i],i);

    //Send and recieve vertices
    Migration::iterator itr;
    PCU_Comm_Begin();
    for (itr = plan->begin();itr!=plan->end();itr++) {
      sendVertex(itr->first,itr->second);
    }
    PCU_Comm_Send();
    while (PCU_Comm_Receive()) {
      recvVertex(ownedVerts,vertWeights,old_owners);
    }

    //Send and receive edges of each type
    for (etype t = 0;t < nt;t++) {
      PCU_Comm_Begin();
      sendEdges(plan,affectedEdges[t]);
      PCU_Comm_Send();
      recvEdges(addedEdges[t],ownedEdges[t],edgeWeights[t],degrees[t],
                pins[t],ghost_owners,t);
    }
    delete [] addedEdges;

    //Construct the migrated graph
    constructVerts(isHyperGraph,ownedVerts,vertWeights);
    for (int i=0;i<nt;i++) {
      constructEdges(ownedEdges[i],degrees[i],pins[i]);
      setEdgeWeights(edgeWeights[i],i);
    }
    constructGhosts(ghost_owners);
    setOriginalOwners(old_owners);

    delete [] affectedEdges;
    delete [] ownedEdges;
    delete [] edgeWeights;
    delete [] degrees;
    delete [] pins;
    delete plan;
  }

  PartitionMap* Ngraph::getPartition() {
    if (EnGPar_Is_Log_Open()) {
      char message[20];
      sprintf(message,"getPartition\n");
      EnGPar_Log_Function(message);
    }

    PCU_Comm_Begin();
    VertexIterator* itr = begin();
    GraphVertex* vtx;
    while ((vtx = iterate(itr))) {
      gid_t v = globalID(vtx);
      PCU_COMM_PACK(originalOwner(vtx),v);
    }
    PCU_Comm_Send();
    PartitionMap* map = new PartitionMap;
    while (PCU_Comm_Receive()) {
      gid_t v;
      PCU_COMM_UNPACK(v);
      map->insert(std::make_pair(v,PCU_Comm_Sender()));
    }
    if (EnGPar_Is_Log_Open()) {
      EnGPar_End_Function();
    }
    PCU_Barrier();
    return map;
  }

}
<commit_msg>This file was not meant to be pushed<commit_after><|endoftext|>


<commit_before>#include "..\include\model.h"

void Model::init(const char* filename) {
	int lc = line_count(filename);
	std::vector<int> preproc_data = file_preprocess(filename);
	std::vector <std::pair<int, int>> begin_end_markers = file_preprocess_full(preproc_data, lc);

	for (int i = 0; i < begin_end_markers.size(); i++) {
		Mesh mesh;
		load_model(filename, begin_end_markers.back(), mesh);
	}
}

std::vector<std::pair<int, int>> Model::file_preprocess_full(std::vector<int>& preproc_data, int linecount) {
	std::vector <std::pair<int, int>> begin_end_markers;
	for (int i = 0; i < preproc_data.size(); i++) {
		std::pair<int, int> marker;

		if (i == 0)
			marker.first = 3;
		else
			marker.first = preproc_data[i];

		if (i == preproc_data.size() - 1)
			marker.second = linecount - 1;
		else
			marker.second = preproc_data[i + 1] - 2;

		begin_end_markers.push_back(marker);
	}

	return begin_end_markers;
}

int Model::line_count(const char* filename) {
	int count = 0;
	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	while (std::getline(ifs, line)) {
		count++;
	}

	ifs.close();
	return count;
}

std::vector<int> Model::file_preprocess(const char* filename) {

	std::vector<int> preproc_data;

	int current_line_number = 0;

	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	while (std::getline(ifs, line)) {
		current_line_number++;

		if (line.front() == 'o')
			preproc_data.push_back(current_line_number);
	}

	ifs.close();
	return preproc_data;
}

void Model::load_model(const char* filename, const std::pair<int, int>& begin_end, Mesh& mesh) {
	std::string line;

	std::vector<vec3> temp_vertices;
	std::vector<vec3> temp_normals;
	std::vector<vec2> temp_uvs;

	std::vector<int> vertex_indices;
	std::vector<int> normal_indices;
	std::vector<int> uv_indices;

	mesh.uvs_included = check_uvs_included(filename);

	std::ifstream ifs(filename, std::istream::in);

	int line_num = 0;
	while (std::getline(ifs, line)) {
		if(line_num >= begin_end.first && line_num <= begin_end.second) {
			std::istringstream iss(line);
			std::string type;
			iss >> type;

			if (type == "v") {
				float x, y, z;
				iss >> x >> y >> z;
				temp_vertices.push_back({ x, y, z });
			}
			else if (type == "vn") {
				float x, y, z;
				iss >> x >> y >> z;
				temp_normals.push_back({ x, y, z });
			}
			else if (type == "vt") {
				float u, v;
				iss >> u >> v;
				temp_uvs.push_back({ u, v });
			}
			else if (type == "f") {
				process_face(line, mesh.uvs_included, vertex_indices, uv_indices, normal_indices);
			}
		}
		line_num++;
	}

	ifs.close();

	for (int i = 0; i < vertex_indices.size(); i++) {
		vec3 vertex = { temp_vertices[vertex_indices[i]].x, temp_vertices[vertex_indices[i]].y, temp_vertices[vertex_indices[i]].z };
		vec3 normal = { temp_normals[normal_indices[i]].x, temp_normals[normal_indices[i]].y, temp_normals[normal_indices[i]].z };
		mesh.vertices.push_back(vertex);
		mesh.normals.push_back(normal);

		if (mesh.uvs_included) {
			vec2 uv = { temp_uvs[uv_indices[i]].x, 1.f - temp_uvs[uv_indices[i]].y };
			mesh.uvs.push_back(uv);
		}
	}
}

void Model::process_face(std::string& line, bool uvs_included, std::vector<int>& vertex_indices, std::vector<int>& uv_indices, std::vector<int>& normal_indices) {
	int x_vert, y_vert, z_vert;
	int x_norm, y_norm, z_norm;

	const char* s = line.c_str();

	if (uvs_included) {
		int x_uv, y_uv, z_uv;

		sscanf_s(s, "f %d/%d/%d %d/%d/%d %d/%d/%d", &x_vert, &x_uv, &x_norm, &y_vert, &y_uv, &y_norm, &z_vert, &z_uv, &z_norm);

		uv_indices.push_back(--x_uv);
		uv_indices.push_back(--y_uv);
		uv_indices.push_back(--z_uv);
	}
	else {
		sscanf_s(s, "f %d//%d %d//%d %d//%d", &x_vert, &x_norm, &y_vert, &y_norm, &z_vert, &z_norm);
	}

	vertex_indices.push_back(--x_vert);
	vertex_indices.push_back(--y_vert);
	vertex_indices.push_back(--z_vert);

	normal_indices.push_back(--x_norm);
	normal_indices.push_back(--y_norm);
	normal_indices.push_back(--z_norm);
}

bool Model::check_uvs_included(const char* filename) {
	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	size_t pos;
	bool b = false;
	while (std::getline(ifs, line)) {
		pos = line.find('f');
		if (pos != std::string::npos && pos == 0) {
			char last = '1';
			for (int i = 0; i < line.length(); i++) {
				char c = line.at(i);
				if (c == '/' && last == '/')
					return false;
				else
					last = c;
			}

			return true;
		}
	}

	ifs.close();
	return b;
}<commit_msg>fixed model loading with new changes<commit_after>#include "..\include\model.h"

void Model::init(const char* filename) {
	int lc = line_count(filename);
	std::vector<int> preproc_data = file_preprocess(filename);
	std::vector <std::pair<int, int>> begin_end_markers = file_preprocess_full(preproc_data, lc);

	for (int i = 0; i < begin_end_markers.size(); i++) {
		Mesh mesh;
		load_model(filename, begin_end_markers.back(), mesh);
		meshes.push_back(mesh);
	}
}

std::vector<std::pair<int, int>> Model::file_preprocess_full(std::vector<int>& preproc_data, int linecount) {
	std::vector <std::pair<int, int>> begin_end_markers;
	for (int i = 0; i < preproc_data.size(); i++) {
		std::pair<int, int> marker;

		if (i == 0)
			marker.first = 3;
		else
			marker.first = preproc_data[i];

		if (i == preproc_data.size() - 1)
			marker.second = linecount - 1;
		else
			marker.second = preproc_data[i + 1] - 2;

		begin_end_markers.push_back(marker);
	}

	return begin_end_markers;
}

int Model::line_count(const char* filename) {
	int count = 0;
	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	while (std::getline(ifs, line)) {
		count++;
	}

	ifs.close();
	return count;
}

std::vector<int> Model::file_preprocess(const char* filename) {

	std::vector<int> preproc_data;

	int current_line_number = 0;

	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	while (std::getline(ifs, line)) {
		current_line_number++;

		if (line.front() == 'o')
			preproc_data.push_back(current_line_number);
	}

	ifs.close();
	return preproc_data;
}

void Model::load_model(const char* filename, const std::pair<int, int>& begin_end, Mesh& mesh) {
	std::string line;

	std::vector<vec3> temp_vertices;
	std::vector<vec3> temp_normals;
	std::vector<vec2> temp_uvs;

	std::vector<int> vertex_indices;
	std::vector<int> normal_indices;
	std::vector<int> uv_indices;

	mesh.uvs_included = check_uvs_included(filename);

	std::ifstream ifs(filename, std::istream::in);

	int line_num = 0;
	while (std::getline(ifs, line)) {
		if(line_num >= begin_end.first && line_num <= begin_end.second) {
			std::istringstream iss(line);
			std::string type;
			iss >> type;

			if (type == "v") {
				float x, y, z;
				iss >> x >> y >> z;
				temp_vertices.push_back({ x, y, z });
			}
			else if (type == "vn") {
				float x, y, z;
				iss >> x >> y >> z;
				temp_normals.push_back({ x, y, z });
			}
			else if (type == "vt") {
				float u, v;
				iss >> u >> v;
				temp_uvs.push_back({ u, v });
			}
			else if (type == "f") {
				process_face(line, mesh.uvs_included, vertex_indices, uv_indices, normal_indices);
			}
		}
		line_num++;
	}

	ifs.close();

	for (int i = 0; i < vertex_indices.size(); i++) {
		vec3 vertex = { temp_vertices[vertex_indices[i]].x, temp_vertices[vertex_indices[i]].y, temp_vertices[vertex_indices[i]].z };
		vec3 normal = { temp_normals[normal_indices[i]].x, temp_normals[normal_indices[i]].y, temp_normals[normal_indices[i]].z };
		mesh.vertices.push_back(vertex);
		mesh.normals.push_back(normal);

		if (mesh.uvs_included) {
			vec2 uv = { temp_uvs[uv_indices[i]].x, 1.f - temp_uvs[uv_indices[i]].y };
			mesh.uvs.push_back(uv);
		}
	}
}

void Model::process_face(std::string& line, bool uvs_included, std::vector<int>& vertex_indices, std::vector<int>& uv_indices, std::vector<int>& normal_indices) {
	int x_vert, y_vert, z_vert;
	int x_norm, y_norm, z_norm;

	const char* s = line.c_str();

	if (uvs_included) {
		int x_uv, y_uv, z_uv;

		sscanf_s(s, "f %d/%d/%d %d/%d/%d %d/%d/%d", &x_vert, &x_uv, &x_norm, &y_vert, &y_uv, &y_norm, &z_vert, &z_uv, &z_norm);

		uv_indices.push_back(--x_uv);
		uv_indices.push_back(--y_uv);
		uv_indices.push_back(--z_uv);
	}
	else {
		sscanf_s(s, "f %d//%d %d//%d %d//%d", &x_vert, &x_norm, &y_vert, &y_norm, &z_vert, &z_norm);
	}

	vertex_indices.push_back(--x_vert);
	vertex_indices.push_back(--y_vert);
	vertex_indices.push_back(--z_vert);

	normal_indices.push_back(--x_norm);
	normal_indices.push_back(--y_norm);
	normal_indices.push_back(--z_norm);
}

bool Model::check_uvs_included(const char* filename) {
	std::string line;
	std::ifstream ifs(filename, std::istream::in);

	size_t pos;
	bool b = false;
	while (std::getline(ifs, line)) {
		pos = line.find('f');
		if (pos != std::string::npos && pos == 0) {
			char last = '1';
			for (int i = 0; i < line.length(); i++) {
				char c = line.at(i);
				if (c == '/' && last == '/')
					return false;
				else
					last = c;
			}

			return true;
		}
	}

	ifs.close();
	return b;
}<|endoftext|>


<commit_before>#include "model.hpp"

namespace Model {
	template<typename S, typename T, typename U, typename V>
	void Model::contour<S,T,U,V>::operator()(S *dest, U u, V v) {
		dest[0] = u;
		dest[1] = v;
		dest[2] = 0;
	}
}
<commit_msg>Removed contour<commit_after>#include "model.hpp"

namespace Model {
	/*template<typename S, typename T, typename U, typename V>
	void Model::contour<S,T,U,V>::operator()(S *dest, U u, V v) {
		dest[0] = u;
		dest[1] = v;
		dest[2] = 0;
	}*/
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Smirnov Vladimir mapron1@gmail.com
 * Source code licensed under the Apache License, Version 2.0 (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 or in file COPYING-APACHE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.h
 */

#include "TcpSocket.h"

#include "Tcp_private.h"
#include "TcpConnectionParams_private.h"
#include "TcpListener.h"
#include "Syslogger.h"

#include <algorithm>
#include <vector>
#include <stdint.h>
#include <memory>
#include <cstring>

//#define SOCKET_DEBUG  // for debugging.

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#ifdef TCP_SOCKET_WIN

void SocketEngineCheck()
{
	struct WSA_RAII {
		WSA_RAII() {  int ec;
					 WSADATA wsa;

							  if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0)
								  Wuild::Syslogger(Syslogger::Err) <<  "WIN32_SOCKET: winsock error: code " << ec;
				  }
		~WSA_RAII() { WSACleanup(); }
	};

	static WSA_RAII init ;
}

#endif

namespace
{
	const size_t g_defaultBufferSize = 4 * 1024;
}

namespace Wuild
{

std::atomic_bool TcpSocket::s_applicationInterruption(false);

TcpSocket::TcpSocket(const TcpConnectionParams &params)
	: m_params(params)
	, m_impl(new TcpSocketPrivate())
{
	SocketEngineCheck();
	m_logContext = params.GetShortInfo();
	Syslogger(m_logContext) << "TcpSocket::TcpSocket() ";
}

TcpSocket::~TcpSocket()
{
	Disconnect();
}

IDataSocket::Ptr TcpSocket::Create(const TcpConnectionParams &params, TcpListener *pendingListener)
{
	auto sock  = new TcpSocket(params);
	sock->SetListener(pendingListener);
	return IDataSocket::Ptr(sock);
}

bool TcpSocket::Connect ()
{
	if (s_applicationInterruption)
		return false;

	if (m_state == ConnectionState::Success)
		return true;

	if (m_acceptedByListener)
	{
		if (m_state == ConnectionState::Fail)
			return false;

		if (m_state == ConnectionState::Pending && m_pendingListener->DoAccept(this))
		{
			SetBufferSize();
			if (m_impl->SetBlocking(false))
			{
				m_state = ConnectionState::Success;
				return true;
			}
		}
		m_state = ConnectionState::Fail;
		return false;
	}
	Syslogger(m_logContext) << "Trying to connect..." ;

	if (m_impl->m_socket != INVALID_SOCKET)
	{
		Syslogger(m_logContext, Syslogger::Alert) << "Trying to reopen existing socket!" ;
		return false;
	}

	if (!m_params.Resolve())
		return false;

	m_impl->m_socket = socket(m_params.m_impl->ai->ai_family, m_params.m_impl->ai->ai_socktype, m_params.m_impl->ai->ai_protocol);
	if (m_impl->m_socket == INVALID_SOCKET)
	{
		Syslogger(m_logContext, Syslogger::Err) << "socket creation failed." ;
		Fail();
		return false;
	}

	SetBufferSize();
	if (!m_impl->SetNoSigPipe())
	{
		Syslogger(m_logContext, Syslogger::Warning) << "Failed to disable SIGPIPE signal." ;
	}
	if (!m_impl->SetBlocking(false))
	{
		Fail();
		return false;
	}

	int cres = connect(m_impl->m_socket, m_params.m_impl->ai->ai_addr, m_params.m_impl->ai->ai_addrlen);
	if (cres < 0)
	{

		const auto err = SocketGetLastError();
		const bool inProgress = SocketCheckConnectionPending(err);
		if (inProgress)
		{
			struct timeval timeout;
			SET_TIMEVAL_US(timeout, m_params.m_connectTimeout);
			fd_set select_set;
			FD_ZERO( &select_set );
			FD_SET( m_impl->m_socket, &select_set );
			int valopt;
			socklen_t valopt_len = sizeof(valopt);

			if (select( m_impl->m_socket + 1, 0, &select_set, 0, &timeout ) <= 0 || !FD_ISSET( m_impl->m_socket, &select_set ) ||
				getsockopt( m_impl->m_socket, SOL_SOCKET, SO_ERROR, SOCK_OPT_ARG (&valopt), &valopt_len ) < 0 || valopt
					)
			{
				Syslogger(m_logContext) << "Connection timeout." ;
				Fail();
				return false;
			}
		}
		else
		{
			Syslogger(m_logContext) << "Connection failed. ("<< cres << ") err=" << err ;
			Fail();
			return false;
		}
	}

	m_state = ConnectionState::Success;
	Syslogger(m_logContext) << "Connected.";
	return true;
}

void TcpSocket::Disconnect()
{
	m_state = ConnectionState::Fail;
	if (m_impl->m_socket != INVALID_SOCKET)
	{
		Syslogger(m_logContext) << "TcpSocket::Disconnect() ";
		close( m_impl->m_socket );
		m_impl->m_socket = INVALID_SOCKET;
	}
}

bool TcpSocket::IsConnected() const
{
	return m_state == ConnectionState::Success;
}

bool TcpSocket::IsPending() const
{
	return m_state == ConnectionState::Pending;
}

IDataSocket::ReadState TcpSocket::Read(ByteArrayHolder & buffer)
{
	if (!IsConnected())
		return ReadState::Fail;

	if (!IsSocketReadReady( ))
		return ReadState::TryAgain;

	if (!SelectRead( m_params.m_readTimeout ))  //Нет данных в порту
		return ReadState::TryAgain;

	size_t bufferInitialSize = buffer.size();(void)bufferInitialSize;
	char tmpbuffer[0x4000]; // 16k buffer. stack is rather cheap...
	int recieved, totalRecieved = 0;
	do {

	  recieved =
		#ifdef TCP_SOCKET_WIN
			recv( m_impl->m_socket, tmpbuffer, sizeof(tmpbuffer), 0 );
		#else
			read( m_impl->m_socket, tmpbuffer, sizeof(tmpbuffer) );
		#endif
	  if (recieved == 0)
		  break;

	  if (recieved < 0)
	  {
		  const auto err = SocketGetLastError();
		  if (SocketRWPending(err) )
			  break;
		  Syslogger(m_logContext, Syslogger::Err) << "Disconnecting while Reading ("<< recieved << ") err=" << err;
		  Disconnect();
		  return ReadState::Fail;
	  }
	  totalRecieved += recieved;
	  buffer.ref().insert(buffer.ref().end(), tmpbuffer, tmpbuffer + recieved );

	} while(recieved == sizeof(tmpbuffer));

#ifdef SOCKET_DEBUG
	Syslogger(m_logContext) << "TcpSocket::Read: " << Syslogger::Binary(buffer.data() + bufferInitialSize, totalRecieved);
#endif

	return totalRecieved > 0 ? ReadState::Success : ReadState::TryAgain;
}

TcpSocket::WriteState TcpSocket::Write(const ByteArrayHolder & buffer, size_t maxBytes)
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return WriteState::Fail;

	maxBytes = std::min(maxBytes, buffer.size());

	auto written = send( m_impl->m_socket, (const char*)(buffer.data()), maxBytes, MSG_NOSIGNAL);
	if (written < 0)
	{
		const auto err = SocketGetLastError();
		if (SocketRWPending(err))
			return WriteState::TryAgain;

		const int EPIPE_code = 32;
		Syslogger(m_logContext, err == EPIPE_code ? Syslogger::Info : Syslogger::Err) << "Disconnecting while Writing, (" << written << ") err=" << err;
		Disconnect();
		return WriteState::Fail;
	}

#ifdef SOCKET_DEBUG
	Syslogger(m_logContext) << "TcpSocket::Write: " << Syslogger::Binary(buffer.data(), written);
#endif
	return maxBytes == written ? WriteState::Success : WriteState::Fail;
}

void TcpSocket::SetListener(TcpListener* pendingListener)
{
	if (!pendingListener)
		return;

	m_state = ConnectionState::Pending;
	m_pendingListener = pendingListener;
	m_acceptedByListener = true;
}

void TcpSocket::Fail ()
{
	Syslogger(m_logContext) << "Disconnection cased by Fail()";
	Disconnect();
}

bool TcpSocket::IsSocketReadReady()
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return false;

	fd_set set;
	FD_ZERO( &set );
	FD_SET( m_impl->m_socket, &set );

	struct timeval timeout = { 0, 0 };
	int selected = select( m_impl->m_socket + 1U, &set, 0, 0, &timeout );
	if (selected < 0)
	{
		Syslogger(m_logContext) << "Disconnect from IsSocketReadReady" ;
		Disconnect();
		return false;
	}
	return (selected != 0 && FD_ISSET( m_impl->m_socket, &set ));
}

bool TcpSocket::SelectRead (const TimePoint &timeout)
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return false;

	bool res= false;
	fd_set selected;
	FD_ZERO( &selected );
	FD_SET( m_impl->m_socket, &selected );
	struct timeval timeoutTV;
	SET_TIMEVAL_US(timeoutTV, timeout);
	res = select( m_impl->m_socket + 1, &selected, 0, 0, &timeoutTV ) > 0 && FD_ISSET( m_impl->m_socket, &selected );
	return res;
}

void TcpSocket::SetBufferSize()
{
	m_recieveBufferSize = m_impl->GetRecieveBuffer();
	if (m_recieveBufferSize < m_params.m_recommendedRecieveBufferSize)
	{
		if (!m_impl->SetRecieveBuffer(m_params.m_recommendedRecieveBufferSize))
		{
			Syslogger(m_logContext, Syslogger::Info) << "Failed to set recieve socket buffer size:" << m_params.m_recommendedRecieveBufferSize;
		}
		m_recieveBufferSize = m_impl->GetRecieveBuffer();
	}
	m_sendBufferSize = m_impl->GetSendBuffer();
	if (m_sendBufferSize < m_params.m_recommendedSendBufferSize)
	{
		if (!m_impl->SetSendBuffer(m_params.m_recommendedSendBufferSize))
		{
			Syslogger(m_logContext, Syslogger::Info) << "Failed to set send socket buffer size:" << m_params.m_recommendedSendBufferSize;
		}
		m_sendBufferSize = m_impl->GetSendBuffer();
	}
}

bool TcpSocketPrivate::SetBlocking(bool blocking)
{
#if  defined(TCP_SOCKET_WIN )
	u_long flags = blocking ? 0 : 1;
	if(ioctlsocket( m_socket, FIONBIO, &flags ) != NO_ERROR)
	{
		Syslogger(Syslogger::Err) << "ioctlsocket(FIONBIO O_NONBLOCK) failed." ;
		return false;
	}
#else
	long flags = fcntl( m_socket, F_GETFL, 0 );
	if (flags < 0)
	{
		Syslogger(Syslogger::Err) << "fcntl(F_GETFL) failed." ;
		return false;
	}
	if (!blocking)
		flags |= O_NONBLOCK;
	else
		flags &= ~O_NONBLOCK;

	if(fcntl( m_socket, F_SETFL, flags ) < 0)
	{
		Syslogger(Syslogger::Err) << "fcntl(F_SETFL O_NONBLOCK) failed." ;
		return false;
	}
#endif
	return true;
}

bool TcpSocketPrivate::SetRecieveBuffer(uint32_t size)
{
	int valopt = static_cast<int>(size);
	socklen_t valopt_len = sizeof(valopt);
	return setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, SOCK_OPT_ARG &valopt, valopt_len) == 0;
}

uint32_t TcpSocketPrivate::GetRecieveBuffer()
{
	int valopt = 0;
	socklen_t valopt_len = sizeof(valopt);
	if (getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, SOCK_OPT_ARG &valopt, &valopt_len))
		return g_defaultBufferSize;

	return static_cast<uint32_t>(valopt);
}
bool TcpSocketPrivate::SetSendBuffer(uint32_t size)
{
	int valopt = static_cast<int>(size);
	socklen_t valopt_len = sizeof(valopt);
	return setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, SOCK_OPT_ARG &valopt, valopt_len) == 0;
}

uint32_t TcpSocketPrivate::GetSendBuffer()
{
	int valopt = 0;
	socklen_t valopt_len = sizeof(valopt);
	if (getsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, SOCK_OPT_ARG &valopt, &valopt_len))
		return g_defaultBufferSize;

	return static_cast<uint32_t>(valopt);
}

bool TcpSocketPrivate::SetNoSigPipe()
{
	int value = 1;
	return setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) == 0;
}
}
<commit_msg>Fixed Win compilation.<commit_after>/*
 * Copyright (C) 2017 Smirnov Vladimir mapron1@gmail.com
 * Source code licensed under the Apache License, Version 2.0 (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 or in file COPYING-APACHE-2.0.txt
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.h
 */

#include "TcpSocket.h"

#include "Tcp_private.h"
#include "TcpConnectionParams_private.h"
#include "TcpListener.h"
#include "Syslogger.h"

#include <algorithm>
#include <vector>
#include <stdint.h>
#include <memory>
#include <cstring>

//#define SOCKET_DEBUG  // for debugging.

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#ifdef TCP_SOCKET_WIN

void SocketEngineCheck()
{
	struct WSA_RAII {
		WSA_RAII() {  int ec;
					 WSADATA wsa;

							  if ((ec = WSAStartup(MAKEWORD(2,0), &wsa)) != 0)
								  Wuild::Syslogger(Wuild::Syslogger::Err) <<  "WIN32_SOCKET: winsock error: code " << ec;
				  }
		~WSA_RAII() { WSACleanup(); }
	};

	static WSA_RAII init ;
}

#endif

namespace
{
	const size_t g_defaultBufferSize = 4 * 1024;
}

namespace Wuild
{

std::atomic_bool TcpSocket::s_applicationInterruption(false);

TcpSocket::TcpSocket(const TcpConnectionParams &params)
	: m_params(params)
	, m_impl(new TcpSocketPrivate())
{
	SocketEngineCheck();
	m_logContext = params.GetShortInfo();
	Syslogger(m_logContext) << "TcpSocket::TcpSocket() ";
}

TcpSocket::~TcpSocket()
{
	Disconnect();
}

IDataSocket::Ptr TcpSocket::Create(const TcpConnectionParams &params, TcpListener *pendingListener)
{
	auto sock  = new TcpSocket(params);
	sock->SetListener(pendingListener);
	return IDataSocket::Ptr(sock);
}

bool TcpSocket::Connect ()
{
	if (s_applicationInterruption)
		return false;

	if (m_state == ConnectionState::Success)
		return true;

	if (m_acceptedByListener)
	{
		if (m_state == ConnectionState::Fail)
			return false;

		if (m_state == ConnectionState::Pending && m_pendingListener->DoAccept(this))
		{
			SetBufferSize();
			if (m_impl->SetBlocking(false))
			{
				m_state = ConnectionState::Success;
				return true;
			}
		}
		m_state = ConnectionState::Fail;
		return false;
	}
	Syslogger(m_logContext) << "Trying to connect..." ;

	if (m_impl->m_socket != INVALID_SOCKET)
	{
		Syslogger(m_logContext, Syslogger::Alert) << "Trying to reopen existing socket!" ;
		return false;
	}

	if (!m_params.Resolve())
		return false;

	m_impl->m_socket = socket(m_params.m_impl->ai->ai_family, m_params.m_impl->ai->ai_socktype, m_params.m_impl->ai->ai_protocol);
	if (m_impl->m_socket == INVALID_SOCKET)
	{
		Syslogger(m_logContext, Syslogger::Err) << "socket creation failed." ;
		Fail();
		return false;
	}

	SetBufferSize();
	if (!m_impl->SetNoSigPipe())
	{
		Syslogger(m_logContext, Syslogger::Warning) << "Failed to disable SIGPIPE signal." ;
	}
	if (!m_impl->SetBlocking(false))
	{
		Fail();
		return false;
	}

	int cres = connect(m_impl->m_socket, m_params.m_impl->ai->ai_addr, m_params.m_impl->ai->ai_addrlen);
	if (cres < 0)
	{

		const auto err = SocketGetLastError();
		const bool inProgress = SocketCheckConnectionPending(err);
		if (inProgress)
		{
			struct timeval timeout;
			SET_TIMEVAL_US(timeout, m_params.m_connectTimeout);
			fd_set select_set;
			FD_ZERO( &select_set );
			FD_SET( m_impl->m_socket, &select_set );
			int valopt;
			socklen_t valopt_len = sizeof(valopt);

			if (select( m_impl->m_socket + 1, 0, &select_set, 0, &timeout ) <= 0 || !FD_ISSET( m_impl->m_socket, &select_set ) ||
				getsockopt( m_impl->m_socket, SOL_SOCKET, SO_ERROR, SOCK_OPT_ARG (&valopt), &valopt_len ) < 0 || valopt
					)
			{
				Syslogger(m_logContext) << "Connection timeout." ;
				Fail();
				return false;
			}
		}
		else
		{
			Syslogger(m_logContext) << "Connection failed. ("<< cres << ") err=" << err ;
			Fail();
			return false;
		}
	}

	m_state = ConnectionState::Success;
	Syslogger(m_logContext) << "Connected.";
	return true;
}

void TcpSocket::Disconnect()
{
	m_state = ConnectionState::Fail;
	if (m_impl->m_socket != INVALID_SOCKET)
	{
		Syslogger(m_logContext) << "TcpSocket::Disconnect() ";
		close( m_impl->m_socket );
		m_impl->m_socket = INVALID_SOCKET;
	}
}

bool TcpSocket::IsConnected() const
{
	return m_state == ConnectionState::Success;
}

bool TcpSocket::IsPending() const
{
	return m_state == ConnectionState::Pending;
}

IDataSocket::ReadState TcpSocket::Read(ByteArrayHolder & buffer)
{
	if (!IsConnected())
		return ReadState::Fail;

	if (!IsSocketReadReady( ))
		return ReadState::TryAgain;

	if (!SelectRead( m_params.m_readTimeout ))  //Нет данных в порту
		return ReadState::TryAgain;

	size_t bufferInitialSize = buffer.size();(void)bufferInitialSize;
	char tmpbuffer[0x4000]; // 16k buffer. stack is rather cheap...
	int recieved, totalRecieved = 0;
	do {

	  recieved =
		#ifdef TCP_SOCKET_WIN
			recv( m_impl->m_socket, tmpbuffer, sizeof(tmpbuffer), 0 );
		#else
			read( m_impl->m_socket, tmpbuffer, sizeof(tmpbuffer) );
		#endif
	  if (recieved == 0)
		  break;

	  if (recieved < 0)
	  {
		  const auto err = SocketGetLastError();
		  if (SocketRWPending(err) )
			  break;
		  Syslogger(m_logContext, Syslogger::Err) << "Disconnecting while Reading ("<< recieved << ") err=" << err;
		  Disconnect();
		  return ReadState::Fail;
	  }
	  totalRecieved += recieved;
	  buffer.ref().insert(buffer.ref().end(), tmpbuffer, tmpbuffer + recieved );

	} while(recieved == sizeof(tmpbuffer));

#ifdef SOCKET_DEBUG
	Syslogger(m_logContext) << "TcpSocket::Read: " << Syslogger::Binary(buffer.data() + bufferInitialSize, totalRecieved);
#endif

	return totalRecieved > 0 ? ReadState::Success : ReadState::TryAgain;
}

TcpSocket::WriteState TcpSocket::Write(const ByteArrayHolder & buffer, size_t maxBytes)
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return WriteState::Fail;

	maxBytes = std::min(maxBytes, buffer.size());

	auto written = send( m_impl->m_socket, (const char*)(buffer.data()), maxBytes, MSG_NOSIGNAL);
	if (written < 0)
	{
		const auto err = SocketGetLastError();
		if (SocketRWPending(err))
			return WriteState::TryAgain;

		const int EPIPE_code = 32;
		Syslogger(m_logContext, err == EPIPE_code ? Syslogger::Info : Syslogger::Err) << "Disconnecting while Writing, (" << written << ") err=" << err;
		Disconnect();
		return WriteState::Fail;
	}

#ifdef SOCKET_DEBUG
	Syslogger(m_logContext) << "TcpSocket::Write: " << Syslogger::Binary(buffer.data(), written);
#endif
	return maxBytes == written ? WriteState::Success : WriteState::Fail;
}

void TcpSocket::SetListener(TcpListener* pendingListener)
{
	if (!pendingListener)
		return;

	m_state = ConnectionState::Pending;
	m_pendingListener = pendingListener;
	m_acceptedByListener = true;
}

void TcpSocket::Fail ()
{
	Syslogger(m_logContext) << "Disconnection cased by Fail()";
	Disconnect();
}

bool TcpSocket::IsSocketReadReady()
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return false;

	fd_set set;
	FD_ZERO( &set );
	FD_SET( m_impl->m_socket, &set );

	struct timeval timeout = { 0, 0 };
	int selected = select( m_impl->m_socket + 1U, &set, 0, 0, &timeout );
	if (selected < 0)
	{
		Syslogger(m_logContext) << "Disconnect from IsSocketReadReady" ;
		Disconnect();
		return false;
	}
	return (selected != 0 && FD_ISSET( m_impl->m_socket, &set ));
}

bool TcpSocket::SelectRead (const TimePoint &timeout)
{
	if (m_impl->m_socket == INVALID_SOCKET)
		return false;

	bool res= false;
	fd_set selected;
	FD_ZERO( &selected );
	FD_SET( m_impl->m_socket, &selected );
	struct timeval timeoutTV;
	SET_TIMEVAL_US(timeoutTV, timeout);
	res = select( m_impl->m_socket + 1, &selected, 0, 0, &timeoutTV ) > 0 && FD_ISSET( m_impl->m_socket, &selected );
	return res;
}

void TcpSocket::SetBufferSize()
{
	m_recieveBufferSize = m_impl->GetRecieveBuffer();
	if (m_recieveBufferSize < m_params.m_recommendedRecieveBufferSize)
	{
		if (!m_impl->SetRecieveBuffer(m_params.m_recommendedRecieveBufferSize))
		{
			Syslogger(m_logContext, Syslogger::Info) << "Failed to set recieve socket buffer size:" << m_params.m_recommendedRecieveBufferSize;
		}
		m_recieveBufferSize = m_impl->GetRecieveBuffer();
	}
	m_sendBufferSize = m_impl->GetSendBuffer();
	if (m_sendBufferSize < m_params.m_recommendedSendBufferSize)
	{
		if (!m_impl->SetSendBuffer(m_params.m_recommendedSendBufferSize))
		{
			Syslogger(m_logContext, Syslogger::Info) << "Failed to set send socket buffer size:" << m_params.m_recommendedSendBufferSize;
		}
		m_sendBufferSize = m_impl->GetSendBuffer();
	}
}

bool TcpSocketPrivate::SetBlocking(bool blocking)
{
#if  defined(TCP_SOCKET_WIN )
	u_long flags = blocking ? 0 : 1;
	if(ioctlsocket( m_socket, FIONBIO, &flags ) != NO_ERROR)
	{
		Syslogger(Syslogger::Err) << "ioctlsocket(FIONBIO O_NONBLOCK) failed." ;
		return false;
	}
#else
	long flags = fcntl( m_socket, F_GETFL, 0 );
	if (flags < 0)
	{
		Syslogger(Syslogger::Err) << "fcntl(F_GETFL) failed." ;
		return false;
	}
	if (!blocking)
		flags |= O_NONBLOCK;
	else
		flags &= ~O_NONBLOCK;

	if(fcntl( m_socket, F_SETFL, flags ) < 0)
	{
		Syslogger(Syslogger::Err) << "fcntl(F_SETFL O_NONBLOCK) failed." ;
		return false;
	}
#endif
	return true;
}

bool TcpSocketPrivate::SetRecieveBuffer(uint32_t size)
{
	int valopt = static_cast<int>(size);
	socklen_t valopt_len = sizeof(valopt);
	return setsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, SOCK_OPT_ARG &valopt, valopt_len) == 0;
}

uint32_t TcpSocketPrivate::GetRecieveBuffer()
{
	int valopt = 0;
	socklen_t valopt_len = sizeof(valopt);
	if (getsockopt(m_socket, SOL_SOCKET, SO_RCVBUF, SOCK_OPT_ARG &valopt, &valopt_len))
		return g_defaultBufferSize;

	return static_cast<uint32_t>(valopt);
}
bool TcpSocketPrivate::SetSendBuffer(uint32_t size)
{
	int valopt = static_cast<int>(size);
	socklen_t valopt_len = sizeof(valopt);
	return setsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, SOCK_OPT_ARG &valopt, valopt_len) == 0;
}

uint32_t TcpSocketPrivate::GetSendBuffer()
{
	int valopt = 0;
	socklen_t valopt_len = sizeof(valopt);
	if (getsockopt(m_socket, SOL_SOCKET, SO_SNDBUF, SOCK_OPT_ARG &valopt, &valopt_len))
		return g_defaultBufferSize;

	return static_cast<uint32_t>(valopt);
}

bool TcpSocketPrivate::SetNoSigPipe()
{
#ifdef __APPLE__
	int value = 1;
	return setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) == 0;
#else
	return true;
#endif
}
}
<|endoftext|>