<commit_before>#include "atom.h"
#include "details/ir/sequence.h"
#include "details/atom/classdef-table.h"
#include "details/atom/classdef-table-view.h"
#include "details/reporting/report.h"

using namespace Yuni;

namespace Nany
{

	Atom::Atom(const AnyString& name, Atom::Type type)
		: type(type)
		, name(name)
	{}

	Atom::Atom(Atom& rootparent, const AnyString& name, Atom::Type type)
		: type(type)
		, parent(&rootparent)
		, name(name)
	{
		rootparent.pChildren.insert(std::pair<AnyString, Atom::Ptr>(name, this));
	}

	Atom::~Atom()
	{
		assert(instances.size() == pSymbolInstances.size());
		if (opcodes.owned)
			delete opcodes.sequence;
	}

	uint32_t Atom::findInstance(IR::Sequence*& sequence, Signature& signature)
	{
		auto it = pInstancesBySign.find(signature);
		if (it != pInstancesBySign.end())
		{
			sequence = it->second.second;

			auto& storedRetType = it->first.returnType;
			signature.returnType.import(storedRetType);
			signature.returnType.qualifiers = storedRetType.qualifiers;
			return it->second.first;
		}
		return (uint32_t) -1;
	}

	bool Atom::canAccessTo(const Atom& atom) const
	{
		// same ancestor ? requesting access to a namespace ?
		if ((parent == atom.parent) or (atom.type == Type::namespacedef))
			return true;

		// get if the targets are identical
		if (origin.target == atom.origin.target)
		{
			// determining whether the current atom is an ancestor of the provided one
			// TODO fix accessibility (with visibility)
			return true;
		}
		else
		{
			// not on the same target ? Only public elements are accessible
			return atom.isPublicOrPublished();
		}
		return false; // fallback
	}

	void Atom::printFullname(Yuni::String& out, bool clearBefore) const
	{
		if (clearBefore)
			out.clear();

		if (parent)
		{
			if (parent->parent)
			{
				parent->printFullname(out, false);
				out += '.';
			}

			if (name.first() != '^')
			{
				out += name;
			}
			else
			{
				if (name.startsWith("^default-var-%"))
				{
					AnyString sub{name.c_str() + 14, name.size() - 14};
					auto ix = sub.find('-');

					if (ix < sub.size())
					{
						++ix;
						AnyString varname{sub.c_str() + ix, sub.size() - ix};
						out << varname;
					}
					else
						out << "<invalid-field>";
				}
				else
					out.append(name.c_str() + 1, name.size() - 1);
			}
		}
	}

	template<class T>
	void Atom::doAppendCaption(YString& out, const T* table) const
	{
		printFullname(out, false);

		switch (type)
		{
			case Type::funcdef:
			{
				if (name.startsWith("^default-var-%")) // keep it simple
					break;

				out << '(';
				bool first = true;

				for (uint i = 0; i != parameters.size(); ++i)
				{
					AnyString paramname = parameters.name(i);

					// avoid the first virtual parameter
					if (i == 0 and paramname == "self")
						continue;

					if (not first)
						out << ", ";
					first = false;

					out << paramname;

					const Vardef& vardef = parameters.vardef(i);
					if (table)
					{
						if (table) // and table->hasClassdef(vardef.clid))
						{
							out << ": ";
							table->classdef(vardef.clid).print(out, *table, false);
						}
						else
							out << ": void";
					}
					else
					{
						if (not vardef.clid.isVoid())
							out << ": any";
						else
							out << ": void";
					}
				}
				out << ')';

				if (table)
				{
					if (not returnType.clid.isVoid() and table->hasClassdef(returnType.clid))
					{
						out.write(": ", 2);
						table->classdef(returnType.clid).print(out, *table, false);
						break;
					}
				}
				else
				{
					out << ((returnType.clid.isVoid()) ? ": void" : ": ref");
					break;
				}

				// no return type
				out.write(": void", 6);
				break;
			}

			case Type::classdef:
			case Type::namespacedef:
			case Type::vardef:
				break;
		}
	}

	void Atom::appendCaption(YString& out) const
	{
		doAppendCaption<ClassdefTableView>(out, nullptr);
	}

	void Atom::appendCaption(YString& out, const ClassdefTableView& table) const
	{
		doAppendCaption(out, &table);
	}

	inline void Atom::doPrint(Logs::Report& report, const ClassdefTableView& table, uint depth) const
	{
		auto entry = report.trace();
		for (uint i = depth; i--; )
			entry.message.prefix << "    ";

		if (parent != nullptr)
		{
			entry.message.prefix << table.keyword(*this) << ' ';
			appendCaption(entry.data().message, table);
			entry << " [id:" << atomid;
			if (isMemberVariable())
				entry << ", field: " << varinfo.effectiveFieldIndex;
			entry << ']';
		}
		else
			entry << "{global namespace}";

		++depth;
		for (auto& child: pChildren)
			child.second->doPrint(report, table, depth);

		if (Type::classdef == type)
			report.trace(); // for beauty
	}

	void Atom::print(Logs::Report& report, const ClassdefTableView& table) const
	{
		doPrint(report, table, 0);
	}

	bool Atom::performNameLookupOnChildren(std::vector<std::reference_wrapper<Atom>>& list, const AnyString& name)
	{
		assert(not name.empty());

		// the current scope
		Atom& scope = (nullptr == scopeForNameResolution) ? *this : *scopeForNameResolution;

		if (scope.isFunction() and name == "^()") // shorthand for function calls
		{
			list.push_back(std::ref(scope));
			return true;
		}

		bool success = false;
		scope.eachChild(name, [&](Atom& child) -> bool
		{
			list.push_back(std::ref(child));
			success = true;
			return true; // let's continue
		});

		return success;
	}

	bool Atom::performNameLookupFromParent(std::vector<std::reference_wrapper<Atom>>& list, const AnyString& name)
	{
		assert(not name.empty());

		// the current scope
		Atom& scope = (nullptr == scopeForNameResolution) ? *this : *scopeForNameResolution;

		// rule: do not continue if there are some matches and if the scope is a class
		// this is to avois spurious name resolution:
		//
		//     func foo() -> 42;
		//
		//     class SomeClass
		//     {
		//         func foo() -> 12;
		//         func bar -> foo(); // must resolve to `SomeClass.foo`, and not `foo`
		//     }
		//

		if (scope.parent)
		{
			// should start from the very bottom
			bool askToParentFirst = not scope.isClass();;
			if (askToParentFirst)
			{
				if (scope.parent->performNameLookupFromParent(list, name))
					return true;
			}

			// try to resolve locally
			bool found = scope.performNameLookupOnChildren(list, name);

			if (not found and (not askToParentFirst)) // try again
				found = scope.parent->performNameLookupFromParent(list, name);

			return found;
		}
		else
		{
			// try to resolve locally
			return scope.performNameLookupOnChildren(list, name);
		}

		return false;
	}

	uint32_t Atom::assignInvalidInstance(const Signature& signature)
	{
		pInstancesBySign.insert(std::make_pair(signature, std::make_pair((uint32_t) -1, nullptr)));
		return (uint32_t) -1;
	}

	uint32_t Atom::assignInstance(const Signature& signature, IR::Sequence* sequence, const AnyString& symbolname)
	{
		assert(sequence != nullptr);
		uint32_t iid = (uint32_t) instances.size();
		instances.emplace_back(sequence);
		pSymbolInstances.emplace_back(symbolname);
		pInstancesBySign.insert(std::make_pair(signature, std::make_pair(iid, sequence)));
		assert(instances.size() == pSymbolInstances.size());
		return iid;
	}

	void Atom::printInstances(Clob& out, const AtomMap& atommap) const
	{
		assert(instances.size() == pSymbolInstances.size());
		Clob prgm;

		for (size_t i = 0; i != instances.size(); ++i)
		{
			out << pSymbolInstances[i] << " // " << atomid << " #" << i << "\n{\n";

			instances[i].get()->print(prgm, &atommap);
			prgm.replace("\n", "\n    ");
			prgm.trimRight();
			out << prgm << "\n}\n";
		}
	}

	uint32_t Atom::findInstanceID(const IR::Sequence& sequence) const
	{
		for (size_t i = 0; i != instances.size(); ++i)
		{
			if (&sequence == instances[i].get())
				return static_cast<uint32_t>(i);
		}
		return (uint32_t) -1;
	}

	AnyString Atom::findInstanceCaption(const IR::Sequence& sequence) const
	{
		for (size_t i = 0; i != instances.size(); ++i)
		{
			if (&sequence == instances[i].get())
				return pSymbolInstances[i];
		}
		return AnyString{};
	}

	const Atom* Atom::findChildByMemberFieldID(uint32_t field) const
	{
		const Atom* ret = nullptr;
		eachChild([&](const Atom& child) -> bool
		{
			if (child.varinfo.fieldindex == field)
			{
				ret = &child;
				return false;
			}
			return true; // let's continue
		});
		return ret;
	}

	AnyString Atom::keyword() const
	{
		switch (type)
		{
			case Type::funcdef:
			{
				return (name[0] != '^')
					? "func"
					: ((not name.startsWith("^default-var-%"))
						? "operator"
						: "<default-init>");
			}
			case Type::classdef:     return "class";
			case Type::namespacedef: return "namespace";
			case Type::vardef:       return "var";
		}
		return "auto";
	}

	uint32_t Atom::findClassAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isClass())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	uint32_t Atom::findFuncAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isFunction())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	uint32_t Atom::findVarAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isMemberVariable())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	void Atom::renameChild(const AnyString& from, const AnyString& to)
	{
		Ptr child;
		auto range = pChildren.equal_range(from);
		for (auto it = range.first; it != range.second; )
		{
			if (unlikely(!!child)) // error
				return;
			child = it->second;
			it = pChildren.erase(it);
		}

		child->name = to;
		pChildren.insert(std::pair<AnyString, Atom::Ptr>(to, child));
	}

} // namespace Nany
<commit_msg>atom name: added extra space for operators (just for beauty)<commit_after>#include "atom.h"
#include "details/ir/sequence.h"
#include "details/atom/classdef-table.h"
#include "details/atom/classdef-table-view.h"
#include "details/reporting/report.h"

using namespace Yuni;

namespace Nany
{

	Atom::Atom(const AnyString& name, Atom::Type type)
		: type(type)
		, name(name)
	{}

	Atom::Atom(Atom& rootparent, const AnyString& name, Atom::Type type)
		: type(type)
		, parent(&rootparent)
		, name(name)
	{
		rootparent.pChildren.insert(std::pair<AnyString, Atom::Ptr>(name, this));
	}

	Atom::~Atom()
	{
		assert(instances.size() == pSymbolInstances.size());
		if (opcodes.owned)
			delete opcodes.sequence;
	}

	uint32_t Atom::findInstance(IR::Sequence*& sequence, Signature& signature)
	{
		auto it = pInstancesBySign.find(signature);
		if (it != pInstancesBySign.end())
		{
			sequence = it->second.second;

			auto& storedRetType = it->first.returnType;
			signature.returnType.import(storedRetType);
			signature.returnType.qualifiers = storedRetType.qualifiers;
			return it->second.first;
		}
		return (uint32_t) -1;
	}

	bool Atom::canAccessTo(const Atom& atom) const
	{
		// same ancestor ? requesting access to a namespace ?
		if ((parent == atom.parent) or (atom.type == Type::namespacedef))
			return true;

		// get if the targets are identical
		if (origin.target == atom.origin.target)
		{
			// determining whether the current atom is an ancestor of the provided one
			// TODO fix accessibility (with visibility)
			return true;
		}
		else
		{
			// not on the same target ? Only public elements are accessible
			return atom.isPublicOrPublished();
		}
		return false; // fallback
	}

	void Atom::printFullname(Yuni::String& out, bool clearBefore) const
	{
		if (clearBefore)
			out.clear();

		if (parent)
		{
			if (parent->parent)
			{
				parent->printFullname(out, false);
				out += '.';
			}

			if (name.first() != '^')
			{
				out += name;
			}
			else
			{
				if (name.startsWith("^default-var-%"))
				{
					AnyString sub{name.c_str() + 14, name.size() - 14};
					auto ix = sub.find('-');

					if (ix < sub.size())
					{
						++ix;
						AnyString varname{sub.c_str() + ix, sub.size() - ix};
						out << varname;
					}
					else
						out << "<invalid-field>";
				}
				else
					out.append(name.c_str() + 1, name.size() - 1);
			}
		}
	}

	template<class T>
	void Atom::doAppendCaption(YString& out, const T* table) const
	{
		printFullname(out, false);

		switch (type)
		{
			case Type::funcdef:
			{
				if (name.startsWith("^default-var-%")) // keep it simple
					break;

				if (name[0] == '^')
					out << ' ';
				out << '(';
				bool first = true;

				for (uint i = 0; i != parameters.size(); ++i)
				{
					AnyString paramname = parameters.name(i);

					// avoid the first virtual parameter
					if (i == 0 and paramname == "self")
						continue;

					if (not first)
						out << ", ";
					first = false;

					out << paramname;

					const Vardef& vardef = parameters.vardef(i);
					if (table)
					{
						if (table) // and table->hasClassdef(vardef.clid))
						{
							out << ": ";
							table->classdef(vardef.clid).print(out, *table, false);
						}
						else
							out << ": void";
					}
					else
					{
						if (not vardef.clid.isVoid())
							out << ": any";
						else
							out << ": void";
					}
				}
				out << ')';

				if (table)
				{
					if (not returnType.clid.isVoid() and table->hasClassdef(returnType.clid))
					{
						out.write(": ", 2);
						table->classdef(returnType.clid).print(out, *table, false);
						break;
					}
				}
				else
				{
					out << ((returnType.clid.isVoid()) ? ": void" : ": ref");
					break;
				}

				// no return type
				out.write(": void", 6);
				break;
			}

			case Type::classdef:
			case Type::namespacedef:
			case Type::vardef:
				break;
		}
	}

	void Atom::appendCaption(YString& out) const
	{
		doAppendCaption<ClassdefTableView>(out, nullptr);
	}

	void Atom::appendCaption(YString& out, const ClassdefTableView& table) const
	{
		doAppendCaption(out, &table);
	}

	inline void Atom::doPrint(Logs::Report& report, const ClassdefTableView& table, uint depth) const
	{
		auto entry = report.trace();
		for (uint i = depth; i--; )
			entry.message.prefix << "    ";

		if (parent != nullptr)
		{
			entry.message.prefix << table.keyword(*this) << ' ';
			appendCaption(entry.data().message, table);
			entry << " [id:" << atomid;
			if (isMemberVariable())
				entry << ", field: " << varinfo.effectiveFieldIndex;
			entry << ']';
		}
		else
			entry << "{global namespace}";

		++depth;
		for (auto& child: pChildren)
			child.second->doPrint(report, table, depth);

		if (Type::classdef == type)
			report.trace(); // for beauty
	}

	void Atom::print(Logs::Report& report, const ClassdefTableView& table) const
	{
		doPrint(report, table, 0);
	}

	bool Atom::performNameLookupOnChildren(std::vector<std::reference_wrapper<Atom>>& list, const AnyString& name)
	{
		assert(not name.empty());

		// the current scope
		Atom& scope = (nullptr == scopeForNameResolution) ? *this : *scopeForNameResolution;

		if (scope.isFunction() and name == "^()") // shorthand for function calls
		{
			list.push_back(std::ref(scope));
			return true;
		}

		bool success = false;
		scope.eachChild(name, [&](Atom& child) -> bool
		{
			list.push_back(std::ref(child));
			success = true;
			return true; // let's continue
		});

		return success;
	}

	bool Atom::performNameLookupFromParent(std::vector<std::reference_wrapper<Atom>>& list, const AnyString& name)
	{
		assert(not name.empty());

		// the current scope
		Atom& scope = (nullptr == scopeForNameResolution) ? *this : *scopeForNameResolution;

		// rule: do not continue if there are some matches and if the scope is a class
		// this is to avois spurious name resolution:
		//
		//     func foo() -> 42;
		//
		//     class SomeClass
		//     {
		//         func foo() -> 12;
		//         func bar -> foo(); // must resolve to `SomeClass.foo`, and not `foo`
		//     }
		//

		if (scope.parent)
		{
			// should start from the very bottom
			bool askToParentFirst = not scope.isClass();;
			if (askToParentFirst)
			{
				if (scope.parent->performNameLookupFromParent(list, name))
					return true;
			}

			// try to resolve locally
			bool found = scope.performNameLookupOnChildren(list, name);

			if (not found and (not askToParentFirst)) // try again
				found = scope.parent->performNameLookupFromParent(list, name);

			return found;
		}
		else
		{
			// try to resolve locally
			return scope.performNameLookupOnChildren(list, name);
		}

		return false;
	}

	uint32_t Atom::assignInvalidInstance(const Signature& signature)
	{
		pInstancesBySign.insert(std::make_pair(signature, std::make_pair((uint32_t) -1, nullptr)));
		return (uint32_t) -1;
	}

	uint32_t Atom::assignInstance(const Signature& signature, IR::Sequence* sequence, const AnyString& symbolname)
	{
		assert(sequence != nullptr);
		uint32_t iid = (uint32_t) instances.size();
		instances.emplace_back(sequence);
		pSymbolInstances.emplace_back(symbolname);
		pInstancesBySign.insert(std::make_pair(signature, std::make_pair(iid, sequence)));
		assert(instances.size() == pSymbolInstances.size());
		return iid;
	}

	void Atom::printInstances(Clob& out, const AtomMap& atommap) const
	{
		assert(instances.size() == pSymbolInstances.size());
		Clob prgm;

		for (size_t i = 0; i != instances.size(); ++i)
		{
			out << pSymbolInstances[i] << " // " << atomid << " #" << i << "\n{\n";

			instances[i].get()->print(prgm, &atommap);
			prgm.replace("\n", "\n    ");
			prgm.trimRight();
			out << prgm << "\n}\n";
		}
	}

	uint32_t Atom::findInstanceID(const IR::Sequence& sequence) const
	{
		for (size_t i = 0; i != instances.size(); ++i)
		{
			if (&sequence == instances[i].get())
				return static_cast<uint32_t>(i);
		}
		return (uint32_t) -1;
	}

	AnyString Atom::findInstanceCaption(const IR::Sequence& sequence) const
	{
		for (size_t i = 0; i != instances.size(); ++i)
		{
			if (&sequence == instances[i].get())
				return pSymbolInstances[i];
		}
		return AnyString{};
	}

	const Atom* Atom::findChildByMemberFieldID(uint32_t field) const
	{
		const Atom* ret = nullptr;
		eachChild([&](const Atom& child) -> bool
		{
			if (child.varinfo.fieldindex == field)
			{
				ret = &child;
				return false;
			}
			return true; // let's continue
		});
		return ret;
	}

	AnyString Atom::keyword() const
	{
		switch (type)
		{
			case Type::funcdef:
			{
				return (name[0] != '^')
					? "func"
					: ((not name.startsWith("^default-var-%"))
						? "operator"
						: "<default-init>");
			}
			case Type::classdef:     return "class";
			case Type::namespacedef: return "namespace";
			case Type::vardef:       return "var";
		}
		return "auto";
	}

	uint32_t Atom::findClassAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isClass())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	uint32_t Atom::findFuncAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isFunction())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	uint32_t Atom::findVarAtom(Atom*& out, const AnyString& name)
	{
		// first, try to find the dtor function
		Atom* atomA = nullptr;
		uint32_t count = 0;

		eachChild([&](Atom& child) -> bool
		{
			if (child.isMemberVariable())
			{
				if (child.name == name)
				{
					if (likely(atomA == nullptr))
					{
						atomA = &child;
					}
					else
					{
						count = 2;
						return false;
					}
				}
			}
			return true;
		});

		if (count != 0)
			return count;

		out = atomA;
		return atomA ? 1 : 0;
	}

	void Atom::renameChild(const AnyString& from, const AnyString& to)
	{
		Ptr child;
		auto range = pChildren.equal_range(from);
		for (auto it = range.first; it != range.second; )
		{
			if (unlikely(!!child)) // error
				return;
			child = it->second;
			it = pChildren.erase(it);
		}

		child->name = to;
		pChildren.insert(std::pair<AnyString, Atom::Ptr>(to, child));
	}

} // namespace Nany
<|endoftext|>


<commit_before><commit_msg>Gently down the stream,<commit_after><|endoftext|>


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

/*******************************************************************************
 * \file 	mavrinux.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Emulated board running on linux
 *
 ******************************************************************************/

#include "mavrinux.hpp"

extern "C"
{
	#include "print_util.h"
	#include "time_keeper.h"

	#include "servos.h"
	#include "servos_default_config.h"
}

static Serial_linux_io* p_uart_usb;
uint8_t serial2stream( stream_data_t data, uint8_t byte )
{
	p_uart_usb->write(&byte);
	return 0;
}

Mavrinux::Mavrinux(mavrinux_conf_t config):
	dynamic_model( Dynamic_model_quad_diag(servos) ),
	sim( Simulation(dynamic_model) ),
	imu( Imu(sim.accelerometer(), sim.gyroscope(), sim.magnetometer(), config.imu_config) ),
	adc_battery( Adc_dummy( 12.34f ) ),
	battery( Battery(adc_battery) ),
	spektrum_satellite( Spektrum_satellite(dsm_serial, dsm_receiver_pin, dsm_power_pin) ),
	file_flash( File_linux("flash.bin") )
	// file_flash( "flash.bin" )
{}

bool Mavrinux::init(void)
{
	bool init_success = true;
	bool ret;

	// -------------------------------------------------------------------------
	// Init UART3
	// -------------------------------------------------------------------------
	ret = debug_serial.init();
	init_success &= ret;

	// -------------------------------------------------------------------------
	// Init stream for USB debug stream TODO: remove
	p_uart_usb = &debug_serial;
	dbg_stream_.get = NULL;
	dbg_stream_.put = &serial2stream;
	dbg_stream_.flush = NULL;
	dbg_stream_.buffer_empty = NULL;
	dbg_stream_.data = NULL;
	print_util_dbg_print_init(&dbg_stream_);
	// -------------------------------------------------------------------------

	time_keeper_delay_ms(1000);

	print_util_dbg_sep('%');
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);
	print_util_dbg_print("[MAVRINUX] ...\r\n");
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init GPIO dsm receiver
	// -------------------------------------------------------------------------
	ret = dsm_receiver_pin.init();
	print_util_dbg_init_msg("[DSM RX PIN]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init GPIO dsm power
	// -------------------------------------------------------------------------
	ret = dsm_power_pin.init();
	print_util_dbg_init_msg("[DSM VCC PIN]", ret);
	init_success &= ret;

	// -------------------------------------------------------------------------
	// Init UDP serial
	// -------------------------------------------------------------------------
	ret = mavlink_serial.init();
	print_util_dbg_init_msg("[UDP]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init servos
	// -------------------------------------------------------------------------
	ret = servos_init( &servos, servos_default_config() );
	print_util_dbg_init_msg("[SERVOS]", ret);
	init_success &= ret;
	if( ret )
	{
		servos_set_value_failsafe( &servos );
	}
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init spektrum_satelitte
	// -------------------------------------------------------------------------
	ret = spektrum_satellite.init();
	print_util_dbg_init_msg("[SAT]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);
	print_util_dbg_init_msg("[MAVRINUX]", init_success);
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);

	return init_success;
}<commit_msg>Test for travis<commit_after>/*******************************************************************************
 * Copyright (c) 2009-2014, MAV'RIC Development Team
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 ******************************************************************************/

/*******************************************************************************
 * \file 	mavrinux.cpp
 *
 * \author 	MAV'RIC Team
 *
 * \brief 	Emulated board running on linux
 *
 ******************************************************************************/

#include "mavrinux.hpp"

extern "C"
{
	#include "print_util.h"
	#include "time_keeper.h"

	#include "servos.h"
	#include "servos_default_config.h"
}

static Serial_linux_io* p_uart_usb;
uint8_t serial2stream( stream_data_t data, uint8_t byte )
{
	p_uart_usb->write(&byte);
	return 0;
}

Mavrinux::Mavrinux(mavrinux_conf_t config):
	dynamic_model( Dynamic_model_quad_diag(servos) ),
	sim( Simulation(dynamic_model) ),
	imu( Imu(sim.accelerometer(), sim.gyroscope(), sim.magnetometer(), config.imu_config) ),
	adc_battery( Adc_dummy( 12.34f ) ),
	battery( Battery(adc_battery) ),
	spektrum_satellite( Spektrum_satellite(dsm_serial, dsm_receiver_pin, dsm_power_pin) ),
	// file_flash( File_linux("flash.bin") )
	file_flash( "flash.bin" )
{}

bool Mavrinux::init(void)
{
	bool init_success = true;
	bool ret;

	// -------------------------------------------------------------------------
	// Init UART3
	// -------------------------------------------------------------------------
	ret = debug_serial.init();
	init_success &= ret;

	// -------------------------------------------------------------------------
	// Init stream for USB debug stream TODO: remove
	p_uart_usb = &debug_serial;
	dbg_stream_.get = NULL;
	dbg_stream_.put = &serial2stream;
	dbg_stream_.flush = NULL;
	dbg_stream_.buffer_empty = NULL;
	dbg_stream_.data = NULL;
	print_util_dbg_print_init(&dbg_stream_);
	// -------------------------------------------------------------------------

	time_keeper_delay_ms(1000);

	print_util_dbg_sep('%');
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);
	print_util_dbg_print("[MAVRINUX] ...\r\n");
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init GPIO dsm receiver
	// -------------------------------------------------------------------------
	ret = dsm_receiver_pin.init();
	print_util_dbg_init_msg("[DSM RX PIN]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init GPIO dsm power
	// -------------------------------------------------------------------------
	ret = dsm_power_pin.init();
	print_util_dbg_init_msg("[DSM VCC PIN]", ret);
	init_success &= ret;

	// -------------------------------------------------------------------------
	// Init UDP serial
	// -------------------------------------------------------------------------
	ret = mavlink_serial.init();
	print_util_dbg_init_msg("[UDP]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init servos
	// -------------------------------------------------------------------------
	ret = servos_init( &servos, servos_default_config() );
	print_util_dbg_init_msg("[SERVOS]", ret);
	init_success &= ret;
	if( ret )
	{
		servos_set_value_failsafe( &servos );
	}
	time_keeper_delay_ms(100);

	// -------------------------------------------------------------------------
	// Init spektrum_satelitte
	// -------------------------------------------------------------------------
	ret = spektrum_satellite.init();
	print_util_dbg_init_msg("[SAT]", ret);
	init_success &= ret;
	time_keeper_delay_ms(100);

	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);
	print_util_dbg_init_msg("[MAVRINUX]", init_success);
	time_keeper_delay_ms(100);
	print_util_dbg_sep('-');
	time_keeper_delay_ms(100);

	return init_success;
}<|endoftext|>


<commit_before>/*!
 * \file xgboost.cpp
 * \brief bootser implementations
 * \author Tianqi Chen: tianqi.tchen@gmail.com
 */
// implementation of boosters go to here
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#include <climits>
#include "xgboost.h"
#include "../utils/xgboost_utils.h"
#include "../gbm-base/xgboost_base_model.h"
namespace xgboost{
    namespace booster{
        /*!
         * \brief create a gradient booster, given type of booster
         * \param booster_type type of gradient booster, can be used to specify implements
         * \return the pointer to the gradient booster created
         */
        IBooster *CreateBooster( int booster_type ){
            // TODO
            return NULL;
        }
    };
};

<commit_msg>add empty folder for regression. TODO<commit_after>/*!
 * \file xgboost.cpp
 * \brief bootser implementations
 * \author Tianqi Chen: tianqi.tchen@gmail.com
 */
// implementation of boosters go to here
#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE
#include <climits>
#include "xgboost.h"
#include "../utils/xgboost_utils.h"
#include "xgboost_gbmbase.h"
namespace xgboost{
    namespace booster{
        /*!
         * \brief create a gradient booster, given type of booster
         * \param booster_type type of gradient booster, can be used to specify implements
         * \return the pointer to the gradient booster created
         */
        IBooster *CreateBooster( int booster_type ){
            // TODO
            return NULL;
        }
    };
};

<|endoftext|>


<commit_before>#ifndef ARCH_RUNTIME_MESSAGE_HUB_HPP_
#define ARCH_RUNTIME_MESSAGE_HUB_HPP_

#include <pthread.h>
#include <strings.h>
#include "arch/runtime/system_event.hpp"
#include "containers/intrusive_list.hpp"
#include "utils.hpp"
#include "config/args.hpp"
#include "arch/runtime/event_queue.hpp"
#include "arch/runtime/runtime_utils.hpp"

class linux_thread_pool_t;

// TODO: perhaps we can issue cache prefetching commands to the CPU to
// speed up the process of sending messages across cores.

/* There is one message hub per thread, NOT one message hub for the entire program.

Each message hub stores messages that are going from that message hub's home thread to
other threads. It keeps a separate queue for messages destined for each other thread. */

struct linux_message_hub_t
{
public:
    typedef intrusive_list_t<linux_thread_message_t> msg_list_t;

public:
    linux_message_hub_t(linux_event_queue_t *queue, linux_thread_pool_t *thread_pool, int current_thread);

    /* For each thread, transfer messages from our msg_local_list for that thread to our
    msg_global_list for that thread */
    void push_messages();

    /* Schedules the given message to be sent to the given thread by pushing it onto our
    msg_local_list for that thread */
    void store_message(unsigned int nthread, linux_thread_message_t *msg);

    // Schedules the given message to be sent to the given thread.  However, these are not
    // guaranteed to be called in the same order relative to one another.
    void store_message_sometime(unsigned int nthread, linux_thread_message_t *msg);

    // Called by the thread pool when it needs to deliver a message from the main thread
    // (which does not have an event queue)
    void insert_external_message(linux_thread_message_t *msg);

    ~linux_message_hub_t();

private:
    // Does store_message or store_message_sometime, only without setting the reloop_count_ in
    // debug mode.
    void do_store_message(unsigned int nthread, linux_thread_message_t *msg);

    /* pull_messages should be called on thread N with N as its argument. (The argument is
    partially redundant.) It will cause the actual delivery of messages that originated
    on this->current_thread and are destined for thread N. It is (almost) the only method on
    linux_message_hub_t that is not called on the thread that the message hub belongs to. */
    void pull_messages(int thread);

    linux_event_queue_t *const queue_;
    linux_thread_pool_t *const thread_pool_;

    /* Queue for messages going from this->current_thread to other threads */
    struct thread_queue_t {
        //TODO this doesn't need to be a class anymore

        /* Messages are cached here before being pushed to the global list so that we don't
        have to acquire the spinlock as often */
        msg_list_t msg_local_list;
    } queues_[MAX_THREADS];

    msg_list_t incoming_messages_;
    pthread_spinlock_t incoming_messages_lock_;

    /* We keep one notify_t for each other message hub that we interact with. When it has
    messages for us, it signals the appropriate notify_t from our set of notify_ts. We get
    the notification and call push_messages on the sender in reply. */
    struct notify_t : public linux_event_callback_t
    {
    public:
        /* message_hubs[i]->notify[j].on_event() is called when thread #j has messages for
        thread #i. */
        void on_event(int events);

    public:
        /* hub->notify[j].notifier_thread == j */
        int notifier_thread;

        system_event_t event;                    // the eventfd to notify

        /* hub->notify[i].parent = hub */
        linux_message_hub_t *parent;
    };
    notify_t *notify_;

    /* The thread that we queue messages originating from. (Recall that there is one
    message_hub_t per thread.) */
    const unsigned int current_thread_;
};

#endif // ARCH_RUNTIME_MESSAGE_HUB_HPP_
<commit_msg>Made linux_message_hub_t be a class not a struct.<commit_after>#ifndef ARCH_RUNTIME_MESSAGE_HUB_HPP_
#define ARCH_RUNTIME_MESSAGE_HUB_HPP_

#include <pthread.h>
#include <strings.h>
#include "arch/runtime/system_event.hpp"
#include "containers/intrusive_list.hpp"
#include "utils.hpp"
#include "config/args.hpp"
#include "arch/runtime/event_queue.hpp"
#include "arch/runtime/runtime_utils.hpp"

class linux_thread_pool_t;

// TODO: perhaps we can issue cache prefetching commands to the CPU to
// speed up the process of sending messages across cores.

/* There is one message hub per thread, NOT one message hub for the entire program.

Each message hub stores messages that are going from that message hub's home thread to
other threads. It keeps a separate queue for messages destined for each other thread. */

class linux_message_hub_t {
public:
    typedef intrusive_list_t<linux_thread_message_t> msg_list_t;

    linux_message_hub_t(linux_event_queue_t *queue, linux_thread_pool_t *thread_pool, int current_thread);

    /* For each thread, transfer messages from our msg_local_list for that thread to our
    msg_global_list for that thread */
    void push_messages();

    /* Schedules the given message to be sent to the given thread by pushing it onto our
    msg_local_list for that thread */
    void store_message(unsigned int nthread, linux_thread_message_t *msg);

    // Schedules the given message to be sent to the given thread.  However, these are not
    // guaranteed to be called in the same order relative to one another.
    void store_message_sometime(unsigned int nthread, linux_thread_message_t *msg);

    // Called by the thread pool when it needs to deliver a message from the main thread
    // (which does not have an event queue)
    void insert_external_message(linux_thread_message_t *msg);

    ~linux_message_hub_t();

private:
    // Does store_message or store_message_sometime, only without setting the reloop_count_ in
    // debug mode.
    void do_store_message(unsigned int nthread, linux_thread_message_t *msg);

    /* pull_messages should be called on thread N with N as its argument. (The argument is
    partially redundant.) It will cause the actual delivery of messages that originated
    on this->current_thread and are destined for thread N. It is (almost) the only method on
    linux_message_hub_t that is not called on the thread that the message hub belongs to. */
    void pull_messages(int thread);

    linux_event_queue_t *const queue_;
    linux_thread_pool_t *const thread_pool_;

    /* Queue for messages going from this->current_thread to other threads */
    struct thread_queue_t {
        //TODO this doesn't need to be a class anymore

        /* Messages are cached here before being pushed to the global list so that we don't
        have to acquire the spinlock as often */
        msg_list_t msg_local_list;
    } queues_[MAX_THREADS];

    msg_list_t incoming_messages_;
    pthread_spinlock_t incoming_messages_lock_;

    /* We keep one notify_t for each other message hub that we interact with. When it has
    messages for us, it signals the appropriate notify_t from our set of notify_ts. We get
    the notification and call push_messages on the sender in reply. */
    struct notify_t : public linux_event_callback_t
    {
    public:
        /* message_hubs[i]->notify[j].on_event() is called when thread #j has messages for
        thread #i. */
        void on_event(int events);

    public:
        /* hub->notify[j].notifier_thread == j */
        int notifier_thread;

        system_event_t event;                    // the eventfd to notify

        /* hub->notify[i].parent = hub */
        linux_message_hub_t *parent;
    };
    notify_t *notify_;

    /* The thread that we queue messages originating from. (Recall that there is one
    message_hub_t per thread.) */
    const unsigned int current_thread_;

    DISABLE_COPYING(linux_message_hub_t);
};

#endif // ARCH_RUNTIME_MESSAGE_HUB_HPP_
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 "internal/string_view.h"

#include "gtest/gtest.h"

namespace cpu_features {

bool operator==(const StringView& a, const StringView& b) {
  return CpuFeatures_StringView_IsEquals(a, b);
}

namespace {

TEST(StringViewTest, Empty) {
  EXPECT_EQ(kEmptyStringView.ptr, nullptr);
  EXPECT_EQ(kEmptyStringView.size, 0);
}

TEST(StringViewTest, Build) {
  const auto view = str("test");
  EXPECT_EQ(view.ptr[0], 't');
  EXPECT_EQ(view.size, 4);
}

TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) {
  // Found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
  // Not found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
  // Empty.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_IndexOf) {
  // Found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
  // Not found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
  // Empty.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1);
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_StartsWith) {
  EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
  EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
  EXPECT_FALSE(
      CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
  EXPECT_FALSE(
      CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test")));
}

TEST(StringViewTest, CpuFeatures_StringView_IsEquals) {
  EXPECT_TRUE(
      CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
}

TEST(StringViewTest, CpuFeatures_StringView_PopFront) {
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st"));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test"));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str(""));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
}

TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) {
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);

  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
  char buf[4];
  buf[0] = 'X';

  // Empty
  CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf));
  EXPECT_STREQ(buf, "");

  // Less
  CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "a");

  // exact
  CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "abc");

  // More
  CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "abc");
}

TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
  // Find flags at beginning, middle and end.
  EXPECT_TRUE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
  EXPECT_TRUE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
  EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
  // Do not match partial flags
  EXPECT_FALSE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
  EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
  EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
}

TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {
  const StringView line = str(" key :   first middle last   ");
  StringView key, value;
  EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
  EXPECT_EQ(key, str("key"));
  EXPECT_EQ(value, str("first middle last"));
}

TEST(StringViewTest, FailingGetAttributeKeyValue) {
  const StringView line = str("key  first middle last");
  StringView key, value;
  EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
}

}  // namespace
}  // namespace cpu_features
<commit_msg>Add more test cases for the string view (#119)<commit_after>// Copyright 2017 Google Inc.
//
// 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 "internal/string_view.h"

#include "gtest/gtest.h"

namespace cpu_features {

bool operator==(const StringView& a, const StringView& b) {
  return CpuFeatures_StringView_IsEquals(a, b);
}

namespace {

TEST(StringViewTest, Empty) {
  EXPECT_EQ(kEmptyStringView.ptr, nullptr);
  EXPECT_EQ(kEmptyStringView.size, 0);
}

TEST(StringViewTest, Build) {
  const auto view = str("test");
  EXPECT_EQ(view.ptr[0], 't');
  EXPECT_EQ(view.size, 4);
}

TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) {
  // Found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0);
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1);
  // Not found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
  // Empty.
  EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_IndexOf) {
  // Found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0);
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4);
  // Not found.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
  // Empty.
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1);
  EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_StartsWith) {
  EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
  EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test")));
  EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st")));
  EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est")));
  EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
  EXPECT_FALSE(
      CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
  EXPECT_FALSE(
      CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test")));
}

TEST(StringViewTest, CpuFeatures_StringView_IsEquals) {
  EXPECT_TRUE(
      CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test")));
  EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa")));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
  EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
}

TEST(StringViewTest, CpuFeatures_StringView_PopFront) {
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st"));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test"));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str(""));
  EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
}

TEST(StringViewTest, CpuFeatures_StringView_PopBack) {
  EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te"));
  EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test"));
  EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str(""));
  EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str(""));
}

TEST(StringViewTest, CpuFeatures_StringView_KeepFront) {
  EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te"));
  EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str(""));
  EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test"));
  EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test"));
}

TEST(StringViewTest, CpuFeatures_StringView_Front) {
  EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a');
  EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a');
}

TEST(StringViewTest, CpuFeatures_StringView_Back) {
  EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e');
  EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a');
}

TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) {
  EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("  first middle last  ")),
                                                  str("first middle last"));
  EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last  ")),
                                                  str("first middle last"));
  EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("  first middle last")),
                                                  str("first middle last"));
  EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")),
                                                  str("first middle last"));
}

TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) {
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794);

  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
  EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);
}

TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
  char buf[4];
  buf[0] = 'X';

  // Empty
  CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf));
  EXPECT_STREQ(buf, "");

  // Less
  CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "a");

  // exact
  CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "abc");

  // More
  CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf));
  EXPECT_STREQ(buf, "abc");
}

TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
  // Find flags at beginning, middle and end.
  EXPECT_TRUE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
  EXPECT_TRUE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
  EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
  // Do not match partial flags
  EXPECT_FALSE(
      CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
  EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
  EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
}

TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {
  const StringView line = str(" key :   first middle last   ");
  StringView key, value;
  EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
  EXPECT_EQ(key, str("key"));
  EXPECT_EQ(value, str("first middle last"));
}

TEST(StringViewTest, FailingGetAttributeKeyValue) {
  const StringView line = str("key  first middle last");
  StringView key, value;
  EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
}

}  // namespace
}  // namespace cpu_features
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include "mesh.h"

using namespace std;

Mesh::Mesh() {
	transformation = identity();
}

void Mesh::insertEdge(int a, int b) {
	edges.push_back(a);
	edges.push_back(b);
}

/* Circle Functions */
void Mesh::insertCircle(double cx, double cy, double r) {
	double t;
	double  x,  y,
		   x0, y0;

	x0 = cx + r;
	y0 = cy;
	for( t=0; t<=1+STEP_SIZE; t+=STEP_SIZE ) {
		x = cx + r*unitCircleX(t);
		y = cy + r*unitCircleY(t);
		insertEdge(insert(x0,y0,0,1), insert(x,y,0,1));
		x0 = x;
		y0 = y;
	}
}
inline double Mesh::unitCircleX(double t) {
	return cos(t*2*M_PI);
}
inline double Mesh::unitCircleY(double t) {
	return sin(t*2*M_PI);
}

/* Bezier Curve Functions */
void Mesh::insertBezier( double x0, double y0,
						 double x1, double y1,
                         double x2, double y2,
                         double x3, double y3) {
	double x, y, Px, Py;
	Mat4 input, bezier, coef;
	Vect4 v1(x0, x1, x2, x3);
	Vect4 v2(y0, y1, y2, y3);
	input.insert(v1);
	input.insert(v2);

	bezier = bezierMatrix();

	Px = x0;
	Py = y0;
	double t;
	for( t=0; t<1.0+STEP_SIZE; t+=STEP_SIZE ){
		coef = mult(bezier, input);
		x = calcCubic(
				coef.get(0,0),
				coef.get(1,0),
				coef.get(2,0),
				coef.get(3,0),
				t );
		y = calcCubic(
				coef.get(0,1),
				coef.get(1,1),
				coef.get(2,1),
				coef.get(3,1),
				t );
		insertEdge(insert(Px, Py, 0, 1), insert(x, y, 0, 1));
		Px = x;
		Py = y;
	}
}

inline double Mesh::calcCubic(double a, double b, double c, double d, double t) {
	return (a*t*t*t) + (b*t*t) + (c*t) + d;
}

Mat4 Mesh::bezierMatrix() {
	Mat4 tmp;
	Vect4 v1(-1, 3,-3, 1 ),
		  v2( 3,-6, 3, 0 ),
		  v3(-3, 3, 0, 0 ),
		  v4( 1, 0, 0, 0 );

	tmp.insert(v1);
	tmp.insert(v2);
	tmp.insert(v3);
	tmp.insert(v4);

	return tmp;

}

/* Hermite Creation Functions */
void Mesh::insertHermite(double x0, double y0,
                         double rx0, double ry0,
	                     double x1, double y1,
                         double rx1, double ry1){
	double x, y, Px, Py;
	Mat4 input, hermite, coef;
	Vect4 v1(x0, x1, rx0, rx1);
	Vect4 v2(y0, y1, ry0, ry1);
	input.insert(v1);
	input.insert(v2);

	hermite = hermiteMatrix();

	Px = x0;
	Py = y0;
	double t;
	for( t=0; t<1.0+STEP_SIZE; t+=STEP_SIZE ){
		coef = mult(hermite, input);
		x = calcCubic(
				coef.get(0,0),
				coef.get(1,0),
				coef.get(2,0),
				coef.get(3,0),
				t );
		y = calcCubic(
				coef.get(0,1),
				coef.get(1,1),
				coef.get(2,1),
				coef.get(3,1),
				t );
		insertEdge(insert(Px, Py, 0, 1), insert(x, y, 0, 1));
		Px = x;
		Py = y;
	}
}

Mat4 Mesh::hermiteMatrix() {
	Mat4 tmp;
	Vect4 v1( 2,-3, 0, 1 ),
		  v2(-2, 3, 0, 0 ),
		  v3( 1,-2, 1, 0 ),
		  v4( 1,-1, 0, 0 );

	tmp.insert(v1);
	tmp.insert(v2);
	tmp.insert(v3);
	tmp.insert(v4);

	return tmp;
}

void Mesh::applyTransformation() {
	apply(transformation);
}
Mat4 Mesh::transformPoints() {
	return Mat4::mult(transformation, *this);
}

// Transformation Function Overrides
bool Mesh::trans(double dx, double dy, double dz) {
	transformation.apply(transMatrix(dx,dy,dz));
	return true;
}
bool Mesh::scale(double a, double b, double c) {
	transformation.apply(scaleMatrix(a,b,c));
	return true;
}
bool Mesh::rotateX(double theta) {
	transformation.apply(rotXMatrix(theta));
	return true;
}
bool Mesh::rotateY(double theta) {
	transformation.apply(rotYMatrix(theta));
	return true;
}
bool Mesh::rotateZ(double theta) {
	transformation.apply(rotZMatrix(theta));
	return true;
}

void Mesh::resetPosition() {
	transformation = identity();
}
<commit_msg>bezier finalized<commit_after>#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include "mesh.h"

using namespace std;

Mesh::Mesh() {
	transformation = identity();
}

void Mesh::insertEdge(int a, int b) {
	edges.push_back(a);
	edges.push_back(b);
}

/* Circle Functions */
void Mesh::insertCircle(double cx, double cy, double r) {
	double t;
	double  x,  y,
		   x0, y0;

	x0 = cx + r;
	y0 = cy;
	for( t=0; t<=1+STEP_SIZE; t+=STEP_SIZE ) {
		x = cx + r*unitCircleX(t);
		y = cy + r*unitCircleY(t);
		insertEdge(insert(x0,y0,0,1), insert(x,y,0,1));
		x0 = x;
		y0 = y;
	}
}
inline double Mesh::unitCircleX(double t) {
	return cos(t*2*M_PI);
}
inline double Mesh::unitCircleY(double t) {
	return sin(t*2*M_PI);
}

/* Bezier Curve Functions */
void Mesh::insertBezier( double x0, double y0,
						 double x1, double y1,
                         double x2, double y2,
                         double x3, double y3) {
	double x, y, Px, Py;
	Mat4 input, bezier, coef;
	Vect4 v1(x0, x1, x2, x3);
	Vect4 v2(y0, y1, y2, y3);
	input.insert(v1);
	input.insert(v2);

	bezier = bezierMatrix();

	Px = x0;
	Py = y0;
	double t;
	for( t=0; t<1.0+STEP_SIZE; t+=STEP_SIZE ){
		coef = mult(bezier, input);
		x = calcCubic(
				coef.get(0,0),
				coef.get(1,0),
				coef.get(2,0),
				coef.get(3,0),
				t );
		y = calcCubic(
				coef.get(0,1),
				coef.get(1,1),
				coef.get(2,1),
				coef.get(3,1),
				t );
		insertEdge(insert(Px, Py, 0, 1), insert(x, y, 0, 1));
		Px = x;
		Py = y;
	}
}

inline double Mesh::calcCubic(double a, double b, double c, double d, double t) {
	return (a*t*t*t) + (b*t*t) + (c*t) + d;
}

Mat4 Mesh::bezierMatrix() {
	Mat4 tmp;
	Vect4 v1(-1, 3,-3, 1 ),
		  v2( 3,-6, 3, 0 ),
		  v3(-3, 3, 0, 0 ),
		  v4( 1, 0, 0, 0 );

	tmp.insert(v1);
	tmp.insert(v2);
	tmp.insert(v3);
	tmp.insert(v4);

	return tmp;

}

/* Hermite Creation Functions */
void Mesh::insertHermite(double x0, double y0,
	                     double x1, double y1,
	                     double x2, double y2,
                         double x3, double y3){
	double x, y, Px, Py;
	double rx0, ry0, rx2, ry2;

	rx0 = x1 - x0;
	ry0 = y1 - y0;
	rx2 = x3 - x2;
	ry2 = y3 - y2;

	Mat4 input, hermite, coef;
	Vect4 v1(x0, x2, rx0, rx2);
	Vect4 v2(y0, y2, ry0, ry2);
	input.insert(v1);
	input.insert(v2);

	hermite = hermiteMatrix();

	Px = x0;
	Py = y0;
	double t;
	for( t=0; t<1.0+STEP_SIZE; t+=STEP_SIZE ){
		coef = mult(hermite, input);
		x = calcCubic(
				coef.get(0,0),
				coef.get(1,0),
				coef.get(2,0),
				coef.get(3,0),
				t );
		y = calcCubic(
				coef.get(0,1),
				coef.get(1,1),
				coef.get(2,1),
				coef.get(3,1),
				t );
		insertEdge(insert(Px, Py, 0, 1), insert(x, y, 0, 1));
		Px = x;
		Py = y;
	}
}

Mat4 Mesh::hermiteMatrix() {
	Mat4 tmp;
	Vect4 v1( 2,-3, 0, 1 ),
		  v2(-2, 3, 0, 0 ),
		  v3( 1,-2, 1, 0 ),
		  v4( 1,-1, 0, 0 );

	tmp.insert(v1);
	tmp.insert(v2);
	tmp.insert(v3);
	tmp.insert(v4);

	return tmp;
}

void Mesh::applyTransformation() {
	apply(transformation);
}
Mat4 Mesh::transformPoints() {
	return Mat4::mult(transformation, *this);
}

// Transformation Function Overrides
bool Mesh::trans(double dx, double dy, double dz) {
	transformation.apply(transMatrix(dx,dy,dz));
	return true;
}
bool Mesh::scale(double a, double b, double c) {
	transformation.apply(scaleMatrix(a,b,c));
	return true;
}
bool Mesh::rotateX(double theta) {
	transformation.apply(rotXMatrix(theta));
	return true;
}
bool Mesh::rotateY(double theta) {
	transformation.apply(rotYMatrix(theta));
	return true;
}
bool Mesh::rotateZ(double theta) {
	transformation.apply(rotZMatrix(theta));
	return true;
}

void Mesh::resetPosition() {
	transformation = identity();
}
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <Teuchos_UnitTestHarness.hpp>

#include <DTK_DBC.hpp> // DataTransferKitException
#include <DTK_NearestNeighborOperator.hpp>
#include <Kokkos_Core.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Tpetra_CrsMatrix.hpp>
#include <Tpetra_Distributor.hpp>
#include <Tpetra_Map.hpp>

#include <array>
#include <numeric>
#include <random>
#include <vector>

std::vector<std::array<double, 3>>
makeStructuredCloud( double Lx, double Ly, double Lz, int nx, int ny, int nz,
                     double ox = 0., double oy = 0., double oz = 0. )
{
    std::vector<std::array<double, 3>> cloud( nx * ny * nz );
    std::function<int( int, int, int )> ind = [nx, ny]( int i, int j, int k ) {
        return i + j * nx + k * ( nx * ny );
    };
    double x, y, z;
    for ( int i = 0; i < nx; ++i )
        for ( int j = 0; j < ny; ++j )
            for ( int k = 0; k < nz; ++k )
            {
                x = ox + i * Lx / nx;
                y = oy + j * Ly / ny;
                z = oz + k * Lz / nz;
                cloud[ind( i, j, k )] = {{x, y, z}};
            }
    return cloud;
}

std::vector<std::array<double, 3>>
makeRandomCloud( double Lx, double Ly, double Lz, int n, double seed = 0. )
{
    std::vector<std::array<double, 3>> cloud( n );
    std::default_random_engine generator( seed );
    std::uniform_real_distribution<double> distributionx( 0.0, Lx );
    std::uniform_real_distribution<double> distributiony( 0.0, Ly );
    std::uniform_real_distribution<double> distributionz( 0.0, Lz );
    for ( int i = 0; i < n; ++i )
    {
        double x = distributionx( generator );
        double y = distributiony( generator );
        double z = distributionz( generator );
        cloud[i] = {{x, y, z}};
    }
    return cloud;
}

template <typename DeviceType>
void copyPointsFromCloud( std::vector<std::array<double, 3>> const &cloud,
                          Kokkos::View<double **, DeviceType> &points )
{
    int const n_points = cloud.size();
    int const spatial_dim = 3;
    Kokkos::realloc( points, n_points, spatial_dim );
    auto points_host = Kokkos::create_mirror_view( points );
    for ( int i = 0; i < n_points; ++i )
        for ( int d = 0; d < spatial_dim; ++d )
            points_host( i, d ) = cloud[i][d];
    Kokkos::deep_copy( points, points_host );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, unique_source_point,
                                   DeviceType )
{
    Teuchos::RCP<const Teuchos::Comm<int>> comm =
        Teuchos::DefaultComm<int>::getComm();
    int const comm_size = comm->getSize();
    int const comm_rank = comm->getRank();

    int const space_dim = 3;

    // Build structured cloud of points for the source and random cloud for the
    // target.
    Kokkos::View<double **, DeviceType> source_points( "source" );

    Kokkos::View<double **, DeviceType> target_points( "target", 1, space_dim );

    // violate pre condition that source cloud is not empty
    TEST_THROW( DataTransferKit::NearestNeighborOperator<DeviceType>(
                    comm, source_points, target_points ),
                DataTransferKit::DataTransferKitException );

    if ( comm_rank == 0 )
    {
        Kokkos::resize( source_points, 1, space_dim );
        auto source_points_host = Kokkos::create_mirror_view( source_points );
        for ( int d = 0; d < space_dim; ++d )
            source_points_host( 0, d ) = (double)comm_size;
        Kokkos::deep_copy( source_points, source_points_host );
    }

    auto target_points_host = Kokkos::create_mirror_view( target_points );
    for ( int d = 0; d < space_dim; ++d )
        target_points_host( 0, d ) = (double)comm_rank;
    Kokkos::deep_copy( target_points, target_points_host );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    Kokkos::View<double *, DeviceType> source_values( "in" );
    Kokkos::View<double *, DeviceType> target_values( "out" );

    // violate pre condition of apply
    TEST_THROW( nnop.apply( source_values, target_values ),
                DataTransferKit::DataTransferKitException );

    Kokkos::realloc( target_values, target_points.extent( 0 ) );
    Kokkos::realloc( source_values, source_points.extent( 0 ) );
    if ( comm_rank == 0 )
    {
        auto source_values_host = Kokkos::create_mirror_view( source_values );
        source_values_host( 0 ) = 255.;
        Kokkos::deep_copy( source_values, source_values_host );
    }

    nnop.apply( source_values, target_values );

    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    std::vector<double> target_values_ref = {255.};
    TEST_COMPARE_ARRAYS( target_values_host, target_values_ref );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, structured_clouds,
                                   DeviceType )
{
    // The source is a structured cloud. The target is the same cloud but
    // distributed differently among the processors.
    Teuchos::RCP<Teuchos::Comm<int> const> comm =
        Teuchos::DefaultComm<int>::getComm();
    unsigned int const comm_size = comm->getSize();
    unsigned int const comm_rank = comm->getRank();

    // Build the structured cloud of points for the source and the target.
    double const Lx = 2.;
    double const Ly = 3.;
    double const Lz = 5.;
    unsigned int const nx = 7;
    unsigned int const ny = 11;
    unsigned int const nz = 13;
    double const source_offset_x = comm_rank * Lx;
    double const source_offset_y = comm_rank * Ly;
    double const source_offset_z = comm_rank * Lz;

    Kokkos::View<double **, DeviceType> source_points( "source_points" );
    copyPointsFromCloud<DeviceType>(
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, source_offset_x,
                             source_offset_y, source_offset_z ),
        source_points );

    double const target_offset_x = ( ( comm_rank + 1 ) % comm_size ) * Lx;
    double const target_offset_y = ( ( comm_rank + 1 ) % comm_size ) * Ly;
    double const target_offset_z = ( ( comm_rank + 1 ) % comm_size ) * Lz;

    Kokkos::View<double **, DeviceType> target_points( "target_points" );
    copyPointsFromCloud<DeviceType>(
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, target_offset_x,
                             target_offset_y, target_offset_z ),
        target_points );

    unsigned int const n_points = source_points.extent( 0 );
    Kokkos::View<double *, DeviceType> target_values( "target_values",
                                                      n_points );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    Kokkos::View<double *, DeviceType> source_values( "source_values",
                                                      n_points );
    Kokkos::deep_copy( source_values,
                       Kokkos::subview( source_points, Kokkos::ALL, 0 ) );

    nnop.apply( source_values, target_values );

    // Check results
    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    auto target_points_host = Kokkos::create_mirror_view( target_points );
    Kokkos::deep_copy( target_points_host, target_points );
    for ( unsigned int i = 0; i < n_points; ++i )
        TEST_FLOATING_EQUALITY( target_values_host( i ),
                                target_points_host( i, 0 ), 1e-14 );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, mixed_clouds,
                                   DeviceType )
{
    // The source is a structured cloud. The target is a random cloud.
    Teuchos::RCP<Teuchos::Comm<int> const> comm =
        Teuchos::DefaultComm<int>::getComm();
    unsigned int const comm_size = comm->getSize();
    unsigned int const comm_rank = comm->getRank();

    // Build the structured cloud of points for the source.
    unsigned int constexpr spacedim = 3;
    double const Lx = 17.;
    double const Ly = 19.;
    double const Lz = 23.;
    unsigned int const nx = 29;
    unsigned int const ny = 31;
    unsigned int const nz = 37;
    double const source_offset_x = comm_rank * Lx;
    double const source_offset_y = 0;
    double const source_offset_z = 0;

    std::vector<std::array<double, spacedim>> structured_cloud =
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, source_offset_x,
                             source_offset_y, source_offset_z );
    Kokkos::View<double **, DeviceType> source_points( "source_points" );
    copyPointsFromCloud<DeviceType>( structured_cloud, source_points );

    // Build the random cloud of points for the target.
    unsigned int const n_target_points = 41;
    std::vector<std::array<double, spacedim>> random_cloud =
        makeRandomCloud( comm_size * Lx, Ly, Lz, n_target_points, comm_rank );

    Kokkos::View<double **, DeviceType> target_points( "target_points" );
    copyPointsFromCloud<DeviceType>( random_cloud, target_points );

    Kokkos::View<double *, DeviceType> target_values( "target_values",
                                                      n_target_points );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    unsigned int const n_points = source_points.extent( 0 );
    Kokkos::View<double *, DeviceType> source_values( "source_values",
                                                      n_points );
    Kokkos::deep_copy( source_values,
                       Kokkos::subview( source_points, Kokkos::ALL, 0 ) );

    nnop.apply( source_values, target_values );

    // Check results
    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    for ( unsigned int i = 0; i < n_target_points; ++i )
    {
        double ref_value = round( target_points( i, 0 ) / Lx * nx ) * Lx / nx;
        if ( ref_value == Lx * comm_size )
            ref_value -= Lx / nx;
        TEST_FLOATING_EQUALITY( target_values_host( i, 0 ), ref_value, 1e-14 );
    }
}

// Include the test macros.
#include "DataTransferKitMeshfree_ETIHelperMacros.h"

// Create the test group
#define UNIT_TEST_GROUP( NODE )                                                \
    using DeviceType##NODE = typename NODE::device_type;                       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(                                      \
        NearestNeighborOperator, unique_source_point, DeviceType##NODE )       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(                                      \
        NearestNeighborOperator, structured_clouds, DeviceType##NODE )         \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( NearestNeighborOperator,             \
                                          mixed_clouds, DeviceType##NODE )

// Demangle the types
DTK_ETI_MANGLING_TYPEDEFS()

// Instantiate the tests
DTK_INSTANTIATE_N( UNIT_TEST_GROUP )
<commit_msg>Check that NNOp throws if source is not properly sized<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#include <Teuchos_UnitTestHarness.hpp>

#include <DTK_DBC.hpp> // DataTransferKitException
#include <DTK_NearestNeighborOperator.hpp>
#include <Kokkos_Core.hpp>
#include <Teuchos_DefaultComm.hpp>
#include <Tpetra_CrsMatrix.hpp>
#include <Tpetra_Distributor.hpp>
#include <Tpetra_Map.hpp>

#include <array>
#include <numeric>
#include <random>
#include <vector>

std::vector<std::array<double, 3>>
makeStructuredCloud( double Lx, double Ly, double Lz, int nx, int ny, int nz,
                     double ox = 0., double oy = 0., double oz = 0. )
{
    std::vector<std::array<double, 3>> cloud( nx * ny * nz );
    std::function<int( int, int, int )> ind = [nx, ny]( int i, int j, int k ) {
        return i + j * nx + k * ( nx * ny );
    };
    double x, y, z;
    for ( int i = 0; i < nx; ++i )
        for ( int j = 0; j < ny; ++j )
            for ( int k = 0; k < nz; ++k )
            {
                x = ox + i * Lx / nx;
                y = oy + j * Ly / ny;
                z = oz + k * Lz / nz;
                cloud[ind( i, j, k )] = {{x, y, z}};
            }
    return cloud;
}

std::vector<std::array<double, 3>>
makeRandomCloud( double Lx, double Ly, double Lz, int n, double seed = 0. )
{
    std::vector<std::array<double, 3>> cloud( n );
    std::default_random_engine generator( seed );
    std::uniform_real_distribution<double> distributionx( 0.0, Lx );
    std::uniform_real_distribution<double> distributiony( 0.0, Ly );
    std::uniform_real_distribution<double> distributionz( 0.0, Lz );
    for ( int i = 0; i < n; ++i )
    {
        double x = distributionx( generator );
        double y = distributiony( generator );
        double z = distributionz( generator );
        cloud[i] = {{x, y, z}};
    }
    return cloud;
}

template <typename DeviceType>
void copyPointsFromCloud( std::vector<std::array<double, 3>> const &cloud,
                          Kokkos::View<double **, DeviceType> &points )
{
    int const n_points = cloud.size();
    int const spatial_dim = 3;
    Kokkos::realloc( points, n_points, spatial_dim );
    auto points_host = Kokkos::create_mirror_view( points );
    for ( int i = 0; i < n_points; ++i )
        for ( int d = 0; d < spatial_dim; ++d )
            points_host( i, d ) = cloud[i][d];
    Kokkos::deep_copy( points, points_host );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, unique_source_point,
                                   DeviceType )
{
    Teuchos::RCP<const Teuchos::Comm<int>> comm =
        Teuchos::DefaultComm<int>::getComm();
    int const comm_size = comm->getSize();
    int const comm_rank = comm->getRank();

    int const space_dim = 3;

    // Build structured cloud of points for the source and random cloud for the
    // target.
    Kokkos::View<double **, DeviceType> source_points( "source" );

    Kokkos::View<double **, DeviceType> target_points( "target", 1, space_dim );

    // violate pre condition that source cloud is not empty
    TEST_THROW( DataTransferKit::NearestNeighborOperator<DeviceType>(
                    comm, source_points, target_points ),
                DataTransferKit::DataTransferKitException );

    if ( comm_rank == 0 )
    {
        Kokkos::resize( source_points, 1, space_dim );
        auto source_points_host = Kokkos::create_mirror_view( source_points );
        for ( int d = 0; d < space_dim; ++d )
            source_points_host( 0, d ) = (double)comm_size;
        Kokkos::deep_copy( source_points, source_points_host );
    }

    auto target_points_host = Kokkos::create_mirror_view( target_points );
    for ( int d = 0; d < space_dim; ++d )
        target_points_host( 0, d ) = (double)comm_rank;
    Kokkos::deep_copy( target_points, target_points_host );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    Kokkos::View<double *, DeviceType> source_values( "in" );
    Kokkos::View<double *, DeviceType> target_values( "out" );

    // violate pre condition of apply
    TEST_THROW( nnop.apply( source_values, target_values ),
                DataTransferKit::DataTransferKitException );

    Kokkos::realloc( target_values, target_points.extent( 0 ) );
    TEST_THROW( nnop.apply( source_values, target_values ),
                DataTransferKit::DataTransferKitException );

    Kokkos::realloc( source_values, source_points.extent( 0 ) );
    Kokkos::realloc( target_values, 0 );
    TEST_THROW( nnop.apply( source_values, target_values ),
                DataTransferKit::DataTransferKitException );

    Kokkos::realloc( source_values, source_points.extent( 0 ) );
    Kokkos::realloc( target_values, target_points.extent( 0 ) );
    if ( comm_rank == 0 )
    {
        auto source_values_host = Kokkos::create_mirror_view( source_values );
        source_values_host( 0 ) = 255.;
        Kokkos::deep_copy( source_values, source_values_host );
    }

    nnop.apply( source_values, target_values );

    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    std::vector<double> target_values_ref = {255.};
    TEST_COMPARE_ARRAYS( target_values_host, target_values_ref );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, structured_clouds,
                                   DeviceType )
{
    // The source is a structured cloud. The target is the same cloud but
    // distributed differently among the processors.
    Teuchos::RCP<Teuchos::Comm<int> const> comm =
        Teuchos::DefaultComm<int>::getComm();
    unsigned int const comm_size = comm->getSize();
    unsigned int const comm_rank = comm->getRank();

    // Build the structured cloud of points for the source and the target.
    double const Lx = 2.;
    double const Ly = 3.;
    double const Lz = 5.;
    unsigned int const nx = 7;
    unsigned int const ny = 11;
    unsigned int const nz = 13;
    double const source_offset_x = comm_rank * Lx;
    double const source_offset_y = comm_rank * Ly;
    double const source_offset_z = comm_rank * Lz;

    Kokkos::View<double **, DeviceType> source_points( "source_points" );
    copyPointsFromCloud<DeviceType>(
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, source_offset_x,
                             source_offset_y, source_offset_z ),
        source_points );

    double const target_offset_x = ( ( comm_rank + 1 ) % comm_size ) * Lx;
    double const target_offset_y = ( ( comm_rank + 1 ) % comm_size ) * Ly;
    double const target_offset_z = ( ( comm_rank + 1 ) % comm_size ) * Lz;

    Kokkos::View<double **, DeviceType> target_points( "target_points" );
    copyPointsFromCloud<DeviceType>(
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, target_offset_x,
                             target_offset_y, target_offset_z ),
        target_points );

    unsigned int const n_points = source_points.extent( 0 );
    Kokkos::View<double *, DeviceType> target_values( "target_values",
                                                      n_points );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    Kokkos::View<double *, DeviceType> source_values( "source_values",
                                                      n_points );
    Kokkos::deep_copy( source_values,
                       Kokkos::subview( source_points, Kokkos::ALL, 0 ) );

    nnop.apply( source_values, target_values );

    // Check results
    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    auto target_points_host = Kokkos::create_mirror_view( target_points );
    Kokkos::deep_copy( target_points_host, target_points );
    for ( unsigned int i = 0; i < n_points; ++i )
        TEST_FLOATING_EQUALITY( target_values_host( i ),
                                target_points_host( i, 0 ), 1e-14 );
}

TEUCHOS_UNIT_TEST_TEMPLATE_1_DECL( NearestNeighborOperator, mixed_clouds,
                                   DeviceType )
{
    // The source is a structured cloud. The target is a random cloud.
    Teuchos::RCP<Teuchos::Comm<int> const> comm =
        Teuchos::DefaultComm<int>::getComm();
    unsigned int const comm_size = comm->getSize();
    unsigned int const comm_rank = comm->getRank();

    // Build the structured cloud of points for the source.
    unsigned int constexpr spacedim = 3;
    double const Lx = 17.;
    double const Ly = 19.;
    double const Lz = 23.;
    unsigned int const nx = 29;
    unsigned int const ny = 31;
    unsigned int const nz = 37;
    double const source_offset_x = comm_rank * Lx;
    double const source_offset_y = 0;
    double const source_offset_z = 0;

    std::vector<std::array<double, spacedim>> structured_cloud =
        makeStructuredCloud( Lx, Ly, Lz, nx, ny, nz, source_offset_x,
                             source_offset_y, source_offset_z );
    Kokkos::View<double **, DeviceType> source_points( "source_points" );
    copyPointsFromCloud<DeviceType>( structured_cloud, source_points );

    // Build the random cloud of points for the target.
    unsigned int const n_target_points = 41;
    std::vector<std::array<double, spacedim>> random_cloud =
        makeRandomCloud( comm_size * Lx, Ly, Lz, n_target_points, comm_rank );

    Kokkos::View<double **, DeviceType> target_points( "target_points" );
    copyPointsFromCloud<DeviceType>( random_cloud, target_points );

    Kokkos::View<double *, DeviceType> target_values( "target_values",
                                                      n_target_points );

    DataTransferKit::NearestNeighborOperator<DeviceType> nnop(
        comm, source_points, target_points );

    unsigned int const n_points = source_points.extent( 0 );
    Kokkos::View<double *, DeviceType> source_values( "source_values",
                                                      n_points );
    Kokkos::deep_copy( source_values,
                       Kokkos::subview( source_points, Kokkos::ALL, 0 ) );

    nnop.apply( source_values, target_values );

    // Check results
    auto target_values_host = Kokkos::create_mirror_view( target_values );
    Kokkos::deep_copy( target_values_host, target_values );
    for ( unsigned int i = 0; i < n_target_points; ++i )
    {
        double ref_value = round( target_points( i, 0 ) / Lx * nx ) * Lx / nx;
        if ( ref_value == Lx * comm_size )
            ref_value -= Lx / nx;
        TEST_FLOATING_EQUALITY( target_values_host( i, 0 ), ref_value, 1e-14 );
    }
}

// Include the test macros.
#include "DataTransferKitMeshfree_ETIHelperMacros.h"

// Create the test group
#define UNIT_TEST_GROUP( NODE )                                                \
    using DeviceType##NODE = typename NODE::device_type;                       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(                                      \
        NearestNeighborOperator, unique_source_point, DeviceType##NODE )       \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT(                                      \
        NearestNeighborOperator, structured_clouds, DeviceType##NODE )         \
    TEUCHOS_UNIT_TEST_TEMPLATE_1_INSTANT( NearestNeighborOperator,             \
                                          mixed_clouds, DeviceType##NODE )

// Demangle the types
DTK_ETI_MANGLING_TYPEDEFS()

// Instantiate the tests
DTK_INSTANTIATE_N( UNIT_TEST_GROUP )
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Test.h"
#include "RecordTestUtils.h"

#include "SkDebugCanvas.h"
#include "SkDrawPictureCallback.h"
#include "SkRecord.h"
#include "SkRecordOpts.h"
#include "SkRecordDraw.h"
#include "SkRecorder.h"
#include "SkRecords.h"

static const int W = 1920, H = 1080;

class JustOneDraw : public SkDrawPictureCallback {
public:
    JustOneDraw() : fCalls(0) {}

    virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; }
private:
    int fCalls;
};

DEF_TEST(RecordDraw_Abort, r) {
    // Record two commands.
    SkRecord record;
    SkRecorder recorder(&record, W, H);
    recorder.drawRect(SkRect::MakeWH(200, 300), SkPaint());
    recorder.clipRect(SkRect::MakeWH(100, 200));

    SkRecord rerecord;
    SkRecorder canvas(&rerecord, W, H);

    JustOneDraw callback;
    SkRecordDraw(record, &canvas, NULL/*bbh*/, &callback);

    REPORTER_ASSERT(r, 3 == rerecord.count());
    assert_type<SkRecords::Save>    (r, rerecord, 0);
    assert_type<SkRecords::DrawRect>(r, rerecord, 1);
    assert_type<SkRecords::Restore> (r, rerecord, 2);
}

DEF_TEST(RecordDraw_Unbalanced, r) {
    SkRecord record;
    SkRecorder recorder(&record, W, H);
    recorder.save();  // We won't balance this, but SkRecordDraw will for us.

    SkRecord rerecord;
    SkRecorder canvas(&rerecord, W, H);
    SkRecordDraw(record, &canvas, NULL/*bbh*/, NULL/*callback*/);

    REPORTER_ASSERT(r, 4 == rerecord.count());
    assert_type<SkRecords::Save>    (r, rerecord, 0);
    assert_type<SkRecords::Save>    (r, rerecord, 1);
    assert_type<SkRecords::Restore> (r, rerecord, 2);
    assert_type<SkRecords::Restore> (r, rerecord, 3);
}

DEF_TEST(RecordDraw_SetMatrixClobber, r) {
    // Set up an SkRecord that just scales by 2x,3x.
    SkRecord scaleRecord;
    SkRecorder scaleCanvas(&scaleRecord, W, H);
    SkMatrix scale;
    scale.setScale(2, 3);
    scaleCanvas.setMatrix(scale);

    // Set up an SkRecord with an initial +20, +20 translate.
    SkRecord translateRecord;
    SkRecorder translateCanvas(&translateRecord, W, H);
    SkMatrix translate;
    translate.setTranslate(20, 20);
    translateCanvas.setMatrix(translate);

    SkRecordDraw(scaleRecord, &translateCanvas, NULL/*bbh*/, NULL/*callback*/);
    REPORTER_ASSERT(r, 4 == translateRecord.count());
    assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
    assert_type<SkRecords::Save>     (r, translateRecord, 1);
    assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
    assert_type<SkRecords::Restore>  (r, translateRecord, 3);

    // When we look at translateRecord now, it should have its first +20,+20 translate,
    // then a 2x,3x scale that's been concatted with that +20,+20 translate.
    const SkRecords::SetMatrix* setMatrix;
    setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
    REPORTER_ASSERT(r, setMatrix->matrix == translate);

    setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
    SkMatrix expected = scale;
    expected.postConcat(translate);
    REPORTER_ASSERT(r, setMatrix->matrix == expected);
}

struct TestBBH : public SkBBoxHierarchy {
    virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE {
        Entry e = { (uintptr_t)data, bounds };
        entries.push(e);
    }
    virtual int getCount() const SK_OVERRIDE { return entries.count(); }

    virtual void flushDeferredInserts() SK_OVERRIDE {}

    virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
    virtual void clear() SK_OVERRIDE {}
    virtual void rewindInserts() SK_OVERRIDE {}
    virtual int getDepth() const SK_OVERRIDE { return -1; }

    struct Entry {
        uintptr_t data;
        SkRect bounds;
    };
    SkTDArray<Entry> entries;
};

// This test is not meant to make total sense yet.  It's testing the status quo
// of SkRecordFillBounds(), which itself doesn't make total sense yet.
DEF_TEST(RecordDraw_BBH, r) {
    TestBBH bbh;

    SkRecord record;

    SkRecorder recorder(&record, W, H);
    recorder.save();
        recorder.clipRect(SkRect::MakeWH(400, 500));
        recorder.scale(2, 2);
        recorder.drawRect(SkRect::MakeWH(320, 240), SkPaint());
    recorder.restore();

    SkRecordFillBounds(record, &bbh);

    REPORTER_ASSERT(r, bbh.entries.count() == 5);
    for (int i = 0; i < bbh.entries.count(); i++) {
        REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i);

        REPORTER_ASSERT(r, bbh.entries[i].bounds == SkRect::MakeWH(400, 480));
    }
}
<commit_msg>Add some debugging to figure out what's up with failing Mac 10.8 Release bot.<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Test.h"
#include "RecordTestUtils.h"

#include "SkDebugCanvas.h"
#include "SkDrawPictureCallback.h"
#include "SkRecord.h"
#include "SkRecordOpts.h"
#include "SkRecordDraw.h"
#include "SkRecorder.h"
#include "SkRecords.h"

static const int W = 1920, H = 1080;

class JustOneDraw : public SkDrawPictureCallback {
public:
    JustOneDraw() : fCalls(0) {}

    virtual bool abortDrawing() SK_OVERRIDE { return fCalls++ > 0; }
private:
    int fCalls;
};

DEF_TEST(RecordDraw_Abort, r) {
    // Record two commands.
    SkRecord record;
    SkRecorder recorder(&record, W, H);
    recorder.drawRect(SkRect::MakeWH(200, 300), SkPaint());
    recorder.clipRect(SkRect::MakeWH(100, 200));

    SkRecord rerecord;
    SkRecorder canvas(&rerecord, W, H);

    JustOneDraw callback;
    SkRecordDraw(record, &canvas, NULL/*bbh*/, &callback);

    REPORTER_ASSERT(r, 3 == rerecord.count());
    assert_type<SkRecords::Save>    (r, rerecord, 0);
    assert_type<SkRecords::DrawRect>(r, rerecord, 1);
    assert_type<SkRecords::Restore> (r, rerecord, 2);
}

DEF_TEST(RecordDraw_Unbalanced, r) {
    SkRecord record;
    SkRecorder recorder(&record, W, H);
    recorder.save();  // We won't balance this, but SkRecordDraw will for us.

    SkRecord rerecord;
    SkRecorder canvas(&rerecord, W, H);
    SkRecordDraw(record, &canvas, NULL/*bbh*/, NULL/*callback*/);

    REPORTER_ASSERT(r, 4 == rerecord.count());
    assert_type<SkRecords::Save>    (r, rerecord, 0);
    assert_type<SkRecords::Save>    (r, rerecord, 1);
    assert_type<SkRecords::Restore> (r, rerecord, 2);
    assert_type<SkRecords::Restore> (r, rerecord, 3);
}

DEF_TEST(RecordDraw_SetMatrixClobber, r) {
    // Set up an SkRecord that just scales by 2x,3x.
    SkRecord scaleRecord;
    SkRecorder scaleCanvas(&scaleRecord, W, H);
    SkMatrix scale;
    scale.setScale(2, 3);
    scaleCanvas.setMatrix(scale);

    // Set up an SkRecord with an initial +20, +20 translate.
    SkRecord translateRecord;
    SkRecorder translateCanvas(&translateRecord, W, H);
    SkMatrix translate;
    translate.setTranslate(20, 20);
    translateCanvas.setMatrix(translate);

    SkRecordDraw(scaleRecord, &translateCanvas, NULL/*bbh*/, NULL/*callback*/);
    REPORTER_ASSERT(r, 4 == translateRecord.count());
    assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
    assert_type<SkRecords::Save>     (r, translateRecord, 1);
    assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
    assert_type<SkRecords::Restore>  (r, translateRecord, 3);

    // When we look at translateRecord now, it should have its first +20,+20 translate,
    // then a 2x,3x scale that's been concatted with that +20,+20 translate.
    const SkRecords::SetMatrix* setMatrix;
    setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 0);
    REPORTER_ASSERT(r, setMatrix->matrix == translate);

    setMatrix = assert_type<SkRecords::SetMatrix>(r, translateRecord, 2);
    SkMatrix expected = scale;
    expected.postConcat(translate);
    REPORTER_ASSERT(r, setMatrix->matrix == expected);
}

struct TestBBH : public SkBBoxHierarchy {
    virtual void insert(void* data, const SkRect& bounds, bool defer) SK_OVERRIDE {
        Entry e = { (uintptr_t)data, bounds };
        entries.push(e);
    }
    virtual int getCount() const SK_OVERRIDE { return entries.count(); }

    virtual void flushDeferredInserts() SK_OVERRIDE {}

    virtual void search(const SkRect& query, SkTDArray<void*>* results) const SK_OVERRIDE {}
    virtual void clear() SK_OVERRIDE {}
    virtual void rewindInserts() SK_OVERRIDE {}
    virtual int getDepth() const SK_OVERRIDE { return -1; }

    struct Entry {
        uintptr_t data;
        SkRect bounds;
    };
    SkTDArray<Entry> entries;
};

// This test is not meant to make total sense yet.  It's testing the status quo
// of SkRecordFillBounds(), which itself doesn't make total sense yet.
DEF_TEST(RecordDraw_BBH, r) {
    TestBBH bbh;

    SkRecord record;

    SkRecorder recorder(&record, W, H);
    recorder.save();
        recorder.clipRect(SkRect::MakeWH(400, 500));
        recorder.scale(2, 2);
        recorder.drawRect(SkRect::MakeWH(320, 240), SkPaint());
    recorder.restore();

    SkRecordFillBounds(record, &bbh);

    REPORTER_ASSERT(r, bbh.entries.count() == 5);
    for (int i = 0; i < bbh.entries.count(); i++) {
        REPORTER_ASSERT(r, bbh.entries[i].data == (uintptr_t)i);

        if (bbh.entries[i].bounds != SkRect::MakeWH(400, 480)) {
            SkRect bounds = bbh.entries[i].bounds;
            SkDebugf("Expected 0,0,400,480, got %f %f %f %f\n",
                     bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
        }
        REPORTER_ASSERT(r, bbh.entries[i].bounds == SkRect::MakeWH(400, 480));
    }
}
<|endoftext|>