<commit_before>#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;

bitset<100000> bs;
vector<ll> primes;

void sieve(ll sz) {
	bs[0] = bs[1] = 1;
	for (ll i = 2; i <= sz; i++) {
		if (!bs[i]) {
			for (ll j = i*i; j <= sz; j+=i) {
				bs[j] = 1;
			}
			primes.push_back(i);
		}
	}
}

ll fex(ll base, ll exp, ll mod = 1e18) {
	if (exp == 1) return base;
	if (exp == 0) return 1ll;
	ll ret = fex(base, exp / 2, mod);
	ret *= ret;
	ret %= mod;
	if (exp % 2) {
		ret *= base;
		ret %= mod;
	}
	return ret;
}

ll invmod(ll operand, ll mod) {
	return fex(operand, mod - 2, mod);
}

ll invmod_ex(ll operand, ll mod) {
	ll b0 = mod, t, q;
	ll x0 = 0, x1 = 1;
	if (mod == 1) return 1;
	while (operand > 1) {
		q = operand / mod;
		t = mod, mod = operand % mod, operand = t;
		t = x0, x0 = x1 - q * x0, x1 = t;
	}
	if (x1 < 0) x1 += b0;
	return x1;
}

vector<ii> primeFactorialization(ll num) {
	vector<ii> ret;
	int p = 0;
	while (num > 1) {
		int cnt = 0;
		while (num % primes[p] == 0) {
			num /= primes[p];
			cnt++;
		}
		if (cnt) ret.emplace_back(primes[p], cnt);
		p++;
	}
	return ret;
}

ll chinese_remainder(vector<ll>& mods, vector<ll>& rems) {
	ll prod = 1, sum = 0;

	for (ll mod: mods) {
		prod *= mod;
	}
	for (int i = 0; i < (int) rems.size(); i++) {
		ll p = prod / mods[i];
		sum += rems[i] * invmod_ex(p, mods[i]) * p;
	}

	return sum % prod;
}

struct Lucas {
	ll m, sz;
	vector<ll> fact, ifact;
	const static ll maxSz = 100000;

	Lucas(ll m) : m(m), sz(min(m + 1, 100000ll)), fact(min(m + 1, 100000ll)), ifact(min(m + 1, 100000ll)) {
		generateFact();
	}

	void generateFact() {
		fact[0] = ifact[0] = 1;
		for (int i = 1; i < sz; i++) {
			fact[i] = (fact[i-1] * i) % m;
			ifact[i] = invmod(fact[i], m);
		}
	}

	ll ncr(int n, int r) {
		if (r > n) {
			return 0;
		}
		return ((fact[n] * ifact[n-r]) % m * ifact[r]) % m;
	}

	vector<ll> decompose(ll num) {
		vector<ll> ret;
		while (num > 0) {
			ret.push_back(num % m);
			num /= m;
		}
		return ret;
	}

	ll calculate(ll n, ll r) {
		vector<ll> dn = decompose(n);
		vector<ll> dr = decompose(r);

		int size = (int) dr.size();
		ll ret = 1;
		for (int i = 0; i < size; i++) {
			ret *= ncr(dn[i], dr[i]);
			ret %= m;
		}
		return ret;
	}
};

struct LucasAux {
	int m;
	vector<ll> mods;
	vector<Lucas> lucases;

	LucasAux(int m) : m(m) {
		if (primes.size() == 0) sieve(100000);
		vector<ii> pfactors = primeFactorialization(m);

		for (ii pfactor: pfactors) {
			if (pfactor.second > 1) throw;
			mods.push_back(pfactor.first);
			lucases.emplace_back(pfactor.first);
		}
	}

	ll calculate(ll n, ll r) {
		vector<ll> rems;
		for (Lucas lucas: lucases) {
			rems.push_back(lucas.calculate(n, r));
		}
		return chinese_remainder(mods, rems);
	}
};

int main() {
	sieve(100000);

	// Sanity test
	cout << "Sanity test, mod 1e9+7\n";
	Lucas lucas(1e9+7);
	cout << "C(8,2) = 56 ----> " << lucas.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 ----> " << lucas.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 ----> " << lucas.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 ----> " << lucas.calculate(3, 1) << '\n';

	// Real test
	cout << "Real test, mod 3\n";
	Lucas lucas2(3);
	cout << "C(8,2) = 56 % 3 = 1 ----> " << lucas2.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 % 3 = 2 ----> " << lucas2.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 % 3 = 1 ----> " << lucas2.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 % 3 = 0 ----> " << lucas2.calculate(3, 1) << '\n';

	// Real test
	cout << "Real test, mod 15\n";
	LucasAux lucasAux(15);
	cout << "C(8,2) = 56 % 15 = 11 ----> " << lucasAux.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 % 15 =  5 ----> " << lucasAux.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 % 15 =  1 ----> " << lucasAux.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 % 15 =  3 ----> " << lucasAux.calculate(3, 1) << '\n';
}
<commit_msg>Reformat<commit_after>#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int, int> ii;

bitset<100000> bs;
vector<ll> primes;

void sieve(ll sz) {
	bs[0] = bs[1] = 1;
	for (ll i = 2; i <= sz; i++) {
		if (!bs[i]) {
			for (ll j = i*i; j <= sz; j+=i) {
				bs[j] = 1;
			}
			primes.push_back(i);
		}
	}
}

ll fex(ll base, ll exp, ll mod = 1e18) {
	if (exp == 1) return base;
	if (exp == 0) return 1ll;
	ll ret = fex(base, exp / 2, mod);
	ret *= ret;
	ret %= mod;
	if (exp % 2) {
		ret *= base;
		ret %= mod;
	}
	return ret;
}

ll invmod(ll operand, ll mod) {
	return fex(operand, mod - 2, mod);
}

ll invmodEx(ll operand, ll mod) {
	ll b0 = mod, t, q;
	ll x0 = 0, x1 = 1;
	if (mod == 1) return 1;
	while (operand > 1) {
		q = operand / mod;
		t = mod, mod = operand % mod, operand = t;
		t = x0, x0 = x1 - q * x0, x1 = t;
	}
	if (x1 < 0) x1 += b0;
	return x1;
}

vector<ii> primeFactorialization(ll num) {
	vector<ii> ret;
	int p = 0;
	while (num > 1) {
		int cnt = 0;
		while (num % primes[p] == 0) {
			num /= primes[p];
			cnt++;
		}
		if (cnt) ret.emplace_back(primes[p], cnt);
		p++;
	}
	return ret;
}

ll chineseRemainder(vector<ll>& mods, vector<ll>& rems) {
	ll prod = 1, sum = 0;

	for (ll mod: mods) {
		prod *= mod;
	}
	for (int i = 0; i < (int) rems.size(); i++) {
		ll p = prod / mods[i];
		sum += rems[i] * invmodEx(p, mods[i]) * p;
	}

	return sum % prod;
}

struct Lucas {
	ll m, sz;
	vector<ll> fact, ifact;
	const static ll maxSz = 100000;

	inline int size(ll m) {
		return min(m + 1, 100000ll);
	}

	Lucas(ll m) : m(m), sz(size(m)), fact(sz), ifact(sz) {
		generateFact();
	}

	void generateFact() {
		fact[0] = ifact[0] = 1;
		for (int i = 1; i < sz; i++) {
			fact[i] = (fact[i-1] * i) % m;
			ifact[i] = invmod(fact[i], m);
		}
	}

	ll ncr(int n, int r) {
		if (r > n) {
			return 0;
		}
		return ((fact[n] * ifact[n-r]) % m * ifact[r]) % m;
	}

	vector<ll> decompose(ll num) {
		vector<ll> ret;
		while (num > 0) {
			ret.push_back(num % m);
			num /= m;
		}
		return ret;
	}

	ll calculate(ll n, ll r) {
		vector<ll> dn = decompose(n);
		vector<ll> dr = decompose(r);

		int size = (int) dr.size();
		ll ret = 1;
		for (int i = 0; i < size; i++) {
			ret *= ncr(dn[i], dr[i]);
			ret %= m;
		}
		return ret;
	}
};

struct LucasAux {
	int m;
	vector<ll> mods;
	vector<Lucas> lucases;

	LucasAux(int m) : m(m) {
		if (primes.size() == 0) sieve(100000);
		vector<ii> pfactors = primeFactorialization(m);

		for (ii pfactor: pfactors) {
			if (pfactor.second > 1) throw;
			mods.push_back(pfactor.first);
			lucases.emplace_back(pfactor.first);
		}
	}

	ll calculate(ll n, ll r) {
		vector<ll> rems;
		for (Lucas lucas: lucases) {
			rems.push_back(lucas.calculate(n, r));
		}
		return chineseRemainder(mods, rems);
	}
};

int main() {
	sieve(100000);

	// Sanity test
	cout << "Sanity test, mod 1e9+7\n";
	Lucas lucas(1e9+7);
	cout << "C(8,2) = 56 ----> " << lucas.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 ----> " << lucas.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 ----> " << lucas.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 ----> " << lucas.calculate(3, 1) << '\n';

	// Real test
	cout << "Real test, mod 3\n";
	Lucas lucas2(3);
	cout << "C(8,2) = 56 % 3 = 1 ----> " << lucas2.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 % 3 = 2 ----> " << lucas2.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 % 3 = 1 ----> " << lucas2.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 % 3 = 0 ----> " << lucas2.calculate(3, 1) << '\n';

	// Real test
	cout << "Real test, mod 15\n";
	LucasAux lucasAux(15);
	cout << "C(8,2) = 56 % 15 = 11 ----> " << lucasAux.calculate(8, 3) << '\n';
	cout << "C(6,3) = 20 % 15 =  5 ----> " << lucasAux.calculate(6, 3) << '\n';
	cout << "C(3,0) =  1 % 15 =  1 ----> " << lucasAux.calculate(3, 0) << '\n';
	cout << "C(3,1) =  3 % 15 =  3 ----> " << lucasAux.calculate(3, 1) << '\n';
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: ignoreTraditionalKana_ja_JP.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: rt $ $Date: 2003-04-08 16:04:32 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// prevent internal compiler error with MSVC6SP3
#include <stl/utility>

#define TRANSLITERATION_TraditionalKana_ja_JP
#include <transliteration_Ignore.hxx>

namespace com { namespace sun { namespace star { namespace i18n {

sal_Unicode
ignoreTraditionalKana_ja_JP_translator (const sal_Unicode c)
{

    switch (c) {
        case 0x3090:     // HIRAGANA LETTER WI
            return 0x3044; // HIRAGANA LETTER I

        case 0x3091:     // HIRAGANA LETTER WE
            return 0x3048; // HIRAGANA LETTER E

        case 0x30F0:     // KATAKANA LETTER WI
            return 0x30A4; // KATAKANA LETTER I

        case 0x30F1:     // KATAKANA LETTER WE
            return 0x30A8; // KATAKANA LETTER E
    }
    return c;
}

ignoreTraditionalKana_ja_JP::ignoreTraditionalKana_ja_JP()
{
        func = ignoreTraditionalKana_ja_JP_translator;
        table = 0;
        map = 0;
        transliterationName = "ignoreTraditionalKana_ja_JP";
        implementationName = "com.sun.star.i18n.Transliteration.ignoreTraditionalKana_ja_JP";
}

} } } }
<commit_msg>INTEGRATION: CWS ooo20030412 (1.2.44); FILE MERGED 2003/04/12 22:29:08 mh 1.2.44.2: RESYNC: (1.2-1.5); FILE MERGED 2003/04/11 11:38:41 mh 1.2.44.1: join: from ooo11beta<commit_after>/*************************************************************************
 *
 *  $RCSfile: ignoreTraditionalKana_ja_JP.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: hr $ $Date: 2003-04-28 16:52:49 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// prevent internal compiler error with MSVC6SP3
#include <utility>

#define TRANSLITERATION_TraditionalKana_ja_JP
#include <transliteration_Ignore.hxx>

namespace com { namespace sun { namespace star { namespace i18n {

sal_Unicode
ignoreTraditionalKana_ja_JP_translator (const sal_Unicode c)
{

    switch (c) {
        case 0x3090:     // HIRAGANA LETTER WI
            return 0x3044; // HIRAGANA LETTER I

        case 0x3091:     // HIRAGANA LETTER WE
            return 0x3048; // HIRAGANA LETTER E

        case 0x30F0:     // KATAKANA LETTER WI
            return 0x30A4; // KATAKANA LETTER I

        case 0x30F1:     // KATAKANA LETTER WE
            return 0x30A8; // KATAKANA LETTER E
    }
    return c;
}

ignoreTraditionalKana_ja_JP::ignoreTraditionalKana_ja_JP()
{
        func = ignoreTraditionalKana_ja_JP_translator;
        table = 0;
        map = 0;
        transliterationName = "ignoreTraditionalKana_ja_JP";
        implementationName = "com.sun.star.i18n.Transliteration.ignoreTraditionalKana_ja_JP";
}

} } } }
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUNCTOR_ALGEBRA_SOLVER_NEWTON_HPP
#define STAN_MATH_REV_FUNCTOR_ALGEBRA_SOLVER_NEWTON_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/functor/algebra_system.hpp>
#include <stan/math/rev/functor/kinsol_solve.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/eval.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/algebra_solver_adapter.hpp>
#include <unsupported/Eigen/NonLinearOptimization>
#include <iostream>
#include <string>
#include <vector>

namespace stan {
namespace math {

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * This overload handles non-autodiff parameters.
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 * @tparam Args types of additional parameters to the equation system functor
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @param[in] args Additional parameters to the equation system functor.
 * @return theta Vector of solutions to the system of equations.
 * @pre f returns finite values when passed any value of x and the given args.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T, typename... Args,
          require_eigen_vector_t<T>* = nullptr,
          require_all_st_arithmetic<Args...>* = nullptr>
Eigen::VectorXd algebra_solver_newton_impl(const F& f, const T& x,
                                           std::ostream* const msgs,
                                           const double scaling_step_size,
                                           const double function_tolerance,
                                           const int64_t max_num_steps,
                                           const Args&... args) {
  const auto& x_ref = to_ref(value_of(x));

  check_nonzero_size("algebra_solver_newton", "initial guess", x_ref);
  check_finite("algebra_solver_newton", "initial guess", x_ref);
  check_nonnegative("algebra_solver_newton", "scaling_step_size",
                    scaling_step_size);
  check_nonnegative("algebra_solver_newton", "function_tolerance",
                    function_tolerance);
  check_positive("algebra_solver_newton", "max_num_steps", max_num_steps);

  return kinsol_solve(f, x_ref, scaling_step_size, function_tolerance,
                      max_num_steps, 1, 10, KIN_LINESEARCH, msgs, args...);
}

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * This overload handles var parameters.
 *
 * The Jacobian \(J_{xy}\) (i.e., Jacobian of unknown \(x\) w.r.t. the parameter
 * \(y\)) is calculated given the solution as follows. Since
 * \[
 *   f(x, y) = 0,
 * \]
 * we have (\(J_{pq}\) being the Jacobian matrix \(\tfrac {dq} {dq}\))
 * \[
 *   - J_{fx} J_{xy} = J_{fy},
 * \]
 * and therefore \(J_{xy}\) can be solved from system
 * \[
 *  - J_{fx} J_{xy} = J_{fy}.
 * \]
 * Let \(eta\) be the adjoint with respect to \(x\); then to calculate
 * \[
 *   \eta J_{xy},
 * \]
 * we solve
 * \[
 *   - (\eta J_{fx}^{-1}) J_{fy}.
 * \]
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 * @tparam Args types of additional parameters to the equation system functor
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @param[in] args Additional parameters to the equation system functor.
 * @return theta Vector of solutions to the system of equations.
 * @pre f returns finite values when passed any value of x and the given args.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T, typename... T_Args,
          require_eigen_vector_t<T>* = nullptr,
          require_any_st_var<T_Args...>* = nullptr>
Eigen::Matrix<var, Eigen::Dynamic, 1> algebra_solver_newton_impl(
    const F& f, const T& x, std::ostream* const msgs,
    const double scaling_step_size, const double function_tolerance,
    const int64_t max_num_steps, const T_Args&... args) {
  const auto& x_ref = to_ref(value_of(x));
  auto arena_args_tuple = make_chainable_ptr(std::make_tuple(eval(args)...));
  auto args_vals_tuple = apply(
      [&](const auto&... args) {
        return std::make_tuple(to_ref(value_of(args))...);
      },
      *arena_args_tuple);

  check_nonzero_size("algebra_solver_newton", "initial guess", x_ref);
  check_finite("algebra_solver_newton", "initial guess", x_ref);
  check_nonnegative("algebra_solver_newton", "scaling_step_size",
                    scaling_step_size);
  check_nonnegative("algebra_solver_newton", "function_tolerance",
                    function_tolerance);
  check_positive("algebra_solver_newton", "max_num_steps", max_num_steps);

  // Solve the system
  Eigen::VectorXd theta_dbl = apply(
      [&](const auto&... vals) {
        return kinsol_solve(f, x_ref, scaling_step_size, function_tolerance,
                            max_num_steps, 1, 10, KIN_LINESEARCH, msgs,
                            vals...);
      },
      args_vals_tuple);

  auto f_wrt_x = [&](const auto& x) {
    return apply([&](const auto&... args) { return f(x, msgs, args...); },
                 args_vals_tuple);
  };

  Eigen::MatrixXd Jf_x;
  Eigen::VectorXd f_x;

  jacobian(f_wrt_x, theta_dbl, f_x, Jf_x);

  using ret_type = Eigen::Matrix<var, Eigen::Dynamic, -1>;
  arena_t<ret_type> ret = theta_dbl;
  auto Jf_x_T_lu_ptr
      = make_unsafe_chainable_ptr(Jf_x.transpose().partialPivLu());  // Lu

  reverse_pass_callback([f, ret, arena_args_tuple, Jf_x_T_lu_ptr,
                         msgs]() mutable {
    Eigen::VectorXd eta = -Jf_x_T_lu_ptr->solve(ret.adj().eval());

    // Contract with Jacobian of f with respect to y using a nested reverse
    // autodiff pass.
    {
      nested_rev_autodiff rev;

      Eigen::VectorXd ret_val = ret.val();
      auto x_nrad_ = apply(
          [&ret_val, &f, msgs](const auto&... args) { return eval(f(ret_val, msgs, args...)); },
          *arena_args_tuple);
      x_nrad_.adj() = eta;
      grad();
    }
  });

  return ret_type(ret);
}

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * Signature to maintain backward compatibility, will be removed
 * in the future.
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in] y Parameter vector for the equation system.
 * @param[in] dat Continuous data vector for the equation system.
 * @param[in] dat_int Integer data vector for the equation system.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @return theta Vector of solutions to the system of equations.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if y has non-finite elements.
 * @throw std::invalid_argument if dat has non-finite elements.
 * @throw std::invalid_argument if dat_int has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T1, typename T2,
          require_all_eigen_vector_t<T1, T2>* = nullptr>
Eigen::Matrix<scalar_type_t<T2>, Eigen::Dynamic, 1> algebra_solver_newton(
    const F& f, const T1& x, const T2& y, const std::vector<double>& dat,
    const std::vector<int>& dat_int, std::ostream* const msgs = nullptr,
    const double scaling_step_size = 1e-3,
    const double function_tolerance = 1e-6,
    const long int max_num_steps = 200) {  // NOLINT(runtime/int)
  return algebra_solver_newton_impl(algebra_solver_adapter<F>(f), x, msgs,
                                    scaling_step_size, function_tolerance,
                                    max_num_steps, y, dat, dat_int);
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_REV_FUNCTOR_ALGEBRA_SOLVER_NEWTON_HPP
#define STAN_MATH_REV_FUNCTOR_ALGEBRA_SOLVER_NEWTON_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/functor/algebra_system.hpp>
#include <stan/math/rev/functor/kinsol_solve.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/eval.hpp>
#include <stan/math/prim/fun/value_of.hpp>
#include <stan/math/prim/functor/algebra_solver_adapter.hpp>
#include <unsupported/Eigen/NonLinearOptimization>
#include <iostream>
#include <string>
#include <vector>

namespace stan {
namespace math {

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * This overload handles non-autodiff parameters.
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 * @tparam Args types of additional parameters to the equation system functor
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @param[in] args Additional parameters to the equation system functor.
 * @return theta Vector of solutions to the system of equations.
 * @pre f returns finite values when passed any value of x and the given args.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T, typename... Args,
          require_eigen_vector_t<T>* = nullptr,
          require_all_st_arithmetic<Args...>* = nullptr>
Eigen::VectorXd algebra_solver_newton_impl(const F& f, const T& x,
                                           std::ostream* const msgs,
                                           const double scaling_step_size,
                                           const double function_tolerance,
                                           const int64_t max_num_steps,
                                           const Args&... args) {
  const auto& x_ref = to_ref(value_of(x));

  check_nonzero_size("algebra_solver_newton", "initial guess", x_ref);
  check_finite("algebra_solver_newton", "initial guess", x_ref);
  check_nonnegative("algebra_solver_newton", "scaling_step_size",
                    scaling_step_size);
  check_nonnegative("algebra_solver_newton", "function_tolerance",
                    function_tolerance);
  check_positive("algebra_solver_newton", "max_num_steps", max_num_steps);

  return kinsol_solve(f, x_ref, scaling_step_size, function_tolerance,
                      max_num_steps, 1, 10, KIN_LINESEARCH, msgs, args...);
}

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * This overload handles var parameters.
 *
 * The Jacobian \(J_{xy}\) (i.e., Jacobian of unknown \(x\) w.r.t. the parameter
 * \(y\)) is calculated given the solution as follows. Since
 * \[
 *   f(x, y) = 0,
 * \]
 * we have (\(J_{pq}\) being the Jacobian matrix \(\tfrac {dq} {dq}\))
 * \[
 *   - J_{fx} J_{xy} = J_{fy},
 * \]
 * and therefore \(J_{xy}\) can be solved from system
 * \[
 *  - J_{fx} J_{xy} = J_{fy}.
 * \]
 * Let \(eta\) be the adjoint with respect to \(x\); then to calculate
 * \[
 *   \eta J_{xy},
 * \]
 * we solve
 * \[
 *   - (\eta J_{fx}^{-1}) J_{fy}.
 * \]
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 * @tparam Args types of additional parameters to the equation system functor
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @param[in] args Additional parameters to the equation system functor.
 * @return theta Vector of solutions to the system of equations.
 * @pre f returns finite values when passed any value of x and the given args.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T, typename... T_Args,
          require_eigen_vector_t<T>* = nullptr,
          require_any_st_var<T_Args...>* = nullptr>
Eigen::Matrix<var, Eigen::Dynamic, 1> algebra_solver_newton_impl(
    const F& f, const T& x, std::ostream* const msgs,
    const double scaling_step_size, const double function_tolerance,
    const int64_t max_num_steps, const T_Args&... args) {
  const auto& x_ref = to_ref(value_of(x));
  auto arena_args_tuple = make_chainable_ptr(std::make_tuple(eval(args)...));
  auto args_vals_tuple = apply(
      [&](const auto&... args) {
        return std::make_tuple(to_ref(value_of(args))...);
      },
      *arena_args_tuple);

  check_nonzero_size("algebra_solver_newton", "initial guess", x_ref);
  check_finite("algebra_solver_newton", "initial guess", x_ref);
  check_nonnegative("algebra_solver_newton", "scaling_step_size",
                    scaling_step_size);
  check_nonnegative("algebra_solver_newton", "function_tolerance",
                    function_tolerance);
  check_positive("algebra_solver_newton", "max_num_steps", max_num_steps);

  // Solve the system
  Eigen::VectorXd theta_dbl = apply(
      [&](const auto&... vals) {
        return kinsol_solve(f, x_ref, scaling_step_size, function_tolerance,
                            max_num_steps, 1, 10, KIN_LINESEARCH, msgs,
                            vals...);
      },
      args_vals_tuple);

  auto f_wrt_x = [&](const auto& x) {
    return apply([&](const auto&... args) { return f(x, msgs, args...); },
                 args_vals_tuple);
  };

  Eigen::MatrixXd Jf_x;
  Eigen::VectorXd f_x;

  jacobian(f_wrt_x, theta_dbl, f_x, Jf_x);

  using ret_type = Eigen::Matrix<var, Eigen::Dynamic, -1>;
  arena_t<ret_type> ret = theta_dbl;
  auto Jf_x_T_lu_ptr
      = make_unsafe_chainable_ptr(Jf_x.transpose().partialPivLu());  // Lu

  reverse_pass_callback(
      [f, ret, arena_args_tuple, Jf_x_T_lu_ptr, msgs]() mutable {
        Eigen::VectorXd eta = -Jf_x_T_lu_ptr->solve(ret.adj().eval());

        // Contract with Jacobian of f with respect to y using a nested reverse
        // autodiff pass.
        {
          nested_rev_autodiff rev;

          Eigen::VectorXd ret_val = ret.val();
          auto x_nrad_ = apply(
              [&ret_val, &f, msgs](const auto&... args) {
                return eval(f(ret_val, msgs, args...));
              },
              *arena_args_tuple);
          x_nrad_.adj() = eta;
          grad();
        }
      });

  return ret_type(ret);
}

/**
 * Return the solution to the specified system of algebraic
 * equations given an initial guess, and parameters and data,
 * which get passed into the algebraic system. Use the
 * KINSOL solver from the SUNDIALS suite.
 *
 * The user can also specify the scaled step size, the function
 * tolerance, and the maximum number of steps.
 *
 * Signature to maintain backward compatibility, will be removed
 * in the future.
 *
 * @tparam F type of equation system function.
 * @tparam T type of initial guess vector.
 *
 * @param[in] f Functor that evaluated the system of equations.
 * @param[in] x Vector of starting values.
 * @param[in] y Parameter vector for the equation system.
 * @param[in] dat Continuous data vector for the equation system.
 * @param[in] dat_int Integer data vector for the equation system.
 * @param[in, out] msgs The print stream for warning messages.
 * @param[in] scaling_step_size Scaled-step stopping tolerance. If
 *            a Newton step is smaller than the scaling step
 *            tolerance, the code breaks, assuming the solver is no
 *            longer making significant progress (i.e. is stuck)
 * @param[in] function_tolerance determines whether roots are acceptable.
 * @param[in] max_num_steps  maximum number of function evaluations.
 * @return theta Vector of solutions to the system of equations.
 * @throw std::invalid_argument if x has size zero.
 * @throw std::invalid_argument if x has non-finite elements.
 * @throw std::invalid_argument if y has non-finite elements.
 * @throw std::invalid_argument if dat has non-finite elements.
 * @throw std::invalid_argument if dat_int has non-finite elements.
 * @throw std::invalid_argument if scaled_step_size is strictly
 * negative.
 * @throw std::invalid_argument if function_tolerance is strictly
 * negative.
 * @throw std::invalid_argument if max_num_steps is not positive.
 * @throw std::domain_error if solver exceeds max_num_steps.
 */
template <typename F, typename T1, typename T2,
          require_all_eigen_vector_t<T1, T2>* = nullptr>
Eigen::Matrix<scalar_type_t<T2>, Eigen::Dynamic, 1> algebra_solver_newton(
    const F& f, const T1& x, const T2& y, const std::vector<double>& dat,
    const std::vector<int>& dat_int, std::ostream* const msgs = nullptr,
    const double scaling_step_size = 1e-3,
    const double function_tolerance = 1e-6,
    const long int max_num_steps = 200) {  // NOLINT(runtime/int)
  return algebra_solver_newton_impl(algebra_solver_adapter<F>(f), x, msgs,
                                    scaling_step_size, function_tolerance,
                                    max_num_steps, y, dat, dat_int);
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#include "IBLPass.h"
#include "Director.h"
#include "BindIndexInfo.h"
#include "ResourceManager.h"
#include "SkyBox.h"

using namespace Rendering::PostProcessing;
using namespace Rendering::Texture;
using namespace Rendering::Shader;
using namespace Rendering::Buffer;
using namespace Rendering::Camera;
using namespace Rendering::TBDR;
using namespace Rendering::Sky;
using namespace Device;
using namespace Resource;

IBLPass::IBLPass() : FullScreen()
{
}

IBLPass::~IBLPass()
{
}

void IBLPass::Initialize()
{
	std::vector<ShaderMacro> macros;
	macros.push_back(Director::SharedInstance()->GetDirectX()->GetMSAAShaderMacro());
	FullScreen::Initialize("IBLPass", "PS", &macros);

	const Texture2D* preIntegrateEnvBRDFMap = ResourceManager::SharedInstance()->GetPreIntegrateEnvBRDFMap();
	_inputTextures.push_back(ShaderForm::InputTexture(uint(TextureBindIndex::IBLPass_PreIntegrateEnvBRDFMap), preIntegrateEnvBRDFMap, false, false, false, true));
}

void IBLPass::Render(const Device::DirectX* dx, const RenderTexture* outResultRT, const MeshCamera* meshCam, const SkyForm* sky)
{
	ID3D11DeviceContext* context	= dx->GetContext();

	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Albedo_Occlusion,				meshCam->GetGBufferAlbedoOcclusion());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Emission_MaterialFlag,			meshCam->GetGBufferEmissionMaterialFlag());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_MotionXY_Metallic_Specularity,		meshCam->GetGBufferMotionXYMetallicSpecularity());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Normal_Roughness,				meshCam->GetGBufferNormalRoughness());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Depth,					meshCam->GetOpaqueDepthBuffer());
	PixelShader::BindTexture(context, TextureBindIndex::IBLPass_IlluminationMap,				meshCam->GetRenderTarget());

	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::TBRParam, meshCam->GetTBRParamConstBuffer());

	// Sky Cube Map
	if(sky)
	{
		const Texture2D* cubeMap = nullptr;

		if(sky->GetType() == SkyForm::Type::Box)
			cubeMap = dynamic_cast<const SkyBox*>(sky)->GetSkyCubeMap();
		else
			ASSERT_MSG("cant support");

		PixelShader::BindTexture(context, TextureBindIndex::AmbientCubeMap, cubeMap);
		PixelShader::BindConstBuffer(context, ConstBufferBindIndex::SkyMapInfoParam, sky->GetSkyMapInfoConstBuffer());
	}

	PixelShader::BindSamplerState(context, SamplerStateBindIndex::AmbientCubeMapSamplerState, dx->GetSamplerStateLinear());

	FullScreen::Render(dx, outResultRT);

	PixelShader::BindSamplerState(context, SamplerStateBindIndex::AmbientCubeMapSamplerState,	nullptr);
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::SkyMapInfoParam,			nullptr);
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::TBRParam,				nullptr);

	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Albedo_Occlusion,			nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Emission_MaterialFlag,		nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_MotionXY_Metallic_Specularity,	nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Normal_Roughness,			nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Depth,				nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::AmbientCubeMap,				nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::IBLPass_IlluminationMap,			nullptr);
}
<commit_msg>IBLPass.cpp - Render에서 CameraCB 바인드 하지 않던 문제 수정<commit_after>#include "IBLPass.h"
#include "Director.h"
#include "BindIndexInfo.h"
#include "ResourceManager.h"
#include "SkyBox.h"

using namespace Rendering::PostProcessing;
using namespace Rendering::Texture;
using namespace Rendering::Shader;
using namespace Rendering::Buffer;
using namespace Rendering::Camera;
using namespace Rendering::TBDR;
using namespace Rendering::Sky;
using namespace Device;
using namespace Resource;

IBLPass::IBLPass() : FullScreen()
{
}

IBLPass::~IBLPass()
{
}

void IBLPass::Initialize()
{
	std::vector<ShaderMacro> macros;
	macros.push_back(Director::SharedInstance()->GetDirectX()->GetMSAAShaderMacro());
	FullScreen::Initialize("IBLPass", "PS", &macros);

	const Texture2D* preIntegrateEnvBRDFMap = ResourceManager::SharedInstance()->GetPreIntegrateEnvBRDFMap();
	_inputTextures.push_back(ShaderForm::InputTexture(uint(TextureBindIndex::IBLPass_PreIntegrateEnvBRDFMap), preIntegrateEnvBRDFMap, false, false, false, true));
}

void IBLPass::Render(const Device::DirectX* dx, const RenderTexture* outResultRT, const MeshCamera* meshCam, const SkyForm* sky)
{
	ID3D11DeviceContext* context	= dx->GetContext();

	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Albedo_Occlusion,				meshCam->GetGBufferAlbedoOcclusion());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Emission_MaterialFlag,			meshCam->GetGBufferEmissionMaterialFlag());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_MotionXY_Metallic_Specularity,		meshCam->GetGBufferMotionXYMetallicSpecularity());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Normal_Roughness,				meshCam->GetGBufferNormalRoughness());
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Depth,					meshCam->GetOpaqueDepthBuffer());
	PixelShader::BindTexture(context, TextureBindIndex::IBLPass_IlluminationMap,				meshCam->GetRenderTarget());

	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::TBRParam, meshCam->GetTBRParamConstBuffer());
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::Camera, meshCam->GetCamConstBuffer());

	// Sky Cube Map
	if(sky)
	{
		const Texture2D* cubeMap = nullptr;

		if(sky->GetType() == SkyForm::Type::Box)
			cubeMap = dynamic_cast<const SkyBox*>(sky)->GetSkyCubeMap();
		else
			ASSERT_MSG("cant support");

		PixelShader::BindTexture(context, TextureBindIndex::AmbientCubeMap, cubeMap);
		PixelShader::BindConstBuffer(context, ConstBufferBindIndex::SkyMapInfoParam, sky->GetSkyMapInfoConstBuffer());
	}

	PixelShader::BindSamplerState(context, SamplerStateBindIndex::AmbientCubeMapSamplerState, dx->GetSamplerStateLinear());

	FullScreen::Render(dx, outResultRT);

	PixelShader::BindSamplerState(context, SamplerStateBindIndex::AmbientCubeMapSamplerState,	nullptr);
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::SkyMapInfoParam,			nullptr);
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::TBRParam,				nullptr);
	PixelShader::BindConstBuffer(context, ConstBufferBindIndex::Camera,				nullptr);

	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Albedo_Occlusion,			nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Emission_MaterialFlag,		nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_MotionXY_Metallic_Specularity,	nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Normal_Roughness,			nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::GBuffer_Depth,				nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::AmbientCubeMap,				nullptr);
	PixelShader::BindTexture(context, TextureBindIndex::IBLPass_IlluminationMap,			nullptr);
}
<|endoftext|>


<commit_before>// include log4cxx header files.
#include <log4cxx/logger.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/helpers/exception.h>

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

  // Basic configuration of the logger
  log4cxx::BasicConfigurator::configure();

  //char buffer[1024];

  log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("log4cxxTest") );
  logger->debug ( "This is a debug message" );
  logger->info ( "This is an info message" );
  logger->warn ( "This is a warn message" );
  logger->error ( "This is a error message" );
  exit ( 0 );
  return 0;
  }
<commit_msg>BUG: Changed exit(0) to return 0<commit_after>// include log4cxx header files.
#include <log4cxx/logger.h>
#include <log4cxx/basicconfigurator.h>
#include <log4cxx/helpers/exception.h>

int main ( int argc, char* argv[] )
  {
  // Basic configuration of the logger
  log4cxx::BasicConfigurator::configure();

  //char buffer[1024];

  log4cxx::LoggerPtr logger(log4cxx::Logger::getLogger("log4cxxTest") );
  logger->debug ( "This is a debug message" );
  logger->info ( "This is an info message" );
  logger->warn ( "This is a warn message" );
  logger->error ( "This is a error message" );
  return 0;
  }
<|endoftext|>


<commit_before>//
//  main.cpp
//  MusicPlayer
//
//  Created by Albert Zeyer on 06.02.14.
//  Copyright (c) 2014 Albert Zeyer. All rights reserved.
//

#include <Python.h>
#include <stdio.h>
#include <signal.h>

#include "sysutils.hpp"

#ifndef __APPLE__
#warning "No implementation of AmIBeingDebugged()"
bool AmIBeingDebugged() { return false; }
#endif

bool logEnabled = false;
std::string logFilename = "~/Library/Logs/com.albertzeyer.MusicPlayer.log";

bool forkExecProc = false;

static void addPyPath() {
	std::string path = getResourcePath() + "/Python:" + Py_GetPath();
	PySys_SetPath((char*)path.c_str());
	if(!forkExecProc)
		printf("Python path: %s\n", path.c_str());
}

static int sys_argc;
static char** sys_argv;

static bool haveArg(const char* arg) {
	for(int i = 1; i < sys_argc; ++i)
		if(strcmp(sys_argv[i], arg) == 0) {
			return true;
		}
	return false;
}

static bool checkStartupSuccess() {
	PyObject* mods = PyImport_GetModuleDict();
	if(!mods) return false;
	PyObject* m = PyDict_GetItemString(mods, "main");
	if(!m) return false;

	PyObject* successObj = PyObject_GetAttrString(m, "successStartup");
	bool success = false;
	if(successObj)
		success = PyObject_IsTrue(successObj);

	Py_XDECREF(successObj);
	mods = NULL; // borrowed
	m = NULL; // borrowed

	return success;
}

void signal_handler(int sig) {
	handleFatalError("There was a fatal error.");
}

void install_signal_handler() {
	signal(SIGABRT, signal_handler);
	signal(SIGBUS, signal_handler);
	signal(SIGSEGV, signal_handler);
	signal(SIGFPE, signal_handler);
	signal(SIGILL, signal_handler);
}

#ifdef __APPLE__
const char* StartupStr = "Hello from MusicPlayer on MacOSX.\n";
#else
const char* StartupStr = "Hello from MusicPlayer.\n";
#endif

int main(int argc, char *argv[])
{
	sys_argc = argc;
	sys_argv = argv;

	forkExecProc = haveArg("--forkExecProc");
	bool shell = haveArg("--shell");
	bool pyShell = haveArg("--pyshell");
	bool pyExec = haveArg("--pyexec");
	bool noLog = haveArg("--nolog");
	bool help = haveArg("--help") || haveArg("-h");
	bool beingDebugged = AmIBeingDebugged();

	const char* logDisabledReason = NULL;
	if(pyShell || pyExec || shell || forkExecProc || help) {} // be quiet
	else if(beingDebugged) {
		logDisabledReason = "debugger detected, not redirecting stdout/stderr";
	}
	else if(noLog) {
		logDisabledReason = "not redirecting stdout/stderr";
	}
	else {
		// current workaround to log stdout/stderr. see http://stackoverflow.com/questions/13104588/how-to-get-stdout-into-console-app
		logEnabled = true;
		printf("MusicPlayer: stdout/stderr goes to %s now\n", logFilename.c_str());
		fflush(stdout);
		int newFd = open(logFilename.c_str(), O_WRONLY|O_APPEND|O_CREAT);
		dup2(newFd, fileno(stdout));
		dup2(newFd, fileno(stderr));
		close(newFd);
		//freopen(logFilename.c_str(), "a", stdout);
		//freopen(logFilename.c_str(), "a", stderr);
		stderr = stdout; // well, hack, ... I don't like two seperate buffers. just messes up the output
	}

	if(!forkExecProc) {
		printf("%s", StartupStr);
		install_signal_handler();
	}

	if(help) {
		printf(
			   "Help: Available options:\n"
			   "  --nolog		: don't redirect stdout/stderr to log. also implied when run in debugger\n"
			   );
	}

	if(!logEnabled && logDisabledReason)
		printf("%s\n", logDisabledReason);

	std::string mainPyFilename = getResourcePath() + "/Python/main.py";
	Py_SetProgramName(argv[0]);
	if(!forkExecProc)
		printf("Python version: %s, prefix: %s, main: %s\n", Py_GetVersion(), Py_GetPrefix(), mainPyFilename.c_str());

	Py_Initialize();
	PyEval_InitThreads();
	addPyPath();

	if(logEnabled) {
		PySys_SetObject("stdout", PyFile_FromFile(stdout, "<stdout>", "w", fclose));
		PySys_SetObject("stderr", PySys_GetObject("stdout"));
	}

	// Preload imp and thread. I hope to fix this bug: https://github.com/albertz/music-player/issues/8 , there was a crash in initthread which itself has called initimp
	PyObject* m = NULL;
	m = PyImport_ImportModule("imp");
	Py_XDECREF(m);
	m = PyImport_ImportModule("thread");
	Py_XDECREF(m);

	PySys_SetArgvEx(argc, argv, 0);

	FILE* fp = fopen((char*)mainPyFilename.c_str(), "r");
	assert(fp);
	PyRun_SimpleFile(fp, "main.py");

	if(!forkExecProc && !help && !pyShell && !pyExec && !shell) {
		bool successStartup = checkStartupSuccess();
		if(!successStartup) {
			printf("Error at startup.\n");
			handleFatalError("There was an error at startup.");
		}
	}

	return 0;
}
<commit_msg>main.cpp<commit_after>//
//  main.cpp
//  MusicPlayer
//
//  Created by Albert Zeyer on 06.02.14.
//  Copyright (c) 2014 Albert Zeyer. All rights reserved.
//

#include <Python.h>
#include <stdio.h>
#include <signal.h>

#include "sysutils.hpp"

#ifndef __APPLE__
#warning "No implementation of AmIBeingDebugged()"
bool AmIBeingDebugged() { return false; }
#endif

bool logEnabled = false;
#ifdef __APPLE__
std::string logFilename = "~/Library/Logs/com.albertzeyer.MusicPlayer.log";
#else
std::string logFilename = "~/.com.albertzeyer.MusicPlayer/musicplayer.log";
#endif

bool forkExecProc = false;

static void addPyPath() {
	std::string path = getResourcePath() + "/Python:" + Py_GetPath();
	PySys_SetPath((char*)path.c_str());
	if(!forkExecProc)
		printf("Python path: %s\n", path.c_str());
}

static int sys_argc;
static char** sys_argv;

static bool haveArg(const char* arg) {
	for(int i = 1; i < sys_argc; ++i)
		if(strcmp(sys_argv[i], arg) == 0) {
			return true;
		}
	return false;
}

static bool checkStartupSuccess() {
	PyObject* mods = PyImport_GetModuleDict();
	if(!mods) return false;
	PyObject* m = PyDict_GetItemString(mods, "main");
	if(!m) return false;

	PyObject* successObj = PyObject_GetAttrString(m, "successStartup");
	bool success = false;
	if(successObj)
		success = PyObject_IsTrue(successObj);

	Py_XDECREF(successObj);
	mods = NULL; // borrowed
	m = NULL; // borrowed

	return success;
}

void signal_handler(int sig) {
	handleFatalError("There was a fatal error.");
}

void install_signal_handler() {
	signal(SIGABRT, signal_handler);
	signal(SIGBUS, signal_handler);
	signal(SIGSEGV, signal_handler);
	signal(SIGFPE, signal_handler);
	signal(SIGILL, signal_handler);
}

#ifdef __APPLE__
const char* StartupStr = "Hello from MusicPlayer on MacOSX.\n";
#else
const char* StartupStr = "Hello from MusicPlayer.\n";
#endif

int main(int argc, char *argv[])
{
	sys_argc = argc;
	sys_argv = argv;

	forkExecProc = haveArg("--forkExecProc");
	bool shell = haveArg("--shell");
	bool pyShell = haveArg("--pyshell");
	bool pyExec = haveArg("--pyexec");
	bool noLog = haveArg("--nolog");
	bool help = haveArg("--help") || haveArg("-h");
	bool beingDebugged = AmIBeingDebugged();

	const char* logDisabledReason = NULL;
	if(pyShell || pyExec || shell || forkExecProc || help) {} // be quiet
	else if(beingDebugged) {
		logDisabledReason = "debugger detected, not redirecting stdout/stderr";
	}
	else if(noLog) {
		logDisabledReason = "not redirecting stdout/stderr";
	}
	else {
		// current workaround to log stdout/stderr. see http://stackoverflow.com/questions/13104588/how-to-get-stdout-into-console-app
		logEnabled = true;
		printf("MusicPlayer: stdout/stderr goes to %s now\n", logFilename.c_str());
		fflush(stdout);
		int newFd = open(logFilename.c_str(), O_WRONLY|O_APPEND|O_CREAT);
		dup2(newFd, fileno(stdout));
		dup2(newFd, fileno(stderr));
		close(newFd);
		//freopen(logFilename.c_str(), "a", stdout);
		//freopen(logFilename.c_str(), "a", stderr);
		stderr = stdout; // well, hack, ... I don't like two seperate buffers. just messes up the output
	}

	if(!forkExecProc) {
		printf("%s", StartupStr);
		install_signal_handler();
	}

	if(help) {
		printf(
			   "Help: Available options:\n"
			   "  --nolog		: don't redirect stdout/stderr to log. also implied when run in debugger\n"
			   );
	}

	if(!logEnabled && logDisabledReason)
		printf("%s\n", logDisabledReason);

	std::string mainPyFilename = getResourcePath() + "/Python/main.py";
	Py_SetProgramName(argv[0]);
	if(!forkExecProc)
		printf("Python version: %s, prefix: %s, main: %s\n", Py_GetVersion(), Py_GetPrefix(), mainPyFilename.c_str());

	Py_Initialize();
	PyEval_InitThreads();
	addPyPath();

	if(logEnabled) {
		PySys_SetObject("stdout", PyFile_FromFile(stdout, "<stdout>", "w", fclose));
		PySys_SetObject("stderr", PySys_GetObject("stdout"));
	}

	// Preload imp and thread. I hope to fix this bug: https://github.com/albertz/music-player/issues/8 , there was a crash in initthread which itself has called initimp
	PyObject* m = NULL;
	m = PyImport_ImportModule("imp");
	Py_XDECREF(m);
	m = PyImport_ImportModule("thread");
	Py_XDECREF(m);

	PySys_SetArgvEx(argc, argv, 0);

	FILE* fp = fopen((char*)mainPyFilename.c_str(), "r");
	assert(fp);
	PyRun_SimpleFile(fp, "main.py");

	if(!forkExecProc && !help && !pyShell && !pyExec && !shell) {
		bool successStartup = checkStartupSuccess();
		if(!successStartup) {
			printf("Error at startup.\n");
			handleFatalError("There was an error at startup.");
		}
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */
#ifndef _APP_TEMPLATE_HH
#define _APP_TEMPLATE_HH

#include <boost/program_options.hpp>
#include <fstream>
#include <cstdlib>
#include "core/reactor.hh"

namespace bpo = boost::program_options;

class app_template {
private:
    bpo::options_description _opts;
    boost::optional<bpo::variables_map> _configuration;
public:
    app_template() {
        _opts.add_options()
                ("help", "show help message")
                ;
        _opts.add(reactor::get_options_description());
        _opts.add(smp::get_options_description());
    };

    boost::program_options::options_description_easy_init add_options() {
        return _opts.add_options();
    }

    bpo::variables_map& configuration() { return *_configuration; }

    template<typename Func>
    int run(int ac, char ** av, Func&& func) {
        bpo::variables_map configuration;
        bpo::store(bpo::command_line_parser(ac, av).options(_opts).run(), configuration);
        auto home = std::getenv("HOME");
        if (home) {
            std::ifstream ifs(std::string(home) + "/.config/seastar/seastar.conf");
            if (ifs) {
                bpo::store(bpo::parse_config_file(ifs, _opts), configuration);
            }
        }
        bpo::notify(configuration);
        if (configuration.count("help")) {
            std::cout << _opts << "\n";
            return 1;
        }
        smp::configure(configuration);
        _configuration = {std::move(configuration)};
        engine.when_started().then(func).rescue([] (auto get_ex) {
            try {
                get_ex();
            } catch (std::exception& ex) {
                std::cout << "program failed with uncaught exception: " << ex.what() << "\n";
            engine.exit(1);
            }
            });
        return engine.run();
    };
};

#endif
<commit_msg>core: fix formatting<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 */
#ifndef _APP_TEMPLATE_HH
#define _APP_TEMPLATE_HH

#include <boost/program_options.hpp>
#include <fstream>
#include <cstdlib>
#include "core/reactor.hh"

namespace bpo = boost::program_options;

class app_template {
private:
    bpo::options_description _opts;
    boost::optional<bpo::variables_map> _configuration;
public:
    app_template() {
        _opts.add_options()
                ("help", "show help message")
                ;
        _opts.add(reactor::get_options_description());
        _opts.add(smp::get_options_description());
    };

    boost::program_options::options_description_easy_init add_options() {
        return _opts.add_options();
    }

    bpo::variables_map& configuration() { return *_configuration; }

    template<typename Func>
    int run(int ac, char ** av, Func&& func) {
        bpo::variables_map configuration;
        bpo::store(bpo::command_line_parser(ac, av).options(_opts).run(), configuration);
        auto home = std::getenv("HOME");
        if (home) {
            std::ifstream ifs(std::string(home) + "/.config/seastar/seastar.conf");
            if (ifs) {
                bpo::store(bpo::parse_config_file(ifs, _opts), configuration);
            }
        }
        bpo::notify(configuration);
        if (configuration.count("help")) {
            std::cout << _opts << "\n";
            return 1;
        }
        smp::configure(configuration);
        _configuration = {std::move(configuration)};
        engine.when_started().then(func).rescue([] (auto get_ex) {
            try {
                get_ex();
            } catch (std::exception& ex) {
                std::cout << "program failed with uncaught exception: " << ex.what() << "\n";
                engine.exit(1);
            }
        });
        return engine.run();
    };
};

#endif
<|endoftext|>


<commit_before>/*
#include "gtec-gmobilabplus/src/ovasCDriverGTecGMobiLabPlus.h"
#include "openeeg-modulareeg/src/ovasCDriverOpenEEGModularEEG.h"
#include "field-trip-protocol/src/ovasCDriverFieldtrip.h"
#include "brainproducts-brainvisionrecorder/src/ovasCDriverBrainProductsBrainVisionRecorder.h"
#include "egi-ampserver/src/ovasCDriverEGIAmpServer.h"
*/

#include "ovasCPluginExternalStimulations.h"

#include "ovasCDriverGTecGUSBamp.h"
#include "ovasCDriverCtfVsmMeg.h"
#include "ovasCDriverBrainProductsBrainVisionRecorder.h"
#include "ovasCDriverMitsarEEG202A.h"

namespace OpenViBEContributions {

	void initiateContributions(OpenViBEAcquisitionServer::CAcquisitionServerGUI* pGUI, OpenViBEAcquisitionServer::CAcquisitionServer* pAcquisitionServer, const OpenViBE::Kernel::IKernelContext& rKernelContext, std::vector<OpenViBEAcquisitionServer::IDriver*>* vDriver)
	{
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverCtfVsmMeg(pAcquisitionServer->getDriverContext()));
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverBrainProductsBrainVisionRecorder(pAcquisitionServer->getDriverContext()));
#if defined TARGET_HAS_ThirdPartyGUSBampCAPI
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverGTecGUSBamp(pAcquisitionServer->getDriverContext()));
#endif
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverMitsarEEG202A(pAcquisitionServer->getDriverContext()));

		pGUI->registerPlugin(new OpenViBEAcquisitionServer::OpenViBEAcquisitionServerPlugins::CPluginExternalStimulations(rKernelContext));
	}

}
<commit_msg>contrib/common: * fixed problem with MITSAR on linux<commit_after>/*
#include "gtec-gmobilabplus/src/ovasCDriverGTecGMobiLabPlus.h"
#include "openeeg-modulareeg/src/ovasCDriverOpenEEGModularEEG.h"
#include "field-trip-protocol/src/ovasCDriverFieldtrip.h"
#include "brainproducts-brainvisionrecorder/src/ovasCDriverBrainProductsBrainVisionRecorder.h"
#include "egi-ampserver/src/ovasCDriverEGIAmpServer.h"
*/

#include "ovasCPluginExternalStimulations.h"

#include "ovasCDriverGTecGUSBamp.h"
#include "ovasCDriverCtfVsmMeg.h"
#include "ovasCDriverBrainProductsBrainVisionRecorder.h"
#include "ovasCDriverMitsarEEG202A.h"

namespace OpenViBEContributions {

	void initiateContributions(OpenViBEAcquisitionServer::CAcquisitionServerGUI* pGUI, OpenViBEAcquisitionServer::CAcquisitionServer* pAcquisitionServer, const OpenViBE::Kernel::IKernelContext& rKernelContext, std::vector<OpenViBEAcquisitionServer::IDriver*>* vDriver)
	{
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverCtfVsmMeg(pAcquisitionServer->getDriverContext()));
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverBrainProductsBrainVisionRecorder(pAcquisitionServer->getDriverContext()));
#if defined TARGET_HAS_ThirdPartyGUSBampCAPI
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverGTecGUSBamp(pAcquisitionServer->getDriverContext()));
#endif
#if defined TARGET_OS_Windows
		vDriver->push_back(new OpenViBEAcquisitionServer::CDriverMitsarEEG202A(pAcquisitionServer->getDriverContext()));
#endif

		pGUI->registerPlugin(new OpenViBEAcquisitionServer::OpenViBEAcquisitionServerPlugins::CPluginExternalStimulations(rKernelContext));
	}

}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED
#define CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED

#include <cppcoro/generator.hpp>

#include <experimental/coroutine>
#include <type_traits>
#include <utility>
#include <cassert>
#include <functional>

namespace cppcoro
{
	template<typename T>
	class recursive_generator
	{
	public:

		class promise_type final
		{
		public:

			promise_type() noexcept
				: m_value(nullptr)
				, m_exception(nullptr)
				, m_root(this)
				, m_parentOrLeaf(this)
			{}

			promise_type(const promise_type&) = delete;
			promise_type(promise_type&&) = delete;

			auto get_return_object() noexcept
			{
				return recursive_generator<T>{ *this };
			}

			std::experimental::suspend_always initial_suspend() noexcept
			{
				return {};
			}

			std::experimental::suspend_always final_suspend() noexcept
			{
				return {};
			}

			void unhandled_exception() noexcept
			{
				m_exception = std::current_exception();
			}

			void return_void() noexcept {}

			std::experimental::suspend_always yield_value(T& value) noexcept
			{
				m_value = std::addressof(value);
				return {};
			}

			std::experimental::suspend_always yield_value(T&& value) noexcept
			{
				m_value = std::addressof(value);
				return {};
			}

			auto yield_value(recursive_generator&& generator) noexcept
			{
				return yield_value(generator);
			}

			auto yield_value(recursive_generator& generator) noexcept
			{
				struct awaitable
				{

					awaitable(promise_type* childPromise)
						: m_childPromise(childPromise)
					{}

					bool await_ready() noexcept
					{
						return this->m_childPromise == nullptr;
					}

					void await_suspend(std::experimental::coroutine_handle<promise_type>) noexcept
					{}

					void await_resume()
					{
						if (this->m_childPromise != nullptr)
						{
							this->m_childPromise->throw_if_exception();
						}
					}

				private:
					promise_type* m_childPromise;
				};

				if (generator.m_promise != nullptr)
				{
					m_root->m_parentOrLeaf = generator.m_promise;
					generator.m_promise->m_root = m_root;
					generator.m_promise->m_parentOrLeaf = this;
					generator.m_promise->resume();

					if (!generator.m_promise->is_complete())
					{
						return awaitable{ generator.m_promise };
					}

					m_root->m_parentOrLeaf = this;
				}

				return awaitable{ nullptr };
			}

			// Don't allow any use of 'co_await' inside the recursive_generator coroutine.
			template<typename U>
			std::experimental::suspend_never await_transform(U&& value) = delete;

			void destroy() noexcept
			{
				std::experimental::coroutine_handle<promise_type>::from_promise(*this).destroy();
			}

			void throw_if_exception()
			{
				if (m_exception != nullptr)
				{
					std::rethrow_exception(std::move(m_exception));
				}
			}

			bool is_complete() noexcept
			{
				return std::experimental::coroutine_handle<promise_type>::from_promise(*this).done();
			}

			T& value() noexcept
			{
				assert(this == m_root);
				assert(!is_complete());
				return *(m_parentOrLeaf->m_value);
			}

			void pull() noexcept
			{
				assert(this == m_root);
				assert(!m_parentOrLeaf->is_complete());

				m_parentOrLeaf->resume();

				while (m_parentOrLeaf != this && m_parentOrLeaf->is_complete())
				{
					m_parentOrLeaf = m_parentOrLeaf->m_parentOrLeaf;
					m_parentOrLeaf->resume();
				}
			}

		private:

			void resume() noexcept
			{
				std::experimental::coroutine_handle<promise_type>::from_promise(*this).resume();
			}

			T* m_value;
			std::exception_ptr m_exception;

			promise_type* m_root;

			// If this is the promise of the root generator then this field
			// is a pointer to the leaf promise.
			// For non-root generators this is a pointer to the parent promise.
			promise_type* m_parentOrLeaf;

		};

		recursive_generator() noexcept
			: m_promise(nullptr)
		{}

		recursive_generator(promise_type& promise) noexcept
			: m_promise(&promise)
		{}

		recursive_generator(recursive_generator&& other) noexcept
			: m_promise(other.m_promise)
		{
			other.m_promise = nullptr;
		}

		recursive_generator(const recursive_generator& other) = delete;
		recursive_generator& operator=(const recursive_generator& other) = delete;

		~recursive_generator()
		{
			if (m_promise != nullptr)
			{
				m_promise->destroy();
			}
		}

		recursive_generator& operator=(recursive_generator&& other) noexcept
		{
			if (this != &other)
			{
				if (m_promise != nullptr)
				{
					m_promise->destroy();
				}

				m_promise = other.m_promise;
				other.m_promise = nullptr;
			}

			return *this;
		}

		class iterator
		{
		public:

			using iterator_category = std::input_iterator_tag;
			// What type should we use for counting elements of a potentially infinite sequence?
			using difference_type = std::size_t;
			using value_type = std::remove_reference_t<T>;
			using reference = value_type&;
			using pointer = value_type*;

			iterator(promise_type* promise) noexcept
				: m_promise(promise)
			{}

			bool operator==(const iterator& other) const noexcept
			{
				return m_promise == other.m_promise;
			}

			bool operator!=(const iterator& other) const noexcept
			{
				return m_promise != other.m_promise;
			}

			iterator& operator++()
			{
				assert(m_promise != nullptr);
				assert(!m_promise->is_complete());

				m_promise->pull();
				if (m_promise->is_complete())
				{
					auto* temp = m_promise;
					m_promise = nullptr;
					temp->throw_if_exception();
				}

				return *this;
			}

			reference operator*() const noexcept
			{
				assert(m_promise != nullptr);
				return m_promise->value();
			}

			pointer operator->() const noexcept
			{
				return std::addressof(operator*());
			}

		private:

			promise_type* m_promise;

		};

		iterator begin()
		{
			if (m_promise != nullptr)
			{
				m_promise->pull();
				if (!m_promise->is_complete())
				{
					return iterator(m_promise);
				}

				m_promise->throw_if_exception();
			}

			return iterator(nullptr);
		}

		iterator end() noexcept
		{
			return iterator(nullptr);
		}

		void swap(recursive_generator& other) noexcept
		{
			std::swap(m_promise, other.m_promise);
		}

	private:

		friend class promise_type;

		promise_type* m_promise;

	};

	template<typename T>
	void swap(recursive_generator<T>& a, recursive_generator<T>& b) noexcept
	{
		a.swap(b);
	}

	// Note: When applying fmap operator to a recursive_generator we just yield a non-recursive
	// generator since we generally won't be using the result in a recursive context.
	template<typename FUNC, typename T>
	generator<std::invoke_result_t<FUNC&, typename recursive_generator<T>::iterator::reference>> fmap(FUNC func, recursive_generator<T> source)
	{
		for (auto&& value : source)
		{
			co_yield std::invoke(func, static_cast<decltype(value)>(value));
		}
	}
}

#endif
<commit_msg>Make recursive_generator<T> satisfy the Range concept.<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED
#define CPPCORO_RECURSIVE_GENERATOR_HPP_INCLUDED

#include <cppcoro/generator.hpp>

#include <experimental/coroutine>
#include <type_traits>
#include <utility>
#include <cassert>
#include <functional>

namespace cppcoro
{
	template<typename T>
	class recursive_generator
	{
	public:

		class promise_type final
		{
		public:

			promise_type() noexcept
				: m_value(nullptr)
				, m_exception(nullptr)
				, m_root(this)
				, m_parentOrLeaf(this)
			{}

			promise_type(const promise_type&) = delete;
			promise_type(promise_type&&) = delete;

			auto get_return_object() noexcept
			{
				return recursive_generator<T>{ *this };
			}

			std::experimental::suspend_always initial_suspend() noexcept
			{
				return {};
			}

			std::experimental::suspend_always final_suspend() noexcept
			{
				return {};
			}

			void unhandled_exception() noexcept
			{
				m_exception = std::current_exception();
			}

			void return_void() noexcept {}

			std::experimental::suspend_always yield_value(T& value) noexcept
			{
				m_value = std::addressof(value);
				return {};
			}

			std::experimental::suspend_always yield_value(T&& value) noexcept
			{
				m_value = std::addressof(value);
				return {};
			}

			auto yield_value(recursive_generator&& generator) noexcept
			{
				return yield_value(generator);
			}

			auto yield_value(recursive_generator& generator) noexcept
			{
				struct awaitable
				{

					awaitable(promise_type* childPromise)
						: m_childPromise(childPromise)
					{}

					bool await_ready() noexcept
					{
						return this->m_childPromise == nullptr;
					}

					void await_suspend(std::experimental::coroutine_handle<promise_type>) noexcept
					{}

					void await_resume()
					{
						if (this->m_childPromise != nullptr)
						{
							this->m_childPromise->throw_if_exception();
						}
					}

				private:
					promise_type* m_childPromise;
				};

				if (generator.m_promise != nullptr)
				{
					m_root->m_parentOrLeaf = generator.m_promise;
					generator.m_promise->m_root = m_root;
					generator.m_promise->m_parentOrLeaf = this;
					generator.m_promise->resume();

					if (!generator.m_promise->is_complete())
					{
						return awaitable{ generator.m_promise };
					}

					m_root->m_parentOrLeaf = this;
				}

				return awaitable{ nullptr };
			}

			// Don't allow any use of 'co_await' inside the recursive_generator coroutine.
			template<typename U>
			std::experimental::suspend_never await_transform(U&& value) = delete;

			void destroy() noexcept
			{
				std::experimental::coroutine_handle<promise_type>::from_promise(*this).destroy();
			}

			void throw_if_exception()
			{
				if (m_exception != nullptr)
				{
					std::rethrow_exception(std::move(m_exception));
				}
			}

			bool is_complete() noexcept
			{
				return std::experimental::coroutine_handle<promise_type>::from_promise(*this).done();
			}

			T& value() noexcept
			{
				assert(this == m_root);
				assert(!is_complete());
				return *(m_parentOrLeaf->m_value);
			}

			void pull() noexcept
			{
				assert(this == m_root);
				assert(!m_parentOrLeaf->is_complete());

				m_parentOrLeaf->resume();

				while (m_parentOrLeaf != this && m_parentOrLeaf->is_complete())
				{
					m_parentOrLeaf = m_parentOrLeaf->m_parentOrLeaf;
					m_parentOrLeaf->resume();
				}
			}

		private:

			void resume() noexcept
			{
				std::experimental::coroutine_handle<promise_type>::from_promise(*this).resume();
			}

			std::add_pointer_t<T> m_value;
			std::exception_ptr m_exception;

			promise_type* m_root;

			// If this is the promise of the root generator then this field
			// is a pointer to the leaf promise.
			// For non-root generators this is a pointer to the parent promise.
			promise_type* m_parentOrLeaf;

		};

		recursive_generator() noexcept
			: m_promise(nullptr)
		{}

		recursive_generator(promise_type& promise) noexcept
			: m_promise(&promise)
		{}

		recursive_generator(recursive_generator&& other) noexcept
			: m_promise(other.m_promise)
		{
			other.m_promise = nullptr;
		}

		recursive_generator(const recursive_generator& other) = delete;
		recursive_generator& operator=(const recursive_generator& other) = delete;

		~recursive_generator()
		{
			if (m_promise != nullptr)
			{
				m_promise->destroy();
			}
		}

		recursive_generator& operator=(recursive_generator&& other) noexcept
		{
			if (this != &other)
			{
				if (m_promise != nullptr)
				{
					m_promise->destroy();
				}

				m_promise = other.m_promise;
				other.m_promise = nullptr;
			}

			return *this;
		}

		class iterator
		{
		public:

			using iterator_category = std::input_iterator_tag;
			// What type should we use for counting elements of a potentially infinite sequence?
			using difference_type = std::ptrdiff_t;
			using value_type = std::remove_reference_t<T>;
			using reference = std::conditional_t<std::is_reference_v<T>, T, T&>;
			using pointer = std::add_pointer_t<T>;

			iterator() noexcept
				: m_promise(nullptr)
			{}

			explicit iterator(promise_type* promise) noexcept
				: m_promise(promise)
			{}

			bool operator==(const iterator& other) const noexcept
			{
				return m_promise == other.m_promise;
			}

			bool operator!=(const iterator& other) const noexcept
			{
				return m_promise != other.m_promise;
			}

			iterator& operator++()
			{
				assert(m_promise != nullptr);
				assert(!m_promise->is_complete());

				m_promise->pull();
				if (m_promise->is_complete())
				{
					auto* temp = m_promise;
					m_promise = nullptr;
					temp->throw_if_exception();
				}

				return *this;
			}

			void operator++(int)
			{
				(void)operator++();
			}

			reference operator*() const noexcept
			{
				assert(m_promise != nullptr);
				return static_cast<reference>(m_promise->value());
			}

			pointer operator->() const noexcept
			{
				return std::addressof(operator*());
			}

		private:

			promise_type* m_promise;

		};

		iterator begin()
		{
			if (m_promise != nullptr)
			{
				m_promise->pull();
				if (!m_promise->is_complete())
				{
					return iterator(m_promise);
				}

				m_promise->throw_if_exception();
			}

			return iterator(nullptr);
		}

		iterator end() noexcept
		{
			return iterator(nullptr);
		}

		void swap(recursive_generator& other) noexcept
		{
			std::swap(m_promise, other.m_promise);
		}

	private:

		friend class promise_type;

		promise_type* m_promise;

	};

	template<typename T>
	void swap(recursive_generator<T>& a, recursive_generator<T>& b) noexcept
	{
		a.swap(b);
	}

	// Note: When applying fmap operator to a recursive_generator we just yield a non-recursive
	// generator since we generally won't be using the result in a recursive context.
	template<typename FUNC, typename T>
	generator<std::invoke_result_t<FUNC&, typename recursive_generator<T>::iterator::reference>> fmap(FUNC func, recursive_generator<T> source)
	{
		for (auto&& value : source)
		{
			co_yield std::invoke(func, static_cast<decltype(value)>(value));
		}
	}
}

#endif
<|endoftext|>


<commit_before>#include "device_impl.h"
#include "global_include.h"
#include "dronelink_impl.h"
#include "mavlink_include.h"
#include <functional>

namespace dronelink {

using namespace std::placeholders; // for `_1`

DeviceImpl::DeviceImpl(DroneLinkImpl *parent,
                       uint8_t target_system_id,
                       uint8_t target_component_id) :
    _target_system_id(target_system_id),
    _target_component_id(target_component_id),
    _parent(parent),
    _params(this),
    _commands(this)
{
    _device_thread = new std::thread(device_thread, this);

    register_mavlink_message_handler(
        MAVLINK_MSG_ID_HEARTBEAT,
        std::bind(&DeviceImpl::process_heartbeat, this, _1), this);

    register_mavlink_message_handler(
        MAVLINK_MSG_ID_AUTOPILOT_VERSION,
        std::bind(&DeviceImpl::process_autopilot_version, this, _1), this);
}

DeviceImpl::~DeviceImpl()
{
    _should_exit = true;
    unregister_all_mavlink_message_handlers(this);

    if (_device_thread != nullptr) {
        _device_thread->join();
        delete _device_thread;
        _device_thread = nullptr;
    }
}

void DeviceImpl::register_mavlink_message_handler(uint16_t msg_id,
                                                  mavlink_message_handler_t callback,
                                                  const void *cookie)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    MavlinkHandlerTableEntry entry = {msg_id, callback, cookie};
    _mavlink_handler_table.push_back(entry);
}

void DeviceImpl::unregister_all_mavlink_message_handlers(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    for (auto it = _mavlink_handler_table.begin();
         it != _mavlink_handler_table.end();
         /* no ++it */) {

        if (it->cookie == cookie) {
            it = _mavlink_handler_table.erase(it);
        } else {
            ++it;
        }
    }
    _mavlink_handler_table.clear();
}

void DeviceImpl::register_timeout_handler(timeout_handler_t callback,
                                          double duration_s,
                                          const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    dl_time_t future_time = steady_time_in_future(duration_s);

    TimeoutHandlerMapEntry entry = {future_time, duration_s, callback};
    _timeout_handler_map.insert({cookie, entry});
}

void DeviceImpl::refresh_timeout_handler(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    auto it = _timeout_handler_map.find(cookie);
    if (it != _timeout_handler_map.end()) {
        dl_time_t future_time = steady_time_in_future(it->second.duration_s);
        it->second.time = future_time;
    }
}

void DeviceImpl::unregister_timeout_handler(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    auto it = _timeout_handler_map.find(cookie);
    if (it != _timeout_handler_map.end()) {
        _timeout_handler_map.erase(cookie);
    }
}

void DeviceImpl::process_mavlink_message(const mavlink_message_t &message)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    for (auto it = _mavlink_handler_table.begin(); it != _mavlink_handler_table.end(); ++it) {
        if (it->msg_id == message.msgid) {
            it->callback(message);
        }
    }
}

void DeviceImpl::process_heartbeat(const mavlink_message_t &message)
{
    mavlink_heartbeat_t heartbeat;
    mavlink_msg_heartbeat_decode(&message, &heartbeat);

    /* If we don't know the UUID yet, or we had a timeout, we want to check that the
     * UUID is still the same. */
    if (_target_uuid == 0 || !_heartbeats_arriving) {
        request_autopilot_version();
    }

    _armed = ((heartbeat.base_mode & MAV_MODE_FLAG_SAFETY_ARMED) ? true : false);

    _heartbeats_arriving = true;
    _last_heartbeat_received_time = steady_time();
}

void DeviceImpl::process_autopilot_version(const mavlink_message_t &message)
{
    mavlink_autopilot_version_t autopilot_version;
    mavlink_msg_autopilot_version_decode(&message, &autopilot_version);

    _target_supports_mission_int =
        ((autopilot_version.capabilities & MAV_PROTOCOL_CAPABILITY_MISSION_INT) ? true : false);

    if (_target_uuid == 0) {
        _target_uuid = autopilot_version.uid;
        _parent->notify_on_discover(_target_uuid);

    } else if (_target_uuid == autopilot_version.uid) {
        if (!_heartbeats_arriving) {
            // It looks like the vehicle has reconnected, let's accept it again.
            _parent->notify_on_discover(_target_uuid);
        } else {
            // This means we just got a autopilot version message but we don't need it
            // or didn't request it.
        }

    } else {
        // TODO: this is bad, we should raise a flag to invalidate device.
        Debug() << "Error: UUID changed";
    }
}

void DeviceImpl::device_thread(DeviceImpl *self)
{
    dl_time_t last_time {};

    while (!self->_should_exit) {

        if (elapsed_since_s(last_time) >= DeviceImpl::_HEARTBEAT_SEND_INTERVAL_S) {
            send_heartbeat(self);
            last_time = steady_time();
        }
        check_timeouts(self);
        check_heartbeat_timeout(self);
        self->_params.do_work();
        self->_commands.do_work();
        if (self->_heartbeats_arriving) {
            // Work fairly fast if we're connected.
            usleep(10000);
        } else {
            // Be less aggressive when unconnected.
            usleep(500000);
        }
    }
}

void DeviceImpl::send_heartbeat(DeviceImpl *self)
{
    mavlink_message_t message;
    mavlink_msg_heartbeat_pack(_own_system_id, _own_component_id, &message,
                               MAV_TYPE_GCS, MAV_AUTOPILOT_GENERIC, 0, 0, 0);
    self->send_message(message);
}

void DeviceImpl::check_timeouts(DeviceImpl *self)
{
    timeout_handler_t callback = nullptr;

    {
        std::lock_guard<std::mutex> lock(self->_timeout_handler_map_mutex);

        for (auto it = self->_timeout_handler_map.begin();
             it != self->_timeout_handler_map.end(); /* no ++it */) {

            // If time is passed, call timeout callback.
            if (it->second.time < steady_time()) {

                callback = it->second.callback;
                //Self-destruct before calling to avoid locking issues.
                self->_timeout_handler_map.erase(it++);
                break;

            } else {
                ++it;
            }
        }
    }

    // Now that the lock is out of scope and therefore unlocked, we're safe
    // to call the callback if set which might in turn register new timeout callbacks.
    if (callback != nullptr) {
        callback();
    }
}

void DeviceImpl::check_heartbeat_timeout(DeviceImpl *self)
{
    if (elapsed_since_s(self->_last_heartbeat_received_time) > DeviceImpl::_HEARTBEAT_TIMEOUT_S) {
        if (self->_heartbeats_arriving) {
            self->_parent->notify_on_timeout(self->_target_uuid);
            self->_heartbeats_arriving = true;
        }
    }
}

bool DeviceImpl::send_message(const mavlink_message_t &message)
{
    return _parent->send_message(message);
}

void DeviceImpl::request_autopilot_version()
{
    send_command_with_ack_async(
        MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES,
        MavlinkCommands::Params {1.0f, NAN, NAN, NAN, NAN, NAN, NAN},
        nullptr);
}

uint64_t DeviceImpl::get_target_uuid() const
{
    return _target_uuid;
}

uint8_t DeviceImpl::get_target_system_id() const
{
    return _target_system_id;
}

uint8_t DeviceImpl::get_target_component_id() const
{
    return _target_component_id;
}

void DeviceImpl::set_param_float_async(const std::string &name, float value, success_t callback)
{
    MavlinkParameters::ParamValue param_value;
    param_value.set_float(value);
    _params.set_param_async(name, param_value, callback);
}

void DeviceImpl::set_param_int_async(const std::string &name, int32_t value, success_t callback)
{
    MavlinkParameters::ParamValue param_value;
    param_value.set_int(value);
    _params.set_param_async(name, param_value, callback);
}

void DeviceImpl::get_param_float_async(const std::string &name,
                                       get_param_float_callback_t callback)
{
    _params.get_param_async(name, std::bind(&DeviceImpl::receive_float_param, _1, _2,
                                            callback));
}

void DeviceImpl::get_param_int_async(const std::string &name,
                                     get_param_int_callback_t callback)
{
    _params.get_param_async(name, std::bind(&DeviceImpl::receive_int_param, _1, _2,
                                            callback));
}

void DeviceImpl::receive_float_param(bool success, MavlinkParameters::ParamValue value,
                                     get_param_float_callback_t callback)
{
    if (callback) {
        callback(success, value.get_float());
    }
}

void DeviceImpl::receive_int_param(bool success, MavlinkParameters::ParamValue value,
                                   get_param_int_callback_t callback)
{
    if (callback) {
        callback(success, value.get_int());
    }
}

MavlinkCommands::Result DeviceImpl::send_command_with_ack(
    uint16_t command, const MavlinkCommands::Params &params, uint8_t component_id)
{
    if (_target_system_id == 0 && _target_component_id == 0) {
        return MavlinkCommands::Result::NO_DEVICE;
    }

    const uint8_t component_id_to_use =
        ((component_id != 0) ? component_id : _target_component_id);

    return _commands.send_command(command, params, _target_system_id, component_id_to_use);
}

void DeviceImpl::send_command_with_ack_async(uint16_t command,
                                             const MavlinkCommands::Params &params,
                                             command_result_callback_t callback,
                                             uint8_t component_id)
{
    if (_target_system_id == 0 && _target_component_id == 0) {
        if (callback) {
            callback(MavlinkCommands::Result::NO_DEVICE, NAN);
        }
        return;
    }

    const uint8_t component_id_to_use =
        ((component_id != 0) ? component_id : _target_component_id);

    _commands.queue_command_async(command, params, _target_system_id, component_id_to_use,
                                  callback);
}

MavlinkCommands::Result DeviceImpl::set_msg_rate(uint16_t message_id, double rate_hz)
{
    // If left at -1 it will stop the message stream.
    float interval_us = -1.0f;
    if (rate_hz > 0) {
        interval_us = 1e6f / (float)rate_hz;
    }

    return send_command_with_ack(
               MAV_CMD_SET_MESSAGE_INTERVAL,
               MavlinkCommands::Params {float(message_id), interval_us, NAN, NAN, NAN, NAN, NAN});
}

void DeviceImpl::set_msg_rate_async(uint16_t message_id, double rate_hz,
                                    command_result_callback_t callback)
{
    // If left at -1 it will stop the message stream.
    float interval_us = -1.0f;
    if (rate_hz > 0) {
        interval_us = 1e6f / (float)rate_hz;
    }

    send_command_with_ack_async(
        MAV_CMD_SET_MESSAGE_INTERVAL,
        MavlinkCommands::Params {float(message_id), interval_us, NAN, NAN, NAN, NAN, NAN},
        callback);
}

} // namespace dronelink
<commit_msg>device_impl: ignore version from other components<commit_after>#include "device_impl.h"
#include "global_include.h"
#include "dronelink_impl.h"
#include "mavlink_include.h"
#include <functional>

namespace dronelink {

using namespace std::placeholders; // for `_1`

DeviceImpl::DeviceImpl(DroneLinkImpl *parent,
                       uint8_t target_system_id,
                       uint8_t target_component_id) :
    _target_system_id(target_system_id),
    _target_component_id(target_component_id),
    _parent(parent),
    _params(this),
    _commands(this)
{
    _device_thread = new std::thread(device_thread, this);

    register_mavlink_message_handler(
        MAVLINK_MSG_ID_HEARTBEAT,
        std::bind(&DeviceImpl::process_heartbeat, this, _1), this);

    register_mavlink_message_handler(
        MAVLINK_MSG_ID_AUTOPILOT_VERSION,
        std::bind(&DeviceImpl::process_autopilot_version, this, _1), this);
}

DeviceImpl::~DeviceImpl()
{
    _should_exit = true;
    unregister_all_mavlink_message_handlers(this);

    if (_device_thread != nullptr) {
        _device_thread->join();
        delete _device_thread;
        _device_thread = nullptr;
    }
}

void DeviceImpl::register_mavlink_message_handler(uint16_t msg_id,
                                                  mavlink_message_handler_t callback,
                                                  const void *cookie)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    MavlinkHandlerTableEntry entry = {msg_id, callback, cookie};
    _mavlink_handler_table.push_back(entry);
}

void DeviceImpl::unregister_all_mavlink_message_handlers(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    for (auto it = _mavlink_handler_table.begin();
         it != _mavlink_handler_table.end();
         /* no ++it */) {

        if (it->cookie == cookie) {
            it = _mavlink_handler_table.erase(it);
        } else {
            ++it;
        }
    }
    _mavlink_handler_table.clear();
}

void DeviceImpl::register_timeout_handler(timeout_handler_t callback,
                                          double duration_s,
                                          const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    dl_time_t future_time = steady_time_in_future(duration_s);

    TimeoutHandlerMapEntry entry = {future_time, duration_s, callback};
    _timeout_handler_map.insert({cookie, entry});
}

void DeviceImpl::refresh_timeout_handler(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    auto it = _timeout_handler_map.find(cookie);
    if (it != _timeout_handler_map.end()) {
        dl_time_t future_time = steady_time_in_future(it->second.duration_s);
        it->second.time = future_time;
    }
}

void DeviceImpl::unregister_timeout_handler(const void *cookie)
{
    std::lock_guard<std::mutex> lock(_timeout_handler_map_mutex);

    auto it = _timeout_handler_map.find(cookie);
    if (it != _timeout_handler_map.end()) {
        _timeout_handler_map.erase(cookie);
    }
}

void DeviceImpl::process_mavlink_message(const mavlink_message_t &message)
{
    std::lock_guard<std::mutex> lock(_mavlink_handler_table_mutex);

    for (auto it = _mavlink_handler_table.begin(); it != _mavlink_handler_table.end(); ++it) {
        if (it->msg_id == message.msgid) {
            it->callback(message);
        }
    }
}

void DeviceImpl::process_heartbeat(const mavlink_message_t &message)
{
    mavlink_heartbeat_t heartbeat;
    mavlink_msg_heartbeat_decode(&message, &heartbeat);

    /* If we don't know the UUID yet, or we had a timeout, we want to check that the
     * UUID is still the same. */
    if (_target_uuid == 0 || !_heartbeats_arriving) {
        request_autopilot_version();
    }

    _armed = ((heartbeat.base_mode & MAV_MODE_FLAG_SAFETY_ARMED) ? true : false);

    _heartbeats_arriving = true;
    _last_heartbeat_received_time = steady_time();
}

void DeviceImpl::process_autopilot_version(const mavlink_message_t &message)
{
    // Ignore if they don't come from the autopilot component
    if (message.compid != MavlinkCommands::DEFAULT_COMPONENT_ID_AUTOPILOT) {
        return;
    }

    mavlink_autopilot_version_t autopilot_version;
    mavlink_msg_autopilot_version_decode(&message, &autopilot_version);

    _target_supports_mission_int =
        ((autopilot_version.capabilities & MAV_PROTOCOL_CAPABILITY_MISSION_INT) ? true : false);

    if (_target_uuid == 0) {
        _target_uuid = autopilot_version.uid;
        _parent->notify_on_discover(_target_uuid);

    } else if (_target_uuid == autopilot_version.uid) {
        if (!_heartbeats_arriving) {
            // It looks like the vehicle has reconnected, let's accept it again.
            _parent->notify_on_discover(_target_uuid);
        } else {
            // This means we just got a autopilot version message but we don't need it
            // or didn't request it.
        }

    } else {
        // TODO: this is bad, we should raise a flag to invalidate device.
        Debug() << "Error: UUID changed";
    }
}

void DeviceImpl::device_thread(DeviceImpl *self)
{
    dl_time_t last_time {};

    while (!self->_should_exit) {

        if (elapsed_since_s(last_time) >= DeviceImpl::_HEARTBEAT_SEND_INTERVAL_S) {
            send_heartbeat(self);
            last_time = steady_time();
        }
        check_timeouts(self);
        check_heartbeat_timeout(self);
        self->_params.do_work();
        self->_commands.do_work();
        if (self->_heartbeats_arriving) {
            // Work fairly fast if we're connected.
            usleep(10000);
        } else {
            // Be less aggressive when unconnected.
            usleep(500000);
        }
    }
}

void DeviceImpl::send_heartbeat(DeviceImpl *self)
{
    mavlink_message_t message;
    mavlink_msg_heartbeat_pack(_own_system_id, _own_component_id, &message,
                               MAV_TYPE_GCS, MAV_AUTOPILOT_GENERIC, 0, 0, 0);
    self->send_message(message);
}

void DeviceImpl::check_timeouts(DeviceImpl *self)
{
    timeout_handler_t callback = nullptr;

    {
        std::lock_guard<std::mutex> lock(self->_timeout_handler_map_mutex);

        for (auto it = self->_timeout_handler_map.begin();
             it != self->_timeout_handler_map.end(); /* no ++it */) {

            // If time is passed, call timeout callback.
            if (it->second.time < steady_time()) {

                callback = it->second.callback;
                //Self-destruct before calling to avoid locking issues.
                self->_timeout_handler_map.erase(it++);
                break;

            } else {
                ++it;
            }
        }
    }

    // Now that the lock is out of scope and therefore unlocked, we're safe
    // to call the callback if set which might in turn register new timeout callbacks.
    if (callback != nullptr) {
        callback();
    }
}

void DeviceImpl::check_heartbeat_timeout(DeviceImpl *self)
{
    if (elapsed_since_s(self->_last_heartbeat_received_time) > DeviceImpl::_HEARTBEAT_TIMEOUT_S) {
        if (self->_heartbeats_arriving) {
            self->_parent->notify_on_timeout(self->_target_uuid);
            self->_heartbeats_arriving = true;
        }
    }
}

bool DeviceImpl::send_message(const mavlink_message_t &message)
{
    return _parent->send_message(message);
}

void DeviceImpl::request_autopilot_version()
{
    send_command_with_ack_async(
        MAV_CMD_REQUEST_AUTOPILOT_CAPABILITIES,
        MavlinkCommands::Params {1.0f, NAN, NAN, NAN, NAN, NAN, NAN},
        nullptr);
}

uint64_t DeviceImpl::get_target_uuid() const
{
    return _target_uuid;
}

uint8_t DeviceImpl::get_target_system_id() const
{
    return _target_system_id;
}

uint8_t DeviceImpl::get_target_component_id() const
{
    return _target_component_id;
}

void DeviceImpl::set_param_float_async(const std::string &name, float value, success_t callback)
{
    MavlinkParameters::ParamValue param_value;
    param_value.set_float(value);
    _params.set_param_async(name, param_value, callback);
}

void DeviceImpl::set_param_int_async(const std::string &name, int32_t value, success_t callback)
{
    MavlinkParameters::ParamValue param_value;
    param_value.set_int(value);
    _params.set_param_async(name, param_value, callback);
}

void DeviceImpl::get_param_float_async(const std::string &name,
                                       get_param_float_callback_t callback)
{
    _params.get_param_async(name, std::bind(&DeviceImpl::receive_float_param, _1, _2,
                                            callback));
}

void DeviceImpl::get_param_int_async(const std::string &name,
                                     get_param_int_callback_t callback)
{
    _params.get_param_async(name, std::bind(&DeviceImpl::receive_int_param, _1, _2,
                                            callback));
}

void DeviceImpl::receive_float_param(bool success, MavlinkParameters::ParamValue value,
                                     get_param_float_callback_t callback)
{
    if (callback) {
        callback(success, value.get_float());
    }
}

void DeviceImpl::receive_int_param(bool success, MavlinkParameters::ParamValue value,
                                   get_param_int_callback_t callback)
{
    if (callback) {
        callback(success, value.get_int());
    }
}

MavlinkCommands::Result DeviceImpl::send_command_with_ack(
    uint16_t command, const MavlinkCommands::Params &params, uint8_t component_id)
{
    if (_target_system_id == 0 && _target_component_id == 0) {
        return MavlinkCommands::Result::NO_DEVICE;
    }

    const uint8_t component_id_to_use =
        ((component_id != 0) ? component_id : _target_component_id);

    return _commands.send_command(command, params, _target_system_id, component_id_to_use);
}

void DeviceImpl::send_command_with_ack_async(uint16_t command,
                                             const MavlinkCommands::Params &params,
                                             command_result_callback_t callback,
                                             uint8_t component_id)
{
    if (_target_system_id == 0 && _target_component_id == 0) {
        if (callback) {
            callback(MavlinkCommands::Result::NO_DEVICE, NAN);
        }
        return;
    }

    const uint8_t component_id_to_use =
        ((component_id != 0) ? component_id : _target_component_id);

    _commands.queue_command_async(command, params, _target_system_id, component_id_to_use,
                                  callback);
}

MavlinkCommands::Result DeviceImpl::set_msg_rate(uint16_t message_id, double rate_hz)
{
    // If left at -1 it will stop the message stream.
    float interval_us = -1.0f;
    if (rate_hz > 0) {
        interval_us = 1e6f / (float)rate_hz;
    }

    return send_command_with_ack(
               MAV_CMD_SET_MESSAGE_INTERVAL,
               MavlinkCommands::Params {float(message_id), interval_us, NAN, NAN, NAN, NAN, NAN});
}

void DeviceImpl::set_msg_rate_async(uint16_t message_id, double rate_hz,
                                    command_result_callback_t callback)
{
    // If left at -1 it will stop the message stream.
    float interval_us = -1.0f;
    if (rate_hz > 0) {
        interval_us = 1e6f / (float)rate_hz;
    }

    send_command_with_ack_async(
        MAV_CMD_SET_MESSAGE_INTERVAL,
        MavlinkCommands::Params {float(message_id), interval_us, NAN, NAN, NAN, NAN, NAN},
        callback);
}

} // namespace dronelink
<|endoftext|>