<commit_before>#include <cmath>
#include <limits>
#include <sstream>
#include <algorithm>

#include "Tools/general_utils.h"
#include "Tools/Exception/exception.hpp"

#include "general_utils.h"

std::vector<std::string> aff3ct::tools::split(const std::string &s, char delim)
{
	std::stringstream ss(s);
	std::string item;
	std::vector<std::string> elems;
	while (std::getline(ss, item, delim))
		elems.push_back(std::move(item));

	return elems;
}

std::vector<std::string> aff3ct::tools::split(const std::string &s)
{
	std::string buf;                 // have a buffer string
	std::stringstream ss(s);         // insert the string into a stream
	std::vector<std::string> tokens; // create vector to hold our words

	while (ss >> buf)
		tokens.push_back(buf);

	return tokens;
}

void aff3ct::tools::getline(std::istream &file, std::string &line)
{
	if (file.eof() || file.fail() || file.bad())
		throw runtime_error(__FILE__, __LINE__, __func__, "Something went wrong when getting a new line.");

	while (std::getline(file, line))
		if (line[0] != '#' && !std::all_of(line.begin(),line.end(),isspace))
			break;
}

template <typename R>
R aff3ct::tools::sigma_to_esn0(const R sigma, const int upsample_factor)
{
	if (upsample_factor <= 0)
	{
		std::stringstream message;
		message << "'upsample_factor' has to be greater than 0 ('upsample_factor' = " << upsample_factor << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (sigma < (R)0)
	{
		std::stringstream message;
		message << "'sigma' has to be greater than 0 ('sigma' = " << sigma << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (sigma == (R)0)
	{
		const auto esn0 = std::numeric_limits<R>::infinity();
		return esn0;
	}
	else
	{
		const auto esn0 = (R)10 * std::log10((R)upsample_factor / (sigma * sigma));
		return esn0;
	}
}

template <typename R>
R aff3ct::tools::esn0_to_sigma(const R esn0, const int upsample_factor)
{
	if (upsample_factor <= 0)
	{
		std::stringstream message;
		message << "'upsample_factor' has to be greater than 0 ('upsample_factor' = " << upsample_factor << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto sigma = std::sqrt((R)upsample_factor / ((R)2 * std::pow((R)10, (esn0 / (R)10))));
	return sigma;
}

template <typename R>
R aff3ct::tools::esn0_to_ebn0(const R esn0, const R bit_rate, const int bps)
{
	if (bit_rate <= (R)0 || bit_rate > (R)1)
	{
		std::stringstream message;
		message << "'bit_rate' has to be positive and smaller or equal to 1 ('bit_rate' = " << bit_rate << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (bps <= 0)
	{
		std::stringstream message;
		message << "'bps' has to be greater than 0 ('bps' = " << bps << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto ebn0 = esn0 - (R)10 * std::log10(bit_rate * (R)bps);
	return ebn0;
}

template <typename R>
R aff3ct::tools::ebn0_to_esn0(const R ebn0, const R bit_rate, const int bps)
{
	if (bit_rate <= (R)0 || bit_rate > (R)1)
	{
		std::stringstream message;
		message << "'bit_rate' has to be positive and smaller or equal to 1 ('bit_rate' = " << bit_rate << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (bps <= 0)
	{
		std::stringstream message;
		message << "'bps' has to be greater than 0 ('bps' = " << bps << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto esn0 = ebn0 + (R)10 * std::log10(bit_rate * (R)bps);
	return esn0;
}

template <typename R>
std::vector<R> aff3ct::tools::generate_range(const std::vector<std::vector<R>>& range_description, const R default_step)
{
	std::vector<R> range;

	for (auto& s : range_description)
	{
		if (s.size() != 3 && s.size() != 2)
		{
			std::stringstream message;
			message << "'s.size()' has to be 2 or 3 ('s.size()' = " << s.size() << ").";
			throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
		}

		R step = (s.size() == 3) ? s[1] : default_step;

		for (R v = s.front(); v <= (s.back() + 0.0001f); v += step) // 0.0001f is a hack to avoid the miss of the last snr
			range.push_back(v);
	}

	return range;
}

// ==================================================================================== explicit template instantiation
template float  aff3ct::tools::sigma_to_esn0<float >(const float,                const int);
template double aff3ct::tools::sigma_to_esn0<double>(const double,               const int);
template float  aff3ct::tools::esn0_to_sigma<float >(const float,                const int);
template double aff3ct::tools::esn0_to_sigma<double>(const double,               const int);
template float  aff3ct::tools::esn0_to_ebn0 <float >(const float,  const float,  const int);
template double aff3ct::tools::esn0_to_ebn0 <double>(const double, const double, const int);
template float  aff3ct::tools::ebn0_to_esn0 <float >(const float,  const float,  const int);
template double aff3ct::tools::ebn0_to_esn0 <double>(const double, const double, const int);
template std::vector<float > aff3ct::tools::generate_range(const std::vector<std::vector<float >>&, const float );
template std::vector<double> aff3ct::tools::generate_range(const std::vector<std::vector<double>>&, const double);
// ==================================================================================== explicit template instantiation
<commit_msg>Sort the computed range and parse it to have each SNR only once<commit_after>#include <cmath>
#include <limits>
#include <sstream>
#include <algorithm>

#include "Tools/Math/utils.h"
#include "Tools/Exception/exception.hpp"

#include "general_utils.h"

std::vector<std::string> aff3ct::tools::split(const std::string &s, char delim)
{
	std::stringstream ss(s);
	std::string item;
	std::vector<std::string> elems;
	while (std::getline(ss, item, delim))
		elems.push_back(std::move(item));

	return elems;
}

std::vector<std::string> aff3ct::tools::split(const std::string &s)
{
	std::string buf;                 // have a buffer string
	std::stringstream ss(s);         // insert the string into a stream
	std::vector<std::string> tokens; // create vector to hold our words

	while (ss >> buf)
		tokens.push_back(buf);

	return tokens;
}

void aff3ct::tools::getline(std::istream &file, std::string &line)
{
	if (file.eof() || file.fail() || file.bad())
		throw runtime_error(__FILE__, __LINE__, __func__, "Something went wrong when getting a new line.");

	while (std::getline(file, line))
		if (line[0] != '#' && !std::all_of(line.begin(),line.end(),isspace))
			break;
}

template <typename R>
R aff3ct::tools::sigma_to_esn0(const R sigma, const int upsample_factor)
{
	if (upsample_factor <= 0)
	{
		std::stringstream message;
		message << "'upsample_factor' has to be greater than 0 ('upsample_factor' = " << upsample_factor << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (sigma < (R)0)
	{
		std::stringstream message;
		message << "'sigma' has to be greater than 0 ('sigma' = " << sigma << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (sigma == (R)0)
	{
		const auto esn0 = std::numeric_limits<R>::infinity();
		return esn0;
	}
	else
	{
		const auto esn0 = (R)10 * std::log10((R)upsample_factor / (sigma * sigma));
		return esn0;
	}
}

template <typename R>
R aff3ct::tools::esn0_to_sigma(const R esn0, const int upsample_factor)
{
	if (upsample_factor <= 0)
	{
		std::stringstream message;
		message << "'upsample_factor' has to be greater than 0 ('upsample_factor' = " << upsample_factor << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto sigma = std::sqrt((R)upsample_factor / ((R)2 * std::pow((R)10, (esn0 / (R)10))));
	return sigma;
}

template <typename R>
R aff3ct::tools::esn0_to_ebn0(const R esn0, const R bit_rate, const int bps)
{
	if (bit_rate <= (R)0 || bit_rate > (R)1)
	{
		std::stringstream message;
		message << "'bit_rate' has to be positive and smaller or equal to 1 ('bit_rate' = " << bit_rate << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (bps <= 0)
	{
		std::stringstream message;
		message << "'bps' has to be greater than 0 ('bps' = " << bps << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto ebn0 = esn0 - (R)10 * std::log10(bit_rate * (R)bps);
	return ebn0;
}

template <typename R>
R aff3ct::tools::ebn0_to_esn0(const R ebn0, const R bit_rate, const int bps)
{
	if (bit_rate <= (R)0 || bit_rate > (R)1)
	{
		std::stringstream message;
		message << "'bit_rate' has to be positive and smaller or equal to 1 ('bit_rate' = " << bit_rate << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	if (bps <= 0)
	{
		std::stringstream message;
		message << "'bps' has to be greater than 0 ('bps' = " << bps << ").";
		throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
	}

	const auto esn0 = ebn0 + (R)10 * std::log10(bit_rate * (R)bps);
	return esn0;
}

template <typename R>
std::vector<R> aff3ct::tools::generate_range(const std::vector<std::vector<R>>& range_description, const R default_step)
{
	std::vector<R> range;

	for (auto& s : range_description)
	{
		if (s.size() != 3 && s.size() != 2)
		{
			std::stringstream message;
			message << "'s.size()' has to be 2 or 3 ('s.size()' = " << s.size() << ").";
			throw invalid_argument(__FILE__, __LINE__, __func__, message.str());
		}

		R step = (s.size() == 3) ? s[1] : default_step;

		for (R v = s.front(); v <= (s.back() + 0.0001f); v += step) // 0.0001f is a hack to avoid the miss of the last snr
			range.push_back(v);
	}

	std::sort  (range.begin(), range.end());
	std::unique(range.begin(), range.end(), comp_equal<R>);

	return range;
}

// ==================================================================================== explicit template instantiation
template float  aff3ct::tools::sigma_to_esn0<float >(const float,                const int);
template double aff3ct::tools::sigma_to_esn0<double>(const double,               const int);
template float  aff3ct::tools::esn0_to_sigma<float >(const float,                const int);
template double aff3ct::tools::esn0_to_sigma<double>(const double,               const int);
template float  aff3ct::tools::esn0_to_ebn0 <float >(const float,  const float,  const int);
template double aff3ct::tools::esn0_to_ebn0 <double>(const double, const double, const int);
template float  aff3ct::tools::ebn0_to_esn0 <float >(const float,  const float,  const int);
template double aff3ct::tools::ebn0_to_esn0 <double>(const double, const double, const int);
template std::vector<float > aff3ct::tools::generate_range(const std::vector<std::vector<float >>&, const float );
template std::vector<double> aff3ct::tools::generate_range(const std::vector<std::vector<double>>&, const double);
// ==================================================================================== explicit template instantiation
<|endoftext|>


<commit_before>//
// File:   map.cc
// Author: ruehle
//
// Created on April 13, 2007, 4:41 PM
//

#include "map.h"
#include <iostream>
#include <tools/matrix.h>

using namespace std;

Map::~Map()
{
    vector<BeadMap *>::iterator iter;
    for(iter=_maps.begin();iter!=_maps.end();++iter)
        delete (*iter);
    _maps.clear();
}

void Map::Apply(Molecule &in, Molecule &out)
{
    vector<BeadMap *>::iterator iter;
    for(iter=_maps.begin();iter!=_maps.end();++iter)
        (*iter)->Apply(in, out);
}

void Map_Sphere::Apply(Molecule &in, Molecule &out)
{
    vector<element_t>::iterator iter;
    vec cg(0., 0., 0.), f(0.,0.,0.), vel(0.,0.,0.);
    bool bPos, bVel, bF;
    bPos=bVel=bF=false;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if(in.getBead((*iter)._in)->HasPos()) {
            cg += (*iter)._weight * in.getBead((*iter)._in)->getPos();
            bPos=true;
        }
        if(in.getBead((*iter)._in)->HasVel()) {
            vel += (*iter)._weight * in.getBead((*iter)._in)->getVel();
            bVel = true;
        }
        if(in.getBead((*iter)._in)->HasF()) {
            /// \todo fix me, right calculation should be F_i = m_cg / sum(w_i) * sum(w_i/m_i*F_i)
            //f += (*iter)._weight * in.getBeadF((*iter)._in);
            f += in.getBead((*iter)._in)->getF();
            bF = true;
        }
    }
    if(bPos)
        out.getBead(_out)->setPos(cg);
    if(bVel)
        out.getBead(_out)->setVel(vel);
    if(bF)
        out.getBead(_out)->setF(f);
}

/// \todo implement this function
void Map_Ellipsoid::Apply(Molecule &in, Molecule &out)
{
    vector<element_t>::iterator iter;
    vec cg(0., 0., 0.), c(0., 0., 0.), f(0.,0.,0.), vel(0.,0.,0.);
    matrix m(0.);
     bool bPos, bVel, bF;
    bPos=bVel=bF=false;

    int n;
    n = 0;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if(in.getBead((*iter)._in)->HasPos()) {
            cg += (*iter)._weight * in.getBead((*iter)._in)->getPos();
            bPos=true;
        }
        if(in.getBead((*iter)._in)->HasVel() == true) {
            vel += (*iter)._weight * in.getBead((*iter)._in)->getVel();
            bVel = true;
        }
        if(in.getBead((*iter)._in)->HasF()) {
            /// \todo fix me, right calculation should be F_i = m_cg / sum(w_i) * sum(w_i/m_i*F_i)
            //f += (*iter)._weight * in.getBeadF((*iter)._in);
            f += in.getBead((*iter)._in)->getF();
            bF = true;
        }

        if((*iter)._weight>0) {
            c += in.getBead((*iter)._in)->getPos();
            n++;
        }
    }

    if(bPos)
        out.getBead(_out)->setPos(cg);
    if(bVel)
        out.getBead(_out)->setVel(vel);
    if(bF)
        out.getBead(_out)->setF(f);

    // calculate the tensor of gyration
    c=c/(double)n;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if((*iter)._weight == 0) continue;
        vec v = (in.getBead((*iter)._in)->getPos() - c);
        //v = vec(1, 0.5, 0) * 0.*(drand48()-0.5)
        //    + vec(0.5, -1, 0) * (drand48()-0.5)
        //    + vec(0, 0, 1) * (drand48()-0.5);
        m[0][0] += v.getX()*v.getX();
        m[0][1] += v.getX()*v.getY();
        m[0][2] += v.getX()*v.getZ();
        m[1][1] += v.getY()*v.getY();
        m[1][2] += v.getY()*v.getZ();
        m[2][2] += v.getZ()*v.getZ();
    }
    m[1][0] = m[0][1];
    m[2][0] = m[0][2];
    m[2][1] = m[1][2];

    // calculate the eigenvectors
    matrix::eigensystem_t es;
    m.SolveEigensystem(es);

    vec u = es.eigenvecs[0];
    vec v = in.getBead(_matrix[1]._in)->getPos() - in.getBead(_matrix[0]._in)->getPos();
    v.normalize();

    out.getBead(_out)->setV(v);

    vec w = in.getBead(_matrix[2]._in)->getPos() - in.getBead(_matrix[0]._in)->getPos();
    w.normalize();
    if((v^w)*u < 0) u=vec(0.,0.,0.)-u;
    out.getBead(_out)->setU(u);
    //out.BeadV(_out) = v;

    //out.BeadW(_out) = es.eigenvecs[2];
}
<commit_msg>added --first-frame option map.cc changed to write out w vector as well<commit_after>//
// File:   map.cc
// Author: ruehle
//
// Created on April 13, 2007, 4:41 PM
//

#include "map.h"
#include <iostream>
#include <tools/matrix.h>

using namespace std;

Map::~Map()
{
    vector<BeadMap *>::iterator iter;
    for(iter=_maps.begin();iter!=_maps.end();++iter)
        delete (*iter);
    _maps.clear();
}

void Map::Apply(Molecule &in, Molecule &out)
{
    vector<BeadMap *>::iterator iter;
    for(iter=_maps.begin();iter!=_maps.end();++iter)
        (*iter)->Apply(in, out);
}

void Map_Sphere::Apply(Molecule &in, Molecule &out)
{
    vector<element_t>::iterator iter;
    vec cg(0., 0., 0.), f(0.,0.,0.), vel(0.,0.,0.);
    bool bPos, bVel, bF;
    bPos=bVel=bF=false;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if(in.getBead((*iter)._in)->HasPos()) {
            cg += (*iter)._weight * in.getBead((*iter)._in)->getPos();
            bPos=true;
        }
        if(in.getBead((*iter)._in)->HasVel()) {
            vel += (*iter)._weight * in.getBead((*iter)._in)->getVel();
            bVel = true;
        }
        if(in.getBead((*iter)._in)->HasF()) {
            /// \todo fix me, right calculation should be F_i = m_cg / sum(w_i) * sum(w_i/m_i*F_i)
            //f += (*iter)._weight * in.getBeadF((*iter)._in);
            f += in.getBead((*iter)._in)->getF();
            bF = true;
        }
    }
    if(bPos)
        out.getBead(_out)->setPos(cg);
    if(bVel)
        out.getBead(_out)->setVel(vel);
    if(bF)
        out.getBead(_out)->setF(f);
}

/// \todo implement this function
void Map_Ellipsoid::Apply(Molecule &in, Molecule &out)
{
    vector<element_t>::iterator iter;
    vec cg(0., 0., 0.), c(0., 0., 0.), f(0.,0.,0.), vel(0.,0.,0.);
    matrix m(0.);
     bool bPos, bVel, bF;
    bPos=bVel=bF=false;

    int n;
    n = 0;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if(in.getBead((*iter)._in)->HasPos()) {
            cg += (*iter)._weight * in.getBead((*iter)._in)->getPos();
            bPos=true;
        }
        if(in.getBead((*iter)._in)->HasVel() == true) {
            vel += (*iter)._weight * in.getBead((*iter)._in)->getVel();
            bVel = true;
        }
        if(in.getBead((*iter)._in)->HasF()) {
            /// \todo fix me, right calculation should be F_i = m_cg / sum(w_i) * sum(w_i/m_i*F_i)
            //f += (*iter)._weight * in.getBeadF((*iter)._in);
            f += in.getBead((*iter)._in)->getF();
            bF = true;
        }

        if((*iter)._weight>0) {
            c += in.getBead((*iter)._in)->getPos();
            n++;
        }
    }

    if(bPos)
        out.getBead(_out)->setPos(cg);
    if(bVel)
        out.getBead(_out)->setVel(vel);
    if(bF)
        out.getBead(_out)->setF(f);

    // calculate the tensor of gyration
    c=c/(double)n;
    for(iter = _matrix.begin(); iter != _matrix.end(); ++iter) {
        if((*iter)._weight == 0) continue;
        vec v = (in.getBead((*iter)._in)->getPos() - c);
        //v = vec(1, 0.5, 0) * 0.*(drand48()-0.5)
        //    + vec(0.5, -1, 0) * (drand48()-0.5)
        //    + vec(0, 0, 1) * (drand48()-0.5);
        m[0][0] += v.getX()*v.getX();
        m[0][1] += v.getX()*v.getY();
        m[0][2] += v.getX()*v.getZ();
        m[1][1] += v.getY()*v.getY();
        m[1][2] += v.getY()*v.getZ();
        m[2][2] += v.getZ()*v.getZ();
    }
    m[1][0] = m[0][1];
    m[2][0] = m[0][2];
    m[2][1] = m[1][2];

    // calculate the eigenvectors
    matrix::eigensystem_t es;
    m.SolveEigensystem(es);

    vec u = es.eigenvecs[0];
    vec v = in.getBead(_matrix[1]._in)->getPos() - in.getBead(_matrix[0]._in)->getPos();
    v.normalize();

    out.getBead(_out)->setV(v);

    vec w = in.getBead(_matrix[2]._in)->getPos() - in.getBead(_matrix[0]._in)->getPos();
    w.normalize();
    out.getBead(_out)->setW(w);

    if((v^w)*u < 0) u=vec(0.,0.,0.)-u;
    out.getBead(_out)->setU(u);

    //out.BeadV(_out) = v;

    //out.BeadW(_out) = es.eigenvecs[2];
}
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/unbounded_arrays.hpp"

#include <cmath>
#include <vector>

#include "base/macros.hpp"
#include "quantities/elementary_functions.hpp"
#include "unbounded_arrays.hpp"

namespace principia {
namespace numerics {
namespace internal_unbounded_arrays {

using base::uninitialized;
using quantities::Sqrt;

template<class T>
template<class U, class... Args>
inline void uninitialized_allocator<T>::construct(U* const p, Args&&... args) {
#if PRINCIPIA_COMPILER_CLANG
  ::new ((void*)p) U(std::forward<Args>(args)...);  // NOLINT
#endif
}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(int const size)
    : data_(size, Scalar{}) {}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(int const size, uninitialized_t)
    : data_(size)  {}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(std::initializer_list<Scalar> data)
    : data_(std::move(data)) {}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(int const extra_size) {
  DCHECK_LE(0, extra_size);
  data_.resize(data_.size() + extra_size, Scalar{});
}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(int const extra_size, uninitialized_t) {
  DCHECK_LE(0, extra_size);
  data_.resize(data_.size() + extra_size);
}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(std::initializer_list<Scalar> data) {
  std::move(data.begin(), data.end(), std::back_inserter(data_));
}

template<typename Scalar>
void UnboundedVector<Scalar>::EraseToEnd(int const begin_index) {
  data_.erase(data_.begin() + begin_index, data_.end());
}

template<typename Scalar>
int UnboundedVector<Scalar>::size() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedVector<Scalar>::operator==(UnboundedVector const& right) const {
  return data_ == right.data_;
}

template<typename Scalar>
Scalar& UnboundedVector<Scalar>::operator[](int const index) {
  return data_[index];
}

template<typename Scalar>
Scalar const& UnboundedVector<Scalar>::operator[](int const index) const {
  return data_[index];
}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    int const rows)
    : rows_(rows),
      data_(rows_ * (rows_ + 1) / 2, Scalar{}) {}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    int const rows,
    uninitialized_t)
    : rows_(rows),
      data_(rows_ * (rows_ + 1) / 2) {}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    std::initializer_list<Scalar> data)
    : rows_(static_cast<int>(std::lround((-1 + Sqrt(8 * data.size())) * 0.5))),
      data_(std::move(data)) {
  DCHECK_EQ(data_.size(), rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(int const extra_rows) {
  rows_ += extra_rows;
  data_.resize(rows_ * (rows_ + 1) / 2, Scalar{});
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(int const extra_rows,
                                                    uninitialized_t) {
  rows_ += extra_rows;
  data_.resize(rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(
    std::initializer_list<Scalar> data) {
  std::move(data.begin(), data.end(), std::back_inserter(data_));
  rows_ = static_cast<int>(std::lround((-1 + Sqrt(8 * data_.size())) * 0.5));
  DCHECK_EQ(data_.size(), rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::EraseToEnd(
    int const begin_row_index) {
  rows_ = begin_row_index;
  data_.erase(data_.begin() + begin_row_index * (begin_row_index + 1) / 2,
              data_.end());
}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>
UnboundedLowerTriangularMatrix<Scalar>::Transpose() const {
  UnboundedUpperTriangularMatrix<Scalar> u(rows_, uninitialized);
  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j <= i; ++j) {
      u[j][i] = (*this)[i][j];
    }
  }
  return u;
}

template<typename Scalar>
int UnboundedLowerTriangularMatrix<Scalar>::rows() const {
  return rows_;
}

template<typename Scalar>
int UnboundedLowerTriangularMatrix<Scalar>::dimension() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedLowerTriangularMatrix<Scalar>::operator==(
    UnboundedLowerTriangularMatrix const& right) const {
  return rows_ == right.rows_ && data_ == right.data_;
}

template<typename Scalar>
Scalar* UnboundedLowerTriangularMatrix<Scalar>::operator[](int const index) {
  DCHECK_LT(index, rows_);
  return &data_[index * (index + 1) / 2];
}

template<typename Scalar>
Scalar const* UnboundedLowerTriangularMatrix<Scalar>::operator[](
    int const index) const {
  DCHECK_LT(index, rows_);
  return &data_[index * (index + 1) / 2];
}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    int const columns)
    : columns_(columns),
      data_(columns_ * (columns_ + 1) / 2, Scalar{}) {}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    int const columns,
    uninitialized_t)
    : columns_(columns),
      data_(columns_ * (columns_ + 1) / 2) {}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    std::initializer_list<Scalar> const& data)
    : columns_(
          static_cast<int>(std::lround((-1 + Sqrt(8 * data.size())) * 0.5))),
      data_(Transpose(data,
                      /*current_columns=*/0,
                      /*extra_columns=*/columns_)) {
  DCHECK_EQ(data_.size(), columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(int const extra_columns) {
  columns_ += extra_columns;
  data_.resize(columns_ * (columns_ + 1) / 2, Scalar{});
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(int const extra_columns,
                                                    uninitialized_t) {
  columns_ += extra_columns;
  data_.resize(columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(
    std::initializer_list<Scalar> const& data) {
  int const new_columns = static_cast<int>(
      std::lround((-1 + Sqrt(8 * (data_.size() + data.size()))) * 0.5));
  auto transposed_data = Transpose(data,
                                   /*current_columns=*/columns_,
                                   /*extra_columns=*/new_columns - columns_);
  columns_ = new_columns;
  std::move(transposed_data.begin(),
            transposed_data.end(),
            std::back_inserter(data_));
  DCHECK_EQ(data_.size(), columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::EraseToEnd(
    int const begin_column_index) {
  columns_ = begin_column_index;
  data_.erase(data_.begin() + begin_column_index * (begin_column_index + 1) / 2,
              data_.end());
}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>
UnboundedUpperTriangularMatrix<Scalar>::Transpose() const {
  UnboundedLowerTriangularMatrix<Scalar> l(columns_, uninitialized);
  for (int i = 0; i < columns_; ++i) {
    for (int j = i; j < columns_; ++j) {
      l[j][i] = (*this)[i][j];
    }
  }
  return l;
}

template<typename Scalar>
int UnboundedUpperTriangularMatrix<Scalar>::columns() const {
  return columns_;
}

template<typename Scalar>
int UnboundedUpperTriangularMatrix<Scalar>::dimension() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedUpperTriangularMatrix<Scalar>::operator==(
    UnboundedUpperTriangularMatrix const& right) const {
  return columns_ == right.columns_ && data_ == right.data_;
}

template<typename Scalar>
template<typename Matrix>
Scalar& UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::operator[](
    int const column) {
  DCHECK_LT(column, matrix_.columns_);
  auto x = column * (column + 1) / 2 + row_;
  Matrix& m = matrix_;
  std::vector<Scalar, uninitialized_allocator<Scalar>>& y = matrix_.data_;
  Scalar& z = y[x];
  return z;
  //return matrix_.data_[column * (column + 1) / 2 + row_];
}

template<typename Scalar>
template<typename Matrix>
Scalar const&
UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::operator[](
    int const column) const {
  DCHECK_LT(column, matrix_.columns_);
  return matrix_.data_[column * (column + 1) / 2 + row_];
}

template<typename Scalar>
template<typename Matrix>
UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::Row(Matrix& matrix,
                                                         int const row)
    : matrix_(const_cast<std::remove_const_t<Matrix>&>(matrix)),
      row_(row) {}

template<typename Scalar>
auto UnboundedUpperTriangularMatrix<Scalar>::operator[](int const row)
    -> Row<UnboundedUpperTriangularMatrix> {
  return Row<UnboundedUpperTriangularMatrix>{*this, row};
}

template<typename Scalar>
auto UnboundedUpperTriangularMatrix<Scalar>::operator[](int const row) const
    -> Row<UnboundedUpperTriangularMatrix const> {
  return Row<UnboundedUpperTriangularMatrix const>{*this, row};
}

template<typename Scalar>
auto
UnboundedUpperTriangularMatrix<Scalar>::Transpose(
    std::initializer_list<Scalar> const& data,
    int const current_columns,
    int const extra_columns) ->
  std::vector<Scalar, uninitialized_allocator<Scalar>> {
  // |data| is a trapezoidal slice at the end of the matrix.  This is
  // inconvenient to index, so we start by constructing a rectangular array with
  // |extra_columns| columns and |current_columns + extra_columns| rows padded
  // with junk.
  std::vector<Scalar, uninitialized_allocator<Scalar>> padded;
  {
    padded.reserve(2 * data.size());  // An overestimate.
    int row = 0;
    int column = 0;
    for (auto it = data.begin(); it != data.end();) {
      if (row <= current_columns + column) {
        padded.push_back(*it);
        ++it;
      } else {
        padded.emplace_back();
      }
      ++column;
      if (column == extra_columns) {
        column = 0;
        ++row;
      }
    }
  }

  // Scan the padded array by column and append the part above the diagonal to
  // the result.
  std::vector<Scalar, uninitialized_allocator<Scalar>> result;
  result.reserve(data.size());
  int const number_of_rows = current_columns + extra_columns;
  for (int column = 0; column < extra_columns; ++column) {
    for (int row = 0; row < number_of_rows; ++row) {
      if (row <= current_columns + column) {
        result.push_back(padded[row * extra_columns + column]);
      }
    }
  }

  return result;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedVector<Scalar> const& vector) {
  std::stringstream s;
  for (int i = 0; i < vector.data_.size(); ++i) {
    s << (i == 0 ? "{" : "") << vector.data_[i]
      << (i == vector.data_.size() - 1 ? "}" : ", ");
  }
  out << s.str();
  return out;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedLowerTriangularMatrix<Scalar> const& matrix) {
  std::stringstream s;
  s << "rows: " << matrix.rows_ << "\n";
  for (int i = 0; i < matrix.columns(); ++i) {
    out << "{";
    for (int j = 0; j <= i; ++j) {
      if (j > i) {
        out << ", ";
      }
      out << matrix[i][j];
    }
    out << "}\n";
  }
  return out;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedUpperTriangularMatrix<Scalar> const& matrix) {
  out << "columns: " << matrix.columns_ << "\n";
  for (int i = 0; i < matrix.columns(); ++i) {
    out << "{";
    for (int j = i; j < matrix.columns(); ++j) {
      if (j > i) {
        out << ", ";
      }
      out << matrix[i][j];
    }
    out << "}\n";
  }
  return out;
}

}  // namespace internal_unbounded_arrays
}  // namespace numerics
}  // namespace principia
<commit_msg>Fix a compilation error.<commit_after>
#pragma once

#include "numerics/unbounded_arrays.hpp"

#include <cmath>
#include <vector>

#include "base/macros.hpp"
#include "quantities/elementary_functions.hpp"
#include "unbounded_arrays.hpp"

namespace principia {
namespace numerics {
namespace internal_unbounded_arrays {

using base::uninitialized;
using quantities::Sqrt;

template<class T>
template<class U, class... Args>
inline void uninitialized_allocator<T>::construct(U* const p, Args&&... args) {
#if PRINCIPIA_COMPILER_CLANG
  ::new ((void*)p) U(std::forward<Args>(args)...);  // NOLINT
#endif
}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(int const size)
    : data_(size, Scalar{}) {}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(int const size, uninitialized_t)
    : data_(size)  {}

template<typename Scalar>
UnboundedVector<Scalar>::UnboundedVector(std::initializer_list<Scalar> data)
    : data_(std::move(data)) {}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(int const extra_size) {
  DCHECK_LE(0, extra_size);
  data_.resize(data_.size() + extra_size, Scalar{});
}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(int const extra_size, uninitialized_t) {
  DCHECK_LE(0, extra_size);
  data_.resize(data_.size() + extra_size);
}

template<typename Scalar>
void UnboundedVector<Scalar>::Extend(std::initializer_list<Scalar> data) {
  std::move(data.begin(), data.end(), std::back_inserter(data_));
}

template<typename Scalar>
void UnboundedVector<Scalar>::EraseToEnd(int const begin_index) {
  data_.erase(data_.begin() + begin_index, data_.end());
}

template<typename Scalar>
int UnboundedVector<Scalar>::size() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedVector<Scalar>::operator==(UnboundedVector const& right) const {
  return data_ == right.data_;
}

template<typename Scalar>
Scalar& UnboundedVector<Scalar>::operator[](int const index) {
  return data_[index];
}

template<typename Scalar>
Scalar const& UnboundedVector<Scalar>::operator[](int const index) const {
  return data_[index];
}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    int const rows)
    : rows_(rows),
      data_(rows_ * (rows_ + 1) / 2, Scalar{}) {}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    int const rows,
    uninitialized_t)
    : rows_(rows),
      data_(rows_ * (rows_ + 1) / 2) {}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>::UnboundedLowerTriangularMatrix(
    std::initializer_list<Scalar> data)
    : rows_(static_cast<int>(std::lround((-1 + Sqrt(8 * data.size())) * 0.5))),
      data_(std::move(data)) {
  DCHECK_EQ(data_.size(), rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(int const extra_rows) {
  rows_ += extra_rows;
  data_.resize(rows_ * (rows_ + 1) / 2, Scalar{});
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(int const extra_rows,
                                                    uninitialized_t) {
  rows_ += extra_rows;
  data_.resize(rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::Extend(
    std::initializer_list<Scalar> data) {
  std::move(data.begin(), data.end(), std::back_inserter(data_));
  rows_ = static_cast<int>(std::lround((-1 + Sqrt(8 * data_.size())) * 0.5));
  DCHECK_EQ(data_.size(), rows_ * (rows_ + 1) / 2);
}

template<typename Scalar>
void UnboundedLowerTriangularMatrix<Scalar>::EraseToEnd(
    int const begin_row_index) {
  rows_ = begin_row_index;
  data_.erase(data_.begin() + begin_row_index * (begin_row_index + 1) / 2,
              data_.end());
}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>
UnboundedLowerTriangularMatrix<Scalar>::Transpose() const {
  UnboundedUpperTriangularMatrix<Scalar> u(rows_, uninitialized);
  for (int i = 0; i < rows_; ++i) {
    for (int j = 0; j <= i; ++j) {
      u[j][i] = (*this)[i][j];
    }
  }
  return u;
}

template<typename Scalar>
int UnboundedLowerTriangularMatrix<Scalar>::rows() const {
  return rows_;
}

template<typename Scalar>
int UnboundedLowerTriangularMatrix<Scalar>::dimension() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedLowerTriangularMatrix<Scalar>::operator==(
    UnboundedLowerTriangularMatrix const& right) const {
  return rows_ == right.rows_ && data_ == right.data_;
}

template<typename Scalar>
Scalar* UnboundedLowerTriangularMatrix<Scalar>::operator[](int const index) {
  DCHECK_LT(index, rows_);
  return &data_[index * (index + 1) / 2];
}

template<typename Scalar>
Scalar const* UnboundedLowerTriangularMatrix<Scalar>::operator[](
    int const index) const {
  DCHECK_LT(index, rows_);
  return &data_[index * (index + 1) / 2];
}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    int const columns)
    : columns_(columns),
      data_(columns_ * (columns_ + 1) / 2, Scalar{}) {}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    int const columns,
    uninitialized_t)
    : columns_(columns),
      data_(columns_ * (columns_ + 1) / 2) {}

template<typename Scalar>
UnboundedUpperTriangularMatrix<Scalar>::UnboundedUpperTriangularMatrix(
    std::initializer_list<Scalar> const& data)
    : columns_(
          static_cast<int>(std::lround((-1 + Sqrt(8 * data.size())) * 0.5))),
      data_(Transpose(data,
                      /*current_columns=*/0,
                      /*extra_columns=*/columns_)) {
  DCHECK_EQ(data_.size(), columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(int const extra_columns) {
  columns_ += extra_columns;
  data_.resize(columns_ * (columns_ + 1) / 2, Scalar{});
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(int const extra_columns,
                                                    uninitialized_t) {
  columns_ += extra_columns;
  data_.resize(columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::Extend(
    std::initializer_list<Scalar> const& data) {
  int const new_columns = static_cast<int>(
      std::lround((-1 + Sqrt(8 * (data_.size() + data.size()))) * 0.5));
  auto transposed_data = Transpose(data,
                                   /*current_columns=*/columns_,
                                   /*extra_columns=*/new_columns - columns_);
  columns_ = new_columns;
  std::move(transposed_data.begin(),
            transposed_data.end(),
            std::back_inserter(data_));
  DCHECK_EQ(data_.size(), columns_ * (columns_ + 1) / 2);
}

template<typename Scalar>
void UnboundedUpperTriangularMatrix<Scalar>::EraseToEnd(
    int const begin_column_index) {
  columns_ = begin_column_index;
  data_.erase(data_.begin() + begin_column_index * (begin_column_index + 1) / 2,
              data_.end());
}

template<typename Scalar>
UnboundedLowerTriangularMatrix<Scalar>
UnboundedUpperTriangularMatrix<Scalar>::Transpose() const {
  UnboundedLowerTriangularMatrix<Scalar> l(columns_, uninitialized);
  for (int i = 0; i < columns_; ++i) {
    for (int j = i; j < columns_; ++j) {
      l[j][i] = (*this)[i][j];
    }
  }
  return l;
}

template<typename Scalar>
int UnboundedUpperTriangularMatrix<Scalar>::columns() const {
  return columns_;
}

template<typename Scalar>
int UnboundedUpperTriangularMatrix<Scalar>::dimension() const {
  return data_.size();
}

template<typename Scalar>
bool UnboundedUpperTriangularMatrix<Scalar>::operator==(
    UnboundedUpperTriangularMatrix const& right) const {
  return columns_ == right.columns_ && data_ == right.data_;
}

template<typename Scalar>
template<typename Matrix>
Scalar& UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::operator[](
    int const column) {
  DCHECK_LT(column, matrix_.columns_);
  auto x = column * (column + 1) / 2 + row_;
  Matrix& m = matrix_;
  std::vector<Scalar, uninitialized_allocator<Scalar>>& y = matrix_.data_;
  Scalar& z = y[x];
  return z;
  //return matrix_.data_[column * (column + 1) / 2 + row_];
}

template<typename Scalar>
template<typename Matrix>
Scalar const&
UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::operator[](
    int const column) const {
  DCHECK_LT(column, matrix_.columns_);
  return matrix_.data_[column * (column + 1) / 2 + row_];
}

template<typename Scalar>
template<typename Matrix>
UnboundedUpperTriangularMatrix<Scalar>::Row<Matrix>::Row(Matrix& matrix,
                                                         int const row)
    : matrix_(const_cast<std::remove_const_t<Matrix>&>(matrix)),
      row_(row) {}

template<typename Scalar>
auto UnboundedUpperTriangularMatrix<Scalar>::operator[](int const row)
    -> Row<UnboundedUpperTriangularMatrix> {
  return Row<UnboundedUpperTriangularMatrix>{*this, row};
}

template<typename Scalar>
auto UnboundedUpperTriangularMatrix<Scalar>::operator[](int const row) const
    -> Row<UnboundedUpperTriangularMatrix const> {
  return Row<UnboundedUpperTriangularMatrix const>{*this, row};
}

template<typename Scalar>
auto
UnboundedUpperTriangularMatrix<Scalar>::Transpose(
    std::initializer_list<Scalar> const& data,
    int const current_columns,
    int const extra_columns) ->
  std::vector<Scalar, uninitialized_allocator<Scalar>> {
  // |data| is a trapezoidal slice at the end of the matrix.  This is
  // inconvenient to index, so we start by constructing a rectangular array with
  // |extra_columns| columns and |current_columns + extra_columns| rows padded
  // with junk.
  std::vector<Scalar, uninitialized_allocator<Scalar>> padded;
  {
    padded.reserve(2 * data.size());  // An overestimate.
    int row = 0;
    int column = 0;
    for (auto it = data.begin(); it != data.end();) {
      if (row <= current_columns + column) {
        padded.push_back(*it);
        ++it;
      } else {
        padded.emplace_back();
      }
      ++column;
      if (column == extra_columns) {
        column = 0;
        ++row;
      }
    }
  }

  // Scan the padded array by column and append the part above the diagonal to
  // the result.
  std::vector<Scalar, uninitialized_allocator<Scalar>> result;
  result.reserve(data.size());
  int const number_of_rows = current_columns + extra_columns;
  for (int column = 0; column < extra_columns; ++column) {
    for (int row = 0; row < number_of_rows; ++row) {
      if (row <= current_columns + column) {
        result.push_back(padded[row * extra_columns + column]);
      }
    }
  }

  return result;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedVector<Scalar> const& vector) {
  std::stringstream s;
  for (int i = 0; i < vector.data_.size(); ++i) {
    s << (i == 0 ? "{" : "") << vector.data_[i]
      << (i == vector.data_.size() - 1 ? "}" : ", ");
  }
  out << s.str();
  return out;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedLowerTriangularMatrix<Scalar> const& matrix) {
  std::stringstream s;
  s << "rows: " << matrix.rows() << "\n";
  for (int i = 0; i < matrix.rows(); ++i) {
    out << "{";
    for (int j = 0; j <= i; ++j) {
      if (j > i) {
        out << ", ";
      }
      out << matrix[i][j];
    }
    out << "}\n";
  }
  return out;
}

template<typename Scalar>
std::ostream& operator<<(std::ostream& out,
                         UnboundedUpperTriangularMatrix<Scalar> const& matrix) {
  out << "columns: " << matrix.columns_ << "\n";
  for (int i = 0; i < matrix.columns(); ++i) {
    out << "{";
    for (int j = i; j < matrix.columns(); ++j) {
      if (j > i) {
        out << ", ";
      }
      out << matrix[i][j];
    }
    out << "}\n";
  }
  return out;
}

}  // namespace internal_unbounded_arrays
}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>#include "broadcastdaemon.h"
#ifdef BUILD_PYTHON
#include "gil.h"
#endif
#include <chrono>

namespace gg
{

BroadcastDaemon::BroadcastDaemon(IVideoSource * source)
        : _source(source)
        , _running(false)
{
    if (_source == nullptr)
        throw VideoSourceError("Null pointer passed"
                               " to broadcast daemon");
}

BroadcastDaemon::~BroadcastDaemon()
{
    stop();
}

void BroadcastDaemon::start(float frame_rate)
{
    if (frame_rate <= 0.0)
        throw VideoSourceError("Invalid frame rate");

    {
        std::lock_guard<std::mutex> lock_guard(_lock);
        if (_running)
            throw VideoSourceError("Broadcast daemon already running");
        else
            _running = true;
    }

#ifdef BUILD_PYTHON
    ScopedPythonGILRelease gil_release;
#endif

    _thread = std::thread(&BroadcastDaemon::run,
                          this,
                          1000.0 / frame_rate);
}

void BroadcastDaemon::stop()
{
    bool stopped = false;
    {
        std::lock_guard<std::mutex> lock_guard(_lock);
        if (_running)
        {
            _running = false;
            stopped = true;
        }
    }
    if (stopped)
        _thread.join();
}

void BroadcastDaemon::run(float sleep_duration_ms)
{
    VideoFrame frame(_source->get_colour(), false);
    /* in case no frame is obtained, an empty frame is
     * broadcast, to help against potential synchronisation
     * problems
     */
    int cols = 1920, rows = 1080; // default value, in case
                                  // something goes wrong
    _source->get_frame_dimensions(cols, rows);
    VideoFrame * fill_frame = new VideoFrame(_source->get_colour(), cols, rows);
    std::chrono::microseconds inter_frame_duration(
                static_cast<int>(1000 * sleep_duration_ms));
    while (_running)
    {
        auto start = std::chrono::high_resolution_clock::now();
        if (_source->get_frame(frame))
            _source->notify(frame);
        else
        {
            _source->get_frame_dimensions(cols, rows);
            if (cols != fill_frame->cols() or rows != fill_frame->rows())
            {
                delete fill_frame;
                fill_frame = new VideoFrame(_source->get_colour(), cols, rows);
            }
            _source->notify(*fill_frame);
        }
        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::microseconds processing_duration =
                std::chrono::duration_cast<std::chrono::microseconds>(
                    end - start
                    );
        auto sleep_duration = inter_frame_duration - processing_duration;
        if (sleep_duration.count() > 0)
            std::this_thread::sleep_for(sleep_duration);
    }
    delete fill_frame;
}

BroadcastDaemon::BroadcastDaemon()
{
    // nop
}

}
<commit_msg>Issue #74: BroadcastDaemon mitigates case where frame dimensions are not returned by source, also decreased default frame size from 1920x1080 to 256x64<commit_after>#include "broadcastdaemon.h"
#ifdef BUILD_PYTHON
#include "gil.h"
#endif
#include <chrono>

namespace gg
{

BroadcastDaemon::BroadcastDaemon(IVideoSource * source)
        : _source(source)
        , _running(false)
{
    if (_source == nullptr)
        throw VideoSourceError("Null pointer passed"
                               " to broadcast daemon");
}

BroadcastDaemon::~BroadcastDaemon()
{
    stop();
}

void BroadcastDaemon::start(float frame_rate)
{
    if (frame_rate <= 0.0)
        throw VideoSourceError("Invalid frame rate");

    {
        std::lock_guard<std::mutex> lock_guard(_lock);
        if (_running)
            throw VideoSourceError("Broadcast daemon already running");
        else
            _running = true;
    }

#ifdef BUILD_PYTHON
    ScopedPythonGILRelease gil_release;
#endif

    _thread = std::thread(&BroadcastDaemon::run,
                          this,
                          1000.0 / frame_rate);
}

void BroadcastDaemon::stop()
{
    bool stopped = false;
    {
        std::lock_guard<std::mutex> lock_guard(_lock);
        if (_running)
        {
            _running = false;
            stopped = true;
        }
    }
    if (stopped)
        _thread.join();
}

void BroadcastDaemon::run(float sleep_duration_ms)
{
    VideoFrame frame(_source->get_colour(), false);
    /* in case no frame is obtained, an empty frame is
     * broadcast, to help against potential synchronisation
     * problems
     */
    int cols = 0, rows = 0;
    if (not _source->get_frame_dimensions(cols, rows))
    {
        // default values, in case something goes wrong
        cols = 256;
        rows = 64;
    }
    VideoFrame * fill_frame = new VideoFrame(_source->get_colour(), cols, rows);
    std::chrono::microseconds inter_frame_duration(
                static_cast<int>(1000 * sleep_duration_ms));
    while (_running)
    {
        auto start = std::chrono::high_resolution_clock::now();
        if (_source->get_frame(frame))
            _source->notify(frame);
        else
        {
            int old_cols = cols, old_rows = rows;
            if (not _source->get_frame_dimensions(cols, rows))
            {
                cols = old_cols;
                rows = old_rows;
            }
            if (cols != fill_frame->cols() or rows != fill_frame->rows())
            {
                delete fill_frame;
                fill_frame = new VideoFrame(_source->get_colour(), cols, rows);
            }
            _source->notify(*fill_frame);
        }
        auto end = std::chrono::high_resolution_clock::now();
        std::chrono::microseconds processing_duration =
                std::chrono::duration_cast<std::chrono::microseconds>(
                    end - start
                    );
        auto sleep_duration = inter_frame_duration - processing_duration;
        if (sleep_duration.count() > 0)
            std::this_thread::sleep_for(sleep_duration);
    }
    delete fill_frame;
}

BroadcastDaemon::BroadcastDaemon()
{
    // nop
}

}
<|endoftext|>


<commit_before>#include "tmc.h"

#include <deque>
#include <fstream>
#include <sstream>

#include "util.h"

namespace redsea {

namespace tmc {

std::map<uint16_t,Event> g_event_data;

namespace {

uint16_t popBits(std::deque<int>& bit_deque, int len) {
  uint16_t result = 0x00;
  if ((int)bit_deque.size() >= len) {
    for (int i=0; i<len; i++) {
      result = (result << 1) | bit_deque.at(0);
      bit_deque.pop_front();
    }
  }
  return result;
}

// label, field_data
std::vector<std::pair<uint16_t,uint16_t>>
  getFreeformFields(std::vector<MessagePart> parts) {

  const std::vector<int> field_size(
      {3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0});

  uint16_t second_gsi = bits(parts[1].data[0], 12, 2);

  // Concatenate freeform data from used message length (derived from
  // GSI of second group)
  std::deque<int> freeform_data_bits;
  for (int i=0; i<(int)parts.size(); i++) {
    if (!parts[i].is_received)
      break;

    if (i <= 1 || i >= (int)parts.size() - second_gsi) {
      for (int b=0; b<12; b++)
        freeform_data_bits.push_back((parts[i].data[0] >> (11-b)) & 0x1);
      for (int b=0; b<16; b++)
        freeform_data_bits.push_back((parts[i].data[1] >> (15-b)) & 0x1);
    }
  }

  // Decode freeform data
  int bits_left = freeform_data_bits.size();
  std::vector<std::pair<uint16_t,uint16_t>> result;
  while (freeform_data_bits.size() > 4) {
    uint16_t label = popBits(freeform_data_bits, 4);
    if ((int)freeform_data_bits.size() < field_size.at(label))
      break;

    uint16_t field_data = popBits(freeform_data_bits, field_size.at(label));

    result.push_back({label, field_data});
  }

  return result;
}

std::string timeString(uint16_t field_data) {
  std::string time_string("");
  if (field_data <= 95) {
    char t[6];
    std::snprintf(t, 6, "%02d:%02d", field_data/4, 15*(field_data % 4));
    time_string = t;
  } else if (field_data <= 200) {
    char t[25];
    std::snprintf(t, 25, "after %d days at %02d:00", (field_data-96)/24,
        (field_data-96)%24);
    time_string = t;
  } else if (field_data <= 231) {
    char t[20];
    std::snprintf(t, 20, "day %d of the month", field_data-200);
    time_string = t;
  } else {
    int mo = (field_data-232) / 2;
    bool end_mid = (field_data-232) % 2;
    std::vector<std::string> month_names({"Jan","Feb","Mar","Apr","May",
        "Jun","Jul","Aug","Sep","Oct","Nov","Dec"});
    if (mo < 12) {
      time_string = (end_mid ? "end of " : "mid-") + month_names.at(mo);
    }
  }

  return time_string;
}

std::string sentence(std::string in) {
  std::string result = in + ".";
  result[0] = std::toupper(result[0]);
  return result;
}

} // namespace

Event::Event() {

}

Event::Event(std::string _desc, std::string _desc_q, uint16_t _nature,
    uint16_t _qtype, uint16_t _dur, uint16_t _dir, uint16_t _urg,
    uint16_t _class) : description(_desc), description_with_quantifier(_desc_q),
    nature(_nature), quantifier_type(_qtype), duration_type(_dur),
    directionality(_dir), urgency(_urg), update_class(_class) {
}

Event getEvent(uint16_t code) {

  if (g_event_data.find(code) != g_event_data.end())
    return g_event_data.find(code)->second;
  else
    return Event();

}

std::string getSupplInfoString(uint16_t code) {
  std::map<uint16_t,std::string> suppl_info_list;
  return suppl_info_list[code];
}

void loadEventData() {
  std::ifstream in("data/tmc_events.csv");

  if (!in.is_open())
    return;

  for (std::string line; std::getline(in, line); ) {
    if (!in.good())
      break;

    std::stringstream iss(line);
    uint16_t code;
    std::vector<std::string> strings(2);
    std::vector<uint16_t> nums(6);

    for (int col=0; col<9; col++) {
      std::string val;
      std::getline(iss, val, ';');
      if (!iss.good())
        break;

      if (col == 0)
        code = std::stoi(val);
      else if (col <= 2)
        strings[col-1] = val;
      else
        nums[col-3] = std::stoi(val);
    }

    g_event_data.insert({code, {strings[0], strings[1], nums[0], nums[1],
        nums[2], nums[3], nums[4], nums[5]}});

  }

  in.close();

}

TMC::TMC() : is_initialized_(false), has_encid_(false), multi_group_buffer_(5),
  ps_(8) {

}

void TMC::systemGroup(uint16_t message) {

  if (bits(message, 14, 1) == 0) {
    printf(", tmc: { system_info: { ");

    if (g_event_data.empty())
      loadEventData();

    is_initialized_ = true;
    ltn_ = bits(message, 6, 6);
    is_encrypted_ = (ltn_ == 0);

    printf("is_encrypted: %s", is_encrypted_ ? "true" : "false");

    if (!is_encrypted_)
      printf(", location_table: \"0x%02x\"", ltn_);

    bool afi   = bits(message, 5, 1);
    bool m     = bits(message, 4, 1);
    bool mgs_i = bits(message, 3, 1);
    bool mgs_n = bits(message, 2, 1);
    bool mgs_r = bits(message, 1, 1);
    bool mgs_u = bits(message, 0, 1);

    printf(", is_on_alt_freqs: %s", afi ? "true" : "false");

    std::vector<std::string> scope;
    if (mgs_i)
      scope.push_back("\"inter-road\"");
    if (mgs_n)
      scope.push_back("\"national\"");
    if (mgs_r)
      scope.push_back("\"regional\"");
    if (mgs_u)
      scope.push_back("\"urban\"");

    printf(", scope: [ %s ]", commaJoin(scope).c_str());

    printf(" } }");
  }

}

void TMC::userGroup(uint16_t x, uint16_t y, uint16_t z) {

  if (!is_initialized_)
    return;

  bool t = bits(x, 4, 1);

  // Encryption administration group
  if (bits(x, 0, 5) == 0x00) {
    sid_   = bits(y, 5, 6);
    encid_ = bits(y, 0, 5);
    ltnbe_ = bits(z, 10, 6);
    has_encid_ = true;

    printf(", tmc: { service_id: \"0x%02x\", encryption_id: \"0x%02x\", "
        "location_table: \"0x%02x\" }", sid_, encid_, ltnbe_);

  // Tuning information
  } else if (t) {
    uint16_t variant = bits(x, 0, 4);

    if (variant == 4 || variant == 5) {

      int pos = 4 * (variant - 4);

      ps_.setAt(pos,   bits(y, 8, 8));
      ps_.setAt(pos+1, bits(y, 0, 8));
      ps_.setAt(pos+2, bits(z, 8, 8));
      ps_.setAt(pos+3, bits(z, 0, 8));

      if (ps_.isComplete())
        printf(", tmc: { service_provider: \"%s\" }",
            ps_.getLastCompleteString().c_str());

    } else {
      printf(", tmc: { /* TODO: tuning info variant %d */ }", variant);
    }

  // User message
  } else {

    if (is_encrypted_ && !has_encid_)
      return;

    bool f = bits(x, 3, 1);

    // Single-group message
    if (f) {
      Message message(false, is_encrypted_, {{true, {x, y, z}}});
      message.print();
      current_ci_ = 0;

    // Part of multi-group message
    } else {

      uint16_t ci = bits(x, 0, 3);
      bool     fg = bits(y, 15, 1);

      if (ci != current_ci_ /* TODO 15-second limit */) {
        Message message(true, is_encrypted_, multi_group_buffer_);
        message.print();
        multi_group_buffer_[0].is_received = false;
        current_ci_ = ci;
      }

      int cur_grp;

      if (fg)
        cur_grp = 0;
      else if (bits(y, 14, 1))
        cur_grp = 1;
      else
        cur_grp = 4 - bits(y, 12, 2);

      multi_group_buffer_.at(cur_grp) = {true, {y, z}};

    }
  }

}

Message::Message(bool is_multi, bool is_loc_encrypted,
    std::vector<MessagePart> parts) : is_encrypted(is_loc_encrypted), events() {

  // single-group
  if (!is_multi) {
    duration  = bits(parts[0].data[0], 0, 3);
    divertadv = bits(parts[0].data[1], 15, 1);
    direction = bits(parts[0].data[1], 14, 1);
    extent    = bits(parts[0].data[1], 11, 3);
    events.push_back(bits(parts[0].data[1], 0, 11));
    location  = parts[0].data[2];
    is_complete = true;

  // multi-group
  } else {

    // Need at least the first group
    if (!parts[0].is_received)
      return;

    is_complete=true;

    // First group
    direction = bits(parts[0].data[0], 14, 1);
    extent    = bits(parts[0].data[0], 11, 3);
    events.push_back(bits(parts[0].data[0], 0, 11));
    location  = parts[0].data[1];

    // Subsequent parts
    if (parts[1].is_received) {
      auto freeform = getFreeformFields(parts);

      for (auto p : freeform) {
        uint16_t label = p.first;
        uint16_t field_data = p.second;
        //printf ("tmc: label %04x: field_data %04x\n",label,field_data);

        // Duration
        if (label == 0) {
          duration = field_data;

        // Length of route affected
        } else if (label == 2) {
            length_affected = field_data;
            has_length_affected = true;

        // Start / stop time
        } else if (label == 7) {
          time_starts = field_data;
          has_time_starts = true;
        } else if (label == 8) {
          time_until = field_data;
          has_time_until = true;
        } else {
          printf(" /* TODO label=%d */",label);
        }
      }
    }
  }
}

void Message::print() const {
  printf(", traffic_message: { ");

  if (!is_complete || events.empty()) {
    printf("}\n");
    return;
  }

  if (events.size() > 1) {
    printf("events: [ %s ]", commaJoin(events).c_str());
  } else {
    printf("event: { code: %d, description: \"%s\" }", events[0],
        sentence(getEvent(events[0]).description).c_str());
  }

  printf(", %slocation: \"0x%02x\", direction: \"%s\", extent: %d, "
         "diversion_advised: %s",
         (is_encrypted ? "encrypted_" : ""), location,
         direction ? "negative" : "positive",
         extent, divertadv ? "true" : "false" );

  if (has_time_starts)
    printf(", starts: \"%s\"", timeString(time_starts).c_str());
  if (has_time_until)
    printf(", until: \"%s\"", timeString(time_until).c_str());

  printf ("}");

}

} // namespace tmc
} // namespace redsea
<commit_msg>unused var<commit_after>#include "tmc.h"

#include <deque>
#include <fstream>
#include <sstream>

#include "util.h"

namespace redsea {

namespace tmc {

std::map<uint16_t,Event> g_event_data;

namespace {

uint16_t popBits(std::deque<int>& bit_deque, int len) {
  uint16_t result = 0x00;
  if ((int)bit_deque.size() >= len) {
    for (int i=0; i<len; i++) {
      result = (result << 1) | bit_deque.at(0);
      bit_deque.pop_front();
    }
  }
  return result;
}

// label, field_data
std::vector<std::pair<uint16_t,uint16_t>>
  getFreeformFields(std::vector<MessagePart> parts) {

  const std::vector<int> field_size(
      {3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0});

  uint16_t second_gsi = bits(parts[1].data[0], 12, 2);

  // Concatenate freeform data from used message length (derived from
  // GSI of second group)
  std::deque<int> freeform_data_bits;
  for (int i=0; i<(int)parts.size(); i++) {
    if (!parts[i].is_received)
      break;

    if (i <= 1 || i >= (int)parts.size() - second_gsi) {
      for (int b=0; b<12; b++)
        freeform_data_bits.push_back((parts[i].data[0] >> (11-b)) & 0x1);
      for (int b=0; b<16; b++)
        freeform_data_bits.push_back((parts[i].data[1] >> (15-b)) & 0x1);
    }
  }

  // Decode freeform data
  //int bits_left = freeform_data_bits.size();
  std::vector<std::pair<uint16_t,uint16_t>> result;
  while (freeform_data_bits.size() > 4) {
    uint16_t label = popBits(freeform_data_bits, 4);
    if ((int)freeform_data_bits.size() < field_size.at(label))
      break;

    uint16_t field_data = popBits(freeform_data_bits, field_size.at(label));

    result.push_back({label, field_data});
  }

  return result;
}

std::string timeString(uint16_t field_data) {
  std::string time_string("");
  if (field_data <= 95) {
    char t[6];
    std::snprintf(t, 6, "%02d:%02d", field_data/4, 15*(field_data % 4));
    time_string = t;
  } else if (field_data <= 200) {
    char t[25];
    std::snprintf(t, 25, "after %d days at %02d:00", (field_data-96)/24,
        (field_data-96)%24);
    time_string = t;
  } else if (field_data <= 231) {
    char t[20];
    std::snprintf(t, 20, "day %d of the month", field_data-200);
    time_string = t;
  } else {
    int mo = (field_data-232) / 2;
    bool end_mid = (field_data-232) % 2;
    std::vector<std::string> month_names({"Jan","Feb","Mar","Apr","May",
        "Jun","Jul","Aug","Sep","Oct","Nov","Dec"});
    if (mo < 12) {
      time_string = (end_mid ? "end of " : "mid-") + month_names.at(mo);
    }
  }

  return time_string;
}

std::string sentence(std::string in) {
  std::string result = in + ".";
  result[0] = std::toupper(result[0]);
  return result;
}

} // namespace

Event::Event() {

}

Event::Event(std::string _desc, std::string _desc_q, uint16_t _nature,
    uint16_t _qtype, uint16_t _dur, uint16_t _dir, uint16_t _urg,
    uint16_t _class) : description(_desc), description_with_quantifier(_desc_q),
    nature(_nature), quantifier_type(_qtype), duration_type(_dur),
    directionality(_dir), urgency(_urg), update_class(_class) {
}

Event getEvent(uint16_t code) {

  if (g_event_data.find(code) != g_event_data.end())
    return g_event_data.find(code)->second;
  else
    return Event();

}

std::string getSupplInfoString(uint16_t code) {
  std::map<uint16_t,std::string> suppl_info_list;
  return suppl_info_list[code];
}

void loadEventData() {
  std::ifstream in("data/tmc_events.csv");

  if (!in.is_open())
    return;

  for (std::string line; std::getline(in, line); ) {
    if (!in.good())
      break;

    std::stringstream iss(line);
    uint16_t code;
    std::vector<std::string> strings(2);
    std::vector<uint16_t> nums(6);

    for (int col=0; col<9; col++) {
      std::string val;
      std::getline(iss, val, ';');
      if (!iss.good())
        break;

      if (col == 0)
        code = std::stoi(val);
      else if (col <= 2)
        strings[col-1] = val;
      else
        nums[col-3] = std::stoi(val);
    }

    g_event_data.insert({code, {strings[0], strings[1], nums[0], nums[1],
        nums[2], nums[3], nums[4], nums[5]}});

  }

  in.close();

}

TMC::TMC() : is_initialized_(false), has_encid_(false), multi_group_buffer_(5),
  ps_(8) {

}

void TMC::systemGroup(uint16_t message) {

  if (bits(message, 14, 1) == 0) {
    printf(", tmc: { system_info: { ");

    if (g_event_data.empty())
      loadEventData();

    is_initialized_ = true;
    ltn_ = bits(message, 6, 6);
    is_encrypted_ = (ltn_ == 0);

    printf("is_encrypted: %s", is_encrypted_ ? "true" : "false");

    if (!is_encrypted_)
      printf(", location_table: \"0x%02x\"", ltn_);

    bool afi   = bits(message, 5, 1);
    bool m     = bits(message, 4, 1);
    bool mgs_i = bits(message, 3, 1);
    bool mgs_n = bits(message, 2, 1);
    bool mgs_r = bits(message, 1, 1);
    bool mgs_u = bits(message, 0, 1);

    printf(", is_on_alt_freqs: %s", afi ? "true" : "false");

    std::vector<std::string> scope;
    if (mgs_i)
      scope.push_back("\"inter-road\"");
    if (mgs_n)
      scope.push_back("\"national\"");
    if (mgs_r)
      scope.push_back("\"regional\"");
    if (mgs_u)
      scope.push_back("\"urban\"");

    printf(", scope: [ %s ]", commaJoin(scope).c_str());

    printf(" } }");
  }

}

void TMC::userGroup(uint16_t x, uint16_t y, uint16_t z) {

  if (!is_initialized_)
    return;

  bool t = bits(x, 4, 1);

  // Encryption administration group
  if (bits(x, 0, 5) == 0x00) {
    sid_   = bits(y, 5, 6);
    encid_ = bits(y, 0, 5);
    ltnbe_ = bits(z, 10, 6);
    has_encid_ = true;

    printf(", tmc: { service_id: \"0x%02x\", encryption_id: \"0x%02x\", "
        "location_table: \"0x%02x\" }", sid_, encid_, ltnbe_);

  // Tuning information
  } else if (t) {
    uint16_t variant = bits(x, 0, 4);

    if (variant == 4 || variant == 5) {

      int pos = 4 * (variant - 4);

      ps_.setAt(pos,   bits(y, 8, 8));
      ps_.setAt(pos+1, bits(y, 0, 8));
      ps_.setAt(pos+2, bits(z, 8, 8));
      ps_.setAt(pos+3, bits(z, 0, 8));

      if (ps_.isComplete())
        printf(", tmc: { service_provider: \"%s\" }",
            ps_.getLastCompleteString().c_str());

    } else {
      printf(", tmc: { /* TODO: tuning info variant %d */ }", variant);
    }

  // User message
  } else {

    if (is_encrypted_ && !has_encid_)
      return;

    bool f = bits(x, 3, 1);

    // Single-group message
    if (f) {
      Message message(false, is_encrypted_, {{true, {x, y, z}}});
      message.print();
      current_ci_ = 0;

    // Part of multi-group message
    } else {

      uint16_t ci = bits(x, 0, 3);
      bool     fg = bits(y, 15, 1);

      if (ci != current_ci_ /* TODO 15-second limit */) {
        Message message(true, is_encrypted_, multi_group_buffer_);
        message.print();
        multi_group_buffer_[0].is_received = false;
        current_ci_ = ci;
      }

      int cur_grp;

      if (fg)
        cur_grp = 0;
      else if (bits(y, 14, 1))
        cur_grp = 1;
      else
        cur_grp = 4 - bits(y, 12, 2);

      multi_group_buffer_.at(cur_grp) = {true, {y, z}};

    }
  }

}

Message::Message(bool is_multi, bool is_loc_encrypted,
    std::vector<MessagePart> parts) : is_encrypted(is_loc_encrypted), events() {

  // single-group
  if (!is_multi) {
    duration  = bits(parts[0].data[0], 0, 3);
    divertadv = bits(parts[0].data[1], 15, 1);
    direction = bits(parts[0].data[1], 14, 1);
    extent    = bits(parts[0].data[1], 11, 3);
    events.push_back(bits(parts[0].data[1], 0, 11));
    location  = parts[0].data[2];
    is_complete = true;

  // multi-group
  } else {

    // Need at least the first group
    if (!parts[0].is_received)
      return;

    is_complete=true;

    // First group
    direction = bits(parts[0].data[0], 14, 1);
    extent    = bits(parts[0].data[0], 11, 3);
    events.push_back(bits(parts[0].data[0], 0, 11));
    location  = parts[0].data[1];

    // Subsequent parts
    if (parts[1].is_received) {
      auto freeform = getFreeformFields(parts);

      for (auto p : freeform) {
        uint16_t label = p.first;
        uint16_t field_data = p.second;
        //printf ("tmc: label %04x: field_data %04x\n",label,field_data);

        // Duration
        if (label == 0) {
          duration = field_data;

        // Length of route affected
        } else if (label == 2) {
            length_affected = field_data;
            has_length_affected = true;

        // Start / stop time
        } else if (label == 7) {
          time_starts = field_data;
          has_time_starts = true;
        } else if (label == 8) {
          time_until = field_data;
          has_time_until = true;
        } else {
          printf(" /* TODO label=%d */",label);
        }
      }
    }
  }
}

void Message::print() const {
  printf(", traffic_message: { ");

  if (!is_complete || events.empty()) {
    printf("}\n");
    return;
  }

  if (events.size() > 1) {
    printf("events: [ %s ]", commaJoin(events).c_str());
  } else {
    printf("event: { code: %d, description: \"%s\" }", events[0],
        sentence(getEvent(events[0]).description).c_str());
  }

  printf(", %slocation: \"0x%02x\", direction: \"%s\", extent: %d, "
         "diversion_advised: %s",
         (is_encrypted ? "encrypted_" : ""), location,
         direction ? "negative" : "positive",
         extent, divertadv ? "true" : "false" );

  if (has_time_starts)
    printf(", starts: \"%s\"", timeString(time_starts).c_str());
  if (has_time_until)
    printf(", until: \"%s\"", timeString(time_until).c_str());

  printf ("}");

}

} // namespace tmc
} // namespace redsea
<|endoftext|>


<commit_before>// augmentation_widget.cpp

#include <QDebug>

#include "augmentation_widget.h"

augmentation_widget::augmentation_widget (QWidget* parent)
: QOpenGLWidget (parent)
, _scale_factor (1.0f)
, _x_pos (0.0f)
, _y_pos (0.0f)
, _x_rot (0)
, _y_rot (0)
, _z_rot (0)
, _cap (0)
, _frame_timer (new QTimer (this)) {
    connect (_frame_timer, SIGNAL (timeout ()), this, SLOT (update ()));
    _frame_timer->setInterval (1000 / _framerate);
    _frame_timer->start ();
}

augmentation_widget::~augmentation_widget () {
    delete _frame_timer;
}

QSize augmentation_widget::minimumSizeHint () const {
    return QSize (100, 100);
}

QSize augmentation_widget::sizeHint () const {
    return QSize (500, 500);
}

static void qNormalizeAngle (int& angle) {
    while (angle < 0) angle += 360;
    while (angle > 360) angle -= 360;
}

void augmentation_widget::setScale (float scale) {
    _scale_factor = scale;
    // emit xPositionChanged (location);
}

void augmentation_widget::setXPosition (float location) {
    _x_pos = location;
    // emit xPositionChanged (location);
}

void augmentation_widget::setYPosition (float location) {
    _y_pos = location;
    // emit yPositionChanged (location);
}

void augmentation_widget::setXRotation (int angle) {
    qNormalizeAngle (angle);
    _x_rot = angle;
}

void augmentation_widget::setYRotation (int angle) {
    qNormalizeAngle (angle);
    _y_rot = angle;
}

void augmentation_widget::setZRotation (int angle) {
    qNormalizeAngle (angle);
    _z_rot = angle;
}

void augmentation_widget::initializeGL () {
    initializeOpenGLFunctions ();

    glClearColor (0, 0, 0, 1.0f);
    glEnable (GL_DEPTH_TEST);
    glEnable (GL_CULL_FACE);
    glShadeModel (GL_SMOOTH);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glMatrixMode (GL_PROJECTION);
    glEnable (GL_TEXTURE_2D);
    glGenTextures (1, &_texture_background);

    // glMatrixMode (GL_MODELVIEW);
    /*static GLfloat lightPosition[4] = { 0, 0, 10, 1.0 };
    glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
    glLoadIdentity ();
    gluPerspective (33.7, 1.3, 0.1, 100.0);
    glMatrixMode (GL_MODELVIEW)*/
}

void augmentation_widget::resizeGL (int width, int height) {
    int side = qMin (width, height);
    glViewport ((width - side) / 2, (height - side) / 2, side, side);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
#ifdef QT_OPENGL_ES_1
    glOrthof (-2, +2, -2, +2, 1.0, 15.0);
#else
    glOrtho (-2, +2, -2, +2, 1.0, 15.0);
#endif
    glMatrixMode (GL_MODELVIEW);
}

void augmentation_widget::paintGL () {
    // QOpenGLFunctions* f = QOpenGLContext::currentContext ()->functions ();
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity ();

    cv::Mat frame;
    _cap >> frame;
    if (frame.empty ()) {
        printf ("empty video frame"); // TODO throw error here
        return;
    }
    // create background texture
    glBindTexture (GL_TEXTURE_2D, _texture_background);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, frame.cols, frame.rows, 0, GL_BGR,
    GL_UNSIGNED_BYTE, frame.ptr ());

    // glMatrixMode (GL_MODELVIEW);

    // draw background
    glTranslatef (0.0, 0.0, -10.0);

    glBegin (GL_QUADS);
    glTexCoord2f (0.0, 1.0);
    glVertex3f (-4.0, -3.0, -2.0);
    glTexCoord2f (1.0, 1.0);
    glVertex3f (4.0, -3.0, -2.0);
    glTexCoord2f (1.0, 0.0);
    glVertex3f (4.0, 3.0, -2.0);
    glTexCoord2f (0.0, 0.0);
    glVertex3f (-4.0, 3.0, -2.0);
    glEnd ();
    // glPopMatrix ();

    glPushMatrix ();
    glScalef (_scale_factor, _scale_factor, _scale_factor);
    glRotatef (_x_rot, 1, 0, 0);
    glRotatef (_y_rot, 0, 1, 0);
    glRotatef (_z_rot, 0, 0, 1);
    glTranslatef (_x_pos, _y_pos, 0);

    glBegin (GL_QUADS);
    glNormal3f (0, 0, -1);
    glVertex3f (-1, -1, 0);
    glVertex3f (-1, 1, 0);
    glVertex3f (1, 1, 0);
    glVertex3f (1, -1, 0);
    glEnd ();

    glBegin (GL_TRIANGLES);
    glNormal3f (0, -1, 0.707);
    glVertex3f (-1, -1, 0);
    glVertex3f (1, -1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glNormal3f (1, 0, 0.707);
    glVertex3f (1, -1, 0);
    glVertex3f (1, 1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glNormal3f (0, 1, 0.707);
    glVertex3f (1, 1, 0);
    glVertex3f (-1, 1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glNormal3f (-1, 0, 0.707);
    glVertex3f (-1, 1, 0);
    glVertex3f (-1, -1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glPopMatrix ();
}
<commit_msg>fix augmentatation widget<commit_after>// augmentation_widget.cpp

#include "augmentation_widget.h"
#include <GL/gl.h>
#include <QDebug>

augmentation_widget::augmentation_widget (QWidget* parent)
: QOpenGLWidget (parent)
, _scale_factor (1.0f)
, _x_pos (0.0f)
, _y_pos (0.0f)
, _x_rot (0)
, _y_rot (0)
, _z_rot (0)
, _cap (0)
, _frame_timer (new QTimer (this)) {
    connect (_frame_timer, SIGNAL (timeout ()), this, SLOT (update ()));
    _frame_timer->setInterval (1000 / _framerate);
    _frame_timer->start ();
}

augmentation_widget::~augmentation_widget () {
    delete _frame_timer;
}

QSize augmentation_widget::minimumSizeHint () const {
    return QSize (100, 100);
}

QSize augmentation_widget::sizeHint () const {
    return QSize (500, 500);
}

static void qNormalizeAngle (int& angle) {
    while (angle < 0) angle += 360;
    while (angle > 360) angle -= 360;
}

void augmentation_widget::setScale (float scale) {
    _scale_factor = scale;
    // emit xPositionChanged (location);
}

void augmentation_widget::setXPosition (float location) {
    _x_pos = location;
    // emit xPositionChanged (location);
}

void augmentation_widget::setYPosition (float location) {
    _y_pos = location;
    // emit yPositionChanged (location);
}

void augmentation_widget::setXRotation (int angle) {
    qNormalizeAngle (angle);
    _x_rot = angle;
}

void augmentation_widget::setYRotation (int angle) {
    qNormalizeAngle (angle);
    _y_rot = angle;
}

void augmentation_widget::setZRotation (int angle) {
    qNormalizeAngle (angle);
    _z_rot = angle;
}

void augmentation_widget::initializeGL () {
    initializeOpenGLFunctions ();

    glClearColor (0, 0, 0, 1.0f);
    glEnable (GL_DEPTH_TEST);
    glEnable (GL_CULL_FACE);
    glShadeModel (GL_SMOOTH);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);
    glMatrixMode (GL_PROJECTION);
    glEnable (GL_TEXTURE_2D);
    glGenTextures (1, &_texture_background);
    glEnable (GL_COLOR_MATERIAL);

    glMatrixMode (GL_MODELVIEW);
    static GLfloat lightPosition[4] = { 0, 0, 10, 1.0 };
    glLightfv (GL_LIGHT0, GL_POSITION, lightPosition);
    glLoadIdentity ();
    // gluPerspective (33.7, 1.3, 0.1, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

void augmentation_widget::resizeGL (int width, int height) {
    int side = qMin (width, height);
    glViewport ((width - side) / 2, (height - side) / 2, side, side);

    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
#ifdef QT_OPENGL_ES_1
    glOrthof (-2, +2, -2, +2, 1.0, 15.0);
#else
    glOrtho (-2, +2, -2, +2, 1.0, 15.0);
#endif
    glMatrixMode (GL_MODELVIEW);
}

void augmentation_widget::paintGL () {
    glMatrixMode (GL_MODELVIEW);
    // QOpenGLFunctions* f = QOpenGLContext::currentContext ()->functions ();
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity ();

    cv::Mat frame;
    _cap >> frame;
    if (frame.empty ()) {
        printf ("empty video frame"); // TODO throw error here
        return;
    }
    // create background texture
    glBindTexture (GL_TEXTURE_2D, _texture_background);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, frame.cols, frame.rows, 0, GL_BGR,
    GL_UNSIGNED_BYTE, frame.ptr ());

    // draw background
    glTranslatef (0.0, 0.0, -10.0);

    glBegin (GL_QUADS);
    glColor3f (1, 1, 1);
    glTexCoord2f (0.0, 1.0);
    glVertex3f (-4.0, -3.0, -2.0);
    glTexCoord2f (1.0, 1.0);
    glVertex3f (4.0, -3.0, -2.0);
    glTexCoord2f (1.0, 0.0);
    glVertex3f (4.0, 3.0, -2.0);
    glTexCoord2f (0.0, 0.0);
    glVertex3f (-4.0, 3.0, -2.0);
    glEnd ();

    glPushMatrix ();

    /*GLfloat persp_mat[16] = { 1, 0, -3.845925372767128e-16, 0, 0,
        0.5000000000000003, -5.768888059150692e-16, 0, 0, 0, 1, 0, 0, 0, 0, 1 };
    glMultMatrixf (persp_mat);*/
    //[1, 0, -3.845925372767128e-16;
    // 0, 0.3333333333333335, 0.6666666666666663;
    // 0, 0, 1]

    //[1, 0, -3.845925372767128e-16;
    // 0, 0.5000000000000003, -5.768888059150692e-16;
    // 0, 0, 1]

    glTranslatef (_x_pos, _y_pos, 0);
    glScalef (_scale_factor, _scale_factor, _scale_factor);
    glRotatef (_x_rot, 1, 0, 0);
    glRotatef (_y_rot, 0, 1, 0);
    glRotatef (_z_rot, 0, 0, 1);

    glBegin (GL_QUADS);
    glColor3f (0, 1, 1);
    glNormal3f (0, 0, -1);
    glVertex3f (-1, -1, 0);
    glVertex3f (-1, 1, 0);
    glVertex3f (1, 1, 0);
    glVertex3f (1, -1, 0);
    glEnd ();

    glBegin (GL_TRIANGLES);
    glColor3f (1, 0, 0);
    glNormal3f (0, -1, 0.707);
    glVertex3f (-1, -1, 0);
    glVertex3f (1, -1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glColor3f (0, 1, 0);
    glNormal3f (1, 0, 0.707);
    glVertex3f (1, -1, 0);
    glVertex3f (1, 1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glColor3f (0, 0, 1);
    glNormal3f (0, 1, 0.707);
    glVertex3f (1, 1, 0);
    glVertex3f (-1, 1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glBegin (GL_TRIANGLES);
    glColor3f (1, 1, 0);
    glNormal3f (-1, 0, 0.707);
    glVertex3f (-1, 1, 0);
    glVertex3f (-1, -1, 0);
    glVertex3f (0, 0, 1.2);
    glEnd ();
    glPopMatrix ();
}
<|endoftext|>


<commit_before>/***************************************
** Tsunagari Tile Engine              **
** gosu-window.cpp                    **
** Copyright 2011-2014 Michael Reiley **
** Copyright 2011-2017 Paul Merrill   **
***************************************/

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

#include <Gosu/Graphics.hpp>  // for Gosu::Graphics
#include <Gosu/Timing.hpp>
#include <Gosu/Utility.hpp>

#include "av/gosu/gosu-window.h"

#include "core/client-conf.h"
#include "core/world.h"

#define CHECK(x)  if (!(x)) { return false; }

// Garbage collection called every X milliseconds
#define GC_CALL_PERIOD 10 * 1000

#ifdef BACKEND_GOSU
static GosuGameWindow* globalWindow = nullptr;

GameWindow* GameWindow::create()
{
    globalWindow = new GosuGameWindow();
    return globalWindow;
}

GameWindow& GameWindow::instance()
{
    return *globalWindow;
}

time_t GameWindow::time()
{
    return (time_t)Gosu::milliseconds();
}
#endif

namespace Gosu {
    /**
     * Enable 1980s-style graphics scaling: nearest-neighbor filtering.
     * Call this function before creating any Gosu::Image.
     */
    void enableUndocumentedRetrofication() {
        extern bool undocumented_retrofication;
        undocumented_retrofication = true;
    }
}

GosuGameWindow::GosuGameWindow()
    // Gosu emulates the requested screen resolution on fullscreen,
    // but this breaks our aspect ratio-correcting letterbox.
    // Ergo we just make a window the size of the screen.
    : Gosu::Window(
        conf.fullscreen ? Gosu::screen_width() :
                          (unsigned)conf.windowSize.x,
        conf.fullscreen ? Gosu::screen_height() :
                          (unsigned)conf.windowSize.y,
        conf.fullscreen
      ),
      now(this->time()),
      lastGCtime(0)
{
    Gosu::enableUndocumentedRetrofication();

    auto& keys = gosuToTsunagariKey;
    keys[Gosu::ButtonName::KB_ESCAPE] = KBEscape;
    keys[Gosu::ButtonName::KB_LEFT_SHIFT] = KBLeftShift;
    keys[Gosu::ButtonName::KB_RIGHT_SHIFT] = KBRightShift;
    keys[Gosu::ButtonName::KB_LEFT_CONTROL] = KBLeftControl;
    keys[Gosu::ButtonName::KB_RIGHT_CONTROL] = KBRightControl;
    keys[Gosu::ButtonName::KB_SPACE] = KBSpace;
    keys[Gosu::ButtonName::KB_LEFT] = KBLeftArrow;
    keys[Gosu::ButtonName::KB_RIGHT] = KBRightArrow;
    keys[Gosu::ButtonName::KB_UP] = KBUpArrow;
    keys[Gosu::ButtonName::KB_DOWN] = KBDownArrow;
}

unsigned GosuGameWindow::width() const
{
    return graphics().width();
}

unsigned GosuGameWindow::height() const
{
    return graphics().height();
}

void GosuGameWindow::setCaption(const std::string& caption)
{
    Gosu::Window::set_caption(caption);
}

void GosuGameWindow::button_down(const Gosu::Button btn)
{
    now = this->time();
    if (keystates.find(btn) == keystates.end()) {
        keystate& state = keystates[btn];
        state.since = now;
        state.initiallyResolved = false;
        state.consecutive = false;
    }

    // We process the initial buttonDown here so that it
    // gets handled even if we receive a buttonUp before an
    // update.
    auto mapped = gosuToTsunagariKey[btn.id()];
    if (mapped) {
        emitKeyDown(mapped);
    }
}

void GosuGameWindow::button_up(const Gosu::Button btn)
{
    keystates.erase(btn);

    auto mapped = gosuToTsunagariKey[btn.id()];
    if (mapped) {
        emitKeyUp(mapped);
    }
}

void GosuGameWindow::draw()
{
    World::instance().draw();
}

bool GosuGameWindow::needs_redraw() const
{
    return World::instance().needsRedraw();
}

void GosuGameWindow::update()
{
    now = this->time();

    if (conf.moveMode == TURN) {
        handleKeyboardInput(now);
    }
    World::instance().update(now);

    if (now > lastGCtime + GC_CALL_PERIOD) {
        lastGCtime = now;
        World::instance().garbageCollect();
    }
}

void GosuGameWindow::mainLoop()
{
    show();
}

void GosuGameWindow::drawRect(double x1, double x2, double y1, double y2,
        uint32_t argb)
{
    Gosu::Color c(argb);
    double top = std::numeric_limits<double>::max();
    graphics().draw_quad(
        x1, y1, c,
        x2, y1, c,
        x2, y2, c,
        x1, y2, c,
        top
    );
}

void GosuGameWindow::scale(double x, double y, std::function<void()> op)
{
    graphics().transform(Gosu::scale(x, y), op);
}

void GosuGameWindow::translate(double x, double y, std::function<void()> op)
{
    graphics().transform(Gosu::translate(x, y), op);
}

void GosuGameWindow::clip(double x, double y, double width, double height,
                          std::function<void()> op)
{
    graphics().clip_to(x, y, width, height, op);
}

void GosuGameWindow::close()
{
    Gosu::Window::close();
}

void GosuGameWindow::handleKeyboardInput(time_t now)
{
    std::map<Gosu::Button, keystate>::iterator it;

    // Persistent input handling code
    for (it = keystates.begin(); it != keystates.end(); it++) {
        Gosu::Button btn = it->first;
        auto mapped = gosuToTsunagariKey[btn.id()];
        keystate& state = it->second;

        // If there is persistCons milliseconds of latency
        // between when a button is depressed and when we first look at
        // it here, we'll incorrectly try to fire off a second round of
        // input.
        // This can happen if an intermediary function blocks the thread
        // for a while.
        if (!state.initiallyResolved) {
            state.initiallyResolved = true;
            continue;
        }

        time_t delay = state.consecutive ?
            conf.persistCons : conf.persistInit;
        if (now >= state.since + delay) {
            state.since += delay;
            World::instance().buttonDown(mapped);
            state.consecutive = true;
        }
    }
}
<commit_msg>GosuWindow: Don't initialize unused keys<commit_after>/***************************************
** Tsunagari Tile Engine              **
** gosu-window.cpp                    **
** Copyright 2011-2014 Michael Reiley **
** Copyright 2011-2017 Paul Merrill   **
***************************************/

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

#include <Gosu/Graphics.hpp>  // for Gosu::Graphics
#include <Gosu/Timing.hpp>
#include <Gosu/Utility.hpp>

#include "av/gosu/gosu-window.h"

#include "core/client-conf.h"
#include "core/world.h"

#define CHECK(x)  if (!(x)) { return false; }

// Garbage collection called every X milliseconds
#define GC_CALL_PERIOD 10 * 1000

#ifdef BACKEND_GOSU
static GosuGameWindow* globalWindow = nullptr;

GameWindow* GameWindow::create()
{
    globalWindow = new GosuGameWindow();
    return globalWindow;
}

GameWindow& GameWindow::instance()
{
    return *globalWindow;
}

time_t GameWindow::time()
{
    return (time_t)Gosu::milliseconds();
}
#endif

namespace Gosu {
    /**
     * Enable 1980s-style graphics scaling: nearest-neighbor filtering.
     * Call this function before creating any Gosu::Image.
     */
    void enableUndocumentedRetrofication() {
        extern bool undocumented_retrofication;
        undocumented_retrofication = true;
    }
}

GosuGameWindow::GosuGameWindow()
    // Gosu emulates the requested screen resolution on fullscreen,
    // but this breaks our aspect ratio-correcting letterbox.
    // Ergo we just make a window the size of the screen.
    : Gosu::Window(
        conf.fullscreen ? Gosu::screen_width() :
                          (unsigned)conf.windowSize.x,
        conf.fullscreen ? Gosu::screen_height() :
                          (unsigned)conf.windowSize.y,
        conf.fullscreen
      ),
      now(this->time()),
      lastGCtime(0)
{
    Gosu::enableUndocumentedRetrofication();

    gosuToTsunagariKey.reserve(Gosu::ButtonName::NUM_BUTTONS);
    auto& keys = gosuToTsunagariKey;
    keys[Gosu::ButtonName::KB_ESCAPE] = KBEscape;
    keys[Gosu::ButtonName::KB_LEFT_SHIFT] = KBLeftShift;
    keys[Gosu::ButtonName::KB_RIGHT_SHIFT] = KBRightShift;
    keys[Gosu::ButtonName::KB_LEFT_CONTROL] = KBLeftControl;
    keys[Gosu::ButtonName::KB_RIGHT_CONTROL] = KBRightControl;
    keys[Gosu::ButtonName::KB_SPACE] = KBSpace;
    keys[Gosu::ButtonName::KB_LEFT] = KBLeftArrow;
    keys[Gosu::ButtonName::KB_RIGHT] = KBRightArrow;
    keys[Gosu::ButtonName::KB_UP] = KBUpArrow;
    keys[Gosu::ButtonName::KB_DOWN] = KBDownArrow;
}

unsigned GosuGameWindow::width() const
{
    return graphics().width();
}

unsigned GosuGameWindow::height() const
{
    return graphics().height();
}

void GosuGameWindow::setCaption(const std::string& caption)
{
    Gosu::Window::set_caption(caption);
}

void GosuGameWindow::button_down(const Gosu::Button btn)
{
    now = this->time();
    if (keystates.find(btn) == keystates.end()) {
        keystate& state = keystates[btn];
        state.since = now;
        state.initiallyResolved = false;
        state.consecutive = false;
    }

    // We process the initial buttonDown here so that it
    // gets handled even if we receive a buttonUp before an
    // update.
    auto mapped = gosuToTsunagariKey[btn.id()];
    if (mapped) {
        emitKeyDown(mapped);
    }
}

void GosuGameWindow::button_up(const Gosu::Button btn)
{
    keystates.erase(btn);

    auto mapped = gosuToTsunagariKey[btn.id()];
    if (mapped) {
        emitKeyUp(mapped);
    }
}

void GosuGameWindow::draw()
{
    World::instance().draw();
}

bool GosuGameWindow::needs_redraw() const
{
    return World::instance().needsRedraw();
}

void GosuGameWindow::update()
{
    now = this->time();

    if (conf.moveMode == TURN) {
        handleKeyboardInput(now);
    }
    World::instance().update(now);

    if (now > lastGCtime + GC_CALL_PERIOD) {
        lastGCtime = now;
        World::instance().garbageCollect();
    }
}

void GosuGameWindow::mainLoop()
{
    show();
}

void GosuGameWindow::drawRect(double x1, double x2, double y1, double y2,
        uint32_t argb)
{
    Gosu::Color c(argb);
    double top = std::numeric_limits<double>::max();
    graphics().draw_quad(
        x1, y1, c,
        x2, y1, c,
        x2, y2, c,
        x1, y2, c,
        top
    );
}

void GosuGameWindow::scale(double x, double y, std::function<void()> op)
{
    graphics().transform(Gosu::scale(x, y), op);
}

void GosuGameWindow::translate(double x, double y, std::function<void()> op)
{
    graphics().transform(Gosu::translate(x, y), op);
}

void GosuGameWindow::clip(double x, double y, double width, double height,
                          std::function<void()> op)
{
    graphics().clip_to(x, y, width, height, op);
}

void GosuGameWindow::close()
{
    Gosu::Window::close();
}

void GosuGameWindow::handleKeyboardInput(time_t now)
{
    std::map<Gosu::Button, keystate>::iterator it;

    // Persistent input handling code
    for (it = keystates.begin(); it != keystates.end(); it++) {
        Gosu::Button btn = it->first;
        auto mapped = gosuToTsunagariKey[btn.id()];
        keystate& state = it->second;

        // If there is persistCons milliseconds of latency
        // between when a button is depressed and when we first look at
        // it here, we'll incorrectly try to fire off a second round of
        // input.
        // This can happen if an intermediary function blocks the thread
        // for a while.
        if (!state.initiallyResolved) {
            state.initiallyResolved = true;
            continue;
        }

        time_t delay = state.consecutive ?
            conf.persistCons : conf.persistInit;
        if (now >= state.since + delay) {
            state.since += delay;
            World::instance().buttonDown(mapped);
            state.consecutive = true;
        }
    }
}
<|endoftext|>


<commit_before>#include <cassert>
#include <functional>
#include <iostream>
#include <type_traits>
#include <unordered_map>

#include "vm.h"

const int STACK_SIZE = 1024;

enum offset {
	return_address = 0,
	enclosing_frame = 1,
	declaration_frame = 2,
	local = 3
};

void pl0::execute(const bytecode & code, int entry_addr) {
	int pc = 0;
	int *stack = new int[STACK_SIZE];
	int *bp = stack;
	int *sp = bp + offset::declaration_frame;

	auto resolve = [&](int dist) -> int* {
		int *fp = bp;
		while (dist > 0) {
			fp = reinterpret_cast<int*>(fp[offset::declaration_frame]);
			dist--;
		}
		return fp;
	};

	auto push = [&](auto value) -> void {
		if constexpr (std::is_pointer_v<decltype(value)>) {
			*++sp = reinterpret_cast<int>(value);
		} else {
			*++sp = value;
		}
	};

	auto pop = [&]() -> int {
		return *sp--;
	};

	const std::unordered_map<opt, std::function<int(int, int)>> bifunctors = {
		{ opt::ADD, std::plus<int>() },
		{ opt::SUB, std::minus<int>() },
		{ opt::DIV, std::divides<int>() },
		{ opt::MUL, std::multiplies<int>() },
		{ opt::LE, std::less<int>() },
		{ opt::LEQ, std::less_equal<int>() },
		{ opt::GE, std::greater<int>() },
		{ opt::GEQ, std::greater_equal<int>() },
		{ opt::EQ, std::equal_to<int>() },
		{ opt::NEQ, std::not_equal_to<int>() }
	};

    int codelen = static_cast<int>(code.size());
	while (pc < codelen) {
		const instruction & ins = code[pc];
		pc++;
		switch (std::get<0>(ins)) {
		case opcode::LIT:
			push(std::get<2>(ins));
			break;
		case opcode::LOD:
			push(resolve(std::get<1>(ins))[offset::local + std::get<2>(ins)]);
			break;
		case opcode::STO:
			resolve(std::get<1>(ins))[offset::local + std::get<2>(ins)] = pop();
			break;
		case opcode::CAL:
			push(pc);
			push(bp);
			push(resolve(std::get<1>(ins)));
			bp = sp - 3;
			pc = std::get<2>(ins);
			break;
		case opcode::INT:
			sp += std::get<2>(ins);
			break;
		case opcode::JMP:
			pc = std::get<2>(ins);
			break;
		case opcode::JPC:
			if (pop()) pc = std::get<2>(ins);
			break;
		case opcode::OPR:
			if (std::get<2>(ins) == *opt::ODD) {
				push(pop() % 2);
			} else if (std::get<2>(ins) == *opt::READ) {
				int tmp;
				std::cin >> tmp;
				push(tmp);
			} else if (std::get<2>(ins) == *opt::WRITE) {
				std::cout << pop() << '\n';
			} else if (std::get<2>(ins) == *opt::RET) {
				sp = bp + offset::enclosing_frame;
				bp = reinterpret_cast<int*>(pop());
				pc = pop();
			} else {
				int rhs = pop(), lhs = pop();
				bifunctors.find(opt(std::get<2>(ins)))->second(lhs, rhs);
			}
			break;
		}
	}
}
<commit_msg>Make virtual machine works!<commit_after>#include <cassert>
#include <functional>
#include <iostream>
#include <type_traits>
#include <unordered_map>

#include "vm.h"

const int STACK_SIZE = 1024;

enum offset {
	return_address = 0,
	enclosing_frame = 1,
	declaration_frame = 2,
	local = 3
};

void pl0::execute(const bytecode & code, int entry_addr) {
	int pc = 0;
	int *stack = new int[STACK_SIZE];
	int *bp = stack;
	int *sp = bp;

	auto push = [&](auto value) -> void {
		if constexpr (std::is_pointer_v<decltype(value)>) {
			*++sp = reinterpret_cast<int>(value);
		} else {
			*++sp = value;
		}
	};

	auto pop = [&]() -> int {
		return *sp--;
	};

	const std::unordered_map<opt, std::function<int(int, int)>> bifunctors = {
		{ opt::ADD, std::plus<int>() },
		{ opt::SUB, std::minus<int>() },
		{ opt::DIV, std::divides<int>() },
		{ opt::MUL, std::multiplies<int>() },
		{ opt::LE, std::less<int>() },
		{ opt::LEQ, std::less_equal<int>() },
		{ opt::GE, std::greater<int>() },
		{ opt::GEQ, std::greater_equal<int>() },
		{ opt::EQ, std::equal_to<int>() },
		{ opt::NEQ, std::not_equal_to<int>() }
	};

    int codelen = static_cast<int>(code.size());
    bp[offset::return_address] = codelen;

	while (pc < codelen) {
        opcode opc;
        int level, address;
        std::tie(opc, level, address) = code[pc];
		pc++;

        /* get bp of the frame whose distance from current frame is given */
        auto resolve = [&]() -> int* {
            int *fp = bp, dist = level;
            while (dist > 0) {
                fp = reinterpret_cast<int*>(fp[offset::declaration_frame]);
                dist--;
            }
            return fp;
        };

		switch (opc) {
		case opcode::LIT:
			push(address);
			break;
		case opcode::LOD:
			push(resolve()[offset::local + address]);
			break;
		case opcode::STO:
			resolve()[offset::local + address] = pop();
			break;
		case opcode::CAL:
            // save context
            sp[0] = pc;
            sp[1] = reinterpret_cast<int>(bp);
            sp[2] = reinterpret_cast<int>(resolve());
            bp = sp;
			pc = address;
			break;
		case opcode::INT:
			sp += address;
			break;
		case opcode::JMP:
			pc = address;
			break;
		case opcode::JPC:
			if (!pop()) pc = address;
			break;
		case opcode::OPR:
			if (address == *opt::ODD) {
				push(pop() % 2);
			} else if (address == *opt::READ) {
				int tmp;
				std::cin >> tmp;
				push(tmp);
			} else if (address == *opt::WRITE) {
				std::cout << pop() << '\n';
			} else if (address == *opt::RET) {
                // restore context
                pc = bp[0];
                sp = bp;
                bp = reinterpret_cast<int*>(bp[1]);
			} else {
				int rhs = pop(), lhs = pop();
				auto op = bifunctors.find(opt(address))->second;
                push(op(lhs, rhs));
			}
			break;
		}
	}
}
<|endoftext|>