<commit_before>#include <sstream>
#include <iostream>

#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/ASTConsumers.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Rewrite/Core/Rewriter.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>

using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;

class CLASTVisitor : public RecursiveASTVisitor<CLASTVisitor>
{
public:
	CLASTVisitor(Rewriter &R)
		: rewriter(R) {}

	bool VisitStmt(Stmt* s)
	{
		// If access belongs to a structure with pointer,
		// translate it!
		switch(s->getStmtClass())
		{
			case clang::Stmt::MemberExprClass:
			{
				clang::MemberExpr* member = static_cast<clang::MemberExpr*>(s);
				if (member->getType()->isAnyPointerType())
				{
					rewriter.ReplaceText(s->getSourceRange(),
										 rewriter.getRewrittenText(member->getBase()->getSourceRange())
											 + "_"
											 + member->getMemberNameInfo().getAsString());
				}
				else
				{
					char num = 0;
					switch(member->getMemberNameInfo().getAsString()[0])
					{
						case 'x':
							num = '0';
							break;

						case 'y':
							num = '1';
							break;

						case 'z':
							num = '2';
							break;

						default:
							return true;
					}

					std::string object = rewriter.getRewrittenText(member->getBase()->getSourceRange());
					if(object == "threadIdx")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
										std::string("get_local_id(") + num + ")");
					}
					else if(object == "blockIdx")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_group_id(") + num + ")");
					}
					else if(object == "blockDim")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_local_size(") + num + ")");
					}
					else if(object == "gridDim")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_num_groups(") + num + ")");
					}
				}
			}
				break;
		}

		return true;
	}

	bool VisitDecl(Decl* d)
	{
		// If declaration is forced to be on the device for compilation
		if(d->hasAttr<AnnotateAttr>() && d->getAttr<AnnotateAttr>()->getAnnotation().str() == "device")
		{
			rewriter.RemoveText(SourceRange(d->getLocStart(), d->getLocEnd().getLocWithOffset(9)));
			return true;
		}

		if(d->getKind() == Decl::Var
			&& d->isLexicallyWithinFunctionOrMethod())
		{
			VarDecl* var = static_cast<VarDecl*>(d);

			if(var == nullptr
				|| var->getType()->getAsTagDecl() == nullptr
				|| var->getType()->getAsTagDecl()->getKind() != Decl::CXXRecord)
				return true;

			RecordDecl* recdecl = static_cast<RecordDecl*>(var->getType()->getAsTagDecl());

			for(FieldDecl* c : recdecl->fields())
			{
				// Pointer need to be moved out of the struct
				if(c->getType()->isAnyPointerType())
				{
					rewriter.InsertTextBefore(var->getLocStart(),
											  c->getType()->getPointeeType().getAsString()
												  + "* "
												  + var->getNameAsString()
												  + "_"
												  + c->getNameAsString() + ";\n"
					);
				}
			}
		}
		return true;
	}

	bool VisitRecordDecl(RecordDecl* r)
	{
		for(FieldDecl* c : r->fields())
		{
			// @todo Can't handle pointers for now. Needs runtime workaround for OpenCL.
			if(c->getType()->isAnyPointerType())
			{
				rewriter.InsertTextBefore(c->getOuterLocStart(),
										  std::string("// Pointers in structs need to be emulated\n") +
											  "unsigned int filler" + c->getNameAsString() + "; // This keeps the struct the right size for OpenCL\n// ");
			}
		}
		return true;
	}

	bool VisitFunctionDecl(FunctionDecl *f)
	{
		if (f->hasBody())
		{
			// Add __kernel if needed
			std::stringstream SSBefore;
			AnnotateAttr* attribute = f->getAttr<AnnotateAttr>();

			if(attribute && attribute->getAnnotation().str() == "kernel")
			{
				for(int i = 0; i < f->getNumParams(); i++)
				{
					auto param = f->getParamDecl(i);

					if(param->getType()->isAnyPointerType())
					{
						SSBefore.str("");
						SSBefore << "__global ";

						rewriter.InsertText(param->getSourceRange().getBegin(), SSBefore.str(), true, true);
					}
					else if(param->getType()->isRecordType())
					{
						for(FieldDecl* c : static_cast<RecordDecl*>(param->getType()->getAsTagDecl())->fields())
						{
							// Pointer need to be moved out of the struct
							if(c->getType()->isAnyPointerType())
							{
								rewriter.InsertTextBefore(param->getLocStart(),
														  "__global "
															  + c->getType()->getPointeeType().getAsString()
															  + "* "
															  + param->getNameAsString()
															  + "_"
															  + c->getNameAsString() + ", "
								);
							}
						}
					}
				}
			}
		}

		return true;
	}

private:
	Rewriter& rewriter;
};

class CLASTConsumer : public ASTConsumer
{
public:
	CLASTConsumer(Rewriter &R) : visitor(R) {}
	bool HandleTopLevelDecl(DeclGroupRef DR) override
	{
		for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b)
		{
			if(b)
				visitor.TraverseDecl(*b);
		}
		return true;
	}

private:
	CLASTVisitor visitor;
};

class CLFrontendAction : public ASTFrontendAction
{
	llvm::raw_string_ostream result;

public:
	CLFrontendAction(std::string& clResult) : result(clResult) {}
	void EndSourceFileAction() override
	{
		SourceManager &SM = TheRewriter.getSourceMgr();
		TheRewriter.getEditBuffer(SM.getMainFileID()).write(result);

		result.flush();
	}

	std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
												   StringRef file) override
	{
		TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
		return llvm::make_unique<CLASTConsumer>(TheRewriter);
	}

private:
	Rewriter TheRewriter;
};

int transformCudaClang(const std::string &code, std::string& result)
{
	std::string src;

	src = "// Ensures our compiler does not cough up at OpenCL builtins.\n"
		"#ifdef __CLANG_CUDALIBRE__\n"
		"extern int get_num_groups(int);\n"
		"extern int get_local_size(int);\n"
		"extern int get_group_id(int);\n"
		"extern int get_local_id(int);\n"
		"#define __kernel __attribute__((annotate(\"kernel\")))\n"
		"#define __local __attribute__((annotate(\"local\")))\n"
		"struct dim3{int x; int y; int z;};\n"
		"dim3 threadIdx;\n"
		"dim3 blockIdx;\n"
		"dim3 blockDim;\n"
		"#endif\n";

	src += "\n\n" + code;

	auto frontend = new CLFrontendAction(result);

	// Transform to CL
	int retval = 0;
	retval = !runToolOnCodeWithArgs(frontend, src,
						  {"-fsyntax-only",
						   "-D__CLANG_CUDALIBRE__",
						   "-xc++"});

	if(retval)
	{
		std::cerr << "CUDA translation failed!" << std::endl;
		//return retval;
	}

	// Check syntax of produced CL code
	// @todo Add switch for additional syntax check!
	retval = !runToolOnCodeWithArgs(new SyntaxOnlyAction, result,
									{"-Wno-implicit-function-declaration", "-xcl", "-cl-std=CL2.0"}, "input.cl");
	if(retval)
		std::cerr << "OpenCL syntax check failed!" << std::endl;

	return retval;
}
<commit_msg>* Strip produced OpenCL code a little<commit_after>#include <sstream>
#include <iostream>

#include <clang/AST/AST.h>
#include <clang/AST/ASTConsumer.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Frontend/ASTConsumers.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/FrontendActions.h>
#include <clang/Rewrite/Core/Rewriter.h>
#include <clang/Tooling/CommonOptionsParser.h>
#include <clang/Tooling/Tooling.h>

using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;

class CLASTVisitor : public RecursiveASTVisitor<CLASTVisitor>
{
public:
	CLASTVisitor(Rewriter &R)
		: rewriter(R) {}

	bool VisitStmt(Stmt* s)
	{
		// If access belongs to a structure with pointer,
		// translate it!
		switch(s->getStmtClass())
		{
			case clang::Stmt::MemberExprClass:
			{
				clang::MemberExpr* member = static_cast<clang::MemberExpr*>(s);
				if (member->getType()->isAnyPointerType())
				{
					rewriter.ReplaceText(s->getSourceRange(),
										 rewriter.getRewrittenText(member->getBase()->getSourceRange())
											 + "_"
											 + member->getMemberNameInfo().getAsString());
				}
				else
				{
					char num = 0;
					switch(member->getMemberNameInfo().getAsString()[0])
					{
						case 'x':
							num = '0';
							break;

						case 'y':
							num = '1';
							break;

						case 'z':
							num = '2';
							break;

						default:
							return true;
					}

					std::string object = rewriter.getRewrittenText(member->getBase()->getSourceRange());
					if(object == "threadIdx")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
										std::string("get_local_id(") + num + ")");
					}
					else if(object == "blockIdx")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_group_id(") + num + ")");
					}
					else if(object == "blockDim")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_local_size(") + num + ")");
					}
					else if(object == "gridDim")
					{
						rewriter.ReplaceText(
							SourceRange(member->getBase()->getLocStart(),
										member->getLocEnd()),
							std::string("get_num_groups(") + num + ")");
					}
				}
			}
				break;
		}

		return true;
	}

	bool VisitDecl(Decl* d)
	{
		// If declaration is forced to be on the device for compilation
		if(d->hasAttr<AnnotateAttr>() && d->getAttr<AnnotateAttr>()->getAnnotation().str() == "device")
		{
			rewriter.RemoveText(SourceRange(d->getLocStart(), d->getLocEnd().getLocWithOffset(9)));
			return true;
		}

		if(d->getKind() == Decl::Var
			&& d->isLexicallyWithinFunctionOrMethod())
		{
			VarDecl* var = static_cast<VarDecl*>(d);

			if(var == nullptr
				|| var->getType()->getAsTagDecl() == nullptr
				|| var->getType()->getAsTagDecl()->getKind() != Decl::CXXRecord)
				return true;

			RecordDecl* recdecl = static_cast<RecordDecl*>(var->getType()->getAsTagDecl());

			for(FieldDecl* c : recdecl->fields())
			{
				// Pointer need to be moved out of the struct
				if(c->getType()->isAnyPointerType())
				{
					rewriter.InsertTextBefore(var->getLocStart(),
											  c->getType()->getPointeeType().getAsString()
												  + "* "
												  + var->getNameAsString()
												  + "_"
												  + c->getNameAsString() + ";\n"
					);
				}
			}
		}
		return true;
	}

	bool VisitRecordDecl(RecordDecl* r)
	{
		for(FieldDecl* c : r->fields())
		{
			// @todo Can't handle pointers for now. Needs runtime workaround for OpenCL.
			if(c->getType()->isAnyPointerType())
			{
				rewriter.InsertTextBefore(c->getOuterLocStart(),
										  std::string("// Pointers in structs need to be emulated\n") +
											  "unsigned int filler" + c->getNameAsString() + "; // This keeps the struct the right size for OpenCL\n// ");
			}
		}
		return true;
	}

	bool VisitFunctionDecl(FunctionDecl *f)
	{
		if (f->hasBody())
		{
			// Add __kernel if needed
			std::stringstream SSBefore;
			AnnotateAttr* attribute = f->getAttr<AnnotateAttr>();

			if(attribute && attribute->getAnnotation().str() == "kernel")
			{
				for(int i = 0; i < f->getNumParams(); i++)
				{
					auto param = f->getParamDecl(i);

					if(param->getType()->isAnyPointerType())
					{
						SSBefore.str("");
						SSBefore << "__global ";

						rewriter.InsertText(param->getSourceRange().getBegin(), SSBefore.str(), true, true);
					}
					else if(param->getType()->isRecordType())
					{
						for(FieldDecl* c : static_cast<RecordDecl*>(param->getType()->getAsTagDecl())->fields())
						{
							// Pointer need to be moved out of the struct
							if(c->getType()->isAnyPointerType())
							{
								rewriter.InsertTextBefore(param->getLocStart(),
											  "__global "
											  + c->getType()->getPointeeType().getAsString()
											  + "* "
											  + param->getNameAsString()
											  + "_"
											  + c->getNameAsString() + ", "
								);
							}
						}
					}
				}
			}
		}

		return true;
	}

private:
	Rewriter& rewriter;
};

class CLASTConsumer : public ASTConsumer
{
public:
	CLASTConsumer(Rewriter &R) : visitor(R) {}
	bool HandleTopLevelDecl(DeclGroupRef DR) override
	{
		for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b)
		{
			if(b)
				visitor.TraverseDecl(*b);
		}
		return true;
	}

private:
	CLASTVisitor visitor;
};

class CLFrontendAction : public ASTFrontendAction
{
	llvm::raw_string_ostream result;

public:
	CLFrontendAction(std::string& clResult) : result(clResult) {}
	void EndSourceFileAction() override
	{
		SourceManager &SM = TheRewriter.getSourceMgr();
		TheRewriter.getEditBuffer(SM.getMainFileID()).write(result);

		result.flush();
	}

	std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
												   StringRef file) override
	{
		TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
		return llvm::make_unique<CLASTConsumer>(TheRewriter);
	}

private:
	Rewriter TheRewriter;
};

int transformCudaClang(const std::string &code, std::string& result)
{
	std::string src;
	src = "// Ensures our compiler does not cough up at OpenCL builtins.\n"
		"#ifdef __CLANG_CUDALIBRE__\n"
		"extern int get_num_groups(int);\n"
		"extern int get_local_size(int);\n"
		"extern int get_group_id(int);\n"
		"extern int get_local_id(int);\n"
		"#define __kernel __attribute__((annotate(\"kernel\")))\n"
		"#define __local __attribute__((annotate(\"local\")))\n"
		"struct dim3{int x; int y; int z;};\n"
		"dim3 threadIdx;\n"
		"dim3 blockIdx;\n"
		"dim3 blockDim;\n"
		"#endif\n";

	size_t prefixSize = src.size();
	src += "\n\n" + code;

	auto frontend = new CLFrontendAction(result);

	// Transform to CL
	int retval = 0;
	retval = !runToolOnCodeWithArgs(frontend, src,
						  {"-fsyntax-only",
						   "-D__CLANG_CUDALIBRE__",
						   "-xc++"});

	if(retval)
	{
		std::cerr << "CUDA translation failed!" << std::endl;
		//return retval;
	}

	// Strip away the part that's only for validation
	result = result.substr(prefixSize);

	// Check syntax of produced CL code
	// @todo Add switch for additional syntax check!
	retval = !runToolOnCodeWithArgs(new SyntaxOnlyAction, result,
					{"-Wno-implicit-function-declaration", "-xcl", "-cl-std=CL2.0"}, "input.cl");

	if(retval)
		std::cerr << "OpenCL syntax check failed!" << std::endl;

	return retval;
}
<|endoftext|>


<commit_before>#include "external_scorer.h"

#include <cstdio> // popen
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sstream>
#include <iostream>
#include <cassert>

#include "stringlib.h"
#include "filelib.h"
#include "tdict.h"

using namespace std;

extern const char* meteor_jar_path;
extern void setup_child_process_handler();

map<string, boost::shared_ptr<ScoreServer> > ScoreServerManager::servers_;

class METEORServer : public ScoreServer {
 public:
  METEORServer(const string& cmd) : ScoreServer(cmd) {}
};

ScoreServer* ScoreServerManager::Instance(const string& score_type) {
  boost::shared_ptr<ScoreServer>& s = servers_[score_type];
  if (!s) {
    if (score_type == "meteor") {
#if HAVE_METEOR
      if (!FileExists(meteor_jar_path)) {
        cerr << meteor_jar_path << " not found!\n";
        abort();
      }
      s.reset(new METEORServer(string("java -Xmx1536m -jar ") + meteor_jar_path + " - - -mira -lower -t tune -l en"));
#else
      cerr << "cdec was not built with the --with-meteor option." << endl;
      abort();
#endif
    } else {
      cerr << "Don't know how to create score server for type '" << score_type << "'\n";
      abort();
    }
  }
  return s.get();
}

ScoreServer::ScoreServer(const string& cmd) {
  setup_child_process_handler();
  cerr << "Invoking " << cmd << " ..." << endl;
  if (pipe(p2c) < 0) { perror("pipe"); exit(1); }
  if (pipe(c2p) < 0) { perror("pipe"); exit(1); }
  pid_t cpid = fork();
  if (cpid < 0) { perror("fork"); exit(1); }
  if (cpid == 0) {  // child
    close(p2c[1]);
    close(c2p[0]);
    dup2(p2c[0], 0);
    close(p2c[0]);
    dup2(c2p[1], 1);
    close(c2p[1]);
    cerr << "Exec'ing from child " << cmd << endl;
    vector<string> vargs;
    SplitOnWhitespace(cmd, &vargs);
    const char** cargv = static_cast<const char**>(malloc(sizeof(const char*) * vargs.size()));
    for (unsigned i = 1; i < vargs.size(); ++i) cargv[i-1] = vargs[i].c_str();
    cargv[vargs.size() - 1] = NULL;
    execvp(vargs[0].c_str(), (char* const*)cargv);
  } else { // parent
    close(c2p[1]);
    close(p2c[0]);
  }
  string dummy;
  RequestResponse("SCORE ||| Reference initialization string . ||| Testing initialization string .", &dummy);
  assert(dummy.size() > 0);
  cerr << "Connection established.\n";
}

ScoreServer::~ScoreServer() {
  cerr << "ScoreServer::~ScoreServer()\n";
  // TODO close stuff, join stuff
}

float ScoreServer::ComputeScore(const vector<float>& fields) {
  ostringstream os;
  os << "EVAL |||";
  for (unsigned i = 0; i < fields.size(); ++i)
    os << ' ' << fields[i];
  string sres;
  RequestResponse(os.str(), &sres);
  return strtod(sres.c_str(), NULL);
}

void ScoreServer::Evaluate(const vector<vector<WordID> >& refs, const vector<WordID>& hyp, vector<float>* fields) {
  ostringstream os;
  os << "SCORE";
  for (unsigned i = 0; i < refs.size(); ++i) {
    os << " |||";
    for (unsigned j = 0; j < refs[i].size(); ++j) {
      os << ' ' << TD::Convert(refs[i][j]);
    }
  }
  os << " |||";
  for (unsigned i = 0; i < hyp.size(); ++i) {
    os << ' ' << TD::Convert(hyp[i]);
  }
  string sres;
  RequestResponse(os.str(), &sres);
  istringstream is(sres);
  float val;
  fields->clear();
  while(is >> val)
    fields->push_back(val);
}

#define MAX_BUF 16000

void ScoreServer::RequestResponse(const string& request, string* response) {
//  cerr << "@SERVER: " << request << endl;
  string x = request + "\n";
  write(p2c[1], x.c_str(), x.size());
  char buf[MAX_BUF];
  size_t n = read(c2p[0], buf, MAX_BUF);
  while (n < MAX_BUF && buf[n-1] != '\n')
    n += read(c2p[0], &buf[n], MAX_BUF - n);

  buf[n-1] = 0;
  if (n < 2) {
    cerr << "Malformed response: " << buf << endl;
  }
  *response = Trim(buf, " \t\n");
//  cerr << "@RESPONSE: '" << *response << "'\n";
}

struct ExternalScore : public ScoreBase<ExternalScore> {
  ExternalScore() : score_server() {}
  explicit ExternalScore(ScoreServer* s) : score_server(s), fields() {}
  ExternalScore(ScoreServer* s, const vector<float>& f) : score_server(s), fields(f) {}
  float ComputePartialScore() const { return 0.0;}
  float ComputeScore() const {
    return score_server->ComputeScore(fields);
  }
  void ScoreDetails(string* details) const {
    ostringstream os;
    os << "EXT=" << ComputeScore() << " <";
    for (unsigned i = 0; i < fields.size(); ++i)
      os << (i ? " " : "") << fields[i];
    os << '>';
    *details = os.str();
  }
  void PlusPartialEquals(const Score&, int, int, int){
    assert(!"not implemented"); // no idea
  }
  void PlusEquals(const Score& delta, const float scale) {
    if (static_cast<const ExternalScore&>(delta).score_server) score_server = static_cast<const ExternalScore&>(delta).score_server;
    if (fields.size() != static_cast<const ExternalScore&>(delta).fields.size())
      fields.resize(max(fields.size(), static_cast<const ExternalScore&>(delta).fields.size()));
    for (unsigned i = 0; i < static_cast<const ExternalScore&>(delta).fields.size(); ++i)
      fields[i] += static_cast<const ExternalScore&>(delta).fields[i] * scale;
  }
  void PlusEquals(const Score& delta) {
    if (static_cast<const ExternalScore&>(delta).score_server) score_server = static_cast<const ExternalScore&>(delta).score_server;
    if (fields.size() != static_cast<const ExternalScore&>(delta).fields.size())
      fields.resize(max(fields.size(), static_cast<const ExternalScore&>(delta).fields.size()));
    for (unsigned i = 0; i < static_cast<const ExternalScore&>(delta).fields.size(); ++i)
      fields[i] += static_cast<const ExternalScore&>(delta).fields[i];
  }
  ScoreP GetZero() const {
    return ScoreP(new ExternalScore(score_server));
  }
  ScoreP GetOne() const {
    return ScoreP(new ExternalScore(score_server));
  }
  void Subtract(const Score& rhs, Score* res) const {
    static_cast<ExternalScore*>(res)->score_server = score_server;
    vector<float>& rf = static_cast<ExternalScore*>(res)->fields;
    rf.resize(max(fields.size(), static_cast<const ExternalScore&>(rhs).fields.size()));
    for (unsigned i = 0; i < rf.size(); ++i) {
      rf[i] = (i < fields.size() ? fields[i] : 0.0f) -
              (i < static_cast<const ExternalScore&>(rhs).fields.size() ? static_cast<const ExternalScore&>(rhs).fields[i] : 0.0f);
    }
  }
  void Encode(string* out) const {
    ostringstream os;
    for (unsigned i = 0; i < fields.size(); ++i)
      os << (i == 0 ? "" : " ") << fields[i];
    *out = os.str();
  }
  bool IsAdditiveIdentity() const {
    for (unsigned i = 0; i < fields.size(); ++i)
      if (fields[i]) return false;
    return true;
  }

  mutable ScoreServer* score_server;
  vector<float> fields;
};

ScoreP ExternalSentenceScorer::ScoreCandidate(const Sentence& hyp) const {
  ExternalScore* res = new ExternalScore(eval_server);
  eval_server->Evaluate(refs, hyp, &res->fields);
  return ScoreP(res);
}

ScoreP ExternalSentenceScorer::ScoreCCandidate(const Sentence& hyp) const {
  assert(!"not implemented");
}

ScoreP ExternalSentenceScorer::ScoreFromString(ScoreServer* s, const string& data) {
  istringstream is(data);
  vector<float> fields;
  float val;
  while(is >> val)
    fields.push_back(val);
  return ScoreP(new ExternalScore(s, fields));
}

<commit_msg>Include full argv (including command) as arg 2 of execvp()<commit_after>#include "external_scorer.h"

#include <cstdio> // popen
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sstream>
#include <iostream>
#include <cassert>

#include "stringlib.h"
#include "filelib.h"
#include "tdict.h"

using namespace std;

extern const char* meteor_jar_path;
extern void setup_child_process_handler();

map<string, boost::shared_ptr<ScoreServer> > ScoreServerManager::servers_;

class METEORServer : public ScoreServer {
 public:
  METEORServer(const string& cmd) : ScoreServer(cmd) {}
};

ScoreServer* ScoreServerManager::Instance(const string& score_type) {
  boost::shared_ptr<ScoreServer>& s = servers_[score_type];
  if (!s) {
    if (score_type == "meteor") {
#if HAVE_METEOR
      if (!FileExists(meteor_jar_path)) {
        cerr << meteor_jar_path << " not found!\n";
        abort();
      }
      s.reset(new METEORServer(string("java -Xmx1536m -jar ") + meteor_jar_path + " - - -mira -lower -t tune -l en"));
#else
      cerr << "cdec was not built with the --with-meteor option." << endl;
      abort();
#endif
    } else {
      cerr << "Don't know how to create score server for type '" << score_type << "'\n";
      abort();
    }
  }
  return s.get();
}

ScoreServer::ScoreServer(const string& cmd) {
  setup_child_process_handler();
  cerr << "Invoking " << cmd << " ..." << endl;
  if (pipe(p2c) < 0) { perror("pipe"); exit(1); }
  if (pipe(c2p) < 0) { perror("pipe"); exit(1); }
  pid_t cpid = fork();
  if (cpid < 0) { perror("fork"); exit(1); }
  if (cpid == 0) {  // child
    close(p2c[1]);
    close(c2p[0]);
    dup2(p2c[0], 0);
    close(p2c[0]);
    dup2(c2p[1], 1);
    close(c2p[1]);
    cerr << "Exec'ing from child " << cmd << endl;
    vector<string> vargs;
    SplitOnWhitespace(cmd, &vargs);
    const char** cargv = static_cast<const char**>(malloc(sizeof(const char*) * (vargs.size() + 1)));
    for (unsigned i = 0; i < vargs.size(); i++) cargv[i] = vargs[i].c_str();
    cargv[vargs.size()] = NULL;
    execvp(*cargv, (char* const*)cargv);
  } else { // parent
    close(c2p[1]);
    close(p2c[0]);
  }
  string dummy;
  RequestResponse("SCORE ||| Reference initialization string . ||| Testing initialization string .", &dummy);
  assert(dummy.size() > 0);
  cerr << "Connection established.\n";
}

ScoreServer::~ScoreServer() {
  cerr << "ScoreServer::~ScoreServer()\n";
  // TODO close stuff, join stuff
}

float ScoreServer::ComputeScore(const vector<float>& fields) {
  ostringstream os;
  os << "EVAL |||";
  for (unsigned i = 0; i < fields.size(); ++i)
    os << ' ' << fields[i];
  string sres;
  RequestResponse(os.str(), &sres);
  return strtod(sres.c_str(), NULL);
}

void ScoreServer::Evaluate(const vector<vector<WordID> >& refs, const vector<WordID>& hyp, vector<float>* fields) {
  ostringstream os;
  os << "SCORE";
  for (unsigned i = 0; i < refs.size(); ++i) {
    os << " |||";
    for (unsigned j = 0; j < refs[i].size(); ++j) {
      os << ' ' << TD::Convert(refs[i][j]);
    }
  }
  os << " |||";
  for (unsigned i = 0; i < hyp.size(); ++i) {
    os << ' ' << TD::Convert(hyp[i]);
  }
  string sres;
  RequestResponse(os.str(), &sres);
  istringstream is(sres);
  float val;
  fields->clear();
  while(is >> val)
    fields->push_back(val);
}

#define MAX_BUF 16000

void ScoreServer::RequestResponse(const string& request, string* response) {
//  cerr << "@SERVER: " << request << endl;
  string x = request + "\n";
  write(p2c[1], x.c_str(), x.size());
  char buf[MAX_BUF];
  size_t n = read(c2p[0], buf, MAX_BUF);
  while (n < MAX_BUF && buf[n-1] != '\n')
    n += read(c2p[0], &buf[n], MAX_BUF - n);

  buf[n-1] = 0;
  if (n < 2) {
    cerr << "Malformed response: " << buf << endl;
  }
  *response = Trim(buf, " \t\n");
//  cerr << "@RESPONSE: '" << *response << "'\n";
}

struct ExternalScore : public ScoreBase<ExternalScore> {
  ExternalScore() : score_server() {}
  explicit ExternalScore(ScoreServer* s) : score_server(s), fields() {}
  ExternalScore(ScoreServer* s, const vector<float>& f) : score_server(s), fields(f) {}
  float ComputePartialScore() const { return 0.0;}
  float ComputeScore() const {
    return score_server->ComputeScore(fields);
  }
  void ScoreDetails(string* details) const {
    ostringstream os;
    os << "EXT=" << ComputeScore() << " <";
    for (unsigned i = 0; i < fields.size(); ++i)
      os << (i ? " " : "") << fields[i];
    os << '>';
    *details = os.str();
  }
  void PlusPartialEquals(const Score&, int, int, int){
    assert(!"not implemented"); // no idea
  }
  void PlusEquals(const Score& delta, const float scale) {
    if (static_cast<const ExternalScore&>(delta).score_server) score_server = static_cast<const ExternalScore&>(delta).score_server;
    if (fields.size() != static_cast<const ExternalScore&>(delta).fields.size())
      fields.resize(max(fields.size(), static_cast<const ExternalScore&>(delta).fields.size()));
    for (unsigned i = 0; i < static_cast<const ExternalScore&>(delta).fields.size(); ++i)
      fields[i] += static_cast<const ExternalScore&>(delta).fields[i] * scale;
  }
  void PlusEquals(const Score& delta) {
    if (static_cast<const ExternalScore&>(delta).score_server) score_server = static_cast<const ExternalScore&>(delta).score_server;
    if (fields.size() != static_cast<const ExternalScore&>(delta).fields.size())
      fields.resize(max(fields.size(), static_cast<const ExternalScore&>(delta).fields.size()));
    for (unsigned i = 0; i < static_cast<const ExternalScore&>(delta).fields.size(); ++i)
      fields[i] += static_cast<const ExternalScore&>(delta).fields[i];
  }
  ScoreP GetZero() const {
    return ScoreP(new ExternalScore(score_server));
  }
  ScoreP GetOne() const {
    return ScoreP(new ExternalScore(score_server));
  }
  void Subtract(const Score& rhs, Score* res) const {
    static_cast<ExternalScore*>(res)->score_server = score_server;
    vector<float>& rf = static_cast<ExternalScore*>(res)->fields;
    rf.resize(max(fields.size(), static_cast<const ExternalScore&>(rhs).fields.size()));
    for (unsigned i = 0; i < rf.size(); ++i) {
      rf[i] = (i < fields.size() ? fields[i] : 0.0f) -
              (i < static_cast<const ExternalScore&>(rhs).fields.size() ? static_cast<const ExternalScore&>(rhs).fields[i] : 0.0f);
    }
  }
  void Encode(string* out) const {
    ostringstream os;
    for (unsigned i = 0; i < fields.size(); ++i)
      os << (i == 0 ? "" : " ") << fields[i];
    *out = os.str();
  }
  bool IsAdditiveIdentity() const {
    for (unsigned i = 0; i < fields.size(); ++i)
      if (fields[i]) return false;
    return true;
  }

  mutable ScoreServer* score_server;
  vector<float> fields;
};

ScoreP ExternalSentenceScorer::ScoreCandidate(const Sentence& hyp) const {
  ExternalScore* res = new ExternalScore(eval_server);
  eval_server->Evaluate(refs, hyp, &res->fields);
  return ScoreP(res);
}

ScoreP ExternalSentenceScorer::ScoreCCandidate(const Sentence& hyp) const {
  assert(!"not implemented");
}

ScoreP ExternalSentenceScorer::ScoreFromString(ScoreServer* s, const string& data) {
  istringstream is(data);
  vector<float> fields;
  float val;
  while(is >> val)
    fields.push_back(val);
  return ScoreP(new ExternalScore(s, fields));
}

<|endoftext|>


<commit_before>/*
 * Copyright 2016-2020 Luca Zanconato
 *
 * 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
 *
 * 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.
 */

#include <cstddef>
#include <cmath>
#include <sodium.h>
#include "saltpack/Utils.h"
#include "saltpack/SaltpackException.h"
#include "../ext/Num/num.hpp"

namespace saltpack {

    void Utils::generateKeypair(BYTE_ARRAY &publickey, BYTE_ARRAY &secretkey) {

        if (secretkey.size() != crypto_box_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (publickey.size() != crypto_box_PUBLICKEYBYTES)
            throw SaltpackException("Wrong publickey size.");

        if (crypto_box_keypair(publickey.data(), secretkey.data()) != 0)
            throw SaltpackException("Errors while generating keypair.");
    }

    void Utils::generateSignKeypair(BYTE_ARRAY &publickey, BYTE_ARRAY &secretkey) {

        if (secretkey.size() != crypto_sign_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (publickey.size() != crypto_sign_PUBLICKEYBYTES)
            throw SaltpackException("Wrong publickey size.");

        if (crypto_sign_keypair(publickey.data(), secretkey.data()) != 0)
            throw SaltpackException("Errors while generating keypair.");
    }

    BYTE_ARRAY Utils::derivePublickey(BYTE_ARRAY secretkey) {

        if (secretkey.size() != crypto_box_SECRETKEYBYTES && secretkey.size() != crypto_sign_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (secretkey.size() == crypto_box_SECRETKEYBYTES) {

            BYTE_ARRAY publickey(crypto_box_PUBLICKEYBYTES);
            if (crypto_scalarmult_base(publickey.data(), secretkey.data()) != 0)
                throw SaltpackException("Errors while deriving public key.");

            return publickey;

        } else {

            BYTE_ARRAY publickey(crypto_sign_PUBLICKEYBYTES);
            if (crypto_sign_ed25519_sk_to_pk(publickey.data(), secretkey.data()) != 0)
                throw SaltpackException("Errors while deriving public key.");

            return publickey;
        }
    }

    int Utils::baseXblockSize(const std::string& alphabet, int size) {

        return (int) ceil(size * 8 / log2(alphabet.size()));
    }

    std::string Utils::baseXencode(const BYTE_ARRAY& data, std::string alphabet) {

        return baseXencode(data, data.size(), std::move(alphabet));
    }

    std::string Utils::baseXencode(BYTE_ARRAY data, size_t size, std::string alphabet) {

        int c = baseXblockSize(alphabet, (int) size);
        std::string out;

        Num num;
        for (size_t i = 0; i < size; i++) {

            num.mul_word(256);
            num.add_word(data.at(i));
        }

        Num bA((int) alphabet.length());
        Num mod;
        for (int i = 0; i < c; i++) {

            mod = num % bA;
            out.insert(0, 1, alphabet.at(mod.to_double()));
            num /= bA;
        }

        return out;
    }

    BYTE_ARRAY Utils::baseXdecode(std::string data, const std::string& alphabet) {

        unsigned long a = alphabet.length();
        unsigned long c = data.length();
        auto b = (size_t) floor((double) c * log2(a) / 8);

        Num num(0);
        Num bA((int) a);
        Num pow;
        for (int i = (int) c - 1; i >= 0; i--) {

            Num digit((unsigned char) alphabet.find(data.at(c - i - 1)));
            pow = bA.pow(i);
            digit *= pow;
            num += digit;
        }

        BYTE_ARRAY out;
        while (num.size() > 0) {

            Num::word remainder;
            Num::div_mod_half_word(num, 256, num, remainder);
            out.push_back(remainder);
        }

        if (out.size() > b)
            throw SaltpackException("Illegal block.");

        out.resize(out.size() + (b - out.size()));
        std::reverse(out.begin(), out.end());

        return out;
    }

    BYTE_ARRAY Utils::hexToBin(const std::string& hex) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        BYTE_ARRAY out(hex.size() / 2);

        if (sodium_hex2bin(out.data(), out.size(), hex.c_str(), hex.size(), nullptr, nullptr, nullptr) != 0)
            throw SaltpackException("Unable to decode HEX string.");

        return out;
    }

    std::string Utils::binToHex(BYTE_ARRAY bin) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        std::vector<char> data(bin.size() * 2 + 1);

        if (sodium_bin2hex(data.data(), data.size(), bin.data(), bin.size()) == nullptr)
            throw SaltpackException("Unable to encode HEX string.");

        return std::string(data.data());
    }

    BYTE_ARRAY Utils::generateRandomBytes(size_t size) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        BYTE_ARRAY salt(size);
        randombytes_buf(salt.data(), size);

        return salt;
    }

    BYTE_ARRAY Utils::deriveKeyFromPassword(unsigned long long int keySize, const std::string& password, BYTE_ARRAY salt,
                                            unsigned long long int opsLimit, size_t memLimit) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        if (salt.size() != crypto_pwhash_SALTBYTES)
            throw SaltpackException("Wrong salt size.");

        BYTE_ARRAY key(keySize);

        if (crypto_pwhash(key.data(), keySize, password.c_str(), password.size(), salt.data(), opsLimit, memLimit,
                          crypto_pwhash_ALG_DEFAULT) != 0)
            throw SaltpackException("Errors while deriving key (out of memory).");

        return key;
    }
}
<commit_msg>Faster base conversion<commit_after>/*
 * Copyright 2016-2020 Luca Zanconato
 *
 * 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
 *
 * 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.
 */

#include <cstddef>
#include <cmath>
#include <sodium.h>
#include "saltpack/Utils.h"
#include "saltpack/SaltpackException.h"
#include "../ext/Num/num.hpp"

namespace saltpack {

    void Utils::generateKeypair(BYTE_ARRAY &publickey, BYTE_ARRAY &secretkey) {

        if (secretkey.size() != crypto_box_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (publickey.size() != crypto_box_PUBLICKEYBYTES)
            throw SaltpackException("Wrong publickey size.");

        if (crypto_box_keypair(publickey.data(), secretkey.data()) != 0)
            throw SaltpackException("Errors while generating keypair.");
    }

    void Utils::generateSignKeypair(BYTE_ARRAY &publickey, BYTE_ARRAY &secretkey) {

        if (secretkey.size() != crypto_sign_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (publickey.size() != crypto_sign_PUBLICKEYBYTES)
            throw SaltpackException("Wrong publickey size.");

        if (crypto_sign_keypair(publickey.data(), secretkey.data()) != 0)
            throw SaltpackException("Errors while generating keypair.");
    }

    BYTE_ARRAY Utils::derivePublickey(BYTE_ARRAY secretkey) {

        if (secretkey.size() != crypto_box_SECRETKEYBYTES && secretkey.size() != crypto_sign_SECRETKEYBYTES)
            throw SaltpackException("Wrong secretkey size.");

        if (secretkey.size() == crypto_box_SECRETKEYBYTES) {

            BYTE_ARRAY publickey(crypto_box_PUBLICKEYBYTES);
            if (crypto_scalarmult_base(publickey.data(), secretkey.data()) != 0)
                throw SaltpackException("Errors while deriving public key.");

            return publickey;

        } else {

            BYTE_ARRAY publickey(crypto_sign_PUBLICKEYBYTES);
            if (crypto_sign_ed25519_sk_to_pk(publickey.data(), secretkey.data()) != 0)
                throw SaltpackException("Errors while deriving public key.");

            return publickey;
        }
    }

    int Utils::baseXblockSize(const std::string& alphabet, int size) {

        return (int) ceil(size * 8 / log2(alphabet.size()));
    }

    std::string Utils::baseXencode(const BYTE_ARRAY& data, std::string alphabet) {

        return baseXencode(data, data.size(), std::move(alphabet));
    }

    std::string Utils::baseXencode(BYTE_ARRAY data, size_t size, std::string alphabet) {

        int c = baseXblockSize(alphabet, (int) size);
        std::string out;

        Num num;
        for (size_t i = 0; i < size; i++) {

            num.mul_word(256);
            num.add_word(data.at(i));
        }

        for (int i = 0; i < c; i++) {

            Num::word remainder;
            Num::div_mod_half_word(num, alphabet.length(), num, remainder);
            out.insert(0, 1, alphabet.at(remainder));
        }

        return out;
    }

    BYTE_ARRAY Utils::baseXdecode(std::string data, const std::string& alphabet) {

        unsigned long a = alphabet.length();
        unsigned long c = data.length();
        auto b = (size_t) floor((double) c * log2(a) / 8);

        Num num(0);
        for (int i = (int) c - 1; i >= 0; i--) {

            num.mul_word(alphabet.length());
            num.add_word(alphabet.find(data.at(c - i - 1)));
        }

        BYTE_ARRAY out;
        while (num.size() > 0) {

            Num::word remainder;
            Num::div_mod_half_word(num, 256, num, remainder);
            out.push_back(remainder);
        }

        if (out.size() > b)
            throw SaltpackException("Illegal block.");

        out.resize(out.size() + (b - out.size()));
        std::reverse(out.begin(), out.end());

        return out;
    }

    BYTE_ARRAY Utils::hexToBin(const std::string& hex) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        BYTE_ARRAY out(hex.size() / 2);

        if (sodium_hex2bin(out.data(), out.size(), hex.c_str(), hex.size(), nullptr, nullptr, nullptr) != 0)
            throw SaltpackException("Unable to decode HEX string.");

        return out;
    }

    std::string Utils::binToHex(BYTE_ARRAY bin) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        std::vector<char> data(bin.size() * 2 + 1);

        if (sodium_bin2hex(data.data(), data.size(), bin.data(), bin.size()) == nullptr)
            throw SaltpackException("Unable to encode HEX string.");

        return std::string(data.data());
    }

    BYTE_ARRAY Utils::generateRandomBytes(size_t size) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        BYTE_ARRAY salt(size);
        randombytes_buf(salt.data(), size);

        return salt;
    }

    BYTE_ARRAY Utils::deriveKeyFromPassword(unsigned long long int keySize, const std::string& password, BYTE_ARRAY salt,
                                            unsigned long long int opsLimit, size_t memLimit) {

        if (sodium_init() == -1)
            throw SaltpackException("Unable to initialise libsodium.");

        if (salt.size() != crypto_pwhash_SALTBYTES)
            throw SaltpackException("Wrong salt size.");

        BYTE_ARRAY key(keySize);

        if (crypto_pwhash(key.data(), keySize, password.c_str(), password.size(), salt.data(), opsLimit, memLimit,
                          crypto_pwhash_ALG_DEFAULT) != 0)
            throw SaltpackException("Errors while deriving key (out of memory).");

        return key;
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __SYSTEMC_EXT_CORE_SC_PORT_HH__
#define __SYSTEMC_EXT_CORE_SC_PORT_HH__

#include <typeinfo>
#include <vector>

#include "../channel/messages.hh"
#include "../utils/sc_report_handler.hh"
#include "sc_module.hh" // for sc_gen_unique_name
#include "sc_object.hh"

namespace sc_gem5
{

class Port;

};

namespace sc_core
{

class sc_interface;
class sc_trace_file;

// Nonstandard
// Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this
// class definition in the Accellera implementation, it appears in their
// examples and test programs, and so we need to have it here as well.
struct sc_trace_params
{
    sc_trace_file *tf;
    std::string name;

    sc_trace_params(sc_trace_file *tf, const std::string &name) :
        tf(tf), name(name)
    {}
};
typedef std::vector<sc_trace_params *> sc_trace_params_vec;

enum sc_port_policy
{
    SC_ONE_OR_MORE_BOUND, // Default
    SC_ZERO_OR_MORE_BOUND,
    SC_ALL_BOUND
};

class sc_port_base : public sc_object
{
  public:
    sc_port_base(const char *name, int n, sc_port_policy p);
    virtual ~sc_port_base();

    void warn_port_constructor() const;

    int maxSize() const;
    int size() const;

    const char *kind() const { return "sc_port_base"; }

  protected:
    // Implementation defined, but depended on by the tests.
    void bind(sc_interface &);
    void bind(sc_port_base &);

    friend class ::sc_gem5::Module;

    // Implementation defined, but depended on by the tests.
    virtual int vbind(sc_interface &) = 0;
    virtual int vbind(sc_port_base &) = 0;

    virtual void before_end_of_elaboration() = 0;
    virtual void end_of_elaboration() = 0;
    virtual void start_of_simulation() = 0;
    virtual void end_of_simulation() = 0;

    void report_error(const char *id, const char *add_msg) const;

  private:
    friend class ::sc_gem5::Port;
    friend class ::sc_gem5::Kernel;

    virtual sc_interface *_gem5Interface(int n) const = 0;
    virtual void _gem5AddInterface(sc_interface *i) = 0;

    ::sc_gem5::Port *_gem5Port;
    virtual const char *_ifTypeName() const = 0;
    virtual sc_port_policy _portPolicy() const = 0;
};

template <class IF>
class sc_port_b : public sc_port_base
{
  public:
    void operator () (IF &i) { bind(i); }
    void operator () (sc_port_b<IF> &p) { bind(p); }

    virtual void bind(IF &i) { sc_port_base::bind(i); }
    virtual void bind(sc_port_b<IF> &p) { sc_port_base::bind(p); }

    IF *
    operator -> ()
    {
        if (_interfaces.empty()) {
            report_error(SC_ID_GET_IF_, "port is not bound");
            sc_abort();
        }
        return _interfaces[0];
    }
    const IF *
    operator -> () const
    {
        if (_interfaces.empty()) {
            report_error(SC_ID_GET_IF_, "port is not bound");
            sc_abort();
        }
        return _interfaces[0];
    }

    IF *
    operator [] (int n)
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }
    const IF *
    operator [] (int n) const
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }

    sc_interface *
    get_interface()
    {
        if (_interfaces.empty())
            return NULL;
        return _interfaces[0];
    }
    const sc_interface *
    get_interface() const
    {
        if (_interfaces.empty())
            return NULL;
        return _interfaces[0];
    }

  protected:
    void before_end_of_elaboration() {}
    void end_of_elaboration() {}
    void start_of_simulation() {}
    void end_of_simulation() {}

    explicit sc_port_b(int n, sc_port_policy p) :
            sc_port_base(sc_gen_unique_name("port"), n, p)
    {}
    sc_port_b(const char *name, int n, sc_port_policy p) :
            sc_port_base(name, n, p)
    {}
    virtual ~sc_port_b() {}

    // Implementation defined, but depended on by the tests.
    int
    vbind(sc_interface &i)
    {
        IF *interface = dynamic_cast<IF *>(&i);
        if (!interface)
            return 2;
        sc_port_base::bind(*interface);
        return 0;
    }
    int
    vbind(sc_port_base &pb)
    {
        sc_port_b<IF> *p = dynamic_cast<sc_port_b<IF> *>(&pb);
        if (!p)
            return 2;
        sc_port_base::bind(*p);
        return 0;
    }

  private:
    std::vector<IF *> _interfaces;

    sc_interface *
    _gem5Interface(int n) const
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }
    void
    _gem5AddInterface(sc_interface *iface)
    {
        IF *interface = dynamic_cast<IF *>(iface);
        sc_assert(interface);
        for (int i = 0; i < _interfaces.size(); i++) {
            if (interface == _interfaces[i]) {
                report_error(SC_ID_BIND_IF_TO_PORT_,
                        "interface already bound to port");
            }
        }
        _interfaces.push_back(interface);
    }

    const char *_ifTypeName() const { return typeid(IF).name(); }

    // Disabled
    sc_port_b() {}
    sc_port_b(const sc_port_b<IF> &) {}
    sc_port_b<IF> &operator = (const sc_port_b<IF> &) { return *this; }
};

template <class IF, int N=1, sc_port_policy P=SC_ONE_OR_MORE_BOUND>
class sc_port : public sc_port_b<IF>
{
  public:
    sc_port() : sc_port_b<IF>(N, P) {}
    explicit sc_port(const char *name) : sc_port_b<IF>(name, N, P) {}
    virtual ~sc_port() {}

    // Deprecated binding constructors.
    explicit sc_port(const IF &interface) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(const_cast<IF &>(interface));
    }
    sc_port(const char *name, const IF &interface) : sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(const_cast<IF &>(interface));
    }
    explicit sc_port(sc_port_b<IF> &parent) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    sc_port(const char *name, sc_port_b<IF> &parent) :
        sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    explicit sc_port(sc_port<IF, N, P> &parent) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    sc_port(const char *name, sc_port<IF, N, P> &parent) :
        sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }

    virtual const char *kind() const { return "sc_port"; }

  private:
    // Disabled
    sc_port(const sc_port<IF, N, P> &) {}
    sc_port<IF, N, P> &operator = (const sc_port<IF, N, P> &) { return *this; }

    virtual sc_port_policy _portPolicy() const { return P; }
};

} // namespace sc_core

#endif  //__SYSTEMC_EXT_CORE_SC_PORT_HH__
<commit_msg>systemc: Change the type of a loop counter to avoid a warning.<commit_after>/*
 * Copyright 2018 Google, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Gabe Black
 */

#ifndef __SYSTEMC_EXT_CORE_SC_PORT_HH__
#define __SYSTEMC_EXT_CORE_SC_PORT_HH__

#include <typeinfo>
#include <vector>

#include "../channel/messages.hh"
#include "../utils/sc_report_handler.hh"
#include "sc_module.hh" // for sc_gen_unique_name
#include "sc_object.hh"

namespace sc_gem5
{

class Port;

};

namespace sc_core
{

class sc_interface;
class sc_trace_file;

// Nonstandard
// Despite having a warning "FOR INTERNAL USE ONLY!" in all caps above this
// class definition in the Accellera implementation, it appears in their
// examples and test programs, and so we need to have it here as well.
struct sc_trace_params
{
    sc_trace_file *tf;
    std::string name;

    sc_trace_params(sc_trace_file *tf, const std::string &name) :
        tf(tf), name(name)
    {}
};
typedef std::vector<sc_trace_params *> sc_trace_params_vec;

enum sc_port_policy
{
    SC_ONE_OR_MORE_BOUND, // Default
    SC_ZERO_OR_MORE_BOUND,
    SC_ALL_BOUND
};

class sc_port_base : public sc_object
{
  public:
    sc_port_base(const char *name, int n, sc_port_policy p);
    virtual ~sc_port_base();

    void warn_port_constructor() const;

    int maxSize() const;
    int size() const;

    const char *kind() const { return "sc_port_base"; }

  protected:
    // Implementation defined, but depended on by the tests.
    void bind(sc_interface &);
    void bind(sc_port_base &);

    friend class ::sc_gem5::Module;

    // Implementation defined, but depended on by the tests.
    virtual int vbind(sc_interface &) = 0;
    virtual int vbind(sc_port_base &) = 0;

    virtual void before_end_of_elaboration() = 0;
    virtual void end_of_elaboration() = 0;
    virtual void start_of_simulation() = 0;
    virtual void end_of_simulation() = 0;

    void report_error(const char *id, const char *add_msg) const;

  private:
    friend class ::sc_gem5::Port;
    friend class ::sc_gem5::Kernel;

    virtual sc_interface *_gem5Interface(int n) const = 0;
    virtual void _gem5AddInterface(sc_interface *i) = 0;

    ::sc_gem5::Port *_gem5Port;
    virtual const char *_ifTypeName() const = 0;
    virtual sc_port_policy _portPolicy() const = 0;
};

template <class IF>
class sc_port_b : public sc_port_base
{
  public:
    void operator () (IF &i) { bind(i); }
    void operator () (sc_port_b<IF> &p) { bind(p); }

    virtual void bind(IF &i) { sc_port_base::bind(i); }
    virtual void bind(sc_port_b<IF> &p) { sc_port_base::bind(p); }

    IF *
    operator -> ()
    {
        if (_interfaces.empty()) {
            report_error(SC_ID_GET_IF_, "port is not bound");
            sc_abort();
        }
        return _interfaces[0];
    }
    const IF *
    operator -> () const
    {
        if (_interfaces.empty()) {
            report_error(SC_ID_GET_IF_, "port is not bound");
            sc_abort();
        }
        return _interfaces[0];
    }

    IF *
    operator [] (int n)
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }
    const IF *
    operator [] (int n) const
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }

    sc_interface *
    get_interface()
    {
        if (_interfaces.empty())
            return NULL;
        return _interfaces[0];
    }
    const sc_interface *
    get_interface() const
    {
        if (_interfaces.empty())
            return NULL;
        return _interfaces[0];
    }

  protected:
    void before_end_of_elaboration() {}
    void end_of_elaboration() {}
    void start_of_simulation() {}
    void end_of_simulation() {}

    explicit sc_port_b(int n, sc_port_policy p) :
            sc_port_base(sc_gen_unique_name("port"), n, p)
    {}
    sc_port_b(const char *name, int n, sc_port_policy p) :
            sc_port_base(name, n, p)
    {}
    virtual ~sc_port_b() {}

    // Implementation defined, but depended on by the tests.
    int
    vbind(sc_interface &i)
    {
        IF *interface = dynamic_cast<IF *>(&i);
        if (!interface)
            return 2;
        sc_port_base::bind(*interface);
        return 0;
    }
    int
    vbind(sc_port_base &pb)
    {
        sc_port_b<IF> *p = dynamic_cast<sc_port_b<IF> *>(&pb);
        if (!p)
            return 2;
        sc_port_base::bind(*p);
        return 0;
    }

  private:
    std::vector<IF *> _interfaces;

    sc_interface *
    _gem5Interface(int n) const
    {
        if (n < 0 || n >= size()) {
            report_error(SC_ID_GET_IF_, "index out of range");
            return NULL;
        }
        return _interfaces[n];
    }
    void
    _gem5AddInterface(sc_interface *iface)
    {
        IF *interface = dynamic_cast<IF *>(iface);
        sc_assert(interface);
        for (unsigned i = 0; i < _interfaces.size(); i++) {
            if (interface == _interfaces[i]) {
                report_error(SC_ID_BIND_IF_TO_PORT_,
                        "interface already bound to port");
            }
        }
        _interfaces.push_back(interface);
    }

    const char *_ifTypeName() const { return typeid(IF).name(); }

    // Disabled
    sc_port_b() {}
    sc_port_b(const sc_port_b<IF> &) {}
    sc_port_b<IF> &operator = (const sc_port_b<IF> &) { return *this; }
};

template <class IF, int N=1, sc_port_policy P=SC_ONE_OR_MORE_BOUND>
class sc_port : public sc_port_b<IF>
{
  public:
    sc_port() : sc_port_b<IF>(N, P) {}
    explicit sc_port(const char *name) : sc_port_b<IF>(name, N, P) {}
    virtual ~sc_port() {}

    // Deprecated binding constructors.
    explicit sc_port(const IF &interface) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(const_cast<IF &>(interface));
    }
    sc_port(const char *name, const IF &interface) : sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(const_cast<IF &>(interface));
    }
    explicit sc_port(sc_port_b<IF> &parent) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    sc_port(const char *name, sc_port_b<IF> &parent) :
        sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    explicit sc_port(sc_port<IF, N, P> &parent) : sc_port_b<IF>(N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }
    sc_port(const char *name, sc_port<IF, N, P> &parent) :
        sc_port_b<IF>(name, N, P)
    {
        this->warn_port_constructor();
        sc_port_b<IF>::bind(parent);
    }

    virtual const char *kind() const { return "sc_port"; }

  private:
    // Disabled
    sc_port(const sc_port<IF, N, P> &) {}
    sc_port<IF, N, P> &operator = (const sc_port<IF, N, P> &) { return *this; }

    virtual sc_port_policy _portPolicy() const { return P; }
};

} // namespace sc_core

#endif  //__SYSTEMC_EXT_CORE_SC_PORT_HH__
<|endoftext|>


<commit_before>#ifndef __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__
#define __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__

#include <list>

#include "concurrency/queue/passive_producer.hpp"
#include "concurrency/semaphore.hpp"
#include "concurrency/drain_semaphore.hpp"
#include "do_on_thread.hpp"

/* `cross_thread_limited_fifo_t` is like `limited_fifo_t`, except that it is
efficient even when objects are being pushed onto the queue from a thread other
than the home thread. In the constructor, pass an extra parameter for the
thread that you intend to push objects onto the queue from. Pushing objects
onto the queue from that thread will be very efficient. */

template <class value_t, class queue_t = std::list<value_t> >
struct cross_thread_limited_fifo_t :
    public passive_producer_t<value_t>,
    public home_thread_mixin_t
{
    cross_thread_limited_fifo_t(int st, int capacity, float trickle_fraction = 0.0) :
        passive_producer_t<value_t>(&available_control),
        source_thread(st),
        semaphore(capacity, trickle_fraction),
        drain_semaphore(source_thread),
        in_destructor(false)
    {
        assert_good_thread_id(source_thread);
    }

    ~cross_thread_limited_fifo_t() {
        // Set `in_destructor` to `true` so nothing gets pushed onto the queue
        // or popped off of it; that way we will release the drain semaphore
        // the correct number of times
        in_destructor = true;
        int number_times_to_release_drain_semaphore = queue.size();
        {
            on_thread_t thread_switcher(source_thread);
            // The drain semaphore was acquired once for each thing pushed onto the
            // queue, and released once for each thing popped off the queue. The
            // difference, which we compensate for here, is the number of objects
            // that were on the queue at the time that the destructor was called.
            for (int i = 0; i < number_times_to_release_drain_semaphore; i++) {
                drain_semaphore.release();
            }
            drain_semaphore.drain();
        }
    }

    struct do_pusher_t {
	cross_thread_limited_fifo_t *parent_;
	value_t value_;
	do_pusher_t(cross_thread_limited_fifo_t *parent, const value_t& value)
	    : parent_(parent), value_(value) { }

	void operator()() {
	    parent_->do_push(value_);
	}
    };

    void push(const value_t& value) {
        rassert(get_thread_id() == source_thread);
        drain_semaphore.acquire();
        semaphore.co_lock();

        do_on_thread(home_thread(), do_pusher_t(this, value));
    }

    void set_capacity(int capacity) {
        on_thread_t thread_switcher(source_thread);
        semaphore.set_capacity(capacity);
    }

private:
    int source_thread;
    adjustable_semaphore_t semaphore;
    drain_semaphore_t drain_semaphore;
    bool in_destructor;
    queue_t queue;
    availability_control_t available_control;

    void do_push(const value_t &value) {
        assert_thread();
        rassert(!in_destructor);
        queue.push_back(value);
        available_control.set_available(!queue.empty());
    }

    void do_done() {
        rassert(get_thread_id() == source_thread);
        semaphore.unlock();
        drain_semaphore.release();
    }

    struct do_done_caller_t {
	cross_thread_limited_fifo_t *parent_;
	explicit do_done_caller_t(cross_thread_limited_fifo_t *parent) : parent_(parent) { }
	void operator()() { parent_->do_done(); }
    };

    value_t produce_next_value() {
        assert_thread();
        rassert(!in_destructor);
        value_t v = queue.front();
        queue.pop_front();
        do_on_thread(source_thread, do_done_caller_t(this));
        available_control.set_available(!queue.empty());
        return v;
    }

    DISABLE_COPYING(cross_thread_limited_fifo_t);
};

#endif /* __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__ */

<commit_msg>Revert "Removed rethread calls in cross_thread_limited_fifo_t and used specific_home_thread constructors instead."<commit_after>#ifndef __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__
#define __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__

#include <list>

#include "concurrency/queue/passive_producer.hpp"
#include "concurrency/semaphore.hpp"
#include "concurrency/drain_semaphore.hpp"
#include "do_on_thread.hpp"

/* `cross_thread_limited_fifo_t` is like `limited_fifo_t`, except that it is
efficient even when objects are being pushed onto the queue from a thread other
than the home thread. In the constructor, pass an extra parameter for the
thread that you intend to push objects onto the queue from. Pushing objects
onto the queue from that thread will be very efficient. */

template <class value_t, class queue_t = std::list<value_t> >
struct cross_thread_limited_fifo_t :
    public passive_producer_t<value_t>,
    public home_thread_mixin_t
{
    cross_thread_limited_fifo_t(int st, int capacity, float trickle_fraction = 0.0) :
        passive_producer_t<value_t>(&available_control),
        source_thread(st),
        semaphore(capacity, trickle_fraction),
        in_destructor(false)
    {
        assert_good_thread_id(source_thread);
        drain_semaphore.rethread(source_thread);
    }

    ~cross_thread_limited_fifo_t() {
        // Set `in_destructor` to `true` so nothing gets pushed onto the queue
        // or popped off of it; that way we will release the drain semaphore
        // the correct number of times
        in_destructor = true;
        int number_times_to_release_drain_semaphore = queue.size();
        {
            on_thread_t thread_switcher(source_thread);
            // The drain semaphore was acquired once for each thing pushed onto the
            // queue, and released once for each thing popped off the queue. The
            // difference, which we compensate for here, is the number of objects
            // that were on the queue at the time that the destructor was called.
            for (int i = 0; i < number_times_to_release_drain_semaphore; i++) drain_semaphore.release();
            drain_semaphore.drain();
        }
        drain_semaphore.rethread(home_thread());
    }

    struct do_pusher_t {
	cross_thread_limited_fifo_t *parent_;
	value_t value_;
	do_pusher_t(cross_thread_limited_fifo_t *parent, const value_t& value)
	    : parent_(parent), value_(value) { }

	void operator()() {
	    parent_->do_push(value_);
	}
    };

    void push(const value_t& value) {
        rassert(get_thread_id() == source_thread);
        drain_semaphore.acquire();
        semaphore.co_lock();

        do_on_thread(home_thread(), do_pusher_t(this, value));
    }

    void set_capacity(int capacity) {
        on_thread_t thread_switcher(source_thread);
        semaphore.set_capacity(capacity);
    }

private:
    int source_thread;
    adjustable_semaphore_t semaphore;
    drain_semaphore_t drain_semaphore;
    bool in_destructor;
    queue_t queue;
    availability_control_t available_control;

    void do_push(const value_t &value) {
        assert_thread();
        rassert(!in_destructor);
        queue.push_back(value);
        available_control.set_available(!queue.empty());
    }

    void do_done() {
        rassert(get_thread_id() == source_thread);
        semaphore.unlock();
        drain_semaphore.release();
    }

    struct do_done_caller_t {
	cross_thread_limited_fifo_t *parent_;
	explicit do_done_caller_t(cross_thread_limited_fifo_t *parent) : parent_(parent) { }
	void operator()() { parent_->do_done(); }
    };

    value_t produce_next_value() {
        assert_thread();
        rassert(!in_destructor);
        value_t v = queue.front();
        queue.pop_front();
        do_on_thread(source_thread, do_done_caller_t(this));
        available_control.set_available(!queue.empty());
        return v;
    }

    DISABLE_COPYING(cross_thread_limited_fifo_t);
};

#endif /* __CONCURRENCY_QUEUE_CROSS_THREAD_LIMITED_FIFO_HPP__ */

<|endoftext|>


<commit_before>#include "DissentTest.hpp"
#include "TestNode.hpp"

using namespace Dissent::Utils;

namespace Dissent {
namespace Tests {
  int Dissent::Tests::TestNode::calledback;

  void ConstructOverlay(int count, QVector<TestNode *> &nodes, QVector<Id> &group_vector)
  {
    for(int idx = 0; idx < count; idx++) {
      nodes.append(new TestNode(idx+1));
      group_vector.append(nodes[idx]->cm.GetId());
    }

    for(int idx = 0; idx < count; idx++) {
      for(int jdx = 0; jdx < count; jdx++) {
        if(idx == jdx) {
          continue;
        }
        nodes[idx]->cm.ConnectTo(BufferAddress(jdx+1));
      }
    }

    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }
  }

  void CreateSession(const QVector<TestNode *> &nodes, const Group &group,
      const Id &leader_id, const Id &session_id)
  {
    for(int idx = 0; idx < nodes.count(); idx++) {
      Session *session = new Session(nodes[idx]->cm.GetId(), leader_id, group,
          nodes[idx]->cm.GetConnectionTable(), &(nodes[idx]->rpc), session_id);
      nodes[idx]->session = session;
      session->SetSink(&(nodes[idx]->sink));
      nodes[idx]->sm.AddSession(session);
      QObject::connect(session, SIGNAL(RoundFinished(Session *, Round *)),
          nodes[idx], SLOT(HandleRoundFinished(Session *, Round *)));
    }
  }

  void CleanUp(const QVector<TestNode *> &nodes)
  {
    for(int idx = 0; idx < nodes.count(); idx++) {
      nodes[idx]->session->Stop();
      nodes[idx]->cm.Disconnect();
    }

    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < nodes.count(); idx++) {
      delete nodes[idx]->session;
      delete nodes[idx];
    }
  }

  TEST(NullRound, Basic)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int sender = random(0, count);

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    for(int idx = 0; idx < count; idx++) {
      for(int jdx = 0; jdx < count; jdx++) {
        if(idx == jdx) {
          continue;
        }
        EXPECT_TRUE(nodes[idx]->cm.GetConnectionTable().GetConnection(nodes[jdx]->cm.GetId()));
      }
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_TRUE(nodes[idx]->sink.GetLastData().isEmpty());
    }

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    Id data;
    QByteArray msg = data.GetByteArray();
    nodes[sender]->session->Send(msg);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    CleanUp(nodes);
  }

  TEST(NullRound, MultiRound)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int sender0 = random(0, count);
    int sender1 = random(0, count);
    while(sender0 != sender1) {
      sender1 = random(0, count);
    }

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    Id data0;
    QByteArray msg = data0.GetByteArray();
    nodes[sender0]->session->Send(msg);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    Id data1;
    msg = data1.GetByteArray();
    nodes[sender1]->session->Send(msg);

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count * 2) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    CleanUp(nodes);
  }

  TEST(NullRound, PeerDisconnect)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int disconnecter = random(0, count);
    while(leader != disconnecter) {
      disconnecter = random(0, count);
    }

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    nodes[disconnecter]->session->Stop();
    nodes[disconnecter]->cm.Disconnect();
    EXPECT_TRUE(nodes[disconnecter]->session->Closed());

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    Id data;
    QByteArray msg = data.GetByteArray();
    nodes[(leader + disconnecter) % count]->session->Send(msg);

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_TRUE(nodes[idx]->sink.GetLastData().isEmpty());
      EXPECT_TRUE(nodes[idx]->session->Closed());
    }

    nodes.remove(disconnecter);
    CleanUp(nodes);
  }
}
}
<commit_msg>[Tests] Bug in disconnecting a node...<commit_after>#include "DissentTest.hpp"
#include "TestNode.hpp"

using namespace Dissent::Utils;

namespace Dissent {
namespace Tests {
  int Dissent::Tests::TestNode::calledback;

  void ConstructOverlay(int count, QVector<TestNode *> &nodes, QVector<Id> &group_vector)
  {
    for(int idx = 0; idx < count; idx++) {
      nodes.append(new TestNode(idx+1));
      group_vector.append(nodes[idx]->cm.GetId());
    }

    for(int idx = 0; idx < count; idx++) {
      for(int jdx = 0; jdx < count; jdx++) {
        if(idx == jdx) {
          continue;
        }
        nodes[idx]->cm.ConnectTo(BufferAddress(jdx+1));
      }
    }

    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }
  }

  void CreateSession(const QVector<TestNode *> &nodes, const Group &group,
      const Id &leader_id, const Id &session_id)
  {
    for(int idx = 0; idx < nodes.count(); idx++) {
      Session *session = new Session(nodes[idx]->cm.GetId(), leader_id, group,
          nodes[idx]->cm.GetConnectionTable(), &(nodes[idx]->rpc), session_id);
      nodes[idx]->session = session;
      session->SetSink(&(nodes[idx]->sink));
      nodes[idx]->sm.AddSession(session);
      QObject::connect(session, SIGNAL(RoundFinished(Session *, Round *)),
          nodes[idx], SLOT(HandleRoundFinished(Session *, Round *)));
    }
  }

  void CleanUp(const QVector<TestNode *> &nodes)
  {
    for(int idx = 0; idx < nodes.count(); idx++) {
      nodes[idx]->session->Stop();
      nodes[idx]->cm.Disconnect();
    }

    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < nodes.count(); idx++) {
      delete nodes[idx]->session;
      delete nodes[idx];
    }
  }

  TEST(NullRound, Basic)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int sender = random(0, count);

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    for(int idx = 0; idx < count; idx++) {
      for(int jdx = 0; jdx < count; jdx++) {
        if(idx == jdx) {
          continue;
        }
        EXPECT_TRUE(nodes[idx]->cm.GetConnectionTable().GetConnection(nodes[jdx]->cm.GetId()));
      }
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_TRUE(nodes[idx]->sink.GetLastData().isEmpty());
    }

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    Id data;
    QByteArray msg = data.GetByteArray();
    nodes[sender]->session->Send(msg);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    CleanUp(nodes);
  }

  TEST(NullRound, MultiRound)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int sender0 = random(0, count);
    int sender1 = random(0, count);
    while(sender0 != sender1) {
      sender1 = random(0, count);
    }

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    Id data0;
    QByteArray msg = data0.GetByteArray();
    nodes[sender0]->session->Send(msg);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    Id data1;
    msg = data1.GetByteArray();
    nodes[sender1]->session->Send(msg);

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count * 2) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_EQ(msg, nodes[idx]->sink.GetLastData());
    }

    CleanUp(nodes);
  }

  TEST(NullRound, PeerDisconnect)
  {
    Timer::GetInstance().UseVirtualTime();

    int count = random(10, 100);
    int leader = random(0, count);
    int disconnecter = random(0, count);
    while(leader != disconnecter) {
      disconnecter = random(0, count);
    }

    QVector<TestNode *> nodes;
    QVector<Id> group_vector;

    ConstructOverlay(count, nodes, group_vector);
    Group group(group_vector);

    Id leader_id = nodes[leader]->cm.GetId();
    Id session_id;

    CreateSession(nodes, group, leader_id, session_id);

    for(int idx = 0; idx < count; idx++) {
      nodes[idx]->session->Start();
    }

    TestNode::calledback = 0;
    qint64 next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    nodes[disconnecter]->session->Stop();
    nodes[disconnecter]->cm.Disconnect();
    EXPECT_TRUE(nodes[disconnecter]->session->Closed());

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    Id data;
    QByteArray msg = data.GetByteArray();
    nodes[(leader + disconnecter) % count]->session->Send(msg);

    TestNode::calledback = 0;
    next = Timer::GetInstance().VirtualRun();
    while(next != -1 && TestNode::calledback < count) {
      Time::GetInstance().IncrementVirtualClock(next);
      next = Timer::GetInstance().VirtualRun();
    }

    for(int idx = 0; idx < count; idx++) {
      EXPECT_TRUE(nodes[idx]->sink.GetLastData().isEmpty());
      EXPECT_TRUE(nodes[idx]->session->Closed());
    }

    delete nodes[disconnecter];
    nodes.remove(disconnecter);
    CleanUp(nodes);
  }
}
}
<|endoftext|>


<commit_before>//
// Created by manu343726 on 4/08/15.
//

#include "type_id.hpp"
#include <unordered_map>
#include <iostream>

int main()
{
    std::unordered_map<ctti::type_id_t, int> map;
    std::string name = ctti::type_id("hello").name().c_str();

    map[ctti::type_id(1)]   = 1;
    map[ctti::type_id(1u)]  = 2;
    map[ctti::type_id(1ul)] = 3;

    static_assert(ctti::type_id<int>() == ctti::type_id(1), "???");
    static_assert(ctti::type_id<int>() != ctti::type_id<int*>(), "???");

    std::cout << map[ctti::type_id<int>()] << std::endl;
    std::cout << map[ctti::type_id<char>()] << std::endl;
    std::cout << map[ctti::type_id<unsigned long int>()] << std::endl;
    std::cout << ctti::type_id<int>().name() << std::endl;

    std::cin.get();
}
<commit_msg>Simplified main.cpp for disassembly checks<commit_after>//
// Created by manu343726 on 4/08/15.
//

#include "type_id.hpp"
#include <iostream>

int main()
{
    static_assert(ctti::type_id<int>() == ctti::type_id(1), "???");
    static_assert(ctti::type_id<int>() != ctti::type_id<int*>(), "???");

    std::cout << ctti::type_id<int>().name() << std::endl;
}
<|endoftext|>


<commit_before>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/io/SystemPipe.h>
#include <xzero/defines.h>
#include <xzero/sysconfig.h>
#include <xzero/RuntimeError.h>

#if defined(XZERO_OS_WIN32)
#include <Windows.h>
#else
#include <fcntl.h>
#include <unistd.h>
#endif

namespace xzero {

SystemPipe::SystemPipe() {
#if defined(XZERO_OS_WIN32)
  if (CreatePipe(&reader_, &writer_, nullptr, 4096) == FALSE) {
    // TODO: handle error with `DWORD GetLastError();`
  }
#else
  if (pipe(fds_) < 0) {
    RAISE_ERRNO(errno);
  }
#endif
}

SystemPipe::~SystemPipe() {
  closeReader();
  closeWriter();
}

void SystemPipe::setNonBlocking(bool enable) {
#if defined(XZERO_OS_WIN32)
  logFatal("Not Implemented yet.");
#else
  if (enable) {
    fcntl(fds_[0], F_SETFL, O_NONBLOCK);
    fcntl(fds_[1], F_SETFL, O_NONBLOCK);
  } else {
    for (int i = 0; i < 2; ++i) {
      int flags = fcntl(fds_[i], F_GETFL);
      if (flags != -1) {
        fcntl(fds_[i], F_SETFL, flags & ~O_NONBLOCK);
      }
    }
  }
#endif
}

void SystemPipe::closeReader() {
#if defined(XZERO_OS_WIN32)
  CloseHandle(reader_);
  writer_ = nullptr;
#else
  if (fds_[0] != -1) {
    ::close(fds_[0]);
    fds_[0] = -1;
  }
#endif
}

void SystemPipe::closeWriter() {
#if defined(XZERO_OS_WIN32)
  CloseHandle(writer_);
  writer_ = nullptr;
#else
  if (fds_[1] != -1) {
    ::close(fds_[1]);
    fds_[1] = -1;
  }
#endif
}

int SystemPipe::write(const void* buf, size_t count) {
#if defined(XZERO_OS_WIN32)
  DWORD nwritten = 0;
  WriteFile(writer_, buf, count, &nwritten, nullptr);
  return nwritten;
#else
  return ::write(writerFd(), buf, count);
#endif
}

int SystemPipe::write(const std::string& msg) {
  return write(msg.data(), msg.size());
}

void SystemPipe::consume() {
#if defined(XZERO_OS_WIN32)
  logFatal("Not Implemented yet.");
#else
  char buf[4096];
  int n;
  do n = ::read(readerFd(), buf, sizeof(buf));
  while (n > 0);
#endif
}

} // namespace xzero
<commit_msg>[xzero] SystemPipe: emulate pipe() on Win32<commit_after>// This file is part of the "x0" project, http://github.com/christianparpart/x0>
//   (c) 2009-2017 Christian Parpart <christian@parpart.family>
//
// Licensed under the MIT License (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of
// the License at: http://opensource.org/licenses/MIT

#include <xzero/io/SystemPipe.h>
#include <xzero/defines.h>
#include <xzero/sysconfig.h>
#include <xzero/RuntimeError.h>

#if defined(XZERO_OS_WIN32)
#include <Windows.h>
#else
#include <fcntl.h>
#include <unistd.h>
#endif

namespace xzero {

#if defined(XZERO_OS_WIN32)
struct WinSocket {
  SOCKET handle;

  WinSocket() : WinSocket{ INVALID_SOCKET } {}
  WinSocket(SOCKET h) : handle{h} {}

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

  ~WinSocket () {
    if (handle != INVALID_SOCKET) {
      closesocket(handle);
    }
  }

  WinSocket& operator=(SOCKET other) {
    if (handle != INVALID_SOCKET) {
      closesocket(handle);
    }
    handle = other;
    return *this;
  }

  bool operator!() const noexcept {
    return handle == INVALID_SOCKET;
  }

  operator SOCKET () {
    return ws;
  }

  int make_filedes() {
    int fd = _open_osfhandle(handle, 0);
    handle = INVALID_SOCKET;
    return fd;
  }
};

int pipe(int fd[2]) {
  // XXX setup listener
  WinSocket listener = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, 0);
  sockaddr_in addr = { 0 };
  int addr_size = sizeof(addr);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  addr.sin_port = 0;

  if (bind(listener, (struct sockaddr *)&addr, addr_size) == -1)
    return -1;

  if (getsockname(listener, (sockaddr *)&addr, &addr_size) == -1)
    return -1;

  if (listen(listener, 1) == -1)
    return -1;

  // XXX setup sender/receiver
  WinSocket receiver = WSASocket(AF_INET, SOCK_STREAM, 0, 0, 0, 0);
  if (connect(receiver, (struct sockaddr *)&addr, addr_size) == -1)
    return -1;

  WinSocket sender = accept(listener, 0, 0);
  if (!sender)
    return -1;

  sockaddr_in addr2;
  int addr2_size = sizeof(addr2);
  getpeername(receiver, (sockaddr*)&addr2, &addr2_size);
  getpeername(sender, (sockaddr*)&addr, &addr_size);

  fd[0] = receiver.make_filedes();
  fd[1] = sender.make_filedes();
  return 0;
}
#endif

SystemPipe::SystemPipe() {
  if (pipe(fds_) < 0) {
    RAISE_ERRNO(errno);
  }
}

SystemPipe::~SystemPipe() {
  closeReader();
  closeWriter();
}

void SystemPipe::setNonBlocking(bool enable) {
#if defined(XZERO_OS_WIN32)
  logFatal("Not Implemented yet.");
#else
  if (enable) {
    fcntl(fds_[0], F_SETFL, O_NONBLOCK);
    fcntl(fds_[1], F_SETFL, O_NONBLOCK);
  } else {
    for (int i = 0; i < 2; ++i) {
      int flags = fcntl(fds_[i], F_GETFL);
      if (flags != -1) {
        fcntl(fds_[i], F_SETFL, flags & ~O_NONBLOCK);
      }
    }
  }
#endif
}

void SystemPipe::closeReader() {
#if defined(XZERO_OS_WIN32)
  CloseHandle(reader_);
  writer_ = nullptr;
#else
  if (fds_[0] != -1) {
    ::close(fds_[0]);
    fds_[0] = -1;
  }
#endif
}

void SystemPipe::closeWriter() {
#if defined(XZERO_OS_WIN32)
  CloseHandle(writer_);
  writer_ = nullptr;
#else
  if (fds_[1] != -1) {
    ::close(fds_[1]);
    fds_[1] = -1;
  }
#endif
}

int SystemPipe::write(const void* buf, size_t count) {
#if defined(XZERO_OS_WIN32)
  DWORD nwritten = 0;
  WriteFile(writer_, buf, count, &nwritten, nullptr);
  return nwritten;
#else
  return ::write(writerFd(), buf, count);
#endif
}

int SystemPipe::write(const std::string& msg) {
  return write(msg.data(), msg.size());
}

void SystemPipe::consume() {
#if defined(XZERO_OS_WIN32)
  logFatal("Not Implemented yet.");
#else
  char buf[4096];
  int n;
  do n = ::read(readerFd(), buf, sizeof(buf));
  while (n > 0);
#endif
}

} // namespace xzero
<|endoftext|>