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

#ifndef MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP
#define MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP

#include <boost/fusion/include/adapt_struct.hpp>

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::geometry::point,
    (double, x)
    (double, y)
)

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::geometry::polygon,
    (mapnik::geometry::linear_ring const&, exterior_ring)
    (std::vector<mapnik::geometry::linear_ring> const& , interior_rings))

#endif // MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP
<commit_msg>add headers detected as needed by include-what-you-use<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP
#define MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP

#include <mapnik/geometry.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <vector>

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::geometry::point,
    (double, x)
    (double, y)
)

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::geometry::polygon,
    (mapnik::geometry::linear_ring const&, exterior_ring)
    (std::vector<mapnik::geometry::linear_ring> const& , interior_rings))

#endif // MAPNIK_GEOMETRY_FUSION_ADAPTED_HPP
<|endoftext|>


<commit_before>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_UI_CONNECTED_BUTTONS_HPP
#define RJ_UI_CONNECTED_BUTTONS_HPP

#include "button.hpp"
#include <rectojump/global/common.hpp>

#include <mlk/signals_slots/slot.h>

namespace rj
{
	namespace ui
	{
		template<typename T>
		using btn_ptr = mlk::sptr<T>;

		using base_btn_ptr = btn_ptr<button>;

		class connected_buttons : public sf::Drawable
		{
			std::map<int, base_btn_ptr> m_buttons;
			int m_current_pressed_index{0};
			int m_current_add_index{0};

		public:
			mlk::slot<base_btn_ptr&> on_active_button;
			mlk::slot<base_btn_ptr&> on_inactive_button;

			connected_buttons() = default;

			void update(dur duration)
			{
				for(auto& a : m_buttons)
				{
					// update all buttons
					a.second->update(duration);

					// get current pressed button
					on_inactive_button(a.second);
					if(a.second->is_pressed())
						m_current_pressed_index = a.first;
				}
				// call the custom user settings
				if(m_current_pressed_index != -1)
					on_active_button(m_buttons[m_current_pressed_index]);
			}

			template<typename Button_Type, typename... Args>
			btn_ptr<Button_Type> add_button(Args&&... args)
			{
				auto ptr(std::make_shared<Button_Type>(std::forward<Args>(args)...));
				m_buttons.emplace(m_current_add_index, ptr);
				++m_current_add_index;
				return ptr;
			}

			void inactivate() noexcept
			{m_current_pressed_index = -1;}

			const base_btn_ptr& get_active_btn() const noexcept
			{return m_buttons.at(m_current_pressed_index);}

		private:
			void draw(sf::RenderTarget& target, sf::RenderStates states) const override
			{
				for(auto& a : m_buttons)
					target.draw(*a.second, states);
			}
		};
	}
}

#endif // RJ_UI_CONNECTED_BUTTONS_HPP
<commit_msg>connected_buttons: added possibility to set custom events<commit_after>//
// Copyright (c) 2013-2014 Christoph Malek
// See LICENSE for more information.
//

#ifndef RJ_UI_CONNECTED_BUTTONS_HPP
#define RJ_UI_CONNECTED_BUTTONS_HPP

#include "button.hpp"
#include <rectojump/global/common.hpp>

#include <mlk/signals_slots/slot.h>

namespace rj
{
	namespace ui
	{
		template<typename T>
		using btn_ptr = mlk::sptr<T>;

		using base_btn_ptr = btn_ptr<button>;

		struct button_event
		{base_btn_ptr button; mlk::slot<> event;};

		class connected_buttons : public sf::Drawable
		{
			std::map<int, button_event> m_buttons;
			int m_current_pressed_index{0};
			int m_current_add_index{0};

		public:
			mlk::slot<base_btn_ptr&> on_active_button;
			mlk::slot<base_btn_ptr&> on_inactive_button;

			connected_buttons() = default;

			void update(dur duration)
			{
				for(auto& a : m_buttons)
				{
					// update all buttons
					a.second.button->update(duration);

					// get current pressed button
					on_inactive_button(a.second.button);
					if(a.second.button->is_pressed())
					{
						m_current_pressed_index = a.first;
						a.second.event();
					}
				}
				// call the custom user settings
				if(m_current_pressed_index != -1)
					on_active_button(m_buttons[m_current_pressed_index].button);
			}

			template<typename Button_Type, typename... Args>
			btn_ptr<Button_Type> add_button(Args&&... args)
			{
				auto ptr(std::make_shared<Button_Type>(std::forward<Args>(args)...));
				m_buttons.emplace(m_current_add_index, button_event{ptr, {}});
				++m_current_add_index;
				return ptr;
			}

			template<typename Button_Type, typename Func, typename... Args>
			btn_ptr<Button_Type> add_button_event(Func&& f, Args&&... args)
			{
				auto ptr(std::make_shared<Button_Type>(std::forward<Args>(args)...));
				m_buttons.emplace(m_current_add_index, button_event{ptr, {f}});
				++m_current_add_index;
				return ptr;
			}

			void inactivate() noexcept
			{m_current_pressed_index = -1;}

			const base_btn_ptr& get_active_btn() const noexcept
			{return m_buttons.at(m_current_pressed_index).button;}

		private:
			void draw(sf::RenderTarget& target, sf::RenderStates states) const override
			{
				for(auto& a : m_buttons)
					target.draw(*a.second.button, states);
			}
		};
	}
}

#endif // RJ_UI_CONNECTED_BUTTONS_HPP
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2014, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
 * Create default binning and initalise the binning component with this. In case
 * users already defined a binning, do not overwrite this.
 *
 *   Author: Markus Fasel
 */
#include "AliEMCalTriggerBinningComponent.h"
#include "AliEMCalTriggerBinningFactory.h"
#include <map>
#include <vector>
#include <TMath.h>
#include <TArrayD.h>

namespace EMCalTriggerPtAnalysis {

//______________________________________________________________________________
AliEMCalTriggerBinningFactory::AliEMCalTriggerBinningFactory() {
  /*
   * Default constructor, nothing to do
   */
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::Create(AliEMCalTriggerBinningComponent* const data) {
  /*
   * Initialise binning component with default binning
   *
   * @param data: the binning component to be initialised
   */
  TArrayD binLimits;
  if(!data->GetBinning("pt")){
    CreateDefaultPtBinning(binLimits);
    data->SetBinning("pt", binLimits);
  }
  if(!data->GetBinning("eta")){
    CreateDefaultEtaBinning(binLimits);
    data->SetBinning("eta", binLimits);
  }
  if(!data->GetBinning("phi")){
    CreateLinearBinning(binLimits, 100, 0, 2*TMath::Pi());
    data->SetBinning("phi", binLimits);
  }
  if(!data->GetBinning("zvertex")){
    CreateDefaultZVertexBinning(binLimits);
    data->SetBinning("zvertex", binLimits);
  }
  if(!data->GetBinning("centrality")){
	CreateLinearBinning(binLimits, 5, 0., 100.);
	data->SetBinning("centrality", binLimits);
  }
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultPtBinning(TArrayD &binning) const{
  /*
   * Creating the default pt binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  std::map<double,double> definitions;
  definitions.insert(std::pair<double,double>(2.5, 0.1));
  definitions.insert(std::pair<double,double>(7., 0.25));
  definitions.insert(std::pair<double,double>(15., 0.5));
  definitions.insert(std::pair<double,double>(25., 1.));
  definitions.insert(std::pair<double,double>(40., 2.5));
  definitions.insert(std::pair<double,double>(50., 5.));
  definitions.insert(std::pair<double,double>(100., 10.));
  definitions.insert(std::pair<double, double>(200., 20.));
  double currentval = 0;
  for(std::map<double,double>::iterator id = definitions.begin(); id != definitions.end(); ++id){
    double limit = id->first, binwidth = id->second;
    while(currentval < limit){
      currentval += binwidth;
      mybinning.push_back(currentval);
    }
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultZVertexBinning(TArrayD &binning) const {
  /*
   * Creating default z-Vertex binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  double currentval = -10;
  mybinning.push_back(currentval);
  while(currentval < 10.){
    currentval += 5.;
    mybinning.push_back(currentval);
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultEtaBinning(TArrayD& binning) const {
  /*
   * Creating default z-Vertex binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  double currentval = -0.8;
  mybinning.push_back(currentval);
  while(currentval < 0.8){
    currentval += 0.1;
    mybinning.push_back(currentval);
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateLinearBinning(TArrayD& binning, int nbins, double min, double max) const {
  /*
   * Create any kind of linear binning from given ranges and stores it in the binning array.
   *
   * @param binning: output array
   * @param nbins: Number of bins
   * @param min: lower range
   * @param max: upper range
   */
  double binwidth = (max-min)/static_cast<double>(nbins);
  binning.Set(nbins+1);
  binning[0] = min;
  double currentlimit = min + binwidth;
  for(int ibin = 0; ibin < nbins; ibin++){
    binning[ibin+1] = currentlimit;
    currentlimit += binwidth;
  }
}

} /* namespace EMCalTriggerPtAnalysis */
<commit_msg>Limit pt range again<commit_after>/**************************************************************************
 * Copyright(c) 1998-2014, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/
/*
 * Create default binning and initalise the binning component with this. In case
 * users already defined a binning, do not overwrite this.
 *
 *   Author: Markus Fasel
 */
#include "AliEMCalTriggerBinningComponent.h"
#include "AliEMCalTriggerBinningFactory.h"
#include <map>
#include <vector>
#include <TMath.h>
#include <TArrayD.h>

namespace EMCalTriggerPtAnalysis {

//______________________________________________________________________________
AliEMCalTriggerBinningFactory::AliEMCalTriggerBinningFactory() {
  /*
   * Default constructor, nothing to do
   */
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::Create(AliEMCalTriggerBinningComponent* const data) {
  /*
   * Initialise binning component with default binning
   *
   * @param data: the binning component to be initialised
   */
  TArrayD binLimits;
  if(!data->GetBinning("pt")){
    CreateDefaultPtBinning(binLimits);
    data->SetBinning("pt", binLimits);
  }
  if(!data->GetBinning("eta")){
    CreateDefaultEtaBinning(binLimits);
    data->SetBinning("eta", binLimits);
  }
  if(!data->GetBinning("phi")){
    CreateLinearBinning(binLimits, 100, 0, 2*TMath::Pi());
    data->SetBinning("phi", binLimits);
  }
  if(!data->GetBinning("zvertex")){
    CreateDefaultZVertexBinning(binLimits);
    data->SetBinning("zvertex", binLimits);
  }
  if(!data->GetBinning("centrality")){
	CreateLinearBinning(binLimits, 5, 0., 100.);
	data->SetBinning("centrality", binLimits);
  }
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultPtBinning(TArrayD &binning) const{
  /*
   * Creating the default pt binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  std::map<double,double> definitions;
  definitions.insert(std::pair<double,double>(2.5, 0.1));
  definitions.insert(std::pair<double,double>(7., 0.25));
  definitions.insert(std::pair<double,double>(15., 0.5));
  definitions.insert(std::pair<double,double>(25., 1.));
  definitions.insert(std::pair<double,double>(40., 2.5));
  definitions.insert(std::pair<double,double>(50., 5.));
  definitions.insert(std::pair<double,double>(100., 10.));
  //definitions.insert(std::pair<double, double>(200., 20.));
  double currentval = 0;
  for(std::map<double,double>::iterator id = definitions.begin(); id != definitions.end(); ++id){
    double limit = id->first, binwidth = id->second;
    while(currentval < limit){
      currentval += binwidth;
      mybinning.push_back(currentval);
    }
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultZVertexBinning(TArrayD &binning) const {
  /*
   * Creating default z-Vertex binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  double currentval = -10;
  mybinning.push_back(currentval);
  while(currentval < 10.){
    currentval += 5.;
    mybinning.push_back(currentval);
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateDefaultEtaBinning(TArrayD& binning) const {
  /*
   * Creating default z-Vertex binning.
   *
   * @param binning: Array where to store the results.
   */
  std::vector<double> mybinning;
  double currentval = -0.8;
  mybinning.push_back(currentval);
  while(currentval < 0.8){
    currentval += 0.1;
    mybinning.push_back(currentval);
  }
  binning.Set(mybinning.size());
  int ib = 0;
  for(std::vector<double>::iterator it = mybinning.begin(); it != mybinning.end(); ++it)
    binning[ib++] = *it;
}

//______________________________________________________________________________
void AliEMCalTriggerBinningFactory::CreateLinearBinning(TArrayD& binning, int nbins, double min, double max) const {
  /*
   * Create any kind of linear binning from given ranges and stores it in the binning array.
   *
   * @param binning: output array
   * @param nbins: Number of bins
   * @param min: lower range
   * @param max: upper range
   */
  double binwidth = (max-min)/static_cast<double>(nbins);
  binning.Set(nbins+1);
  binning[0] = min;
  double currentlimit = min + binwidth;
  for(int ibin = 0; ibin < nbins; ibin++){
    binning[ibin+1] = currentlimit;
    currentlimit += binwidth;
  }
}

} /* namespace EMCalTriggerPtAnalysis */
<|endoftext|>


<commit_before>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    const ssize_t read_result = sftp_read(file, v.data(), v.size());
    sftp_close(file);

    if (seek_result < 0 || read_result != ssize_t(v.size()))
     throw Exception("Error during sftp_read");

    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session),
  server_position(0)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::retry(std::function<void()> f, bool call_reset)
 ////////////////////////////////////////////////////////////////////////////
 {
  while (true)
  {
   try
   {
    f();
    return;
   }
   catch(const std::runtime_error &e)
   {
    if (trace)
     std::cerr << "Error: " << e.what() << '\n';
   }

   if (trace)
    std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

   std::this_thread::sleep_for(std::chrono::seconds(sleep_time));

   if (call_reset)
   {
    if (trace)
     std::cerr << "Trying to reconnect... ";
    try
    {
     if (trace)
      std::cerr << "Success!\n";
     reset();
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::lock_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->lock_pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->push_unlock(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  // Restoring the server position is better if we reset during a push
  const int64_t server_position = connection ?
   connection->server_position : 0;

  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );

  connection->server_position = server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level)
 {
  retry([this](){reset();}, false);
 }
}

#endif
<commit_msg>fix trace of robust connection<commit_after>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    const ssize_t read_result = sftp_read(file, v.data(), v.size());
    sftp_close(file);

    if (seek_result < 0 || read_result != ssize_t(v.size()))
     throw Exception("Error during sftp_read");

    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session),
  server_position(0)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::retry(std::function<void()> f, bool call_reset)
 ////////////////////////////////////////////////////////////////////////////
 {
  while (true)
  {
   try
   {
    f();
    return;
   }
   catch(const std::runtime_error &e)
   {
    if (trace)
     std::cerr << "Error: " << e.what() << '\n';
   }

   if (trace)
    std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

   std::this_thread::sleep_for(std::chrono::seconds(sleep_time));

   if (call_reset)
   {
    if (trace)
     std::cerr << "Trying to reconnect... ";
    try
    {
     reset();
     if (trace)
      std::cerr << "Success!\n";
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::lock_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->lock_pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->push_unlock(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  // Restoring the server position is better if we reset during a push
  const int64_t server_position = connection ?
   connection->server_position : 0;

  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );

  connection->server_position = server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level)
 {
  retry([this](){reset();}, false);
 }
}

#endif
<|endoftext|>


<commit_before>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    const ssize_t read_result = sftp_read(file, v.data(), v.size());
    sftp_close(file);

    if (seek_result < 0 || read_result != ssize_t(v.size()))
     throw Exception("Error during sftp_read");

    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session),
  server_position(0)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::retry(std::function<void()> f, bool call_reset)
 ////////////////////////////////////////////////////////////////////////////
 {
  while (true)
  {
   try
   {
    f();
    return;
   }
   catch(const std::runtime_error &e)
   {
    if (trace)
     std::cerr << "Error: " << e.what() << '\n';
   }

   if (trace)
    std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

   std::this_thread::sleep_for(std::chrono::seconds(sleep_time));

   if (call_reset)
   {
    try
    {
     reset();
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::lock_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->lock_pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->push_unlock(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level)
 {
  retry([this](){reset();}, false);
 }
}

#endif
<commit_msg>SSH_Robust_Connection: restore server position when resetting the connection.<commit_after>#ifdef JOEDB_HAS_SSH

#include "joedb/server/SSH_Connection.h"
#include "joedb/Exception.h"

#include <fcntl.h>
#include <thread>
#include <chrono>
#include <iostream>

//
// Windows does not define those
//
#ifndef S_IRUSR
#define	S_IRUSR	0000400
#endif

#ifndef S_IWUSR
#define	S_IWUSR	0000200
#endif

namespace joedb
{
 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::lock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": lock()... ";

  bool done = false;
  const int max_attempts = 60;

  for (int attempt = 1; attempt <= max_attempts; attempt++)
  {
   sftp_file file = sftp_open
   (
    sftp.get(),
    mutex_file_name.c_str(),
    O_CREAT | O_EXCL,
    S_IRUSR
   );

   if (file)
   {
    done = true;
    sftp_close(file);
    break;
   }
   else
   {
    if (trace)
     std::cerr << "Retrying(" << attempt << "/" << max_attempts << ")... ";
    std::this_thread::sleep_for(std::chrono::seconds(1));
   }
  }

  if (trace)
  {
   if (done)
    std::cerr << "done.\n";
   else
    std::cerr << "timeout.\n";
  }

  if (!done)
   throw Exception("SSH_Connection::lock: timeout");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::unlock()
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": unlock()\n";

  if (sftp_unlink(sftp.get(), mutex_file_name.c_str()) < 0)
   throw Exception("Error removing remote mutex");
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": pull()... ";

  server_position = 0;

  try
  {
   ssh::SFTP_Attributes attributes
   (
    sftp_stat(sftp.get(), remote_file_name.c_str())
   );

   server_position = int64_t(attributes.get()->size);
  }
  catch (const joedb::Exception &)
  {
  }

  const int64_t client_position = client_journal.get_checkpoint_position();

  if (client_position < server_position)
  {
   std::vector<char> v(size_t(server_position - client_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_RDONLY,
    S_IRUSR | S_IWUSR
   );

   if (file)
   {
    const int seek_result = sftp_seek64(file, uint64_t(client_position));
    const ssize_t read_result = sftp_read(file, v.data(), v.size());
    sftp_close(file);

    if (seek_result < 0 || read_result != ssize_t(v.size()))
     throw Exception("Error during sftp_read");

    client_journal.append_raw_tail(v);
   }
   else
    throw Exception("Could not open remote file for reading");
  }
  else if (server_position > 0 && client_position > server_position)
   throw Exception("Trying to pull when ahead of server");

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Connection::raw_push(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  if (trace)
   std::cerr << full_remote_name << ": push()... ";

  const int64_t client_position = client_journal.get_checkpoint_position();
  if (client_position > server_position)
  {
   std::vector<char> v(client_journal.get_raw_tail(server_position));

   if (trace)
    std::cerr << v.size() << " bytes... ";

   sftp_file file = sftp_open
   (
    sftp.get(),
    remote_file_name.c_str(),
    O_WRONLY | O_CREAT,
    S_IRUSR | S_IWUSR
   );

   const int seek_result = sftp_seek64(file, uint64_t(server_position));

   if (file)
   {
    //
    // https://tools.ietf.org/html/draft-ietf-secsh-filexfer-00
    //
    // The maximum size of a packet is in practise determined by the client
    // (the maximum size of read or write requests that it sends, plus a few
    // bytes of packet overhead).  All servers SHOULD support packets of at
    // least 34000 bytes (where the packet size refers to the full length,
    // including the header above).  This should allow for reads and writes of
    // at most 32768 bytes.
    //
    const size_t max_block_size = 32768;
    const size_t size = v.size();
    size_t written = 0;

    while (seek_result >= 0 && written < size)
    {
     size_t block_size = size - written;

     if (block_size > max_block_size)
      block_size = max_block_size;

     const ssize_t result = sftp_write(file, v.data() + written, block_size);

     if (result <= 0)
      break;

     written += size_t(result);
    }

    sftp_close(file);

    if (written < size)
     throw Exception("Incomplete write during push");
   }
   else
    throw Exception("Could not open remote file for writing");
  }

  if (trace)
   std::cerr << "done\n";
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Connection::SSH_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  remote_file_name(remote_file_name),
  trace(trace),
  mutex_file_name(remote_file_name + ".mutex"),
  full_remote_name(user + "@" + host + ":" + remote_file_name),
  session
  (
   user,
   host,
   port,
   ssh_log_level
  ),
  sftp(session),
  server_position(0)
 {
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::retry(std::function<void()> f, bool call_reset)
 ////////////////////////////////////////////////////////////////////////////
 {
  while (true)
  {
   try
   {
    f();
    return;
   }
   catch(const std::runtime_error &e)
   {
    if (trace)
     std::cerr << "Error: " << e.what() << '\n';
   }

   if (trace)
    std::cerr << "Sleeping for " << sleep_time << " seconds...\n";

   std::this_thread::sleep_for(std::chrono::seconds(sleep_time));

   if (call_reset)
   {
    if (trace)
     std::cerr << "Trying to reconnect... ";
    try
    {
     if (trace)
      std::cerr << "Success!\n";
     reset();
    }
    catch(const std::runtime_error &e)
    {
     if (trace)
      std::cerr << "Error: " << e.what() << '\n';
    }
   }
  }
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::lock_pull(Journal_File &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->lock_pull(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::push_unlock(Readonly_Journal &client_journal)
 ////////////////////////////////////////////////////////////////////////////
 {
  retry
  (
   [&client_journal,this](){connection->push_unlock(client_journal);},
   true
  );
 }

 ////////////////////////////////////////////////////////////////////////////
 void SSH_Robust_Connection::reset()
 ////////////////////////////////////////////////////////////////////////////
 {
  // Restoring the server position is better if we reset during a push
  const int64_t server_position = connection ?
   connection->server_position : 0;

  connection.reset
  (
   new SSH_Connection
   (
    user,
    host,
    port,
    remote_file_name,
    trace,
    ssh_log_level
   )
  );

  connection->server_position = server_position;
 }

 ////////////////////////////////////////////////////////////////////////////
 SSH_Robust_Connection::SSH_Robust_Connection
 ////////////////////////////////////////////////////////////////////////////
 (
  std::string user,
  std::string host,
  int port,
  std::string remote_file_name,
  bool trace,
  int ssh_log_level
 ):
  user(user),
  host(host),
  port(port),
  remote_file_name(remote_file_name),
  trace(trace),
  ssh_log_level(ssh_log_level)
 {
  retry([this](){reset();}, false);
 }
}

#endif
<|endoftext|>


<commit_before>#include "Command.h"

 #define DATABUFFERSIZE      80
 static char dataBuffer[DATABUFFERSIZE+1]; //Add 1 for NULL terminator
 static byte dataBufferIndex = 0;

 const char endChar = ';'; // or '!', or whatever your end character is
 static boolean storeString = false; //This will be our flag to put the data in our buffer

boolean getSerialString(){
    static byte dataBufferIndex = 0;
    while(Serial.available()>0){
        char incomingbyte = Serial.read();
 //       if(incomingbyte==startChar){
 //           dataBufferIndex = 0;  //Initialize our dataBufferIndex variable
       if (storeString == false) {
         storeString = true;
         dataBufferIndex=0;
        }
        if(storeString){
            //Let's check our index here, and abort if we're outside our buffer size
            //We use our define here so our buffer size can be easily modified
            if(dataBufferIndex==DATABUFFERSIZE){
                //Oops, our index is pointing to an array element outside our buffer.
                dataBufferIndex = 0;
                break;
            }
            if(incomingbyte==endChar){
                dataBuffer[dataBufferIndex] = 0; //null terminate the C string
                storeString = false;
                //Our data string is complete.  return true
                return true;
            }
            else{
                dataBuffer[dataBufferIndex++] = incomingbyte;
                dataBuffer[dataBufferIndex] = 0; //null terminate the C string
            }
        }
        else{
        }
    }

    //We've read in all the available Serial data, and don't have a valid string yet, so return false
    return false;
}

    int Command::_array[MAX_ARGS];
    int Command::args[MAX_ARGS];

// match from command received
boolean Command::cmp(char const* targetcommand){
  char* pos = strstr(dataBuffer, targetcommand);
  if(pos==dataBuffer) { //starts with
    return true;
  }
  return false;
}

// get string from buffer
boolean Command::get(){
  if(getSerialString()){
    //String available for parsing.  Parse it here
     parse();
     return true;
  }
  return false;
}

// get 'arguments' from command
void Command::parse(){
  char * pch;
  byte i = 0;
  pch = strtok (dataBuffer," ,();");
  while (pch != NULL){
    if (i == 0) {
      //this is the command text
     Serial.print(F("cmd:"));
     Serial.println(pch);
    } else {
      //this is a parameter
      args[i] = atoi(pch);
    }
    i++;
    pch = strtok (NULL," ,();");
  }
  args[0] = i;
}

<commit_msg>Clearing the prior message so that it does not repeat. Changed the socket.io sockets to volititle to prevent backups that stop the cockpit from responding<commit_after>#include "Command.h"

 #define DATABUFFERSIZE      80
 static char dataBuffer[DATABUFFERSIZE+1]; //Add 1 for NULL terminator
 static byte dataBufferIndex = 0;
 static boolean commandReady = false;
 const char endChar = ';'; // or '!', or whatever your end character is
 static boolean storeString = false; //This will be our flag to put the data in our buffer

boolean getSerialString(){
    static byte dataBufferIndex = 0;
    while(Serial.available()>0){
        char incomingbyte = Serial.read();
 //       if(incomingbyte==startChar){
 //           dataBufferIndex = 0;  //Initialize our dataBufferIndex variable
       if (storeString == false) {
         storeString = true;
         dataBufferIndex=0;
        }
        if(storeString){
            //Let's check our index here, and abort if we're outside our buffer size
            //We use our define here so our buffer size can be easily modified
            if(dataBufferIndex==DATABUFFERSIZE){
                //Oops, our index is pointing to an array element outside our buffer.
                dataBufferIndex = 0;
                break;
            }
            if(incomingbyte==endChar){
                dataBuffer[dataBufferIndex] = 0; //null terminate the C string
                storeString = false;
                //Our data string is complete.  return true
                return true;
            }
            else{
                dataBuffer[dataBufferIndex++] = incomingbyte;
                dataBuffer[dataBufferIndex] = 0; //null terminate the C string
            }
        }
        else{
        }
    }

    //We've read in all the available Serial data, and don't have a valid string yet, so return false
    return false;
}

    int Command::_array[MAX_ARGS];
    int Command::args[MAX_ARGS];

// match from command received
boolean Command::cmp(char const* targetcommand){
  if (!commandReady) return false;
  char* pos = strstr(dataBuffer, targetcommand);
  if(pos==dataBuffer) { //starts with
    return true;
  }
  return false;
}

// get string from buffer
boolean Command::get(){
  commandReady = false;
  if(getSerialString()){
    //String available for parsing.  Parse it here
     parse();
     commandReady = true;
     return true;
  }
  return false;
}

// get 'arguments' from command
void Command::parse(){
  char * pch;
  byte i = 0;
  pch = strtok (dataBuffer," ,();");
  while (pch != NULL){
    if (i == 0) {
      //this is the command text
     Serial.print(F("cmd:"));
     Serial.print(pch);
     Serial.print('(');
    } else {
      //this is a parameter
      args[i] = atoi(pch);
      if(i>1){
        Serial.print(',');
      }
      Serial.print(pch);
    }
    i++;
    pch = strtok (NULL," ,();");
  }
  Serial.println(");");
  args[0] = i;
}

<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "benchmark/reporter.h"
#include "complexity.h"

#include <cstdint>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>

#include "check.h"
#include "colorprint.h"
#include "commandlineflags.h"
#include "internal_macros.h"
#include "string_util.h"
#include "walltime.h"

namespace benchmark {

bool ConsoleReporter::ReportContext(const Context& context) {
  name_field_width_ = context.name_field_width;

  PrintBasicContext(&GetErrorStream(), context);

#ifdef BENCHMARK_OS_WINDOWS
  if (FLAGS_color_print && &std::cout != &GetOutputStream()) {
      GetErrorStream() << "Color printing is only supported for stdout on windows."
                          " Disabling color printing\n";
      FLAGS_color_print = false;
  }
#endif
  std::string str = FormatString("%-*s %13s %13s %10s\n",
                             static_cast<int>(name_field_width_), "Benchmark",
                             "Time", "CPU", "Iterations");
  GetOutputStream() << str << std::string(str.length() - 1, '-') << "\n";

  return true;
}

void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
  for (const auto& run : reports)
    PrintRunData(run);
}

void ConsoleReporter::PrintRunData(const Run& result) {
  auto& Out = GetOutputStream();

  auto name_color = (result.report_big_o || result.report_rms)
      ? COLOR_BLUE : COLOR_GREEN;
  ColorPrintf(Out, name_color, "%-*s ", name_field_width_,
              result.benchmark_name.c_str());

  if (result.error_occurred) {
    ColorPrintf(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'",
                result.error_message.c_str());
    ColorPrintf(Out, COLOR_DEFAULT, "\n");
    return;
  }
  // Format bytes per second
  std::string rate;
  if (result.bytes_per_second > 0) {
    rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s");
  }

  // Format items per second
  std::string items;
  if (result.items_per_second > 0) {
    items = StrCat(" ", HumanReadableNumber(result.items_per_second),
                   " items/s");
  }

  const double real_time = result.GetAdjustedRealTime();
  const double cpu_time = result.GetAdjustedCPUTime();

  if(result.report_big_o) {
    std::string big_o = result.report_big_o ? GetBigOString(result.complexity) : "";
    ColorPrintf(Out, COLOR_YELLOW, "%10.4f %s %10.4f %s ",
                real_time, big_o.c_str(), cpu_time, big_o.c_str());
  } else if(result.report_rms) {
    ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ",
                real_time * 100, cpu_time * 100);
  } else {
    const char* timeLabel = GetTimeUnitString(result.time_unit);
    ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ",
                real_time, timeLabel, cpu_time, timeLabel);
  }

  if(!result.report_big_o && !result.report_rms) {
    ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations);
  }

  if (!rate.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str());
  }

  if (!items.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %*s", 18, items.c_str());
  }

  if (!result.report_label.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %s", result.report_label.c_str());
  }

  ColorPrintf(Out, COLOR_DEFAULT, "\n");
}

}  // end namespace benchmark
<commit_msg>Fix missing declaration of FLAGS_color_print<commit_after>// Copyright 2015 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "benchmark/reporter.h"
#include "complexity.h"

#include <cstdint>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>

#include "check.h"
#include "colorprint.h"
#include "commandlineflags.h"
#include "internal_macros.h"
#include "string_util.h"
#include "walltime.h"

DECLARE_bool(color_print);

namespace benchmark {

bool ConsoleReporter::ReportContext(const Context& context) {
  name_field_width_ = context.name_field_width;

  PrintBasicContext(&GetErrorStream(), context);

#ifdef BENCHMARK_OS_WINDOWS
  if (FLAGS_color_print && &std::cout != &GetOutputStream()) {
      GetErrorStream() << "Color printing is only supported for stdout on windows."
                          " Disabling color printing\n";
      FLAGS_color_print = false;
  }
#endif
  std::string str = FormatString("%-*s %13s %13s %10s\n",
                             static_cast<int>(name_field_width_), "Benchmark",
                             "Time", "CPU", "Iterations");
  GetOutputStream() << str << std::string(str.length() - 1, '-') << "\n";

  return true;
}

void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
  for (const auto& run : reports)
    PrintRunData(run);
}

void ConsoleReporter::PrintRunData(const Run& result) {
  auto& Out = GetOutputStream();

  auto name_color = (result.report_big_o || result.report_rms)
      ? COLOR_BLUE : COLOR_GREEN;
  ColorPrintf(Out, name_color, "%-*s ", name_field_width_,
              result.benchmark_name.c_str());

  if (result.error_occurred) {
    ColorPrintf(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'",
                result.error_message.c_str());
    ColorPrintf(Out, COLOR_DEFAULT, "\n");
    return;
  }
  // Format bytes per second
  std::string rate;
  if (result.bytes_per_second > 0) {
    rate = StrCat(" ", HumanReadableNumber(result.bytes_per_second), "B/s");
  }

  // Format items per second
  std::string items;
  if (result.items_per_second > 0) {
    items = StrCat(" ", HumanReadableNumber(result.items_per_second),
                   " items/s");
  }

  const double real_time = result.GetAdjustedRealTime();
  const double cpu_time = result.GetAdjustedCPUTime();

  if(result.report_big_o) {
    std::string big_o = result.report_big_o ? GetBigOString(result.complexity) : "";
    ColorPrintf(Out, COLOR_YELLOW, "%10.4f %s %10.4f %s ",
                real_time, big_o.c_str(), cpu_time, big_o.c_str());
  } else if(result.report_rms) {
    ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ",
                real_time * 100, cpu_time * 100);
  } else {
    const char* timeLabel = GetTimeUnitString(result.time_unit);
    ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ",
                real_time, timeLabel, cpu_time, timeLabel);
  }

  if(!result.report_big_o && !result.report_rms) {
    ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations);
  }

  if (!rate.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %*s", 13, rate.c_str());
  }

  if (!items.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %*s", 18, items.c_str());
  }

  if (!result.report_label.empty()) {
    ColorPrintf(Out, COLOR_DEFAULT, " %s", result.report_label.c_str());
  }

  ColorPrintf(Out, COLOR_DEFAULT, "\n");
}

}  // end namespace benchmark
<|endoftext|>


<commit_before>#define STANDALONE 0
#define USE_INTERFACE 1
#include <scheme.h>
#include <scheme-private.h>

// Include standard headers
#include <iostream>      // std::cout, std::cin, std::cerr

// Based on https://github.com/dchest/tinyscheme/blob/master/example.c

pointer display(scheme* sc, pointer args)
{
    if (sc == nullptr)
    {
        std::cerr << "error: scheme* sc is nullptr\n";
        return nullptr;
    }

    if (args != sc->NIL)
    {
        if (sc->vptr->is_string(sc->vptr->pair_car(args)))
        {
            char* str = sc->vptr->string_value(sc->vptr->pair_car(args));
            printf("%s", str);
        }
    }
    return sc->NIL;
}

scheme* init_scheme()
{
    scheme* sc = scheme_init_new();

    if (sc == nullptr)
    {
        std::cerr << "error: scheme_init_new() failed\n";
        return nullptr;
    }

    FILE* init_file = fopen("init.scm", "r");

    if (init_file == nullptr)
    {
        std::cerr << "error loading init.scm\n";
        free(sc);
        return nullptr;
    }

    scheme_load_file(sc, init_file);
    fclose(init_file);

    sc->vptr->scheme_define(sc, sc->global_env, sc->vptr->mk_symbol(sc, "display"), sc->vptr->mk_foreign_func(sc, display));

    return sc;
}

bool do_stuff(scheme* sc)
{
    if (sc == nullptr)
    {
        std::cerr << "error: scheme* sc is nullptr\n";
        return false;
    }

    FILE* hello_world_file = fopen("hello_world.scm", "r");

    if (hello_world_file == nullptr)
    {
        std::cerr << "error loading hello_world.scm\n";
        return false;
    }
    scheme_load_file(sc, hello_world_file);
    fclose(hello_world_file);

    /* eval a C string as Scheme code */
    const char* hello_world_char = "(display \"Hello world!\n\")";
    scheme_load_string(sc, hello_world_char);

    return true;
}

int main(void)
{
    scheme* sc = init_scheme();

    if (sc == nullptr)
    {
        std::cerr << "error occurred in init_scheme function.\n";
        return 1;
    }

    if (!do_stuff(sc))
    {
        std::cerr << "error occurred in do_stuff function.\n";
        scheme_deinit(sc);
        return 1;
    }

    scheme_deinit(sc);
    return 0;
}
<commit_msg>`tinyscheme_test.cpp`: calling foreign C++ `cube` function works.<commit_after>#define STANDALONE 0
#define USE_INTERFACE 1
#include <scheme.h>
#include <scheme-private.h>

// Include standard headers
#include <iostream>      // std::cout, std::cin, std::cerr

// Based on https://github.com/dchest/tinyscheme/blob/master/example.c

pointer cube(scheme* sc, pointer args)
{
    if (sc == nullptr)
    {
        std::cerr << "error: scheme* sc is nullptr\n";
        return nullptr;
    }

    if (args == sc->NIL || !sc->vptr->is_number(sc->vptr->pair_car(args)))
    {
        return sc->NIL;
    }

    double value = sc->vptr->rvalue(sc->vptr->pair_car(args));
    return sc->vptr->mk_real(sc, value * value * value);
}

pointer display(scheme* sc, pointer args)
{
    if (sc == nullptr)
    {
        std::cerr << "error: scheme* sc is nullptr\n";
        return nullptr;
    }

    if (args != sc->NIL)
    {
        if (sc->vptr->is_string(sc->vptr->pair_car(args)))
        {
            char* str = sc->vptr->string_value(sc->vptr->pair_car(args));
            printf("%s", str);
        }
    }
    return sc->NIL;
}

scheme* init_scheme()
{
    scheme* sc = scheme_init_new();

    if (sc == nullptr)
    {
        std::cerr << "error: scheme_init_new() failed\n";
        return nullptr;
    }

    FILE* init_file = fopen("init.scm", "r");

    if (init_file == nullptr)
    {
        std::cerr << "error loading init.scm\n";
        free(sc);
        return nullptr;
    }

    scheme_load_file(sc, init_file);
    fclose(init_file);

    sc->vptr->scheme_define(sc, sc->global_env, sc->vptr->mk_symbol(sc, "cube"), sc->vptr->mk_foreign_func(sc, cube));
    sc->vptr->scheme_define(sc, sc->global_env, sc->vptr->mk_symbol(sc, "display"), sc->vptr->mk_foreign_func(sc, display));

    return sc;
}

bool do_stuff(scheme* sc)
{
    if (sc == nullptr)
    {
        std::cerr << "error: scheme* sc is nullptr\n";
        return false;
    }

    FILE* hello_world_file = fopen("hello_world.scm", "r");

    if (hello_world_file == nullptr)
    {
        std::cerr << "error loading hello_world.scm\n";
        return false;
    }
    scheme_load_file(sc, hello_world_file);
    fclose(hello_world_file);

    /* eval a C string as Scheme code */
    const char* hello_world_char = "(display \"Hello world!\n\")";
    scheme_load_string(sc, hello_world_char);

    const char* cube_char = "(display (string-append \"5.0 cubed is \" (number->string (cube 5.0)) \"\n\"))";
    scheme_load_string(sc, cube_char);

    const char* see_you_char = "(display \"See you!\n\")";
    scheme_load_string(sc, see_you_char);

    return true;
}

int main(void)
{
    scheme* sc = init_scheme();

    if (sc == nullptr)
    {
        std::cerr << "error occurred in init_scheme function.\n";
        return 1;
    }

    if (!do_stuff(sc))
    {
        std::cerr << "error occurred in do_stuff function.\n";
        scheme_deinit(sc);
        return 1;
    }

    scheme_deinit(sc);
    return 0;
}
<|endoftext|>


<commit_before>#include "compare.h"
#include <cassert>
#include <cmath>

int remove_single_exon_transcripts(genome &gm)
{
	for(int i = 0; i < gm.genes.size(); i++)
	{
		gm.genes[i].remove_single_exon_transcripts();
	}
	return 0;
}

bool compare_structure(const transcript &x, const transcript &y)
{
	if(x.exons.size() != y.exons.size()) return false;
	for(int i = 0; i < x.exons.size(); i++)
	{
		if(x.exons[i].first != y.exons[i].first) return false;
		if(x.exons[i].second != y.exons[i].second) return false;
	}
	return true;
}

bool compare_intron_chain(const transcript &x, const transcript &y)
{
	if(x.exons.size() != y.exons.size()) return false;

	if(x.exons.size() == 0) return false;

	if(x.exons.size() == 1)
	{
		if(fabs(x.exons[0].first - y.exons[0].first) > 100) return false;
		if(fabs(x.exons[0].second - y.exons[0].second) > 100) return false;
		return true;
	}

	for(int i = 0; i < x.exons.size(); i++)
	{
		double diff1 = 0.5;
		double diff2 = 0.5;
		if(i == 0) diff1 = 9999999999;
		if(i == x.exons.size() - 1) diff2 = 9999999999;

		if(fabs(x.exons[i].first - y.exons[i].first) > diff1) return false;
		if(fabs(x.exons[i].second - y.exons[i].second) > diff2) return false;
	}
	return true;
}

bool compare_expression(const transcript &x, const transcript &y)
{
	if(x.expression == y.expression) return true;
	else return false;
}

int compare_gene(const gene &x, const gene &y, int mode)
{
	return compare_transcripts(x.transcripts, y.transcripts, mode);
}

int compare_transcripts(const vector<transcript> &y, const vector<transcript> &x, int mode)
{
	int cnt = 0;
	vector<bool> v;
	v.assign(y.size(), false);
	for(int i = 0; i < x.size(); i++)
	{
		const transcript &t1 = x[i];
		bool flag = false;
		for(int j = 0; j < y.size(); j++)
		{
			if(v[j] == true) continue;
			const transcript &t2 = y[j];
			bool b = false;
			if(mode == 1)
			{
				if(compare_structure(t1, t2) == false) b = false;
				if(compare_expression(t1, t2) == false) b = false;
			}
			if(mode == 2)
			{
				b = compare_intron_chain(t1, t2);

				if(b == true)
				{
					printf("TRUE %s %s %s %c %d %lu %d %s %s %s %c %d %lu %d\n",
							t1.gene_id.c_str(), t1.transcript_id.c_str(), t1.label().c_str(), t1.strand, t1.expression, t1.exons.size(), t1.length(),
							t2.gene_id.c_str(), t2.transcript_id.c_str(), t2.label().c_str(), t2.strand, t2.expression, t2.exons.size(), t2.length());
				}

				if(t1.strand != t2.strand) b = false;
			}

			if(b == false) continue;

			flag = true;
			v[j] = true;
			cnt++;
			break;
		}

		if(flag == false) printf("FALSE %s %s %s %c %d %lu %d\n",
				t1.gene_id.c_str(), t1.transcript_id.c_str(), t1.label().c_str(), t1.strand, t1.expression, t1.exons.size(), t1.length());
	}
	return cnt;
}

int compare_gene_bounds(const gene &x, const gene &y)
{
	if(x.get_seqname() != y.get_seqname()) return 0;
	PI32 px = x.get_bounds();
	PI32 py = y.get_bounds();
	assert(px.first < px.second);
	assert(py.first < py.second);

	if(py.first < px.first && px.first < py.second && py.second < px.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d overlap1\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(px.first < py.first && py.first < px.second && px.second < py.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d overlap2\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(px.first <= py.first && px.second >= py.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d inclusive1\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(py.first <= px.first && py.second >= px.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d inclusive2\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);

	return 0;
}

int compare_genome1(const genome &x, const genome &y)
{
	int gequal = 0;
	int tequal = 0;
	int gtotal = x.genes.size();
	int ttotal = 0;
	for(int i = 0; i < x.genes.size(); i++)
	{
		const gene* gx = &(x.genes[i]);
		const gene* gy = y.get_gene(x.genes[i].get_gene_id());
		if(gx == NULL || gy == NULL) continue;
		int tx = gx->transcripts.size();
		int ty = gy->transcripts.size();
		int t0 = compare_gene(*gx, *gy, 1);
		assert(t0 <= tx);
		assert(t0 <= ty);
		ttotal += tx;
		tequal += t0;
		if(t0 == tx) gequal++;
		string s;
		if(tx == ty) s = "EQUAL";
		else if(tx > ty) s = "GREATER";
		else s = "LESS";
		printf("%s %d and %d transcripts, %d are equal, %s, %s\n", gx->get_gene_id().c_str(), tx, ty, t0, (t0 == tx) ? "TRUE" : "FALSE", s.c_str());
	}
	printf("summary: %d out of %d genes are equal, %d out of %d transcripts are equal\n",
			gequal, gtotal, tequal, ttotal);
	return 0;
}

int compare_genome2(const genome &x, const genome &y)
{
	typedef pair< string, vector<transcript> > PSVT;
	typedef map< string, vector<transcript> > MSVT;
	MSVT m1;
	MSVT m2;

	int xtotal = 0;
	int ytotal = 0;
	for(int i = 0; i < x.genes.size(); i++)
	{
		string chrm = x.genes[i].get_seqname();
		const vector<transcript> &v = x.genes[i].transcripts;
		xtotal += v.size();
		if(m1.find(chrm) == m1.end())
		{
			m1.insert(PSVT(chrm, v));
		}
		else
		{
			m1[chrm].insert(m1[chrm].end(), v.begin(), v.end());
		}
	}

	for(int i = 0; i < y.genes.size(); i++)
	{
		string chrm = y.genes[i].get_seqname();
		const vector<transcript> &v = y.genes[i].transcripts;
		ytotal += v.size();
		if(m2.find(chrm) == m2.end())
		{
			m2.insert(PSVT(chrm, v));
		}
		else
		{
			m2[chrm].insert(m2[chrm].end(), v.begin(), v.end());
		}
	}

	int correct = 0;
	for(MSVT::iterator it = m1.begin(); it != m1.end(); it++)
	{
		const vector<transcript> &v1 = it->second;
		if(m2.find(it->first) == m2.end()) continue;
		const vector<transcript> &v2 = m2[it->first];

		correct += compare_transcripts(v1, v2, 2);
	}

	double s = (xtotal == 0) ? 0 : correct * 100.0 / xtotal;
	double p = (ytotal == 0) ? 0 : correct * 100.0 / ytotal;
	printf("reference = %d prediction = %d correct = %d sensitivity = %.2lf precision = %.2lf\n", xtotal, ytotal, correct, s, p);

	return 0;
}

int compare_genome3(const genome &x, const genome &y)
{
	typedef pair< string, vector<int> > PSVI;
	typedef map< string, vector<int> > MSVI;
	MSVI m1;
	MSVI m2;

	for(int i = 0; i < x.genes.size(); i++)
	{
		string chrm = x.genes[i].get_seqname();
		if(m1.find(chrm) == m1.end())
		{
			vector<int> v;
			v.push_back(i);
			m1.insert(PSVI(chrm, v));
		}
		else
		{
			m1[chrm].push_back(i);
		}
	}

	for(int i = 0; i < y.genes.size(); i++)
	{
		string chrm = y.genes[i].get_seqname();
		if(m2.find(chrm) == m2.end())
		{
			vector<int> v;
			v.push_back(i);
			m2.insert(PSVI(chrm, v));
		}
		else
		{
			m2[chrm].push_back(i);
		}
	}

	for(MSVI::iterator it = m1.begin(); it != m1.end(); it++)
	{
		vector<int> v1 = it->second;
		if(m2.find(it->first) == m2.end()) continue;
		vector<int> v2 = m2[it->first];

		for(int i = 0; i < v1.size(); i++)
		{
			for(int j = 0; j < v2.size(); j++)
			{
				compare_gene_bounds(x.genes[v1[i]], y.genes[v2[j]]);
			}
		}
	}

	return 0;
}

<commit_msg>add coverage to gtfcompare<commit_after>#include "compare.h"
#include <cassert>
#include <cmath>

int remove_single_exon_transcripts(genome &gm)
{
	for(int i = 0; i < gm.genes.size(); i++)
	{
		gm.genes[i].remove_single_exon_transcripts();
	}
	return 0;
}

bool compare_structure(const transcript &x, const transcript &y)
{
	if(x.exons.size() != y.exons.size()) return false;
	for(int i = 0; i < x.exons.size(); i++)
	{
		if(x.exons[i].first != y.exons[i].first) return false;
		if(x.exons[i].second != y.exons[i].second) return false;
	}
	return true;
}

bool compare_intron_chain(const transcript &x, const transcript &y)
{
	if(x.exons.size() != y.exons.size()) return false;

	if(x.exons.size() == 0) return false;

	if(x.exons.size() == 1)
	{
		if(fabs(x.exons[0].first - y.exons[0].first) > 100) return false;
		if(fabs(x.exons[0].second - y.exons[0].second) > 100) return false;
		return true;
	}

	for(int i = 0; i < x.exons.size(); i++)
	{
		double diff1 = 0.5;
		double diff2 = 0.5;
		if(i == 0) diff1 = 9999999999;
		if(i == x.exons.size() - 1) diff2 = 9999999999;

		if(fabs(x.exons[i].first - y.exons[i].first) > diff1) return false;
		if(fabs(x.exons[i].second - y.exons[i].second) > diff2) return false;
	}
	return true;
}

bool compare_expression(const transcript &x, const transcript &y)
{
	if(x.expression == y.expression) return true;
	else return false;
}

int compare_gene(const gene &x, const gene &y, int mode)
{
	return compare_transcripts(x.transcripts, y.transcripts, mode);
}

int compare_transcripts(const vector<transcript> &y, const vector<transcript> &x, int mode)
{
	int cnt = 0;
	vector<bool> v;
	v.assign(y.size(), false);
	for(int i = 0; i < x.size(); i++)
	{
		const transcript &t1 = x[i];
		bool flag = false;
		for(int j = 0; j < y.size(); j++)
		{
			if(v[j] == true) continue;
			const transcript &t2 = y[j];
			bool b = false;
			if(mode == 1)
			{
				if(compare_structure(t1, t2) == false) b = false;
				if(compare_expression(t1, t2) == false) b = false;
			}
			if(mode == 2)
			{
				b = compare_intron_chain(t1, t2);

				if(b == true)
				{
					printf("TRUE %s %s %s %c %d %lu %d %.2lf %s %s %s %c %d %lu %d %.2lf\n",
							t1.gene_id.c_str(), t1.transcript_id.c_str(), t1.label().c_str(), t1.strand, t1.expression, t1.exons.size(), t1.length(), t1.coverage,
							t2.gene_id.c_str(), t2.transcript_id.c_str(), t2.label().c_str(), t2.strand, t2.expression, t2.exons.size(), t2.length(), t2.coverage);
				}

				if(t1.strand != t2.strand) b = false;
			}

			if(b == false) continue;

			flag = true;
			v[j] = true;
			cnt++;
			break;
		}

		if(flag == false) printf("FALSE %s %s %s %c %d %lu %d %.2lf\n",
				t1.gene_id.c_str(), t1.transcript_id.c_str(), t1.label().c_str(), t1.strand, t1.expression, t1.exons.size(), t1.length(), t1.coverage);
	}
	return cnt;
}

int compare_gene_bounds(const gene &x, const gene &y)
{
	if(x.get_seqname() != y.get_seqname()) return 0;
	PI32 px = x.get_bounds();
	PI32 py = y.get_bounds();
	assert(px.first < px.second);
	assert(py.first < py.second);

	if(py.first < px.first && px.first < py.second && py.second < px.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d overlap1\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(px.first < py.first && py.first < px.second && px.second < py.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d overlap2\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(px.first <= py.first && px.second >= py.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d inclusive1\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);
	if(py.first <= px.first && py.second >= px.second) printf("%s %c %s:%d-%d %s %c %s:%d-%d inclusive2\n", x.get_gene_id().c_str(), x.get_strand(), x.get_seqname().c_str(), px.first, px.second, y.get_gene_id().c_str(), y.get_strand(), y.get_seqname().c_str(), py.first, py.second);

	return 0;
}

int compare_genome1(const genome &x, const genome &y)
{
	int gequal = 0;
	int tequal = 0;
	int gtotal = x.genes.size();
	int ttotal = 0;
	for(int i = 0; i < x.genes.size(); i++)
	{
		const gene* gx = &(x.genes[i]);
		const gene* gy = y.get_gene(x.genes[i].get_gene_id());
		if(gx == NULL || gy == NULL) continue;
		int tx = gx->transcripts.size();
		int ty = gy->transcripts.size();
		int t0 = compare_gene(*gx, *gy, 1);
		assert(t0 <= tx);
		assert(t0 <= ty);
		ttotal += tx;
		tequal += t0;
		if(t0 == tx) gequal++;
		string s;
		if(tx == ty) s = "EQUAL";
		else if(tx > ty) s = "GREATER";
		else s = "LESS";
		printf("%s %d and %d transcripts, %d are equal, %s, %s\n", gx->get_gene_id().c_str(), tx, ty, t0, (t0 == tx) ? "TRUE" : "FALSE", s.c_str());
	}
	printf("summary: %d out of %d genes are equal, %d out of %d transcripts are equal\n",
			gequal, gtotal, tequal, ttotal);
	return 0;
}

int compare_genome2(const genome &x, const genome &y)
{
	typedef pair< string, vector<transcript> > PSVT;
	typedef map< string, vector<transcript> > MSVT;
	MSVT m1;
	MSVT m2;

	int xtotal = 0;
	int ytotal = 0;
	for(int i = 0; i < x.genes.size(); i++)
	{
		string chrm = x.genes[i].get_seqname();
		const vector<transcript> &v = x.genes[i].transcripts;
		xtotal += v.size();
		if(m1.find(chrm) == m1.end())
		{
			m1.insert(PSVT(chrm, v));
		}
		else
		{
			m1[chrm].insert(m1[chrm].end(), v.begin(), v.end());
		}
	}

	for(int i = 0; i < y.genes.size(); i++)
	{
		string chrm = y.genes[i].get_seqname();
		const vector<transcript> &v = y.genes[i].transcripts;
		ytotal += v.size();
		if(m2.find(chrm) == m2.end())
		{
			m2.insert(PSVT(chrm, v));
		}
		else
		{
			m2[chrm].insert(m2[chrm].end(), v.begin(), v.end());
		}
	}

	int correct = 0;
	for(MSVT::iterator it = m1.begin(); it != m1.end(); it++)
	{
		const vector<transcript> &v1 = it->second;
		if(m2.find(it->first) == m2.end()) continue;
		const vector<transcript> &v2 = m2[it->first];

		correct += compare_transcripts(v1, v2, 2);
	}

	double s = (xtotal == 0) ? 0 : correct * 100.0 / xtotal;
	double p = (ytotal == 0) ? 0 : correct * 100.0 / ytotal;
	printf("reference = %d prediction = %d correct = %d sensitivity = %.2lf precision = %.2lf\n", xtotal, ytotal, correct, s, p);

	return 0;
}

int compare_genome3(const genome &x, const genome &y)
{
	typedef pair< string, vector<int> > PSVI;
	typedef map< string, vector<int> > MSVI;
	MSVI m1;
	MSVI m2;

	for(int i = 0; i < x.genes.size(); i++)
	{
		string chrm = x.genes[i].get_seqname();
		if(m1.find(chrm) == m1.end())
		{
			vector<int> v;
			v.push_back(i);
			m1.insert(PSVI(chrm, v));
		}
		else
		{
			m1[chrm].push_back(i);
		}
	}

	for(int i = 0; i < y.genes.size(); i++)
	{
		string chrm = y.genes[i].get_seqname();
		if(m2.find(chrm) == m2.end())
		{
			vector<int> v;
			v.push_back(i);
			m2.insert(PSVI(chrm, v));
		}
		else
		{
			m2[chrm].push_back(i);
		}
	}

	for(MSVI::iterator it = m1.begin(); it != m1.end(); it++)
	{
		vector<int> v1 = it->second;
		if(m2.find(it->first) == m2.end()) continue;
		vector<int> v2 = m2[it->first];

		for(int i = 0; i < v1.size(); i++)
		{
			for(int j = 0; j < v2.size(); j++)
			{
				compare_gene_bounds(x.genes[v1[i]], y.genes[v2[j]]);
			}
		}
	}

	return 0;
}

<|endoftext|>