<commit_before>//////////////////////////////////////////////////////////////////////
// sect2.cpp -- Emit the Section2 Procedures
// Date: Sat Nov 30 13:50:35 2013
///////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#include <iostream>
#include <sstream>
#include <unordered_set>

#include "glue.hpp"
#include "comp.hpp"
#include "config.hpp"

void
emit_section2() {
	char sgenset[32];
	std::fstream ads, adb, cc;
	std::unordered_set<std::string> inclset;

	sprintf(sgenset,"%04d",config.section2.genset);

	std::cout << "Genset " << sgenset << " emit section2\n";

	if ( !gcc_open(ads,config.section2.genset,".ads") )
		exit(3);

	if ( !gcc_open(adb,config.section2.genset,".adb") )
		exit(3);

	ads << "\n";

	for ( auto it=config.section2.funcs.begin(); it != config.section2.funcs.end(); ++it ) {
		s_config::s_section2::s_func& func = *it;
		std::stringstream proto;
		std::string binding_name = "UX_";
		std::vector<std::string> macros_used;
		bool skip = false;

		if ( func.cases.size() > 0 ) {
			skip = true;		// For now

			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() ) {
							skip = false;
							macros_used.push_back(the_case);
						}
					}
				}
			}
		}

		if ( skip )
			continue;			// No cases are define macro names

		binding_name += func.c_name;		// Default internal c binding name

		if ( func.alt_name != "" )
			binding_name = func.alt_name;

		proto << func.type << " " << func.ada_name;

		if ( func.aargs.size() > 0 ) {
			proto << "(";

			bool f=true;

			for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
				s_config::s_section2::s_func::s_aarg& arg = *ait;

				if ( !f ) {
					proto << "; ";
				} else	{
					f = false;
				}
				proto << arg.name << ": ";
				if ( arg.io != "in" )
					proto << arg.io << " ";
				proto << arg.type;
			}
			proto << ")";
			if ( func.type == "function" )
				proto << " return " << func.ada_return;
		}

		//////////////////////////////////////////////////////
		// Generate the prototype in the Spec
		//////////////////////////////////////////////////////

		for ( auto mit = macros_used.begin(); mit != macros_used.end(); ++mit ) {
			const std::string macro_name = *mit;
			ads << "   -- " << macro_name << "\n";
		}

		ads << "   " << proto.str() << ";\n";
		if ( func.finline )
			ads << "   pragma Inline(" << func.ada_name << ");\n\n";

		//////////////////////////////////////////////////////
		// The body
		//////////////////////////////////////////////////////

		adb 	<< "   " << proto.str() << " is\n";

		// Use clauses
		for ( auto uit=func.use_clauses.begin(); uit != func.use_clauses.end(); ++uit ) {
			const std::string& use_clause = *uit;
			adb << "      use " << use_clause << ";\n";
		}

		// C Function Declaration
		if ( func.returns != "" )
			adb << "      function " << binding_name;
		else	adb << "      procedure " << binding_name;
		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto cit=func.cargs.begin(); cit != func.cargs.end(); ++cit ) {
				const s_config::s_section2::s_func::s_carg& arg = *cit;
				if ( !f )
					adb << "; ";
				else	f = false;
				adb << arg.name << " : " << arg.type;
			}
			adb << ")";
		}

		if ( func.returns != "" )
			adb << " return " << func.returns << ";\n";
		else	adb << ";\n";

		//  pragma Import(C,UX_close,"close");
		adb << "      pragma Import(C," << binding_name << ",\""
                    << func.bind_prefix << func.c_name << "\");\n";

		// Temporaries
		for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
			s_config::s_section2::s_func::s_aarg& arg = *ait;

			if ( arg.io == "in" && arg.temp != "" ) {
				std::stringstream s;
				std::string tempname;

				s << "T" << arg.argno;
				tempname = s.str();

				adb << "      " << tempname << " : " << arg.type
				    << " := " << arg.tempval << ";\n";
			}
		}

		// Declaration text
		for ( auto t=func.decls.begin(); t != func.decls.end(); ++t ) {
			const std::string& declaration = *t;

			adb << "      " << declaration << "\n";
		}

		// Temporary variables
		for ( auto t=func.temps.begin(); t != func.temps.end(); ++t ) {
			s_config::s_section2::s_func::s_temp& temp = *t;

			adb << "      " << temp.name << " : " << temp.type;
			if ( temp.init != "" )
				adb << " := " << temp.init;
			adb << ";\n";
		}

		// Return value:
		if ( func.rname != "" ) {
			adb << "      " << func.rname << " : " << func.returns << ";\n";
		}

		adb	<< "   begin\n";

		// Insert pre-checks
		if ( func.prechecks.size() > 0 ) {
			for ( auto pit=func.prechecks.cbegin(); pit != func.prechecks.cend(); ++pit ) {
				const std::string& cond = *pit;
				adb << "      if not ( " << cond << " ) then\n"
				    << "         " << func.on_error << ";\n"
				    << "         return;\n"
				    << "      end if;\n";
			}
		}

		// Insert case & when checks
		if ( func.cases.size() > 0 ) {
			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					std::vector<std::string> kvec;

					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() )
							kvec.push_back(the_case);
					}

					if ( kvec.size() > 0 ) {
						adb << "      case " << varname << " is\n";

						for ( auto vit=kvec.cbegin(); vit != kvec.cend(); ++vit ) {
							const std::string& the_case = *vit;
							adb << "         when " << the_case << "=>\n"
							    << "            null;\n";
						}

						adb << "         when others =>\n"
						    << "            Error := EINVAL;\n";

						if ( centry.on_error != "" )
							adb << "            " << centry.on_error << ";\n";

						adb << "            return;\n"
						    << "      end case;\n";
					}
				}
			}
		}

		if ( func.rname != "" ) {
			adb << "      " << func.rname << " := " << binding_name;
		} else	{
			adb << "      " << binding_name;
		}

		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto fit=func.cargs.begin(); fit != func.cargs.end(); ++fit ) {
				s_config::s_section2::s_func::s_carg& arg = *fit;
				if ( f )
					f = false;
				else	adb << ",";
				adb << arg.from;
			}
			adb << ")";
		}
		adb 	<< ";\n";

		// Output values:
		for ( auto oit=func.aargs.begin(); oit != func.aargs.end(); ++oit ) {
			s_config::s_section2::s_func::s_aarg& arg = *oit;

			if ( arg.from != "implied" ) {
				if ( arg.io == "out" || arg.io == "in out" ) {
					adb << "      " << arg.name << " := "
					    << arg.from << ";\n";
				}
			}
		}

		// Function return value
		if ( func.type == "function" ) {
			adb << "      return " << func.ada_rfrom << ";\n";
		}

		adb	<< "   end " << func.ada_name << ";\n\n";

		//////////////////////////////////////////////////////
		// Check if a macro must be emitted
		//////////////////////////////////////////////////////

		if ( func.macro != "" ) {
			if ( !cc.is_open() && !gcc_open(cc,config.section2.genset,".cc") )
				exit(3);

			for ( auto it=func.includes.begin(); it != func.includes.end(); ++it ) {
				const std::string& incl = *it;

				if ( inclset.find(incl) == inclset.end() ) {
					if ( incl[0] != '.' )
						cc << "#include <" << incl << ">\n";
					else	cc << "#include \"" << incl << "\"\n";
					inclset.insert(incl);
				}
			}

			cc << "\n"
			   << func.macro << "\n\n";
		}

	}

	ads.close();
	adb.close();
	cc.close();
}

// End sect2.cpp
<commit_msg>Fixed generation of Ada functions (without args)<commit_after>//////////////////////////////////////////////////////////////////////
// sect2.cpp -- Emit the Section2 Procedures
// Date: Sat Nov 30 13:50:35 2013
///////////////////////////////////////////////////////////////////////

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <assert.h>

#include <iostream>
#include <sstream>
#include <unordered_set>

#include "glue.hpp"
#include "comp.hpp"
#include "config.hpp"

void
emit_section2() {
	char sgenset[32];
	std::fstream ads, adb, cc;
	std::unordered_set<std::string> inclset;

	sprintf(sgenset,"%04d",config.section2.genset);

	std::cout << "Genset " << sgenset << " emit section2\n";

	if ( !gcc_open(ads,config.section2.genset,".ads") )
		exit(3);

	if ( !gcc_open(adb,config.section2.genset,".adb") )
		exit(3);

	ads << "\n";

	for ( auto it=config.section2.funcs.begin(); it != config.section2.funcs.end(); ++it ) {
		s_config::s_section2::s_func& func = *it;
		std::stringstream proto;
		std::string binding_name = "UX_";
		std::vector<std::string> macros_used;
		bool skip = false;

		if ( func.cases.size() > 0 ) {
			skip = true;		// For now

			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() ) {
							skip = false;
							macros_used.push_back(the_case);
						}
					}
				}
			}
		}

		if ( skip )
			continue;			// No cases are define macro names

		binding_name += func.c_name;		// Default internal c binding name

		if ( func.alt_name != "" )
			binding_name = func.alt_name;

		proto << func.type << " " << func.ada_name;

		if ( func.aargs.size() > 0 ) {
			proto << "(";

			bool f=true;

			for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
				s_config::s_section2::s_func::s_aarg& arg = *ait;

				if ( !f ) {
					proto << "; ";
				} else	{
					f = false;
				}
				proto << arg.name << ": ";
				if ( arg.io != "in" )
					proto << arg.io << " ";
				proto << arg.type;
			}
			proto << ")";
		}

		if ( func.type == "function" )
			proto << " return " << func.ada_return;

		//////////////////////////////////////////////////////
		// Generate the prototype in the Spec
		//////////////////////////////////////////////////////

		for ( auto mit = macros_used.begin(); mit != macros_used.end(); ++mit ) {
			const std::string macro_name = *mit;
			ads << "   -- " << macro_name << "\n";
		}

		ads << "   " << proto.str() << ";\n";
		if ( func.finline )
			ads << "   pragma Inline(" << func.ada_name << ");\n\n";

		//////////////////////////////////////////////////////
		// The body
		//////////////////////////////////////////////////////

		adb 	<< "   " << proto.str() << " is\n";

		// Use clauses
		for ( auto uit=func.use_clauses.begin(); uit != func.use_clauses.end(); ++uit ) {
			const std::string& use_clause = *uit;
			adb << "      use " << use_clause << ";\n";
		}

		// C Function Declaration
		if ( func.returns != "" )
			adb << "      function " << binding_name;
		else	adb << "      procedure " << binding_name;
		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto cit=func.cargs.begin(); cit != func.cargs.end(); ++cit ) {
				const s_config::s_section2::s_func::s_carg& arg = *cit;
				if ( !f )
					adb << "; ";
				else	f = false;
				adb << arg.name << " : " << arg.type;
			}
			adb << ")";
		}

		if ( func.returns != "" )
			adb << " return " << func.returns << ";\n";
		else	adb << ";\n";

		//  pragma Import(C,UX_close,"close");
		adb << "      pragma Import(C," << binding_name << ",\""
                    << func.bind_prefix << func.c_name << "\");\n";

		// Temporaries
		for ( auto ait=func.aargs.begin(); ait != func.aargs.end(); ++ait ) {
			s_config::s_section2::s_func::s_aarg& arg = *ait;

			if ( arg.io == "in" && arg.temp != "" ) {
				std::stringstream s;
				std::string tempname;

				s << "T" << arg.argno;
				tempname = s.str();

				adb << "      " << tempname << " : " << arg.type
				    << " := " << arg.tempval << ";\n";
			}
		}

		// Declaration text
		for ( auto t=func.decls.begin(); t != func.decls.end(); ++t ) {
			const std::string& declaration = *t;

			adb << "      " << declaration << "\n";
		}

		// Temporary variables
		for ( auto t=func.temps.begin(); t != func.temps.end(); ++t ) {
			s_config::s_section2::s_func::s_temp& temp = *t;

			adb << "      " << temp.name << " : " << temp.type;
			if ( temp.init != "" )
				adb << " := " << temp.init;
			adb << ";\n";
		}

		// Return value:
		if ( func.rname != "" ) {
			adb << "      " << func.rname << " : " << func.returns << ";\n";
		}

		adb	<< "   begin\n";

		// Insert pre-checks
		if ( func.prechecks.size() > 0 ) {
			for ( auto pit=func.prechecks.cbegin(); pit != func.prechecks.cend(); ++pit ) {
				const std::string& cond = *pit;
				adb << "      if not ( " << cond << " ) then\n"
				    << "         " << func.on_error << ";\n"
				    << "         return;\n"
				    << "      end if;\n";
			}
		}

		// Insert case & when checks
		if ( func.cases.size() > 0 ) {
			for ( auto cit=func.cases.cbegin(); cit != func.cases.cend(); ++cit ) {
				const std::string varname = cit->first;
				const s_config::s_section2::s_func::s_cases& centry = cit->second;

				if ( centry.casevec.size() > 0 ) {
					std::vector<std::string> kvec;

					for ( auto vit=centry.casevec.cbegin(); vit != centry.casevec.cend(); ++vit ) {
						const std::string& the_case = *vit;

						auto mit = config.declared_macros.find(the_case);
						if ( mit != config.declared_macros.end() )
							kvec.push_back(the_case);
					}

					if ( kvec.size() > 0 ) {
						adb << "      case " << varname << " is\n";

						for ( auto vit=kvec.cbegin(); vit != kvec.cend(); ++vit ) {
							const std::string& the_case = *vit;
							adb << "         when " << the_case << "=>\n"
							    << "            null;\n";
						}

						adb << "         when others =>\n"
						    << "            Error := EINVAL;\n";

						if ( centry.on_error != "" )
							adb << "            " << centry.on_error << ";\n";

						adb << "            return;\n"
						    << "      end case;\n";
					}
				}
			}
		}

		if ( func.rname != "" ) {
			adb << "      " << func.rname << " := " << binding_name;
		} else	{
			adb << "      " << binding_name;
		}

		if ( func.cargs.size() > 0 ) {
			adb << "(";
			bool f = true;
			for ( auto fit=func.cargs.begin(); fit != func.cargs.end(); ++fit ) {
				s_config::s_section2::s_func::s_carg& arg = *fit;
				if ( f )
					f = false;
				else	adb << ",";
				adb << arg.from;
			}
			adb << ")";
		}
		adb 	<< ";\n";

		// Output values:
		for ( auto oit=func.aargs.begin(); oit != func.aargs.end(); ++oit ) {
			s_config::s_section2::s_func::s_aarg& arg = *oit;

			if ( arg.from != "implied" ) {
				if ( arg.io == "out" || arg.io == "in out" ) {
					adb << "      " << arg.name << " := "
					    << arg.from << ";\n";
				}
			}
		}

		// Function return value
		if ( func.type == "function" ) {
			adb << "      return " << func.ada_rfrom << ";\n";
		}

		adb	<< "   end " << func.ada_name << ";\n\n";

		//////////////////////////////////////////////////////
		// Check if a macro must be emitted
		//////////////////////////////////////////////////////

		if ( func.macro != "" ) {
			if ( !cc.is_open() && !gcc_open(cc,config.section2.genset,".cc") )
				exit(3);

			for ( auto it=func.includes.begin(); it != func.includes.end(); ++it ) {
				const std::string& incl = *it;

				if ( inclset.find(incl) == inclset.end() ) {
					if ( incl[0] != '.' )
						cc << "#include <" << incl << ">\n";
					else	cc << "#include \"" << incl << "\"\n";
					inclset.insert(incl);
				}
			}

			cc << "\n"
			   << func.macro << "\n\n";
		}

	}

	ads.close();
	adb.close();
	cc.close();
}

// End sect2.cpp
<|endoftext|>


<commit_before>#ifndef FACTOR_ENCODER
#define FACTOR_ENCODER

#include <limits>
#include <map>
#include <queue>
#include <string>

class Token {
    public:
        int source;
        double cost;
        Token(): source(-1), cost(std::numeric_limits<double>::max()) {};
        Token(int src, double cst): source(src), cost(cst) {};
        Token(const Token& orig) { this->source=orig.source; this->cost=orig.cost; };
};

// Note just changed > to < ..
bool operator< (const Token& token1, const Token &token2)
{
    return token1.cost < token2.cost;
}

typedef std::priority_queue<Token> Node;

int read_vocab(const char* fname,
               std::map<std::string, double> &vocab,
               int &maxlen);

int viterbi(const std::map<std::string, double> &vocab,
            int maxlen,
            const std::string &sentence,
            std::vector<std::string> &best_path);

#endif
<commit_msg>some code to try different segmentations hypothesizing removal of some subwords.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <vector>
#include "common.hh"
#include "token.hh"

namespace loxpp {

class ErrorReporter;

class Scanner final : private UnCopyable {
  ErrorReporter& error_repoter_;
  const str_t& source_bytes_;
  str_t filename_;
  std::vector<Token> tokens_;

  sz_t start_pos_{};
  sz_t current_pos_{};
  int lineno_{1};

  inline str_t gen_literal(sz_t begpos, sz_t endpos) const noexcept {
    return source_bytes_.substr(begpos, endpos - begpos);
  }

  inline bool is_at_end() const noexcept { return current_pos_ >= source_bytes_.size(); }
  inline char advance() noexcept { return source_bytes_[current_pos_++]; }

  inline void add_token(TokenType type) noexcept {
    str_t literal = gen_literal(start_pos_, current_pos_);
    tokens_.push_back(Token::make_from_details(type, literal, lineno_));
  }

  void scan_token() noexcept;
public:
  Scanner(ErrorReporter& error_repoter, const str_t& source_bytes, const str_t& filename = "") noexcept;

  std::vector<Token>& scan_tokens() noexcept;
};

}
<commit_msg>:construction: chore(scanner): add match method implementation<commit_after>// Copyright (c) 2022 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#pragma once

#include <vector>
#include "common.hh"
#include "token.hh"

namespace loxpp {

class ErrorReporter;

class Scanner final : private UnCopyable {
  ErrorReporter& error_repoter_;
  const str_t& source_bytes_;
  str_t filename_;
  std::vector<Token> tokens_;

  sz_t start_pos_{};
  sz_t current_pos_{};
  int lineno_{1};

  inline str_t gen_literal(sz_t begpos, sz_t endpos) const noexcept {
    return source_bytes_.substr(begpos, endpos - begpos);
  }

  inline bool is_at_end() const noexcept { return current_pos_ >= source_bytes_.size(); }
  inline char advance() noexcept { return source_bytes_[current_pos_++]; }

  inline bool match(char expected) noexcept {
    if (is_at_end() || source_bytes_[current_pos_] != expected)
      return false;

    ++current_pos_;
    return true;
  }

  inline void add_token(TokenType type) noexcept {
    str_t literal = gen_literal(start_pos_, current_pos_);
    tokens_.push_back(Token::make_from_details(type, literal, lineno_));
  }

  void scan_token() noexcept;
public:
  Scanner(ErrorReporter& error_repoter, const str_t& source_bytes, const str_t& filename = "") noexcept;

  std::vector<Token>& scan_tokens() noexcept;
};

}
<|endoftext|>


<commit_before>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include "reliable_udp.hh"

#define GENERAL_PACKAGE (128)

#define TYPE_IGNORE     (0)
#define TYPE_CORRUPT    (1)
#define TYPE_REQUEST    (2)
#define TYPE_MISSING    (3)
#define TYPE_NORMAL     (4)

namespace rudp {

struct message {
  struct message* next;
  uint8_t* buffer;
  int sz;
  int cap;
  int id;
  int tick;
};

struct message_queue {
  struct message* head;
  struct message* tail;
};

static void queue_push(struct message_queue* mq, struct message* m) {
  if (mq->head == nullptr) {
    mq->head = mq->tail = m;
  }
  else {
    mq->tail->next = m;
    mq->tail = m;
  }
}

static struct message* queue_pop(struct message_queue* mq, int id) {
  if (mq->head == nullptr)
    return nullptr;

  struct message* m = mq->head;
  if (m->id != id)
    return nullptr;

  mq->head = m->next;
  m->next = nullptr;
  if (mq->head == nullptr)
    mq->tail = nullptr;
  return m;
}

struct array {
  int cap;
  int n;
  int* a;
};

static void array_insert(struct array* a, int id) {
  int i{};
  for (; i < a->n; ++i) {
    if (a->a[i] == id)
      return;
    if (a->a[i] > id)
      break;
  }
  // insert id before index [i]
  if (a->n >= a->cap) {
    if (a->cap == 0)
      a->cap = 16;
    else
      a->cap *= 2;
    a->a = (int*)realloc(a->a, sizeof(int) * a->cap);
  }
  for (int j = a->n; j > i; --j)
    a->a[j] = a->a[j - 1];
  a->a[i] = id;
  ++a->n;
}

struct rudp {
  struct message_queue send_queue; // user packages will send
  struct message_queue recv_queue; // the packages received
  struct message_queue send_history; // user packages already send

  struct rudp_package* send_package; // returns by rudp_update

  struct message* free_list; // recycle message
  struct array send_argain;

  int corrupt;
  int current_tick;
  int last_send_tick;
  int last_expired_tick;
  int send_id;
  int recv_id_min;
  int recv_id_max;
  int send_delay;
  int expired;
};

static int gen_id(struct rudp* u, const uint8_t* buffer) {
  int id = buffer[0] * 256 + buffer[1];
  id |= u->recv_id_max & ~0xffff;
  if (id < u->recv_id_max - 0x8000)
    id += 0x10000;
  else if (id > u->recv_id_max + 0x8000)
    id -= 0x10000;
  return id;
}

static void clear_outpackage(struct rudp* u) {
  struct rudp_package* package = u->send_package;
  while (package) {
    struct rudp_package* next_package = package->next;
    free(package);
    package = next_package;
  }
  u->send_package = nullptr;
}

static void free_message_list(struct message* m) {
  while (m) {
    struct message* next_message = m->next;
    free(m);
    m = next_message;
  }
}

// region: message methods
static struct message* new_message(struct rudp* u, const uint8_t* buffer, int sz) {
  struct message* m = u->free_list;
  if (m) {
    u->free_list = m->next;
    if (m->cap < sz) {
      free(m);
      m = nullptr;
    }
  }
  if (m == nullptr) {
    int cap = sz;
    if (cap < GENERAL_PACKAGE)
      cap = GENERAL_PACKAGE;
    m = (struct message*)malloc(sizeof(*m) + cap);
    if (m)
      m->cap = cap;
  }
  if (m == nullptr)
    return m;

  m->sz = sz;
  m->buffer = (uint8_t*)(m + 1);
  if (sz > 0 && buffer)
    memcpy(m->buffer, buffer, sz);
  m->tick = 0;
  m->id = 0;
  m->next = nullptr;
  return m;
}

static void delete_message(struct rudp* u, struct message* m) {
  m->next = u->free_list;
  u->free_list = m;
}

static void insert_message(struct rudp* u, int id, const uint8_t* buffer, int sz) {
  if (id < u->recv_id_min)
    return;
  if (id > u->recv_id_max || u->recv_queue.head == nullptr) {
    struct message* m = new_message(u, buffer, sz);
    m->id = id;
    queue_push(&u->recv_queue, m);
    u->recv_id_max = id;
  }
  else {
    struct message* m = u->recv_queue.head;
    struct message** last = &u->recv_queue.head;
    do {
      if (m->id == id)
        return;
      if (m->id > id) {
        struct message* temp_message = new_message(u, buffer, sz);
        temp_message->id = id;
        temp_message->next = m;
        *last = temp_message;
        return;
      }
      last = &m->next;
      m = m->next;
    } while (m);
  }
}

static void add_missing(struct rudp* u, int id) {
  insert_message(u, id, nullptr, -1);
}
// endregion: message methods

static void clear_send_expired(struct rudp* u, int tick) {
  struct message* m = u->send_history.head;
  struct message* last = nullptr;
  while (m) {
    if (m->tick >= tick)
      break;
    last = m;
    m = m->next;
  }
  if (last) {
    last->next = u->free_list;
    u->free_list = u->send_history.head;
  }
  u->send_history.head = m;
  if (m == nullptr)
    u->send_history.tail = nullptr;
}

static void add_request(struct rudp* u, int id) {
  array_insert(&u->send_argain, id);
}

// region: package functions
static void extrat_package(struct rudp* u, const uint8_t* buffer, int sz) {
  while (sz > 0) {
    int len = buffer[0];
    if (len > 127) {
      if (sz <= 1) {
        u->corrupt = 1;
        return;
      }
      len = (len * 256 + buffer[1]) & 0x7fff;
      buffer += 2;
      sz -= 2;
    }
    else {
      buffer += 1;
      sz -= 1;
    }

    switch (len) {
    case TYPE_IGNORE:
      if (u->send_argain.n == 0)
        array_insert(&u->send_argain, u->recv_id_min); // request next package id
      break;
    case TYPE_CORRUPT:
      u->corrupt = 1;
      return;
    case TYPE_REQUEST:
    case TYPE_MISSING:
      if (sz < 2) {
        u->corrupt = 1;
        return;
      }
      if (len == TYPE_REQUEST)
        add_request(u, gen_id(u, buffer));
      else
        add_missing(u, gen_id(u, buffer));
      buffer += 2;
      sz -= 2;
      break;
    default:
      len -= TYPE_NORMAL;
      if (sz < len + 2) {
        u->corrupt = 1;
        return;
      }
      else {
        int id = gen_id(u, buffer);
        insert_message(u, id, buffer + 2, len);
      }
      buffer += len + 2;
      sz -= len + 2;
      break;
    }
  }
}

struct temp_buffer {
  uint8_t buf[GENERAL_PACKAGE];
  int sz;
  struct rudp_package* head;
  struct rudp_package* tail;
};

static void new_package(struct rudp* u, struct temp_buffer* tmp) {
  struct rudp_package* p = (struct rudp_package*)malloc(sizeof(*p) + tmp->sz);
  p->next = nullptr;
  p->buffer = (char*)(p + 1);
  p->sz = tmp->sz;
  memcpy(p->buffer, tmp->buf, tmp->sz);
  if (tmp->tail == nullptr) {
    tmp->head = tmp->tail = p;
  }
  else {
    tmp->tail->next = p;
    tmp->tail = p;
  }
  tmp->sz = 0;
}

static int fill_header(uint8_t* buf, int len, int id) {
  int sz;
  if (len < 128) {
    buf[0] = len;
    ++buf;
    sz = 1;
  }
  else {
    buf[0] = ((len & 0x7f00) >> 8) | 0x80;
    buf[1] = len & 0xff;
    buf += 2;
    sz = 2;
  }
  buf[0] = (id & 0xff00) >> 8;
  buf[1] = id & 0xff;
  return sz + 2;
}

static void pack_request(struct rudp* u, struct temp_buffer* temp, int id, int tag) {
  int sz = GENERAL_PACKAGE - temp->sz;
  if (sz < 3)
    new_package(u, temp);
  uint8_t* buffer = temp->buf + temp->sz;
  temp->sz += fill_header(buffer, tag, id);
}
// endregion: package functions

// region: rudp export methods
struct rudp* rudp_new(int send_delay, int expired_time) {
  struct rudp* u = (struct rudp*)malloc(sizeof(*u));
  if (u) {
    memset(u, 0, sizeof(*u));
    u->send_delay = send_delay;
    u->expired = expired_time;
  }

  return u;
}

void rudp_delete(struct rudp* u) {
  free_message_list(u->send_queue.head);
  free_message_list(u->recv_queue.head);
  free_message_list(u->send_history.head);
  free_message_list(u->free_list);
  clear_outpackage(u);
  free(u->send_argain.a);
  free(u);
}

void rudp_send(struct rudp* u, const char* buffer, int sz) {
  assert(sz <= MAX_PACKAGE);
  struct message* m = new_message(u, (const uint8_t*)buffer, sz);
  m->id = u->send_id++;
  m->tick = u->current_tick;
  queue_push(&u->send_queue, m);
}

int rudp_recv(struct rudp* u, char buffer[MAX_PACKAGE]) {
  if (u->corrupt) {
    u->corrupt = 0;
    return -1;
  }
  struct message* m = queue_pop(&u->recv_queue, u->recv_id_min);
  if (m == nullptr)
    return 0;
  ++u->recv_id_min;
  int sz = m->sz;
  if (sz > 0)
    memcpy(buffer, m->buffer, sz);
  delete_message(u, m);

  return sz;
}
// endregion: rudp export methods

}
<commit_msg>:construction: chore(message): packing message for rudp<commit_after>// Copyright (c) 2020 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include "reliable_udp.hh"

#define GENERAL_PACKAGE (128)

#define TYPE_IGNORE     (0)
#define TYPE_CORRUPT    (1)
#define TYPE_REQUEST    (2)
#define TYPE_MISSING    (3)
#define TYPE_NORMAL     (4)

namespace rudp {

struct message {
  struct message* next;
  uint8_t* buffer;
  int sz;
  int cap;
  int id;
  int tick;
};

struct message_queue {
  struct message* head;
  struct message* tail;
};

static void queue_push(struct message_queue* mq, struct message* m) {
  if (mq->head == nullptr) {
    mq->head = mq->tail = m;
  }
  else {
    mq->tail->next = m;
    mq->tail = m;
  }
}

static struct message* queue_pop(struct message_queue* mq, int id) {
  if (mq->head == nullptr)
    return nullptr;

  struct message* m = mq->head;
  if (m->id != id)
    return nullptr;

  mq->head = m->next;
  m->next = nullptr;
  if (mq->head == nullptr)
    mq->tail = nullptr;
  return m;
}

struct array {
  int cap;
  int n;
  int* a;
};

static void array_insert(struct array* a, int id) {
  int i{};
  for (; i < a->n; ++i) {
    if (a->a[i] == id)
      return;
    if (a->a[i] > id)
      break;
  }
  // insert id before index [i]
  if (a->n >= a->cap) {
    if (a->cap == 0)
      a->cap = 16;
    else
      a->cap *= 2;
    a->a = (int*)realloc(a->a, sizeof(int) * a->cap);
  }
  for (int j = a->n; j > i; --j)
    a->a[j] = a->a[j - 1];
  a->a[i] = id;
  ++a->n;
}

struct rudp {
  struct message_queue send_queue; // user packages will send
  struct message_queue recv_queue; // the packages received
  struct message_queue send_history; // user packages already send

  struct rudp_package* send_package; // returns by rudp_update

  struct message* free_list; // recycle message
  struct array send_argain;

  int corrupt;
  int current_tick;
  int last_send_tick;
  int last_expired_tick;
  int send_id;
  int recv_id_min;
  int recv_id_max;
  int send_delay;
  int expired;
};

static int gen_id(struct rudp* u, const uint8_t* buffer) {
  int id = buffer[0] * 256 + buffer[1];
  id |= u->recv_id_max & ~0xffff;
  if (id < u->recv_id_max - 0x8000)
    id += 0x10000;
  else if (id > u->recv_id_max + 0x8000)
    id -= 0x10000;
  return id;
}

static void clear_outpackage(struct rudp* u) {
  struct rudp_package* package = u->send_package;
  while (package) {
    struct rudp_package* next_package = package->next;
    free(package);
    package = next_package;
  }
  u->send_package = nullptr;
}

static void free_message_list(struct message* m) {
  while (m) {
    struct message* next_message = m->next;
    free(m);
    m = next_message;
  }
}

// region: message methods
static struct message* new_message(struct rudp* u, const uint8_t* buffer, int sz) {
  struct message* m = u->free_list;
  if (m) {
    u->free_list = m->next;
    if (m->cap < sz) {
      free(m);
      m = nullptr;
    }
  }
  if (m == nullptr) {
    int cap = sz;
    if (cap < GENERAL_PACKAGE)
      cap = GENERAL_PACKAGE;
    m = (struct message*)malloc(sizeof(*m) + cap);
    if (m)
      m->cap = cap;
  }
  if (m == nullptr)
    return m;

  m->sz = sz;
  m->buffer = (uint8_t*)(m + 1);
  if (sz > 0 && buffer)
    memcpy(m->buffer, buffer, sz);
  m->tick = 0;
  m->id = 0;
  m->next = nullptr;
  return m;
}

static void delete_message(struct rudp* u, struct message* m) {
  m->next = u->free_list;
  u->free_list = m;
}

static void insert_message(struct rudp* u, int id, const uint8_t* buffer, int sz) {
  if (id < u->recv_id_min)
    return;
  if (id > u->recv_id_max || u->recv_queue.head == nullptr) {
    struct message* m = new_message(u, buffer, sz);
    m->id = id;
    queue_push(&u->recv_queue, m);
    u->recv_id_max = id;
  }
  else {
    struct message* m = u->recv_queue.head;
    struct message** last = &u->recv_queue.head;
    do {
      if (m->id == id)
        return;
      if (m->id > id) {
        struct message* temp_message = new_message(u, buffer, sz);
        temp_message->id = id;
        temp_message->next = m;
        *last = temp_message;
        return;
      }
      last = &m->next;
      m = m->next;
    } while (m);
  }
}

static void add_missing(struct rudp* u, int id) {
  insert_message(u, id, nullptr, -1);
}
// endregion: message methods

static void clear_send_expired(struct rudp* u, int tick) {
  struct message* m = u->send_history.head;
  struct message* last = nullptr;
  while (m) {
    if (m->tick >= tick)
      break;
    last = m;
    m = m->next;
  }
  if (last) {
    last->next = u->free_list;
    u->free_list = u->send_history.head;
  }
  u->send_history.head = m;
  if (m == nullptr)
    u->send_history.tail = nullptr;
}

static void add_request(struct rudp* u, int id) {
  array_insert(&u->send_argain, id);
}

// region: package functions
static void extrat_package(struct rudp* u, const uint8_t* buffer, int sz) {
  while (sz > 0) {
    int len = buffer[0];
    if (len > 127) {
      if (sz <= 1) {
        u->corrupt = 1;
        return;
      }
      len = (len * 256 + buffer[1]) & 0x7fff;
      buffer += 2;
      sz -= 2;
    }
    else {
      buffer += 1;
      sz -= 1;
    }

    switch (len) {
    case TYPE_IGNORE:
      if (u->send_argain.n == 0)
        array_insert(&u->send_argain, u->recv_id_min); // request next package id
      break;
    case TYPE_CORRUPT:
      u->corrupt = 1;
      return;
    case TYPE_REQUEST:
    case TYPE_MISSING:
      if (sz < 2) {
        u->corrupt = 1;
        return;
      }
      if (len == TYPE_REQUEST)
        add_request(u, gen_id(u, buffer));
      else
        add_missing(u, gen_id(u, buffer));
      buffer += 2;
      sz -= 2;
      break;
    default:
      len -= TYPE_NORMAL;
      if (sz < len + 2) {
        u->corrupt = 1;
        return;
      }
      else {
        int id = gen_id(u, buffer);
        insert_message(u, id, buffer + 2, len);
      }
      buffer += len + 2;
      sz -= len + 2;
      break;
    }
  }
}

struct temp_buffer {
  uint8_t buf[GENERAL_PACKAGE];
  int sz;
  struct rudp_package* head;
  struct rudp_package* tail;
};

static void new_package(struct rudp* u, struct temp_buffer* tmp) {
  struct rudp_package* p = (struct rudp_package*)malloc(sizeof(*p) + tmp->sz);
  p->next = nullptr;
  p->buffer = (char*)(p + 1);
  p->sz = tmp->sz;
  memcpy(p->buffer, tmp->buf, tmp->sz);
  if (tmp->tail == nullptr) {
    tmp->head = tmp->tail = p;
  }
  else {
    tmp->tail->next = p;
    tmp->tail = p;
  }
  tmp->sz = 0;
}

static int fill_header(uint8_t* buf, int len, int id) {
  int sz;
  if (len < 128) {
    buf[0] = len;
    ++buf;
    sz = 1;
  }
  else {
    buf[0] = ((len & 0x7f00) >> 8) | 0x80;
    buf[1] = len & 0xff;
    buf += 2;
    sz = 2;
  }
  buf[0] = (id & 0xff00) >> 8;
  buf[1] = id & 0xff;
  return sz + 2;
}

static void pack_request(struct rudp* u, struct temp_buffer* temp, int id, int tag) {
  int sz = GENERAL_PACKAGE - temp->sz;
  if (sz < 3)
    new_package(u, temp);
  uint8_t* buffer = temp->buf + temp->sz;
  temp->sz += fill_header(buffer, tag, id);
}

static void pack_message(struct rudp* u, struct temp_buffer* temp, struct message* m) {
  int sz = GENERAL_PACKAGE - temp->sz;
  if (m->sz > GENERAL_PACKAGE - 4) {
    if (temp->sz > 0)
      new_package(u, temp);
    sz = 4 + m->sz;
    struct rudp_package* p = (struct rudp_package*)malloc(sizeof(*p) + sz);
    p->next = nullptr;
    p->buffer = (char*)(p + 1);
    p->sz = sz;
    fill_header((uint8_t*)p->buffer, m->sz + TYPE_NORMAL, m->id);
    memcpy(p->buffer + 4, m->buffer, m->sz);
    if (temp->tail == nullptr) {
      temp->head = temp->tail = p;
    }
    else {
      temp->tail->next = p;
      temp->tail = p;
    }
    return;
  }
  if (sz < 4 + m->sz)
    new_package(u, temp);
  uint8_t* buf = temp->buf + temp->sz;
  int len = fill_header(buf, m->sz + TYPE_NORMAL, m->id);
  temp->sz += len + m->sz;
  buf += len;
  memcpy(buf, m->buffer, m->sz);
}
// endregion: package functions

// region: rudp export methods
struct rudp* rudp_new(int send_delay, int expired_time) {
  struct rudp* u = (struct rudp*)malloc(sizeof(*u));
  if (u) {
    memset(u, 0, sizeof(*u));
    u->send_delay = send_delay;
    u->expired = expired_time;
  }

  return u;
}

void rudp_delete(struct rudp* u) {
  free_message_list(u->send_queue.head);
  free_message_list(u->recv_queue.head);
  free_message_list(u->send_history.head);
  free_message_list(u->free_list);
  clear_outpackage(u);
  free(u->send_argain.a);
  free(u);
}

void rudp_send(struct rudp* u, const char* buffer, int sz) {
  assert(sz <= MAX_PACKAGE);
  struct message* m = new_message(u, (const uint8_t*)buffer, sz);
  m->id = u->send_id++;
  m->tick = u->current_tick;
  queue_push(&u->send_queue, m);
}

int rudp_recv(struct rudp* u, char buffer[MAX_PACKAGE]) {
  if (u->corrupt) {
    u->corrupt = 0;
    return -1;
  }
  struct message* m = queue_pop(&u->recv_queue, u->recv_id_min);
  if (m == nullptr)
    return 0;
  ++u->recv_id_min;
  int sz = m->sz;
  if (sz > 0)
    memcpy(buffer, m->buffer, sz);
  delete_message(u, m);

  return sz;
}
// endregion: rudp export methods

}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. 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.
 *
 */

#include <memory>
#include <iostream>
#include <string>
#include <thread>

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc++/async_unary_call.h>
#include <grpc++/completion_queue.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/status.h>
#include "helloworld.grpc.pb.h"

using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

static bool got_sigint = false;

class ServerImpl final {
 public:
  ServerImpl() : service_(&service_cq_) {}

  ~ServerImpl() {
    server_->Shutdown();
    rpc_cq_.Shutdown();
    service_cq_.Shutdown();
  }

  // There is no shutdown handling in this code.
  void Run() {
    std::string server_address("0.0.0.0:50051");

    ServerBuilder builder;
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterAsyncService(&service_);
    server_ = builder.BuildAndStart();
    std::cout << "Server listening on " << server_address << std::endl;

    while (true) {
      CallData* rpc = new CallData();
      service_.RequestSayHello(&rpc->ctx, &rpc->request, &rpc->responder,
                               &rpc_cq_, rpc);
      void* got_tag;
      bool ok;
      service_cq_.Next(&got_tag, &ok);
      GPR_ASSERT(ok);
      GPR_ASSERT(got_tag == rpc);

      std::thread t(&ServerImpl::HandleRpc, this, rpc);
      t.detach();
    }
  }

 private:
  struct CallData {
    CallData() : responder(&ctx) {}
    ServerContext ctx;
    HelloRequest request;
    HelloReply reply;
    ServerAsyncResponseWriter<HelloReply> responder;
  };

  // Runs in a detached thread, processes rpc then deletes data.
  void HandleRpc(CallData* rpc) {
    std::string prefix("Hello ");
    rpc->reply.set_message(prefix + rpc->request.name());
    rpc->responder.Finish(rpc->reply, Status::OK, &rpc->ctx);
    void* got_tag;
    bool ok;
    rpc_cq_.Next(&got_tag, &ok);
    GPR_ASSERT(ok);
    GPR_ASSERT(got_tag == &rpc->ctx);

    delete rpc;
  }

  CompletionQueue service_cq_;
  CompletionQueue rpc_cq_;
  Greeter::AsyncService service_;
  std::unique_ptr<Server> server_;
};

int main(int argc, char** argv) {
  grpc_init();

  ServerImpl server;
  server.Run();

  grpc_shutdown();
  return 0;
}
<commit_msg>Update code according to comment<commit_after>/*
 *
 * Copyright 2015, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. 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.
 *
 */

#include <memory>
#include <iostream>
#include <string>
#include <thread>

#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <grpc++/async_unary_call.h>
#include <grpc++/completion_queue.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/server_credentials.h>
#include <grpc++/status.h>
#include "helloworld.grpc.pb.h"

using grpc::CompletionQueue;
using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::Status;
using helloworld::HelloRequest;
using helloworld::HelloReply;
using helloworld::Greeter;

class ServerImpl final {
 public:
  ServerImpl() : service_(&cq_) {}

  ~ServerImpl() {
    server_->Shutdown();
    cq_.Shutdown();
  }

  // There is no shutdown handling in this code.
  void Run() {
    std::string server_address("0.0.0.0:50051");

    ServerBuilder builder;
    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    builder.RegisterAsyncService(&service_);
    server_ = builder.BuildAndStart();
    std::cout << "Server listening on " << server_address << std::endl;

    HandleRpcs();
  }

 private:
  class CallData {
   public:
    CallData(Greeter::AsyncService* service, CompletionQueue* cq)
        : service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) {
      Proceed();
    }

    void Proceed() {
      if (status_ == CREATE) {
        service_->RequestSayHello(&ctx_, &request_, &responder_, cq_, this);
        status_ = PROCESS;
      } else if (status_ == PROCESS) {
        new CallData(service_, cq_);
        std::string prefix("Hello ");
        reply_.set_message(prefix + request_.name());
        responder_.Finish(reply_, Status::OK, this);
        status_ = FINISH;
      } else {
        delete this;
      }
    }

   private:
    Greeter::AsyncService* service_;
    CompletionQueue* cq_;
    ServerContext ctx_;
    HelloRequest request_;
    HelloReply reply_;
    ServerAsyncResponseWriter<HelloReply> responder_;
    enum CallStatus { CREATE, PROCESS, FINISH };
    CallStatus status_;
  };

  // This can be run in multiple threads if needed.
  void HandleRpcs() {
    new CallData(&service_, &cq_);
    void* tag;
    bool ok;
    while (true) {
      cq_.Next(&tag, &ok);
      GPR_ASSERT(ok);
      static_cast<CallData*>(tag)->Proceed();
    }
  }

  CompletionQueue cq_;
  Greeter::AsyncService service_;
  std::unique_ptr<Server> server_;
};

int main(int argc, char** argv) {
  grpc_init();

  ServerImpl server;
  server.Run();

  grpc_shutdown();
  return 0;
}
<|endoftext|>


<commit_before>#include "ISprite.h"
#include "ISymbol.h"
#include "IBody.h"

#include <Box2D/Box2D.h>

#include "common/Math.h"
#include "common/color_trans.h"
#include "dataset/BVFactory.h"
#include "dataset/AbstractBV.h"
#include "dataset/SpriteFactory.h"

namespace d2d
{

ISprite::ISprite()
	: m_body(NULL)
	, m_observer(NULL)
{
	multiCol.set(1, 1, 1, 1);
	addCol.set(0, 0, 0, 0);
	clip = false;

	visiable = editable = true;

	m_angle = 0.0f;
	m_scale.set(1, 1);
	m_shear.set(0, 0);
	m_xMirror = m_yMirror = false;
	m_bounding = NULL;
}

ISprite::ISprite(const ISprite& sprite)
	: m_observer(NULL)
{
	name = sprite.name;
	multiCol = sprite.multiCol;
	addCol = sprite.addCol;
	clip = sprite.clip;

	visiable = sprite.visiable;
	editable = sprite.editable;
	tag = sprite.tag;

	m_pos = sprite.m_pos;
	m_angle = sprite.m_angle;
	m_offset = sprite.m_offset;
	m_scale = sprite.m_scale;
	m_shear = sprite.m_shear;
	m_xMirror = sprite.m_xMirror;
	m_yMirror = sprite.m_yMirror;
	m_bounding = sprite.m_bounding->clone();
	m_body = sprite.m_body ? sprite.m_body->clone() : NULL;
}

ISprite::~ISprite()
{
	delete m_bounding;
	delete m_body;

	SpriteFactory::Instance()->remove(this);
}

ISprite* ISprite::clone() const
{
	return NULL;
}

void ISprite::clearUserData(bool deletePtr)
{
	delete m_userData, m_userData = NULL;
}

void ISprite::load(const Json::Value& val)
{
	name = val["name"].asString();
	tag = val["tag"].asString();
	clip = val["clip"].asBool();

	std::string str = val["multi color"].asString();
	if (str.empty())
		multiCol = Colorf(1, 1, 1, 1);
	else
		multiCol = transColor(str, PT_BGRA);
	str = val["add color"].asString();
	if (str.empty())
		addCol = Colorf(0, 0, 0, 0);
	else
		addCol = transColor(str, PT_ARGB);

	float x = val["position"]["x"].asDouble();
	float y = val["position"]["y"].asDouble();
	float angle = val["angle"].asDouble();
	setTransform(Vector(x, y), angle);

	float sx, sy;
	if (val["scale"].isNull())
	{
		sx = val["x scale"].asDouble();
		sy = val["y scale"].asDouble();
	}
	else
	{
		sx = sy = val["scale"].asDouble();
	}
	setScale(sx, sy);

	float kx, ky;
	if (!val["x shear"].isNull())
	{
		kx = val["x shear"].asDouble();
		ky = val["y shear"].asDouble();
	}
	else
	{
		kx = ky = 0;
	}
	setShear(kx, ky);

	bool mx = val["x mirror"].asBool();
	bool my = val["y mirror"].asBool();
	setMirror(mx, my);

	float ox, oy;
	if (!val["x offset"].isNull())
	{
		ox = val["x offset"].asDouble();
		oy = val["y offset"].asDouble();
	}
	else
	{
		ox = oy = 0;
	}
	setOffset(Vector(ox, oy));
}

void ISprite::store(Json::Value& val) const
{
	val["name"] = name;
	val["tag"] = tag;
	val["clip"] = clip;

	val["multi color"] = transColor(multiCol, PT_BGRA);
	val["add color"] = transColor(addCol, PT_ARGB);

	val["position"]["x"] = m_pos.x;
	val["position"]["y"] = m_pos.y;

	val["angle"] = m_angle;

	val["x scale"] = m_scale.x;
	val["y scale"] = m_scale.y;

	val["x shear"] = m_shear.x;
	val["y shear"] = m_shear.y;

	val["x mirror"] = m_xMirror;
	val["y mirror"] = m_yMirror;

	val["x offset"] = m_offset.x;
	val["y offset"] = m_offset.y;
}

void ISprite::buildBounding()
{
	if (!m_bounding)
		m_bounding = BVFactory::createBV(e_obb);
	const ISymbol& symbol = getSymbol();
	Rect rect(symbol.getSize(this));
	if (m_offset.x == 0 && m_offset.y == 0)
		m_offset.set(rect.xCenter(), rect.yCenter());
	rect.scale(m_scale.x, m_scale.y);
	rect.shear(m_shear.x, m_shear.y);
	m_bounding->initFromRect(rect);
	m_bounding->setTransform(m_pos, m_offset, m_angle);
}

// todo: translate() and rotate() has no opt to m_body
void ISprite::setTransform(const Vector& position, float angle)
{
	if (m_pos != position) translate(position - m_pos);
	if (m_angle != angle) rotate(angle - m_angle);

	if (m_body)
		m_body->getBody()->SetTransform(b2Vec2(position.x / BOX2D_SCALE_FACTOR, position.y / BOX2D_SCALE_FACTOR), angle);
}

void ISprite::setScale(float xScale, float yScale)
{
	m_offset.x *= (xScale / m_scale.x);
	m_offset.y *= (yScale / m_scale.y);

	m_scale.set(xScale, yScale);
	onSizeChanged();
}

void ISprite::setShear(float xShear, float yShear)
{
	m_shear.set(xShear, yShear);
	onSizeChanged();
}

bool ISprite::isContain(const Vector& pos) const
{
	return m_bounding->isContain(pos);
}

bool ISprite::isIntersect(const Rect& rect) const
{
	return m_bounding->isIntersect(rect);
}

void ISprite::translate(const Vector& offset)
{
	if (m_observer)
		m_observer->translate(this, offset);

	m_pos += offset;
	if (m_bounding) {
		m_bounding->setTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::rotate(float delta)
{
	if (m_observer)
		m_observer->rotate(this, delta);

	m_angle += delta;

	if (m_bounding) {
		m_bounding->setTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::setOffset(const Vector& offset)
{
	// rotate + offset -> offset + rotate
	Vector old_center = getCenter();
	m_offset = offset;
	Vector new_center = getCenter();
	m_pos += (old_center - new_center);

	m_bounding->setTransform(m_pos, m_offset, m_angle);
}

Vector ISprite::getCenter() const
{
	d2d::Vector center_offset = Math::rotateVector(-m_offset, m_angle) + m_offset;
	d2d::Vector center = m_pos + center_offset;
	return center;
}

void ISprite::updateEachFrame()
{
	if (!m_body) return;

	b2Body* body = m_body->getBody();
	if (!body) return;

	if (m_body->isAlive() && m_body->getBody()->GetType() != b2_staticBody)
	{
		const b2Vec2& pos = body->GetPosition();
		setTransform(Vector(pos.x * BOX2D_SCALE_FACTOR, pos.y * BOX2D_SCALE_FACTOR), body->GetAngle());
	}
	else
	{
		body->SetTransform(b2Vec2(m_pos.x / BOX2D_SCALE_FACTOR, m_pos.y / BOX2D_SCALE_FACTOR), m_angle);
	}
}

IBody* ISprite::getBody() const
{
	return m_body;
}

void ISprite::onSizeChanged()
{
	buildBounding();

	if (m_body)
	{
		b2BodyType type = m_body->getBody()->GetType();
		loadBodyFromFile();
		if (m_body)
		{
			m_body->getBody()->SetTransform(b2Vec2(m_pos.x / BOX2D_SCALE_FACTOR, m_pos.y / BOX2D_SCALE_FACTOR), m_angle);
			m_body->getBody()->SetType(type);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
// class SpriteCmp
//////////////////////////////////////////////////////////////////////////

SpriteCmp::SpriteCmp(Type type /*= e_file*/)
	: m_type(type)
{
}

bool SpriteCmp::operator() (const ISprite* s0, const ISprite* s1) const
{
	switch (m_type)
	{
	case e_file:
		return s0->getSymbol().getFilepath() < s1->getSymbol().getFilepath();
	case e_x:
		return s0->getPosition().x < s1->getPosition().x;
	case e_y:
		return s0->getPosition().y < s1->getPosition().y;
	case e_x_invert:
		return s0->getPosition().x > s1->getPosition().x;
	case e_y_invert:
		return s0->getPosition().y > s1->getPosition().y;
	default:
		return s0->getSymbol().getFilepath() < s1->getSymbol().getFilepath();
	}
}

} // d2d<commit_msg>[FIXED] 调整sprite scale影响到offset<commit_after>#include "ISprite.h"
#include "ISymbol.h"
#include "IBody.h"

#include <Box2D/Box2D.h>

#include "common/Math.h"
#include "common/color_trans.h"
#include "dataset/BVFactory.h"
#include "dataset/AbstractBV.h"
#include "dataset/SpriteFactory.h"

namespace d2d
{

ISprite::ISprite()
	: m_body(NULL)
	, m_observer(NULL)
{
	multiCol.set(1, 1, 1, 1);
	addCol.set(0, 0, 0, 0);
	clip = false;

	visiable = editable = true;

	m_angle = 0.0f;
	m_scale.set(1, 1);
	m_shear.set(0, 0);
	m_xMirror = m_yMirror = false;
	m_bounding = NULL;
}

ISprite::ISprite(const ISprite& sprite)
	: m_observer(NULL)
{
	name = sprite.name;
	multiCol = sprite.multiCol;
	addCol = sprite.addCol;
	clip = sprite.clip;

	visiable = sprite.visiable;
	editable = sprite.editable;
	tag = sprite.tag;

	m_pos = sprite.m_pos;
	m_angle = sprite.m_angle;
	m_offset = sprite.m_offset;
	m_scale = sprite.m_scale;
	m_shear = sprite.m_shear;
	m_xMirror = sprite.m_xMirror;
	m_yMirror = sprite.m_yMirror;
	m_bounding = sprite.m_bounding->clone();
	m_body = sprite.m_body ? sprite.m_body->clone() : NULL;
}

ISprite::~ISprite()
{
	delete m_bounding;
	delete m_body;

	SpriteFactory::Instance()->remove(this);
}

ISprite* ISprite::clone() const
{
	return NULL;
}

void ISprite::clearUserData(bool deletePtr)
{
	delete m_userData, m_userData = NULL;
}

void ISprite::load(const Json::Value& val)
{
	name = val["name"].asString();
	tag = val["tag"].asString();
	clip = val["clip"].asBool();

	std::string str = val["multi color"].asString();
	if (str.empty())
		multiCol = Colorf(1, 1, 1, 1);
	else
		multiCol = transColor(str, PT_BGRA);
	str = val["add color"].asString();
	if (str.empty())
		addCol = Colorf(0, 0, 0, 0);
	else
		addCol = transColor(str, PT_ARGB);

	float x = val["position"]["x"].asDouble();
	float y = val["position"]["y"].asDouble();
	float angle = val["angle"].asDouble();
	setTransform(Vector(x, y), angle);

	float sx, sy;
	if (val["scale"].isNull())
	{
		sx = val["x scale"].asDouble();
		sy = val["y scale"].asDouble();
	}
	else
	{
		sx = sy = val["scale"].asDouble();
	}
	setScale(sx, sy);

	float kx, ky;
	if (!val["x shear"].isNull())
	{
		kx = val["x shear"].asDouble();
		ky = val["y shear"].asDouble();
	}
	else
	{
		kx = ky = 0;
	}
	setShear(kx, ky);

	bool mx = val["x mirror"].asBool();
	bool my = val["y mirror"].asBool();
	setMirror(mx, my);

	float ox, oy;
	if (!val["x offset"].isNull())
	{
		ox = val["x offset"].asDouble();
		oy = val["y offset"].asDouble();
	}
	else
	{
		ox = oy = 0;
	}
	setOffset(Vector(ox, oy));
}

void ISprite::store(Json::Value& val) const
{
	val["name"] = name;
	val["tag"] = tag;
	val["clip"] = clip;

	val["multi color"] = transColor(multiCol, PT_BGRA);
	val["add color"] = transColor(addCol, PT_ARGB);

	val["position"]["x"] = m_pos.x;
	val["position"]["y"] = m_pos.y;

	val["angle"] = m_angle;

	val["x scale"] = m_scale.x;
	val["y scale"] = m_scale.y;

	val["x shear"] = m_shear.x;
	val["y shear"] = m_shear.y;

	val["x mirror"] = m_xMirror;
	val["y mirror"] = m_yMirror;

	val["x offset"] = m_offset.x;
	val["y offset"] = m_offset.y;
}

void ISprite::buildBounding()
{
	if (!m_bounding)
		m_bounding = BVFactory::createBV(e_obb);
	const ISymbol& symbol = getSymbol();
	Rect rect(symbol.getSize(this));
	if (m_offset.x == 0 && m_offset.y == 0)
		m_offset.set(rect.xCenter(), rect.yCenter());
	rect.scale(m_scale.x, m_scale.y);
	rect.shear(m_shear.x, m_shear.y);
	m_bounding->initFromRect(rect);
	m_bounding->setTransform(m_pos, m_offset, m_angle);
}

// todo: translate() and rotate() has no opt to m_body
void ISprite::setTransform(const Vector& position, float angle)
{
	if (m_pos != position) translate(position - m_pos);
	if (m_angle != angle) rotate(angle - m_angle);

	if (m_body)
		m_body->getBody()->SetTransform(b2Vec2(position.x / BOX2D_SCALE_FACTOR, position.y / BOX2D_SCALE_FACTOR), angle);
}

void ISprite::setScale(float xScale, float yScale)
{
	m_scale.set(xScale, yScale);
	onSizeChanged();
}

void ISprite::setShear(float xShear, float yShear)
{
	m_shear.set(xShear, yShear);
	onSizeChanged();
}

bool ISprite::isContain(const Vector& pos) const
{
	return m_bounding->isContain(pos);
}

bool ISprite::isIntersect(const Rect& rect) const
{
	return m_bounding->isIntersect(rect);
}

void ISprite::translate(const Vector& offset)
{
	if (m_observer)
		m_observer->translate(this, offset);

	m_pos += offset;
	if (m_bounding) {
		m_bounding->setTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::rotate(float delta)
{
	if (m_observer)
		m_observer->rotate(this, delta);

	m_angle += delta;

	if (m_bounding) {
		m_bounding->setTransform(m_pos, m_offset, m_angle);
	}
}

void ISprite::setOffset(const Vector& offset)
{
	// rotate + offset -> offset + rotate
	Vector old_center = getCenter();
	m_offset = offset;
	Vector new_center = getCenter();
	m_pos += (old_center - new_center);

	m_bounding->setTransform(m_pos, m_offset, m_angle);
}

Vector ISprite::getCenter() const
{
	d2d::Vector center_offset = Math::rotateVector(-m_offset, m_angle) + m_offset;
	d2d::Vector center = m_pos + center_offset;
	return center;
}

void ISprite::updateEachFrame()
{
	if (!m_body) return;

	b2Body* body = m_body->getBody();
	if (!body) return;

	if (m_body->isAlive() && m_body->getBody()->GetType() != b2_staticBody)
	{
		const b2Vec2& pos = body->GetPosition();
		setTransform(Vector(pos.x * BOX2D_SCALE_FACTOR, pos.y * BOX2D_SCALE_FACTOR), body->GetAngle());
	}
	else
	{
		body->SetTransform(b2Vec2(m_pos.x / BOX2D_SCALE_FACTOR, m_pos.y / BOX2D_SCALE_FACTOR), m_angle);
	}
}

IBody* ISprite::getBody() const
{
	return m_body;
}

void ISprite::onSizeChanged()
{
	buildBounding();

	if (m_body)
	{
		b2BodyType type = m_body->getBody()->GetType();
		loadBodyFromFile();
		if (m_body)
		{
			m_body->getBody()->SetTransform(b2Vec2(m_pos.x / BOX2D_SCALE_FACTOR, m_pos.y / BOX2D_SCALE_FACTOR), m_angle);
			m_body->getBody()->SetType(type);
		}
	}
}

//////////////////////////////////////////////////////////////////////////
// class SpriteCmp
//////////////////////////////////////////////////////////////////////////

SpriteCmp::SpriteCmp(Type type /*= e_file*/)
	: m_type(type)
{
}

bool SpriteCmp::operator() (const ISprite* s0, const ISprite* s1) const
{
	switch (m_type)
	{
	case e_file:
		return s0->getSymbol().getFilepath() < s1->getSymbol().getFilepath();
	case e_x:
		return s0->getPosition().x < s1->getPosition().x;
	case e_y:
		return s0->getPosition().y < s1->getPosition().y;
	case e_x_invert:
		return s0->getPosition().x > s1->getPosition().x;
	case e_y_invert:
		return s0->getPosition().y > s1->getPosition().y;
	default:
		return s0->getSymbol().getFilepath() < s1->getSymbol().getFilepath();
	}
}

} // d2d<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "swissknife_lease.h"

#include <algorithm>

#include "swissknife_lease_curl.h"
#include "swissknife_lease_json.h"

#include "logging.h"
#include "util/string.h"

namespace {

bool CheckParams(const swissknife::CommandLease::Parameters& p) {
  if (p.action != "acquire" && p.action != "drop") {
    return false;
  }

  return true;
}

}  // namespace

namespace swissknife {

enum LeaseError {
  kLeaseSuccess = 0,
  kLeaseUnused = 1,
  kLeaseParamError = 2,
  kLeaseCurlInitError = 3,
  kLeaseFileOpenError = 4,
  kLeaseFileDeleteError = 5,
  kLeaseParseError = 6,
  kLeaseCurlReqError = 7,
};

CommandLease::~CommandLease() {}

ParameterList CommandLease::GetParams() const {
  ParameterList r;
  r.push_back(Parameter::Mandatory('u', "repo service url"));
  r.push_back(Parameter::Mandatory('a', "action (acquire or drop)"));
  r.push_back(Parameter::Mandatory('n', "user name"));
  r.push_back(Parameter::Mandatory('p', "lease path"));
  return r;
}

int CommandLease::Main(const ArgumentList& args) {
  Parameters params;

  params.repo_service_url = *(args.find('u')->second);
  params.action = *(args.find('a')->second);
  params.user_name = *(args.find('n')->second);

  const std::string lease_full_path = *(args.find('p')->second);
  std::vector<std::string> tokens = SplitString(lease_full_path, '/');
  params.lease_fqdn = tokens.front();

  // Remove the fqdn from the list of tokens and join them with "_" to make the
  // token file suffix
  tokens.erase(tokens.begin());
  params.token_file_suffix = JoinStrings(tokens, "_");

  if (!CheckParams(params)) {
    return kLeaseParamError;
  }

  // Initialize curl
  if (curl_global_init(CURL_GLOBAL_ALL)) {
    return kLeaseCurlInitError;
  }

  LeaseError ret = kLeaseSuccess;
  if (params.action == "acquire") {
    CurlBuffer buffer;
    if (MakeAcquireRequest(params.user_name, params.lease_fqdn,
                           params.repo_service_url, &buffer)) {
      std::string session_token;
      if (buffer.data.size() > 0 && ParseAcquireReply(buffer, &session_token)) {
        // Save session token to
        // /var/spool/cvmfs/<REPO_NAME>/session_token_<SUBPATH>
        // TODO(radu): Is there a special way to access the scratch directory?
        const std::string token_file_name =
            "/var/spool/cvmfs/" + params.lease_fqdn + "/session_token_" +
            params.token_file_suffix;
        if (!SafeWriteToFile(session_token, token_file_name, 0600)) {
          LogCvmfs(kLogCvmfs, kLogStderr, "Error opening file: %s",
                   std::strerror(errno));
          ret = kLeaseFileOpenError;
        }
      } else {
        ret = kLeaseParseError;
      }
    } else {
      ret = kLeaseCurlReqError;
    }
  } else if (params.action == "drop") {
    // Try to read session token from repository scratch directory
    std::string session_token;
    std::string token_file_name = "/var/spool/cvmfs/" + params.lease_fqdn +
                                  "/session_token_" + params.token_file_suffix;
    FILE* token_file = std::fopen(token_file_name.c_str(), "r");
    if (token_file) {
      GetLineFile(token_file, &session_token);
      LogCvmfs(kLogCvmfs, kLogStderr, "Read session token from file: %s",
               session_token.c_str());

      CurlBuffer buffer;
      if (MakeDeleteRequest(session_token, params.repo_service_url, &buffer)) {
        if (buffer.data.size() > 0 && ParseDropReply(buffer)) {
          std::fclose(token_file);
          if (unlink(token_file_name.c_str())) {
            LogCvmfs(kLogCvmfs, kLogStderr,
                     "Error deleting session token file");
            ret = kLeaseFileDeleteError;
          }
        } else {
          LogCvmfs(kLogCvmfs, kLogStderr, "Could not drop active lease");
          ret = kLeaseParseError;
        }
      } else {
        LogCvmfs(kLogCvmfs, kLogStderr, "Error making DELETE request");
        ret = kLeaseCurlReqError;
      }
    } else {
      LogCvmfs(kLogCvmfs, kLogStderr, "Error reading session token from file");
      ret = kLeaseFileOpenError;
    }
  }

  return ret;
}

}  // namespace swissknife
<commit_msg>Fixing cpplint<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "swissknife_lease.h"

#include <algorithm>
#include <vector>

#include "swissknife_lease_curl.h"
#include "swissknife_lease_json.h"

#include "logging.h"
#include "util/string.h"

namespace {

bool CheckParams(const swissknife::CommandLease::Parameters& p) {
  if (p.action != "acquire" && p.action != "drop") {
    return false;
  }

  return true;
}

}  // namespace

namespace swissknife {

enum LeaseError {
  kLeaseSuccess = 0,
  kLeaseUnused = 1,
  kLeaseParamError = 2,
  kLeaseCurlInitError = 3,
  kLeaseFileOpenError = 4,
  kLeaseFileDeleteError = 5,
  kLeaseParseError = 6,
  kLeaseCurlReqError = 7,
};

CommandLease::~CommandLease() {}

ParameterList CommandLease::GetParams() const {
  ParameterList r;
  r.push_back(Parameter::Mandatory('u', "repo service url"));
  r.push_back(Parameter::Mandatory('a', "action (acquire or drop)"));
  r.push_back(Parameter::Mandatory('n', "user name"));
  r.push_back(Parameter::Mandatory('p', "lease path"));
  return r;
}

int CommandLease::Main(const ArgumentList& args) {
  Parameters params;

  params.repo_service_url = *(args.find('u')->second);
  params.action = *(args.find('a')->second);
  params.user_name = *(args.find('n')->second);

  const std::string lease_full_path = *(args.find('p')->second);
  std::vector<std::string> tokens = SplitString(lease_full_path, '/');
  params.lease_fqdn = tokens.front();

  // Remove the fqdn from the list of tokens and join them with "_" to make the
  // token file suffix
  tokens.erase(tokens.begin());
  params.token_file_suffix = JoinStrings(tokens, "_");

  if (!CheckParams(params)) {
    return kLeaseParamError;
  }

  // Initialize curl
  if (curl_global_init(CURL_GLOBAL_ALL)) {
    return kLeaseCurlInitError;
  }

  LeaseError ret = kLeaseSuccess;
  if (params.action == "acquire") {
    CurlBuffer buffer;
    if (MakeAcquireRequest(params.user_name, params.lease_fqdn,
                           params.repo_service_url, &buffer)) {
      std::string session_token;
      if (buffer.data.size() > 0 && ParseAcquireReply(buffer, &session_token)) {
        // Save session token to
        // /var/spool/cvmfs/<REPO_NAME>/session_token_<SUBPATH>
        // TODO(radu): Is there a special way to access the scratch directory?
        const std::string token_file_name =
            "/var/spool/cvmfs/" + params.lease_fqdn + "/session_token_" +
            params.token_file_suffix;
        if (!SafeWriteToFile(session_token, token_file_name, 0600)) {
          LogCvmfs(kLogCvmfs, kLogStderr, "Error opening file: %s",
                   std::strerror(errno));
          ret = kLeaseFileOpenError;
        }
      } else {
        ret = kLeaseParseError;
      }
    } else {
      ret = kLeaseCurlReqError;
    }
  } else if (params.action == "drop") {
    // Try to read session token from repository scratch directory
    std::string session_token;
    std::string token_file_name = "/var/spool/cvmfs/" + params.lease_fqdn +
                                  "/session_token_" + params.token_file_suffix;
    FILE* token_file = std::fopen(token_file_name.c_str(), "r");
    if (token_file) {
      GetLineFile(token_file, &session_token);
      LogCvmfs(kLogCvmfs, kLogStderr, "Read session token from file: %s",
               session_token.c_str());

      CurlBuffer buffer;
      if (MakeDeleteRequest(session_token, params.repo_service_url, &buffer)) {
        if (buffer.data.size() > 0 && ParseDropReply(buffer)) {
          std::fclose(token_file);
          if (unlink(token_file_name.c_str())) {
            LogCvmfs(kLogCvmfs, kLogStderr,
                     "Error deleting session token file");
            ret = kLeaseFileDeleteError;
          }
        } else {
          LogCvmfs(kLogCvmfs, kLogStderr, "Could not drop active lease");
          ret = kLeaseParseError;
        }
      } else {
        LogCvmfs(kLogCvmfs, kLogStderr, "Error making DELETE request");
        ret = kLeaseCurlReqError;
      }
    } else {
      LogCvmfs(kLogCvmfs, kLogStderr, "Error reading session token from file");
      ret = kLeaseFileOpenError;
    }
  }

  return ret;
}

}  // namespace swissknife
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH
#define DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH

#include <vector>

#include <dune/common/bartonnackmanifcheck.hh>
#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>

#include <dune/stuff/functions/interfaces.hh>

namespace Dune {
namespace GDT {

/**
 *  \brief Interface for matrix valued basis functions.
 *
 *  \note   see specialization for rangeDimCols = 1 for vector and scalar valued basis functions.
 */
template< class Traits, class DomainFieldImp, int domainDim, class RangeFieldImp, int rangeDimRows, int rangeDimCols = 1 >
class BaseFunctionSetInterface;

/**
 *  \brief Interface for scalar and vector valued basis functions.
 */
template< class Traits, class DomainFieldImp, int domainDim, class RangeFieldImp, int rangeDim >
class BaseFunctionSetInterface< Traits, DomainFieldImp, domainDim, RangeFieldImp, rangeDim, 1 >
  : public Stuff::LocalfunctionSetInterface< typename Traits::EntityType, DomainFieldImp, domainDim, RangeFieldImp, rangeDim >
{
  typedef Stuff::LocalfunctionSetInterface
      < typename Traits::EntityType, DomainFieldImp, domainDim, RangeFieldImp, rangeDim >
    BaseType;
public:
  typedef typename Traits::derived_type derived_type;
  typedef typename Traits::BackendType  BackendType;
  typedef typename Traits::EntityType   EntityType;

  typedef DomainFieldImp                                  DomainFieldType;
  static const unsigned int                               dimDomain = domainDim;
  typedef Dune::FieldVector< DomainFieldType, dimDomain > DomainType;
  typedef RangeFieldImp                                 RangeFieldType;
  static const unsigned int                             dimRange = rangeDim;
  static const unsigned int                             dimRangeRows = rangeDim;
  static const unsigned int                             dimRangeCols = 1;
  typedef Dune::FieldVector< RangeFieldType, dimRange > RangeType;
  typedef Dune::FieldMatrix< RangeFieldType, dimRange, dimDomain > JacobianRangeType;

  BaseFunctionSetInterface(const EntityType& ent)
    : BaseType(ent)
  {}

  const BackendType& backend() const
  {
    CHECK_INTERFACE_IMPLEMENTATION(asImp().backend());
    return asImp().backend();
  }

  derived_type& asImp()
  {
    return static_cast< derived_type& >(*this);
  }

  const derived_type& asImp() const
  {
    return static_cast< const derived_type& >(*this);
  }
}; // class BaseFunctionSetInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH
<commit_msg>[basefunctionset.interface] update * use CRTP from dune-stuff * use types from base type<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Kirsten Weber

#ifndef DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH
#define DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH

#include <vector>

#include <dune/common/fvector.hh>
#include <dune/common/fmatrix.hh>

#include <dune/stuff/functions/interfaces.hh>
#include <dune/stuff/common/crtp.hh>

namespace Dune {
namespace GDT {

template< class Traits, class DomainFieldImp, int domainDim, class RangeFieldImp, int rangeDim, int rangeDimCols = 1 >
class BaseFunctionSetInterface
  : public Stuff::LocalfunctionSetInterface< typename Traits::EntityType, DomainFieldImp, domainDim, RangeFieldImp, rangeDim, rangeDimCols >
  , public Stuff::CRTPInterface< BaseFunctionSetInterface< Traits, DomainFieldImp, domainDim, RangeFieldImp, rangeDim, rangeDimCols >,
                                 Traits >
{
  typedef Stuff::LocalfunctionSetInterface
      < typename Traits::EntityType, DomainFieldImp, domainDim, RangeFieldImp, rangeDim, rangeDimCols > BaseType;
public:
  typedef typename Traits::derived_type derived_type;
  typedef typename Traits::BackendType  BackendType;
  typedef typename Traits::EntityType   EntityType;

  using typename BaseType::DomainFieldType;
  using BaseType::dimDomain;
  using typename BaseType::DomainType;
  using typename BaseType::RangeFieldType;
  using BaseType::dimRange;
  using BaseType::dimRangeCols;
  using typename BaseType::RangeType;
  using typename BaseType::JacobianRangeType;

  BaseFunctionSetInterface(const EntityType& ent)
    : BaseType(ent)
  {}

  const BackendType& backend() const
  {
    CHECK_CRTP(this->as_imp(*this).backend());
    return this->as_imp(*this).backend();
  }
}; // class BaseFunctionSetInterface

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_BASEFUNCTIONSET_INTERFACE_HH
<|endoftext|>