<commit_before>#pragma once
#include "lubee/meta/check_macro.hpp"
#include "lubee/meta/enable_if.hpp"
#include "lubee/error.hpp"
#include "enum.hpp"
#include <vector>
#include <algorithm>
#include <memory>

namespace spi {
	DEF_HASMETHOD(clone)

	// cloneメソッドを持っていればそれを呼ぶ
	template <class T, ENABLE_IF(HasMethod_clone_t<T>{})>
	auto CopyAsSP(T& t) {
		return t.clone();
	}
	// cloneメソッドを持っていない時はコピーコンストラクタで対処
	template <class T, ENABLE_IF(!HasMethod_clone_t<T>{})>
	auto CopyAsSP(T& t) {
		using Tc = typename std::remove_const<T>::type;
		return std::shared_ptr<Tc>(new Tc(t));
	}

	//! iterateDepthFirstの戻り値
	DefineEnum(
		Iterate,
		(ReturnFromChild)	//!< 内部用
		(StepIn)			//!< 子を巡回
		(Next)				//!< 子を巡回せず兄弟ノードへ進む
		(Quit)				//!< 直ちに巡回を終える
	);
	//! 汎用ツリー構造
	/*! Tは必ずTreeNode<T>を継承する前提 */
	template <class T>
	class TreeNode : public std::enable_shared_from_this<T> {
		// 巡回参照を避けるために親ノードはweak_ptrで格納
		public:
			using Iterate = ::spi::Iterate;
			using this_t = TreeNode<T>;
			using pointer = this_t*;
			using element_type = T;
			using SP = std::shared_ptr<T>;
			using SPC = std::shared_ptr<const T>;
			using WP = std::weak_ptr<T>;
			using SPVector = std::vector<SP>;
			using SPCVector = std::vector<SPC>;
			using PVector = std::vector<T*>;
			using PCVector = std::vector<const T*>;

		private:
			template <class Ar, class T2>
			friend void serialize(Ar&, TreeNode<T2>&);

			SP			_spChild,
						_spSibling;
			WP			_wpParent,
						_wpPrevSibling;

			// --- ノードつなぎ変え時に呼ばれる関数. 継承先クラスが適時オーバーライドする ---
			static void OnParentChange(const TreeNode* /*self*/, const SP& /*node*/) {}
			static void OnChildRemove(const TreeNode* /*self*/, const SP& /*node*/) {}
			static void OnChildAdded(const TreeNode* /*self*/, const SP& /*node*/) {}

		private:
			//! 決められた回数分、タブを出力
			static void _PrintIndent(std::ostream& os, int n) {
				while(--n >= 0)
					os << '\t';
			}
			template <class CB>
			void _iterateAll(CB&& cb) const {
				auto* self = const_cast<this_t*>(this);
				self->template iterateDepthFirst<true>([&cb](auto& nd, int){
					cb(nd);
					return Iterate::StepIn;
				});
			}
			template <class T_SP>
			std::vector<T_SP> _plain() const {
				std::vector<T_SP> spv;
				_iterateAll([&spv](auto& nd){
					spv.emplace_back(nd.shared_from_this());
				});
				return spv;
			}
			template <class T_PTR>
			std::vector<T_PTR> _plainPtr() const {
				std::vector<T_PTR> pv;
				_iterateAll([&pv](auto& nd){
					pv.emplace_back(&nd);
				});
				return pv;
			}
			void _isolate() {
				if(const auto p = getPrevSibling())
					p->_spSibling = getSibling();
				if(const auto s = getSibling()) {
					s->_wpPrevSibling = _wpPrevSibling;
					_spSibling.reset();
				}
				_wpPrevSibling.reset();
				if(auto s = getParent()) {
					T::OnParentChange(this, nullptr);
					_wpParent.reset();
				}
			}
			void _setParent(const SP& s) NOEXCEPT_IF_RELEASE {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(isolating(), "target node must isolated");
				T::OnParentChange(this, s);
				_wpParent = s;
			}
			template <class S, class CB>
			static void _IterateChild(S& node, CB&& cb) noexcept(noexcept(cb(node.getChild()))) {
				if(auto sp = node.getChild()) {
					do {
						if(!cb(sp))
							break;
						sp = sp->getSibling();
					} while(sp);
				}
			}
		public:
			TreeNode() = default;
			explicit TreeNode(TreeNode&& t) = default;
			//! copy-ctorに置いてはリンク情報をコピーしない
			explicit TreeNode(const TreeNode&) {}
			// コピー禁止
			TreeNode& operator = (const TreeNode&) = delete;
			// ムーブは可
			TreeNode& operator = (TreeNode&& t) = default;

			//! 孤立判定
			bool isolating() const {
				return _wpParent.expired() && !hasSibling();
			}
			//! 前後どちらかでも兄弟ノードを持っているか
			bool hasSibling() const {
				return !_wpPrevSibling.expired() || _spSibling;
			}
			//! 直下の子ノードだけ巡回
			template <class CB>
			void iterateChild(CB&& cb) const { _IterateChild(*this, std::forward<CB>(cb)); }
			template <class CB>
			void iterateChild(CB&& cb) { _IterateChild(*this, std::forward<CB>(cb)); }
			//! 任意の基準で子ノードをソート
			template <class CMP>
			void sortChild(CMP&& cmp, const bool recursive) {
				if(auto c = getChild()) {
					SPVector spv;
					iterateChild([&spv](auto& nd){
						spv.emplace_back(nd);
						return true;
					});
					std::sort(spv.begin(), spv.end(), cmp);
					SP	cur = spv.front(),
						pcur;
					_spChild = cur;
					auto itr = spv.begin();
					do {
						cur = *itr;
						if(pcur) {
							cur->_wpPrevSibling = pcur;
							pcur->_spSibling = cur;
						} else
							cur->_wpPrevSibling.reset();
						pcur = cur;
					} while(++itr != spv.end());
					cur->_spSibling.reset();

					if(recursive) {
						for(auto& s : spv)
							s->sortChild(cmp, recursive);
					}
				}
			}

			SP getParent() const {
				return SP(_wpParent.lock());
			}
			const SP& getChild() const {
				return _spChild;
			}
			const SP& getSibling() const {
				return _spSibling;
			}
			//! 直前の兄弟ノードを取得
			SP getPrevSibling(const bool bLoop=false) const {
				if(SP ret = _wpPrevSibling.lock())
					return ret;
				if(bLoop) {
					auto cur = getParent();
					if(!cur)
						return const_cast<this_t*>(this)->shared_from_this();
					cur = cur->getChild();
					while(auto next = cur->getSibling())
						cur = next;
					return cur;
				}
				return nullptr;
			}
			void removeChild(const SP& target) {
				D_Assert0(_spChild);
				if(_spChild == target) {
					T::OnChildRemove(this, target);
					// 最初の子ノードが削除対象
					_spChild = target->getSibling();
					target->_isolate();
				} else {
					// 兄弟ノードのどれかが削除対象
					_spChild->removeSibling(nullptr, target);
				}
			}
			void removeSibling(pointer prev, const SP& target) {
				if(target.get() == this) {
					if(auto sp = getParent())
						T::OnChildRemove(sp.get(), this->shared_from_this());
					// このノードが削除対象
					D_Assert0(prev);
					_isolate();
					return;
				}
				D_Assert0(_spSibling);
				_spSibling->removeSibling(this, target);
			}
			void addChild(const SP& s) {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(s->isolating(), "target node must isolated");
				if(_spChild)
					_spChild->addSibling(s);
				else {
					_spChild = s;
					s->_setParent(this->shared_from_this());
					T::OnChildAdded(this, s);
				}
			}
			void addSibling(const SP& s) {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(s->isolating(), "target node must isolated");
				if(_spSibling)
					_spSibling->addSibling(s);
				else {
					_spSibling = s;
					s->_setParent(_wpParent.lock());
					s->_wpPrevSibling = this->shared_from_this();
					if(const auto sp = getParent())
						T::OnChildAdded(sp.get(), s);
				}
			}
			//! 深さ優先で巡回
			/*! \tparam Sib		兄弟ノードを巡回対象に加えるか
				\tparam BConst	trueならconst巡回 */
			template <bool Sib, class Callback, bool BConst=false>
			Iterate iterateDepthFirst(Callback&& cb, int depth=0) {
				using thistc = std::conditional_t<BConst, const T, T>;
				Iterate t = cb(static_cast<thistc&>(*this), depth);
				if(t == Iterate::Quit)
					return Iterate::Quit;
				if(t == Iterate::StepIn) {
					if(_spChild) {
						if(_spChild->template iterateDepthFirst<true>(std::forward<Callback>(cb), depth+1) == Iterate::Quit)
							return Iterate::Quit;
					}
				}
				if(Sib && _spSibling)
					return _spSibling->template iterateDepthFirst<true>(std::forward<Callback>(cb), depth);
				return Iterate::ReturnFromChild;
			}
			template <bool Sib, class Callback>
			Iterate iterateDepthFirst(Callback&& cb, int depth=0) const {
				return const_cast<this_t*>(this)->template iterateDepthFirst<Sib, Callback, true>(std::forward<Callback>(cb), depth);
			}
			template <class Callback>
			SP find(Callback&& cb) const {
				SP ret;
				iterateDepthFirst<false>([&cb, &ret](auto& nd, int){
					if(cb(nd)) {
						ret = nd.shared_from_this();
						return Iterate::Quit;
					}
					return Iterate::StepIn;
				});
				return ret;
			}
			//! このノード以下を全て複製
			SP cloneTree(const WP& parent=WP()) const {
				SP sp = std::dynamic_pointer_cast<T>(CopyAsSP(static_cast<const T&>(*this)));
				if(_spChild)
					sp->_spChild = _spChild->cloneTree(sp);
				if(_spSibling) {
					sp->_spSibling = _spSibling->cloneTree(parent);
					sp->_spSibling->_wpPrevSibling = sp;
				}
				sp->_wpParent = parent;
				return sp;
			}
			//! 主にデバッグ用
			void print(std::ostream& os, int indent) const {
				_PrintIndent(os, indent);
				// 明示的なダウンキャスト
				os << *static_cast<const T*>(this);
			}
			//! ツリー構造を配列化
			SPVector plain() {
				return _plain<SP>();
			}
			//! ツリー構造を配列化 (const)
			SPCVector plain() const {
				return _plain<SPC>();
			}
			//! ツリー構造を配列化 (pointer)
			PVector plainPtr() {
				return _plainPtr<T*>();
			}
			//! ツリー構造を配列化 (const pointer)
			PCVector  plainPtr() const {
				return _plainPtr<const T*>();
			}
			//! 最大ツリー深度を取得
			int getDepth() const {
				int depth = 0;
				if(_spChild)
					depth = _spChild->getDepth() + 1;
				if(_spSibling)
					depth = std::max(depth, _spSibling->getDepth());
				return depth;
			}
	};
	template <class T0, class T1, class CMP>
	bool _CompareTree(const TreeNode<T0>& t0, const TreeNode<T1>& t1, CMP&& cmp) {
		auto fnParentIndex = [](const auto& ar, const auto& p){
			if(!p)
				return ar.end() - ar.begin();
			auto itr = std::find_if(ar.begin(), ar.end(), [&p](auto& r){ return r == p.get(); });
			return itr - ar.begin();
		};
		// 配列化して親ノード番号をチェック
		const auto ar0 = t0.plainPtr();
		const auto ar1 = t1.plainPtr();
		if(ar0.size() != ar1.size())
			return false;
		const auto sz = ar0.size();
		for(size_t i=0 ; i<sz ; i++) {
			// 親ノード番号
			const int idx0 = fnParentIndex(ar0, ar0[i]->getParent()),
						idx1 = fnParentIndex(ar1, ar1[i]->getParent());
			if(idx0!=idx1 || !cmp(ar0[i], ar1[i]))
				return false;
		}
		return true;
	}
	// ツリー構造のみを比較する
	template <class T0, class T1>
	bool CompareTreeStructure(const TreeNode<T0>& t0, const TreeNode<T1>& t1) {
		return _CompareTree(t0, t1, [](auto&,auto&){ return true; });
	}
	//! データも含めて比較
	template <class T0, class T1>
	bool CompareTree(const TreeNode<T0>& t0, const TreeNode<T1>& t1) {
		auto cmp = [](auto& sp0, auto& sp1){
			return *sp0 == *sp1;
		};
		return _CompareTree(t0, t1, cmp);
	}
	template <class T>
	inline std::ostream& operator << (std::ostream& os, const TreeNode<T>& t) {
		auto& self = const_cast<TreeNode<T>&>(t);
		self.iterateDepthFirst<false>([&os](auto& s, int indent){
			s.print(os, indent);
			os << std::endl;
			return TreeNode<T>::Iterate::StepIn;
		});
		return os;
	}
}
<commit_msg>CompareTree: 比較関数を指定するように変更<commit_after>#pragma once
#include "lubee/meta/check_macro.hpp"
#include "lubee/meta/enable_if.hpp"
#include "lubee/error.hpp"
#include "enum.hpp"
#include <vector>
#include <algorithm>
#include <memory>

namespace spi {
	DEF_HASMETHOD(clone)

	// cloneメソッドを持っていればそれを呼ぶ
	template <class T, ENABLE_IF(HasMethod_clone_t<T>{})>
	auto CopyAsSP(T& t) {
		return t.clone();
	}
	// cloneメソッドを持っていない時はコピーコンストラクタで対処
	template <class T, ENABLE_IF(!HasMethod_clone_t<T>{})>
	auto CopyAsSP(T& t) {
		using Tc = typename std::remove_const<T>::type;
		return std::shared_ptr<Tc>(new Tc(t));
	}

	//! iterateDepthFirstの戻り値
	DefineEnum(
		Iterate,
		(ReturnFromChild)	//!< 内部用
		(StepIn)			//!< 子を巡回
		(Next)				//!< 子を巡回せず兄弟ノードへ進む
		(Quit)				//!< 直ちに巡回を終える
	);
	//! 汎用ツリー構造
	/*! Tは必ずTreeNode<T>を継承する前提 */
	template <class T>
	class TreeNode : public std::enable_shared_from_this<T> {
		// 巡回参照を避けるために親ノードはweak_ptrで格納
		public:
			using Iterate = ::spi::Iterate;
			using this_t = TreeNode<T>;
			using pointer = this_t*;
			using element_type = T;
			using SP = std::shared_ptr<T>;
			using SPC = std::shared_ptr<const T>;
			using WP = std::weak_ptr<T>;
			using SPVector = std::vector<SP>;
			using SPCVector = std::vector<SPC>;
			using PVector = std::vector<T*>;
			using PCVector = std::vector<const T*>;

		private:
			template <class Ar, class T2>
			friend void serialize(Ar&, TreeNode<T2>&);

			SP			_spChild,
						_spSibling;
			WP			_wpParent,
						_wpPrevSibling;

			// --- ノードつなぎ変え時に呼ばれる関数. 継承先クラスが適時オーバーライドする ---
			static void OnParentChange(const TreeNode* /*self*/, const SP& /*node*/) {}
			static void OnChildRemove(const TreeNode* /*self*/, const SP& /*node*/) {}
			static void OnChildAdded(const TreeNode* /*self*/, const SP& /*node*/) {}

		private:
			//! 決められた回数分、タブを出力
			static void _PrintIndent(std::ostream& os, int n) {
				while(--n >= 0)
					os << '\t';
			}
			template <class CB>
			void _iterateAll(CB&& cb) const {
				auto* self = const_cast<this_t*>(this);
				self->template iterateDepthFirst<true>([&cb](auto& nd, int){
					cb(nd);
					return Iterate::StepIn;
				});
			}
			template <class T_SP>
			std::vector<T_SP> _plain() const {
				std::vector<T_SP> spv;
				_iterateAll([&spv](auto& nd){
					spv.emplace_back(nd.shared_from_this());
				});
				return spv;
			}
			template <class T_PTR>
			std::vector<T_PTR> _plainPtr() const {
				std::vector<T_PTR> pv;
				_iterateAll([&pv](auto& nd){
					pv.emplace_back(&nd);
				});
				return pv;
			}
			void _isolate() {
				if(const auto p = getPrevSibling())
					p->_spSibling = getSibling();
				if(const auto s = getSibling()) {
					s->_wpPrevSibling = _wpPrevSibling;
					_spSibling.reset();
				}
				_wpPrevSibling.reset();
				if(auto s = getParent()) {
					T::OnParentChange(this, nullptr);
					_wpParent.reset();
				}
			}
			void _setParent(const SP& s) NOEXCEPT_IF_RELEASE {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(isolating(), "target node must isolated");
				T::OnParentChange(this, s);
				_wpParent = s;
			}
			template <class S, class CB>
			static void _IterateChild(S& node, CB&& cb) noexcept(noexcept(cb(node.getChild()))) {
				if(auto sp = node.getChild()) {
					do {
						if(!cb(sp))
							break;
						sp = sp->getSibling();
					} while(sp);
				}
			}
		public:
			TreeNode() = default;
			explicit TreeNode(TreeNode&& t) = default;
			//! copy-ctorに置いてはリンク情報をコピーしない
			explicit TreeNode(const TreeNode&) {}
			// コピー禁止
			TreeNode& operator = (const TreeNode&) = delete;
			// ムーブは可
			TreeNode& operator = (TreeNode&& t) = default;

			//! 孤立判定
			bool isolating() const {
				return _wpParent.expired() && !hasSibling();
			}
			//! 前後どちらかでも兄弟ノードを持っているか
			bool hasSibling() const {
				return !_wpPrevSibling.expired() || _spSibling;
			}
			//! 直下の子ノードだけ巡回
			template <class CB>
			void iterateChild(CB&& cb) const { _IterateChild(*this, std::forward<CB>(cb)); }
			template <class CB>
			void iterateChild(CB&& cb) { _IterateChild(*this, std::forward<CB>(cb)); }
			//! 任意の基準で子ノードをソート
			template <class CMP>
			void sortChild(CMP&& cmp, const bool recursive) {
				if(auto c = getChild()) {
					SPVector spv;
					iterateChild([&spv](auto& nd){
						spv.emplace_back(nd);
						return true;
					});
					std::sort(spv.begin(), spv.end(), cmp);
					SP	cur = spv.front(),
						pcur;
					_spChild = cur;
					auto itr = spv.begin();
					do {
						cur = *itr;
						if(pcur) {
							cur->_wpPrevSibling = pcur;
							pcur->_spSibling = cur;
						} else
							cur->_wpPrevSibling.reset();
						pcur = cur;
					} while(++itr != spv.end());
					cur->_spSibling.reset();

					if(recursive) {
						for(auto& s : spv)
							s->sortChild(cmp, recursive);
					}
				}
			}

			SP getParent() const {
				return SP(_wpParent.lock());
			}
			const SP& getChild() const {
				return _spChild;
			}
			const SP& getSibling() const {
				return _spSibling;
			}
			//! 直前の兄弟ノードを取得
			SP getPrevSibling(const bool bLoop=false) const {
				if(SP ret = _wpPrevSibling.lock())
					return ret;
				if(bLoop) {
					auto cur = getParent();
					if(!cur)
						return const_cast<this_t*>(this)->shared_from_this();
					cur = cur->getChild();
					while(auto next = cur->getSibling())
						cur = next;
					return cur;
				}
				return nullptr;
			}
			void removeChild(const SP& target) {
				D_Assert0(_spChild);
				if(_spChild == target) {
					T::OnChildRemove(this, target);
					// 最初の子ノードが削除対象
					_spChild = target->getSibling();
					target->_isolate();
				} else {
					// 兄弟ノードのどれかが削除対象
					_spChild->removeSibling(nullptr, target);
				}
			}
			void removeSibling(pointer prev, const SP& target) {
				if(target.get() == this) {
					if(auto sp = getParent())
						T::OnChildRemove(sp.get(), this->shared_from_this());
					// このノードが削除対象
					D_Assert0(prev);
					_isolate();
					return;
				}
				D_Assert0(_spSibling);
				_spSibling->removeSibling(this, target);
			}
			void addChild(const SP& s) {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(s->isolating(), "target node must isolated");
				if(_spChild)
					_spChild->addSibling(s);
				else {
					_spChild = s;
					s->_setParent(this->shared_from_this());
					T::OnChildAdded(this, s);
				}
			}
			void addSibling(const SP& s) {
				D_Assert(s.get() != this, "self-reference detected");
				D_Assert(s->isolating(), "target node must isolated");
				if(_spSibling)
					_spSibling->addSibling(s);
				else {
					_spSibling = s;
					s->_setParent(_wpParent.lock());
					s->_wpPrevSibling = this->shared_from_this();
					if(const auto sp = getParent())
						T::OnChildAdded(sp.get(), s);
				}
			}
			//! 深さ優先で巡回
			/*! \tparam Sib		兄弟ノードを巡回対象に加えるか
				\tparam BConst	trueならconst巡回 */
			template <bool Sib, class Callback, bool BConst=false>
			Iterate iterateDepthFirst(Callback&& cb, int depth=0) {
				using thistc = std::conditional_t<BConst, const T, T>;
				Iterate t = cb(static_cast<thistc&>(*this), depth);
				if(t == Iterate::Quit)
					return Iterate::Quit;
				if(t == Iterate::StepIn) {
					if(_spChild) {
						if(_spChild->template iterateDepthFirst<true>(std::forward<Callback>(cb), depth+1) == Iterate::Quit)
							return Iterate::Quit;
					}
				}
				if(Sib && _spSibling)
					return _spSibling->template iterateDepthFirst<true>(std::forward<Callback>(cb), depth);
				return Iterate::ReturnFromChild;
			}
			template <bool Sib, class Callback>
			Iterate iterateDepthFirst(Callback&& cb, int depth=0) const {
				return const_cast<this_t*>(this)->template iterateDepthFirst<Sib, Callback, true>(std::forward<Callback>(cb), depth);
			}
			template <class Callback>
			SP find(Callback&& cb) const {
				SP ret;
				iterateDepthFirst<false>([&cb, &ret](auto& nd, int){
					if(cb(nd)) {
						ret = nd.shared_from_this();
						return Iterate::Quit;
					}
					return Iterate::StepIn;
				});
				return ret;
			}
			//! このノード以下を全て複製
			SP cloneTree(const WP& parent=WP()) const {
				SP sp = std::dynamic_pointer_cast<T>(CopyAsSP(static_cast<const T&>(*this)));
				if(_spChild)
					sp->_spChild = _spChild->cloneTree(sp);
				if(_spSibling) {
					sp->_spSibling = _spSibling->cloneTree(parent);
					sp->_spSibling->_wpPrevSibling = sp;
				}
				sp->_wpParent = parent;
				return sp;
			}
			//! 主にデバッグ用
			void print(std::ostream& os, int indent) const {
				_PrintIndent(os, indent);
				// 明示的なダウンキャスト
				os << *static_cast<const T*>(this);
			}
			//! ツリー構造を配列化
			SPVector plain() {
				return _plain<SP>();
			}
			//! ツリー構造を配列化 (const)
			SPCVector plain() const {
				return _plain<SPC>();
			}
			//! ツリー構造を配列化 (pointer)
			PVector plainPtr() {
				return _plainPtr<T*>();
			}
			//! ツリー構造を配列化 (const pointer)
			PCVector  plainPtr() const {
				return _plainPtr<const T*>();
			}
			//! 最大ツリー深度を取得
			int getDepth() const {
				int depth = 0;
				if(_spChild)
					depth = _spChild->getDepth() + 1;
				if(_spSibling)
					depth = std::max(depth, _spSibling->getDepth());
				return depth;
			}
	};
	template <class T0, class T1, class CMP = std::equal_to<>>
	bool CompareTree(const TreeNode<T0>& t0, const TreeNode<T1>& t1, const CMP& cmp = CMP()) {
		const auto fnParentIndex = [](const auto& ar, const auto& p){
			if(!p)
				return ar.end() - ar.begin();
			const auto itr = std::find_if(ar.begin(), ar.end(),
					[&p](const auto& r){ return r == p.get(); });
			return itr - ar.begin();
		};
		// 配列化して親ノード番号をチェック
		const auto ar0 = t0.plainPtr();
		const auto ar1 = t1.plainPtr();
		if(ar0.size() != ar1.size())
			return false;
		const auto sz = ar0.size();
		for(size_t i=0 ; i<sz ; i++) {
			// 親ノード番号
			const int idx0 = fnParentIndex(ar0, ar0[i]->getParent()),
						idx1 = fnParentIndex(ar1, ar1[i]->getParent());
			if(idx0!=idx1 || !cmp(*ar0[i], *ar1[i]))
				return false;
		}
		return true;
	}
	// ツリー構造のみを比較する
	template <class T0, class T1>
	bool CompareTreeStructure(const TreeNode<T0>& t0, const TreeNode<T1>& t1) {
		return CompareTree(t0, t1, [](auto&,auto&){ return true; });
	}
	template <class T>
	inline std::ostream& operator << (std::ostream& os, const TreeNode<T>& t) {
		auto& self = const_cast<TreeNode<T>&>(t);
		self.iterateDepthFirst<false>([&os](auto& s, int indent){
			s.print(os, indent);
			os << std::endl;
			return TreeNode<T>::Iterate::StepIn;
		});
		return os;
	}
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2007 by Lothar May                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <iostream>

#include "session.h"
#include "configfile.h"
#include <gui/generic/serverguiwrapper.h>
#include <net/socket_startup.h>

#include <QtCore>

#include <csignal>

#ifdef _MSC_VER
	#ifdef _DEBUG
		#define _CRTDBG_MAP_ALLOC
		#include <crtdbg.h>

		#define ENABLE_LEAK_CHECK() \
			{ \
				int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); \
				tmpFlag |= _CRTDBG_LEAK_CHECK_DF; \
				_CrtSetDbgFlag(tmpFlag); \
			}
	#endif
#endif

#ifndef ENABLE_LEAK_CHECK
	#define ENABLE_LEAK_CHECK()
#endif

using namespace std;

volatile int g_pokerthTerminate = 0;

void
TerminateHandler(int /*signal*/)
{
	g_pokerthTerminate = 1;
}

// TODO: Hack
#ifndef _WIN32
	#include <unistd.h>
	#ifndef daemon
		int daemon(int, int);
	#endif
#endif

int
main(int argc, char *argv[])
{
	ENABLE_LEAK_CHECK();

	//_CrtSetBreakAlloc(164);

	// TODO: Hack
#ifndef _WIN32
	daemon(0, 0);
#endif

	signal(SIGTERM, TerminateHandler);
	signal(SIGINT, TerminateHandler);

	//create defaultconfig
	ConfigFile *myConfig = new ConfigFile(argc, argv);

	socket_startup();

	// Create pseudo Gui Wrapper for the server.
	boost::shared_ptr<GuiInterface> myServerGuiInterface(new ServerGuiWrapper(myConfig, NULL, NULL, NULL));
	{
		boost::shared_ptr<Session> session(new Session(myServerGuiInterface.get(), myConfig));
		session->init(); // TODO handle error
		myServerGuiInterface->setSession(session);
	}

	myServerGuiInterface->getSession().startNetworkServer();
	while (!g_pokerthTerminate)
	{
		myServerGuiInterface->getSession().waitForNetworkServer(100);
	}
	myServerGuiInterface->getSession().terminateNetworkServer();

	socket_cleanup();
	return 0;
}

<commit_msg>Removed qtcore include (forgot it before).<commit_after>/***************************************************************************
 *   Copyright (C) 2007 by Lothar May                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <iostream>

#include "session.h"
#include "configfile.h"
#include <gui/generic/serverguiwrapper.h>
#include <net/socket_startup.h>

#include <csignal>

#ifdef _MSC_VER
	#ifdef _DEBUG
		#define _CRTDBG_MAP_ALLOC
		#include <crtdbg.h>

		#define ENABLE_LEAK_CHECK() \
			{ \
				int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); \
				tmpFlag |= _CRTDBG_LEAK_CHECK_DF; \
				_CrtSetDbgFlag(tmpFlag); \
			}
	#endif
#endif

#ifndef ENABLE_LEAK_CHECK
	#define ENABLE_LEAK_CHECK()
#endif

using namespace std;

volatile int g_pokerthTerminate = 0;

void
TerminateHandler(int /*signal*/)
{
	g_pokerthTerminate = 1;
}

// TODO: Hack
#ifndef _WIN32
	#include <unistd.h>
	#ifndef daemon
		int daemon(int, int);
	#endif
#endif

int
main(int argc, char *argv[])
{
	ENABLE_LEAK_CHECK();

	//_CrtSetBreakAlloc(164);

	// TODO: Hack
#ifndef _WIN32
	daemon(0, 0);
#endif

	signal(SIGTERM, TerminateHandler);
	signal(SIGINT, TerminateHandler);

	//create defaultconfig
	ConfigFile *myConfig = new ConfigFile(argc, argv);

	socket_startup();

	// Create pseudo Gui Wrapper for the server.
	boost::shared_ptr<GuiInterface> myServerGuiInterface(new ServerGuiWrapper(myConfig, NULL, NULL, NULL));
	{
		boost::shared_ptr<Session> session(new Session(myServerGuiInterface.get(), myConfig));
		session->init(); // TODO handle error
		myServerGuiInterface->setSession(session);
	}

	myServerGuiInterface->getSession().startNetworkServer();
	while (!g_pokerthTerminate)
	{
		myServerGuiInterface->getSession().waitForNetworkServer(100);
	}
	myServerGuiInterface->getSession().terminateNetworkServer();

	socket_cleanup();
	return 0;
}

<|endoftext|>


<commit_before><commit_msg>moved parameter declaration into the declare pass<commit_after><|endoftext|>


<commit_before>// This shows how to erase a drive

#include <stdio.h>

#include "kinetic/kinetic.h"

using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticStatus;
using kinetic::KineticRecord;

using std::shared_ptr;
using std::string;
using std::unique_ptr;

int main(int argc, char* argv[]) {
    if (argc != 3 && argc != 4) {
        printf("%s: <host> <port>\n", argv[0]);
        printf("%s: <host> <port> <pin>\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    int port = atoi(argv[2]);

    kinetic::ConnectionOptions options;
    options.host = host;
    options.port = port;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    kinetic::KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    unique_ptr<kinetic::ConnectionHandle> connection;
    if (!kinetic_connection_factory.NewConnection(options, 5, connection).ok()) {
        printf("Unable to connect\n");
        return 1;
    }

    shared_ptr<string> pin;

    if (argc == 3) {
        printf("Performing ISE on %s:%d\n", host, port);
    } else {
        pin.reset(new std::string(argv[3]));
        printf("Performing ISE on %s:%d with pin %s\n", host, port, argv[3]);
    }

    KineticStatus status = connection->blocking().InstantSecureErase(pin);
    bool success = status.ok();

    if (!success) {
        printf("Unable to execute ISE: %d %s\n", static_cast<int>(status.statusCode()), status.message().c_str());
        return 1;
    }

    printf("Finished ISE\n");

    return 0;
}
<commit_msg>Increase ISE example timeout to 60 secs becuase ISEs take ~30 seconds<commit_after>// This shows how to erase a drive

#include <stdio.h>

#include "kinetic/kinetic.h"

using kinetic::KineticConnectionFactory;
using kinetic::Status;
using kinetic::KineticStatus;
using kinetic::KineticRecord;

using std::shared_ptr;
using std::string;
using std::unique_ptr;

int main(int argc, char* argv[]) {
    if (argc != 3 && argc != 4) {
        printf("%s: <host> <port>\n", argv[0]);
        printf("%s: <host> <port> <pin>\n", argv[0]);
        return 1;
    }

    const char* host = argv[1];
    int port = atoi(argv[2]);

    kinetic::ConnectionOptions options;
    options.host = host;
    options.port = port;
    options.user_id = 1;
    options.hmac_key = "asdfasdf";

    kinetic::KineticConnectionFactory kinetic_connection_factory = kinetic::NewKineticConnectionFactory();

    unique_ptr<kinetic::ConnectionHandle> connection;
    if (!kinetic_connection_factory.NewConnection(options, 60, connection).ok()) {
        printf("Unable to connect\n");
        return 1;
    }

    shared_ptr<string> pin;

    if (argc == 3) {
        printf("Performing ISE on %s:%d\n", host, port);
    } else {
        pin.reset(new std::string(argv[3]));
        printf("Performing ISE on %s:%d with pin %s\n", host, port, argv[3]);
    }

    KineticStatus status = connection->blocking().InstantSecureErase(pin);
    bool success = status.ok();

    if (!success) {
        printf("Unable to execute ISE: %d %s\n", static_cast<int>(status.statusCode()), status.message().c_str());
        return 1;
    }

    printf("Finished ISE\n");

    return 0;
}
<|endoftext|>


<commit_before>//
//  IDDiskInfoLogger.cpp
//  InvariantDisks
//
//  Created by Gerhard Röthlin on 2014.04.27.
//  Copyright (c) 2014 the-color-black.net. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted
//  provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
//  Additional licensing options are described in the README file.
//

#include "IDDiskInfoLogger.hpp"

#include "IDDiskArbitrationUtils.hpp"

#include <DiskArbitration/DiskArbitration.h>

#include <sstream>

namespace ID
{
	DiskInfoLogger::DiskInfoLogger(bool verbose, ASLClient const & logger) :
		DiskArbitrationHandler(logger),
		m_verbose(verbose)
	{
	}

	void DiskInfoLogger::diskAppeared(DADiskRef /*disk*/, DiskInformation const & info)
	{
		logger().log(ASL_LEVEL_NOTICE, "Disk Appeared: ", formatDisk(info));
	}

	void DiskInfoLogger::diskDisappeared(DADiskRef /*disk*/, DiskInformation const & info)
	{
		logger().log(ASL_LEVEL_NOTICE, "Disk Disappeared: ", formatDisk(info));
	}

	std::string DiskInfoLogger::formatDisk(DiskInformation const & info) const
	{
		std::stringstream ss;
		if (m_verbose)
			ss << info;
		else
			ss << info.mediaBSDName;
		return ss.str();
	}
}
<commit_msg>Log verbosity reduction<commit_after>//
//  IDDiskInfoLogger.cpp
//  InvariantDisks
//
//  Created by Gerhard Röthlin on 2014.04.27.
//  Copyright (c) 2014 the-color-black.net. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted
//  provided that the conditions of the "3-Clause BSD" license described in the BSD.LICENSE file are met.
//  Additional licensing options are described in the README file.
//

#include "IDDiskInfoLogger.hpp"

#include "IDDiskArbitrationUtils.hpp"

#include <DiskArbitration/DiskArbitration.h>

#include <sstream>

namespace ID
{
	DiskInfoLogger::DiskInfoLogger(bool verbose, ASLClient const & logger) :
		DiskArbitrationHandler(logger),
		m_verbose(verbose)
	{
	}

	void DiskInfoLogger::diskAppeared(DADiskRef /*disk*/, DiskInformation const & info)
	{
		if (m_verbose)
			logger().log(ASL_LEVEL_NOTICE, "Disk Appeared: ", formatDisk(info));
	}

	void DiskInfoLogger::diskDisappeared(DADiskRef /*disk*/, DiskInformation const & info)
	{
		if (m_verbose)
			logger().log(ASL_LEVEL_NOTICE, "Disk Disappeared: ", formatDisk(info));
	}

	std::string DiskInfoLogger::formatDisk(DiskInformation const & info) const
	{
		std::stringstream ss;
		ss << info;
		return ss.str();
	}
}
<|endoftext|>


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

// stl includes
#include <set>
#include <cstdlib>
#include <iostream>

// local Cognosco includes
#include "Dataset.hpp"
#include "CSVLoader.hpp"
#include "CognoscoError.hpp"
#include "NaiveBayes.hpp"

// bring these into the current namespace..
using std::set;
using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::vector;

/**
 * output an instance including all its attributes and one extra column for
 * its positive class probability.
 */
void
output_classification(const Instance &inst, const NaiveBayes &nb,
                      const vector<string> &att_names,
                      const string &pos_class_val) {
  for (size_t j = 0; j < att_names.size(); j++) {
    if (j != 0) cout << "\t";
    cout << inst.get_att_occurrence(att_names[j])->to_string();
  }
  cout << "\t" << nb.membership_probability(inst, pos_class_val) << endl;
}

void
k_fold_cross_validation(const Dataset &d, const size_t k,
                        const string &class_label,
                        const string &pos_class_val) {
  DatasetSplitter x_validation_splitter(k);
  DatasetSplit instances_in_fold(x_validation_splitter.split(d, class_label));

  vector<string> att_names;
  for (Dataset::const_attribute_iterator it = d.begin_attributes(); it != d.end_attributes(); ++it) {
    Attribute* att_ptr = (*it );
    att_names.push_back(att_ptr->get_name());
  }

  // for each fold, learn the classifier and output
  for (size_t fold_num = 0; fold_num < k; ++fold_num) {
    NaiveBayes nb;
    set<size_t> exclude(instances_in_fold[k].begin(), instances_in_fold[k].end());
    nb.learn(d, class_label, exclude);
    for (Dataset::const_iterator inst = d.begin(); inst != d.end(); ++inst) {
      if (exclude.find(inst->get_instance_id()) != exclude.end()) {
        output_classification(*inst, nb, att_names, pos_class_val);
      }
    }
  }
}

int
main(int argc, const char* argv[]) {
  try {
    const bool VERBOSE = true;

    if (argc == 4) {

    } else if (argc == 5) {

      Dataset train, test;
      CSVLoader csv_loader("\t");
      csv_loader.load(argv[1], train);
      csv_loader.load(argv[2], test);
      const string class_label(argv[3]);
      const string pos_class_val(argv[4]);

      if (VERBOSE) {
        cerr << "loaded training dataset with attributes: ";
        for (Dataset::const_attribute_iterator it = train.begin_attributes();
             it != train.end_attributes(); ++it) {
          if (it != train.begin_attributes()) cerr << ", ";
          cerr << (*it)->get_name();
        }
        cerr << endl;
      }

      NaiveBayes nb;
      nb.learn(train, class_label);
      cerr << nb.to_string() << endl;

      vector<string> attribute_names;
      for (Dataset::const_attribute_iterator it = test.begin_attributes();
          it != test.end_attributes(); ++it) {
        attribute_names.push_back((*it)->get_name());
      }

      for (Dataset::const_iterator inst = test.begin();
           inst != test.end(); ++inst) {

        for (size_t j = 0; j < attribute_names.size(); j++) {
          if (j != 0) cout << "\t";
          cout << inst->get_att_occurrence(attribute_names[j])->to_string();
        }
        cout << "\t" << nb.membership_probability(*inst, pos_class_val) << endl;
      }
    } else {
      cerr << "USAGE: ./classify training.dat testing.data class_label "
           << "positive_class_value" << endl;
      cerr << "USAGE: ./classify dataset.dat class_label "
           << "positive_class_value" << endl;
      cerr << "first version runs with test and training set, second "
              "perfroms ten-fold cross-validation" << endl;
    }

  } catch (const CognoscoError &e) {
    cerr << "ERROR:\t" << e.what() << endl;
    return EXIT_FAILURE;
  } catch (std::bad_alloc &ba) {
    cerr << "ERROR: could not allocate memory" << endl;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}
<commit_msg>filling in case for cross-validation<commit_after>/* The following applies to this software package and all subparts therein
 *
 * Cognosco Copyright (C) 2015 Philip J. Uren
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

// stl includes
#include <set>
#include <cstdlib>
#include <iostream>

// local Cognosco includes
#include "Dataset.hpp"
#include "CSVLoader.hpp"
#include "CognoscoError.hpp"
#include "NaiveBayes.hpp"

// bring these into the current namespace..
using std::set;
using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::vector;

/**
 * output an instance including all its attributes and one extra column for
 * its positive class probability.
 */
void
output_classification(const Instance &inst, const NaiveBayes &nb,
                      const vector<string> &att_names,
                      const string &pos_class_val) {
  for (size_t j = 0; j < att_names.size(); j++) {
    if (j != 0) cout << "\t";
    cout << inst.get_att_occurrence(att_names[j])->to_string();
  }
  cout << "\t" << nb.membership_probability(inst, pos_class_val) << endl;
}

void
k_fold_cross_validation(const Dataset &d, const size_t k,
                        const string &class_label,
                        const string &pos_class_val) {
  cerr << "creating splitter" << endl;
  DatasetSplitter x_validation_splitter(k);
  cerr << "splitting dataset" << endl;
  DatasetSplit instances_in_fold(x_validation_splitter.split(d, class_label));

  cerr << "extracting attributes" << endl;
  vector<string> att_names;
  for (Dataset::const_attribute_iterator it = d.begin_attributes(); it != d.end_attributes(); ++it) {
    Attribute* att_ptr = (*it );
    att_names.push_back(att_ptr->get_name());
  }

  cerr << "processing folds" << endl;
  // for each fold, learn the classifier and output
  for (size_t fold_num = 0; fold_num < k; ++fold_num) {
    NaiveBayes nb;
    //<< "pull out instance IDs for fold " << k << " when vec has length " << instances_in_fold.size();
    set<size_t> exclude(instances_in_fold[fold_num].begin(), instances_in_fold[fold_num].end());
    cerr << "learning NB classifier for fold " << fold_num << endl;
    nb.learn(d, class_label, exclude);
    for (Dataset::const_iterator inst = d.begin(); inst != d.end(); ++inst) {
      if (exclude.find(inst->get_instance_id()) != exclude.end()) {
        output_classification(*inst, nb, att_names, pos_class_val);
      }
    }
  }
}

int
main(int argc, const char* argv[]) {
  try {
    const bool VERBOSE = true;

    if (argc == 4) {
      Dataset d;
      CSVLoader csv_loader("\t");
      csv_loader.load(argv[1], d);
      const string class_label(argv[2]);
      const string pos_class_val(argv[3]);
      k_fold_cross_validation(d, 10, class_label, pos_class_val);
    } else if (argc == 5) {

      Dataset train, test;
      CSVLoader csv_loader("\t");
      csv_loader.load(argv[1], train);
      csv_loader.load(argv[2], test);
      const string class_label(argv[3]);
      const string pos_class_val(argv[4]);

      if (VERBOSE) {
        cerr << "loaded training dataset with attributes: ";
        for (Dataset::const_attribute_iterator it = train.begin_attributes();
             it != train.end_attributes(); ++it) {
          if (it != train.begin_attributes()) cerr << ", ";
          cerr << (*it)->get_name();
        }
        cerr << endl;
      }

      NaiveBayes nb;
      nb.learn(train, class_label);
      cerr << nb.to_string() << endl;

      vector<string> attribute_names;
      for (Dataset::const_attribute_iterator it = test.begin_attributes();
          it != test.end_attributes(); ++it) {
        attribute_names.push_back((*it)->get_name());
      }

      for (Dataset::const_iterator inst = test.begin();
           inst != test.end(); ++inst) {

        for (size_t j = 0; j < attribute_names.size(); j++) {
          if (j != 0) cout << "\t";
          cout << inst->get_att_occurrence(attribute_names[j])->to_string();
        }
        cout << "\t" << nb.membership_probability(*inst, pos_class_val) << endl;
      }
    } else {
      cerr << "USAGE: ./classify training.dat testing.data class_label "
           << "positive_class_value" << endl;
      cerr << "USAGE: ./classify dataset.dat class_label "
           << "positive_class_value" << endl;
      cerr << "first version runs with test and training set, second "
              "perfroms ten-fold cross-validation" << endl;
    }

  } catch (const CognoscoError &e) {
    cerr << "ERROR:\t" << e.what() << endl;
    return EXIT_FAILURE;
  } catch (std::bad_alloc &ba) {
    cerr << "ERROR: could not allocate memory" << endl;
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>fix pointer narrowing #1<commit_after><|endoftext|>


<commit_before>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

/// @file
///     @author Gus Grubba <mavlink@grubba.com>

#include "PowerComponent.h"
#include "QGCQmlWidgetHolder.h"
#include "PX4AutoPilotPlugin.h"

PowerComponent::PowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) :
    VehicleComponent(vehicle, autopilot, parent),
    _name(tr("Power"))
{
}

QString PowerComponent::name(void) const
{
    return _name;
}

QString PowerComponent::description(void) const
{
    return tr("The Power Component is used to setup battery parameters as well as advanced settings for propellers and magnetometer.");
}

QString PowerComponent::iconResource(void) const
{
    return "/qmlimages/PowerComponentIcon.png";
}

bool PowerComponent::requiresSetup(void) const
{
    return true;
}

bool PowerComponent::setupComplete(void) const
{
    QVariant cvalue, evalue, nvalue;
    return _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_V_CHARGED")->rawValue().toFloat() != 0.0f &&
        _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_V_EMPTY")->rawValue().toFloat() != 0.0f &&
        _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_N_CELLS")->rawValue().toInt() != 0;
}

QStringList PowerComponent::setupCompleteChangedTriggerList(void) const
{
    return QStringList();
}

QUrl PowerComponent::setupSource(void) const
{
    return QUrl::fromUserInput("qrc:/qml/PowerComponent.qml");
}

QUrl PowerComponent::summaryQmlSource(void) const
{
    return QUrl::fromUserInput("qrc:/qml/PowerComponentSummary.qml");
}

QString PowerComponent::prerequisiteSetup(void) const
{
    PX4AutoPilotPlugin* plugin = dynamic_cast<PX4AutoPilotPlugin*>(_autopilot);
    Q_ASSERT(plugin);
    if (!plugin->airframeComponent()->setupComplete()) {
        return plugin->airframeComponent()->name();
    }
    return QString();
}
<commit_msg>Fix trigger list<commit_after>/****************************************************************************
 *
 *   (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

/// @file
///     @author Gus Grubba <mavlink@grubba.com>

#include "PowerComponent.h"
#include "QGCQmlWidgetHolder.h"
#include "PX4AutoPilotPlugin.h"

PowerComponent::PowerComponent(Vehicle* vehicle, AutoPilotPlugin* autopilot, QObject* parent) :
    VehicleComponent(vehicle, autopilot, parent),
    _name(tr("Power"))
{
}

QString PowerComponent::name(void) const
{
    return _name;
}

QString PowerComponent::description(void) const
{
    return tr("The Power Component is used to setup battery parameters as well as advanced settings for propellers and magnetometer.");
}

QString PowerComponent::iconResource(void) const
{
    return "/qmlimages/PowerComponentIcon.png";
}

bool PowerComponent::requiresSetup(void) const
{
    return true;
}

bool PowerComponent::setupComplete(void) const
{
    QVariant cvalue, evalue, nvalue;
    return _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_V_CHARGED")->rawValue().toFloat() != 0.0f &&
        _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_V_EMPTY")->rawValue().toFloat() != 0.0f &&
        _autopilot->getParameterFact(FactSystem::defaultComponentId, "BAT_N_CELLS")->rawValue().toInt() != 0;
}

QStringList PowerComponent::setupCompleteChangedTriggerList(void) const
{
    QStringList triggerList;

    triggerList << "BAT_V_CHARGED" << "BAT_V_EMPTY" << "BAT_N_CELLS";
    return triggerList;
}

QUrl PowerComponent::setupSource(void) const
{
    return QUrl::fromUserInput("qrc:/qml/PowerComponent.qml");
}

QUrl PowerComponent::summaryQmlSource(void) const
{
    return QUrl::fromUserInput("qrc:/qml/PowerComponentSummary.qml");
}

QString PowerComponent::prerequisiteSetup(void) const
{
    PX4AutoPilotPlugin* plugin = dynamic_cast<PX4AutoPilotPlugin*>(_autopilot);
    Q_ASSERT(plugin);
    if (!plugin->airframeComponent()->setupComplete()) {
        return plugin->airframeComponent()->name();
    }
    return QString();
}
<|endoftext|>


<commit_before>/**
 * @file
 * @brief Implementation of pulse transfer module
 * @copyright Copyright (c) 2019 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "PulseTransferModule.hpp"
#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"

#include <string>
#include <utility>

#include <TAxis.h>
#include <TGraph.h>

using namespace allpix;

PulseTransferModule::PulseTransferModule(Configuration& config,
                                         Messenger* messenger,
                                         const std::shared_ptr<Detector>& detector)
    : Module(config, detector), detector_(detector), messenger_(messenger) {

    config_.setDefault<bool>("output_pulsegraphs", false);
    config_.setDefault<bool>("output_plots", config_.get<bool>("output_pulsegraphs"));
    config_.setDefault<int>("output_plots_scale", Units::get(30, "ke"));
    config_.setDefault<int>("output_plots_bins", 100);

    output_plots_ = config_.get<bool>("output_plots");
    output_pulsegraphs_ = config_.get<bool>("output_pulsegraphs");

    messenger_->bindSingle(this, &PulseTransferModule::message_, MsgFlags::REQUIRED);
}

void PulseTransferModule::init() {

    if(output_plots_) {
        LOG(TRACE) << "Creating output plots";

        // Plot axis are in kilo electrons - convert from framework units!
        int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
        auto nbins = config_.get<int>("output_plots_bins");

        // Create histograms if needed
        h_total_induced_charge_ =
            new TH1D("inducedcharge", "total induced charge;induced charge [ke];events", nbins, 0, maximum);
        h_induced_pixel_charge_ =
            new TH1D("pixelcharge", "induced charge per pixel;induced pixel charge [ke];pixels", nbins, 0, maximum);
    }
}

void PulseTransferModule::run(unsigned int event_num) {

    // Create map for all pixels: pulse and propagated charges
    std::map<Pixel::Index, Pulse> pixel_pulse_map;
    std::map<Pixel::Index, std::vector<const PropagatedCharge*>> pixel_charge_map;

    LOG(DEBUG) << "Received " << message_->getData().size() << " propagated charge objects.";
    for(const auto& propagated_charge : message_->getData()) {
        for(auto& pulse : propagated_charge.getPulses()) {
            auto pixel_index = pulse.first;

            // Accumulate all pulses from input message data:
            pixel_pulse_map[pixel_index] += pulse.second;

            auto px = pixel_charge_map[pixel_index];
            // For each pulse, store the corresponding propagated charges to preserve history:
            if(std::find(px.begin(), px.end(), &propagated_charge) == px.end()) {
                pixel_charge_map[pixel_index].emplace_back(&propagated_charge);
            }
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    Pulse total_pulse;
    for(auto& pixel_index_pulse : pixel_pulse_map) {
        auto index = pixel_index_pulse.first;
        auto pulse = pixel_index_pulse.second;

        // Sum all pulses for informational output:
        total_pulse += pulse;

        // Fill pixel charge histogram
        if(output_plots_) {
            h_induced_pixel_charge_->Fill(pulse.getCharge() / 1e3);
        }

        // Fill a graphs with the individual pixel pulses:
        if(output_pulsegraphs_) {
            auto step = pulse.getBinning();
            auto pulse_vec = pulse.getPulse();

            std::string name =
                "pulse_px" + std::to_string(index.x()) + "-" + std::to_string(index.y()) + "_" + std::to_string(event_num);

            // Generate x-axis:
            std::vector<double> time(pulse_vec.size());
            // clang-format off
            std::generate(time.begin(), time.end(), [n = 0.0, step]() mutable { return n += step; });
            // clang-format on

            auto pulse_graph = new TGraph(static_cast<int>(pulse_vec.size()), &time[0], &pulse_vec[0]);
            pulse_graph->GetXaxis()->SetTitle("t [ns]");
            pulse_graph->GetYaxis()->SetTitle("Q_{ind} [e]");
            pulse_graph->SetTitle(("Induced charge in pixel (" + std::to_string(index.x()) + "," +
                                   std::to_string(index.y()) +
                                   "), Q_{tot} = " + std::to_string(pixel_index_pulse.second.getCharge()) + " e")
                                      .c_str());
            pulse_graph->Write(name.c_str());
        }
        LOG(DEBUG) << "Charge on pixel " << index << " has " << pixel_charge_map[index].size() << " ancestors";

        // Store the pulse:
        pixel_charges.emplace_back(detector_->getPixel(index), std::move(pulse), pixel_charge_map[index]);
    }

    // Create a new message with pixel pulses and dispatch:
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);
    messenger_->dispatchMessage(this, pixel_charge_message);

    // Fill pixel charge histogram
    if(output_plots_) {
        h_total_induced_charge_->Fill(total_pulse.getCharge() / 1e3);
    }

    LOG(INFO) << "Total charge induced on all pixels: " << Units::display(total_pulse.getCharge(), "e");
}

void PulseTransferModule::finalize() {

    if(output_plots_) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        h_induced_pixel_charge_->Write();
        h_total_induced_charge_->Write();
    }
}
<commit_msg>PulseTransfer: enable parallelization<commit_after>/**
 * @file
 * @brief Implementation of pulse transfer module
 * @copyright Copyright (c) 2019 CERN and the Allpix Squared authors.
 * This software is distributed under the terms of the MIT License, copied verbatim in the file "LICENSE.md".
 * In applying this license, CERN does not waive the privileges and immunities granted to it by virtue of its status as an
 * Intergovernmental Organization or submit itself to any jurisdiction.
 */

#include "PulseTransferModule.hpp"
#include "core/utils/log.h"
#include "objects/PixelCharge.hpp"

#include <string>
#include <utility>

#include <TAxis.h>
#include <TGraph.h>

using namespace allpix;

PulseTransferModule::PulseTransferModule(Configuration& config,
                                         Messenger* messenger,
                                         const std::shared_ptr<Detector>& detector)
    : Module(config, detector), detector_(detector), messenger_(messenger) {
    // Enable parallelization of this module if multithreading is enabled
    enable_parallelization();

    config_.setDefault<bool>("output_pulsegraphs", false);
    config_.setDefault<bool>("output_plots", config_.get<bool>("output_pulsegraphs"));
    config_.setDefault<int>("output_plots_scale", Units::get(30, "ke"));
    config_.setDefault<int>("output_plots_bins", 100);

    output_plots_ = config_.get<bool>("output_plots");
    output_pulsegraphs_ = config_.get<bool>("output_pulsegraphs");

    messenger_->bindSingle(this, &PulseTransferModule::message_, MsgFlags::REQUIRED);
}

void PulseTransferModule::init() {

    if(output_plots_) {
        LOG(TRACE) << "Creating output plots";

        // Plot axis are in kilo electrons - convert from framework units!
        int maximum = static_cast<int>(Units::convert(config_.get<int>("output_plots_scale"), "ke"));
        auto nbins = config_.get<int>("output_plots_bins");

        // Create histograms if needed
        h_total_induced_charge_ =
            new TH1D("inducedcharge", "total induced charge;induced charge [ke];events", nbins, 0, maximum);
        h_induced_pixel_charge_ =
            new TH1D("pixelcharge", "induced charge per pixel;induced pixel charge [ke];pixels", nbins, 0, maximum);
    }
}

void PulseTransferModule::run(unsigned int event_num) {

    // Create map for all pixels: pulse and propagated charges
    std::map<Pixel::Index, Pulse> pixel_pulse_map;
    std::map<Pixel::Index, std::vector<const PropagatedCharge*>> pixel_charge_map;

    LOG(DEBUG) << "Received " << message_->getData().size() << " propagated charge objects.";
    for(const auto& propagated_charge : message_->getData()) {
        for(auto& pulse : propagated_charge.getPulses()) {
            auto pixel_index = pulse.first;

            // Accumulate all pulses from input message data:
            pixel_pulse_map[pixel_index] += pulse.second;

            auto px = pixel_charge_map[pixel_index];
            // For each pulse, store the corresponding propagated charges to preserve history:
            if(std::find(px.begin(), px.end(), &propagated_charge) == px.end()) {
                pixel_charge_map[pixel_index].emplace_back(&propagated_charge);
            }
        }
    }

    // Create vector of pixel pulses to return for this detector
    std::vector<PixelCharge> pixel_charges;
    Pulse total_pulse;
    for(auto& pixel_index_pulse : pixel_pulse_map) {
        auto index = pixel_index_pulse.first;
        auto pulse = pixel_index_pulse.second;

        // Sum all pulses for informational output:
        total_pulse += pulse;

        // Fill pixel charge histogram
        if(output_plots_) {
            h_induced_pixel_charge_->Fill(pulse.getCharge() / 1e3);
        }

        // Fill a graphs with the individual pixel pulses:
        if(output_pulsegraphs_) {
            auto step = pulse.getBinning();
            auto pulse_vec = pulse.getPulse();

            std::string name =
                "pulse_px" + std::to_string(index.x()) + "-" + std::to_string(index.y()) + "_" + std::to_string(event_num);

            // Generate x-axis:
            std::vector<double> time(pulse_vec.size());
            // clang-format off
            std::generate(time.begin(), time.end(), [n = 0.0, step]() mutable { return n += step; });
            // clang-format on

            auto pulse_graph = new TGraph(static_cast<int>(pulse_vec.size()), &time[0], &pulse_vec[0]);
            pulse_graph->GetXaxis()->SetTitle("t [ns]");
            pulse_graph->GetYaxis()->SetTitle("Q_{ind} [e]");
            pulse_graph->SetTitle(("Induced charge in pixel (" + std::to_string(index.x()) + "," +
                                   std::to_string(index.y()) +
                                   "), Q_{tot} = " + std::to_string(pixel_index_pulse.second.getCharge()) + " e")
                                      .c_str());
            pulse_graph->Write(name.c_str());
        }
        LOG(DEBUG) << "Charge on pixel " << index << " has " << pixel_charge_map[index].size() << " ancestors";

        // Store the pulse:
        pixel_charges.emplace_back(detector_->getPixel(index), std::move(pulse), pixel_charge_map[index]);
    }

    // Create a new message with pixel pulses and dispatch:
    auto pixel_charge_message = std::make_shared<PixelChargeMessage>(std::move(pixel_charges), detector_);
    messenger_->dispatchMessage(this, pixel_charge_message);

    // Fill pixel charge histogram
    if(output_plots_) {
        h_total_induced_charge_->Fill(total_pulse.getCharge() / 1e3);
    }

    LOG(INFO) << "Total charge induced on all pixels: " << Units::display(total_pulse.getCharge(), "e");
}

void PulseTransferModule::finalize() {

    if(output_plots_) {
        // Write histograms
        LOG(TRACE) << "Writing output plots to file";
        h_induced_pixel_charge_->Write();
        h_total_induced_charge_->Write();
    }
}
<|endoftext|>


<commit_before>#include<bits/stdc++.h>
#include "sg-ast.h"
/*
 * StreamGraph language
 *
 * The code related to the abstract syntax tree such
 * as parsing.
 *
 * Pascal Sommer, November 2016
 *
 */

// this is used for the error messages
int line_number;
bool has_error;

void log(std::string type, std::string message){
    std::cerr<<type << " on line " << line_number << ": " << message <<"\n";
}

void log_error(std::string message){
    log("ERROR", message);
    has_error = true;
}
void log_warning(std::string message){
    log("WARNING", message);
}

std::string trimWhitespace(std::string line){
    // strip leading whitespace
    auto strBegin = line.find_first_not_of(" \t");
    if (strBegin != std::string::npos){
	// trim trailing whitespace as well
	auto strEnd = line.find_last_not_of(" \t");
	auto strRange = strEnd - strBegin + 1;

	return line.substr(strBegin, strRange);
    }else{
	// line is empty
	return "";
    }
}

bool alphanumeric(std::string s){
    for(auto c:s){
	if(!isalnum(c)) return false;
    }
    return true;
}

std::string stringToLower(std::string & in){
    std::string out = in;
    for(auto & c: out){
	c = tolower(c);
    }
    return out;
}

Node* parse_node(std::istringstream & line){
    std::string name;
    std::string command;

    std::regex e ("^([a-zA-Z0-9]+)([-:/])\\s*(.*)");
    std::smatch sm;

    std::string sline = line.str();

    if(std::regex_match(sline, sm, e) && sm.size()==4){
	Node* n;

	char node_delimiter = sm.str(2)[0];
	if(node_delimiter == ':'){
	    Bash_node* temp_node = new Bash_node();
	    temp_node->command = sm.str(3);
	    n = temp_node;
	}else if( node_delimiter == '-'){
	    Instance_node* temp_node = new Instance_node();
	    temp_node->group_name = sm.str(3);
	    n = temp_node;
	}else{
	    Io_node* temp_node = new Io_node();
	    temp_node->io_instruction = sm.str(3);
	    n = temp_node;
	}

	n->name = sm.str(1);

    }else{
	log_error("Incorrect syntax:\n"
		  "    Expected: node <name>[:-/] <command>\n"
		  "    Found: node " + sline + "\n");
	return NULL;
    }

}

Edge* parse_edge(std::istringstream & line){
    std::string start;
    std::string end;

    bool ok = (line >> start) && (line >> end);

    if (! ok){
	log_error("Incorrect edge syntax:\n"
		  "    Expected: e <node_name> <node_name>.\n"
		  "    Found: e " + start + "\n");
	return NULL;
    }

    std::string tmp;
    if(line >> tmp){
	log_error("Incorrect edge syntax:\n"
		  "    Expected: e <node_name> <node_name>.\n    "
		  "    Found: e " + start + " " + end + " " + tmp + "\n");
	return NULL;
    }

    Edge* e = new Edge();
    e->source_name = start;
    e->destination_name = end;

    return e;
}

void start_next_subtree(std::stack<Ast*> & current_scope, Ast* & next_subtree){
    current_scope.push(next_subtree);
    next_subtree = NULL;
}

// this function calls itself recursively whenever
// a new group is created inside the main scope
// or inside another group
//
// due to the simple nature of the
// language, this should be in O(n)
Ast* ast_parse(std::ifstream & infile, std::stack<Ast*> & current_scope){
    Ast* next_subtree = NULL;

    std::string line = "";

    while(getline(infile, line)){
	++line_number; // start at line number 1

	line = trimWhitespace(line);

	// is line a comment or empty?
	if(line[0]=='#' || line.length() == 0){
	    continue;
	}

	// check for '}'
	if(line[0]=='}'){
	    // finish current subtree
	    if(current_scope.size() == 1){
		// can't close main group
		log_error("Incorrect syntax:\n"
			  "    Found: '}'\n"
			  "    Can't close main group.\n");
	    }else{
		current_scope.pop();
	    }
	}

	// also, check for '{' if the next subtree
	// hasn't opened yet.
	if(next_subtree != NULL){
	    if(line[0]=='{'){
		start_next_subtree(current_scope, next_subtree);
		continue;
	    }else{
		// maybe add empty group feature later on, for the sake of
		// quick prototyping, but for now this is an error
		log_error("Incorrect group syntax:\n"
			  "    Expected: start of group block '{'\n"
			  "    Found: " + line + "\n");
		next_subtree = NULL;
		continue;
	    }
	}

	// convert line to stringstream to make it
	// easier to read word by word
	std::istringstream iss(line);
	std::string type;
	iss >> type;

	type = stringToLower(type);

	Ast_element* next_element = NULL;

	if(type=="node" || type == "n"){
	    next_element = parse_node(iss);
	}else if (type == "edge" || type == "e"){
	    next_element = parse_edge(iss);
	}else if (type == "group" || type == "g"){
	    next_subtree = new Ast();
	    if ( ! (iss >> next_subtree->name)){
		log_error("Incorrect group syntax:\n"
			  "    Expected: group <group_name>\n");
	    }
	    if(! alphanumeric(next_subtree->name)){
		log_error("Incorrect group syntax:\n"
			  "    Group name has to be alphanumeric\n"
			  "    Found: " + next_subtree->name + "\n");
	    }
	    std::string rest = trimWhitespace(iss.str());
	    if(rest.length() > 0){
		if(rest[0] == '{'){
		    start_next_subtree(current_scope, next_subtree);
		}else{
		    log_error("Incorrect group syntax:\n"
			      "    Expected: '{' or '\n'"
			      "    Found: " + rest + "\n");
		}
	    }
	}else{
	    log_error("Incorrect syntax:\n"
		      "    Expected: either 'node', 'edge' or 'group'"
		      "    Found: " + type + "\n");
	}

	if(next_element != NULL){
	    current_scope.top()->elements.push_back(next_element);
	}
    }
}

void link_tree(Ast* ast){

}

// main parser function
// assumes that ifstream is ok
Ast* parse_file(std::ifstream &infile){

    Ast* root = new Ast();
    std::stack<Ast*> current_scope;

    current_scope.push(root);

    line_number = 0;
    has_error = false;

    root = ast_parse(infile, current_scope);

    if(has_error){
	// some errors have happened.
	std::cerr<<"\n\nCompilation failed\n";
	return NULL;
    }
}
<commit_msg>Start linking function<commit_after>#include<bits/stdc++.h>
#include "sg-ast.h"
/*
 * StreamGraph language
 *
 * The code related to the abstract syntax tree such
 * as parsing.
 *
 * Pascal Sommer, November 2016
 *
 */

// this is used for the error messages
int line_number;
bool has_error;

void log(std::string type, std::string message){
    std::cerr<<type << " on line " << line_number << ": " << message <<"\n";
}

void log_error(std::string message){
    log("ERROR", message);
    has_error = true;
}
void log_warning(std::string message){
    log("WARNING", message);
}

std::string trimWhitespace(std::string line){
    // strip leading whitespace
    auto strBegin = line.find_first_not_of(" \t");
    if (strBegin != std::string::npos){
	// trim trailing whitespace as well
	auto strEnd = line.find_last_not_of(" \t");
	auto strRange = strEnd - strBegin + 1;

	return line.substr(strBegin, strRange);
    }else{
	// line is empty
	return "";
    }
}

bool alphanumeric(std::string s){
    for(auto c:s){
	if(!isalnum(c)) return false;
    }
    return true;
}

std::string stringToLower(std::string & in){
    std::string out = in;
    for(auto & c: out){
	c = tolower(c);
    }
    return out;
}

Node* parse_node(std::istringstream & line){
    std::string name;
    std::string command;

    std::regex e ("^([a-zA-Z0-9]+)([-:/])\\s*(.*)");
    std::smatch sm;

    std::string sline = line.str();

    if(std::regex_match(sline, sm, e) && sm.size()==4){
	Node* n;

	char node_delimiter = sm.str(2)[0];
	if(node_delimiter == ':'){
	    Bash_node* temp_node = new Bash_node();
	    temp_node->command = sm.str(3);
	    n = temp_node;
	}else if( node_delimiter == '-'){
	    Instance_node* temp_node = new Instance_node();
	    temp_node->group_name = sm.str(3);
	    n = temp_node;
	}else{
	    Io_node* temp_node = new Io_node();
	    temp_node->io_instruction = sm.str(3);
	    n = temp_node;
	}

	n->name = sm.str(1);

    }else{
	log_error("Incorrect syntax:\n"
		  "    Expected: node <name>[:-/] <command>\n"
		  "    Found: node " + sline + "\n");
	return NULL;
    }

}

Edge* parse_edge(std::istringstream & line){
    std::string start;
    std::string end;

    bool ok = (line >> start) && (line >> end);

    if (! ok){
	log_error("Incorrect edge syntax:\n"
		  "    Expected: e <node_name> <node_name>.\n"
		  "    Found: e " + start + "\n");
	return NULL;
    }

    std::string tmp;
    if(line >> tmp){
	log_error("Incorrect edge syntax:\n"
		  "    Expected: e <node_name> <node_name>.\n    "
		  "    Found: e " + start + " " + end + " " + tmp + "\n");
	return NULL;
    }

    Edge* e = new Edge();
    e->source_name = start;
    e->destination_name = end;

    return e;
}

void start_next_subtree(std::stack<Ast*> & current_scope, Ast* & next_subtree){
    current_scope.push(next_subtree);
    next_subtree = NULL;
}

// this function calls itself recursively whenever
// a new group is created inside the main scope
// or inside another group
//
// due to the simple nature of the
// language, this should be in O(n)
Ast* ast_parse(std::ifstream & infile, std::stack<Ast*> & current_scope){
    Ast* next_subtree = NULL;

    std::string line = "";

    while(getline(infile, line)){
	++line_number; // start at line number 1

	line = trimWhitespace(line);

	// is line a comment or empty?
	if(line[0]=='#' || line.length() == 0){
	    continue;
	}

	// check for '}'
	if(line[0]=='}'){
	    // finish current subtree
	    if(current_scope.size() == 1){
		// can't close main group
		log_error("Incorrect syntax:\n"
			  "    Found: '}'\n"
			  "    Can't close main group.\n");
	    }else{
		current_scope.pop();
	    }
	}

	// also, check for '{' if the next subtree
	// hasn't opened yet.
	if(next_subtree != NULL){
	    if(line[0]=='{'){
		start_next_subtree(current_scope, next_subtree);
		continue;
	    }else{
		// maybe add empty group feature later on, for the sake of
		// quick prototyping, but for now this is an error
		log_error("Incorrect group syntax:\n"
			  "    Expected: start of group block '{'\n"
			  "    Found: " + line + "\n");
		next_subtree = NULL;
		continue;
	    }
	}

	// convert line to stringstream to make it
	// easier to read word by word
	std::istringstream iss(line);
	std::string type;
	iss >> type;

	type = stringToLower(type);

	Ast_element* next_element = NULL;

	if(type=="node" || type == "n"){
	    next_element = parse_node(iss);
	}else if (type == "edge" || type == "e"){
	    next_element = parse_edge(iss);
	}else if (type == "group" || type == "g"){
	    next_subtree = new Ast();
	    if ( ! (iss >> next_subtree->name)){
		log_error("Incorrect group syntax:\n"
			  "    Expected: group <group_name>\n");
	    }
	    if(! alphanumeric(next_subtree->name)){
		log_error("Incorrect group syntax:\n"
			  "    Group name has to be alphanumeric\n"
			  "    Found: " + next_subtree->name + "\n");
	    }
	    std::string rest = trimWhitespace(iss.str());
	    if(rest.length() > 0){
		if(rest[0] == '{'){
		    start_next_subtree(current_scope, next_subtree);
		}else{
		    log_error("Incorrect group syntax:\n"
			      "    Expected: '{' or '\n'"
			      "    Found: " + rest + "\n");
		}
	    }
	}else{
	    log_error("Incorrect syntax:\n"
		      "    Expected: either 'node', 'edge' or 'group'"
		      "    Found: " + type + "\n");
	}

	if(next_element != NULL){
	    current_scope.top()->elements.push_back(next_element);
	}
    }
}

void link_tree(Ast* ast, std::map<string, Ast_element*> variables){
    // get variables in current scope
    for(auto e:ast){

    }

}

// main parser function
// assumes that ifstream is ok
Ast* parse_file(std::ifstream &infile){

    Ast* root = new Ast();
    std::stack<Ast*> current_scope;

    current_scope.push(root);

    line_number = 0;
    has_error = false;

    root = ast_parse(infile, current_scope);

    if(has_error){
	// some errors have happened.
	std::cerr<<"\n\nCompilation failed\n";
	return NULL;
    }
}
<|endoftext|>


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

#include <boost/python.hpp>
#include <cassert>

#include "boost/static_assert.hpp"

#include "IECore/LineSegment.h"
#include "IECore/bindings/LineSegmentBinding.h"

using namespace boost::python;

namespace IECore
{

template<class L>
static const char *typeName()
{
	BOOST_STATIC_ASSERT( sizeof(L) == 0 );
	return "";
}

template<>
static const char *typeName<LineSegment2f>()
{
	return "LineSegment2f";
}

template<>
static const char *typeName<LineSegment2d>()
{
	return "LineSegment2d";
}

template<>
static const char *typeName<LineSegment3f>()
{
	return "LineSegment3f";
}

template<>
static const char *typeName<LineSegment3d>()
{
	return "LineSegment3d";
}

template<class L>
static std::string repr( L &x )
{
	std::stringstream s;

	s << "IECore." << typeName<L>() << "( ";

	object item0( x.p0 );
	assert( item.attr0( "__repr__" ) != object() );
	s << call_method< std::string >( item0.ptr(), "__repr__" ) << ", ";

	object item1( x.p1 );
	assert( item.attr1( "__repr__" ) != object() );
	s << call_method< std::string >( item1.ptr(), "__repr__" ) << " )";

	return s.str();
}

template<class L>
static tuple closestPoints( const L &l, const L &l2 )
{
	typename L::Point a, b;
	a = l.closestPoints( l2, b );
	return make_tuple( a, b );
}

template<typename Vec>
static void bind3D()
{
	typedef typename Vec::BaseType BaseType;
	typedef LineSegment<Vec> L;
	typedef Imath::Matrix44<BaseType> M;

	const char *name = typeName< L >();

	class_<L>( name )
		.def( init<L>() )
		.def( init<Vec, Vec>() )
		.def_readwrite( "p0", &L::p0 )
		.def_readwrite( "p1", &L::p1 )
		.def( "__repr__", &repr<L> )
		.def( "__call__", &L::operator() )
		.def( "direction", &L::direction )
		.def( "normalizedDirection", &L::normalizedDirection )
		.def( "length", &L::length )
		.def( "length2", &L::length2 )
		.def( "closestPointTo", &L::closestPointTo )
		.def( "closestPoints", &closestPoints<L> )
		.def( "distanceTo", (typename L::BaseType (L::*)( const Vec & ) const)&L::distanceTo )
		.def( "distanceTo", (typename L::BaseType (L::*)( const L & ) const)&L::distanceTo )
		.def( "distance2To", (typename L::BaseType (L::*)( const Vec & ) const)&L::distance2To )
		.def( "distance2To", (typename L::BaseType (L::*)( const L & ) const)&L::distance2To )
		.def( self *= M() )
		.def( self * M() )
		.def( self == self )
		.def( self != self )
		/// \todo Bind the intersect methods when we have a binding for ImathPlane
	;

}

template<typename Vec>
static void bind2D()
{
	typedef typename Vec::BaseType BaseType;
	typedef LineSegment<Vec> L;
	typedef Imath::Matrix33<BaseType> M;

	const char *name = typeName< L >();

	class_<L>( name )
		.def( init<L>() )
		.def( init<Vec, Vec>() )
		.def_readwrite( "p0", &L::p0 )
		.def_readwrite( "p1", &L::p1 )
		.def( "__repr__", &repr<L> )
		.def( "__call__", &L::operator() )
		.def( "direction", &L::direction )
		.def( "normalizedDirection", &L::normalizedDirection )
		.def( "length", &L::length )
		.def( "length2", &L::length2 )
		.def( "closestPointTo", &L::closestPointTo )
		.def( "distanceTo", (typename L::BaseType (L::*)( const Vec & ) const)&L::distanceTo )
		.def( "distance2To", (typename L::BaseType (L::*)( const Vec & ) const)&L::distance2To )
		.def( self *= M() )
		.def( self * M() )
		.def( self == self )
		.def( self != self )
	;

}

void bindLineSegment()
{
	bind3D<Imath::V3f>();
	bind3D<Imath::V3d>();
	bind2D<Imath::V2f>();
	bind2D<Imath::V2d>();
}

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

#include <boost/python.hpp>
#include <cassert>

#include "boost/static_assert.hpp"

#include "IECore/LineSegment.h"
#include "IECore/bindings/LineSegmentBinding.h"

using namespace boost::python;

namespace IECore
{

template<class L>
static const char *typeName()
{
	BOOST_STATIC_ASSERT( sizeof(L) == 0 );
	return "";
}

template<>
static const char *typeName<LineSegment2f>()
{
	return "LineSegment2f";
}

template<>
static const char *typeName<LineSegment2d>()
{
	return "LineSegment2d";
}

template<>
static const char *typeName<LineSegment3f>()
{
	return "LineSegment3f";
}

template<>
static const char *typeName<LineSegment3d>()
{
	return "LineSegment3d";
}

template<class L>
static std::string repr( L &x )
{
	std::stringstream s;

	s << "IECore." << typeName<L>() << "( ";

	object item0( x.p0 );
	assert( item0.attr( "__repr__" ) != object() );
	s << call_method< std::string >( item0.ptr(), "__repr__" ) << ", ";

	object item1( x.p1 );
	assert( item1.attr( "__repr__" ) != object() );
	s << call_method< std::string >( item1.ptr(), "__repr__" ) << " )";

	return s.str();
}

template<class L>
static tuple closestPoints( const L &l, const L &l2 )
{
	typename L::Point a, b;
	a = l.closestPoints( l2, b );
	return make_tuple( a, b );
}

template<typename Vec>
static void bind3D()
{
	typedef typename Vec::BaseType BaseType;
	typedef LineSegment<Vec> L;
	typedef Imath::Matrix44<BaseType> M;

	const char *name = typeName< L >();

	class_<L>( name )
		.def( init<L>() )
		.def( init<Vec, Vec>() )
		.def_readwrite( "p0", &L::p0 )
		.def_readwrite( "p1", &L::p1 )
		.def( "__repr__", &repr<L> )
		.def( "__call__", &L::operator() )
		.def( "direction", &L::direction )
		.def( "normalizedDirection", &L::normalizedDirection )
		.def( "length", &L::length )
		.def( "length2", &L::length2 )
		.def( "closestPointTo", &L::closestPointTo )
		.def( "closestPoints", &closestPoints<L> )
		.def( "distanceTo", (typename L::BaseType (L::*)( const Vec & ) const)&L::distanceTo )
		.def( "distanceTo", (typename L::BaseType (L::*)( const L & ) const)&L::distanceTo )
		.def( "distance2To", (typename L::BaseType (L::*)( const Vec & ) const)&L::distance2To )
		.def( "distance2To", (typename L::BaseType (L::*)( const L & ) const)&L::distance2To )
		.def( self *= M() )
		.def( self * M() )
		.def( self == self )
		.def( self != self )
		/// \todo Bind the intersect methods when we have a binding for ImathPlane
	;

}

template<typename Vec>
static void bind2D()
{
	typedef typename Vec::BaseType BaseType;
	typedef LineSegment<Vec> L;
	typedef Imath::Matrix33<BaseType> M;

	const char *name = typeName< L >();

	class_<L>( name )
		.def( init<L>() )
		.def( init<Vec, Vec>() )
		.def_readwrite( "p0", &L::p0 )
		.def_readwrite( "p1", &L::p1 )
		.def( "__repr__", &repr<L> )
		.def( "__call__", &L::operator() )
		.def( "direction", &L::direction )
		.def( "normalizedDirection", &L::normalizedDirection )
		.def( "length", &L::length )
		.def( "length2", &L::length2 )
		.def( "closestPointTo", &L::closestPointTo )
		.def( "distanceTo", (typename L::BaseType (L::*)( const Vec & ) const)&L::distanceTo )
		.def( "distance2To", (typename L::BaseType (L::*)( const Vec & ) const)&L::distance2To )
		.def( self *= M() )
		.def( self * M() )
		.def( self == self )
		.def( self != self )
	;

}

void bindLineSegment()
{
	bind3D<Imath::V3f>();
	bind3D<Imath::V3d>();
	bind2D<Imath::V2f>();
	bind2D<Imath::V2d>();
}

} // namespace IECore
<|endoftext|>


<commit_before>//===-- AMDGPUTargetTransformInfo.cpp - AMDGPU specific TTI pass ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// \file
// This file implements a TargetTransformInfo analysis pass specific to the
// AMDGPU target machine. It uses the target's detailed information to provide
// more precise answers to certain TTI queries, while letting the target
// independent and default TTI implementations handle the rest.
//
//===----------------------------------------------------------------------===//

#include "AMDGPUTargetTransformInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/BasicTTIImpl.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/CostTable.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

#define DEBUG_TYPE "AMDGPUtti"

void AMDGPUTTIImpl::getUnrollingPreferences(Loop *L,
                                            TTI::UnrollingPreferences &UP) {
  UP.Threshold = 300; // Twice the default.
  UP.MaxCount = UINT_MAX;
  UP.Partial = true;

  // TODO: Do we want runtime unrolling?

  for (const BasicBlock *BB : L->getBlocks()) {
    const DataLayout &DL = BB->getModule()->getDataLayout();
    for (const Instruction &I : *BB) {
      const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&I);
      if (!GEP || GEP->getAddressSpace() != AMDGPUAS::PRIVATE_ADDRESS)
        continue;

      const Value *Ptr = GEP->getPointerOperand();
      const AllocaInst *Alloca =
          dyn_cast<AllocaInst>(GetUnderlyingObject(Ptr, DL));
      if (Alloca) {
        // We want to do whatever we can to limit the number of alloca
        // instructions that make it through to the code generator.  allocas
        // require us to use indirect addressing, which is slow and prone to
        // compiler bugs.  If this loop does an address calculation on an
        // alloca ptr, then we want to use a higher than normal loop unroll
        // threshold. This will give SROA a better chance to eliminate these
        // allocas.
        //
        // Don't use the maximum allowed value here as it will make some
        // programs way too big.
        UP.Threshold = 800;
      }
    }
  }
}

unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) {
  if (Vec)
    return 0;

  // Number of VGPRs on SI.
  if (ST->getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS)
    return 256;

  return 4 * 128; // XXX - 4 channels. Should these count as vector instead?
}

unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool) { return 32; }

unsigned AMDGPUTTIImpl::getMaxInterleaveFactor(unsigned VF) {
  // Semi-arbitrary large amount.
  return 64;
}

unsigned AMDGPUTTIImpl::getCFInstrCost(unsigned Opcode) {
  // XXX - For some reason this isn't called for switch.
  switch (Opcode) {
  case Instruction::Br:
  case Instruction::Ret:
    return 10;
  default:
    return BaseT::getCFInstrCost(Opcode);
  }
}

int AMDGPUTTIImpl::getVectorInstrCost(unsigned Opcode, Type *ValTy,
                                      unsigned Index) {
  switch (Opcode) {
  case Instruction::ExtractElement:
    // Dynamic indexing isn't free and is best avoided.
    return Index == ~0u ? 2 : 0;
  default:
    return BaseT::getVectorInstrCost(Opcode, ValTy, Index);
  }
}

static bool isIntrinsicSourceOfDivergence(const TargetIntrinsicInfo *TII,
                                          const IntrinsicInst *I) {
  switch (I->getIntrinsicID()) {
  default:
    return false;
  case Intrinsic::not_intrinsic:
    // This means we have an intrinsic that isn't defined in
    // IntrinsicsAMDGPU.td
    break;

  case Intrinsic::amdgcn_interp_p1:
  case Intrinsic::amdgcn_interp_p2:
  case Intrinsic::amdgcn_mbcnt_hi:
  case Intrinsic::amdgcn_mbcnt_lo:
  case Intrinsic::r600_read_tidig_x:
  case Intrinsic::r600_read_tidig_y:
  case Intrinsic::r600_read_tidig_z:
    return true;
  }

  StringRef Name = I->getCalledFunction()->getName();
  switch (TII->lookupName((const char *)Name.bytes_begin(), Name.size())) {
  default:
    return false;
  case AMDGPUIntrinsic::SI_tid:
  case AMDGPUIntrinsic::SI_fs_interp:
    return true;
  }
}

static bool isArgPassedInSGPR(const Argument *A) {
  const Function *F = A->getParent();
  unsigned ShaderType = AMDGPU::getShaderType(*F);

  // Arguments to compute shaders are never a source of divergence.
  if (ShaderType == ShaderType::COMPUTE)
    return true;

  // For non-compute shaders, SGPR inputs are marked with either inreg or byval.
  if (F->getAttributes().hasAttribute(A->getArgNo() + 1, Attribute::InReg) ||
      F->getAttributes().hasAttribute(A->getArgNo() + 1, Attribute::ByVal))
    return true;

  // Everything else is in VGPRs.
  return false;
}

///
/// \returns true if the result of the value could potentially be
/// different across workitems in a wavefront.
bool AMDGPUTTIImpl::isSourceOfDivergence(const Value *V) const {

  if (const Argument *A = dyn_cast<Argument>(V))
    return !isArgPassedInSGPR(A);

  // Loads from the private address space are divergent, because threads
  // can execute the load instruction with the same inputs and get different
  // results.
  //
  // All other loads are not divergent, because if threads issue loads with the
  // same arguments, they will always get the same result.
  if (const LoadInst *Load = dyn_cast<LoadInst>(V))
    return Load->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS;

  if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(V)) {
    const TargetMachine &TM = getTLI()->getTargetMachine();
    return isIntrinsicSourceOfDivergence(TM.getIntrinsicInfo(), Intrinsic);
  }

  // Assume all function calls are a source of divergence.
  if (isa<CallInst>(V) || isa<InvokeInst>(V))
    return true;

  return false;
}
<commit_msg>AMDGPU: Fix getRegisterBitWidth for vectors<commit_after>//===-- AMDGPUTargetTransformInfo.cpp - AMDGPU specific TTI pass ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// \file
// This file implements a TargetTransformInfo analysis pass specific to the
// AMDGPU target machine. It uses the target's detailed information to provide
// more precise answers to certain TTI queries, while letting the target
// independent and default TTI implementations handle the rest.
//
//===----------------------------------------------------------------------===//

#include "AMDGPUTargetTransformInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/CodeGen/BasicTTIImpl.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/CostTable.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

#define DEBUG_TYPE "AMDGPUtti"

void AMDGPUTTIImpl::getUnrollingPreferences(Loop *L,
                                            TTI::UnrollingPreferences &UP) {
  UP.Threshold = 300; // Twice the default.
  UP.MaxCount = UINT_MAX;
  UP.Partial = true;

  // TODO: Do we want runtime unrolling?

  for (const BasicBlock *BB : L->getBlocks()) {
    const DataLayout &DL = BB->getModule()->getDataLayout();
    for (const Instruction &I : *BB) {
      const GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&I);
      if (!GEP || GEP->getAddressSpace() != AMDGPUAS::PRIVATE_ADDRESS)
        continue;

      const Value *Ptr = GEP->getPointerOperand();
      const AllocaInst *Alloca =
          dyn_cast<AllocaInst>(GetUnderlyingObject(Ptr, DL));
      if (Alloca) {
        // We want to do whatever we can to limit the number of alloca
        // instructions that make it through to the code generator.  allocas
        // require us to use indirect addressing, which is slow and prone to
        // compiler bugs.  If this loop does an address calculation on an
        // alloca ptr, then we want to use a higher than normal loop unroll
        // threshold. This will give SROA a better chance to eliminate these
        // allocas.
        //
        // Don't use the maximum allowed value here as it will make some
        // programs way too big.
        UP.Threshold = 800;
      }
    }
  }
}

unsigned AMDGPUTTIImpl::getNumberOfRegisters(bool Vec) {
  if (Vec)
    return 0;

  // Number of VGPRs on SI.
  if (ST->getGeneration() >= AMDGPUSubtarget::SOUTHERN_ISLANDS)
    return 256;

  return 4 * 128; // XXX - 4 channels. Should these count as vector instead?
}

unsigned AMDGPUTTIImpl::getRegisterBitWidth(bool Vector) {
  return Vector ? 0 : 32;
}

unsigned AMDGPUTTIImpl::getMaxInterleaveFactor(unsigned VF) {
  // Semi-arbitrary large amount.
  return 64;
}

unsigned AMDGPUTTIImpl::getCFInstrCost(unsigned Opcode) {
  // XXX - For some reason this isn't called for switch.
  switch (Opcode) {
  case Instruction::Br:
  case Instruction::Ret:
    return 10;
  default:
    return BaseT::getCFInstrCost(Opcode);
  }
}

int AMDGPUTTIImpl::getVectorInstrCost(unsigned Opcode, Type *ValTy,
                                      unsigned Index) {
  switch (Opcode) {
  case Instruction::ExtractElement:
    // Dynamic indexing isn't free and is best avoided.
    return Index == ~0u ? 2 : 0;
  default:
    return BaseT::getVectorInstrCost(Opcode, ValTy, Index);
  }
}

static bool isIntrinsicSourceOfDivergence(const TargetIntrinsicInfo *TII,
                                          const IntrinsicInst *I) {
  switch (I->getIntrinsicID()) {
  default:
    return false;
  case Intrinsic::not_intrinsic:
    // This means we have an intrinsic that isn't defined in
    // IntrinsicsAMDGPU.td
    break;

  case Intrinsic::amdgcn_interp_p1:
  case Intrinsic::amdgcn_interp_p2:
  case Intrinsic::amdgcn_mbcnt_hi:
  case Intrinsic::amdgcn_mbcnt_lo:
  case Intrinsic::r600_read_tidig_x:
  case Intrinsic::r600_read_tidig_y:
  case Intrinsic::r600_read_tidig_z:
    return true;
  }

  StringRef Name = I->getCalledFunction()->getName();
  switch (TII->lookupName((const char *)Name.bytes_begin(), Name.size())) {
  default:
    return false;
  case AMDGPUIntrinsic::SI_tid:
  case AMDGPUIntrinsic::SI_fs_interp:
    return true;
  }
}

static bool isArgPassedInSGPR(const Argument *A) {
  const Function *F = A->getParent();
  unsigned ShaderType = AMDGPU::getShaderType(*F);

  // Arguments to compute shaders are never a source of divergence.
  if (ShaderType == ShaderType::COMPUTE)
    return true;

  // For non-compute shaders, SGPR inputs are marked with either inreg or byval.
  if (F->getAttributes().hasAttribute(A->getArgNo() + 1, Attribute::InReg) ||
      F->getAttributes().hasAttribute(A->getArgNo() + 1, Attribute::ByVal))
    return true;

  // Everything else is in VGPRs.
  return false;
}

///
/// \returns true if the result of the value could potentially be
/// different across workitems in a wavefront.
bool AMDGPUTTIImpl::isSourceOfDivergence(const Value *V) const {

  if (const Argument *A = dyn_cast<Argument>(V))
    return !isArgPassedInSGPR(A);

  // Loads from the private address space are divergent, because threads
  // can execute the load instruction with the same inputs and get different
  // results.
  //
  // All other loads are not divergent, because if threads issue loads with the
  // same arguments, they will always get the same result.
  if (const LoadInst *Load = dyn_cast<LoadInst>(V))
    return Load->getPointerAddressSpace() == AMDGPUAS::PRIVATE_ADDRESS;

  if (const IntrinsicInst *Intrinsic = dyn_cast<IntrinsicInst>(V)) {
    const TargetMachine &TM = getTLI()->getTargetMachine();
    return isIntrinsicSourceOfDivergence(TM.getIntrinsicInfo(), Intrinsic);
  }

  // Assume all function calls are a source of divergence.
  if (isa<CallInst>(V) || isa<InvokeInst>(V))
    return true;

  return false;
}
<|endoftext|>