<commit_before>#pragma once
#include <string>

#ifndef _MSC_VER
#include <cxxabi.h>
#endif

namespace wiertlo
{
	namespace detail
	{
		void replaceAll(std::string& source, const std::string& from, const std::string& to)
		{
			std::string newString;
			newString.reserve(source.length());  // avoids a few memory allocations

			std::string::size_type lastPos = 0;
			std::string::size_type findPos;

			while(std::string::npos != (findPos = source.find(from, lastPos)))
			{
				newString.append(source, lastPos, findPos - lastPos);
				newString += to;
				lastPos = findPos + from.length();
			}

			// Care for the rest after last occurrence
			newString += source.substr(lastPos);

			source.swap(newString);
		}

		struct free_deleter
		{
			template<typename T>
			void operator()(T* ptr)
			{
				free(ptr);
			}
		};
	}

	inline std::string demangled(const std::type_info& ti)
	{
#ifndef _MSC_VER
		int status;
		std::size_t length;
		std::unique_ptr<char, detail::free_deleter> demangled(abi::__cxa_demangle(ti.name(), nullptr, &length, &status));
		if(status != 0)
			throw "FUCK";
		std::string s = demangled.get();
#else
		std::string s = ti.name();
#endif
		return s;
	}

	// for use with <wiertlo/pretty_print.hpp>
	struct RTTINamePolicy
	{
		template<typename T>
		static std::string get_name()
		{
			std::string s = demangled(typeid(T));
			// TODO: don't break on identifiers like `lolenum`
			detail::replaceAll(s, "enum ", "");
			detail::replaceAll(s, "struct ", "");
			detail::replaceAll(s, "class ", "");
			detail::replaceAll(s, "union ", "");
			return s;
		}
};
}<commit_msg>Add missing `inline`<commit_after>#pragma once
#include <string>

#ifndef _MSC_VER
#include <cxxabi.h>
#endif

namespace wiertlo
{
	namespace detail
	{
		inline void replaceAll(std::string& source, const std::string& from, const std::string& to)
		{
			std::string newString;
			newString.reserve(source.length());  // avoids a few memory allocations

			std::string::size_type lastPos = 0;
			std::string::size_type findPos;

			while(std::string::npos != (findPos = source.find(from, lastPos)))
			{
				newString.append(source, lastPos, findPos - lastPos);
				newString += to;
				lastPos = findPos + from.length();
			}

			// Care for the rest after last occurrence
			newString += source.substr(lastPos);

			source.swap(newString);
		}

		struct free_deleter
		{
			template<typename T>
			void operator()(T* ptr)
			{
				free(ptr);
			}
		};
	}

	inline std::string demangled(const std::type_info& ti)
	{
#ifndef _MSC_VER
		int status;
		std::size_t length;
		std::unique_ptr<char, detail::free_deleter> demangled(abi::__cxa_demangle(ti.name(), nullptr, &length, &status));
		if(status != 0)
			throw "FUCK";
		std::string s = demangled.get();
#else
		std::string s = ti.name();
#endif
		return s;
	}

	// for use with <wiertlo/pretty_print.hpp>
	struct RTTINamePolicy
	{
		template<typename T>
		static std::string get_name()
		{
			std::string s = demangled(typeid(T));
			// TODO: don't break on identifiers like `lolenum`
			detail::replaceAll(s, "enum ", "");
			detail::replaceAll(s, "struct ", "");
			detail::replaceAll(s, "class ", "");
			detail::replaceAll(s, "union ", "");
			return s;
		}
};
}<|endoftext|>


<commit_before>#pragma once
#include <tuple>
#include <type_traits>
#include <cmath>
#include <limits>

namespace spn {
	//! 累積カウンタの比較用
	template <class T>
	bool CompareAndSet(T& num, const T& target) {
		if(num != target) {
			num = target;
			return true;
		}
		return false;
	}
	//! コンパイル時数値計算 & 比較
	template <int M, int N>
	struct TValue {
		enum { add = M+N,
			sub = M-N,
			less = (M>N) ? N : M,
			great = (M>N) ? M : N,
			less_eq = (M<=N) ? 1 : 0,
			great_eq = (M>=N) ? 1 : 0,
			lesser = (M<N) ? 1 : 0,
			greater = (M>N) ? 1 : 0,
			equal = M==N ? 1 : 0
		};
	};
	//! bool -> std::true_type or std::false_type
	template <int V>
	using TFCond = typename std::conditional<V!=0, std::true_type, std::false_type>::type;
	//! 2つの定数の演算結果をstd::true_type か std::false_typeで返す
	template <int N, int M>
	struct NType {
		using t_and = TFCond<(N&M)>;
		using t_or = TFCond<(N|M)>;
		using t_xor = TFCond<(N^M)>;
		using t_nand = TFCond<((N&M) ^ 0x01)>;
		using less = TFCond<(N<M)>;
		using great = TFCond<(N>M)>;
		using equal = TFCond<N==M>;
		using not_equal = TFCond<N!=M>;
		using less_eq = TFCond<(N<=M)>;
		using great_eq = TFCond<(N>=M)>;
	};
	//! 2つのintegral_constant<bool>を論理演算
	template <class T0, class T1>
	struct TType {
		constexpr static int I0 = std::is_same<T0, std::true_type>::value,
							I1 = std::is_same<T1, std::true_type>::value;
		using t_and = TFCond<I0&I1>;
		using t_or = TFCond<I0|I1>;
		using t_xor = TFCond<I0^I1>;
		using t_nand = TFCond<(I0&I1) ^ 0x01>;
	};
	//! 条件式の評価結果がfalseの場合、マクロ定義した箇所には到達しないことを保証
	#define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0);
	//! 最大値を取得
	template <int... N>
	struct TMax {
		constexpr static int result = 0; };
	template <int N0, int... N>
	struct TMax<N0, N...> {
		constexpr static int result = N0; };
	template <int N0, int N1, int... N>
	struct TMax<N0, N1, N...> {
		constexpr static int result = TValue<N0, TMax<N1, N...>::result>::great; };
	//! SFINAEで関数を無効化する際に使うダミー変数
	static void* Enabler;
	//! コンパイル時定数で数値のN*10乗を計算
	template <class T, int N, typename std::enable_if<N==0>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1, std::integral_constant<int,N>* =nullptr) {
		return value;
	}
	template <class T, int N, typename std::enable_if<(N<0)>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1, std::integral_constant<int,N>* =nullptr) {
		return ConstantPow10(value/10, (std::integral_constant<int,N+1>*)nullptr);
	}
	template <class T, int N, typename std::enable_if<(N>0)>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1.f, std::integral_constant<int,N>* =nullptr) {
		return ConstantPow10(value*10, (std::integral_constant<int,N-1>*)nullptr);
	}

	//! std::tupleのハッシュを計算
	struct TupleHash {
		template <class Tup>
		static size_t get(size_t value, const Tup& /*tup*/, std::integral_constant<int,-1>) { return value; }
		template <class Tup, int N>
		static size_t get(size_t value, const Tup& tup, std::integral_constant<int,N>) {
			const auto& t = std::get<N>(tup);
			size_t h = std::hash<typename std::decay<decltype(t)>::type>()(t);
			value = (value ^ (h<<(h&0x07))) ^ (h>>3);
			return get(value, tup, std::integral_constant<int,N-1>());
		}
		template <class... Ts>
		size_t operator()(const std::tuple<Ts...>& tup) const {
			return get(0xdeadbeef * 0xdeadbeef, tup, std::integral_constant<int,sizeof...(Ts)-1>());
		}
	};

	//! クラスがwidthフィールドを持っていればintegral_constantでそれを返す
	template <class T>
	std::integral_constant<int,T::width> _GetWidthT(decltype(T::width)*);
	template <class T>
	std::integral_constant<int,0> _GetWidthT(...);
	template <class T>
	decltype(_GetWidthT<T>(nullptr)) GetWidthT();
	//! クラスがheightフィールドを持っていればintegral_constantでそれを返す
	template <class T>
	std::integral_constant<int,T::height> _GetHeightT(decltype(T::height)*);
	template <class T>
	std::integral_constant<int,0> _GetHeightT(...);
	template <class T>
	decltype(_GetHeightT<T>(nullptr)) GetHeightT();
	//! クラスがwidthとheightフィールドを持っていればintegral_pairでそれを返す
	template <class T, T val0, T val1>
	using integral_pair = std::pair<std::integral_constant<T, val0>,
									std::integral_constant<T, val1>>;
	template <class T>
	integral_pair<int,T::height, T::width> _GetWidthHeightT(decltype(T::width)*, decltype(T::height)*);
	template <class T>
	integral_pair<int,0, T::width> _GetWidthHeightT(decltype(T::width)*, ...);
	template <class T>
	integral_pair<int,0,0> _GetWidthHeightT(...);
	template <class T>
	decltype(_GetWidthHeightT<T>(nullptr,nullptr)) GetWidthHeightT();

	// 値比較(widthメンバ有り)
	template <class T, class CMP, int N>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,0,N>) {
		for(int i=0 ; i<N ; i++) {
			if(!cmp(v0.m[i], v1.m[i]))
				return false;
		}
		return true;
	}
	// 値比較(width & heightメンバ有り)
	template <class T, class CMP, int M, int N>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,M,N>) {
		for(int i=0 ; i<M ; i++) {
			for(int j=0 ; j<N ; j++) {
				if(!cmp(v0.ma[i][j], v1.ma[i][j]))
					return false;
			}
		}
		return true;
	}
	// 値比較(単一値)
	template <class T, class CMP>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,0,0>) {
		return cmp(v0, v1);
	}

	//! 絶対値の誤差による等値判定
	/*! \param[in] val value to check
		\param[in] vExcept target value
		\param[in] vEps value threshold */
	template <class T, class T2>
	bool EqAbs(const T& val, const T& vExcept, T2 vEps = std::numeric_limits<T>::epsilon()) {
		auto fnCmp = [vEps](const auto& val, const auto& except){ return std::fabs(except-val) <= vEps; };
		return _EqFunc(val, vExcept, fnCmp, decltype(GetWidthHeightT<T>())());
	}
	template <class T, class... Ts>
	bool EqAbsT(const std::tuple<Ts...>& /*tup0*/, const std::tuple<Ts...>& /*tup1*/, const T& /*epsilon*/, std::integral_constant<int,-1>*) {
		return true;
	}
	//! std::tuple全部の要素に対してEqAbsを呼ぶ
	template <class T, int N, class... Ts, typename std::enable_if<(N>=0)>::type*& = Enabler>
	bool EqAbsT(const std::tuple<Ts...>& tup0, const std::tuple<Ts...>& tup1, const T& epsilon, std::integral_constant<int,N>*) {
		return EqAbs(std::get<N>(tup0), std::get<N>(tup1), epsilon)
				&& EqAbsT(tup0, tup1, epsilon, (std::integral_constant<int,N-1>*)nullptr);
	}
	template <class... Ts, class T>
	bool EqAbs(const std::tuple<Ts...>& tup0, const std::tuple<Ts...>& tup1, const T& epsilon) {
		return EqAbsT<T>(tup0, tup1, epsilon, (std::integral_constant<int,sizeof...(Ts)-1>*)nullptr);
	}

	//! 浮動少数点数の値がNaNになっているか
	template <class T, class = typename std::enable_if<std::is_floating_point<T>::value>::type>
	bool IsNaN(const T& val) {
		return !(val>=T(0)) && !(val<T(0)); }
	//! 浮動少数点数の値がNaN又は無限大になっているか
	template <class T, class = typename std::enable_if<std::is_floating_point<T>::value>::type>
	bool IsOutstanding(const T& val) {
		auto valA = std::fabs(val);
		return valA==std::numeric_limits<float>::infinity() || IsNaN(valA); }

	//! 値飽和
	template <class T>
	T Saturate(const T& val, const T& minV, const T& maxV) {
		if(val > maxV)
			return maxV;
		if(val < minV)
			return minV;
		return val;
	}
	template <class T>
	T Saturate(const T& val, const T& range) {
		return Saturate(val, -range, range);
	}
	//! 値の範囲判定
	template <class T>
	bool IsInRange(const T& val, const T& vMin, const T& vMax) {
		return val>=vMin && val<=vMax;
	}
	template <class T>
	bool IsInRange(const T& val, const T& vMin, const T& vMax, const T& vEps) {
		return IsInRange(val, vMin-vEps, vMax+vEps);
	}

	//! std::tupleの要素ごとの距離(EqAbs)比較
	template <class T, int NPow>
	struct TupleNear {
		template <class P>
		bool operator()(const P& t0, const P& t1) const {
			return EqAbs(t0, t1, spn::ConstantPow10<T,NPow>());
		}
	};

	template <size_t N>
	struct GetCountOf_helper {
		using type = char [N];
	};
	template <class T, size_t N>
	typename GetCountOf_helper<N>::type& GetCountOf(T (&)[N]);
	//! 配列の要素数を取得する (配列でない場合はエラー)
	#define countof(e)		sizeof(::spn::GetCountOf(e))

	template <class T>
	char GetCountOfNA(T);
	template <class T, size_t N>
	typename GetCountOf_helper<N>::type& GetCountOfNA(T (&)[N]);
	//! 配列の要素数を取得する (配列でない場合は1が返る)
	#define countof_na(e)	sizeof(::spn::GetCountOfNA(e))
}

<commit_msg>IsCallableを追加 指定の型と引数で呼び出し可能かを調べる<commit_after>#pragma once
#include <tuple>
#include <type_traits>
#include <cmath>
#include <limits>

namespace spn {
	//! 累積カウンタの比較用
	template <class T>
	bool CompareAndSet(T& num, const T& target) {
		if(num != target) {
			num = target;
			return true;
		}
		return false;
	}
	//! コンパイル時数値計算 & 比較
	template <int M, int N>
	struct TValue {
		enum { add = M+N,
			sub = M-N,
			less = (M>N) ? N : M,
			great = (M>N) ? M : N,
			less_eq = (M<=N) ? 1 : 0,
			great_eq = (M>=N) ? 1 : 0,
			lesser = (M<N) ? 1 : 0,
			greater = (M>N) ? 1 : 0,
			equal = M==N ? 1 : 0
		};
	};
	//! bool -> std::true_type or std::false_type
	template <int V>
	using TFCond = typename std::conditional<V!=0, std::true_type, std::false_type>::type;
	//! 2つの定数の演算結果をstd::true_type か std::false_typeで返す
	template <int N, int M>
	struct NType {
		using t_and = TFCond<(N&M)>;
		using t_or = TFCond<(N|M)>;
		using t_xor = TFCond<(N^M)>;
		using t_nand = TFCond<((N&M) ^ 0x01)>;
		using less = TFCond<(N<M)>;
		using great = TFCond<(N>M)>;
		using equal = TFCond<N==M>;
		using not_equal = TFCond<N!=M>;
		using less_eq = TFCond<(N<=M)>;
		using great_eq = TFCond<(N>=M)>;
	};
	//! 2つのintegral_constant<bool>を論理演算
	template <class T0, class T1>
	struct TType {
		constexpr static int I0 = std::is_same<T0, std::true_type>::value,
							I1 = std::is_same<T1, std::true_type>::value;
		using t_and = TFCond<I0&I1>;
		using t_or = TFCond<I0|I1>;
		using t_xor = TFCond<I0^I1>;
		using t_nand = TFCond<(I0&I1) ^ 0x01>;
	};
	//! 条件式の評価結果がfalseの場合、マクロ定義した箇所には到達しないことを保証
	#define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0);
	//! 最大値を取得
	template <int... N>
	struct TMax {
		constexpr static int result = 0; };
	template <int N0, int... N>
	struct TMax<N0, N...> {
		constexpr static int result = N0; };
	template <int N0, int N1, int... N>
	struct TMax<N0, N1, N...> {
		constexpr static int result = TValue<N0, TMax<N1, N...>::result>::great; };
	//! SFINAEで関数を無効化する際に使うダミー変数
	static void* Enabler;
	//! コンパイル時定数で数値のN*10乗を計算
	template <class T, int N, typename std::enable_if<N==0>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1, std::integral_constant<int,N>* =nullptr) {
		return value;
	}
	template <class T, int N, typename std::enable_if<(N<0)>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1, std::integral_constant<int,N>* =nullptr) {
		return ConstantPow10(value/10, (std::integral_constant<int,N+1>*)nullptr);
	}
	template <class T, int N, typename std::enable_if<(N>0)>::type*& = Enabler>
	constexpr T ConstantPow10(T value=1.f, std::integral_constant<int,N>* =nullptr) {
		return ConstantPow10(value*10, (std::integral_constant<int,N-1>*)nullptr);
	}

	//! std::tupleのハッシュを計算
	struct TupleHash {
		template <class Tup>
		static size_t get(size_t value, const Tup& /*tup*/, std::integral_constant<int,-1>) { return value; }
		template <class Tup, int N>
		static size_t get(size_t value, const Tup& tup, std::integral_constant<int,N>) {
			const auto& t = std::get<N>(tup);
			size_t h = std::hash<typename std::decay<decltype(t)>::type>()(t);
			value = (value ^ (h<<(h&0x07))) ^ (h>>3);
			return get(value, tup, std::integral_constant<int,N-1>());
		}
		template <class... Ts>
		size_t operator()(const std::tuple<Ts...>& tup) const {
			return get(0xdeadbeef * 0xdeadbeef, tup, std::integral_constant<int,sizeof...(Ts)-1>());
		}
	};

	//! クラスがwidthフィールドを持っていればintegral_constantでそれを返す
	template <class T>
	std::integral_constant<int,T::width> _GetWidthT(decltype(T::width)*);
	template <class T>
	std::integral_constant<int,0> _GetWidthT(...);
	template <class T>
	decltype(_GetWidthT<T>(nullptr)) GetWidthT();
	//! クラスがheightフィールドを持っていればintegral_constantでそれを返す
	template <class T>
	std::integral_constant<int,T::height> _GetHeightT(decltype(T::height)*);
	template <class T>
	std::integral_constant<int,0> _GetHeightT(...);
	template <class T>
	decltype(_GetHeightT<T>(nullptr)) GetHeightT();
	//! クラスがwidthとheightフィールドを持っていればintegral_pairでそれを返す
	template <class T, T val0, T val1>
	using integral_pair = std::pair<std::integral_constant<T, val0>,
									std::integral_constant<T, val1>>;
	template <class T>
	integral_pair<int,T::height, T::width> _GetWidthHeightT(decltype(T::width)*, decltype(T::height)*);
	template <class T>
	integral_pair<int,0, T::width> _GetWidthHeightT(decltype(T::width)*, ...);
	template <class T>
	integral_pair<int,0,0> _GetWidthHeightT(...);
	template <class T>
	decltype(_GetWidthHeightT<T>(nullptr,nullptr)) GetWidthHeightT();

	// 値比較(widthメンバ有り)
	template <class T, class CMP, int N>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,0,N>) {
		for(int i=0 ; i<N ; i++) {
			if(!cmp(v0.m[i], v1.m[i]))
				return false;
		}
		return true;
	}
	// 値比較(width & heightメンバ有り)
	template <class T, class CMP, int M, int N>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,M,N>) {
		for(int i=0 ; i<M ; i++) {
			for(int j=0 ; j<N ; j++) {
				if(!cmp(v0.ma[i][j], v1.ma[i][j]))
					return false;
			}
		}
		return true;
	}
	// 値比較(単一値)
	template <class T, class CMP>
	bool _EqFunc(const T& v0, const T& v1, CMP&& cmp, integral_pair<int,0,0>) {
		return cmp(v0, v1);
	}

	//! 絶対値の誤差による等値判定
	/*! \param[in] val value to check
		\param[in] vExcept target value
		\param[in] vEps value threshold */
	template <class T, class T2>
	bool EqAbs(const T& val, const T& vExcept, T2 vEps = std::numeric_limits<T>::epsilon()) {
		auto fnCmp = [vEps](const auto& val, const auto& except){ return std::fabs(except-val) <= vEps; };
		return _EqFunc(val, vExcept, fnCmp, decltype(GetWidthHeightT<T>())());
	}
	template <class T, class... Ts>
	bool EqAbsT(const std::tuple<Ts...>& /*tup0*/, const std::tuple<Ts...>& /*tup1*/, const T& /*epsilon*/, std::integral_constant<int,-1>*) {
		return true;
	}
	//! std::tuple全部の要素に対してEqAbsを呼ぶ
	template <class T, int N, class... Ts, typename std::enable_if<(N>=0)>::type*& = Enabler>
	bool EqAbsT(const std::tuple<Ts...>& tup0, const std::tuple<Ts...>& tup1, const T& epsilon, std::integral_constant<int,N>*) {
		return EqAbs(std::get<N>(tup0), std::get<N>(tup1), epsilon)
				&& EqAbsT(tup0, tup1, epsilon, (std::integral_constant<int,N-1>*)nullptr);
	}
	template <class... Ts, class T>
	bool EqAbs(const std::tuple<Ts...>& tup0, const std::tuple<Ts...>& tup1, const T& epsilon) {
		return EqAbsT<T>(tup0, tup1, epsilon, (std::integral_constant<int,sizeof...(Ts)-1>*)nullptr);
	}

	//! 浮動少数点数の値がNaNになっているか
	template <class T, class = typename std::enable_if<std::is_floating_point<T>::value>::type>
	bool IsNaN(const T& val) {
		return !(val>=T(0)) && !(val<T(0)); }
	//! 浮動少数点数の値がNaN又は無限大になっているか
	template <class T, class = typename std::enable_if<std::is_floating_point<T>::value>::type>
	bool IsOutstanding(const T& val) {
		auto valA = std::fabs(val);
		return valA==std::numeric_limits<float>::infinity() || IsNaN(valA); }

	//! 値飽和
	template <class T>
	T Saturate(const T& val, const T& minV, const T& maxV) {
		if(val > maxV)
			return maxV;
		if(val < minV)
			return minV;
		return val;
	}
	template <class T>
	T Saturate(const T& val, const T& range) {
		return Saturate(val, -range, range);
	}
	//! 値の範囲判定
	template <class T>
	bool IsInRange(const T& val, const T& vMin, const T& vMax) {
		return val>=vMin && val<=vMax;
	}
	template <class T>
	bool IsInRange(const T& val, const T& vMin, const T& vMax, const T& vEps) {
		return IsInRange(val, vMin-vEps, vMax+vEps);
	}

	//! std::tupleの要素ごとの距離(EqAbs)比較
	template <class T, int NPow>
	struct TupleNear {
		template <class P>
		bool operator()(const P& t0, const P& t1) const {
			return EqAbs(t0, t1, spn::ConstantPow10<T,NPow>());
		}
	};

	template <size_t N>
	struct GetCountOf_helper {
		using type = char [N];
	};
	template <class T, size_t N>
	typename GetCountOf_helper<N>::type& GetCountOf(T (&)[N]);
	//! 配列の要素数を取得する (配列でない場合はエラー)
	#define countof(e)		sizeof(::spn::GetCountOf(e))

	template <class T>
	char GetCountOfNA(T);
	template <class T, size_t N>
	typename GetCountOf_helper<N>::type& GetCountOfNA(T (&)[N]);
	//! 配列の要素数を取得する (配列でない場合は1が返る)
	#define countof_na(e)	sizeof(::spn::GetCountOfNA(e))

	template <class T, class... Args>
	class IsCallable {
		private:
			template <class F>
			static std::true_type _check(decltype(std::declval<F>()(std::declval<Args>()...), (void)0)*);
			template <class F>
			static std::false_type _check(...);
		public:
			using type = decltype(_check<T>(nullptr));
			constexpr static bool value = type::value;
	};
}
<|endoftext|>


<commit_before>/**@file Logical Channel.  */

/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "GSML3RRElements.h"
#include "GSML3Message.h"
#include "GSML3RRMessages.h"
#include "GSMLogicalChannel.h"
#include "GSMConfig.h"

#include <TransactionTable.h>
#include <SMSControl.h>
#include <ControlCommon.h>

#include <Logger.h>
#undef WARNING

using namespace std;
using namespace GSM;

void LogicalChannel::open()
{
	LOG(INFO);
	if (mSACCH) mSACCH->open();
	if (mL1) mL1->open();
	for (int s=0; s<4; s++) {
		if (mL2[s]) mL2[s]->open();
	}
	// Empty any stray transactions in the FIFO from the SIP layer.
	while (true) {
		Control::TransactionEntry *trans = mTransactionFIFO.readNoBlock();
		if (!trans) break;
		LOG(WARNING) << "flushing stray transaction " << *trans;
		// FIXME -- Shouldn't we be deleting these?
	}
}

void LogicalChannel::connect()
{
	mMux.downstream(mL1);
	if (mL1) mL1->upstream(&mMux);
	for (int s=0; s<4; s++) {
		mMux.upstream(mL2[s],s);
		if (mL2[s]) mL2[s]->downstream(&mMux);
	}
}

void LogicalChannel::downstream(ARFCNManager* radio)
{
	assert(mL1);
	mL1->downstream(radio);
	if (mSACCH) mSACCH->downstream(radio);
}

// Serialize and send an L3Message with a given primitive.
void LogicalChannel::send(const L3Message& msg,
		const GSM::Primitive& prim,
		unsigned SAPI)
{
	LOG(INFO) << "L3 SAP" << SAPI << " sending " << msg;
	send(L3Frame(msg,prim), SAPI);
}

CCCHLogicalChannel::CCCHLogicalChannel(const TDMAMapping& wMapping)
	:mRunning(false)
{
	mL1 = new CCCHL1FEC(wMapping);
	mL2[0] = new CCCHL2;
	connect();
}

void CCCHLogicalChannel::open()
{
	LogicalChannel::open();
	if (!mRunning) {
		mRunning=true;
		mServiceThread.start((void*(*)(void*))CCCHLogicalChannelServiceLoopAdapter,this);
	}
}

void CCCHLogicalChannel::serviceLoop()
{
	// build the idle frame
	static const L3PagingRequestType1 filler;
	static const L3Frame idleFrame(filler,UNIT_DATA);
	// prime the first idle frame
	LogicalChannel::send(idleFrame);
	// run the loop
	while (true) {
		L3Frame* frame = mQ.read();
		if (frame) {
			LogicalChannel::send(*frame);
			OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending " << *frame;
			delete frame;
		}
		if (mQ.size()==0) {
			LogicalChannel::send(idleFrame);
			OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending idle frame";
		}
	}
}

void *GSM::CCCHLogicalChannelServiceLoopAdapter(CCCHLogicalChannel* chan)
{
	chan->serviceLoop();
	return NULL;
}

L3ChannelDescription LogicalChannel::channelDescription() const
{
	// In some debug cases, L1 may not exist, so we fake this information.
	if (mL1==NULL) return L3ChannelDescription(TDMA_MISC,0,0,0);

	// In normal cases, we get this information from L1.
	return L3ChannelDescription(
		mL1->typeAndOffset(),
		mL1->TN(),
		mL1->TSC(),
		mL1->ARFCN()
	);
}

SDCCHLogicalChannel::SDCCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const CompleteMapping& wMapping)
{
	mL1 = new SDCCHL1FEC(wCN,wTN,wMapping.LCH());
	// SAP0 is RR/MM/CC, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	L2LAPDm *SAP0L2 = new SDCCHL2(1,0);
	L2LAPDm *SAP3L2 = new SDCCHL2(1,3);
	LOG(DEBUG) << "LAPDm pairs SAP0=" << SAP0L2 << " SAP3=" << SAP3L2;
	SAP3L2->master(SAP0L2);
	mL2[0] = SAP0L2;
	mL2[3] = SAP3L2;
	mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
	connect();
}

SACCHLogicalChannel::SACCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const MappingPair& wMapping)
		: mRunning(false)
{
	mSACCHL1 = new SACCHL1FEC(wCN,wTN,wMapping);
	mL1 = mSACCHL1;
	// SAP0 is RR, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	mL2[0] = new SACCHL2(1,0);
	mL2[3] = new SACCHL2(1,3);
	connect();
	assert(mSACCH==NULL);
}

void SACCHLogicalChannel::open()
{
	LogicalChannel::open();
	if (!mRunning) {
		mRunning=true;
		mServiceThread.start((void*(*)(void*))SACCHLogicalChannelServiceLoopAdapter,this);
	}
}

L3Message* processSACCHMessage(L3Frame *l3frame)
{
	if (!l3frame) return NULL;
	LOG(DEBUG) << *l3frame;
	Primitive prim = l3frame->primitive();
	if ((prim!=DATA) && (prim!=UNIT_DATA)) {
		LOG(INFO) << "non-data primitive " << prim;
		return NULL;
	}
	// FIXME -- Why, again, do we need to do this?
//	L3Frame realFrame = l3frame->segment(24, l3frame->size()-24);
	L3Message* message = parseL3(*l3frame);
	if (!message) {
		LOG(WARNING) << "SACCH recevied unparsable L3 frame " << *l3frame;
	}
	return message;
}

void SACCHLogicalChannel::serviceLoop()
{
	// run the loop
	unsigned count = 0;
	while (true) {

		// Throttle back if not active.
		if (!active()) {
			OBJLOG(DEBUG) << "SACCH sleeping";
			sleepFrames(51);
			continue;
		}

		// TODO SMS -- Check to see if the tx queues are empty.  If so, send SI5/6,
		// otherwise sleep and continue;

		// Send alternating SI5/SI6.
		OBJLOG(DEBUG) << "sending SI5/6 on SACCH";
		if (count%2) LogicalChannel::send(gBTS.SI5Frame());
		else LogicalChannel::send(gBTS.SI6Frame());
		count++;

		// Receive inbound messages.
		// This read loop flushes stray reports quickly.
		while (true) {

			OBJLOG(DEBUG) << "polling SACCH for inbound messages";
			bool nothing = true;

			// Process SAP0 -- RR Measurement reports
			L3Frame *rrFrame = LogicalChannel::recv(0,0);
			if (rrFrame) nothing=false;
			L3Message* rrMessage = processSACCHMessage(rrFrame);
			delete rrFrame;
			if (rrMessage) {
				L3MeasurementReport* measurement = dynamic_cast<L3MeasurementReport*>(rrMessage);
				if (measurement) {
					mMeasurementResults = measurement->results();
					OBJLOG(DEBUG) << "SACCH measurement report " << mMeasurementResults;
					// Add the measurement results to the table
					// Note that the typeAndOffset of a SACCH match the host channel.
					gPhysStatus.setPhysical(this, mMeasurementResults);
				} else {
					OBJLOG(NOTICE) << "SACCH SAP0 sent unaticipated message " << rrMessage;
				}
				delete rrMessage;
			}

			// Process SAP3 -- SMS
			L3Frame *smsFrame = LogicalChannel::recv(0,3);
			if (smsFrame) nothing=false;
			L3Message* smsMessage = processSACCHMessage(smsFrame);
			delete smsFrame;
			if (smsMessage) {
				const SMS::CPData* cpData = dynamic_cast<const SMS::CPData*>(smsMessage);
				if (cpData) {
					OBJLOG(INFO) << "SMS CPDU " << *cpData;
					Control::TransactionEntry *transaction = gTransactionTable.find(this);
					try {
						if (transaction) {
							Control::InCallMOSMSController(cpData,transaction,this);
						} else {
							OBJLOG(WARNING) << "in-call MOSMS CP-DATA with no corresponding transaction";
						}
					} catch (Control::ControlLayerException e) {
						//LogicalChannel::send(RELEASE,3);
						gTransactionTable.remove(e.transactionID());
					}
				} else {
					OBJLOG(NOTICE) << "SACCH SAP3 sent unaticipated message " << rrMessage;
				}
				delete smsMessage;
			}

			// Anything from the SIP side?
			// MTSMS (delivery from SIP to the MS)
			Control::TransactionEntry *sipTransaction = mTransactionFIFO.readNoBlock();
			if (sipTransaction) {
				OBJLOG(INFO) << "SIP-side transaction: " << sipTransaction;
				assert(sipTransaction->service() == L3CMServiceType::MobileTerminatedShortMessage);
				try {
					Control::MTSMSController(sipTransaction,this);
				} catch (Control::ControlLayerException e) {
					//LogicalChannel::send(RELEASE,3);
					gTransactionTable.remove(e.transactionID());
				}
			}

			// Nothing happened?
			if (nothing) break;
		}

	}
}

void *GSM::SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel* chan)
{
	chan->serviceLoop();
	return NULL;
}

// These have to go into the .cpp file to prevent an illegal forward reference.
void LogicalChannel::setPhy(float wRSSI, float wTimingError)
	{ assert(mSACCH); mSACCH->setPhy(wRSSI,wTimingError); }
void LogicalChannel::setPhy(const LogicalChannel& other)
	{ assert(mSACCH); mSACCH->setPhy(*other.SACCH()); }
float LogicalChannel::RSSI() const
	{ assert(mSACCH); return mSACCH->RSSI(); }
float LogicalChannel::timingError() const
	{ assert(mSACCH); return mSACCH->timingError(); }
int LogicalChannel::actualMSPower() const
	{ assert(mSACCH); return mSACCH->actualMSPower(); }
int LogicalChannel::actualMSTiming() const
	{ assert(mSACCH); return mSACCH->actualMSTiming(); }

TCHFACCHLogicalChannel::TCHFACCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const CompleteMapping& wMapping)
{
	mTCHL1 = new TCHFACCHL1FEC(wCN,wTN,wMapping.LCH());
	mL1 = mTCHL1;
	// SAP0 is RR/MM/CC, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	mL2[0] = new FACCHL2(1,0);
	mL2[3] = new FACCHL2(1,3);
	mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
	connect();
}

bool LogicalChannel::waitForPrimitive(Primitive primitive, unsigned timeout_ms)
{
	bool waiting = true;
	while (waiting) {
		L3Frame *req = recv(timeout_ms);
		if (req==NULL) {
			LOG(NOTICE) << "timeout at uptime " << gBTS.uptime() << " frame " << gBTS.time();
			return false;
		}
		waiting = (req->primitive()!=primitive);
		delete req;
	}
	return true;
}

void LogicalChannel::waitForPrimitive(Primitive primitive)
{
	bool waiting = true;
	while (waiting) {
		L3Frame *req = recv();
		if (req==NULL) continue;
		waiting = (req->primitive()!=primitive);
		delete req;
	}
}

ostream& GSM::operator<<(ostream& os, const LogicalChannel& chan)
{
	os << chan.descriptiveString();
	return os;
}

void LogicalChannel::addTransaction(Control::TransactionEntry *transaction)
{
	assert(transaction->channel()==this);
	mTransactionFIFO.write(transaction);
}

// vim: ts=4 sw=4

<commit_msg>Fixed CCCH serviceLoop().<commit_after>/**@file Logical Channel.  */

/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2010 Kestrel Signal Processing, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published by
	the Free Software Foundation, either version 3 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 Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "GSML3RRElements.h"
#include "GSML3Message.h"
#include "GSML3RRMessages.h"
#include "GSMLogicalChannel.h"
#include "GSMConfig.h"

#include <TransactionTable.h>
#include <SMSControl.h>
#include <ControlCommon.h>

#include <Logger.h>
#undef WARNING

using namespace std;
using namespace GSM;

void LogicalChannel::open()
{
	LOG(INFO);
	if (mSACCH) mSACCH->open();
	if (mL1) mL1->open();
	for (int s=0; s<4; s++) {
		if (mL2[s]) mL2[s]->open();
	}
	// Empty any stray transactions in the FIFO from the SIP layer.
	while (true) {
		Control::TransactionEntry *trans = mTransactionFIFO.readNoBlock();
		if (!trans) break;
		LOG(WARNING) << "flushing stray transaction " << *trans;
		// FIXME -- Shouldn't we be deleting these?
	}
}

void LogicalChannel::connect()
{
	mMux.downstream(mL1);
	if (mL1) mL1->upstream(&mMux);
	for (int s=0; s<4; s++) {
		mMux.upstream(mL2[s],s);
		if (mL2[s]) mL2[s]->downstream(&mMux);
	}
}

void LogicalChannel::downstream(ARFCNManager* radio)
{
	assert(mL1);
	mL1->downstream(radio);
	if (mSACCH) mSACCH->downstream(radio);
}

// Serialize and send an L3Message with a given primitive.
void LogicalChannel::send(const L3Message& msg,
		const GSM::Primitive& prim,
		unsigned SAPI)
{
	LOG(INFO) << "L3 SAP" << SAPI << " sending " << msg;
	send(L3Frame(msg,prim), SAPI);
}

CCCHLogicalChannel::CCCHLogicalChannel(const TDMAMapping& wMapping)
	:mRunning(false)
{
	mL1 = new CCCHL1FEC(wMapping);
	mL2[0] = new CCCHL2;
	connect();
}

void CCCHLogicalChannel::open()
{
	LogicalChannel::open();
	if (!mRunning) {
		mRunning=true;
		mServiceThread.start((void*(*)(void*))CCCHLogicalChannelServiceLoopAdapter,this);
	}
}

void CCCHLogicalChannel::serviceLoop()
{
	// build the idle frame
	static const L3PagingRequestType1 filler;
	static const L3Frame idleFrame(filler,UNIT_DATA);
	// prime the first idle frame
	LogicalChannel::send(idleFrame);
	// run the loop
	while (true) {
		L3Frame* frame = mQ.readNoBlock();
		if (frame) {
			LogicalChannel::send(*frame);
			OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending " << *frame;
			delete frame;
		}
		else {
			LogicalChannel::send(idleFrame);
			OBJLOG(DEBUG) << "CCCHLogicalChannel::serviceLoop sending idle frame";
		}
	}
}

void *GSM::CCCHLogicalChannelServiceLoopAdapter(CCCHLogicalChannel* chan)
{
	chan->serviceLoop();
	return NULL;
}

L3ChannelDescription LogicalChannel::channelDescription() const
{
	// In some debug cases, L1 may not exist, so we fake this information.
	if (mL1==NULL) return L3ChannelDescription(TDMA_MISC,0,0,0);

	// In normal cases, we get this information from L1.
	return L3ChannelDescription(
		mL1->typeAndOffset(),
		mL1->TN(),
		mL1->TSC(),
		mL1->ARFCN()
	);
}

SDCCHLogicalChannel::SDCCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const CompleteMapping& wMapping)
{
	mL1 = new SDCCHL1FEC(wCN,wTN,wMapping.LCH());
	// SAP0 is RR/MM/CC, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	L2LAPDm *SAP0L2 = new SDCCHL2(1,0);
	L2LAPDm *SAP3L2 = new SDCCHL2(1,3);
	LOG(DEBUG) << "LAPDm pairs SAP0=" << SAP0L2 << " SAP3=" << SAP3L2;
	SAP3L2->master(SAP0L2);
	mL2[0] = SAP0L2;
	mL2[3] = SAP3L2;
	mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
	connect();
}

SACCHLogicalChannel::SACCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const MappingPair& wMapping)
		: mRunning(false)
{
	mSACCHL1 = new SACCHL1FEC(wCN,wTN,wMapping);
	mL1 = mSACCHL1;
	// SAP0 is RR, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	mL2[0] = new SACCHL2(1,0);
	mL2[3] = new SACCHL2(1,3);
	connect();
	assert(mSACCH==NULL);
}

void SACCHLogicalChannel::open()
{
	LogicalChannel::open();
	if (!mRunning) {
		mRunning=true;
		mServiceThread.start((void*(*)(void*))SACCHLogicalChannelServiceLoopAdapter,this);
	}
}

L3Message* processSACCHMessage(L3Frame *l3frame)
{
	if (!l3frame) return NULL;
	LOG(DEBUG) << *l3frame;
	Primitive prim = l3frame->primitive();
	if ((prim!=DATA) && (prim!=UNIT_DATA)) {
		LOG(INFO) << "non-data primitive " << prim;
		return NULL;
	}
	// FIXME -- Why, again, do we need to do this?
//	L3Frame realFrame = l3frame->segment(24, l3frame->size()-24);
	L3Message* message = parseL3(*l3frame);
	if (!message) {
		LOG(WARNING) << "SACCH recevied unparsable L3 frame " << *l3frame;
	}
	return message;
}

void SACCHLogicalChannel::serviceLoop()
{
	// run the loop
	unsigned count = 0;
	while (true) {

		// Throttle back if not active.
		if (!active()) {
			OBJLOG(DEBUG) << "SACCH sleeping";
			sleepFrames(51);
			continue;
		}

		// TODO SMS -- Check to see if the tx queues are empty.  If so, send SI5/6,
		// otherwise sleep and continue;

		// Send alternating SI5/SI6.
		OBJLOG(DEBUG) << "sending SI5/6 on SACCH";
		if (count%2) LogicalChannel::send(gBTS.SI5Frame());
		else LogicalChannel::send(gBTS.SI6Frame());
		count++;

		// Receive inbound messages.
		// This read loop flushes stray reports quickly.
		while (true) {

			OBJLOG(DEBUG) << "polling SACCH for inbound messages";
			bool nothing = true;

			// Process SAP0 -- RR Measurement reports
			L3Frame *rrFrame = LogicalChannel::recv(0,0);
			if (rrFrame) nothing=false;
			L3Message* rrMessage = processSACCHMessage(rrFrame);
			delete rrFrame;
			if (rrMessage) {
				L3MeasurementReport* measurement = dynamic_cast<L3MeasurementReport*>(rrMessage);
				if (measurement) {
					mMeasurementResults = measurement->results();
					OBJLOG(DEBUG) << "SACCH measurement report " << mMeasurementResults;
					// Add the measurement results to the table
					// Note that the typeAndOffset of a SACCH match the host channel.
					gPhysStatus.setPhysical(this, mMeasurementResults);
				} else {
					OBJLOG(NOTICE) << "SACCH SAP0 sent unaticipated message " << rrMessage;
				}
				delete rrMessage;
			}

			// Process SAP3 -- SMS
			L3Frame *smsFrame = LogicalChannel::recv(0,3);
			if (smsFrame) nothing=false;
			L3Message* smsMessage = processSACCHMessage(smsFrame);
			delete smsFrame;
			if (smsMessage) {
				const SMS::CPData* cpData = dynamic_cast<const SMS::CPData*>(smsMessage);
				if (cpData) {
					OBJLOG(INFO) << "SMS CPDU " << *cpData;
					Control::TransactionEntry *transaction = gTransactionTable.find(this);
					try {
						if (transaction) {
							Control::InCallMOSMSController(cpData,transaction,this);
						} else {
							OBJLOG(WARNING) << "in-call MOSMS CP-DATA with no corresponding transaction";
						}
					} catch (Control::ControlLayerException e) {
						//LogicalChannel::send(RELEASE,3);
						gTransactionTable.remove(e.transactionID());
					}
				} else {
					OBJLOG(NOTICE) << "SACCH SAP3 sent unaticipated message " << rrMessage;
				}
				delete smsMessage;
			}

			// Anything from the SIP side?
			// MTSMS (delivery from SIP to the MS)
			Control::TransactionEntry *sipTransaction = mTransactionFIFO.readNoBlock();
			if (sipTransaction) {
				OBJLOG(INFO) << "SIP-side transaction: " << sipTransaction;
				assert(sipTransaction->service() == L3CMServiceType::MobileTerminatedShortMessage);
				try {
					Control::MTSMSController(sipTransaction,this);
				} catch (Control::ControlLayerException e) {
					//LogicalChannel::send(RELEASE,3);
					gTransactionTable.remove(e.transactionID());
				}
			}

			// Nothing happened?
			if (nothing) break;
		}

	}
}

void *GSM::SACCHLogicalChannelServiceLoopAdapter(SACCHLogicalChannel* chan)
{
	chan->serviceLoop();
	return NULL;
}

// These have to go into the .cpp file to prevent an illegal forward reference.
void LogicalChannel::setPhy(float wRSSI, float wTimingError)
	{ assert(mSACCH); mSACCH->setPhy(wRSSI,wTimingError); }
void LogicalChannel::setPhy(const LogicalChannel& other)
	{ assert(mSACCH); mSACCH->setPhy(*other.SACCH()); }
float LogicalChannel::RSSI() const
	{ assert(mSACCH); return mSACCH->RSSI(); }
float LogicalChannel::timingError() const
	{ assert(mSACCH); return mSACCH->timingError(); }
int LogicalChannel::actualMSPower() const
	{ assert(mSACCH); return mSACCH->actualMSPower(); }
int LogicalChannel::actualMSTiming() const
	{ assert(mSACCH); return mSACCH->actualMSTiming(); }

TCHFACCHLogicalChannel::TCHFACCHLogicalChannel(
		unsigned wCN,
		unsigned wTN,
		const CompleteMapping& wMapping)
{
	mTCHL1 = new TCHFACCHL1FEC(wCN,wTN,wMapping.LCH());
	mL1 = mTCHL1;
	// SAP0 is RR/MM/CC, SAP3 is SMS
	// SAP1 and SAP2 are not used.
	mL2[0] = new FACCHL2(1,0);
	mL2[3] = new FACCHL2(1,3);
	mSACCH = new SACCHLogicalChannel(wCN,wTN,wMapping.SACCH());
	connect();
}

bool LogicalChannel::waitForPrimitive(Primitive primitive, unsigned timeout_ms)
{
	bool waiting = true;
	while (waiting) {
		L3Frame *req = recv(timeout_ms);
		if (req==NULL) {
			LOG(NOTICE) << "timeout at uptime " << gBTS.uptime() << " frame " << gBTS.time();
			return false;
		}
		waiting = (req->primitive()!=primitive);
		delete req;
	}
	return true;
}

void LogicalChannel::waitForPrimitive(Primitive primitive)
{
	bool waiting = true;
	while (waiting) {
		L3Frame *req = recv();
		if (req==NULL) continue;
		waiting = (req->primitive()!=primitive);
		delete req;
	}
}

ostream& GSM::operator<<(ostream& os, const LogicalChannel& chan)
{
	os << chan.descriptiveString();
	return os;
}

void LogicalChannel::addTransaction(Control::TransactionEntry *transaction)
{
	assert(transaction->channel()==this);
	mTransactionFIFO.write(transaction);
}

// vim: ts=4 sw=4

<|endoftext|>


<commit_before>#include "RPIBeerPongController.h"

#include <signal.h>
#include <unistd.h>

#include "OCPlatform.h"
#include "OCApi.h"

using namespace OIC;
using namespace Service;

RPIBeerPongController::Ptr controller;

#define FREQUENCY_MILLISECONDS 500000 // 500 MS

/*
* This is a signal handling function for SIGINT(CTRL+C).
* A Resource Coordinator handle the SIGINT signal for safe exit.
*
* @param[in] signal
*                 signal number of caught signal.
*/
int g_quitFlag = 0;

void handleSigInt(int signum)
{
    if (signum == SIGINT)
    {
        g_quitFlag = 1;
    }
}

int main()
{
    std::cout << "Starting test program" << std::endl;
    controller = RPIBeerPongController::Ptr(RPIBeerPongController::getInstance());

    static char buffer[50] = {};

    while (!g_quitFlag)
    {
        if(OCProcess() != OC_STACK_OK)
        {
            return 0;
        }

        uint8_t data[4] = {};
        int len, val;

        printf("Input 4 new data values. \n");
        acquireMutex();

        for(size_t i = 0; i < 4; i++)
        {
            fgets(buffer, 50, stdin);

            len = strlen(buffer) - 1;

            for(size_t i = 0; i < len; ++i)
            {
                if(!isdigit(buffer[i]))
                {
                    printf("Invalid input");
                    return 1;
                }
            }
            val = atoi(buffer);
            data[i] = val;
        }

        setTestData(data);
        releaseMutex();

        usleep(FREQUENCY_MILLISECONDS);
    }

	return 0;
}
<commit_msg>ADded individual runthread<commit_after>#include "RPIBeerPongController.h"

#include <signal.h>
#include <unistd.h>

#include <thread>

#include "OCPlatform.h"
#include "OCApi.h"

using namespace OIC;
using namespace Service;

RPIBeerPongController::Ptr controller;

#define FREQUENCY_MILLISECONDS 500000 // 500 MS

/*
* This is a signal handling function for SIGINT(CTRL+C).
* A Resource Coordinator handle the SIGINT signal for safe exit.
*
* @param[in] signal
*                 signal number of caught signal.
*/
int g_quitFlag = 0;

void handleSigInt(int signum)
{
    if (signum == SIGINT)
    {
        g_quitFlag = 1;
    }
}

void runOCThread()
{
    while(!g_quitFlag)
    {
        if(OCProcess() != OC_STACK_OK)
        {
            break;
        }
        usleep(10);
    }
}

int main()
{
    std::cout << "Starting test program" << std::endl;
    controller = RPIBeerPongController::Ptr(RPIBeerPongController::getInstance());

    std::thread runThread(runOCThread);
    runThread.detach();

    static char buffer[50] = {};

    while (!g_quitFlag)
    {

        uint8_t data[4] = {};
        int len, val;

        printf("Input 4 new data values. \n");
        acquireMutex();

        for(size_t i = 0; i < 4; i++)
        {
            fgets(buffer, 50, stdin);

            len = strlen(buffer) - 1;

            for(size_t i = 0; i < len; ++i)
            {
                if(!isdigit(buffer[i]))
                {
                    printf("Invalid input");
                    return 1;
                }
            }
            val = atoi(buffer);
            data[i] = val;
        }

        setTestData(data);
        releaseMutex();

        printf("After released mutex\n");
        usleep(FREQUENCY_MILLISECONDS);
        printf("after usleep\n");
    }

	return 0;
}
<|endoftext|>


<commit_before>#include "../include/semver/semver.hpp"

#include <sstream>
#include <exception>

#include <boost/regex.hpp>

using std::stringstream;

namespace semver {

static unsigned
string_to_int(const string value) {
	stringstream ss(value);
	unsigned result;
	ss >> result;
	return result;
}

/*
 * Methods names 'major' and 'minor' conflicts with sys/sysmacros.h, but POSIX
 * says they must be available, so with the next lines, those macros are
 * undefined. See more information at:
 * http://stackoverflow.com/questions/22240973/major-and-minor-macros-defined-in-sys-sysmacros-h-pulled-in-by-iterator
*/
#undef major
#undef minor

static const string NUMBER_SEPARATOR	= ".";
static const string LABEL_SEPARATOR		= "-";
static const string BUILD_SEPARATOR		= "+";

SemVer::SemVer()
	: fMajor(0),
	  fMinor(0),
	  fPatch(0),
	  fLabel(),
	  fBuild()
{
}

SemVer::SemVer(const SemVer& s)
	: fMajor(s.fMajor),
	  fMinor(s.fMinor),
	  fPatch(s.fPatch),
	  fLabel(s.fLabel),
	  fBuild(s.fBuild)
{
}

SemVer::SemVer(unsigned major, unsigned minor, unsigned patch, const string label, const string build)
	: fMajor(major),
	  fMinor(minor),
	  fPatch(patch),
	  fLabel(label),
	  fBuild(build)
{
}

SemVer::SemVer(const string version)
	: fMajor(0),
	  fMinor(0),
	  fPatch(0),
	  fLabel(),
	  fBuild()
{
	assign(version);
}

SemVer::~SemVer() {
}

void
SemVer::check(const string version) const {
	if (version != toString()) {
		throw std::invalid_argument("Invalid semantic version string: " + version);
	}
}

int
SemVer::intCompare(unsigned a, unsigned b) const {
	return (a < b) ? -1 : (a > b);
}

int
SemVer::stringCompare(string a, string b) const {
	// TODO: Implement this with element precedence rules.
	return a.compare(b);
}

void
SemVer::assign(const string version) {
	// Examples: 1.2.3, 1.2.3-beta, 1.2.3-beta+build, 1.2.3+build
	// RegEx: ([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+)(\+(.*))?|\+(.*))?
	// Matches: 1, 2 and 3: version parts. 4 is always de label part (alpha,
	// beta, etc.); 6 or 7 are the build metainformation part.

	static const boost::regex expression("([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-(\\w+(\\.\\w*)?)(\\+(.*))?|\\+(.*))?");

	boost::match_results<string::const_iterator> results;

	if (boost::regex_search(version, results, expression)) {
		fMajor = string_to_int(results[1]);
		fMinor = string_to_int(results[2]);
		fPatch = string_to_int(results[3]);
		fLabel = results[4];
		fBuild = results[6] != "" ? results[6] : results[7];
		check(version);
	} else {
		throw std::invalid_argument("Invalid semantic version string: " + version);
	}
}

unsigned
SemVer::major() const {
	return fMajor;
}

unsigned
SemVer::minor() const {
	return fMinor;
}

unsigned
SemVer::patch() const {
	return fPatch;
}

const string
SemVer::label() const {
	return fLabel;
}

const string
SemVer::build() const {
	return fBuild;
}

int
SemVer::compare(const SemVer& semver) const {
	if (fMajor == semver.fMajor) {
		if (fMinor == semver.fMinor) {
			if (fPatch == semver.fPatch) {
				if (fLabel == semver.fLabel) {
					return stringCompare(fBuild, semver.fBuild);
				} else {
					return stringCompare(fLabel, semver.fLabel);
				}
			} else {
				return intCompare(fPatch, semver.fPatch);
			}
		} else {
			return intCompare(fMinor, semver.fMinor);
		}
	} else {
		return intCompare(fMajor, semver.fMajor);
	}
	return 0;
}

int
SemVer::compare(const SemVer* semver) const {
	return compare(*semver);
}

bool
SemVer::operator == (const SemVer& semver) const {
	return compare(semver) == 0;
}

bool
SemVer::operator != (const SemVer& semver) const {
	return !operator==(semver);
}

bool
SemVer::operator <	(const SemVer& semver) const {
	return compare(semver) < 0;
}

bool
SemVer::operator >	(const SemVer& semver) const {
	return compare(semver) > 0;
}

bool
SemVer::operator <=	(const SemVer& semver) const {
	return compare(semver) <= 0;
}

bool
SemVer::operator >=	(const SemVer& semver) const {
	return compare(semver) >= 0;
}

const string
SemVer::toString() const {
	stringstream out;
	out << fMajor << NUMBER_SEPARATOR << fMinor << NUMBER_SEPARATOR << fPatch << (fLabel != "" ? LABEL_SEPARATOR + fLabel : "") << (fBuild != "" ? BUILD_SEPARATOR + fBuild : "");
	return out.str();
}

std::ostream&
operator << (std::ostream& out, const SemVer& semver) {
	out << semver.toString();
	return out;
}

}	// namespace semver
<commit_msg>Fix problem getting build information.<commit_after>#include "../include/semver/semver.hpp"

#include <sstream>
#include <exception>

#include <boost/regex.hpp>

using std::stringstream;

namespace semver {

static unsigned
string_to_int(const string value) {
	stringstream ss(value);
	unsigned result;
	ss >> result;
	return result;
}

/*
 * Methods names 'major' and 'minor' conflicts with sys/sysmacros.h, but POSIX
 * says they must be available, so with the next lines, those macros are
 * undefined. See more information at:
 * http://stackoverflow.com/questions/22240973/major-and-minor-macros-defined-in-sys-sysmacros-h-pulled-in-by-iterator
*/
#undef major
#undef minor

static const string NUMBER_SEPARATOR	= ".";
static const string LABEL_SEPARATOR		= "-";
static const string BUILD_SEPARATOR		= "+";

SemVer::SemVer()
	: fMajor(0),
	  fMinor(0),
	  fPatch(0),
	  fLabel(),
	  fBuild()
{
}

SemVer::SemVer(const SemVer& s)
	: fMajor(s.fMajor),
	  fMinor(s.fMinor),
	  fPatch(s.fPatch),
	  fLabel(s.fLabel),
	  fBuild(s.fBuild)
{
}

SemVer::SemVer(unsigned major, unsigned minor, unsigned patch, const string label, const string build)
	: fMajor(major),
	  fMinor(minor),
	  fPatch(patch),
	  fLabel(label),
	  fBuild(build)
{
}

SemVer::SemVer(const string version)
	: fMajor(0),
	  fMinor(0),
	  fPatch(0),
	  fLabel(),
	  fBuild()
{
	assign(version);
}

SemVer::~SemVer() {
}

void
SemVer::check(const string version) const {
	if (version != toString()) {
		throw std::invalid_argument("Invalid semantic version string: " + version);
	}
}

int
SemVer::intCompare(unsigned a, unsigned b) const {
	return (a < b) ? -1 : (a > b);
}

int
SemVer::stringCompare(string a, string b) const {
	// TODO: Implement this with element precedence rules.
	return a.compare(b);
}

void
SemVer::assign(const string version) {
	// Examples: 1.2.3, 1.2.3-beta, 1.2.3-beta+build, 1.2.3+build
	// RegEx: ([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+)(\+(.*))?|\+(.*))?
	// Matches: 1, 2 and 3: version parts. 4 is always de label part (alpha,
	// beta, etc.); 6 or 7 are the build metainformation part.

	static const boost::regex expression("([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-(\\w+(\\.\\w*)?)(\\+(.*))?|\\+(.*))?");

	boost::match_results<string::const_iterator> results;

	if (boost::regex_search(version, results, expression)) {
		fMajor = string_to_int(results[1]);
		fMinor = string_to_int(results[2]);
		fPatch = string_to_int(results[3]);
		fLabel = results[4];
		fBuild = results[7] != "" ? results[7] : results[8];
		check(version);
	} else {
		throw std::invalid_argument("Invalid semantic version string: " + version);
	}
}

unsigned
SemVer::major() const {
	return fMajor;
}

unsigned
SemVer::minor() const {
	return fMinor;
}

unsigned
SemVer::patch() const {
	return fPatch;
}

const string
SemVer::label() const {
	return fLabel;
}

const string
SemVer::build() const {
	return fBuild;
}

int
SemVer::compare(const SemVer& semver) const {
	if (fMajor == semver.fMajor) {
		if (fMinor == semver.fMinor) {
			if (fPatch == semver.fPatch) {
				if (fLabel == semver.fLabel) {
					return stringCompare(fBuild, semver.fBuild);
				} else {
					return stringCompare(fLabel, semver.fLabel);
				}
			} else {
				return intCompare(fPatch, semver.fPatch);
			}
		} else {
			return intCompare(fMinor, semver.fMinor);
		}
	} else {
		return intCompare(fMajor, semver.fMajor);
	}
	return 0;
}

int
SemVer::compare(const SemVer* semver) const {
	return compare(*semver);
}

bool
SemVer::operator == (const SemVer& semver) const {
	return compare(semver) == 0;
}

bool
SemVer::operator != (const SemVer& semver) const {
	return !operator==(semver);
}

bool
SemVer::operator <	(const SemVer& semver) const {
	return compare(semver) < 0;
}

bool
SemVer::operator >	(const SemVer& semver) const {
	return compare(semver) > 0;
}

bool
SemVer::operator <=	(const SemVer& semver) const {
	return compare(semver) <= 0;
}

bool
SemVer::operator >=	(const SemVer& semver) const {
	return compare(semver) >= 0;
}

const string
SemVer::toString() const {
	stringstream out;
	out << fMajor << NUMBER_SEPARATOR << fMinor << NUMBER_SEPARATOR << fPatch << (fLabel != "" ? LABEL_SEPARATOR + fLabel : "") << (fBuild != "" ? BUILD_SEPARATOR + fBuild : "");
	return out.str();
}

std::ostream&
operator << (std::ostream& out, const SemVer& semver) {
	out << semver.toString();
	return out;
}

}	// namespace semver
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005 darkbits                        Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * 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.
 */

#ifndef GCN_LISTBOX_HPP
#define GCN_LISTBOX_HPP

#include "guichan/keylistener.hpp"
#include "guichan/listmodel.hpp"
#include "guichan/mouselistener.hpp"
#include "guichan/platform.hpp"
#include "guichan/widget.hpp"

namespace gcn
{
    /**
     * A ListBox displaying a list in which elemets can be selected. Only one
     * element can be selected at time. ListBox uses a ListModel to handle the
     * list. To be able to use ListBox you must give ListBox an implemented
     * ListModel which represents your list.
     */
    class GCN_CORE_DECLSPEC ListBox :
        public Widget,
        public MouseListener,
        public KeyListener
    {
    public:
        /**
         * Constructor.
         */
        ListBox();

        /**
         * Constructor.
         *
         * @param listModel the ListModel to use.
         */
        ListBox(ListModel *listModel);

        /**
         * Destructor.
         */
        virtual ~ListBox() { }

        /**
         * Gets the ListModel index of the selected element.
         *
         * @return the ListModel index of the selected element.
         */
        virtual int getSelected();

        /**
         * Sets the ListModel index of the selected element.
         *
         * @param selected the ListModel index of the selected element.
         */
        virtual void setSelected(int selected);

        /**
         * Sets the ListModel to use.
         *
         * @param listModel the ListModel to use.
         */
        virtual void setListModel(ListModel *listModel);

        /**
         * Gets the ListModel used.
         *
         * @return the ListModel used.
         */
        virtual ListModel *getListModel();

        /**
         * Adjusts the size of the ListBox to fit the font used.
         */
        virtual void adjustSize();

        // Inherited from Widget

        virtual void draw(Graphics* graphics);

        virtual void drawBorder(Graphics* graphics);

        virtual void logic();

        // Inherited from KeyListener

        virtual void keyPress(const Key& key);

        // Inherited from MouseListener

        virtual void mousePress(int x, int y, int button);

    protected:
        ListModel *mListModel;
        int mSelected;
    };
}

#endif // end GCN_LISTBOX_HPP
<commit_msg>Ability for wrapping keyboard selection has been added.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005 darkbits                        Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * 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.
 */

#ifndef GCN_LISTBOX_HPP
#define GCN_LISTBOX_HPP

#include "guichan/keylistener.hpp"
#include "guichan/listmodel.hpp"
#include "guichan/mouselistener.hpp"
#include "guichan/platform.hpp"
#include "guichan/widget.hpp"

namespace gcn
{
    /**
     * A ListBox displaying a list in which elemets can be selected. Only one
     * element can be selected at time. ListBox uses a ListModel to handle the
     * list. To be able to use ListBox you must give ListBox an implemented
     * ListModel which represents your list.
     */
    class GCN_CORE_DECLSPEC ListBox :
        public Widget,
        public MouseListener,
        public KeyListener
    {
    public:
        /**
         * Constructor.
         */
        ListBox();

        /**
         * Constructor.
         *
         * @param listModel the ListModel to use.
         */
        ListBox(ListModel *listModel);

        /**
         * Destructor.
         */
        virtual ~ListBox() { }

        /**
         * Gets the ListModel index of the selected element.
         *
         * @return the ListModel index of the selected element.
         */
        virtual int getSelected();

        /**
         * Sets the ListModel index of the selected element.
         *
         * @param selected the ListModel index of the selected element.
         */
        virtual void setSelected(int selected);

        /**
         * Sets the ListModel to use.
         *
         * @param listModel the ListModel to use.
         */
        virtual void setListModel(ListModel *listModel);

        /**
         * Gets the ListModel used.
         *
         * @return the ListModel used.
         */
        virtual ListModel *getListModel();

        /**
         * Adjusts the size of the ListBox to fit the font used.
         */
        virtual void adjustSize();

        /**
         * Checks whether the ListBox wraps when selecting items with keyboard.
         *
         * Wrapping means that if up is pressed and the first item is selected, the last
         * item will get selected. If down is pressed and the last item is selected, the
         * first item will get selected.
         *
         * @return true if wrapping, fasle otherwise.
         */
        virtual bool isWrappingKeyboardSelection();

        /**
         * Sets the ListBox to wrap or not when selecting items with keyboard.
         *
         * Wrapping means that if up is pressed and the first item is selected, the last
         * item will get selected. If down is pressed and the last item is selected, the
         * first item will get selected.
         *
         */
         virtual void setWrappingKeyboardSelection(bool wrapping);

        // Inherited from Widget

        virtual void draw(Graphics* graphics);

        virtual void drawBorder(Graphics* graphics);

        virtual void logic();

        // Inherited from KeyListener

        virtual void keyPress(const Key& key);

        // Inherited from MouseListener

        virtual void mousePress(int x, int y, int button);

    protected:
        ListModel *mListModel;
        int mSelected;
        bool mWrappingKeyboardSelection;
    };
}

#endif // end GCN_LISTBOX_HPP
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_BEST_FIT
#define COFFEE_MILL_BEST_FIT
#include <vector>

namespace mill
{

template<typename sclT, template<typename sclT, std::size_t D> class vectorT,
         template<typename sclT, std::size_t R, std::size_t C> class matrixT>
class BestFit
{
  public:

    using scalar_type   = sclT;
    using vector3_type  = vectorT<sclT, 3>;
    using vector4_type  = vectorT<sclT, 4>;
    using matrix33_type = matrixT<sclT, 3, 3>;
    using matrix44_type = matrixT<sclT, 4, 4>;
    using structure_type = std::vector<vector_3_type>;

  public:
    BestFit() = default;
    ~BestFit() = default;

    structure_type
    fit(const structure_type& snapshot, const structure_type& reference) const;

    structure_type // with reference cash
    fit(const structure_type& snapshot) const;

    matrix33_type
    rotational_matrix(const structure_type& snapshot,
                      const structure_type& reference) const;
    matrix33_type // with cash
    rotational_matrix(const structure_type& snapshot) const;

    structure_type const& reference() const {return reference_;}
    structure_type &      reference()       {return reference_;}

  private:

    Matrix33_type make_rotation_matrix(const structure_type& snapshot,
                                       const structure_type& reference) const;
    Matrix33_type make_rotation_matrix(const Vector4d& quaternion) const;

    Matrix44_type score_matrix(const std::vector<Vector3d>& a,
                               const std::vector<Vector3d>& b) const;

  private:

    structure_type reference_; //!< optional;
};

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::Structure
BestFit<sclT, vectorT, matrixT>::fit(
        const structure_type& str, const structure_type& ref) const
{
    if(str.size() != ref.size())
        throw std::invalid_argument("different structure in argument");

    vector3_type sum_str(0., 0., 0.);
    for(auto iter = str.cbegin(); iter != str.cend(); ++iter)
        sum_str += *iter;
    const vector3_type centroid_str =
        sum_str / static_cast<scalar_type>(str.size());

    structure_type rotated_str;
    rotated.reserve(str.size());
    for(auto iter = str.begin(); iter != str.end(); ++iter)
        rotated_str.push_back(*iter - centroid_str);

    vector3_type sum_ref(0., 0., 0.);
    for(auto iter = ref.cbegin(); iter != ref.cend(); ++iter)
        sum_ref += *iter;
    vector3_type centroid_ref =
        sum_ref / static_cast<scalar_type>(ref.size());

    structure_type zeroed_ref;
    zeroed_ref.reserve(ref.size());
    for(auto iter = ref.begin(); iter != ref.end(); ++iter)
        zeroed_ref.push_back(*iter - centroid_ref);

    auto R = this->make_rotation_matrix(rotated_str, zeroed_ref);
    for(auto iter = rotated_str.begin(); iter != rotated_str.end(); ++iter)
    {
        const vector3_type temp = R * (*iter);
        *iter = temp;
    }

    return rotated_str;
}

BestFit::Matrix3d BestFit::RotationMatrix(const Structure& structure) const
{
    assert(structure.size() == this->reference_.size());

    Vector3d sum(0e0);
    for(auto iter = structure.cbegin(); iter != structure.cend(); ++iter)
        sum += *iter;
    const Vector3d CoM = sum / static_cast<double>(structure.size());

    Structure zeroed;
    zeroed.reserve(structure.size());
    for(auto iter = structure.cbegin(); iter != structure.cend(); ++iter)
        zeroed.push_back(*iter - CoM);

    return RotationMatrix(zeroed, true);
}

BestFit::Matrix3d BestFit::RotationMatrix(const Structure& structure, bool zeroed) const
{
    assert(zeroed);
    std::vector<Vector3d> rA(structure.size());
    std::vector<Vector3d> rB(structure.size());

    for(std::size_t i=0; i < structure.size(); ++i)
    {
        rA.at(i) = reference_[i] + structure[i];
        rB.at(i) = reference_[i] - structure[i];
    }

    auto score = score_matrix(rA, rB);
    ax::JacobiSolver<4> solver(score);
    std::pair<double, Vector4d> min_pair = solver.get_mineigenpair();
    const Vector4d q = min_pair.second;

    return rotation_matrix(q);
}

template<typename vector3T,  typename vector4T,
         typename matrix33T, typename matrix44T>
BestFit::Matrix4d
BestFit::score_matrix(const std::vector<Vector3d>& a,
                      const std::vector<Vector3d>& b) const
{
    assert(a.size() == b.size());

    Matrix4d retval(0e0);
    for(std::size_t i(0); i<a.size(); ++i)
    {
        retval(0,0) += (b[i][0]*b[i][0]) + (b[i][1]*b[i][1]) + (b[i][2]*b[i][2]);
        retval(0,1) += (a[i][2]*b[i][1]) - (a[i][1]*b[i][2]);
        retval(0,2) += (a[i][0]*b[i][2]) - (a[i][2]*b[i][0]);
        retval(0,3) += (a[i][1]*b[i][0]) - (a[i][0]*b[i][1]);
        retval(1,1) += (b[i][0]*b[i][0]) + (a[i][1]*a[i][1]) + (a[i][2]*a[i][2]);
        retval(1,2) += (b[i][0]*b[i][1]) - (a[i][0]*a[i][1]);
        retval(1,3) += (b[i][0]*b[i][2]) - (a[i][0]*a[i][2]);
        retval(2,2) += (a[i][0]*a[i][0]) + (b[i][1]*b[i][1]) + (a[i][2]*a[i][2]);
        retval(2,3) += (b[i][1]*b[i][2]) - (a[i][1]*a[i][2]);
        retval(3,3) += (a[i][0]*a[i][0]) + (a[i][1]*a[i][1]) + (b[i][2]*b[i][2]);
    }

    const double N = static_cast<double>(a.size());

    retval(0,0) = retval(0,0) / N;
    retval(0,1) = retval(0,1) / N;
    retval(0,2) = retval(0,2) / N;
    retval(0,3) = retval(0,3) / N;
    retval(1,1) = retval(1,1) / N;
    retval(1,2) = retval(1,2) / N;
    retval(1,3) = retval(1,3) / N;
    retval(2,2) = retval(2,2) / N;
    retval(2,3) = retval(2,3) / N;
    retval(3,3) = retval(3,3) / N;

    //symmetric matrix
    retval(1,0) = retval(0,1);
    retval(2,0) = retval(0,2);
    retval(2,1) = retval(1,2);
    retval(3,0) = retval(0,3);
    retval(3,1) = retval(1,3);
    retval(3,2) = retval(2,3);

    return retval;
}

BestFit::Matrix3d BestFit::rotation_matrix(const Vector4d& q) const
{
    Matrix3d R(0e0);
    R(0,0) = 2e0*q[0]*q[0] + 2e0*q[1]*q[1] - 1e0;
    R(0,1) = 2e0*q[1]*q[2] - 2e0*q[0]*q[3];
    R(0,2) = 2e0*q[1]*q[3] + 2e0*q[0]*q[2];
    R(1,0) = 2e0*q[1]*q[2] + 2e0*q[0]*q[3];
    R(1,1) = 2e0*q[0]*q[0] + 2e0*q[2]*q[2] - 1e0;
    R(1,2) = 2e0*q[2]*q[3] - 2e0*q[0]*q[1];
    R(2,0) = 2e0*q[1]*q[3] - 2e0*q[0]*q[2];
    R(2,1) = 2e0*q[2]*q[3] + 2e0*q[0]*q[1];
    R(2,2) = 2e0*q[0]*q[0] + 2e0*q[3]*q[3] - 1e0;
    return R;
}

}// mill

#endif /* COFFEE_MILL_BEST_FIT */
<commit_msg>change BestFit<commit_after>#ifndef COFFEE_MILL_BEST_FIT
#define COFFEE_MILL_BEST_FIT
#include <vector>

namespace mill
{

template<typename sclT, template<typename sclT1, std::size_t D> class vectorT,
         template<typename sclT2, std::size_t R, std::size_t C> class matrixT>
class BestFit
{
  public:

    using scalar_type   = sclT;
    using vector3_type  = vectorT<sclT, 3>;
    using vector4_type  = vectorT<sclT, 4>;
    using matrix33_type = matrixT<sclT, 3, 3>;
    using matrix44_type = matrixT<sclT, 4, 4>;
    using structure_type = std::vector<vector3_type>;

  public:
    BestFit() = default;
    ~BestFit() = default;

    structure_type
    fit(const structure_type& snapshot, const structure_type& reference) const;

    structure_type // with reference cash
    fit(const structure_type& snapshot) const;

    matrix33_type
    rotational_matrix(const structure_type& snapshot,
                      const structure_type& reference) const;
    matrix33_type // with cash
    rotational_matrix(const structure_type& snapshot) const;

    structure_type const& reference() const {return reference_;}
    structure_type &      reference()       {return reference_;}

  private:

    structure_type move_to_center(const structure_type& str) const;
    void move_to_center(structure_type& str) const;

    matrix33_type make_rotation_matrix(const structure_type& snapshot,
                                       const structure_type& reference) const;
    matrix33_type make_rotation_matrix(const vector4_type& quaternion) const;

    matrix44_type score_matrix(const std::vector<vector3_type>& a,
                               const std::vector<vector3_type>& b) const;

  private:

    structure_type reference_; //!< optional;
};

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::structure_type
BestFit<sclT, vectorT, matrixT>::fit(
        const structure_type& str, const structure_type& ref) const
{
    if(str.size() != ref.size())
        throw std::invalid_argument("different structure in argument");

    vector3_type sum_str(0., 0., 0.);
    for(auto iter = str.cbegin(); iter != str.cend(); ++iter)
        sum_str += *iter;
    const vector3_type centroid_str =
        sum_str / static_cast<scalar_type>(str.size());

    structure_type rotated_str;
    rotated_str.reserve(str.size());
    for(auto iter = str.begin(); iter != str.end(); ++iter)
        rotated_str.push_back(*iter - centroid_str);

    vector3_type sum_ref(0., 0., 0.);
    for(auto iter = ref.cbegin(); iter != ref.cend(); ++iter)
        sum_ref += *iter;
    vector3_type centroid_ref =
        sum_ref / static_cast<scalar_type>(ref.size());

    structure_type zeroed_ref;
    zeroed_ref.reserve(ref.size());
    for(auto iter = ref.begin(); iter != ref.end(); ++iter)
        zeroed_ref.push_back(*iter - centroid_ref);

    auto R = this->make_rotation_matrix(rotated_str, zeroed_ref);
    for(auto iter = rotated_str.begin(); iter != rotated_str.end(); ++iter)
    {
        const vector3_type temp = R * (*iter);
        *iter = temp;
    }

    return rotated_str;
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::matrix33_type
BestFit<sclT, vectorT, matrixT>::rotational_matrix(
        const structure_type& structure) const
{
    assert(structure.size() == this->reference_.size());

    vector3_type sum(0e0);
    for(auto iter = structure.cbegin(); iter != structure.cend(); ++iter)
        sum += *iter;
    const vector3_type centroid = sum / static_cast<sclT>(structure.size());

    structure_type zeroed;
    zeroed.reserve(structure.size());
    for(auto iter = structure.cbegin(); iter != structure.cend(); ++iter)
        zeroed.push_back(*iter - centroid);

    return RotationMatrix(zeroed, true);
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::matrix33_type
BestFit<sclT, vectorT, matrixT>::make_rotation_matrix(
        const structure_type& structure, const structure_type& reference) const
{
    if(structure.size() != reference.size())
        throw std::invalid_argument("different size structures");
    std::vector<vector3_type> rA(structure.size());
    std::vector<vector3_type> rB(structure.size());

    for(std::size_t i=0; i < structure.size(); ++i)
    {
        rA[i] = reference[i] + structure[i];
        rB[i] = reference[i] - structure[i];
    }

    auto score = score_matrix(rA, rB);
//     ax::JacobiSolver<4> solver(score);
//     std::pair<double, Vector4d> min_pair = solver.get_mineigenpair();
//     const Vector4d q = min_pair.second;

//     return rotation_matrix(q);
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::matrix44_type
BestFit<sclT, vectorT, matrixT>::score_matrix(
        const std::vector<vector3_type>& a, const std::vector<vector3_type>& b) const
{
    if(a.size() != b.size())
        throw std::invalid_argument("different size structures");

    matrix44_type retval;
    for(std::size_t i(0); i<a.size(); ++i)
    {
        retval(0,0) += (b[i][0]*b[i][0]) + (b[i][1]*b[i][1]) + (b[i][2]*b[i][2]);
        retval(0,1) += (a[i][2]*b[i][1]) - (a[i][1]*b[i][2]);
        retval(0,2) += (a[i][0]*b[i][2]) - (a[i][2]*b[i][0]);
        retval(0,3) += (a[i][1]*b[i][0]) - (a[i][0]*b[i][1]);
        retval(1,1) += (b[i][0]*b[i][0]) + (a[i][1]*a[i][1]) + (a[i][2]*a[i][2]);
        retval(1,2) += (b[i][0]*b[i][1]) - (a[i][0]*a[i][1]);
        retval(1,3) += (b[i][0]*b[i][2]) - (a[i][0]*a[i][2]);
        retval(2,2) += (a[i][0]*a[i][0]) + (b[i][1]*b[i][1]) + (a[i][2]*a[i][2]);
        retval(2,3) += (b[i][1]*b[i][2]) - (a[i][1]*a[i][2]);
        retval(3,3) += (a[i][0]*a[i][0]) + (a[i][1]*a[i][1]) + (b[i][2]*b[i][2]);
    }

    const sclT inv_N = 1. / static_cast<sclT>(a.size());

    retval(0,0) = retval(0,0) * inv_N;
    retval(0,1) = retval(0,1) * inv_N;
    retval(0,2) = retval(0,2) * inv_N;
    retval(0,3) = retval(0,3) * inv_N;
    retval(1,1) = retval(1,1) * inv_N;
    retval(1,2) = retval(1,2) * inv_N;
    retval(1,3) = retval(1,3) * inv_N;
    retval(2,2) = retval(2,2) * inv_N;
    retval(2,3) = retval(2,3) * inv_N;
    retval(3,3) = retval(3,3) * inv_N;

    //symmetric matrix
    retval(1,0) = retval(0,1);
    retval(2,0) = retval(0,2);
    retval(2,1) = retval(1,2);
    retval(3,0) = retval(0,3);
    retval(3,1) = retval(1,3);
    retval(3,2) = retval(2,3);

    return retval;
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::matrix33_type
BestFit<sclT, vectorT, matrixT>::make_rotation_matrix(const vector4_type& q) const
{
    matrix33_type R;
    R(0,0) = 2e0*q[0]*q[0] + 2e0*q[1]*q[1] - 1e0;
    R(0,1) = 2e0*q[1]*q[2] - 2e0*q[0]*q[3];
    R(0,2) = 2e0*q[1]*q[3] + 2e0*q[0]*q[2];
    R(1,0) = 2e0*q[1]*q[2] + 2e0*q[0]*q[3];
    R(1,1) = 2e0*q[0]*q[0] + 2e0*q[2]*q[2] - 1e0;
    R(1,2) = 2e0*q[2]*q[3] - 2e0*q[0]*q[1];
    R(2,0) = 2e0*q[1]*q[3] - 2e0*q[0]*q[2];
    R(2,1) = 2e0*q[2]*q[3] + 2e0*q[0]*q[1];
    R(2,2) = 2e0*q[0]*q[0] + 2e0*q[3]*q[3] - 1e0;
    return R;
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
typename BestFit<sclT, vectorT, matrixT>::structure_type
BestFit<sclT, vectorT, matrixT>::move_to_center(const structure_type& str) const
{
    vector3_type sum(0., 0., 0.);
    for(auto iter = str.cbegin(); iter != str.cend(); ++iter)
        sum += *iter;
    const sclT invN = 1. / static_cast<double>(str.size());
    const vector3_type centroid = sum * invN;

    structure_type retval(str.size());
    for(std::size_t i = 0; i<str.size(); ++i)
        retval[i] = str[i] - centroid;

    return retval;
}

template<typename sclT, template<typename sT1, std::size_t D> class vectorT,
         template<typename sT2, std::size_t R, std::size_t C> class matrixT>
void BestFit<sclT, vectorT, matrixT>::move_to_center(structure_type& str) const
{
    vector3_type sum(0., 0., 0.);
    for(auto iter = str.cbegin(); iter != str.cend(); ++iter)
        sum += *iter;
    const sclT invN = 1. / static_cast<double>(str.size());
    const vector3_type centroid = sum * invN;

    for(auto iter = str.begin(); iter != str.end(); ++iter)
        *iter -= centroid;

    return ;
}

}// mill

#endif /* COFFEE_MILL_BEST_FIT */
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process_util.h"
#include "base/test/test_timeouts.h"
#include "chrome/browser/service/service_process_control.h"
#include "chrome/browser/service/service_process_control_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/service_process_util.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

class ServiceProcessControlBrowserTest
    : public InProcessBrowserTest {
 public:
  ServiceProcessControlBrowserTest()
      : service_process_handle_(base::kNullProcessHandle) {
  }
  ~ServiceProcessControlBrowserTest() {
    base::CloseProcessHandle(service_process_handle_);
    service_process_handle_ = base::kNullProcessHandle;
    // Delete all instances of ServiceProcessControl.
    ServiceProcessControlManager::GetInstance()->Shutdown();
  }

#if defined(OS_MACOSX)
  virtual void TearDown() {
    // ForceServiceProcessShutdown removes the process from launchd on Mac.
    ForceServiceProcessShutdown("", 0);
  }
#endif  // OS_MACOSX

 protected:
  void LaunchServiceProcessControl() {
    ServiceProcessControl* process =
        ServiceProcessControlManager::GetInstance()->GetProcessControl(
            browser()->profile());
    process_ = process;

    // Launch the process asynchronously.
    process->Launch(
        NewRunnableMethod(
            this,
            &ServiceProcessControlBrowserTest::ProcessControlLaunched),
        NewRunnableMethod(
            this,
            &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed));

    // Then run the message loop to keep things running.
    ui_test_utils::RunMessageLoop();
  }

  // Send a remoting host status request and wait reply from the service.
  void SendRequestAndWait() {
    process()->GetCloudPrintProxyStatus(NewCallback(
        this, &ServiceProcessControlBrowserTest::CloudPrintStatusCallback));
    ui_test_utils::RunMessageLoop();
  }

  void CloudPrintStatusCallback(
      bool enabled, std::string email) {
    MessageLoop::current()->Quit();
  }

  void Disconnect() {
    // This will delete all instances of ServiceProcessControl and close the IPC
    // connections.
    ServiceProcessControlManager::GetInstance()->Shutdown();
    process_ = NULL;
  }

  void WaitForShutdown() {
    EXPECT_TRUE(base::WaitForSingleProcess(
        service_process_handle_,
        TestTimeouts::wait_for_terminate_timeout_ms()));
  }

  void ProcessControlLaunched() {
    base::ProcessId service_pid;
    EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
    EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
    EXPECT_TRUE(base::OpenProcessHandleWithAccess(
        service_pid,
        base::kProcessAccessWaitForTermination,
        &service_process_handle_));
    // Quit the current message. Post a QuitTask instead of just calling Quit()
    // because this can get invoked in the context of a Launch() call and we
    // may not be in Run() yet.
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  void ProcessControlLaunchFailed() {
    ADD_FAILURE();
    // Quit the current message.
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  ServiceProcessControl* process() { return process_; }

 private:
  ServiceProcessControl* process_;
  base::ProcessHandle service_process_handle_;
};

// They way that the IPC is implemented only works on windows. This has to
// change when we implement a different scheme for IPC.
// Times out flakily, http://crbug.com/70076.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       DISABLED_LaunchAndIPC) {
  LaunchServiceProcessControl();

  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // And then shutdown the service process.
  EXPECT_TRUE(process()->Shutdown());
}

// This tests the case when a service process is launched when browser
// starts but we try to launch it again in the remoting setup dialog.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, LaunchTwice) {
  // Launch the service process the first time.
  LaunchServiceProcessControl();

  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // Launch the service process again.
  LaunchServiceProcessControl();
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // And then shutdown the service process.
  EXPECT_TRUE(process()->Shutdown());
}

static void DecrementUntilZero(int* count) {
  (*count)--;
  if (!(*count))
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}

// Invoke multiple Launch calls in succession and ensure that all the tasks
// get invoked.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MultipleLaunchTasks) {
  ServiceProcessControl* process =
      ServiceProcessControlManager::GetInstance()->GetProcessControl(
          browser()->profile());
  int launch_count = 5;
  for (int i = 0; i < launch_count; i++) {
    // Launch the process asynchronously.
    process->Launch(
        NewRunnableFunction(&DecrementUntilZero, &launch_count),
        new MessageLoop::QuitTask());
  }
  // Then run the message loop to keep things running.
  ui_test_utils::RunMessageLoop();
  EXPECT_EQ(0, launch_count);
  // And then shutdown the service process.
  EXPECT_TRUE(process->Shutdown());
}

// Make sure using the same task for success and failure tasks works.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, SameLaunchTask) {
  ServiceProcessControl* process =
      ServiceProcessControlManager::GetInstance()->GetProcessControl(
          browser()->profile());
  int launch_count = 5;
  for (int i = 0; i < launch_count; i++) {
    // Launch the process asynchronously.
    Task * task = NewRunnableFunction(&DecrementUntilZero, &launch_count);
    process->Launch(task, task);
  }
  // Then run the message loop to keep things running.
  ui_test_utils::RunMessageLoop();
  EXPECT_EQ(0, launch_count);
  // And then shutdown the service process.
  EXPECT_TRUE(process->Shutdown());
}

// Tests whether disconnecting from the service IPC causes the service process
// to die.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, DieOnDisconnect) {
  // Launch the service process.
  LaunchServiceProcessControl();
  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  Disconnect();
  WaitForShutdown();
}

//http://code.google.com/p/chromium/issues/detail?id=70793
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       DISABLED_ForceShutdown) {
  // Launch the service process.
  LaunchServiceProcessControl();
  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  base::ProcessId service_pid;
  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
  chrome::VersionInfo version_info;
  ForceServiceProcessShutdown(version_info.Version(), service_pid);
  WaitForShutdown();
}

IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, CheckPid) {
  base::ProcessId service_pid;
  EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid));
  // Launch the service process.
  LaunchServiceProcessControl();
  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
}

DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest);
<commit_msg>Mark CheckPid,DieOnDisconnect,LaunchTwice,MultipleLaunchTasks,SameLaunchTask as FAILS on mac.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/process_util.h"
#include "base/test/test_timeouts.h"
#include "chrome/browser/service/service_process_control.h"
#include "chrome/browser/service/service_process_control_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/service_process_util.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"

class ServiceProcessControlBrowserTest
    : public InProcessBrowserTest {
 public:
  ServiceProcessControlBrowserTest()
      : service_process_handle_(base::kNullProcessHandle) {
  }
  ~ServiceProcessControlBrowserTest() {
    base::CloseProcessHandle(service_process_handle_);
    service_process_handle_ = base::kNullProcessHandle;
    // Delete all instances of ServiceProcessControl.
    ServiceProcessControlManager::GetInstance()->Shutdown();
  }

#if defined(OS_MACOSX)
  virtual void TearDown() {
    // ForceServiceProcessShutdown removes the process from launchd on Mac.
    ForceServiceProcessShutdown("", 0);
  }
#endif  // OS_MACOSX

 protected:
  void LaunchServiceProcessControl() {
    ServiceProcessControl* process =
        ServiceProcessControlManager::GetInstance()->GetProcessControl(
            browser()->profile());
    process_ = process;

    // Launch the process asynchronously.
    process->Launch(
        NewRunnableMethod(
            this,
            &ServiceProcessControlBrowserTest::ProcessControlLaunched),
        NewRunnableMethod(
            this,
            &ServiceProcessControlBrowserTest::ProcessControlLaunchFailed));

    // Then run the message loop to keep things running.
    ui_test_utils::RunMessageLoop();
  }

  // Send a remoting host status request and wait reply from the service.
  void SendRequestAndWait() {
    process()->GetCloudPrintProxyStatus(NewCallback(
        this, &ServiceProcessControlBrowserTest::CloudPrintStatusCallback));
    ui_test_utils::RunMessageLoop();
  }

  void CloudPrintStatusCallback(
      bool enabled, std::string email) {
    MessageLoop::current()->Quit();
  }

  void Disconnect() {
    // This will delete all instances of ServiceProcessControl and close the IPC
    // connections.
    ServiceProcessControlManager::GetInstance()->Shutdown();
    process_ = NULL;
  }

  void WaitForShutdown() {
    EXPECT_TRUE(base::WaitForSingleProcess(
        service_process_handle_,
        TestTimeouts::wait_for_terminate_timeout_ms()));
  }

  void ProcessControlLaunched() {
    base::ProcessId service_pid;
    EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
    EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
    EXPECT_TRUE(base::OpenProcessHandleWithAccess(
        service_pid,
        base::kProcessAccessWaitForTermination,
        &service_process_handle_));
    // Quit the current message. Post a QuitTask instead of just calling Quit()
    // because this can get invoked in the context of a Launch() call and we
    // may not be in Run() yet.
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  void ProcessControlLaunchFailed() {
    ADD_FAILURE();
    // Quit the current message.
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
  }

  ServiceProcessControl* process() { return process_; }

 private:
  ServiceProcessControl* process_;
  base::ProcessHandle service_process_handle_;
};

// They way that the IPC is implemented only works on windows. This has to
// change when we implement a different scheme for IPC.
// Times out flakily, http://crbug.com/70076.
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       DISABLED_LaunchAndIPC) {
  LaunchServiceProcessControl();

  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // And then shutdown the service process.
  EXPECT_TRUE(process()->Shutdown());
}

// This tests the case when a service process is launched when browser
// starts but we try to launch it again in the remoting setup dialog.
// Fails on mac. http://crbug.com/75518
#if defined(OS_MACOSX)
#define MAYBE_LaunchTwice FAILS_LaunchTwice
#else
#define MAYBE_LaunchTwice LaunchTwice
#endif
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_LaunchTwice) {
  // Launch the service process the first time.
  LaunchServiceProcessControl();

  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // Launch the service process again.
  LaunchServiceProcessControl();
  EXPECT_TRUE(process()->is_connected());
  SendRequestAndWait();

  // And then shutdown the service process.
  EXPECT_TRUE(process()->Shutdown());
}

static void DecrementUntilZero(int* count) {
  (*count)--;
  if (!(*count))
    MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask());
}

// Invoke multiple Launch calls in succession and ensure that all the tasks
// get invoked.
// Fails on mac. http://crbug.com/75518
#if defined(OS_MACOSX)
#define MAYBE_MultipleLaunchTasks FAILS_MultipleLaunchTasks
#else
#define MAYBE_MultipleLaunchTasks MultipleLaunchTasks
#endif
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       MAYBE_MultipleLaunchTasks) {
  ServiceProcessControl* process =
      ServiceProcessControlManager::GetInstance()->GetProcessControl(
          browser()->profile());
  int launch_count = 5;
  for (int i = 0; i < launch_count; i++) {
    // Launch the process asynchronously.
    process->Launch(
        NewRunnableFunction(&DecrementUntilZero, &launch_count),
        new MessageLoop::QuitTask());
  }
  // Then run the message loop to keep things running.
  ui_test_utils::RunMessageLoop();
  EXPECT_EQ(0, launch_count);
  // And then shutdown the service process.
  EXPECT_TRUE(process->Shutdown());
}

// Make sure using the same task for success and failure tasks works.
// Fails on mac. http://crbug.com/75518
#if defined(OS_MACOSX)
#define MAYBE_SameLaunchTask FAILS_SameLaunchTask
#else
#define MAYBE_SameLaunchTask SameLaunchTask
#endif
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_SameLaunchTask) {
  ServiceProcessControl* process =
      ServiceProcessControlManager::GetInstance()->GetProcessControl(
          browser()->profile());
  int launch_count = 5;
  for (int i = 0; i < launch_count; i++) {
    // Launch the process asynchronously.
    Task * task = NewRunnableFunction(&DecrementUntilZero, &launch_count);
    process->Launch(task, task);
  }
  // Then run the message loop to keep things running.
  ui_test_utils::RunMessageLoop();
  EXPECT_EQ(0, launch_count);
  // And then shutdown the service process.
  EXPECT_TRUE(process->Shutdown());
}

// Tests whether disconnecting from the service IPC causes the service process
// to die.
// Fails on mac. http://crbug.com/75518
#if defined(OS_MACOSX)
#define MAYBE_DieOnDisconnect FAILS_DieOnDisconnect
#else
#define MAYBE_DieOnDisconnect DieOnDisconnect
#endif
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       MAYBE_DieOnDisconnect) {
  // Launch the service process.
  LaunchServiceProcessControl();
  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  Disconnect();
  WaitForShutdown();
}

//http://code.google.com/p/chromium/issues/detail?id=70793
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest,
                       DISABLED_ForceShutdown) {
  // Launch the service process.
  LaunchServiceProcessControl();
  // Make sure we are connected to the service process.
  EXPECT_TRUE(process()->is_connected());
  base::ProcessId service_pid;
  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
  chrome::VersionInfo version_info;
  ForceServiceProcessShutdown(version_info.Version(), service_pid);
  WaitForShutdown();
}

// Fails on mac. http://crbug.com/75518
#if defined(OS_MACOSX)
#define MAYBE_CheckPid FAILS_CheckPid
#else
#define MAYBE_CheckPid CheckPid
#endif
IN_PROC_BROWSER_TEST_F(ServiceProcessControlBrowserTest, MAYBE_CheckPid) {
  base::ProcessId service_pid;
  EXPECT_FALSE(GetServiceProcessData(NULL, &service_pid));
  // Launch the service process.
  LaunchServiceProcessControl();
  EXPECT_TRUE(GetServiceProcessData(NULL, &service_pid));
  EXPECT_NE(static_cast<base::ProcessId>(0), service_pid);
}

DISABLE_RUNNABLE_METHOD_REFCOUNT(ServiceProcessControlBrowserTest);
<|endoftext|>