<commit_before>#pragma once

#include <iostream>
#include <map>
#include <string>
#include <unordered_map>
#include <utility>

#include "../ast.hpp"
#include "../utils/strings.hpp"

namespace visitor {

	/** Gets a list of variables declared in a grammar rule. */
	class variable_list : ast::visitor {
	public:
		variable_list() {}

		variable_list(const ast::grammar& g) {
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				types.insert(std::make_pair(r.name, r.type));
			}
		}

		void visit(ast::char_matcher& m) {}

		void visit(ast::str_matcher& m) {
			vars.insert(std::make_pair("psCatch", "parse::ind"));
			vars.insert(std::make_pair("psCatchLen", "parse::ind"));
			vars.insert(std::make_pair("psCapture", "std::string"));
		}

		void visit(ast::range_matcher& m) {}

		void visit(ast::rule_matcher& m) {
			if ( ! m.var.empty() ) {
				vars.insert(std::make_pair(m.var, types[m.rule]));
			}
		}

		void visit(ast::any_matcher& m) {}
		void visit(ast::empty_matcher& m) {}
		void visit(ast::action_matcher& m) {}

		void visit(ast::opt_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::many_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::some_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::seq_matcher& m) {
			for (auto it = m.ms.begin(); it != m.ms.end(); ++it) {
				(*it)->accept(this);
			}
		}

		void visit(ast::alt_matcher& m) {
			for (auto it = m.ms.begin(); it != m.ms.end(); ++it) {
				(*it)->accept(this);
			}
		}

		void visit(ast::look_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::not_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::capt_matcher& m) {
			m.m->accept(this);
		}

		std::map<std::string, std::string> list(ast::matcher_ptr& m) {
			vars.clear();
			m->accept(this);
			return vars;
		}

		std::map<std::string, std::string> list(ast::grammar_rule& r) {
			vars.clear();
			r.m->accept(this);
			return vars;
		}

	private:
		/** map of grammar rule names to types */
		std::unordered_map<std::string, std::string> types;
		/** map of variable names to types */
		std::map<std::string, std::string> vars;
	}; /* class variable_list */

	/** Code generator for Egg matcher ASTs */
	class compiler : ast::visitor {
	public:
		compiler(std::string name, std::ostream& out = std::cout)
			: name(name), out(out), tabs(2) {}

		void visit(ast::char_matcher& m) {
			out << "parse::matches<\'" << strings::escape(m.c) << "\'>(ps)";
		}

		void visit(ast::str_matcher& m) {
			std::string indent(++tabs, '\t');

			//setup lambda to match string
			out << "[&ps]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< std::endl
				<< indent << "if ( "
				;

			//match each character in the string
			if ( m.s.empty() ) {
				out << "true";
			} else {
				auto it = m.s.begin();
				out << "\'" << strings::escape(*it) << "\' == ps[ps.pos++]";
				while ( ++it != m.s.end() ) {
					out << std::endl
						<< indent << "&& \'" << strings::escape(*it) << "\' == ps[ps.pos++]"
						;
				}
			}

			//close lambda
			out << " ) { return true; }" << std::endl
				<< indent << "else { ps.pos= psStart; return false; }" << std::endl
				<< indent << "}()";

			--tabs;
		}

		void visit(ast::range_matcher& m) {
			std::string indent(++tabs, '\t');

			//chain matcher ranges
			out << "( ";
			if ( m.rs.empty() ) {
				out << "true";
			} else {
				auto it = m.rs.begin();
				if ( it->single() ) {
					out << "parse::matches<\'" << strings::escape(it->to) << "\'>(ps)";
				} else {
					out << "parse::in_range<\'" << strings::escape(it->from)
							<< "\',\'" << strings::escape(it->to) << "\'>(ps)";
				}
				while ( ++it != m.rs.end() ) {
					out << std::endl
						<< indent << "|| "
						;
					if ( it->single() ) {
						out << "parse::matches<\'" << strings::escape(it->to) << "\'>(ps)";
					} else {
						out << "parse::in_range<\'" << strings::escape(it->from)
								<< "\',\'" << strings::escape(it->to) << "\'>(ps)";
					}
				}
			}
			out << " )";

			--tabs;
		}

		void visit(ast::rule_matcher& m) {
			out << m.rule << "(ps)";
			if ( ! m.var.empty() ) { out << "(" << m.var << ")"; }
		}

		void visit(ast::any_matcher& m) {
			out << "parse::any(ps)";
		}

		void visit(ast::empty_matcher& m) {
			out << "true";
		}

		void visit(ast::action_matcher& m) {
			//runs action code with all variables bound, then returns true
			out << "[&]() {" << m.a << " return true; }()";
		}

		void visit(ast::opt_matcher& m) {
			//runs matcher, returns true regardless
			out << "[&]() { ";
			m.m->accept(this);
			out << "; return true; }()";
		}

		void visit(ast::many_matcher& m) {
			std::string indent(tabs, '\t');
			++tabs;

			//runs matcher as many times as it will match
			out << "[&]() { while ( ";
			m.m->accept(this);
			out << " )" << std::endl
			    << indent << "\t;" << std::endl
			    << indent << "return true; }()";

			--tabs;
		}

		void visit(ast::some_matcher& m) {
			std::string indent(tabs, '\t');
			++tabs;

			//runs matcher at least once, then ast many times as it will match
			out << "[&]() { if ( ";
			m.m->accept(this);
			out << " ) {" << std::endl
				<< indent << "\twhile ( ";
			m.m->accept(this);
			out << " )" << std::endl
				<< indent << "\t\t;" << std::endl
				<< indent << "\treturn true;" << std::endl
				<< indent << "} else { return false; } }()";

			--tabs;
		}

		void visit(ast::seq_matcher& m) {
			//empty sequence bad form, but always matches
			if ( m.ms.empty() ) {
				out << "true";
				return;
			}

			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO check this syntax is correct
			out << "[&]() { " << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";

			//test that all matchers match
			auto it = m.ms.begin();
			(*it)->accept(this);
			++it;
			while ( it != m.ms.end() ) {
				out << std::endl
					<< indent << "\t&& ";
				(*it)->accept(this);
				++it;
			}

			//match if so, reset otherwise
			out << " ) { return true; }" << std::endl
				<< indent << "else { ps.pos = psStart; return false; } }()";

			--tabs;
		}

		void visit(ast::alt_matcher& m) {
			//empty alternation bad form, but always matches
			if ( m.ms.empty() ) {
				out << "true";
				return;
			}

			std::string indent(++tabs, '\t');

			//match any of the contained matchers
			//-contained matchers will all reset pos, so no need to do it here
			out << "( ";
			auto it = m.ms.begin();
			(*it)->accept(this);
			++it;
			while ( it != m.ms.end() ) {
				out << std::endl
					<< indent << "|| ";
				(*it)->accept(this);
				++it;
			}
			out << " )";

			--tabs;
		}

		void visit(ast::look_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO syntax
			out << "[&]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher matches, always reset
			m.m->accept(this);
			out << " ) { ps.pos = psStart; return true; }" << std::endl
				<< indent << "else { ps.pos = psStart; return false; } }()";

			--tabs;
		}

		void visit(ast::not_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO syntax
			out << "[&]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher fails, always reset
			m.m->accept(this);
			out << " ) { ps.pos = psStart; return false; }" << std::endl
				<< indent << "else { ps.pos = psStart; return true; } }()";

			--tabs;
		}

		void visit(ast::capt_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables
			out << "[&]() {" << std::endl
				<< indent << "psCatch = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher matches
			m.m->accept(this);
			out << " ) {" << std::endl
				<< indent << "\tpsCatchLen = ps.pos - psCatch;" << std::endl
				<< indent << "\tpsCapture = ps.string(psCatch, psCatchLen);" << std::endl
				<< indent << "\treturn true;" << std::endl
				<< indent << "} else {" << std::endl
				<< indent << "\tpsCatchLen = 0;" << std::endl
				<< indent << "\tpsCapture = std::string(\"\");" << std::endl
				<< indent << "\treturn false;" << std::endl
				<< indent << "} }()";

			--tabs;
		}

		void compile(ast::grammar_rule& r) {
			bool typed = ! r.type.empty();

			//print prototype
			out << "\tparse::result<" << r.type << "> " << r.name << "(parse::state& ps) {" << std::endl
			//setup return point
				<< "\t\tparse::ind psStart = ps.pos;" << std::endl
				;
			//setup return variable
			if ( typed ) out << "\t\t" << r.type << " psVal;" << std::endl;
			out << std::endl;

			//setup bound variables
			std::map<std::string, std::string> vs = vars.list(r);
			for (auto it = vs.begin(); it != vs.end(); ++it) {
				out << "\t\t" << it->second << " " << it->first << ";" << std::endl;
			}
			out << std::endl;

			//apply matcher
			out << "\t\tif ( ";
			r.m->accept(this);
			out << " ) { return parse::match("
					<< (typed? "psVal" : "parse::val") << "); }" << std::endl
				<< "\t\telse { return parse::fail<"
					<< (typed? r.type : "parse::value") << ">(); }" << std::endl
				<< std::endl
				;

			//close out method
			out << "\t}" << std::endl
				<< std::endl
				;
		}

		/** Compiles a grammar to the output file. */
		void compile(ast::grammar& g) {
			//print pre-amble
			out << "#pragma once" << std::endl
				<< std::endl
				<< "/* THE FOLLOWING HAS BEEN AUTOMATICALLY GENERATED BY THE EGG PARSER GENERATOR." << std::endl
				<< " * DO NOT EDIT. */" << std::endl
				<< std::endl
				;

			//print pre-code
			if ( ! g.pre.empty() ) {
				out << "// {%" << std::endl
					<< g.pre << std::endl
					<< "// %}" << std::endl
					<< std::endl
					;
			}

			//get needed includes
			out << "#include <string>" << std::endl
				<< "#include \"parse.hpp\"" << std::endl
				<< std::endl
				;

			//setup parser namespace
			out << "namespace " << name << " {" << std::endl
				<< std::endl
				;

			//pre-declare matchers
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				out << "\tparse::result<" << r.type << "> " << r.name << "(parse::state&);" << std::endl;
			}
			out << std::endl;

			//generate matching functions
			vars = variable_list(g);
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				compile(r);
			}

			//close parser namespace
			out << "} /* namespace " << name << " */" << std::endl
				<< std::endl
				;
		}

	private:
		std::string name;	/** Name of the grammar */
		std::ostream& out;	/** Output stream to print to */
		variable_list vars;	/** Holds grammar rule types */
		int tabs;			/** Number of tabs for printer */
	}; /* class compiler */

} /* namespace visitor */

<commit_msg>Fixed code generation bug with capture matchers<commit_after>#pragma once

#include <iostream>
#include <map>
#include <string>
#include <unordered_map>
#include <utility>

#include "../ast.hpp"
#include "../utils/strings.hpp"

namespace visitor {

	/** Gets a list of variables declared in a grammar rule. */
	class variable_list : ast::visitor {
	public:
		variable_list() {}

		variable_list(const ast::grammar& g) {
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				types.insert(std::make_pair(r.name, r.type));
			}
		}

		void visit(ast::char_matcher& m) {}

		void visit(ast::str_matcher& m) {}

		void visit(ast::range_matcher& m) {}

		void visit(ast::rule_matcher& m) {
			if ( ! m.var.empty() ) {
				vars.insert(std::make_pair(m.var, types[m.rule]));
			}
		}

		void visit(ast::any_matcher& m) {}
		void visit(ast::empty_matcher& m) {}
		void visit(ast::action_matcher& m) {}

		void visit(ast::opt_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::many_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::some_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::seq_matcher& m) {
			for (auto it = m.ms.begin(); it != m.ms.end(); ++it) {
				(*it)->accept(this);
			}
		}

		void visit(ast::alt_matcher& m) {
			for (auto it = m.ms.begin(); it != m.ms.end(); ++it) {
				(*it)->accept(this);
			}
		}

		void visit(ast::look_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::not_matcher& m) {
			m.m->accept(this);
		}

		void visit(ast::capt_matcher& m) {
			vars.insert(std::make_pair("psCatch", "parse::ind"));
			vars.insert(std::make_pair("psCatchLen", "parse::ind"));
			vars.insert(std::make_pair("psCapture", "std::string"));
			m.m->accept(this);
		}

		std::map<std::string, std::string> list(ast::matcher_ptr& m) {
			vars.clear();
			m->accept(this);
			return vars;
		}

		std::map<std::string, std::string> list(ast::grammar_rule& r) {
			vars.clear();
			r.m->accept(this);
			return vars;
		}

	private:
		/** map of grammar rule names to types */
		std::unordered_map<std::string, std::string> types;
		/** map of variable names to types */
		std::map<std::string, std::string> vars;
	}; /* class variable_list */

	/** Code generator for Egg matcher ASTs */
	class compiler : ast::visitor {
	public:
		compiler(std::string name, std::ostream& out = std::cout)
			: name(name), out(out), tabs(2) {}

		void visit(ast::char_matcher& m) {
			out << "parse::matches<\'" << strings::escape(m.c) << "\'>(ps)";
		}

		void visit(ast::str_matcher& m) {
			std::string indent(++tabs, '\t');

			//setup lambda to match string
			out << "[&ps]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< std::endl
				<< indent << "if ( "
				;

			//match each character in the string
			if ( m.s.empty() ) {
				out << "true";
			} else {
				auto it = m.s.begin();
				out << "\'" << strings::escape(*it) << "\' == ps[ps.pos++]";
				while ( ++it != m.s.end() ) {
					out << std::endl
						<< indent << "&& \'" << strings::escape(*it) << "\' == ps[ps.pos++]"
						;
				}
			}

			//close lambda
			out << " ) { return true; }" << std::endl
				<< indent << "else { ps.pos= psStart; return false; }" << std::endl
				<< indent << "}()";

			--tabs;
		}

		void visit(ast::range_matcher& m) {
			std::string indent(++tabs, '\t');

			//chain matcher ranges
			out << "( ";
			if ( m.rs.empty() ) {
				out << "true";
			} else {
				auto it = m.rs.begin();
				if ( it->single() ) {
					out << "parse::matches<\'" << strings::escape(it->to) << "\'>(ps)";
				} else {
					out << "parse::in_range<\'" << strings::escape(it->from)
							<< "\',\'" << strings::escape(it->to) << "\'>(ps)";
				}
				while ( ++it != m.rs.end() ) {
					out << std::endl
						<< indent << "|| "
						;
					if ( it->single() ) {
						out << "parse::matches<\'" << strings::escape(it->to) << "\'>(ps)";
					} else {
						out << "parse::in_range<\'" << strings::escape(it->from)
								<< "\',\'" << strings::escape(it->to) << "\'>(ps)";
					}
				}
			}
			out << " )";

			--tabs;
		}

		void visit(ast::rule_matcher& m) {
			out << m.rule << "(ps)";
			if ( ! m.var.empty() ) { out << "(" << m.var << ")"; }
		}

		void visit(ast::any_matcher& m) {
			out << "parse::any(ps)";
		}

		void visit(ast::empty_matcher& m) {
			out << "true";
		}

		void visit(ast::action_matcher& m) {
			//runs action code with all variables bound, then returns true
			out << "[&]() {" << m.a << " return true; }()";
		}

		void visit(ast::opt_matcher& m) {
			//runs matcher, returns true regardless
			out << "[&]() { ";
			m.m->accept(this);
			out << "; return true; }()";
		}

		void visit(ast::many_matcher& m) {
			std::string indent(tabs, '\t');
			++tabs;

			//runs matcher as many times as it will match
			out << "[&]() { while ( ";
			m.m->accept(this);
			out << " )" << std::endl
			    << indent << "\t;" << std::endl
			    << indent << "return true; }()";

			--tabs;
		}

		void visit(ast::some_matcher& m) {
			std::string indent(tabs, '\t');
			++tabs;

			//runs matcher at least once, then ast many times as it will match
			out << "[&]() { if ( ";
			m.m->accept(this);
			out << " ) {" << std::endl
				<< indent << "\twhile ( ";
			m.m->accept(this);
			out << " )" << std::endl
				<< indent << "\t\t;" << std::endl
				<< indent << "\treturn true;" << std::endl
				<< indent << "} else { return false; } }()";

			--tabs;
		}

		void visit(ast::seq_matcher& m) {
			//empty sequence bad form, but always matches
			if ( m.ms.empty() ) {
				out << "true";
				return;
			}

			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO check this syntax is correct
			out << "[&]() { " << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";

			//test that all matchers match
			auto it = m.ms.begin();
			(*it)->accept(this);
			++it;
			while ( it != m.ms.end() ) {
				out << std::endl
					<< indent << "\t&& ";
				(*it)->accept(this);
				++it;
			}

			//match if so, reset otherwise
			out << " ) { return true; }" << std::endl
				<< indent << "else { ps.pos = psStart; return false; } }()";

			--tabs;
		}

		void visit(ast::alt_matcher& m) {
			//empty alternation bad form, but always matches
			if ( m.ms.empty() ) {
				out << "true";
				return;
			}

			std::string indent(++tabs, '\t');

			//match any of the contained matchers
			//-contained matchers will all reset pos, so no need to do it here
			out << "( ";
			auto it = m.ms.begin();
			(*it)->accept(this);
			++it;
			while ( it != m.ms.end() ) {
				out << std::endl
					<< indent << "|| ";
				(*it)->accept(this);
				++it;
			}
			out << " )";

			--tabs;
		}

		void visit(ast::look_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO syntax
			out << "[&]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher matches, always reset
			m.m->accept(this);
			out << " ) { ps.pos = psStart; return true; }" << std::endl
				<< indent << "else { ps.pos = psStart; return false; } }()";

			--tabs;
		}

		void visit(ast::not_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables but psStart TODO syntax
			out << "[&]() {" << std::endl
				<< indent << "parse::ind psStart = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher fails, always reset
			m.m->accept(this);
			out << " ) { ps.pos = psStart; return false; }" << std::endl
				<< indent << "else { ps.pos = psStart; return true; } }()";

			--tabs;
		}

		void visit(ast::capt_matcher& m) {
			std::string indent(++tabs, '\t');

			//bind all variables
			out << "[&]() {" << std::endl
				<< indent << "psCatch = ps.pos;" << std::endl
				<< indent << "if ( ";
			//match iff contained matcher matches
			m.m->accept(this);
			out << " ) {" << std::endl
				<< indent << "\tpsCatchLen = ps.pos - psCatch;" << std::endl
				<< indent << "\tpsCapture = ps.string(psCatch, psCatchLen);" << std::endl
				<< indent << "\treturn true;" << std::endl
				<< indent << "} else {" << std::endl
				<< indent << "\tpsCatchLen = 0;" << std::endl
				<< indent << "\tpsCapture = std::string(\"\");" << std::endl
				<< indent << "\treturn false;" << std::endl
				<< indent << "} }()";

			--tabs;
		}

		void compile(ast::grammar_rule& r) {
			bool typed = ! r.type.empty();

			//print prototype
			out << "\tparse::result<" << r.type << "> " << r.name << "(parse::state& ps) {" << std::endl
			//setup return point
				<< "\t\tparse::ind psStart = ps.pos;" << std::endl
				;
			//setup return variable
			if ( typed ) out << "\t\t" << r.type << " psVal;" << std::endl;
			out << std::endl;

			//setup bound variables
			std::map<std::string, std::string> vs = vars.list(r);
			for (auto it = vs.begin(); it != vs.end(); ++it) {
				out << "\t\t" << it->second << " " << it->first << ";" << std::endl;
			}
			out << std::endl;

			//apply matcher
			out << "\t\tif ( ";
			r.m->accept(this);
			out << " ) { return parse::match("
					<< (typed? "psVal" : "parse::val") << "); }" << std::endl
				<< "\t\telse { return parse::fail<"
					<< (typed? r.type : "parse::value") << ">(); }" << std::endl
				<< std::endl
				;

			//close out method
			out << "\t}" << std::endl
				<< std::endl
				;
		}

		/** Compiles a grammar to the output file. */
		void compile(ast::grammar& g) {
			//print pre-amble
			out << "#pragma once" << std::endl
				<< std::endl
				<< "/* THE FOLLOWING HAS BEEN AUTOMATICALLY GENERATED BY THE EGG PARSER GENERATOR." << std::endl
				<< " * DO NOT EDIT. */" << std::endl
				<< std::endl
				;

			//print pre-code
			if ( ! g.pre.empty() ) {
				out << "// {%" << std::endl
					<< g.pre << std::endl
					<< "// %}" << std::endl
					<< std::endl
					;
			}

			//get needed includes
			out << "#include <string>" << std::endl
				<< "#include \"parse.hpp\"" << std::endl
				<< std::endl
				;

			//setup parser namespace
			out << "namespace " << name << " {" << std::endl
				<< std::endl
				;

			//pre-declare matchers
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				out << "\tparse::result<" << r.type << "> " << r.name << "(parse::state&);" << std::endl;
			}
			out << std::endl;

			//generate matching functions
			vars = variable_list(g);
			for (auto it = g.rs.begin(); it != g.rs.end(); ++it) {
				ast::grammar_rule& r = **it;
				compile(r);
			}

			//close parser namespace
			out << "} /* namespace " << name << " */" << std::endl
				<< std::endl
				;
		}

	private:
		std::string name;	/** Name of the grammar */
		std::ostream& out;	/** Output stream to print to */
		variable_list vars;	/** Holds grammar rule types */
		int tabs;			/** Number of tabs for printer */
	}; /* class compiler */

} /* namespace visitor */

<|endoftext|>


<commit_before>/*
Copyright (c) by respective owners including Yahoo!, Microsoft, and
individual contributors. All rights reserved.  Released under a BSD (revised)
license as described in the file LICENSE.
 */
#include <fstream>
#include <float.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#endif
#include <string.h>
#include <stdio.h>
#include "parse_example.h"
#include "constant.h"
#include "sparse_dense.h"
#include "gd.h"
#include "cache.h"
#include "simple_label.h"
#include "rand48.h"
#include "vw.h"

using namespace std;

namespace GDMF {
void mf_local_predict(example* ec, regressor& reg);

float mf_inline_predict(vw& all, example* &ec)
{
  float prediction = 0.0;

  // clear stored predictions
  ec->topic_predictions.erase();

  float linear_prediction = 0;
  // linear terms
  for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
    GD::foreach_feature<vec_add>(all, &linear_prediction, ec->atomics[*i].begin, ec->atomics[*i].end);

  // store constant + linear prediction
  // note: constant is now automatically added
  ec->topic_predictions.push_back(linear_prediction);

  prediction += linear_prediction;

  // interaction terms
  for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
    {
      if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
	{
	  for (uint32_t k = 1; k <= all.rank; k++)
	    {
	      // x_l * l^k
	      // l^k is from index+1 to index+all.rank
	      //float x_dot_l = sd_offset_add(weights, mask, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k);
              float x_dot_l = 0;
	      GD::foreach_feature<vec_add>(all, &x_dot_l, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k);
	      // x_r * r^k
	      // r^k is from index+all.rank+1 to index+2*all.rank
	      //float x_dot_r = sd_offset_add(weights, mask, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank);
              float x_dot_r = 0;
	      GD::foreach_feature<vec_add>(all, &x_dot_r, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank);

	      prediction += x_dot_l * x_dot_r;

	      // store prediction from interaction terms
	      ec->topic_predictions.push_back(x_dot_l);
	      ec->topic_predictions.push_back(x_dot_r);
	    }
	}
    }

  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }

  // ec->topic_predictions has linear, x_dot_l_1, x_dot_r_1, x_dot_l_2, x_dot_r_2, ...

  return prediction;
}

void mf_inline_train(vw& all, example* &ec, float update)
{
      weight* weights = all.reg.weight_vector;
      size_t mask = all.reg.weight_mask;
      label_data* ld = (label_data*)ec->ld;

      // use final prediction to get update size
      // update = eta_t*(y-y_hat) where eta_t = eta/(3*t^p) * importance weight
      float eta_t = all.eta/pow(ec->example_t,all.power_t) / 3.f * ld->weight;
      update = all.loss->getUpdate(ec->final_prediction, ld->label, eta_t, 1.); //ec->total_sum_feat_sq);

      float regularization = eta_t * all.l2_lambda;

      // linear update
      for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
	sd_offset_update(weights, mask, ec->atomics[*i].begin, ec->atomics[*i].end, 0, update, regularization);

      // quadratic update
      for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
	{
	  if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
	    {

	      // update l^k weights
	      for (size_t k = 1; k <= all.rank; k++)
		{
		  // r^k \cdot x_r
		  float r_dot_x = ec->topic_predictions[2*k];
		  // l^k <- l^k + update * (r^k \cdot x_r) * x_l
		  sd_offset_update(weights, mask, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k, update*r_dot_x, regularization);
		}

	      // update r^k weights
	      for (size_t k = 1; k <= all.rank; k++)
		{
		  // l^k \cdot x_l
		  float l_dot_x = ec->topic_predictions[2*k-1];
		  // r^k <- r^k + update * (l^k \cdot x_l) * x_r
		  sd_offset_update(weights, mask, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank, update*l_dot_x, regularization);
		}

	    }
	}
  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }

}

void mf_print_offset_features(vw& all, example* &ec, size_t offset)
{
  weight* weights = all.reg.weight_vector;
  size_t mask = all.reg.weight_mask;
  for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
    if (ec->audit_features[*i].begin != ec->audit_features[*i].end)
      for (audit_data *f = ec->audit_features[*i].begin; f != ec->audit_features[*i].end; f++)
	{
	  cout << '\t' << f->space << '^' << f->feature << ':' << f->weight_index <<"(" << ((f->weight_index + offset) & mask)  << ")" << ':' << f->x;

	  cout << ':' << weights[(f->weight_index + offset) & mask];
	}
    else
      for (feature *f = ec->atomics[*i].begin; f != ec->atomics[*i].end; f++)
	{
	  size_t index = (f->weight_index + offset) & all.reg.weight_mask;

	  cout << "\tConstant:";
	  cout << (index/all.reg.stride & all.parse_mask) << ':' << f->x;
	  cout  << ':' << trunc_weight(weights[index], (float)all.sd->gravity) * (float)all.sd->contraction;
	}
  for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
    if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
      {
	/* print out nsk^feature:hash:value:weight:nsk^feature^:hash:value:weight:prod_weights */
	for (size_t k = 1; k <= all.rank; k++)
	  {
	    for (audit_data* f = ec->audit_features[(int)(*i)[0]].begin; f!= ec->audit_features[(int)(*i)[0]].end; f++)
	      for (audit_data* f2 = ec->audit_features[(int)(*i)[1]].begin; f2!= ec->audit_features[(int)(*i)[1]].end; f2++)
		{
		  cout << '\t' << f->space << k << '^' << f->feature << ':' << ((f->weight_index+k)&mask)
		       <<"(" << ((f->weight_index + offset +k) & mask)  << ")" << ':' << f->x;
		  cout << ':' << weights[(f->weight_index + offset + k) & mask];

		  cout << ':' << f2->space << k << '^' << f2->feature << ':' << ((f2->weight_index+k+all.rank)&mask)
		       <<"(" << ((f2->weight_index + offset +k+all.rank) & mask)  << ")" << ':' << f2->x;
		  cout << ':' << weights[(f2->weight_index + offset + k+all.rank) & mask];

		  cout << ':' <<  weights[(f->weight_index + offset + k) & mask] * weights[(f2->weight_index + offset + k + all.rank) & mask];
		}
	  }
      }
  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }
  cout << endl;
}

void mf_print_audit_features(vw& all, example* ec, size_t offset)
{
  print_result(all.stdout_fileno,ec->final_prediction,-1,ec->tag);
  mf_print_offset_features(all, ec, offset);
}

void mf_local_predict(vw& all, example* ec)
{
  label_data* ld = (label_data*)ec->ld;
  all.set_minmax(all.sd, ld->label);

  ec->final_prediction = GD::finalize_prediction(all, ec->partial_prediction);

  if (ld->label != FLT_MAX)
    {
      ec->loss = all.loss->getLoss(all.sd, ec->final_prediction, ld->label) * ld->weight;
    }

  if (all.audit)
    mf_print_audit_features(all, ec, 0);
}

float mf_predict(vw& all, example* ex)
{
  float prediction = mf_inline_predict(all, ex);

  ex->partial_prediction = prediction;
  mf_local_predict(all, ex);

  return ex->final_prediction;
}

  void save_load(void* d, io_buf& model_file, bool read, bool text)
{
  vw* all = (vw*)d;
  uint32_t length = 1 << all->num_bits;
  uint32_t stride = all->reg.stride;

  if(read)
    {
      initialize_regressor(*all);
      if(all->random_weights)
	for (size_t j = 0; j < all->reg.stride*length; j++)
	  all->reg.weight_vector[j] = (float) (0.1 * frand48());
    }

  if (model_file.files.size() > 0)
    {
      uint32_t i = 0;
      uint32_t text_len;
      char buff[512];
      size_t brw = 1;

      do
	{
	  brw = 0;
	  size_t K = all->rank*2+1;

	  text_len = sprintf(buff, "%d ", i);
	  brw += bin_text_read_write_fixed(model_file,(char *)&i, sizeof (i),
					   "", read,
					   buff, text_len, text);
	  if (brw != 0)
	    for (uint32_t k = 0; k < K; k++)
	      {
		uint32_t ndx = stride*i+k;

		weight* v = &(all->reg.weight_vector[ndx]);
		text_len = sprintf(buff, "%f ", *v);
		brw += bin_text_read_write_fixed(model_file,(char *)v, sizeof (*v),
						 "", read,
						 buff, text_len, text);

	      }
	  if (text)
	    brw += bin_text_read_write_fixed(model_file,buff,0,
					     "", read,
					     "\n",1,text);

	  if (!read)
	    i++;
	}
      while ((!read && i < length) || (read && brw >0));
    }
}

  void learn(void* d, example* ec)
  {
    vw* all = (vw*)d;
    if (ec->end_pass)
    {
      all->eta *= all->eta_decay_rate;
      if (all->save_per_pass)
        save_predictor(*all, all->final_regressor_name, all->current_pass);

      all->current_pass++;
    }

    if (!command_example(all, ec))
      {
	mf_predict(*all,ec);
	if (all->training && ((label_data*)(ec->ld))->label != FLT_MAX)
	  mf_inline_train(*all, ec, ec->eta_round);
      }
  }

  void finish(void* d)
  { }

  void drive(vw* all, void* d)
{
  example* ec = NULL;

  while ( true )
    {
      if ((ec = VW::get_example(all->p)) != NULL)//blocking operation.
	{
	  learn(d,ec);
	  return_simple_example(*all, ec);
	}
      else if (parser_done(all->p))
	return;
      else
	;//busywait when we have predicted on all examples but not yet trained on all.
    }
}

  learner setup(vw& all)
  {
    sl_t sl = {&all, save_load};
    learner l(&all,drive,learn,finish,sl);
    return l;
  }
}
<commit_msg>Use initial prediction for matrix factorization<commit_after>/*
Copyright (c) by respective owners including Yahoo!, Microsoft, and
individual contributors. All rights reserved.  Released under a BSD (revised)
license as described in the file LICENSE.
 */
#include <fstream>
#include <float.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <netdb.h>
#endif
#include <string.h>
#include <stdio.h>
#include "parse_example.h"
#include "constant.h"
#include "sparse_dense.h"
#include "gd.h"
#include "cache.h"
#include "simple_label.h"
#include "rand48.h"
#include "vw.h"

using namespace std;

namespace GDMF {
void mf_local_predict(example* ec, regressor& reg);

float mf_inline_predict(vw& all, example* &ec)
{
  float prediction = all.p->lp->get_initial(ec->ld);

  // clear stored predictions
  ec->topic_predictions.erase();

  float linear_prediction = 0;
  // linear terms
  for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
    GD::foreach_feature<vec_add>(all, &linear_prediction, ec->atomics[*i].begin, ec->atomics[*i].end);

  // store constant + linear prediction
  // note: constant is now automatically added
  ec->topic_predictions.push_back(linear_prediction);

  prediction += linear_prediction;

  // interaction terms
  for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
    {
      if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
	{
	  for (uint32_t k = 1; k <= all.rank; k++)
	    {
	      // x_l * l^k
	      // l^k is from index+1 to index+all.rank
	      //float x_dot_l = sd_offset_add(weights, mask, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k);
              float x_dot_l = 0;
	      GD::foreach_feature<vec_add>(all, &x_dot_l, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k);
	      // x_r * r^k
	      // r^k is from index+all.rank+1 to index+2*all.rank
	      //float x_dot_r = sd_offset_add(weights, mask, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank);
              float x_dot_r = 0;
	      GD::foreach_feature<vec_add>(all, &x_dot_r, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank);

	      prediction += x_dot_l * x_dot_r;

	      // store prediction from interaction terms
	      ec->topic_predictions.push_back(x_dot_l);
	      ec->topic_predictions.push_back(x_dot_r);
	    }
	}
    }

  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }

  // ec->topic_predictions has linear, x_dot_l_1, x_dot_r_1, x_dot_l_2, x_dot_r_2, ...

  return prediction;
}

void mf_inline_train(vw& all, example* &ec, float update)
{
      weight* weights = all.reg.weight_vector;
      size_t mask = all.reg.weight_mask;
      label_data* ld = (label_data*)ec->ld;

      // use final prediction to get update size
      // update = eta_t*(y-y_hat) where eta_t = eta/(3*t^p) * importance weight
      float eta_t = all.eta/pow(ec->example_t,all.power_t) / 3.f * ld->weight;
      update = all.loss->getUpdate(ec->final_prediction, ld->label, eta_t, 1.); //ec->total_sum_feat_sq);

      float regularization = eta_t * all.l2_lambda;

      // linear update
      for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
	sd_offset_update(weights, mask, ec->atomics[*i].begin, ec->atomics[*i].end, 0, update, regularization);

      // quadratic update
      for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
	{
	  if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
	    {

	      // update l^k weights
	      for (size_t k = 1; k <= all.rank; k++)
		{
		  // r^k \cdot x_r
		  float r_dot_x = ec->topic_predictions[2*k];
		  // l^k <- l^k + update * (r^k \cdot x_r) * x_l
		  sd_offset_update(weights, mask, ec->atomics[(int)(*i)[0]].begin, ec->atomics[(int)(*i)[0]].end, k, update*r_dot_x, regularization);
		}

	      // update r^k weights
	      for (size_t k = 1; k <= all.rank; k++)
		{
		  // l^k \cdot x_l
		  float l_dot_x = ec->topic_predictions[2*k-1];
		  // r^k <- r^k + update * (l^k \cdot x_l) * x_r
		  sd_offset_update(weights, mask, ec->atomics[(int)(*i)[1]].begin, ec->atomics[(int)(*i)[1]].end, k+all.rank, update*l_dot_x, regularization);
		}

	    }
	}
  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }

}

void mf_print_offset_features(vw& all, example* &ec, size_t offset)
{
  weight* weights = all.reg.weight_vector;
  size_t mask = all.reg.weight_mask;
  for (unsigned char* i = ec->indices.begin; i != ec->indices.end; i++)
    if (ec->audit_features[*i].begin != ec->audit_features[*i].end)
      for (audit_data *f = ec->audit_features[*i].begin; f != ec->audit_features[*i].end; f++)
	{
	  cout << '\t' << f->space << '^' << f->feature << ':' << f->weight_index <<"(" << ((f->weight_index + offset) & mask)  << ")" << ':' << f->x;

	  cout << ':' << weights[(f->weight_index + offset) & mask];
	}
    else
      for (feature *f = ec->atomics[*i].begin; f != ec->atomics[*i].end; f++)
	{
	  size_t index = (f->weight_index + offset) & all.reg.weight_mask;

	  cout << "\tConstant:";
	  cout << (index/all.reg.stride & all.parse_mask) << ':' << f->x;
	  cout  << ':' << trunc_weight(weights[index], (float)all.sd->gravity) * (float)all.sd->contraction;
	}
  for (vector<string>::iterator i = all.pairs.begin(); i != all.pairs.end();i++)
    if (ec->atomics[(int)(*i)[0]].size() > 0 && ec->atomics[(int)(*i)[1]].size() > 0)
      {
	/* print out nsk^feature:hash:value:weight:nsk^feature^:hash:value:weight:prod_weights */
	for (size_t k = 1; k <= all.rank; k++)
	  {
	    for (audit_data* f = ec->audit_features[(int)(*i)[0]].begin; f!= ec->audit_features[(int)(*i)[0]].end; f++)
	      for (audit_data* f2 = ec->audit_features[(int)(*i)[1]].begin; f2!= ec->audit_features[(int)(*i)[1]].end; f2++)
		{
		  cout << '\t' << f->space << k << '^' << f->feature << ':' << ((f->weight_index+k)&mask)
		       <<"(" << ((f->weight_index + offset +k) & mask)  << ")" << ':' << f->x;
		  cout << ':' << weights[(f->weight_index + offset + k) & mask];

		  cout << ':' << f2->space << k << '^' << f2->feature << ':' << ((f2->weight_index+k+all.rank)&mask)
		       <<"(" << ((f2->weight_index + offset +k+all.rank) & mask)  << ")" << ':' << f2->x;
		  cout << ':' << weights[(f2->weight_index + offset + k+all.rank) & mask];

		  cout << ':' <<  weights[(f->weight_index + offset + k) & mask] * weights[(f2->weight_index + offset + k + all.rank) & mask];
		}
	  }
      }
  if (all.triples.begin() != all.triples.end()) {
    cerr << "cannot use triples in matrix factorization" << endl;
    throw exception();
  }
  cout << endl;
}

void mf_print_audit_features(vw& all, example* ec, size_t offset)
{
  print_result(all.stdout_fileno,ec->final_prediction,-1,ec->tag);
  mf_print_offset_features(all, ec, offset);
}

void mf_local_predict(vw& all, example* ec)
{
  label_data* ld = (label_data*)ec->ld;
  all.set_minmax(all.sd, ld->label);

  ec->final_prediction = GD::finalize_prediction(all, ec->partial_prediction);

  if (ld->label != FLT_MAX)
    {
      ec->loss = all.loss->getLoss(all.sd, ec->final_prediction, ld->label) * ld->weight;
    }

  if (all.audit)
    mf_print_audit_features(all, ec, 0);
}

float mf_predict(vw& all, example* ex)
{
  float prediction = mf_inline_predict(all, ex);

  ex->partial_prediction = prediction;
  mf_local_predict(all, ex);

  return ex->final_prediction;
}

  void save_load(void* d, io_buf& model_file, bool read, bool text)
{
  vw* all = (vw*)d;
  uint32_t length = 1 << all->num_bits;
  uint32_t stride = all->reg.stride;

  if(read)
    {
      initialize_regressor(*all);
      if(all->random_weights)
	for (size_t j = 0; j < all->reg.stride*length; j++)
	  all->reg.weight_vector[j] = (float) (0.1 * frand48());
    }

  if (model_file.files.size() > 0)
    {
      uint32_t i = 0;
      uint32_t text_len;
      char buff[512];
      size_t brw = 1;

      do
	{
	  brw = 0;
	  size_t K = all->rank*2+1;

	  text_len = sprintf(buff, "%d ", i);
	  brw += bin_text_read_write_fixed(model_file,(char *)&i, sizeof (i),
					   "", read,
					   buff, text_len, text);
	  if (brw != 0)
	    for (uint32_t k = 0; k < K; k++)
	      {
		uint32_t ndx = stride*i+k;

		weight* v = &(all->reg.weight_vector[ndx]);
		text_len = sprintf(buff, "%f ", *v);
		brw += bin_text_read_write_fixed(model_file,(char *)v, sizeof (*v),
						 "", read,
						 buff, text_len, text);

	      }
	  if (text)
	    brw += bin_text_read_write_fixed(model_file,buff,0,
					     "", read,
					     "\n",1,text);

	  if (!read)
	    i++;
	}
      while ((!read && i < length) || (read && brw >0));
    }
}

  void learn(void* d, example* ec)
  {
    vw* all = (vw*)d;
    if (ec->end_pass)
    {
      all->eta *= all->eta_decay_rate;
      if (all->save_per_pass)
        save_predictor(*all, all->final_regressor_name, all->current_pass);

      all->current_pass++;
    }

    if (!command_example(all, ec))
      {
	mf_predict(*all,ec);
	if (all->training && ((label_data*)(ec->ld))->label != FLT_MAX)
	  mf_inline_train(*all, ec, ec->eta_round);
      }
  }

  void finish(void* d)
  { }

  void drive(vw* all, void* d)
{
  example* ec = NULL;

  while ( true )
    {
      if ((ec = VW::get_example(all->p)) != NULL)//blocking operation.
	{
	  learn(d,ec);
	  return_simple_example(*all, ec);
	}
      else if (parser_done(all->p))
	return;
      else
	;//busywait when we have predicted on all examples but not yet trained on all.
    }
}

  learner setup(vw& all)
  {
    sl_t sl = {&all, save_load};
    learner l(&all,drive,learn,finish,sl);
    return l;
  }
}
<|endoftext|>


<commit_before>/*
 * esteid-browser-plugin - a browser plugin for Estonian EID card
 *
 * Copyright (C) 2010  Estonian Informatics Centre
 * Copyright (C) 2010  Smartlink OÜ
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _WIN32
#include <stdlib.h>
#endif

#include <algorithm>
#include <fstream>
#include <boost/bind.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>

#include "PluginSettings.h"
#include "config.h"

using namespace boost::filesystem;

PluginSettings::PluginSettings() :
    allowLocal(true), allowDefaults(true)
{
    static const std::string fileName = "esteidplugin.conf";

    m_configFile = configDirectory() / fileName;
    Load();

    /* Builtin whitelist */
    default_whitelist.clear();
    default_whitelist.push_back("id.swedbank.ee");
    default_whitelist.push_back("id.seb.ee");
    default_whitelist.push_back("id.eesti.ee");
}

path PluginSettings::configDirectory()
{
#ifdef _WIN32
    return path(getenv("APPDATA"), native);
#else // UNIX
    path home(getenv("HOME"), native);
# ifdef __APPLE__
    return home / "Library/Application Support";
# else
    return home / ".config";
# endif
#endif
}

PluginSettings::~PluginSettings() {
}

void PluginSettings::Load() {
    std::string line;
    ifstream input;

    whitelist.clear();

    input.open(m_configFile);
    while(input.good()) {
        std::getline(input, line);
        if(line.empty()) continue;

             if(line == "@NODEFAULTS") allowDefaults = false;
        else if(line == "@NOLOCAL")    allowLocal    = false;
        else whitelist.push_back(line);
    }
    input.close();
}

void PluginSettings::Save() {
    std::vector<std::string>::const_iterator i;

    removeDuplicateEntries(whitelist);
    removeDefaultEntries(whitelist);

    ofstream output;
    output.exceptions( std::ofstream::failbit | std::ofstream::badbit );

    path configDir = configDirectory();
    if (!exists(configDir))
        create_directory(configDir);

    output.open(m_configFile);
    if(!allowDefaults) output << "@NODEFAULTS" << std::endl;
    if(!allowLocal)    output << "@NOLOCAL"    << std::endl;
    for(i = whitelist.begin(); i != whitelist.end(); ++i)
        output << *i << std::endl;
    output.close();
}

bool PluginSettings::InWhitelist(std::string s) {
    return (allowDefaults && \
            default_whitelist.end() != find(default_whitelist.begin(), default_whitelist.end(), s)) || \
            whitelist.end() != find(whitelist.begin(), whitelist.end(), s);
}

void PluginSettings::removeDuplicateEntries(std::vector<std::string>& v)
{
    std::sort(v.begin(), v.end());
    v.erase(std::unique(v.begin(), v.end()), v.end());
}

// remove all entries which are also in default whitelist
void PluginSettings::removeDefaultEntries(std::vector<std::string>& v)
{
    v.erase(remove_if(v.begin(), v.end(), boost::bind(&PluginSettings::inDefaultWhitelist, this, _1)), v.end());
}

// predicate for removeDefaultEntries
bool PluginSettings::inDefaultWhitelist(const std::string& s)
{
    return find(default_whitelist.begin(), default_whitelist.end(), s) != default_whitelist.end();
}
<commit_msg>esteid-browser-plugin: Add a few more known sites to default whitelist.<commit_after>/*
 * esteid-browser-plugin - a browser plugin for Estonian EID card
 *
 * Copyright (C) 2010  Estonian Informatics Centre
 * Copyright (C) 2010  Smartlink OÜ
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _WIN32
#include <stdlib.h>
#endif

#include <algorithm>
#include <fstream>
#include <boost/bind.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>

#include "PluginSettings.h"
#include "config.h"

using namespace boost::filesystem;

PluginSettings::PluginSettings() :
    allowLocal(true), allowDefaults(true)
{
    static const std::string fileName = "esteidplugin.conf";

    m_configFile = configDirectory() / fileName;
    Load();

    /* Builtin whitelist */
    default_whitelist.clear();
    default_whitelist.push_back("id.swedbank.ee");
    default_whitelist.push_back("id.business.swedbank.ee");
    default_whitelist.push_back("id.seb.ee");
    default_whitelist.push_back("id.eesti.ee");
    default_whitelist.push_back("digidoc.sk.ee");
    default_whitelist.push_back("xbrl.rik.ee");
}

path PluginSettings::configDirectory()
{
#ifdef _WIN32
    return path(getenv("APPDATA"), native);
#else // UNIX
    path home(getenv("HOME"), native);
# ifdef __APPLE__
    return home / "Library/Application Support";
# else
    return home / ".config";
# endif
#endif
}

PluginSettings::~PluginSettings() {
}

void PluginSettings::Load() {
    std::string line;
    ifstream input;

    whitelist.clear();

    input.open(m_configFile);
    while(input.good()) {
        std::getline(input, line);
        if(line.empty()) continue;

             if(line == "@NODEFAULTS") allowDefaults = false;
        else if(line == "@NOLOCAL")    allowLocal    = false;
        else whitelist.push_back(line);
    }
    input.close();
}

void PluginSettings::Save() {
    std::vector<std::string>::const_iterator i;

    removeDuplicateEntries(whitelist);
    removeDefaultEntries(whitelist);

    ofstream output;
    output.exceptions( std::ofstream::failbit | std::ofstream::badbit );

    path configDir = configDirectory();
    if (!exists(configDir))
        create_directory(configDir);

    output.open(m_configFile);
    if(!allowDefaults) output << "@NODEFAULTS" << std::endl;
    if(!allowLocal)    output << "@NOLOCAL"    << std::endl;
    for(i = whitelist.begin(); i != whitelist.end(); ++i)
        output << *i << std::endl;
    output.close();
}

bool PluginSettings::InWhitelist(std::string s) {
    return (allowDefaults && \
            default_whitelist.end() != find(default_whitelist.begin(), default_whitelist.end(), s)) || \
            whitelist.end() != find(whitelist.begin(), whitelist.end(), s);
}

void PluginSettings::removeDuplicateEntries(std::vector<std::string>& v)
{
    std::sort(v.begin(), v.end());
    v.erase(std::unique(v.begin(), v.end()), v.end());
}

// remove all entries which are also in default whitelist
void PluginSettings::removeDefaultEntries(std::vector<std::string>& v)
{
    v.erase(remove_if(v.begin(), v.end(), boost::bind(&PluginSettings::inDefaultWhitelist, this, _1)), v.end());
}

// predicate for removeDefaultEntries
bool PluginSettings::inDefaultWhitelist(const std::string& s)
{
    return find(default_whitelist.begin(), default_whitelist.end(), s) != default_whitelist.end();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "oat.h"
#include "utils.h"

#include <zlib.h>

namespace art {

const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
const uint8_t OatHeader::kOatVersion[] = { '0', '1', '0', '\0' };

OatHeader::OatHeader() {
  memset(this, 0, sizeof(*this));
}

OatHeader::OatHeader(InstructionSet instruction_set,
                     const InstructionSetFeatures& instruction_set_features,
                     const std::vector<const DexFile*>* dex_files,
                     uint32_t image_file_location_oat_checksum,
                     uint32_t image_file_location_oat_data_begin,
                     const std::string& image_file_location) {
  memcpy(magic_, kOatMagic, sizeof(kOatMagic));
  memcpy(version_, kOatVersion, sizeof(kOatVersion));

  adler32_checksum_ = adler32(0L, Z_NULL, 0);

  CHECK_NE(instruction_set, kNone);
  instruction_set_ = instruction_set;
  UpdateChecksum(&instruction_set_, sizeof(instruction_set_));

  instruction_set_features_ = instruction_set_features;
  UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));

  dex_file_count_ = dex_files->size();
  UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));

  image_file_location_oat_checksum_ = image_file_location_oat_checksum;
  UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));

  CHECK(IsAligned<kPageSize>(image_file_location_oat_data_begin));
  image_file_location_oat_data_begin_ = image_file_location_oat_data_begin;
  UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_));

  image_file_location_size_ = image_file_location.size();
  UpdateChecksum(&image_file_location_size_, sizeof(image_file_location_size_));
  UpdateChecksum(image_file_location.data(), image_file_location_size_);

  executable_offset_ = 0;
  interpreter_to_interpreter_bridge_offset_ = 0;
  interpreter_to_compiled_code_bridge_offset_ = 0;
  jni_dlsym_lookup_offset_ = 0;
  portable_imt_conflict_trampoline_offset_ = 0;
  portable_resolution_trampoline_offset_ = 0;
  portable_to_interpreter_bridge_offset_ = 0;
  quick_imt_conflict_trampoline_offset_ = 0;
  quick_resolution_trampoline_offset_ = 0;
  quick_to_interpreter_bridge_offset_ = 0;
}

bool OatHeader::IsValid() const {
  if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
    return false;
  }
  if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
    return false;
  }
  return true;
}

const char* OatHeader::GetMagic() const {
  CHECK(IsValid());
  return reinterpret_cast<const char*>(magic_);
}

uint32_t OatHeader::GetChecksum() const {
  CHECK(IsValid());
  return adler32_checksum_;
}

void OatHeader::UpdateChecksum(const void* data, size_t length) {
  DCHECK(IsValid());
  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
  adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
}

InstructionSet OatHeader::GetInstructionSet() const {
  CHECK(IsValid());
  return instruction_set_;
}

const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
  CHECK(IsValid());
  return instruction_set_features_;
}

uint32_t OatHeader::GetExecutableOffset() const {
  DCHECK(IsValid());
  DCHECK_ALIGNED(executable_offset_, kPageSize);
  CHECK_GT(executable_offset_, sizeof(OatHeader));
  return executable_offset_;
}

void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
  DCHECK_ALIGNED(executable_offset, kPageSize);
  CHECK_GT(executable_offset, sizeof(OatHeader));
  DCHECK(IsValid());
  DCHECK_EQ(executable_offset_, 0U);

  executable_offset_ = executable_offset;
  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
}

const void* OatHeader::GetInterpreterToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetInterpreterToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(interpreter_to_interpreter_bridge_offset_, executable_offset_);
  return interpreter_to_interpreter_bridge_offset_;
}

void OatHeader::SetInterpreterToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= executable_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(interpreter_to_interpreter_bridge_offset_, 0U) << offset;

  interpreter_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&interpreter_to_interpreter_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetInterpreterToCompiledCodeBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToCompiledCodeBridgeOffset();
}

uint32_t OatHeader::GetInterpreterToCompiledCodeBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(interpreter_to_compiled_code_bridge_offset_, interpreter_to_interpreter_bridge_offset_);
  return interpreter_to_compiled_code_bridge_offset_;
}

void OatHeader::SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= interpreter_to_interpreter_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(interpreter_to_compiled_code_bridge_offset_, 0U) << offset;

  interpreter_to_compiled_code_bridge_offset_ = offset;
  UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetJniDlsymLookup() const {
  return reinterpret_cast<const uint8_t*>(this) + GetJniDlsymLookupOffset();
}

uint32_t OatHeader::GetJniDlsymLookupOffset() const {
  DCHECK(IsValid());
  CHECK_GE(jni_dlsym_lookup_offset_, interpreter_to_compiled_code_bridge_offset_);
  return jni_dlsym_lookup_offset_;
}

void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= interpreter_to_compiled_code_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset;

  jni_dlsym_lookup_offset_ = offset;
  UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableImtConflictTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset();
}

uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_);
  return portable_imt_conflict_trampoline_offset_;
}

void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset;

  portable_imt_conflict_trampoline_offset_ = offset;
  UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableResolutionTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
}

uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_);
  return portable_resolution_trampoline_offset_;
}

void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;

  portable_resolution_trampoline_offset_ = offset;
  UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetPortableToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_to_interpreter_bridge_offset_, portable_resolution_trampoline_offset_);
  return portable_to_interpreter_bridge_offset_;
}

void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_to_interpreter_bridge_offset_, 0U) << offset;

  portable_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickImtConflictTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
}

uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_);
  return quick_imt_conflict_trampoline_offset_;
}

void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;

  quick_imt_conflict_trampoline_offset_ = offset;
  UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickResolutionTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
}

uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
  return quick_resolution_trampoline_offset_;
}

void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;

  quick_resolution_trampoline_offset_ = offset;
  UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
  return quick_to_interpreter_bridge_offset_;
}

void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;

  quick_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&quick_to_interpreter_bridge_offset_, sizeof(offset));
}

uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
  CHECK(IsValid());
  return image_file_location_oat_checksum_;
}

uint32_t OatHeader::GetImageFileLocationOatDataBegin() const {
  CHECK(IsValid());
  return image_file_location_oat_data_begin_;
}

uint32_t OatHeader::GetImageFileLocationSize() const {
  CHECK(IsValid());
  return image_file_location_size_;
}

const uint8_t* OatHeader::GetImageFileLocationData() const {
  CHECK(IsValid());
  return image_file_location_data_;
}

std::string OatHeader::GetImageFileLocation() const {
  CHECK(IsValid());
  return std::string(reinterpret_cast<const char*>(GetImageFileLocationData()),
                     GetImageFileLocationSize());
}

OatMethodOffsets::OatMethodOffsets()
  : code_offset_(0),
    frame_size_in_bytes_(0),
    core_spill_mask_(0),
    fp_spill_mask_(0),
    mapping_table_offset_(0),
    vmap_table_offset_(0),
    gc_map_offset_(0)
{}

OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
                                   uint32_t frame_size_in_bytes,
                                   uint32_t core_spill_mask,
                                   uint32_t fp_spill_mask,
                                   uint32_t mapping_table_offset,
                                   uint32_t vmap_table_offset,
                                   uint32_t gc_map_offset
                                   )
  : code_offset_(code_offset),
    frame_size_in_bytes_(frame_size_in_bytes),
    core_spill_mask_(core_spill_mask),
    fp_spill_mask_(fp_spill_mask),
    mapping_table_offset_(mapping_table_offset),
    vmap_table_offset_(vmap_table_offset),
    gc_map_offset_(gc_map_offset)
{}

OatMethodOffsets::~OatMethodOffsets() {}

}  // namespace art
<commit_msg>am 5da37787: Turn up oat version to 11<commit_after>/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * 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 "oat.h"
#include "utils.h"

#include <zlib.h>

namespace art {

const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
const uint8_t OatHeader::kOatVersion[] = { '0', '1', '1', '\0' };

OatHeader::OatHeader() {
  memset(this, 0, sizeof(*this));
}

OatHeader::OatHeader(InstructionSet instruction_set,
                     const InstructionSetFeatures& instruction_set_features,
                     const std::vector<const DexFile*>* dex_files,
                     uint32_t image_file_location_oat_checksum,
                     uint32_t image_file_location_oat_data_begin,
                     const std::string& image_file_location) {
  memcpy(magic_, kOatMagic, sizeof(kOatMagic));
  memcpy(version_, kOatVersion, sizeof(kOatVersion));

  adler32_checksum_ = adler32(0L, Z_NULL, 0);

  CHECK_NE(instruction_set, kNone);
  instruction_set_ = instruction_set;
  UpdateChecksum(&instruction_set_, sizeof(instruction_set_));

  instruction_set_features_ = instruction_set_features;
  UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_));

  dex_file_count_ = dex_files->size();
  UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_));

  image_file_location_oat_checksum_ = image_file_location_oat_checksum;
  UpdateChecksum(&image_file_location_oat_checksum_, sizeof(image_file_location_oat_checksum_));

  CHECK(IsAligned<kPageSize>(image_file_location_oat_data_begin));
  image_file_location_oat_data_begin_ = image_file_location_oat_data_begin;
  UpdateChecksum(&image_file_location_oat_data_begin_, sizeof(image_file_location_oat_data_begin_));

  image_file_location_size_ = image_file_location.size();
  UpdateChecksum(&image_file_location_size_, sizeof(image_file_location_size_));
  UpdateChecksum(image_file_location.data(), image_file_location_size_);

  executable_offset_ = 0;
  interpreter_to_interpreter_bridge_offset_ = 0;
  interpreter_to_compiled_code_bridge_offset_ = 0;
  jni_dlsym_lookup_offset_ = 0;
  portable_imt_conflict_trampoline_offset_ = 0;
  portable_resolution_trampoline_offset_ = 0;
  portable_to_interpreter_bridge_offset_ = 0;
  quick_imt_conflict_trampoline_offset_ = 0;
  quick_resolution_trampoline_offset_ = 0;
  quick_to_interpreter_bridge_offset_ = 0;
}

bool OatHeader::IsValid() const {
  if (memcmp(magic_, kOatMagic, sizeof(kOatMagic)) != 0) {
    return false;
  }
  if (memcmp(version_, kOatVersion, sizeof(kOatVersion)) != 0) {
    return false;
  }
  return true;
}

const char* OatHeader::GetMagic() const {
  CHECK(IsValid());
  return reinterpret_cast<const char*>(magic_);
}

uint32_t OatHeader::GetChecksum() const {
  CHECK(IsValid());
  return adler32_checksum_;
}

void OatHeader::UpdateChecksum(const void* data, size_t length) {
  DCHECK(IsValid());
  const uint8_t* bytes = reinterpret_cast<const uint8_t*>(data);
  adler32_checksum_ = adler32(adler32_checksum_, bytes, length);
}

InstructionSet OatHeader::GetInstructionSet() const {
  CHECK(IsValid());
  return instruction_set_;
}

const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const {
  CHECK(IsValid());
  return instruction_set_features_;
}

uint32_t OatHeader::GetExecutableOffset() const {
  DCHECK(IsValid());
  DCHECK_ALIGNED(executable_offset_, kPageSize);
  CHECK_GT(executable_offset_, sizeof(OatHeader));
  return executable_offset_;
}

void OatHeader::SetExecutableOffset(uint32_t executable_offset) {
  DCHECK_ALIGNED(executable_offset, kPageSize);
  CHECK_GT(executable_offset, sizeof(OatHeader));
  DCHECK(IsValid());
  DCHECK_EQ(executable_offset_, 0U);

  executable_offset_ = executable_offset;
  UpdateChecksum(&executable_offset_, sizeof(executable_offset));
}

const void* OatHeader::GetInterpreterToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetInterpreterToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(interpreter_to_interpreter_bridge_offset_, executable_offset_);
  return interpreter_to_interpreter_bridge_offset_;
}

void OatHeader::SetInterpreterToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= executable_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(interpreter_to_interpreter_bridge_offset_, 0U) << offset;

  interpreter_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&interpreter_to_interpreter_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetInterpreterToCompiledCodeBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetInterpreterToCompiledCodeBridgeOffset();
}

uint32_t OatHeader::GetInterpreterToCompiledCodeBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(interpreter_to_compiled_code_bridge_offset_, interpreter_to_interpreter_bridge_offset_);
  return interpreter_to_compiled_code_bridge_offset_;
}

void OatHeader::SetInterpreterToCompiledCodeBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= interpreter_to_interpreter_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(interpreter_to_compiled_code_bridge_offset_, 0U) << offset;

  interpreter_to_compiled_code_bridge_offset_ = offset;
  UpdateChecksum(&interpreter_to_compiled_code_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetJniDlsymLookup() const {
  return reinterpret_cast<const uint8_t*>(this) + GetJniDlsymLookupOffset();
}

uint32_t OatHeader::GetJniDlsymLookupOffset() const {
  DCHECK(IsValid());
  CHECK_GE(jni_dlsym_lookup_offset_, interpreter_to_compiled_code_bridge_offset_);
  return jni_dlsym_lookup_offset_;
}

void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= interpreter_to_compiled_code_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(jni_dlsym_lookup_offset_, 0U) << offset;

  jni_dlsym_lookup_offset_ = offset;
  UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableImtConflictTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableImtConflictTrampolineOffset();
}

uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_);
  return portable_imt_conflict_trampoline_offset_;
}

void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset;

  portable_imt_conflict_trampoline_offset_ = offset;
  UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableResolutionTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableResolutionTrampolineOffset();
}

uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_);
  return portable_resolution_trampoline_offset_;
}

void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset;

  portable_resolution_trampoline_offset_ = offset;
  UpdateChecksum(&portable_resolution_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetPortableToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetPortableToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetPortableToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(portable_to_interpreter_bridge_offset_, portable_resolution_trampoline_offset_);
  return portable_to_interpreter_bridge_offset_;
}

void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_resolution_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(portable_to_interpreter_bridge_offset_, 0U) << offset;

  portable_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickImtConflictTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickImtConflictTrampolineOffset();
}

uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_);
  return quick_imt_conflict_trampoline_offset_;
}

void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset;

  quick_imt_conflict_trampoline_offset_ = offset;
  UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickResolutionTrampoline() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickResolutionTrampolineOffset();
}

uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_);
  return quick_resolution_trampoline_offset_;
}

void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset;

  quick_resolution_trampoline_offset_ = offset;
  UpdateChecksum(&quick_resolution_trampoline_offset_, sizeof(offset));
}

const void* OatHeader::GetQuickToInterpreterBridge() const {
  return reinterpret_cast<const uint8_t*>(this) + GetQuickToInterpreterBridgeOffset();
}

uint32_t OatHeader::GetQuickToInterpreterBridgeOffset() const {
  DCHECK(IsValid());
  CHECK_GE(quick_to_interpreter_bridge_offset_, quick_resolution_trampoline_offset_);
  return quick_to_interpreter_bridge_offset_;
}

void OatHeader::SetQuickToInterpreterBridgeOffset(uint32_t offset) {
  CHECK(offset == 0 || offset >= quick_resolution_trampoline_offset_);
  DCHECK(IsValid());
  DCHECK_EQ(quick_to_interpreter_bridge_offset_, 0U) << offset;

  quick_to_interpreter_bridge_offset_ = offset;
  UpdateChecksum(&quick_to_interpreter_bridge_offset_, sizeof(offset));
}

uint32_t OatHeader::GetImageFileLocationOatChecksum() const {
  CHECK(IsValid());
  return image_file_location_oat_checksum_;
}

uint32_t OatHeader::GetImageFileLocationOatDataBegin() const {
  CHECK(IsValid());
  return image_file_location_oat_data_begin_;
}

uint32_t OatHeader::GetImageFileLocationSize() const {
  CHECK(IsValid());
  return image_file_location_size_;
}

const uint8_t* OatHeader::GetImageFileLocationData() const {
  CHECK(IsValid());
  return image_file_location_data_;
}

std::string OatHeader::GetImageFileLocation() const {
  CHECK(IsValid());
  return std::string(reinterpret_cast<const char*>(GetImageFileLocationData()),
                     GetImageFileLocationSize());
}

OatMethodOffsets::OatMethodOffsets()
  : code_offset_(0),
    frame_size_in_bytes_(0),
    core_spill_mask_(0),
    fp_spill_mask_(0),
    mapping_table_offset_(0),
    vmap_table_offset_(0),
    gc_map_offset_(0)
{}

OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
                                   uint32_t frame_size_in_bytes,
                                   uint32_t core_spill_mask,
                                   uint32_t fp_spill_mask,
                                   uint32_t mapping_table_offset,
                                   uint32_t vmap_table_offset,
                                   uint32_t gc_map_offset
                                   )
  : code_offset_(code_offset),
    frame_size_in_bytes_(frame_size_in_bytes),
    core_spill_mask_(core_spill_mask),
    fp_spill_mask_(fp_spill_mask),
    mapping_table_offset_(mapping_table_offset),
    vmap_table_offset_(vmap_table_offset),
    gc_map_offset_(gc_map_offset)
{}

OatMethodOffsets::~OatMethodOffsets() {}

}  // namespace art
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
    @brief  RX65N SIDE
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"
#include "common/spi_io2.hpp"
#include "common/sdc_man.hpp"
#include "common/tpu_io.hpp"
#include "sound/sound_out.hpp"

#include "chip/FAMIPAD.hpp"

#include "spinv.hpp"

namespace {

	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
// オーディオの D/A として使用
//	typedef device::PORT<device::PORT0, device::bitpos::B5> SW2;

	// Famicon PAD (CMOS 4021B Shift Register)
	// 電源は、微小なので、接続を簡単に行う為、ポートを使う
	typedef device::PORT<device::PORT6, device::bitpos::B0> PAD_VCC;
	typedef device::PORT<device::PORT6, device::bitpos::B1> PAD_GND;
	typedef device::PORT<device::PORT6, device::bitpos::B2> PAD_P_S;
	typedef device::PORT<device::PORT6, device::bitpos::B5> PAD_CLK;
	typedef device::PORT<device::PORT7, device::bitpos::B3> PAD_OUT;
	typedef chip::FAMIPAD<PAD_P_S, PAD_CLK, PAD_OUT> FAMIPAD;
	FAMIPAD		famipad_;

	typedef device::system_io<12000000> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512>  RECV_BUFF;
	typedef utils::fixed_fifo<char, 1024> SEND_BUFF;
	typedef device::sci_io<device::SCI9, RECV_BUFF, SEND_BUFF> SCI;
	SCI		sci_;

	typedef device::PORT<device::PORT6, device::bitpos::B3> LCD_DISP;
	typedef device::PORT<device::PORT6, device::bitpos::B6> LCD_LIGHT;
	typedef device::glcdc_io<device::GLCDC, 480, 272,
		device::glcdc_def::PIX_TYPE::RGB565> GLCDC_IO;
	GLCDC_IO	glcdc_io_;

	// カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
//	typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
	typedef device::NULL_PORT SDC_POWER;

#ifdef SDHI_IF
	// RX65N Envision Kit の SDHI ポートは、候補３になっている
	typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, device::port_map::option::THIRD> SDHI;
	SDHI	sdh_;
#else
	// Soft SDC 用　SPI 定義（SPI）
	typedef device::PORT<device::PORT2, device::bitpos::B2> MISO;  // DAT0
	typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI;  // CMD
	typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK;  // CLK

	typedef device::spi_io2<MISO, MOSI, SPCK> SPI;  ///< Soft SPI 定義

	SPI		spi_;

	typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT;  // DAT3 カード選択信号
	typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT;  // CD   カード検出

	typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC;   // ハードウェアー定義

	MMC		sdh_(spi_, 20000000);
#endif
	typedef utils::sdc_man SDC;
	SDC		sdc_;

	volatile uint32_t	wpos_;

	/// DMAC 終了割り込み
	class dmac_term_task {
	public:
		void operator() () {
			device::DMAC0::DMCNT.DTE = 1;  // DMA を再スタート
			wpos_ = 0;
		}
	};

	typedef device::dmac_mgr<device::DMAC0, dmac_term_task> DMAC_MGR;
	DMAC_MGR	dmac_mgr_;

	uint32_t get_wave_pos_() { return (dmac_mgr_.get_count() & 0x3ff) ^ 0x3ff; }

	typedef device::R12DA DAC;
	typedef device::dac_out<DAC> DAC_OUT;
	DAC_OUT		dac_out_;

	typedef utils::sound_out<1024, 256> SOUND_OUT;
	SOUND_OUT	sound_out_;

	class tpu_task {
	public:
		void operator() () {
			uint32_t tmp = wpos_;
			++wpos_;
			if((tmp ^ wpos_) & 64) {
				sound_out_.service(64);
			}
		}
	};

	typedef device::tpu_io<device::TPU0, tpu_task> TPU0;
	TPU0		tpu0_;

	typedef emu::spinv SPINV;
	SPINV		spinv_;

	utils::command<256> cmd_;

	bool check_mount_() {
		auto f = sdc_.get_mount();
		if(!f) {
			utils::format("SD card not mount.\n");
		}
		return f;
	}

	void command_()
	{
		if(!cmd_.service()) {
			return;
		}

		uint8_t cmdn = cmd_.get_words();
		if(cmdn >= 1) {
			bool f = false;
			if(cmd_.cmp_word(0, "dir")) {  // dir [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, sizeof(tmp), tmp);
						sdc_.dir(tmp);
					} else {
						sdc_.dir("");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, sizeof(tmp), tmp);
						sdc_.cd(tmp);
					} else {
						sdc_.cd("/");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "pwd")) { // pwd
				utils::format("%s\n") % sdc_.get_current();
				f = true;
			} else if(cmd_.cmp_word(0, "help")) {
				utils::format("    dir [path]\n");
				utils::format("    cd [path]\n");
				utils::format("    pwd\n");
				f = true;
			}
			if(!f) {
				char tmp[128];
				if(cmd_.get_word(0, sizeof(tmp), tmp)) {
					utils::format("Command error: '%s'\n") % tmp;
				}
			}
		}
	}
}

extern "C" {

	uint8_t get_fami_pad()
	{
		return famipad_.update();
	}

	void set_sample_rate(uint32_t freq)
	{
		uint8_t intr_level = 5;
		if(!tpu0_.start(freq, intr_level)) {
			utils::format("TPU0 start error...\n");
		}
	}

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

	DSTATUS disk_initialize(BYTE drv) {
		return sdh_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdh_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdh_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		time_t t = 0;
///		rtc_.get_time(t);
		return utils::str::get_fattime(t);
	}

	void utf8_to_sjis(const char* src, char* dst, uint32_t len) {
		utils::str::utf8_to_sjis(src, dst, len);
	}

	int fatfs_get_mount() {
		return sdc_.get_mount();
	}

	int make_full_path(const char* src, char* dst, uint16_t len)
	{
		return sdc_.make_full_path(src, dst, len);
	}
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // 内臓１２ビット D/A の設定
		bool amp_ena = true;
		dac_out_.start(DAC_OUT::output::CH0_CH1, amp_ena);
		dac_out_.out0(0x8000);
		dac_out_.out1(0x8000);
	}

	{  // SCI 設定
		static const uint8_t sci_level = 2;
		sci_.start(115200, sci_level);
	}

	{  // SD カード・クラスの初期化
		sdh_.start();
		sdc_.start();
	}

	// 波形メモリーの無音状態初期化
	sound_out_.mute();

	{  // サンプリング・タイマー設定
		set_sample_rate(11127);
	}

	{  // DMAC マネージャー開始
		uint8_t intr_level = 4;
		auto ret = dmac_mgr_.start(tpu0_.get_intr_vec(), DMAC_MGR::trans_type::SP_DN_32,
			reinterpret_cast<uint32_t>(sound_out_.get_wave()), DAC::DADR0.address(),
			sound_out_.size(), intr_level);
		if(!ret) {
			utils::format("DMAC Not start...\n");
		}
	}

	utils::format("\rRTK5RX65N Start for Space Invaders\n");

	cmd_.set_prompt("# ");

	{  // GLCDC 初期化
		LCD_DISP::DIR  = 1;
		LCD_LIGHT::DIR = 1;
		LCD_DISP::P  = 0;  // DISP Disable
		LCD_LIGHT::P = 0;  // BackLight Disable (No PWM)
		if(glcdc_io_.start()) {
			utils::format("Start GLCDC\n");
			LCD_DISP::P  = 1;  // DISP Enable
			LCD_LIGHT::P = 1;  // BackLight Enable (No PWM)
			if(!glcdc_io_.control(GLCDC_IO::CONTROL_CMD::START_DISPLAY)) {
				utils::format("GLCDC ctrl fail...\n");
			}
		} else {
			utils::format("Fail GLCDC\n");
		}
	}

	LED::DIR = 1;

	{
		PAD_VCC::DIR = 1;
		PAD_VCC::P = 1;
		PAD_GND::DIR = 1;
		PAD_GND::P = 0;
		famipad_.start();
	}

	uint32_t delay_inv = 120;
	uint8_t n = 0;
	while(1) {
		glcdc_io_.sync_vpos();

		if(delay_inv > 0) {
			--delay_inv;
			if(delay_inv == 0) {
				if(sdc_.get_mount()) {
					if(spinv_.start("/inv_roms", "/inv_wavs")) {
						utils::format("Space Invaders start...\n");
					} else {
						utils::format("Space Invaders not start...(fail)\n");
					}
				} else {
					delay_inv = 60;
					utils::format("SD card not mount\n");
				}
			}
		} else {
			spinv_.service((void*)0x00000000, glcdc_io_.get_xsize(), glcdc_io_.get_ysize());

			SPINV::SND_MGR& snd = spinv_.at_sound();
			uint32_t len = snd.get_length();
			const int16_t* wav = snd.get_buffer();
			for(uint32_t i = 0; i < len; ++i) {
				while((sound_out_.at_fifo().size() - sound_out_.at_fifo().length()) < 8) {
				}
				sound::wave_t t;
				t.l_ch = t.r_ch = *wav++;
				sound_out_.at_fifo().put(t);
			}
		}

		sdc_.service(sdh_.service());

		command_();

		++n;
		if(n >= 30) {
			n = 0;
		}
		if(n < 10) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<commit_msg>update: command class API<commit_after>//=====================================================================//
/*! @file
    @brief  RX65N SIDE
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2018 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include "common/renesas.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"
#include "common/format.hpp"
#include "common/command.hpp"
#include "common/spi_io2.hpp"
#include "common/sdc_man.hpp"
#include "common/tpu_io.hpp"
#include "sound/sound_out.hpp"

#include "chip/FAMIPAD.hpp"

#include "spinv.hpp"

namespace {

	typedef device::PORT<device::PORT7, device::bitpos::B0> LED;
// オーディオの D/A として使用
//	typedef device::PORT<device::PORT0, device::bitpos::B5> SW2;

	// Famicon PAD (CMOS 4021B Shift Register)
	// 電源は、微小なので、接続を簡単に行う為、ポートを使う
	typedef device::PORT<device::PORT6, device::bitpos::B0> PAD_VCC;
	typedef device::PORT<device::PORT6, device::bitpos::B1> PAD_GND;
	typedef device::PORT<device::PORT6, device::bitpos::B2> PAD_P_S;
	typedef device::PORT<device::PORT6, device::bitpos::B5> PAD_CLK;
	typedef device::PORT<device::PORT7, device::bitpos::B3> PAD_OUT;
	typedef chip::FAMIPAD<PAD_P_S, PAD_CLK, PAD_OUT> FAMIPAD;
	FAMIPAD		famipad_;

	typedef device::system_io<12000000> SYSTEM_IO;

	typedef utils::fixed_fifo<char, 512>  RECV_BUFF;
	typedef utils::fixed_fifo<char, 1024> SEND_BUFF;
	typedef device::sci_io<device::SCI9, RECV_BUFF, SEND_BUFF> SCI;
	SCI		sci_;

	typedef device::PORT<device::PORT6, device::bitpos::B3> LCD_DISP;
	typedef device::PORT<device::PORT6, device::bitpos::B6> LCD_LIGHT;
	typedef device::glcdc_io<device::GLCDC, 480, 272,
		device::glcdc_def::PIX_TYPE::RGB565> GLCDC_IO;
	GLCDC_IO	glcdc_io_;

	// カード電源制御は使わない場合、「device::NULL_PORT」を指定する。
//	typedef device::PORT<device::PORT6, device::bitpos::B4> SDC_POWER;
	typedef device::NULL_PORT SDC_POWER;

#ifdef SDHI_IF
	// RX65N Envision Kit の SDHI ポートは、候補３になっている
	typedef fatfs::sdhi_io<device::SDHI, SDC_POWER, device::port_map::option::THIRD> SDHI;
	SDHI	sdh_;
#else
	// Soft SDC 用　SPI 定義（SPI）
	typedef device::PORT<device::PORT2, device::bitpos::B2> MISO;  // DAT0
	typedef device::PORT<device::PORT2, device::bitpos::B0> MOSI;  // CMD
	typedef device::PORT<device::PORT2, device::bitpos::B1> SPCK;  // CLK

	typedef device::spi_io2<MISO, MOSI, SPCK> SPI;  ///< Soft SPI 定義

	SPI		spi_;

	typedef device::PORT<device::PORT1, device::bitpos::B7> SDC_SELECT;  // DAT3 カード選択信号
	typedef device::PORT<device::PORT2, device::bitpos::B5> SDC_DETECT;  // CD   カード検出

	typedef fatfs::mmc_io<SPI, SDC_SELECT, SDC_POWER, SDC_DETECT> MMC;   // ハードウェアー定義

	MMC		sdh_(spi_, 20000000);
#endif
	typedef utils::sdc_man SDC;
	SDC		sdc_;

	volatile uint32_t	wpos_;

	/// DMAC 終了割り込み
	class dmac_term_task {
	public:
		void operator() () {
			device::DMAC0::DMCNT.DTE = 1;  // DMA を再スタート
			wpos_ = 0;
		}
	};

	typedef device::dmac_mgr<device::DMAC0, dmac_term_task> DMAC_MGR;
	DMAC_MGR	dmac_mgr_;

	uint32_t get_wave_pos_() { return (dmac_mgr_.get_count() & 0x3ff) ^ 0x3ff; }

	typedef device::R12DA DAC;
	typedef device::dac_out<DAC> DAC_OUT;
	DAC_OUT		dac_out_;

	typedef utils::sound_out<1024, 256> SOUND_OUT;
	SOUND_OUT	sound_out_;

	class tpu_task {
	public:
		void operator() () {
			uint32_t tmp = wpos_;
			++wpos_;
			if((tmp ^ wpos_) & 64) {
				sound_out_.service(64);
			}
		}
	};

	typedef device::tpu_io<device::TPU0, tpu_task> TPU0;
	TPU0		tpu0_;

	typedef emu::spinv SPINV;
	SPINV		spinv_;

	utils::command<256> cmd_;

	bool check_mount_() {
		auto f = sdc_.get_mount();
		if(!f) {
			utils::format("SD card not mount.\n");
		}
		return f;
	}

	void command_()
	{
		if(!cmd_.service()) {
			return;
		}

		uint8_t cmdn = cmd_.get_words();
		if(cmdn >= 1) {
			bool f = false;
			if(cmd_.cmp_word(0, "dir")) {  // dir [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.dir(tmp);
					} else {
						sdc_.dir("");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "cd")) {  // cd [xxx]
				if(check_mount_()) {
					if(cmdn >= 2) {
						char tmp[128];
						cmd_.get_word(1, tmp, sizeof(tmp));
						sdc_.cd(tmp);
					} else {
						sdc_.cd("/");
					}
				}
				f = true;
			} else if(cmd_.cmp_word(0, "pwd")) { // pwd
				utils::format("%s\n") % sdc_.get_current();
				f = true;
			} else if(cmd_.cmp_word(0, "help")) {
				utils::format("    dir [path]\n");
				utils::format("    cd [path]\n");
				utils::format("    pwd\n");
				f = true;
			}
			if(!f) {
				char tmp[128];
				if(cmd_.get_word(0, tmp, sizeof(tmp))) {
					utils::format("Command error: '%s'\n") % tmp;
				}
			}
		}
	}
}

extern "C" {

	uint8_t get_fami_pad()
	{
		return famipad_.update();
	}

	void set_sample_rate(uint32_t freq)
	{
		uint8_t intr_level = 5;
		if(!tpu0_.start(freq, intr_level)) {
			utils::format("TPU0 start error...\n");
		}
	}

	void sci_putch(char ch)
	{
		sci_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		sci_.puts(str);
	}

	char sci_getch(void)
	{
		return sci_.getch();
	}

	uint16_t sci_length()
	{
		return sci_.recv_length();
	}

	DSTATUS disk_initialize(BYTE drv) {
		return sdh_.disk_initialize(drv);
	}

	DSTATUS disk_status(BYTE drv) {
		return sdh_.disk_status(drv);
	}

	DRESULT disk_read(BYTE drv, BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_read(drv, buff, sector, count);
	}

	DRESULT disk_write(BYTE drv, const BYTE* buff, DWORD sector, UINT count) {
		return sdh_.disk_write(drv, buff, sector, count);
	}

	DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void* buff) {
		return sdh_.disk_ioctl(drv, ctrl, buff);
	}

	DWORD get_fattime(void) {
		time_t t = 0;
///		rtc_.get_time(t);
		return utils::str::get_fattime(t);
	}

	void utf8_to_sjis(const char* src, char* dst, uint32_t len) {
		utils::str::utf8_to_sjis(src, dst, len);
	}

	int fatfs_get_mount() {
		return sdc_.get_mount();
	}

	int make_full_path(const char* src, char* dst, uint16_t len)
	{
		return sdc_.make_full_path(src, dst, len);
	}
}

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

int main(int argc, char** argv)
{
	SYSTEM_IO::setup_system_clock();

	{  // 内臓１２ビット D/A の設定
		bool amp_ena = true;
		dac_out_.start(DAC_OUT::output::CH0_CH1, amp_ena);
		dac_out_.out0(0x8000);
		dac_out_.out1(0x8000);
	}

	{  // SCI 設定
		static const uint8_t sci_level = 2;
		sci_.start(115200, sci_level);
	}

	{  // SD カード・クラスの初期化
		sdh_.start();
		sdc_.start();
	}

	// 波形メモリーの無音状態初期化
	sound_out_.mute();

	{  // サンプリング・タイマー設定
		set_sample_rate(11127);
	}

	{  // DMAC マネージャー開始
		uint8_t intr_level = 4;
		auto ret = dmac_mgr_.start(tpu0_.get_intr_vec(), DMAC_MGR::trans_type::SP_DN_32,
			reinterpret_cast<uint32_t>(sound_out_.get_wave()), DAC::DADR0.address(),
			sound_out_.size(), intr_level);
		if(!ret) {
			utils::format("DMAC Not start...\n");
		}
	}

	utils::format("\rRTK5RX65N Start for Space Invaders\n");

	cmd_.set_prompt("# ");

	{  // GLCDC 初期化
		LCD_DISP::DIR  = 1;
		LCD_LIGHT::DIR = 1;
		LCD_DISP::P  = 0;  // DISP Disable
		LCD_LIGHT::P = 0;  // BackLight Disable (No PWM)
		if(glcdc_io_.start()) {
			utils::format("Start GLCDC\n");
			LCD_DISP::P  = 1;  // DISP Enable
			LCD_LIGHT::P = 1;  // BackLight Enable (No PWM)
			if(!glcdc_io_.control(GLCDC_IO::CONTROL_CMD::START_DISPLAY)) {
				utils::format("GLCDC ctrl fail...\n");
			}
		} else {
			utils::format("Fail GLCDC\n");
		}
	}

	LED::DIR = 1;

	{
		PAD_VCC::DIR = 1;
		PAD_VCC::P = 1;
		PAD_GND::DIR = 1;
		PAD_GND::P = 0;
		famipad_.start();
	}

	uint32_t delay_inv = 120;
	uint8_t n = 0;
	while(1) {
		glcdc_io_.sync_vpos();

		if(delay_inv > 0) {
			--delay_inv;
			if(delay_inv == 0) {
				if(sdc_.get_mount()) {
					if(spinv_.start("/inv_roms", "/inv_wavs")) {
						utils::format("Space Invaders start...\n");
					} else {
						utils::format("Space Invaders not start...(fail)\n");
					}
				} else {
					delay_inv = 60;
					utils::format("SD card not mount\n");
				}
			}
		} else {
			spinv_.service((void*)0x00000000, glcdc_io_.get_xsize(), glcdc_io_.get_ysize());

			SPINV::SND_MGR& snd = spinv_.at_sound();
			uint32_t len = snd.get_length();
			const int16_t* wav = snd.get_buffer();
			for(uint32_t i = 0; i < len; ++i) {
				while((sound_out_.at_fifo().size() - sound_out_.at_fifo().length()) < 8) {
				}
				sound::wave_t t;
				t.l_ch = t.r_ch = *wav++;
				sound_out_.at_fifo().put(t);
			}
		}

		sdc_.service(sdh_.service());

		command_();

		++n;
		if(n >= 30) {
			n = 0;
		}
		if(n < 10) {
			LED::P = 0;
		} else {
			LED::P = 1;
		}
	}
}
<|endoftext|>