<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2016 Mustafa Serdar Sanli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <algorithm>
#include <stack>
#include <utility>

#include <boost/format.hpp>

#include "Attributes.hpp"
#include "CodeGenerator.hpp"
#include "JsonParserLibrary.hpp"

using namespace std;
using boost::format;

struct Variable
{
	string cppName;
	string jsonName;
	bool skipNull = false;

	explicit Variable(const VariableDef &var)
	  : cppName(var.name)
	  , jsonName("\"" + var.name + "\"")
	{
		if (var.attributes.find(VarAttributes::JsonFieldName.name) != var.attributes.end())
		{
			this->jsonName = "\"" + var.attributes.at(VarAttributes::JsonFieldName.name).args[0] + "\"";
		}

		if (var.attributes.find(VarAttributes::OnNull.name) != var.attributes.end() &&
		    var.attributes.at(VarAttributes::OnNull.name).args[0] == "skip")
		{
			this->skipNull = true;
		}
	}

	bool operator<(const Variable &o) const
	{
		return jsonName < o.jsonName;
	}
	bool operator==(const Variable &o) const
	{
		return jsonName == o.jsonName;
	}
};

static
void RenderVariableType(ostream &out, const VariableTypeDef &vt)
{
	out << vt.typeName;

	if (vt.of.size())
	{
		out << "< ";

		for (size_t i = 0; i < vt.of.size(); ++i)
		{
			if (i != 0)
			{
				out << " , ";
			}
			RenderVariableType(out, vt.of[i]);
		}

		out << " >";
	}
}

char SerializeToJsonDeclarations[] = R"(
	template <typename OutputIteratorType>
	void SerializeTo(OutputIteratorType out) const
	{
		QuantumJsonImpl__::Serializer<OutputIteratorType> s(out);
		this->SerializeTo(s);
	}

	template <typename OutputIteratorType>
	void SerializeTo(QuantumJsonImpl__::Serializer<OutputIteratorType> &s) const;
)";

format SerializeToJsonDefinitionBegin(R"(
template <typename OutputIteratorType>
void %1%::SerializeTo(QuantumJsonImpl__::Serializer<OutputIteratorType> &s) const
{
	*(s.out++) = '{';
)");

char SerializeToJsonDefinitionEnd[] = R"(
	*(s.out++) = '}';
}
)";

char MergeFromJsonDeclarations[] = R"(
	void MergeFromJson(const std::string &json)
	{
		MergeFromJson(json.begin(), json.end());
	}

	template <typename InputIteratorType>
	void MergeFromJson(InputIteratorType it, InputIteratorType end);
)";

// For aligning bind struct name to %1%, and bind spaces of the same length to %2%
format MergeFromJsonDefImpl(R"(
template <typename InputIteratorType>
inline
void %1%::MergeFromJson(InputIteratorType it,
     %2%                InputIteratorType end)
{
	QuantumJsonImpl__::Parser<InputIteratorType> parser(it, end);
	parser.ParseObject(*this);

	// Throw when parsing fails
	if (parser.errorCode != QuantumJsonImpl__::ErrorCode::NoError)
	{
		throw QuantumJsonImpl__::JsonError(parser.errorCode);
	}
}
)");

format StructDefBegin(R"(
struct %1%
{
	%1%() = default;
	%1%(const %1% &) = default;
	%1%(%1% &&) = default;

	%1%& operator=(const %1% &) = default;

)");

// Methods that are called by parser
char ParserExtensionMethodDeclarations[] = R"(
	// Function that parses one field only
	// If the object is as follows:
	// {"a": "sadsadsa", "b": 123}
	//  <------------->  <------>
	// marked regions would map to ParseNextField calls.
	template <typename InputIteratorType>
	void ParseNextField(QuantumJsonImpl__::Parser<InputIteratorType> &parser);

)";

format ParseNextFieldBegin(R"(
template <typename InputIteratorType>
inline
void %1%::ParseNextField(QuantumJsonImpl__::Parser<InputIteratorType> &parser)
{
)");

format ParseNextFieldEnd(R"(
	// Should be unreachable
}
)");

char IncludeStandardHeaders[] = R"(
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

)";

char ParserCommonStuff[] = R"(
	auto &it = parser.it;
	auto &end = parser.end;

	goto _Start; // _Start is the entry point for perser

	_UnknownField:
	// Field name is not known
	// Skip the field completely.
	// TODO make this an exception if flag is given to
	while (it != end && *it != '"')
		++it;
	if (it == end)
	{
		parser.errorCode = QuantumJsonImpl__::ErrorCode::UnexpectedEOF;
		return;
	}

	// Closing quote
	++it;

	parser.SkipWhitespace();
	parser.SkipChar(':'); // Field Separator
	parser.SkipWhitespace();

	parser.SkipValue();

	return; // Done parsing this field
)";

format FieldNameParsed(R"(
	// Matched field [%1%]
	parser.SkipWhitespace();
	parser.SkipChar(':'); // Field Separator
	parser.SkipWhitespace();

%2%
	// Parse the actual value
	parser.ParseValueInto(this->%1%);
	return;
)");

char SkipNullValue[] = R"(
	// Field skip null values for this field.
	{
		bool skipped = false;
		parser.MaybeSkipNull(&skipped);
		if (skipped)
		{
			return;
		}
	}
)";

char PeekNextChar[] = R"(*it)";
char ConsumeNextChar[] = R"(++it)";

// Base gooto labels for generated parser state machine
struct Labels
{
	static constexpr const char *Start = "_Start";
	static constexpr const char *UnknownField = "_UnknownField";
};

void GenerateParserForStructDef(ostream &out, const StructDef &s);

void GenerateHeaderForFile(ostream &out, const ParsedFile &file)
{
	// TODO use include guards
	out << "#pragma once\n\n";

	out << IncludeStandardHeaders;

	GenerateCommonParserDefinitions(out);

	// Header declerations
	for (const StructDef &s : file.structs)
	{
		out << StructDefBegin % s.name;

		for (const VariableDef &var : s.variables)
		{
			out << "\t";
			RenderVariableType(out, var.type);
			out << " " << var.name << ";\n";
		}

		out << ParserExtensionMethodDeclarations;
		out << MergeFromJsonDeclarations;
		out << SerializeToJsonDeclarations;
		out << "};\n";
	}

	// Function definitions
	for (const StructDef &s : file.structs)
	{
		GenerateParserForStructDef(out, s);

		out << MergeFromJsonDefImpl % s.name % string(s.name.size(), ' ');

		out << SerializeToJsonDefinitionBegin % s.name;

		bool putSeparator = false;
		for (const VariableDef &var : s.variables)
		{
			Variable v(var);

			out << "\n";
			out << "\t// Render field " << v.cppName << "\n";

			if (putSeparator)
			{
				out << "\t*(++s.out) = ',';\n";
			}
			putSeparator = true;

			for (char c : v.jsonName)
			{
				out << "\t*(++s.out) = '" << c << "';\n";
			}
			out << "\t*(++s.out) = ':';\n";
			out << "\ts.SerializeValue(this->" << var.name << ");\n";
		}

		out << SerializeToJsonDefinitionEnd;
	}
}

// A state for the matcher state machine
// Keeps track of what has been matched until now
// Only used in code generation, and in comment of output.
struct MatchState
{
	string matched;
	string gotoLabelName;
};

void PrintGotoLabel(ostream &out, const MatchState &ms)
{
	out << "\n"
	    << "\t" << ms.gotoLabelName << ": // [" << ms.matched << "] has been matched\n";
}

// When all known fields start with the same prefix
// Not matching will jump to unknown field label
void MatchOnlyPrefix(ostream &out, const string &prefix)
{
	out << "\t// Matching common prefix: [" << prefix << "]\n";
	for (char c : prefix)
	{
		out << "\tif (" << PeekNextChar << " != '" << c << "') goto " << Labels::UnknownField << ";\n";
		out << "\t" << ConsumeNextChar << ";\n";
	}
}

// Returns common prefix for a range of sorted strings
string CommonPrefix(const vector<Variable>::iterator varsBegin,
                    const vector<Variable>::iterator varsEnd,
                    int matchedChars)
{
	string first = varsBegin->jsonName;
	string last = (varsEnd - 1)->jsonName;

	return string(first.begin() + matchedChars,
	              mismatch(first.begin() + matchedChars, first.end(), last.begin() + matchedChars).first);
}

void GenerateMatchers(ostream &out,
                      const MatchState &ms,
                      int &stateCounter,
                      const vector<Variable>::iterator varsBegin,
                      const vector<Variable>::iterator varsEnd,
                      size_t matchedChars = 0)
{
	if (varsBegin == varsEnd) return;

	out << "\t\n";
	out << "\t// ###\n";
	out << "\t// Matching range [" << varsBegin->jsonName << ", " << (varsEnd-1)->jsonName << "]\n";

	PrintGotoLabel(out, ms);

	string commonPrefix = CommonPrefix(varsBegin, varsEnd, matchedChars);

	if (commonPrefix.size())
	{
		// All elements share the common prefix, match it here
		MatchOnlyPrefix(out, commonPrefix);
	}

	if (varsBegin + 1 == varsEnd)
	{
		// There was only one group and we matched that already

		bool skipNull = false;

		out << FieldNameParsed % varsBegin->cppName
		                       % (varsBegin->skipNull ? SkipNullValue : "");
		return;
	}

	matchedChars += commonPrefix.size();

	struct GroupToMatch
	{
		MatchState matchState;
		vector<Variable>::iterator begin, end;
		size_t matchedChars;
	};
	vector<GroupToMatch> unmatchedGroups;

	// Branch out now
	auto groupBegin = varsBegin;
	for (auto it = varsBegin + 1; it != varsEnd; ++it)
	{
		char initial = (it->jsonName)[matchedChars];
		if (initial != (groupBegin->jsonName)[matchedChars])
		{
			MatchState nextState = {
			    groupBegin->jsonName.substr(0, matchedChars),
			    "state_" + to_string(++stateCounter)
			};
			unmatchedGroups.emplace_back(
			    GroupToMatch{nextState, groupBegin, it, matchedChars});
			groupBegin = it;
		}
	}
	MatchState nextState = {
	    groupBegin->jsonName.substr(0, matchedChars),
	    "state_" + to_string(++stateCounter)
	};
	unmatchedGroups.emplace_back(GroupToMatch{nextState, groupBegin, varsEnd, matchedChars});

	// Create jump table
	out << "\tswitch (" << PeekNextChar << ")\n"
	    << "\t{\n";
	for (const auto &g : unmatchedGroups)
	{
		out << "\t\tcase '" << (g.begin->jsonName)[g.matchedChars] << "': "
		    << "goto " << g.matchState.gotoLabelName << ";\n";
	}
	out << "\t\tdefault: goto " << Labels::UnknownField << ";\n"
	    << "\t}\n";

	for (const auto &g : unmatchedGroups)
	{
		GenerateMatchers(out, g.matchState, stateCounter, g.begin, g.end, g.matchedChars);
	}
}

void GenerateParserForStructDef(ostream &out, const StructDef &s)
{
	out << ParseNextFieldBegin % s.name;

	vector<Variable> vars;
	for (const VariableDef &var : s.variables)
	{
		vars.push_back(Variable(var));
	}
	sort(vars.begin(), vars.end());

	out << ParserCommonStuff;

	int stateCounter = 0;
	MatchState initialState = {"", Labels::Start};
	GenerateMatchers(out, initialState, stateCounter, vars.begin(), vars.end());

	out << ParseNextFieldEnd;
}
<commit_msg>Remove unused variable<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2016 Mustafa Serdar Sanli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#include <algorithm>
#include <stack>
#include <utility>

#include <boost/format.hpp>

#include "Attributes.hpp"
#include "CodeGenerator.hpp"
#include "JsonParserLibrary.hpp"

using namespace std;
using boost::format;

struct Variable
{
	string cppName;
	string jsonName;
	bool skipNull = false;

	explicit Variable(const VariableDef &var)
	  : cppName(var.name)
	  , jsonName("\"" + var.name + "\"")
	{
		if (var.attributes.find(VarAttributes::JsonFieldName.name) != var.attributes.end())
		{
			this->jsonName = "\"" + var.attributes.at(VarAttributes::JsonFieldName.name).args[0] + "\"";
		}

		if (var.attributes.find(VarAttributes::OnNull.name) != var.attributes.end() &&
		    var.attributes.at(VarAttributes::OnNull.name).args[0] == "skip")
		{
			this->skipNull = true;
		}
	}

	bool operator<(const Variable &o) const
	{
		return jsonName < o.jsonName;
	}
	bool operator==(const Variable &o) const
	{
		return jsonName == o.jsonName;
	}
};

static
void RenderVariableType(ostream &out, const VariableTypeDef &vt)
{
	out << vt.typeName;

	if (vt.of.size())
	{
		out << "< ";

		for (size_t i = 0; i < vt.of.size(); ++i)
		{
			if (i != 0)
			{
				out << " , ";
			}
			RenderVariableType(out, vt.of[i]);
		}

		out << " >";
	}
}

char SerializeToJsonDeclarations[] = R"(
	template <typename OutputIteratorType>
	void SerializeTo(OutputIteratorType out) const
	{
		QuantumJsonImpl__::Serializer<OutputIteratorType> s(out);
		this->SerializeTo(s);
	}

	template <typename OutputIteratorType>
	void SerializeTo(QuantumJsonImpl__::Serializer<OutputIteratorType> &s) const;
)";

format SerializeToJsonDefinitionBegin(R"(
template <typename OutputIteratorType>
void %1%::SerializeTo(QuantumJsonImpl__::Serializer<OutputIteratorType> &s) const
{
	*(s.out++) = '{';
)");

char SerializeToJsonDefinitionEnd[] = R"(
	*(s.out++) = '}';
}
)";

char MergeFromJsonDeclarations[] = R"(
	void MergeFromJson(const std::string &json)
	{
		MergeFromJson(json.begin(), json.end());
	}

	template <typename InputIteratorType>
	void MergeFromJson(InputIteratorType it, InputIteratorType end);
)";

// For aligning bind struct name to %1%, and bind spaces of the same length to %2%
format MergeFromJsonDefImpl(R"(
template <typename InputIteratorType>
inline
void %1%::MergeFromJson(InputIteratorType it,
     %2%                InputIteratorType end)
{
	QuantumJsonImpl__::Parser<InputIteratorType> parser(it, end);
	parser.ParseObject(*this);

	// Throw when parsing fails
	if (parser.errorCode != QuantumJsonImpl__::ErrorCode::NoError)
	{
		throw QuantumJsonImpl__::JsonError(parser.errorCode);
	}
}
)");

format StructDefBegin(R"(
struct %1%
{
	%1%() = default;
	%1%(const %1% &) = default;
	%1%(%1% &&) = default;

	%1%& operator=(const %1% &) = default;

)");

// Methods that are called by parser
char ParserExtensionMethodDeclarations[] = R"(
	// Function that parses one field only
	// If the object is as follows:
	// {"a": "sadsadsa", "b": 123}
	//  <------------->  <------>
	// marked regions would map to ParseNextField calls.
	template <typename InputIteratorType>
	void ParseNextField(QuantumJsonImpl__::Parser<InputIteratorType> &parser);

)";

format ParseNextFieldBegin(R"(
template <typename InputIteratorType>
inline
void %1%::ParseNextField(QuantumJsonImpl__::Parser<InputIteratorType> &parser)
{
)");

format ParseNextFieldEnd(R"(
	// Should be unreachable
}
)");

char IncludeStandardHeaders[] = R"(
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

)";

char ParserCommonStuff[] = R"(
	auto &it = parser.it;
	auto &end = parser.end;

	goto _Start; // _Start is the entry point for perser

	_UnknownField:
	// Field name is not known
	// Skip the field completely.
	// TODO make this an exception if flag is given to
	while (it != end && *it != '"')
		++it;
	if (it == end)
	{
		parser.errorCode = QuantumJsonImpl__::ErrorCode::UnexpectedEOF;
		return;
	}

	// Closing quote
	++it;

	parser.SkipWhitespace();
	parser.SkipChar(':'); // Field Separator
	parser.SkipWhitespace();

	parser.SkipValue();

	return; // Done parsing this field
)";

format FieldNameParsed(R"(
	// Matched field [%1%]
	parser.SkipWhitespace();
	parser.SkipChar(':'); // Field Separator
	parser.SkipWhitespace();

%2%
	// Parse the actual value
	parser.ParseValueInto(this->%1%);
	return;
)");

char SkipNullValue[] = R"(
	// Field skip null values for this field.
	{
		bool skipped = false;
		parser.MaybeSkipNull(&skipped);
		if (skipped)
		{
			return;
		}
	}
)";

char PeekNextChar[] = R"(*it)";
char ConsumeNextChar[] = R"(++it)";

// Base gooto labels for generated parser state machine
struct Labels
{
	static constexpr const char *Start = "_Start";
	static constexpr const char *UnknownField = "_UnknownField";
};

void GenerateParserForStructDef(ostream &out, const StructDef &s);

void GenerateHeaderForFile(ostream &out, const ParsedFile &file)
{
	// TODO use include guards
	out << "#pragma once\n\n";

	out << IncludeStandardHeaders;

	GenerateCommonParserDefinitions(out);

	// Header declerations
	for (const StructDef &s : file.structs)
	{
		out << StructDefBegin % s.name;

		for (const VariableDef &var : s.variables)
		{
			out << "\t";
			RenderVariableType(out, var.type);
			out << " " << var.name << ";\n";
		}

		out << ParserExtensionMethodDeclarations;
		out << MergeFromJsonDeclarations;
		out << SerializeToJsonDeclarations;
		out << "};\n";
	}

	// Function definitions
	for (const StructDef &s : file.structs)
	{
		GenerateParserForStructDef(out, s);

		out << MergeFromJsonDefImpl % s.name % string(s.name.size(), ' ');

		out << SerializeToJsonDefinitionBegin % s.name;

		bool putSeparator = false;
		for (const VariableDef &var : s.variables)
		{
			Variable v(var);

			out << "\n";
			out << "\t// Render field " << v.cppName << "\n";

			if (putSeparator)
			{
				out << "\t*(++s.out) = ',';\n";
			}
			putSeparator = true;

			for (char c : v.jsonName)
			{
				out << "\t*(++s.out) = '" << c << "';\n";
			}
			out << "\t*(++s.out) = ':';\n";
			out << "\ts.SerializeValue(this->" << var.name << ");\n";
		}

		out << SerializeToJsonDefinitionEnd;
	}
}

// A state for the matcher state machine
// Keeps track of what has been matched until now
// Only used in code generation, and in comment of output.
struct MatchState
{
	string matched;
	string gotoLabelName;
};

void PrintGotoLabel(ostream &out, const MatchState &ms)
{
	out << "\n"
	    << "\t" << ms.gotoLabelName << ": // [" << ms.matched << "] has been matched\n";
}

// When all known fields start with the same prefix
// Not matching will jump to unknown field label
void MatchOnlyPrefix(ostream &out, const string &prefix)
{
	out << "\t// Matching common prefix: [" << prefix << "]\n";
	for (char c : prefix)
	{
		out << "\tif (" << PeekNextChar << " != '" << c << "') goto " << Labels::UnknownField << ";\n";
		out << "\t" << ConsumeNextChar << ";\n";
	}
}

// Returns common prefix for a range of sorted strings
string CommonPrefix(const vector<Variable>::iterator varsBegin,
                    const vector<Variable>::iterator varsEnd,
                    int matchedChars)
{
	string first = varsBegin->jsonName;
	string last = (varsEnd - 1)->jsonName;

	return string(first.begin() + matchedChars,
	              mismatch(first.begin() + matchedChars, first.end(), last.begin() + matchedChars).first);
}

void GenerateMatchers(ostream &out,
                      const MatchState &ms,
                      int &stateCounter,
                      const vector<Variable>::iterator varsBegin,
                      const vector<Variable>::iterator varsEnd,
                      size_t matchedChars = 0)
{
	if (varsBegin == varsEnd) return;

	out << "\t\n";
	out << "\t// ###\n";
	out << "\t// Matching range [" << varsBegin->jsonName << ", " << (varsEnd-1)->jsonName << "]\n";

	PrintGotoLabel(out, ms);

	string commonPrefix = CommonPrefix(varsBegin, varsEnd, matchedChars);

	if (commonPrefix.size())
	{
		// All elements share the common prefix, match it here
		MatchOnlyPrefix(out, commonPrefix);
	}

	if (varsBegin + 1 == varsEnd)
	{
		// There was only one group and we matched that already

		out << FieldNameParsed % varsBegin->cppName
		                       % (varsBegin->skipNull ? SkipNullValue : "");
		return;
	}

	matchedChars += commonPrefix.size();

	struct GroupToMatch
	{
		MatchState matchState;
		vector<Variable>::iterator begin, end;
		size_t matchedChars;
	};
	vector<GroupToMatch> unmatchedGroups;

	// Branch out now
	auto groupBegin = varsBegin;
	for (auto it = varsBegin + 1; it != varsEnd; ++it)
	{
		char initial = (it->jsonName)[matchedChars];
		if (initial != (groupBegin->jsonName)[matchedChars])
		{
			MatchState nextState = {
			    groupBegin->jsonName.substr(0, matchedChars),
			    "state_" + to_string(++stateCounter)
			};
			unmatchedGroups.emplace_back(
			    GroupToMatch{nextState, groupBegin, it, matchedChars});
			groupBegin = it;
		}
	}
	MatchState nextState = {
	    groupBegin->jsonName.substr(0, matchedChars),
	    "state_" + to_string(++stateCounter)
	};
	unmatchedGroups.emplace_back(GroupToMatch{nextState, groupBegin, varsEnd, matchedChars});

	// Create jump table
	out << "\tswitch (" << PeekNextChar << ")\n"
	    << "\t{\n";
	for (const auto &g : unmatchedGroups)
	{
		out << "\t\tcase '" << (g.begin->jsonName)[g.matchedChars] << "': "
		    << "goto " << g.matchState.gotoLabelName << ";\n";
	}
	out << "\t\tdefault: goto " << Labels::UnknownField << ";\n"
	    << "\t}\n";

	for (const auto &g : unmatchedGroups)
	{
		GenerateMatchers(out, g.matchState, stateCounter, g.begin, g.end, g.matchedChars);
	}
}

void GenerateParserForStructDef(ostream &out, const StructDef &s)
{
	out << ParseNextFieldBegin % s.name;

	vector<Variable> vars;
	for (const VariableDef &var : s.variables)
	{
		vars.push_back(Variable(var));
	}
	sort(vars.begin(), vars.end());

	out << ParserCommonStuff;

	int stateCounter = 0;
	MatchState initialState = {"", Labels::Start};
	GenerateMatchers(out, initialState, stateCounter, vars.begin(), vars.end());

	out << ParseNextFieldEnd;
}
<|endoftext|>


<commit_before>#include "section.hpp"
#include "toolbox.hpp"
#include "rpexception.hpp"
#include "safeint.hpp"

#include <cstring>

Section::Section(std::ifstream &file, const char *name, const unsigned long long offset, const unsigned long long size, const Properties props)
: m_name(name), m_offset(offset), m_size(size), m_props(props), m_section(NULL)
{
    /* NB: std::streampos performs unsigned check */
    unsigned long long fsize = get_file_size(file);
    if(SafeAddU64(offset, size) >= fsize)
        RAISE_EXCEPTION("Your file seems to be fucked up");

    std::streampos backup = file.tellg();

    file.seekg(offset, std::ios::beg);
    m_section = new (std::nothrow) unsigned char[m_size];
    if(m_section == NULL)
        RAISE_EXCEPTION("Cannote allocate a section.");

    file.read((char*)m_section, m_size);

    file.seekg(backup);
}

Section::~Section(void)
{
    if(m_section != NULL)
        delete [] m_section;
}

std::string Section::get_name(void) const
{
    return m_name;
}

unsigned long long Section::get_size(void) const
{
    return m_size;
}

unsigned char* Section::get_section_buffer(void) const
{
    return m_section;
}

const unsigned long long Section::get_offset(void) const
{
    return m_offset;
}

std::list<unsigned long long> Section::search_in_memory(const unsigned char *val, const unsigned int size)
{
    unsigned long long offset = 0;
    std::list<unsigned long long> val_found;

    while(offset < m_size)
    {
        if(std::memcmp(m_section + offset, val, size) == 0)
            val_found.push_back(offset);

        offset += size;
    }

    return val_found;
}<commit_msg>section: fix a bug in the search algorithm (a lame one!)<commit_after>#include "section.hpp"
#include "toolbox.hpp"
#include "rpexception.hpp"
#include "safeint.hpp"

#include <cstring>

Section::Section(std::ifstream &file, const char *name, const unsigned long long offset, const unsigned long long size, const Properties props)
: m_name(name), m_offset(offset), m_size(size), m_props(props), m_section(NULL)
{
    /* NB: std::streampos performs unsigned check */
    unsigned long long fsize = get_file_size(file);
    if(SafeAddU64(offset, size) >= fsize)
        RAISE_EXCEPTION("Your file seems to be fucked up");

    std::streampos backup = file.tellg();

    file.seekg(offset, std::ios::beg);
    m_section = new (std::nothrow) unsigned char[m_size];
    if(m_section == NULL)
        RAISE_EXCEPTION("Cannote allocate a section.");

    file.read((char*)m_section, m_size);

    file.seekg(backup);
}

Section::~Section(void)
{
    if(m_section != NULL)
        delete [] m_section;
}

std::string Section::get_name(void) const
{
    return m_name;
}

unsigned long long Section::get_size(void) const
{
    return m_size;
}

unsigned char* Section::get_section_buffer(void) const
{
    return m_section;
}

const unsigned long long Section::get_offset(void) const
{
    return m_offset;
}

std::list<unsigned long long> Section::search_in_memory(const unsigned char *val, const unsigned int size)
{
    std::list<unsigned long long> val_found;

    for(unsigned long long offset = 0; offset < m_size; offset++)
        if(std::memcmp(m_section + offset, val, size) == 0)
            val_found.push_back(offset);

    return val_found;
}<|endoftext|>


<commit_before>#ifndef EC_META_SYSTEM_THREADPOOL_HPP
#define EC_META_SYSTEM_THREADPOOL_HPP

#include <atomic>
#include <chrono>
#include <deque>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <tuple>
#include <vector>

#ifndef NDEBUG
#include <iostream>
#endif

namespace EC {

namespace Internal {
using TPFnType = std::function<void(void *)>;
using TPTupleType = std::tuple<TPFnType, void *>;
using TPQueueType = std::queue<TPTupleType>;
using ThreadPtr = std::unique_ptr<std::thread>;
using ThreadStackType = std::vector<std::tuple<ThreadPtr, std::thread::id>>;
using ThreadStacksType = std::deque<ThreadStackType>;
using ThreadStacksMutexesT = std::deque<std::mutex>;
using ThreadCountersT = std::deque<std::atomic_uint>;
using PtrsHoldT = std::deque<std::atomic_bool>;
using PointersT =
    std::tuple<ThreadStackType *, std::mutex *, std::atomic_uint *, std::atomic_bool *>;
}  // namespace Internal

/*!
    \brief Implementation of a Thread Pool.

    Note that if SIZE is less than 2, then ThreadPool will not create threads
    and run queued functions on the calling thread.
*/
template <unsigned int MAXSIZE>
class ThreadPool {
   public:
    ThreadPool()
        : threadStacks{}, threadStackMutexes{}, fnQueue{}, queueMutex{} {}

    ~ThreadPool() {
        while (!isNotRunning()) {
            std::this_thread::sleep_for(std::chrono::microseconds(30));
        }
    }

    /*!
        \brief Queues a function to be called (doesn't start calling yet).

        To run the queued functions, wakeThreads() must be called to wake the
        waiting threads which will start pulling functions from the queue to be
        called.
    */
    void queueFn(std::function<void(void *)> &&fn, void *ud = nullptr) {
        std::lock_guard<std::mutex> lock(queueMutex);
        fnQueue.emplace(std::make_tuple(fn, ud));
    }

    Internal::PointersT startThreads() {
        if (MAXSIZE >= 2) {
            checkStacks();
            auto pointers = newStackEntry();
            Internal::ThreadStackType *threadStack = std::get<0>(pointers);
            std::mutex *threadStackMutex = std::get<1>(pointers);
            std::atomic_uint *aCounter = std::get<2>(pointers);
            for (unsigned int i = 0; i < MAXSIZE; ++i) {
                std::thread *newThread = new std::thread(
                    [](Internal::ThreadStackType *threadStack,
                       std::mutex *threadStackMutex,
                       Internal::TPQueueType *fnQueue, std::mutex *queueMutex,
                       std::atomic_uint *initCount) {
                        // add id to idStack "call stack"
                        {
                            std::lock_guard<std::mutex> lock(*threadStackMutex);
                            threadStack->push_back(
                                {Internal::ThreadPtr(nullptr),
                                 std::this_thread::get_id()});
                        }

                        ++(*initCount);

                        // fetch queued fns and execute them
                        // fnTuples must live until end of function
                        std::list<Internal::TPTupleType> fnTuples;
                        do {
                            bool fnFound = false;
                            {
                                std::lock_guard<std::mutex> lock(*queueMutex);
                                if (!fnQueue->empty()) {
                                    fnTuples.emplace_back(
                                        std::move(fnQueue->front()));
                                    fnQueue->pop();
                                    fnFound = true;
                                }
                            }
                            if (fnFound) {
                                std::get<0>(fnTuples.back())(
                                    std::get<1>(fnTuples.back()));
                            } else {
                                break;
                            }
                        } while (true);

                        // pop id from idStack "call stack"
                        do {
                            std::this_thread::sleep_for(
                                std::chrono::microseconds(15));
                            if (initCount->load() != MAXSIZE) {
                                continue;
                            }
                            {
                                std::lock_guard<std::mutex> lock(
                                    *threadStackMutex);
                                if (std::get<1>(threadStack->back()) ==
                                    std::this_thread::get_id()) {
                                    if (!std::get<0>(threadStack->back())) {
                                        continue;
                                    }
                                    std::get<0>(threadStack->back())->detach();
                                    threadStack->pop_back();
                                    break;
                                }
                            }
                        } while (true);
                    },
                    threadStack, threadStackMutex, &fnQueue, &queueMutex,
                    aCounter);
                while (aCounter->load() != i + 1) {
                    std::this_thread::sleep_for(std::chrono::microseconds(15));
                }
                std::lock_guard<std::mutex> stackLock(*threadStackMutex);
                std::get<0>(threadStack->at(i)).reset(newThread);
            }
            while (aCounter->load() != MAXSIZE) {
                std::this_thread::sleep_for(std::chrono::microseconds(15));
            }
            return pointers;
        } else {
            sequentiallyRunTasks();
        }
        return {nullptr, nullptr, nullptr, nullptr};
    }

    /*!
        \brief Returns true if the function queue is empty.
    */
    bool isQueueEmpty() {
        std::lock_guard<std::mutex> lock(queueMutex);
        return fnQueue.empty();
    }

    /*!
        \brief Returns the ThreadCount that this class was created with.
     */
    constexpr unsigned int getMaxThreadCount() { return MAXSIZE; }

    void easyStartAndWait() {
        if (MAXSIZE >= 2) {
            Internal::PointersT pointers = startThreads();
            do {
                std::this_thread::sleep_for(std::chrono::microseconds(30));

                bool isQueueEmpty = false;
                {
                    std::lock_guard<std::mutex> lock(queueMutex);
                    isQueueEmpty = fnQueue.empty();
                }

                if (isQueueEmpty) {
                    break;
                }
            } while (true);
            if (std::get<0>(pointers)) {
                do {
                    {
                        std::lock_guard<std::mutex> lock(*std::get<1>(pointers));
                        if (std::get<0>(pointers)->empty()) {
                            std::get<3>(pointers)->store(false);
                            break;
                        }
                    }
                    std::this_thread::sleep_for(std::chrono::microseconds(15));
                } while (true);
            }
        } else {
            sequentiallyRunTasks();
        }
    }

    bool isNotRunning() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        auto tIter = threadStacks.begin();
        auto mIter = threadStackMutexes.begin();
        while (tIter != threadStacks.end() &&
               mIter != threadStackMutexes.end()) {
            {
                std::lock_guard<std::mutex> lock(*mIter);
                if (!tIter->empty()) {
                    return false;
                }
            }
            ++tIter;
            ++mIter;
        }
        return true;
    }

   private:
    Internal::ThreadStacksType threadStacks;
    Internal::ThreadStacksMutexesT threadStackMutexes;
    Internal::TPQueueType fnQueue;
    std::mutex queueMutex;
    Internal::ThreadCountersT threadCounters;
    Internal::PtrsHoldT ptrsHoldBools;
    std::mutex dequesMutex;

    void sequentiallyRunTasks() {
        // pull functions from queue and run them on current thread
        Internal::TPTupleType fnTuple;
        bool hasFn;
        do {
            {
                std::lock_guard<std::mutex> lock(queueMutex);
                if (!fnQueue.empty()) {
                    hasFn = true;
                    fnTuple = fnQueue.front();
                    fnQueue.pop();
                } else {
                    hasFn = false;
                }
            }
            if (hasFn) {
                std::get<0>(fnTuple)(std::get<1>(fnTuple));
            }
        } while (hasFn);
    }

    void checkStacks() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        if (threadStacks.empty()) {
            return;
        }

        bool erased = false;
        do {
            erased = false;
            {
                std::lock_guard<std::mutex> lock(threadStackMutexes.front());
                if (ptrsHoldBools.front().load()) {
                    break;
                } else if (threadStacks.front().empty()) {
                    threadStacks.pop_front();
                    threadCounters.pop_front();
                    ptrsHoldBools.pop_front();
                    erased = true;
                }
            }
            if (erased) {
                threadStackMutexes.pop_front();
            } else {
                break;
            }
        } while (!threadStacks.empty() && !threadStackMutexes.empty() &&
                 !threadCounters.empty() && !ptrsHoldBools.empty());
    }

    Internal::PointersT newStackEntry() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        threadStacks.emplace_back();
        threadStackMutexes.emplace_back();
        threadCounters.emplace_back();
        threadCounters.back().store(0);
        ptrsHoldBools.emplace_back();
        ptrsHoldBools.back().store(true);

        return {&threadStacks.back(), &threadStackMutexes.back(),
                &threadCounters.back(), &ptrsHoldBools.back()};
    }
};

}  // namespace EC

#endif
<commit_msg>Apply minor fix and documentation to ThreadPool<commit_after>#ifndef EC_META_SYSTEM_THREADPOOL_HPP
#define EC_META_SYSTEM_THREADPOOL_HPP

#include <atomic>
#include <chrono>
#include <deque>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <tuple>
#include <vector>

#ifndef NDEBUG
#include <iostream>
#endif

namespace EC {

namespace Internal {
using TPFnType = std::function<void(void *)>;
using TPTupleType = std::tuple<TPFnType, void *>;
using TPQueueType = std::queue<TPTupleType>;
using ThreadPtr = std::unique_ptr<std::thread>;
using ThreadStackType = std::vector<std::tuple<ThreadPtr, std::thread::id>>;
using ThreadStacksType = std::deque<ThreadStackType>;
using ThreadStacksMutexesT = std::deque<std::mutex>;
using ThreadCountersT = std::deque<std::atomic_uint>;
using PtrsHoldT = std::deque<std::atomic_bool>;
using PointersT =
    std::tuple<ThreadStackType *, std::mutex *, std::atomic_uint *, std::atomic_bool *>;
}  // namespace Internal

/*!
    \brief Implementation of a Thread Pool.

    Note that MAXSIZE template parameter determines how many threads are created
    each time that startThreads() (or easyStartAndWait()) is called.
*/
template <unsigned int MAXSIZE>
class ThreadPool {
   public:
    ThreadPool()
        : threadStacks{}, threadStackMutexes{}, fnQueue{}, queueMutex{} {}

    ~ThreadPool() {
        while (!isNotRunning()) {
            std::this_thread::sleep_for(std::chrono::microseconds(30));
        }
    }

    /*!
        \brief Queues a function to be called (doesn't start calling yet).

        To run the queued functions, startThreads() must be called to wake the
        waiting threads which will start pulling functions from the queue to be
        called.

        Note that the easyStartAndWait() calls startThreads() and waits until
        the threads have finished execution.
    */
    void queueFn(std::function<void(void *)> &&fn, void *ud = nullptr) {
        std::lock_guard<std::mutex> lock(queueMutex);
        fnQueue.emplace(std::make_tuple(fn, ud));
    }

    /*!
        \brief Creates MAXSIZE threads that will process queueFn() functions.

        Note that if MAXSIZE < 2, then this function will synchronously execute
        the queued functions and block until the functions have been executed.
        Otherwise, this function may return before the queued functions have
        been executed.
     */
    Internal::PointersT startThreads() {
        if (MAXSIZE >= 2) {
            checkStacks();
            auto pointers = newStackEntry();
            Internal::ThreadStackType *threadStack = std::get<0>(pointers);
            std::mutex *threadStackMutex = std::get<1>(pointers);
            std::atomic_uint *aCounter = std::get<2>(pointers);
            for (unsigned int i = 0; i < MAXSIZE; ++i) {
                std::thread *newThread = new std::thread(
                    [](Internal::ThreadStackType *threadStack,
                       std::mutex *threadStackMutex,
                       Internal::TPQueueType *fnQueue, std::mutex *queueMutex,
                       std::atomic_uint *initCount) {
                        // add id to idStack "call stack"
                        {
                            std::lock_guard<std::mutex> lock(*threadStackMutex);
                            threadStack->push_back(
                                {Internal::ThreadPtr(nullptr),
                                 std::this_thread::get_id()});
                        }

                        ++(*initCount);

                        // fetch queued fns and execute them
                        // fnTuples must live until end of function
                        std::list<Internal::TPTupleType> fnTuples;
                        do {
                            bool fnFound = false;
                            {
                                std::lock_guard<std::mutex> lock(*queueMutex);
                                if (!fnQueue->empty()) {
                                    fnTuples.emplace_back(
                                        std::move(fnQueue->front()));
                                    fnQueue->pop();
                                    fnFound = true;
                                }
                            }
                            if (fnFound) {
                                std::get<0>(fnTuples.back())(
                                    std::get<1>(fnTuples.back()));
                            } else {
                                break;
                            }
                        } while (true);

                        // pop id from idStack "call stack"
                        do {
                            std::this_thread::sleep_for(
                                std::chrono::microseconds(15));
                            if (initCount->load() != MAXSIZE) {
                                continue;
                            }
                            {
                                std::lock_guard<std::mutex> lock(
                                    *threadStackMutex);
                                if (std::get<1>(threadStack->back()) ==
                                    std::this_thread::get_id()) {
                                    if (!std::get<0>(threadStack->back())) {
                                        continue;
                                    }
                                    std::get<0>(threadStack->back())->detach();
                                    threadStack->pop_back();
                                    break;
                                }
                            }
                        } while (true);
                    },
                    threadStack, threadStackMutex, &fnQueue, &queueMutex,
                    aCounter);
                // Wait until thread has pushed to threadStack before setting
                // the handle to it
                while (aCounter->load() != i + 1) {
                    std::this_thread::sleep_for(std::chrono::microseconds(15));
                }
                std::lock_guard<std::mutex> stackLock(*threadStackMutex);
                std::get<0>(threadStack->at(i)).reset(newThread);
            }
            return pointers;
        } else {
            sequentiallyRunTasks();
        }
        return {nullptr, nullptr, nullptr, nullptr};
    }

    /*!
        \brief Returns true if the function queue is empty.
    */
    bool isQueueEmpty() {
        std::lock_guard<std::mutex> lock(queueMutex);
        return fnQueue.empty();
    }

    /*!
        \brief Returns the MAXSIZE count that this class was created with.
     */
    constexpr unsigned int getMaxThreadCount() { return MAXSIZE; }

    /*!
        \brief Calls startThreads() and waits until all threads have finished.

        Regardless of the value set to MAXSIZE, this function will block until
        all previously queued functions have been executed.
     */
    void easyStartAndWait() {
        if (MAXSIZE >= 2) {
            Internal::PointersT pointers = startThreads();
            do {
                std::this_thread::sleep_for(std::chrono::microseconds(30));

                bool isQueueEmpty = false;
                {
                    std::lock_guard<std::mutex> lock(queueMutex);
                    isQueueEmpty = fnQueue.empty();
                }

                if (isQueueEmpty) {
                    break;
                }
            } while (true);
            if (std::get<0>(pointers)) {
                do {
                    {
                        std::lock_guard<std::mutex> lock(*std::get<1>(pointers));
                        if (std::get<0>(pointers)->empty()) {
                            std::get<3>(pointers)->store(false);
                            break;
                        }
                    }
                    std::this_thread::sleep_for(std::chrono::microseconds(15));
                } while (true);
            }
        } else {
            sequentiallyRunTasks();
        }
    }

    /*!
        \brief Checks if any threads are currently running, returning true if
        there are no threads running.
     */
    bool isNotRunning() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        auto tIter = threadStacks.begin();
        auto mIter = threadStackMutexes.begin();
        while (tIter != threadStacks.end() &&
               mIter != threadStackMutexes.end()) {
            {
                std::lock_guard<std::mutex> lock(*mIter);
                if (!tIter->empty()) {
                    return false;
                }
            }
            ++tIter;
            ++mIter;
        }
        return true;
    }

   private:
    Internal::ThreadStacksType threadStacks;
    Internal::ThreadStacksMutexesT threadStackMutexes;
    Internal::TPQueueType fnQueue;
    std::mutex queueMutex;
    Internal::ThreadCountersT threadCounters;
    Internal::PtrsHoldT ptrsHoldBools;
    std::mutex dequesMutex;

    void sequentiallyRunTasks() {
        // pull functions from queue and run them on current thread
        Internal::TPTupleType fnTuple;
        bool hasFn;
        do {
            {
                std::lock_guard<std::mutex> lock(queueMutex);
                if (!fnQueue.empty()) {
                    hasFn = true;
                    fnTuple = fnQueue.front();
                    fnQueue.pop();
                } else {
                    hasFn = false;
                }
            }
            if (hasFn) {
                std::get<0>(fnTuple)(std::get<1>(fnTuple));
            }
        } while (hasFn);
    }

    void checkStacks() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        if (threadStacks.empty()) {
            return;
        }

        bool erased = false;
        do {
            erased = false;
            {
                std::lock_guard<std::mutex> lock(threadStackMutexes.front());
                if (ptrsHoldBools.front().load()) {
                    break;
                } else if (threadStacks.front().empty()) {
                    threadStacks.pop_front();
                    threadCounters.pop_front();
                    ptrsHoldBools.pop_front();
                    erased = true;
                }
            }
            if (erased) {
                threadStackMutexes.pop_front();
            } else {
                break;
            }
        } while (!threadStacks.empty() && !threadStackMutexes.empty() &&
                 !threadCounters.empty() && !ptrsHoldBools.empty());
    }

    Internal::PointersT newStackEntry() {
        std::lock_guard<std::mutex> lock(dequesMutex);
        threadStacks.emplace_back();
        threadStackMutexes.emplace_back();
        threadCounters.emplace_back();
        threadCounters.back().store(0);
        ptrsHoldBools.emplace_back();
        ptrsHoldBools.back().store(true);

        return {&threadStacks.back(), &threadStackMutexes.back(),
                &threadCounters.back(), &ptrsHoldBools.back()};
    }
};

}  // namespace EC

#endif
<|endoftext|>


<commit_before>#ifndef CS_MATH_EXT
#include "../extension.hpp"
#endif
#include "../cni.hpp"
static cs::extension math_ext;
namespace math_cs_ext {
	using namespace cs;
	number abs(number n)
	{
		return std::abs(n);
	}
	number ln(number n)
	{
		return std::log(n);
	}
	number log10(number n)
	{
		return std::log10(n);
	}
	number log(number a,number b)
	{
		return std::log(b/a);
	}
	number sin(number n)
	{
		return std::sin(n);
	}
	number cos(number n)
	{
		return std::cos(n);
	}
	number tan(number n)
	{
		return std::tan(n);
	}
	number asin(number n)
	{
		return std::asin(n);
	}
	number acos(number n)
	{
		return std::acos(n);
	}
	number atan(number n)
	{
		return std::atan(n);
	}
	number sqrt(number n)
	{
		return std::sqrt(n);
	}
	number root(number a,number b)
	{
		return std::pow(a,number(1)/b);
	}
	number pow(number a,number b)
	{
		return std::pow(a,b);
	}
	void init()
	{
		math_ext.add_var("pi",cov::any::make_constant<number>(3.1415926535));
		math_ext.add_var("e",cov::any::make_constant<number>(2.7182818284));
		math_ext.add_var("abs",cov::any::make_protect<native_interface>(cni(abs),true));
		math_ext.add_var("ln",cov::any::make_protect<native_interface>(cni(ln),true));
		math_ext.add_var("log10",cov::any::make_protect<native_interface>(cni(log10),true));
		math_ext.add_var("log",cov::any::make_protect<native_interface>(cni(log),true));
		math_ext.add_var("sin",cov::any::make_protect<native_interface>(cni(sin),true));
		math_ext.add_var("cos",cov::any::make_protect<native_interface>(cni(cos),true));
		math_ext.add_var("tan",cov::any::make_protect<native_interface>(cni(tan),true));
		math_ext.add_var("asin",cov::any::make_protect<native_interface>(cni(asin),true));
		math_ext.add_var("acos",cov::any::make_protect<native_interface>(cni(acos),true));
		math_ext.add_var("atan",cov::any::make_protect<native_interface>(cni(atan),true));
		math_ext.add_var("sqrt",cov::any::make_protect<native_interface>(cni(sqrt),true));
		math_ext.add_var("root",cov::any::make_protect<native_interface>(cni(root),true));
		math_ext.add_var("pow",cov::any::make_protect<native_interface>(cni(pow),true));
	}
}
#ifndef CS_MATH_EXT
cs::extension* cs_extension()
{
	math_cs_ext::init();
	return &math_ext;
}
#endif
<commit_msg>支持min max函数<commit_after>#ifndef CS_MATH_EXT
#include "../extension.hpp"
#endif
#include "../cni.hpp"
#include <algorithm>
static cs::extension math_ext;
namespace math_cs_ext {
	using namespace cs;
	number abs(number n)
	{
		return std::abs(n);
	}
	number ln(number n)
	{
		return std::log(n);
	}
	number log10(number n)
	{
		return std::log10(n);
	}
	number log(number a,number b)
	{
		return std::log(b/a);
	}
	number sin(number n)
	{
		return std::sin(n);
	}
	number cos(number n)
	{
		return std::cos(n);
	}
	number tan(number n)
	{
		return std::tan(n);
	}
	number asin(number n)
	{
		return std::asin(n);
	}
	number acos(number n)
	{
		return std::acos(n);
	}
	number atan(number n)
	{
		return std::atan(n);
	}
	number sqrt(number n)
	{
		return std::sqrt(n);
	}
	number root(number a,number b)
	{
		return std::pow(a,number(1)/b);
	}
	number pow(number a,number b)
	{
		return std::pow(a,b);
	}
	number min(number a,number b)
	{
		return std::min(a,b);
	}
	number max(number a,number b)
	{
		return std::max(a,b);
	}
	void init()
	{
		math_ext.add_var("pi",cov::any::make_constant<number>(3.1415926535));
		math_ext.add_var("e",cov::any::make_constant<number>(2.7182818284));
		math_ext.add_var("abs",cov::any::make_protect<native_interface>(cni(abs),true));
		math_ext.add_var("ln",cov::any::make_protect<native_interface>(cni(ln),true));
		math_ext.add_var("log10",cov::any::make_protect<native_interface>(cni(log10),true));
		math_ext.add_var("log",cov::any::make_protect<native_interface>(cni(log),true));
		math_ext.add_var("sin",cov::any::make_protect<native_interface>(cni(sin),true));
		math_ext.add_var("cos",cov::any::make_protect<native_interface>(cni(cos),true));
		math_ext.add_var("tan",cov::any::make_protect<native_interface>(cni(tan),true));
		math_ext.add_var("asin",cov::any::make_protect<native_interface>(cni(asin),true));
		math_ext.add_var("acos",cov::any::make_protect<native_interface>(cni(acos),true));
		math_ext.add_var("atan",cov::any::make_protect<native_interface>(cni(atan),true));
		math_ext.add_var("sqrt",cov::any::make_protect<native_interface>(cni(sqrt),true));
		math_ext.add_var("root",cov::any::make_protect<native_interface>(cni(root),true));
		math_ext.add_var("pow",cov::any::make_protect<native_interface>(cni(pow),true));
		math_ext.add_var("min",cov::any::make_protect<native_interface>(cni(min),true));
		math_ext.add_var("max",cov::any::make_protect<native_interface>(cni(max),true));
	}
}
#ifndef CS_MATH_EXT
cs::extension* cs_extension()
{
	math_cs_ext::init();
	return &math_ext;
}
#endif
<|endoftext|>


<commit_before>
// Boat.cpp

// Implements the cBoat class representing a boat in the world

#include "Globals.h"
#include "Boat.h"
#include "../BlockInfo.h"
#include "../World.h"
#include "../ClientHandle.h"
#include "Player.h"

cBoat::cBoat(Vector3d a_Pos, eMaterial a_Material) :
	Super(etBoat, a_Pos, 0.98, 0.7),
	m_LastDamage(0), m_ForwardDirection(0),
	m_DamageTaken(0.0f), m_Material(a_Material),
	m_RightPaddleUsed(false), m_LeftPaddleUsed(false)
{
	SetMass(20.0f);
	SetGravity(-16.0f);
	SetAirDrag(0.05f);
	SetMaxHealth(6);
	SetHealth(6);
}

void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
{
	a_ClientHandle.SendSpawnEntity(*this);
	a_ClientHandle.SendEntityMetadata(*this);  // Boat colour
}

void cBoat::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
	// Cannot use super::BroadcastMovementUpdate here, broadcasting position when not
	// expected by the client breaks things. See https://github.com/cuberite/cuberite/pull/4488

	// Process packet sending every two ticks
	if (GetWorld()->GetWorldAge() % 2 != 0)
	{
		return;
	}

	Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor();
	if (Diff.HasNonZeroLength())  // Have we moved?
	{
		m_World->BroadcastEntityPosition(*this, a_Exclude);
		m_LastSentPosition = GetPosition();
		m_bDirtyOrientation = false;
	}
}

bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
{
	m_LastDamage = 10;
	if (!Super::DoTakeDamage(TDI))
	{
		return false;
	}

	m_World->BroadcastEntityMetadata(*this);

	if (GetHealth() <= 0)
	{
		if (TDI.Attacker != nullptr)
		{
			if (TDI.Attacker->IsPlayer())
			{
				cItems Pickups;
				Pickups.Add(MaterialToItem(m_Material));
				m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 0, 0, 0, true);
			}
		}
		Destroy();
	}
	return true;
}

void cBoat::OnRightClicked(cPlayer & a_Player)
{
	Super::OnRightClicked(a_Player);

	if (m_Attachee != nullptr)
	{
		if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
		{
			// This player is already sitting in, they want out.
			a_Player.Detach();
			return;
		}

		if (m_Attachee->IsPlayer())
		{
			// Another player is already sitting in here, cannot attach
			return;
		}

		// Detach whatever is sitting in this boat now:
		m_Attachee->Detach();
	}

	// Attach the player to this boat
	a_Player.AttachTo(this);
}

void cBoat::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	Super::Tick(a_Dt, a_Chunk);
	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}
	BroadcastMovementUpdate();

	SetSpeed(GetSpeed() * 0.97);  // Slowly decrease the speed

	if ((POSY_TOINT < 0) || (POSY_TOINT >= cChunkDef::Height))
	{
		return;
	}

	if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT)))
	{
		if (GetSpeedY() < 2)
		{
			AddSpeedY(0.2);
		}
	}

	if (GetLastDamage() > 0)
	{
		SetLastDamage(GetLastDamage() - 1);
	}
}

void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
{
	if (GetSpeed().Length() > 7.5)
	{
		return;
	}

	Vector3d ToAddSpeed = m_Attachee->GetLookVector() * (a_Sideways * 0.4) ;
	ToAddSpeed.y = 0;

	AddSpeed(ToAddSpeed);
}

void cBoat::SetLastDamage(int TimeSinceLastHit)
{
	m_LastDamage = TimeSinceLastHit;

	// Tell the client to play the shaking animation
	m_World->BroadcastEntityMetadata(*this);
}

void cBoat::UpdatePaddles(bool a_RightPaddleUsed, bool a_LeftPaddleUsed)
{
	// Avoid telling client what it already knows since it may reset animation 1.13+
	const bool Changed = (m_RightPaddleUsed != a_RightPaddleUsed) || (m_LeftPaddleUsed != a_LeftPaddleUsed);

	m_RightPaddleUsed = a_RightPaddleUsed;
	m_LeftPaddleUsed = a_LeftPaddleUsed;

	if (Changed)
	{
		m_World->BroadcastEntityMetadata(*this);
	}
}

cBoat::eMaterial cBoat::ItemToMaterial(const cItem & a_Item)
{
	switch (a_Item.m_ItemType)
	{
		case E_ITEM_BOAT:          return bmOak;
		case E_ITEM_SPRUCE_BOAT:   return bmSpruce;
		case E_ITEM_BIRCH_BOAT:    return bmBirch;
		case E_ITEM_JUNGLE_BOAT:   return bmJungle;
		case E_ITEM_ACACIA_BOAT:   return bmAcacia;
		case E_ITEM_DARK_OAK_BOAT: return bmDarkOak;
		default:
		{
			LOGWARNING("%s: Item type not handled %d.", __FUNCTION__, a_Item.m_ItemType);
			return cBoat::bmOak;
		}
	}
}

AString cBoat::MaterialToString(eMaterial a_Material)
{
	switch (a_Material)
	{
		case bmOak:     return "oak";
		case bmSpruce:  return "spruce";
		case bmBirch:   return "birch";
		case bmJungle:  return "jungle";
		case bmAcacia:  return "acacia";
		case bmDarkOak: return "dark_oak";
	}
	UNREACHABLE("Unsupported boat material");
}

cBoat::eMaterial cBoat::StringToMaterial(const AString & a_Material)
{
	if (a_Material == "oak")
	{
		return bmOak;
	}
	else if (a_Material == "spruce")
	{
		return bmSpruce;
	}
	else if (a_Material == "birch")
	{
		return bmBirch;
	}
	else if (a_Material == "jungle")
	{
		return bmJungle;
	}
	else if (a_Material == "acacia")
	{
		return bmAcacia;
	}
	else if (a_Material == "dark_oak")
	{
		return bmDarkOak;
	}
	else
	{
		return bmOak;
	}
}

cItem cBoat::MaterialToItem(eMaterial a_Material)
{
	switch (a_Material)
	{
		case bmOak:     return cItem(E_ITEM_BOAT);
		case bmSpruce:  return cItem(E_ITEM_SPRUCE_BOAT);
		case bmBirch:   return cItem(E_ITEM_BIRCH_BOAT);
		case bmJungle:  return cItem(E_ITEM_JUNGLE_BOAT);
		case bmAcacia:  return cItem(E_ITEM_ACACIA_BOAT);
		case bmDarkOak: return cItem(E_ITEM_DARK_OAK_BOAT);
	}
	UNREACHABLE("Unsupported boat material");
}

<commit_msg>Creative mode hits immediately disappear boats (#5117)<commit_after>
// Boat.cpp

// Implements the cBoat class representing a boat in the world

#include "Globals.h"
#include "Boat.h"
#include "../BlockInfo.h"
#include "../World.h"
#include "../ClientHandle.h"
#include "Player.h"

cBoat::cBoat(Vector3d a_Pos, eMaterial a_Material) :
	Super(etBoat, a_Pos, 0.98, 0.7),
	m_LastDamage(0), m_ForwardDirection(0),
	m_DamageTaken(0.0f), m_Material(a_Material),
	m_RightPaddleUsed(false), m_LeftPaddleUsed(false)
{
	SetMass(20.0f);
	SetGravity(-16.0f);
	SetAirDrag(0.05f);
	SetMaxHealth(6);
	SetHealth(6);
}

void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
{
	a_ClientHandle.SendSpawnEntity(*this);
	a_ClientHandle.SendEntityMetadata(*this);  // Boat colour
}

void cBoat::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
{
	// Cannot use super::BroadcastMovementUpdate here, broadcasting position when not
	// expected by the client breaks things. See https://github.com/cuberite/cuberite/pull/4488

	// Process packet sending every two ticks
	if (GetWorld()->GetWorldAge() % 2 != 0)
	{
		return;
	}

	Vector3i Diff = (GetPosition() * 32.0).Floor() - (m_LastSentPosition * 32.0).Floor();
	if (Diff.HasNonZeroLength())  // Have we moved?
	{
		m_World->BroadcastEntityPosition(*this, a_Exclude);
		m_LastSentPosition = GetPosition();
		m_bDirtyOrientation = false;
	}
}

bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
{
	m_LastDamage = 10;
	if (!Super::DoTakeDamage(TDI))
	{
		return false;
	}

	m_World->BroadcastEntityMetadata(*this);

	if ((TDI.Attacker != nullptr) && (TDI.Attacker->IsPlayer()))
	{
		cPlayer * Destroyer = static_cast<cPlayer *>(TDI.Attacker);
		if (Destroyer->IsGameModeCreative())
		{
			Destroy();
			return true;
		}
	}

	if (GetHealth() <= 0)
	{
		if (TDI.Attacker != nullptr)
		{
			if (TDI.Attacker->IsPlayer())
			{
				cItems Pickups;
				Pickups.Add(MaterialToItem(m_Material));
				m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 0, 0, 0, true);
			}
		}
		Destroy();
	}
	return true;
}

void cBoat::OnRightClicked(cPlayer & a_Player)
{
	Super::OnRightClicked(a_Player);

	if (m_Attachee != nullptr)
	{
		if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
		{
			// This player is already sitting in, they want out.
			a_Player.Detach();
			return;
		}

		if (m_Attachee->IsPlayer())
		{
			// Another player is already sitting in here, cannot attach
			return;
		}

		// Detach whatever is sitting in this boat now:
		m_Attachee->Detach();
	}

	// Attach the player to this boat
	a_Player.AttachTo(this);
}

void cBoat::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	Super::Tick(a_Dt, a_Chunk);
	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}
	BroadcastMovementUpdate();

	SetSpeed(GetSpeed() * 0.97);  // Slowly decrease the speed

	if ((POSY_TOINT < 0) || (POSY_TOINT >= cChunkDef::Height))
	{
		return;
	}

	if (IsBlockWater(m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT)))
	{
		if (GetSpeedY() < 2)
		{
			AddSpeedY(0.2);
		}
	}

	if (GetLastDamage() > 0)
	{
		SetLastDamage(GetLastDamage() - 1);
	}
}

void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways)
{
	if (GetSpeed().Length() > 7.5)
	{
		return;
	}

	Vector3d ToAddSpeed = m_Attachee->GetLookVector() * (a_Sideways * 0.4) ;
	ToAddSpeed.y = 0;

	AddSpeed(ToAddSpeed);
}

void cBoat::SetLastDamage(int TimeSinceLastHit)
{
	m_LastDamage = TimeSinceLastHit;

	// Tell the client to play the shaking animation
	m_World->BroadcastEntityMetadata(*this);
}

void cBoat::UpdatePaddles(bool a_RightPaddleUsed, bool a_LeftPaddleUsed)
{
	// Avoid telling client what it already knows since it may reset animation 1.13+
	const bool Changed = (m_RightPaddleUsed != a_RightPaddleUsed) || (m_LeftPaddleUsed != a_LeftPaddleUsed);

	m_RightPaddleUsed = a_RightPaddleUsed;
	m_LeftPaddleUsed = a_LeftPaddleUsed;

	if (Changed)
	{
		m_World->BroadcastEntityMetadata(*this);
	}
}

cBoat::eMaterial cBoat::ItemToMaterial(const cItem & a_Item)
{
	switch (a_Item.m_ItemType)
	{
		case E_ITEM_BOAT:          return bmOak;
		case E_ITEM_SPRUCE_BOAT:   return bmSpruce;
		case E_ITEM_BIRCH_BOAT:    return bmBirch;
		case E_ITEM_JUNGLE_BOAT:   return bmJungle;
		case E_ITEM_ACACIA_BOAT:   return bmAcacia;
		case E_ITEM_DARK_OAK_BOAT: return bmDarkOak;
		default:
		{
			LOGWARNING("%s: Item type not handled %d.", __FUNCTION__, a_Item.m_ItemType);
			return cBoat::bmOak;
		}
	}
}

AString cBoat::MaterialToString(eMaterial a_Material)
{
	switch (a_Material)
	{
		case bmOak:     return "oak";
		case bmSpruce:  return "spruce";
		case bmBirch:   return "birch";
		case bmJungle:  return "jungle";
		case bmAcacia:  return "acacia";
		case bmDarkOak: return "dark_oak";
	}
	UNREACHABLE("Unsupported boat material");
}

cBoat::eMaterial cBoat::StringToMaterial(const AString & a_Material)
{
	if (a_Material == "oak")
	{
		return bmOak;
	}
	else if (a_Material == "spruce")
	{
		return bmSpruce;
	}
	else if (a_Material == "birch")
	{
		return bmBirch;
	}
	else if (a_Material == "jungle")
	{
		return bmJungle;
	}
	else if (a_Material == "acacia")
	{
		return bmAcacia;
	}
	else if (a_Material == "dark_oak")
	{
		return bmDarkOak;
	}
	else
	{
		return bmOak;
	}
}

cItem cBoat::MaterialToItem(eMaterial a_Material)
{
	switch (a_Material)
	{
		case bmOak:     return cItem(E_ITEM_BOAT);
		case bmSpruce:  return cItem(E_ITEM_SPRUCE_BOAT);
		case bmBirch:   return cItem(E_ITEM_BIRCH_BOAT);
		case bmJungle:  return cItem(E_ITEM_JUNGLE_BOAT);
		case bmAcacia:  return cItem(E_ITEM_ACACIA_BOAT);
		case bmDarkOak: return cItem(E_ITEM_DARK_OAK_BOAT);
	}
	UNREACHABLE("Unsupported boat material");
}

<|endoftext|>


<commit_before>/*=======================================================================\
#                                                                        $
#   Copyright (C) 2010 Nokia Corporation.                                $
#                                                                        $
#   Author: Ilya Dogolazky <ilya.dogolazky@nokia.com>                    $
#                                                                        $
#     This file is part of qmlog                                         $
#                                                                        $
#     qmlog is free software; you can redistribute it and/or modify      $
#     it under the terms of the GNU Lesser General Public License        $
#     version 2.1 as published by the Free Software Foundation.          $
#                                                                        $
#     qmlog 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 qmlog. If not, see http://www.gnu.org/licenses/   $
\_______________________________________________________________________*/

#define _BSD_SOURCE

#include <cassert>

#include "FileLoggerDev.h"
#include "log_t.h"

FileLoggerDev::FileLoggerDev(const char *aFileName, int aVerbosityLevel, int aLocationMask, int aMessageFormat)
  : LoggerDev(aVerbosityLevel, aLocationMask, aMessageFormat)
  , iFp(NULL)
  , iIsFpOwner(false)
{
  assert(aFileName);
  iFp = fopen(aFileName, "aw");
  iIsFpOwner = iFp;
}

FileLoggerDev::~FileLoggerDev()
{
  if(iIsFpOwner && iFp)
  {
    fclose(iFp);
    iFp = NULL;
  }
}

FileLoggerDev::FileLoggerDev(FILE *aFp, bool aTakeOwnership, int aVerbosityLevel, int aLocationMask, int aMessageFormat)
  : LoggerDev(aVerbosityLevel, aLocationMask, aMessageFormat)
  , iFp(aFp)
  , iIsFpOwner(aTakeOwnership)
{
}

void FileLoggerDev::printLog( int aLevel, const char *aDateTimeInfo, const char* aProcessInfo,
                              const char *aDebugInfo, bool aIsFullDebugInfo, const char *aMessage) const
{
  //TODO rework: create format string for output as in SysLogDev
  bool hasPrefix = vlogPrefixes(aDateTimeInfo, aProcessInfo);
  bool hasDebugInfo = vlogDebugInfo(aLevel, aDebugInfo, hasPrefix);
  bool hasMessage = (aMessage && aMessage[0] != 0);

  if(hasMessage)
  {
    //TODO probably better to use (hasDebugInfo && settings().isFunc())
    //instead of aIsFullDebugInfo
    // aIsFullDebugInfo shall be romove everywhere in this case
    if(aIsFullDebugInfo && settings().isWordWrap())
    {
      fprintf(iFp, ":\n");
      hasPrefix = vlogPrefixes(aDateTimeInfo, aProcessInfo);
      fprintf(iFp, " ->");
    }
    else if(hasDebugInfo)
    {
      fprintf(iFp, ":");
    }

    fprintf(iFp, " %s", aMessage);
  }
  else if(hasDebugInfo)
  {
    fprintf(iFp, ".");
  }

  fprintf(iFp, "\n");
  fflush(iFp);
}

bool FileLoggerDev::vlogPrefixes(const char *aDateTimeInfo, const char* aProcessInfo) const
{
  bool hasDateTimeInfo = (aDateTimeInfo && aDateTimeInfo[0] != 0);
  bool hasProcessInfo = (aProcessInfo && aProcessInfo[0] != 0);

  if(hasDateTimeInfo)
  {
    fprintf(iFp, "[%s]", aDateTimeInfo);
  }

  if(hasProcessInfo)
  {
    fprintf(iFp, hasDateTimeInfo? " [%s]": "%s:", aProcessInfo);
  }

  return (hasDateTimeInfo | hasProcessInfo);
}

bool FileLoggerDev::vlogDebugInfo(int aLevel, const char *aDebugInfo, bool aPrefixExists) const
{
  bool hasDebugInfo = (aDebugInfo && aDebugInfo[0] != 0);

  fprintf(iFp, (hasDebugInfo && settings().isFileLine())? (aPrefixExists? " %s at": "%s at"):
                                                          (aPrefixExists? " %s":"%s"), log_t::level_name(aLevel));

  if(hasDebugInfo)
  {
    fprintf(iFp, aPrefixExists? " %s": "%s", aDebugInfo);
  }
  else
  {
    fprintf(iFp, ":");
  }

  return hasDebugInfo;
}
<commit_msg>[REWORK] Crash for file open error case is fixed in file logger<commit_after>/*=======================================================================\
#                                                                        $
#   Copyright (C) 2010 Nokia Corporation.                                $
#                                                                        $
#   Author: Ilya Dogolazky <ilya.dogolazky@nokia.com>                    $
#                                                                        $
#     This file is part of qmlog                                         $
#                                                                        $
#     qmlog is free software; you can redistribute it and/or modify      $
#     it under the terms of the GNU Lesser General Public License        $
#     version 2.1 as published by the Free Software Foundation.          $
#                                                                        $
#     qmlog 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 qmlog. If not, see http://www.gnu.org/licenses/   $
\_______________________________________________________________________*/

#define _BSD_SOURCE

#include <cassert>

#include "FileLoggerDev.h"
#include "log_t.h"
#include "log-interface.h"

FileLoggerDev::FileLoggerDev(const char *aFileName, int aVerbosityLevel, int aLocationMask, int aMessageFormat)
  : LoggerDev(aVerbosityLevel, aLocationMask, aMessageFormat)
  , iFp(NULL)
  , iIsFpOwner(false)
{
  assert(aFileName);
  iFp = fopen(aFileName, "aw");
  if(!iFp) log_warning("Failed to create file %s for file logger. Logger disabled.", aFileName);
  iIsFpOwner = iFp;
}

FileLoggerDev::~FileLoggerDev()
{
  if(iIsFpOwner && iFp)
  {
    fclose(iFp);
    iFp = NULL;
  }
}

FileLoggerDev::FileLoggerDev(FILE *aFp, bool aTakeOwnership, int aVerbosityLevel, int aLocationMask, int aMessageFormat)
  : LoggerDev(aVerbosityLevel, aLocationMask, aMessageFormat)
  , iFp(aFp)
  , iIsFpOwner(aTakeOwnership)
{
  if(!iFp) log_warning("Null file descriptor is received by file logger protected constructor. Logger disabled.");
}

void FileLoggerDev::printLog( int aLevel, const char *aDateTimeInfo, const char* aProcessInfo,
                              const char *aDebugInfo, bool aIsFullDebugInfo, const char *aMessage) const
{
  if(!iFp) return;
  //TODO rework: create format string for output as in SysLogDev
  bool hasPrefix = vlogPrefixes(aDateTimeInfo, aProcessInfo);
  bool hasDebugInfo = vlogDebugInfo(aLevel, aDebugInfo, hasPrefix);
  bool hasMessage = (aMessage && aMessage[0] != 0);

  if(hasMessage)
  {
    //TODO probably better to use (hasDebugInfo && settings().isFunc())
    //instead of aIsFullDebugInfo
    // aIsFullDebugInfo shall be romove everywhere in this case
    if(aIsFullDebugInfo && settings().isWordWrap())
    {
      fprintf(iFp, ":\n");
      hasPrefix = vlogPrefixes(aDateTimeInfo, aProcessInfo);
      fprintf(iFp, " ->");
    }
    else if(hasDebugInfo)
    {
      fprintf(iFp, ":");
    }

    fprintf(iFp, " %s", aMessage);
  }
  else if(hasDebugInfo)
  {
    fprintf(iFp, ".");
  }

  fprintf(iFp, "\n");
  fflush(iFp);
}

bool FileLoggerDev::vlogPrefixes(const char *aDateTimeInfo, const char* aProcessInfo) const
{
  if(!iFp) return false;

  bool hasDateTimeInfo = (aDateTimeInfo && aDateTimeInfo[0] != 0);
  bool hasProcessInfo = (aProcessInfo && aProcessInfo[0] != 0);

  if(hasDateTimeInfo)
  {
    fprintf(iFp, "[%s]", aDateTimeInfo);
  }

  if(hasProcessInfo)
  {
    fprintf(iFp, hasDateTimeInfo? " [%s]": "%s:", aProcessInfo);
  }

  return (hasDateTimeInfo | hasProcessInfo);
}

bool FileLoggerDev::vlogDebugInfo(int aLevel, const char *aDebugInfo, bool aPrefixExists) const
{
  if(!iFp) return false;

  bool hasDebugInfo = (aDebugInfo && aDebugInfo[0] != 0);

  fprintf(iFp, (hasDebugInfo && settings().isFileLine())? (aPrefixExists? " %s at": "%s at"):
                                                          (aPrefixExists? " %s":"%s"), log_t::level_name(aLevel));

  if(hasDebugInfo)
  {
    fprintf(iFp, aPrefixExists? " %s": "%s", aDebugInfo);
  }
  else
  {
    fprintf(iFp, ":");
  }

  return hasDebugInfo;
}
<|endoftext|>