<commit_before>#include <iostream>
#include <ctime>
#include <fstream>
#include <Windows.h>
#include <string>

#include "..\include\Game.h"
#include "..\include\Common.h"

#include "..\include\PlayerTypes\PlayerTypes.h"
#include "..\include\EnemyTypes\EnemyTypes.h"

using namespace std;
using namespace Common;

// To avoid conflict with numeric_limits<streamsize>::max used in Game::GetChoice()
#ifdef max
#undef max
#endif

void Game::MainMenu(){
    // Main menu. Loops until you start
    // a game or quit.
	    for (int choice=0; choice!=3;){
        choice = GetChoice(MenuType::eMain);
        switch(choice){
			case 1:
           		StartGame();
				break;
			case 2:
				HowToPlay();
				break;
			case 3:
				break;
        }
    }
}

string Game::InitializePlayerName() {
	ClearScreen();
	string name;
	cout << "What is your name?"
		<< endl << endl
		<< "> ";

  cin.ignore();
	getline(cin,name); // Change to full name
	return name;
}

int Game::InitializePlayerClass() {
	// Initializes the player's class through user choice.
	int player_class = 0;
	player_class = GetChoice(MenuType::ePlayerClass);
	SetPlayerClass(player_class);
	return player_class;
}

void Game::SetPlayerClass(int player_class) {
	// Sets the Player class according to player code given.
	switch (player_class) {
	case 1:
		// Player's class is a warrior.
		_Player = new Warrior;
		break;
	case 2:
		// Player's class is a rogue.
		_Player = new Rogue;
		break;
	case 3:
		// Player's class is a healer.
		_Player = new Healer;
		break;
	case 4:
		// Player's class is a debugger.
		// Used to easily defeat enemies. Only for development purposes.
		_Player = new Debugger;
		break;
	case 5:
		// You are Saitama.
		// Do I have to explain??
		_Player = new Saitama;
		break;
	default:
		// If input does not equal any of the cases, the default class is a warrior.
		_Player = new Warrior;
		break;
	}
}

void Game::SetPlayerData(){
	/* Data initialized in order of:
	* class code
	* name
	* level
	* experience
	* health
	* arrows
	* bombs
	* potions
	* whetstones
	* weaponstrength
	* coins
	*/

	ifstream ReadData;
	ReadData.open("data.txt");

	// Runs if user has never played the game before or data is not found.
	if (!ReadData) {
		ReadData.close();
		ofstream WriteData;
		WriteData.open("data.txt");

		WriteData << InitializePlayerClass() << endl
			<< InitializePlayerName() << endl
			<< 1 << endl
			<< 0 << endl
			<< 100 << endl
			<< 10 << endl
			<< 1 << endl
			<< 1 << endl
			<< 1 << endl
			<< 100 << endl
			<< 0;
		WriteData.close();
	}

	else {
		// Initializes player type from class code given in data.txt
		int player_class;
		ReadData >> player_class;
		SetPlayerClass(player_class);
		ReadData.close();
	}
}

void Game::SetEnemy(){
    // Generates a random integer to determine class of the enemy.
    // The abstract class Enemy is morphed with one of its child classes.

    int selector = rand()%5;
    switch(selector){
        case 0:
            // Enemy is a crab.
            _Enemy = new Crab;
            break;
        case 1:
            // Enemy is a giant crab.
            _Enemy = new GiantCrab;
            break;
        case 2:
            // Enemy is a squid.
            _Enemy = new Squid;
            break;
        case 3:
            // Enemy is a giant squid.
            _Enemy = new GiantSquid;
            break;
		case 4:
			// Enemy is a Lich
			_Enemy = new Lich;
			break;
        default:
            // If the above cases do not match the selector for any reason,
            // the enemy defaults on the crab class.
            _Enemy = new Crab;
            break;
    }
    // Simply prints that the enemy's class was encountered.
	ColourPrint(_Enemy->GetName(), DARK_GREY);
    cout << " encountered!" << endl << endl;
    Sleep(SLEEP_MS);
}

bool Game::PlayAgain(){
    // Returns a bool value to determine if the player wants to play again.

    char choice;
    cout << "Keep going? (y/n)" << endl << endl;
    choice = (char)input();
    // Returns true if the player says yes (Y, y, 1).
    if (choice == 'y' || choice == 'Y' || choice == '1') return true;
    // Returns false otherwise, regardless of choice=='n'.
    return false;
}

void Game::Intermission(){
    // Saves game in case player unexpectedly quits (uses X instead of
    // in-game quit.
    _Player->SaveGame();

    // Loops until the player starts another battle or they quit (IsPlaying=false).
    for (int choice=0; IsPlaying;){
        ClearScreen();
        cout << "*--------- Intermission ----------* " << endl << endl;

	_Player->DisplayInventory();
        cout << "1) Start battle" << endl;
        cout << "2) Store" << endl;
        cout << "3) Gamble" << endl;
	cout << "4) Use Item" << endl;
        cout << "5) Quit" << endl << endl;

        choice = input();

        switch(choice){
        case 1:
            // Returns to StartGame()'s loop, calling Battle().
            return;
        case 2:
            // Goes to the store where the player can buy items.
            /// Currently in working progress.
            _Store.StoreFront(_Player);
            break;
        case 3:
            // Goes to the gambling arena.
            // _Player is passed in to add items won to the player inventory.
            _Gambling.Gamble(_Player);
            break;
	case 4:
	    _Player->UseItem();
	    _Player->SaveGame();
	    break;
        case 5:
            // Breaks the loop in StartGame(), going back to MainMenu().
            IsPlaying=false;
	    break;
        }
    }
}

void Game::StartGame(){
    // Starts the game by initializing values for a new game.

    // Seeds the random number generator for pseudo-random numbers.
    srand((unsigned int)time(NULL));
    IsPlaying=true;

    // SetPlayerData() initializes the variables in this end.
    ClearScreen();
    SetPlayerData();

	// This initializes the variables on the Player end.
    ClearScreen();
    _Player->SetPlayerData();

    // Loops while the game is still playing.
    // Alternates between battles and intermission (gambling, store, et)
    while(IsPlaying){
		Intermission();
		if (!IsPlaying)
			break;
		Battle();
    }

    // Saves the player's data to an external file before quitting.
    _Player->SaveGame();
}

void Game::Battle(){
    ClearScreen();
    // Uses random integers to determine class of the enemy.
    SetEnemy();

    // Loops the actual battle while playing.
    while(IsPlaying){
        ClearScreen();
        // Displays the name and health bar of the player and enemy.
        // The Enemy* argument is to display the enemy's
        // name. Explained more in _Player->DisplayHealthBar().
        _Player->DisplayHUD(_Enemy);
        _Enemy->DisplayHUD();

        // Player's turn to attack Enemy.
        _Enemy->TakeDamage(_Player->Attack());
        // Pauses console and ignores user input for SLEEP_MS milliseconds.
        Sleep(SLEEP_MS);

        // Leaves battle if player chooses to.
        if (!IsPlaying){
            IsPlaying = true;
            return;
        }

        // Executes when the enemy's health is 0 or below.
        if (_Enemy->IsDead()){
            // Adds drops to player's inventory from defeated enemy.
            _Player->AddToInventory(_Enemy->GetDrops());
            // Adds points to player's experience.
            _Player->AddExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			// If player wants to battle again, it breaks the loop and uses tail recursion to play again.
            if (PlayAgain()) break;
            // Returns to StartGame()'s loop, and executes Intermission().
            return;
        }

        // Enemy's turn to attack player.
        _Player->TakeDamage(_Enemy->Attack());
        Sleep(SLEEP_MS);

        // Executes when player's health is 0 or below.
        if (_Player->IsDead()){
            // Player loses the amount of experience points gained when you defeat the enemy.
            _Player->LoseExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			if (PlayAgain()) break;
            return;
        }
    }
    Battle();
}

void Game::HowToPlay() {

	GetChoice(MenuType::eHowToPlay);
}

int Game::GetChoice(MenuType menuType)
{
	DisplayMenu(menuType);
	int choice = -1;
	while (!(cin >> choice)) {
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Invalid input.  Please try again.";
		Sleep(SLEEP_MS);
		DisplayMenu(menuType);
	}
	return choice;
}

void Game::DisplayMenu(MenuType menuType)
{
	ClearScreen();
	switch (menuType)
	{
	case Game::eMain:
		cout << "========== TURN-BASED FIGHTING GAME ==========" << endl << endl
			<< "1) Start Game" << endl
			<< "2) How to play" << endl
			<< "3) Exit" << endl << endl << "> ";
		break;
	case Game::ePlayerClass:
		cout << endl
			<< "Which class do you want to play as?" << endl
			<< "1) Warrior (high damage, low healing capabilities)" << endl
			<< "2) Rogue (moderate damage, moderate healing capabilities)" << endl
			<< "3) Healer (low damage, high healing capabilities)" << endl
			<< "4) Debugger (INFINITE DAMAGE!!!!)" << endl
			<< "5) Saitama (self-explanatory)" << endl
			<< endl << endl
			<< "> ";
		break;
	case Game::eHowToPlay:
		cout << "============== HOW TO PLAY ==============" << endl << endl
			<< "Turn is a turn-based RPG game." << endl
			<< "Create your character and start playing." << endl
			<< "For playing you have to choose what to do by typing" << endl
			<< "the corresponding number." << endl
			<< "You can perform actions and use items." << endl << endl
			<< "-- Actions --" << endl
			<< "Attack: Regular attack" << endl
			<< "Risk Attack: Attack deals more damage, but with a chance of missing" << endl
			<< "Heal: Restore an amount of your HP" << endl
			<< "Flee: Run away from battle" << endl << endl
			<< "-- Items --" << endl
			<< "Bombs: Deals 50HP to your opponent with no chance of missing" << endl
			<< "Arrows: Deals 10-15HP to your opponent with no chance of missing" << endl
			<< "Potion: Replenishes your HP to 100" << endl
			<< "Whetstone: Restores your weapon's sharpness." << endl << endl
			<< "Good luck and have fun!" << endl << endl
			<< "1) Quit" << endl << endl << "> ";
		break;
	default:
		break;
	}
}<commit_msg>Update Game.cpp<commit_after>#include <iostream>
#include <ctime>
#include <fstream>
#include <Windows.h>
#include <string>

#include "..\include\Game.h"
#include "..\include\Common.h"

#include "..\include\PlayerTypes\PlayerTypes.h"
#include "..\include\EnemyTypes\EnemyTypes.h"

using namespace std;
using namespace Common;

// To avoid conflict with numeric_limits<streamsize>::max used in Game::GetChoice()
#ifdef max
#undef max
#endif

void Game::MainMenu(){
    // Main menu. Loops until you start
    // a game or quit.
	    for (int choice=0; choice!=3;){
        choice = GetChoice(MenuType::eMain);
        switch(choice){
			case 1:
           		StartGame();
				break;
			case 2:
				HowToPlay();
				break;
			case 3:
				break;
        }
    }
}

string Game::InitializePlayerName() {
	ClearScreen();
	string name;
	cout << "What is your name?"
		<< endl << endl
		<< "> ";

  cin.ignore();
	getline(cin,name); // Change to full name
	return name;
}

int Game::InitializePlayerClass() {
	// Initializes the player's class through user choice.
	int player_class = 0;
	player_class = GetChoice(MenuType::ePlayerClass);
	SetPlayerClass(player_class);
	return player_class;
}

void Game::SetPlayerClass(int player_class) {
	// Sets the Player class according to player code given.
	switch (player_class) {
	case 1:
		// Player's class is a warrior.
		_Player = new Warrior;
		break;
	case 2:
		// Player's class is a rogue.
		_Player = new Rogue;
		break;
	case 3:
		// Player's class is a healer.
		_Player = new Healer;
		break;
	case 4:
		// Player's class is a debugger.
		// Used to easily defeat enemies. Only for development purposes.
		_Player = new Debugger;
		break;
	case 5:
		// You are Saitama.
		// Do I have to explain??
		_Player = new Saitama;
		break;
	default:
		// If input does not equal any of the cases, the default class is a warrior.
		_Player = new Warrior;
		break;
	}
}

void Game::SetPlayerData(){
	/* Data initialized in order of:
	* class code
	* name
	* level
	* experience
	* health
	* arrows
	* bombs
	* potions
	* whetstones
	* weaponstrength
	* coins
	*/

	ifstream ReadData;
	ReadData.open("data.txt");

	// Runs if user has never played the game before or data is not found.
	if (!ReadData) {
		ReadData.close();
		ofstream WriteData;
		WriteData.open("data.txt");

		WriteData << InitializePlayerClass() << endl
			<< InitializePlayerName() << endl
			<< 1 << endl
			<< 0 << endl
			<< 100 << endl
			<< 10 << endl
			<< 1 << endl
			<< 1 << endl
			<< 1 << endl
			<< 100 << endl
			<< 0;
		WriteData.close();
	}

	else {
		// Initializes player type from class code given in data.txt
		int player_class;
		ReadData >> player_class;
		SetPlayerClass(player_class);
		ReadData.close();
	}
}

void Game::SetEnemy(){
    // Generates a random integer to determine class of the enemy.
    // The abstract class Enemy is morphed with one of its child classes.

    int selector = rand()%6;
    switch(selector){
        case 0:
            // Enemy is a crab.
            _Enemy = new Crab;
            break;
        case 1:
            // Enemy is a giant crab.
            _Enemy = new GiantCrab;
            break;
        case 2:
            // Enemy is a squid.
            _Enemy = new Squid;
            break;
        case 3:
            // Enemy is a giant squid.
            _Enemy = new GiantSquid;
            break;
		case 4:
			// Enemy is a Lich
			_Enemy = new Lich;
			break;
		case 5:
			// Enemy is a Putnafer
			_Enemy = new Putnafer;
			break;
        default:
            // If the above cases do not match the selector for any reason,
            // the enemy defaults on the crab class.
            _Enemy = new Crab;
            break;
    }
    // Simply prints that the enemy's class was encountered.
	ColourPrint(_Enemy->GetName(), DARK_GREY);
    cout << " encountered!" << endl << endl;
    Sleep(SLEEP_MS);
}

bool Game::PlayAgain(){
    // Returns a bool value to determine if the player wants to play again.

    char choice;
    cout << "Keep going? (y/n)" << endl << endl;
    choice = (char)input();
    // Returns true if the player says yes (Y, y, 1).
    if (choice == 'y' || choice == 'Y' || choice == '1') return true;
    // Returns false otherwise, regardless of choice=='n'.
    return false;
}

void Game::Intermission(){
    // Saves game in case player unexpectedly quits (uses X instead of
    // in-game quit.
    _Player->SaveGame();

    // Loops until the player starts another battle or they quit (IsPlaying=false).
    for (int choice=0; IsPlaying;){
        ClearScreen();
        cout << "*--------- Intermission ----------* " << endl << endl;

	_Player->DisplayInventory();
        cout << "1) Start battle" << endl;
        cout << "2) Store" << endl;
        cout << "3) Gamble" << endl;
	cout << "4) Use Item" << endl;
        cout << "5) Quit" << endl << endl;

        choice = input();

        switch(choice){
        case 1:
            // Returns to StartGame()'s loop, calling Battle().
            return;
        case 2:
            // Goes to the store where the player can buy items.
            /// Currently in working progress.
            _Store.StoreFront(_Player);
            break;
        case 3:
            // Goes to the gambling arena.
            // _Player is passed in to add items won to the player inventory.
            _Gambling.Gamble(_Player);
            break;
	case 4:
	    _Player->UseItem();
	    _Player->SaveGame();
	    break;
        case 5:
            // Breaks the loop in StartGame(), going back to MainMenu().
            IsPlaying=false;
	    break;
        }
    }
}

void Game::StartGame(){
    // Starts the game by initializing values for a new game.

    // Seeds the random number generator for pseudo-random numbers.
    srand((unsigned int)time(NULL));
    IsPlaying=true;

    // SetPlayerData() initializes the variables in this end.
    ClearScreen();
    SetPlayerData();

	// This initializes the variables on the Player end.
    ClearScreen();
    _Player->SetPlayerData();

    // Loops while the game is still playing.
    // Alternates between battles and intermission (gambling, store, et)
    while(IsPlaying){
		Intermission();
		if (!IsPlaying)
			break;
		Battle();
    }

    // Saves the player's data to an external file before quitting.
    _Player->SaveGame();
}

void Game::Battle(){
    ClearScreen();
    // Uses random integers to determine class of the enemy.
    SetEnemy();

    // Loops the actual battle while playing.
    while(IsPlaying){
        ClearScreen();
        // Displays the name and health bar of the player and enemy.
        // The Enemy* argument is to display the enemy's
        // name. Explained more in _Player->DisplayHealthBar().
        _Player->DisplayHUD(_Enemy);
        _Enemy->DisplayHUD();

        // Player's turn to attack Enemy.
        _Enemy->TakeDamage(_Player->Attack());
        // Pauses console and ignores user input for SLEEP_MS milliseconds.
        Sleep(SLEEP_MS);

        // Leaves battle if player chooses to.
        if (!IsPlaying){
            IsPlaying = true;
            return;
        }

        // Executes when the enemy's health is 0 or below.
        if (_Enemy->IsDead()){
            // Adds drops to player's inventory from defeated enemy.
            _Player->AddToInventory(_Enemy->GetDrops());
            // Adds points to player's experience.
            _Player->AddExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			// If player wants to battle again, it breaks the loop and uses tail recursion to play again.
            if (PlayAgain()) break;
            // Returns to StartGame()'s loop, and executes Intermission().
            return;
        }

        // Enemy's turn to attack player.
        _Player->TakeDamage(_Enemy->Attack());
        Sleep(SLEEP_MS);

        // Executes when player's health is 0 or below.
        if (_Player->IsDead()){
            // Player loses the amount of experience points gained when you defeat the enemy.
            _Player->LoseExperience(_Enemy->ReturnExperience());
			// Replenishes player's health for the next round.
			_Player->ReplenishHealth();

			if (PlayAgain()) break;
            return;
        }
    }
    Battle();
}

void Game::HowToPlay() {

	GetChoice(MenuType::eHowToPlay);
}

int Game::GetChoice(MenuType menuType)
{
	DisplayMenu(menuType);
	int choice = -1;
	while (!(cin >> choice)) {
		cin.clear();
		cin.ignore(numeric_limits<streamsize>::max(), '\n');
		cout << "Invalid input.  Please try again.";
		Sleep(SLEEP_MS);
		DisplayMenu(menuType);
	}
	return choice;
}

void Game::DisplayMenu(MenuType menuType)
{
	ClearScreen();
	switch (menuType)
	{
	case Game::eMain:
		cout << "========== TURN-BASED FIGHTING GAME ==========" << endl << endl
			<< "1) Start Game" << endl
			<< "2) How to play" << endl
			<< "3) Exit" << endl << endl << "> ";
		break;
	case Game::ePlayerClass:
		cout << endl
			<< "Which class do you want to play as?" << endl
			<< "1) Warrior (high damage, low healing capabilities)" << endl
			<< "2) Rogue (moderate damage, moderate healing capabilities)" << endl
			<< "3) Healer (low damage, high healing capabilities)" << endl
			<< "4) Debugger (INFINITE DAMAGE!!!!)" << endl
			<< "5) Saitama (self-explanatory)" << endl
			<< endl << endl
			<< "> ";
		break;
	case Game::eHowToPlay:
		cout << "============== HOW TO PLAY ==============" << endl << endl
			<< "Turn is a turn-based RPG game." << endl
			<< "Create your character and start playing." << endl
			<< "For playing you have to choose what to do by typing" << endl
			<< "the corresponding number." << endl
			<< "You can perform actions and use items." << endl << endl
			<< "-- Actions --" << endl
			<< "Attack: Regular attack" << endl
			<< "Risk Attack: Attack deals more damage, but with a chance of missing" << endl
			<< "Heal: Restore an amount of your HP" << endl
			<< "Flee: Run away from battle" << endl << endl
			<< "-- Items --" << endl
			<< "Bombs: Deals 50HP to your opponent with no chance of missing" << endl
			<< "Arrows: Deals 10-15HP to your opponent with no chance of missing" << endl
			<< "Potion: Replenishes your HP to 100" << endl
			<< "Whetstone: Restores your weapon's sharpness." << endl << endl
			<< "Good luck and have fun!" << endl << endl
			<< "1) Quit" << endl << endl << "> ";
		break;
	default:
		break;
	}
}
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH
#define DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH

#include <cmath>
#include <limits>
#include <type_traits>

#include <boost/numeric/conversion/cast.hpp>

#include <dune/stuff/common/crtp.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/type_utils.hh>

namespace Dune {
namespace Stuff {
namespace LA {

enum class ChooseBackend {
    common_dense
  , istl_sparse
  , eigen_dense
  , eigen_sparse
}; // enum class ChooseBackend

static constexpr ChooseBackend default_backend =
#if HAVE_EIGEN
                                                 ChooseBackend::eigen_sparse;
#elif HAVE_DUNE_ISTL
                                                 ChooseBackend::istl_sparse;
#else
                                                 ChooseBackend::common_dense;
#endif

static constexpr ChooseBackend default_sparse_backend =
#if HAVE_EIGEN
                                                        ChooseBackend::eigen_sparse;
#elif HAVE_DUNE_ISTL
                                                        ChooseBackend::istl_sparse;
#else
                                                        ChooseBackend::common_dense;
# error "There is no sparse LA backend available!"
#endif

static constexpr ChooseBackend default_dense_backend =
#if HAVE_EIGEN
                                                       ChooseBackend::eigen_dense;
#else
                                                       ChooseBackend::common_dense;
#endif

/**
 *  \brief  Contains tags mostly needed for python bindings.
 */
namespace Tags {

class ContainerInterface {};
class ProvidesDataAccess {};

} // namespace Tags
namespace internal {

/**
 * \brief Tries a boost::numeric_cast and throws an Exceptions::wrong_input_given on failure.
 *
 *        This can be used in the ctor initializer list.
 */
template< class Out, class In >
static Out boost_numeric_cast(const In& in)
{
  try {
    return boost::numeric_cast< Out >(in);
  } catch (boost::bad_numeric_cast& ee) {
    DUNE_THROW(Exceptions::wrong_input_given,
               "There was an error in boost converting '" << in << "' to '"
               << Common::Typename< Out >::value() << "': " << ee.what());
  }
} // ... boost_numeric_cast(...)

} // namespace internal

template< class Traits >
class ProvidesBackend
  : public CRTPInterface< ProvidesBackend< Traits >, Traits >
{
public:
  typedef typename Traits::BackendType BackendType;

  inline BackendType& backend()
  {
    CHECK_CRTP(this->as_imp().backend());
    return this->as_imp().backend();
  }

  inline const BackendType& backend() const
  {
    CHECK_CRTP(this->as_imp().backend());
    return this->as_imp().backend();
  }
}; // class ProvidesBackend

/**
 * \brief Interface for all containers (vectors and matrices).
 *
 * \note  All derived classes are supposed to implement copy-on-write. This can be achieved by internally holding a
 *        shared_prt to the appropriate backend and by passing this shared_prt around on copy, move or assingment. Any
 *        class method that writes to the backend or exposes a reference to the backend is then required to make a deep
 *        copy of the backend, if it is not the sole owner of this resource. This can for instance be achieved by
 *        calling a private method:
\code
  inline void ensure_uniqueness() const
  {
    if (!backend_.unique())
      backend_ = std::make_shared< BackendType >(*backend_);
  }
\endcode
 */
template< class Traits, class ScalarImp = typename Traits::ScalarType >
class ContainerInterface
  : public Tags::ContainerInterface
  , public CRTPInterface< ContainerInterface< Traits, ScalarImp >, Traits >
{
  typedef CRTPInterface< ContainerInterface< Traits, ScalarImp >, Traits > CRTP;
  static_assert(std::is_same< ScalarImp, typename Traits::ScalarType >::value, "");
public:
  typedef ScalarImp ScalarType;

  using typename CRTP::derived_type;

  virtual ~ContainerInterface() {}

  /// \name Have to be implemented by a derived class!
  /// \{

  /**
   * \brief   Creates a (deep) copy of the underlying resource
   * \return  A new container
   */
  inline derived_type copy() const
  {
    CHECK_CRTP(this->as_imp().copy());
    return this->as_imp().copy();
  }

  /**
   * \brief BLAS SCAL operation (in-place sclar multiplication).
   * \param alpha The scalar coefficient with which each element of the container is multiplied.
   */
  inline void scal(const ScalarType& alpha)
  {
    CHECK_AND_CALL_CRTP(this->as_imp().scal(alpha));
  }

  /**
   * \brief BLAS AXPY operation.
   * \param alpha The scalar coefficient with which each element of the container is multiplied
   * \param xx    Container that is to be elementwise added.
   */
  inline void axpy(const ScalarType& alpha, const derived_type& xx)
  {
    CHECK_AND_CALL_CRTP(this->as_imp().axpy(alpha, xx));
  }

  /**
   * \brief Test for equal sizes.
   * \param other Container the sizes of which this is to be compared to.
   */
  inline bool has_equal_shape(const derived_type& other) const
  {
    CHECK_CRTP(this->as_imp().has_equal_shape(other));
    return this->as_imp().has_equal_shape(other);
  }

  /// \}
  /// \name Are provided by the interface for convenience!
  /// \note Those marked as virtual may be implemented more efficiently in a derived class!
  /// \{

  static std::string type_this()
  {
    return Common::Typename< derived_type >::value();
  }

  virtual derived_type& operator*=(const ScalarType& alpha)
  {
    scal(alpha);
    return this->as_imp(*this);
  }
  /// \}
}; // class ContainerInterface

namespace internal {

template< class C >
struct is_container_helper
{
  DSC_has_typedef_initialize_once(Traits)
  DSC_has_typedef_initialize_once(ScalarType)

  static const bool is_candidate = DSC_has_typedef(Traits)< C >::value
                                   && DSC_has_typedef(ScalarType)< C >::value;
}; // class is_container_helper

} // namespace internal

template< class C, bool candidate = internal::is_container_helper< C >::is_candidate >
struct is_container
  : public std::is_base_of< ContainerInterface< typename C::Traits, typename C::ScalarType >, C >
{};

template< class C >
struct is_container< C, false >
  : public std::false_type
{};

template< class Traits >
class ProvidesConstContainer
  : public CRTPInterface< ProvidesConstContainer< Traits >, Traits >
{
public:
  typedef typename Traits::ContainerType ContainerType;

  inline std::shared_ptr< const ContainerType > container() const
  {
    CHECK_CRTP(this->as_imp().container());
    return this->as_imp().container();
  }
}; // class ProvidesConstContainer

template< class Traits >
class ProvidesContainer
  : public ProvidesConstContainer< Traits >
{
  typedef ProvidesConstContainer< Traits > BaseType;
public:
  typedef typename Traits::ContainerType ContainerType;

  using BaseType::container;

  inline std::shared_ptr< ContainerType > container()
  {
    CHECK_CRTP(this->as_imp().container());
    return this->as_imp().container();
  }
}; // class ProvidesContainer

template< class Traits >
class ProvidesDataAccess
  : public CRTPInterface< ProvidesDataAccess< Traits >, Traits >
  , public Tags::ProvidesDataAccess
{
public:
  typedef typename Traits::ScalarType ScalarType;

  inline ScalarType* data()
  {
    CHECK_CRTP(this->as_imp().data());
    return this->as_imp().data();
  }
}; // class ProvidesDataAccess

} // namespace LA
} // namespace Stuff
} // namespace Dune

#endif // #ifndef DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH
<commit_msg>[la.container.container-interface] add RealType to Interface<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff/
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//
// Contributors: Tobias Leibner

#ifndef DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH
#define DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH

#include <cmath>
#include <limits>
#include <type_traits>

#include <boost/numeric/conversion/cast.hpp>

#include <dune/stuff/common/crtp.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/type_utils.hh>

namespace Dune {
namespace Stuff {
namespace LA {

enum class ChooseBackend {
    common_dense
  , istl_sparse
  , eigen_dense
  , eigen_sparse
}; // enum class ChooseBackend

static constexpr ChooseBackend default_backend =
#if HAVE_EIGEN
                                                 ChooseBackend::eigen_sparse;
#elif HAVE_DUNE_ISTL
                                                 ChooseBackend::istl_sparse;
#else
                                                 ChooseBackend::common_dense;
#endif

static constexpr ChooseBackend default_sparse_backend =
#if HAVE_EIGEN
                                                        ChooseBackend::eigen_sparse;
#elif HAVE_DUNE_ISTL
                                                        ChooseBackend::istl_sparse;
#else
                                                        ChooseBackend::common_dense;
# error "There is no sparse LA backend available!"
#endif

static constexpr ChooseBackend default_dense_backend =
#if HAVE_EIGEN
                                                       ChooseBackend::eigen_dense;
#else
                                                       ChooseBackend::common_dense;
#endif

/**
 *  \brief  Contains tags mostly needed for python bindings.
 */
namespace Tags {

class ContainerInterface {};
class ProvidesDataAccess {};

} // namespace Tags
namespace internal {

/**
 * \brief Tries a boost::numeric_cast and throws an Exceptions::wrong_input_given on failure.
 *
 *        This can be used in the ctor initializer list.
 */
template< class Out, class In >
static Out boost_numeric_cast(const In& in)
{
  try {
    return boost::numeric_cast< Out >(in);
  } catch (boost::bad_numeric_cast& ee) {
    DUNE_THROW(Exceptions::wrong_input_given,
               "There was an error in boost converting '" << in << "' to '"
               << Common::Typename< Out >::value() << "': " << ee.what());
  }
} // ... boost_numeric_cast(...)

} // namespace internal

template< class Traits >
class ProvidesBackend
  : public CRTPInterface< ProvidesBackend< Traits >, Traits >
{
public:
  typedef typename Traits::BackendType BackendType;

  inline BackendType& backend()
  {
    CHECK_CRTP(this->as_imp().backend());
    return this->as_imp().backend();
  }

  inline const BackendType& backend() const
  {
    CHECK_CRTP(this->as_imp().backend());
    return this->as_imp().backend();
  }
}; // class ProvidesBackend

/**
 * \brief Interface for all containers (vectors and matrices).
 *
 * \note  All derived classes are supposed to implement copy-on-write. This can be achieved by internally holding a
 *        shared_prt to the appropriate backend and by passing this shared_prt around on copy, move or assingment. Any
 *        class method that writes to the backend or exposes a reference to the backend is then required to make a deep
 *        copy of the backend, if it is not the sole owner of this resource. This can for instance be achieved by
 *        calling a private method:
\code
  inline void ensure_uniqueness() const
  {
    if (!backend_.unique())
      backend_ = std::make_shared< BackendType >(*backend_);
  }
\endcode
 */
template< class Traits, class ScalarImp = typename Traits::ScalarType >
class ContainerInterface
  : public Tags::ContainerInterface
  , public CRTPInterface< ContainerInterface< Traits, ScalarImp >, Traits >
{
  typedef CRTPInterface< ContainerInterface< Traits, ScalarImp >, Traits > CRTP;
  static_assert(std::is_same< ScalarImp, typename Traits::ScalarType >::value, "");
public:
  typedef ScalarImp                 ScalarType;
  typedef typename Traits::RealType RealType;

  using typename CRTP::derived_type;

  virtual ~ContainerInterface() {}

  /// \name Have to be implemented by a derived class!
  /// \{

  /**
   * \brief   Creates a (deep) copy of the underlying resource
   * \return  A new container
   */
  inline derived_type copy() const
  {
    CHECK_CRTP(this->as_imp().copy());
    return this->as_imp().copy();
  }

  /**
   * \brief BLAS SCAL operation (in-place sclar multiplication).
   * \param alpha The scalar coefficient with which each element of the container is multiplied.
   */
  inline void scal(const ScalarType& alpha)
  {
    CHECK_AND_CALL_CRTP(this->as_imp().scal(alpha));
  }

  /**
   * \brief BLAS AXPY operation.
   * \param alpha The scalar coefficient with which each element of the container is multiplied
   * \param xx    Container that is to be elementwise added.
   */
  inline void axpy(const ScalarType& alpha, const derived_type& xx)
  {
    CHECK_AND_CALL_CRTP(this->as_imp().axpy(alpha, xx));
  }

  /**
   * \brief Test for equal sizes.
   * \param other Container the sizes of which this is to be compared to.
   */
  inline bool has_equal_shape(const derived_type& other) const
  {
    CHECK_CRTP(this->as_imp().has_equal_shape(other));
    return this->as_imp().has_equal_shape(other);
  }

  /// \}
  /// \name Are provided by the interface for convenience!
  /// \note Those marked as virtual may be implemented more efficiently in a derived class!
  /// \{

  static std::string type_this()
  {
    return Common::Typename< derived_type >::value();
  }

  virtual derived_type& operator*=(const ScalarType& alpha)
  {
    scal(alpha);
    return this->as_imp(*this);
  }
  /// \}
}; // class ContainerInterface

namespace internal {

template< class C >
struct is_container_helper
{
  DSC_has_typedef_initialize_once(Traits)
  DSC_has_typedef_initialize_once(ScalarType)

  static const bool is_candidate = DSC_has_typedef(Traits)< C >::value
                                   && DSC_has_typedef(ScalarType)< C >::value;
}; // class is_container_helper

} // namespace internal

template< class C, bool candidate = internal::is_container_helper< C >::is_candidate >
struct is_container
  : public std::is_base_of< ContainerInterface< typename C::Traits, typename C::ScalarType >, C >
{};

template< class C >
struct is_container< C, false >
  : public std::false_type
{};

template< class Traits >
class ProvidesConstContainer
  : public CRTPInterface< ProvidesConstContainer< Traits >, Traits >
{
public:
  typedef typename Traits::ContainerType ContainerType;

  inline std::shared_ptr< const ContainerType > container() const
  {
    CHECK_CRTP(this->as_imp().container());
    return this->as_imp().container();
  }
}; // class ProvidesConstContainer

template< class Traits >
class ProvidesContainer
  : public ProvidesConstContainer< Traits >
{
  typedef ProvidesConstContainer< Traits > BaseType;
public:
  typedef typename Traits::ContainerType ContainerType;

  using BaseType::container;

  inline std::shared_ptr< ContainerType > container()
  {
    CHECK_CRTP(this->as_imp().container());
    return this->as_imp().container();
  }
}; // class ProvidesContainer

template< class Traits >
class ProvidesDataAccess
  : public CRTPInterface< ProvidesDataAccess< Traits >, Traits >
  , public Tags::ProvidesDataAccess
{
public:
  typedef typename Traits::ScalarType ScalarType;

  inline ScalarType* data()
  {
    CHECK_CRTP(this->as_imp().data());
    return this->as_imp().data();
  }
}; // class ProvidesDataAccess

} // namespace LA
} // namespace Stuff
} // namespace Dune

#endif // #ifndef DUNE_STUFF_LA_CONTAINER_CONTAINER_INTERFACE_HH
<|endoftext|>


<commit_before>/*
    This file is part of libkcal.

    Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>

#include "todo.h"

using namespace KCal;

Todo::Todo()
{
  mHasDueDate = false;
  mHasStartDate = false;

  mHasCompletedDate = false;
  mPercentComplete = 0;
}

Todo::Todo(const Todo &t) : Incidence(t)
{
  mDtDue = t.mDtDue;
  mHasDueDate = t.mHasDueDate;
  mHasStartDate = t.mHasStartDate;
  mCompleted = t.mCompleted;
  mHasCompletedDate = t.mHasCompletedDate;
  mPercentComplete = t.mPercentComplete;
  mDtRecurrence = t.mDtRecurrence;
}

Todo::~Todo()
{
}

Todo *Todo::clone()
{
  return new Todo( *this );
}

bool Todo::operator==( const Todo& t2 ) const
{
    return
        static_cast<const Incidence&>(*this) == static_cast<const Incidence&>(t2) &&
        dtDue() == t2.dtDue() &&
        hasDueDate() == t2.hasDueDate() &&
        hasStartDate() == t2.hasStartDate() &&
        completed() == t2.completed() &&
        hasCompletedDate() == t2.hasCompletedDate() &&
        percentComplete() == t2.percentComplete();
}

void Todo::setDtDue(const QDateTime &dtDue, bool first )
{
  //int diffsecs = mDtDue.secsTo(dtDue);

  /*if (mReadOnly) return;
  const Alarm::List& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) {
    if (alarm->enabled()) {
      alarm->setTime(alarm->time().addSecs(diffsecs));
    }
  }*/
  if( doesRecur() && !first ) {
    mDtRecurrence = dtDue;
  } else {
    mDtDue = dtDue;
    recurrence()->setRecurStart( dtDue );
  }

  if ( doesRecur() && dtDue < recurrence()->recurStart() )
    setDtStart( dtDue );

  //kdDebug(5800) << "setDtDue says date is " << mDtDue.toString() << endl;

  /*const Alarm::List& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next())
    alarm->setAlarmStart(mDtDue);*/

  updated();
}

QDateTime Todo::dtDue( bool first ) const
{
  if ( doesRecur() && !first && mDtRecurrence.isValid() )
    return mDtRecurrence;

  return mDtDue;
}

QString Todo::dtDueTimeStr() const
{
  return KGlobal::locale()->formatTime( dtDue(!doesRecur()).time() );
}

QString Todo::dtDueDateStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDate(dtDue( !doesRecur() ).date(),shortfmt);
}

QString Todo::dtDueStr() const
{
  return KGlobal::locale()->formatDateTime( dtDue( !doesRecur() ) );
}

bool Todo::hasDueDate() const
{
  return mHasDueDate;
}

void Todo::setHasDueDate(bool f)
{
  if (mReadOnly) return;
  mHasDueDate = f;
  updated();
}

bool Todo::hasStartDate() const
{
  return mHasStartDate;
}

void Todo::setHasStartDate(bool f) // zie reinholds opmerking
{
  if (mReadOnly) return;

  if ( doesRecur() && !f ) {
    if ( !comments().grep("NoStartDate").count() )
      addComment("NoStartDate"); //TODO: --> custom flag?
  } else {
    QString s("NoStartDate");
    removeComment(s);
  }
  mHasStartDate = f;
  updated();
}

QDateTime Todo::dtStart( bool first ) const
{
  if ( doesRecur() && !first )
    return mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
  else
    return IncidenceBase::dtStart();
}

void Todo::setDtStart( const QDateTime &dtStart )
{
  if ( doesRecur() )
    recurrence()->setRecurStart( mDtDue );
  IncidenceBase::setDtStart( dtStart );
}

QString Todo::dtStartTimeStr( bool first ) const
{
  return KGlobal::locale()->formatTime(dtStart(first).time());
}

QString Todo::dtStartDateStr(bool shortfmt, bool first) const
{
  return KGlobal::locale()->formatDate(dtStart(first).date(),shortfmt);
}

QString Todo::dtStartStr(bool first) const
{
  return KGlobal::locale()->formatDateTime(dtStart(first));
}

bool Todo::isCompleted() const
{
  if (mPercentComplete == 100) return true;
  else return false;
}

void Todo::setCompleted(bool completed)
{
  if (completed) mPercentComplete = 100;
  else mPercentComplete = 0;
  updated();
}

QDateTime Todo::completed() const
{
  return mCompleted;
}

QString Todo::completedStr() const
{
  return KGlobal::locale()->formatDateTime(mCompleted);
}

void Todo::setCompleted(const QDateTime &completed)
{
  if( !recurTodo() ) {
    mHasCompletedDate = true;
    mPercentComplete = 100;
    mCompleted = completed;
  }
  updated();
}

bool Todo::hasCompletedDate() const
{
  return mHasCompletedDate;
}

int Todo::percentComplete() const
{
  return mPercentComplete;
}

void Todo::setPercentComplete(int v)
{
  mPercentComplete = v;
  updated();
}

void Todo::setDtRecurrence( const QDateTime &dt )
{
  mDtRecurrence = dt;
}

QDateTime Todo::dtRecurrence() const
{
  return mDtRecurrence.isValid() ? mDtRecurrence : mDtDue;
}

bool Todo::recursOn( const QDate &date )
{
  QDate today = QDate::currentDate();
  return ( Incidence::recursOn(date) &&
           !( date < today && mDtRecurrence.date() < today &&
              mDtRecurrence > recurrence()->recurStart() ) );
}

bool Todo::recurTodo()
{
  if ( doesRecur() ) {
    Recurrence *r = recurrence();
    QDateTime endDateTime = r->endDateTime();
    QDateTime nextDate = r->getNextDateTime( dtDue() );

    if ( ( r->duration() == -1 || ( nextDate.isValid() && endDateTime.isValid()
           && nextDate <= endDateTime ) ) ) {
      setDtDue( nextDate );
      while ( !recursAt( dtDue() ) || dtDue() <= QDateTime::currentDateTime() ) {
        setDtDue( r->getNextDateTime( dtDue() ) );
      }

      setCompleted( false );
      setRevision( revision() + 1 );

      return true;
    }
  }

  return false;
}

<commit_msg>CVS_SILENT Forgot to remove a Dutch comment.<commit_after>/*
    This file is part of libkcal.

    Copyright (c) 2001-2003 Cornelius Schumacher <schumacher@kde.org>

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

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

#include <kglobal.h>
#include <klocale.h>
#include <kdebug.h>

#include "todo.h"

using namespace KCal;

Todo::Todo()
{
  mHasDueDate = false;
  mHasStartDate = false;

  mHasCompletedDate = false;
  mPercentComplete = 0;
}

Todo::Todo(const Todo &t) : Incidence(t)
{
  mDtDue = t.mDtDue;
  mHasDueDate = t.mHasDueDate;
  mHasStartDate = t.mHasStartDate;
  mCompleted = t.mCompleted;
  mHasCompletedDate = t.mHasCompletedDate;
  mPercentComplete = t.mPercentComplete;
  mDtRecurrence = t.mDtRecurrence;
}

Todo::~Todo()
{
}

Todo *Todo::clone()
{
  return new Todo( *this );
}

bool Todo::operator==( const Todo& t2 ) const
{
    return
        static_cast<const Incidence&>(*this) == static_cast<const Incidence&>(t2) &&
        dtDue() == t2.dtDue() &&
        hasDueDate() == t2.hasDueDate() &&
        hasStartDate() == t2.hasStartDate() &&
        completed() == t2.completed() &&
        hasCompletedDate() == t2.hasCompletedDate() &&
        percentComplete() == t2.percentComplete();
}

void Todo::setDtDue(const QDateTime &dtDue, bool first )
{
  //int diffsecs = mDtDue.secsTo(dtDue);

  /*if (mReadOnly) return;
  const Alarm::List& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next()) {
    if (alarm->enabled()) {
      alarm->setTime(alarm->time().addSecs(diffsecs));
    }
  }*/
  if( doesRecur() && !first ) {
    mDtRecurrence = dtDue;
  } else {
    mDtDue = dtDue;
    recurrence()->setRecurStart( dtDue );
  }

  if ( doesRecur() && dtDue < recurrence()->recurStart() )
    setDtStart( dtDue );

  //kdDebug(5800) << "setDtDue says date is " << mDtDue.toString() << endl;

  /*const Alarm::List& alarms = alarms();
  for (Alarm* alarm = alarms.first(); alarm; alarm = alarms.next())
    alarm->setAlarmStart(mDtDue);*/

  updated();
}

QDateTime Todo::dtDue( bool first ) const
{
  if ( doesRecur() && !first && mDtRecurrence.isValid() )
    return mDtRecurrence;

  return mDtDue;
}

QString Todo::dtDueTimeStr() const
{
  return KGlobal::locale()->formatTime( dtDue(!doesRecur()).time() );
}

QString Todo::dtDueDateStr(bool shortfmt) const
{
  return KGlobal::locale()->formatDate(dtDue( !doesRecur() ).date(),shortfmt);
}

QString Todo::dtDueStr() const
{
  return KGlobal::locale()->formatDateTime( dtDue( !doesRecur() ) );
}

bool Todo::hasDueDate() const
{
  return mHasDueDate;
}

void Todo::setHasDueDate(bool f)
{
  if (mReadOnly) return;
  mHasDueDate = f;
  updated();
}

bool Todo::hasStartDate() const
{
  return mHasStartDate;
}

void Todo::setHasStartDate(bool f)
{
  if (mReadOnly) return;

  if ( doesRecur() && !f ) {
    if ( !comments().grep("NoStartDate").count() )
      addComment("NoStartDate"); //TODO: --> custom flag?
  } else {
    QString s("NoStartDate");
    removeComment(s);
  }
  mHasStartDate = f;
  updated();
}

QDateTime Todo::dtStart( bool first ) const
{
  if ( doesRecur() && !first )
    return mDtRecurrence.addDays( dtDue( true ).daysTo( IncidenceBase::dtStart() ) );
  else
    return IncidenceBase::dtStart();
}

void Todo::setDtStart( const QDateTime &dtStart )
{
  if ( doesRecur() )
    recurrence()->setRecurStart( mDtDue );
  IncidenceBase::setDtStart( dtStart );
}

QString Todo::dtStartTimeStr( bool first ) const
{
  return KGlobal::locale()->formatTime(dtStart(first).time());
}

QString Todo::dtStartDateStr(bool shortfmt, bool first) const
{
  return KGlobal::locale()->formatDate(dtStart(first).date(),shortfmt);
}

QString Todo::dtStartStr(bool first) const
{
  return KGlobal::locale()->formatDateTime(dtStart(first));
}

bool Todo::isCompleted() const
{
  if (mPercentComplete == 100) return true;
  else return false;
}

void Todo::setCompleted(bool completed)
{
  if (completed) mPercentComplete = 100;
  else mPercentComplete = 0;
  updated();
}

QDateTime Todo::completed() const
{
  return mCompleted;
}

QString Todo::completedStr() const
{
  return KGlobal::locale()->formatDateTime(mCompleted);
}

void Todo::setCompleted(const QDateTime &completed)
{
  if( !recurTodo() ) {
    mHasCompletedDate = true;
    mPercentComplete = 100;
    mCompleted = completed;
  }
  updated();
}

bool Todo::hasCompletedDate() const
{
  return mHasCompletedDate;
}

int Todo::percentComplete() const
{
  return mPercentComplete;
}

void Todo::setPercentComplete(int v)
{
  mPercentComplete = v;
  updated();
}

void Todo::setDtRecurrence( const QDateTime &dt )
{
  mDtRecurrence = dt;
}

QDateTime Todo::dtRecurrence() const
{
  return mDtRecurrence.isValid() ? mDtRecurrence : mDtDue;
}

bool Todo::recursOn( const QDate &date )
{
  QDate today = QDate::currentDate();
  return ( Incidence::recursOn(date) &&
           !( date < today && mDtRecurrence.date() < today &&
              mDtRecurrence > recurrence()->recurStart() ) );
}

bool Todo::recurTodo()
{
  if ( doesRecur() ) {
    Recurrence *r = recurrence();
    QDateTime endDateTime = r->endDateTime();
    QDateTime nextDate = r->getNextDateTime( dtDue() );

    if ( ( r->duration() == -1 || ( nextDate.isValid() && endDateTime.isValid()
           && nextDate <= endDateTime ) ) ) {
      setDtDue( nextDate );
      while ( !recursAt( dtDue() ) || dtDue() <= QDateTime::currentDateTime() ) {
        setDtDue( r->getNextDateTime( dtDue() ) );
      }

      setCompleted( false );
      setRevision( revision() + 1 );

      return true;
    }
  }

  return false;
}

<|endoftext|>


<commit_before>#include "riptide_hardware/dvl_processor.h"

int main(int argc, char **argv)
{
  ros::init(argc, argv, "dvl_processor");
  DVLProcessor dp;
  ros::spin();
}

DVLProcessor::DVLProcessor() : nh("dvl_processor")
{
  imu_state_sub = nh.subscribe<riptide_msgs::Imu>("/state/imu", 1, &DVLProcessor::ImuCB, this);
  dvl_data_sub = nh.subscribe<nortek_dvl::Dvl>("/dvl/dvl", 1, &DVLProcessor::DvlCB, this);

  dvl_state_pub = nh.advertise<nortek_dvl::Dvl>("/state/dvl", 1);
  // dvl_data_pub = nh.advertise<riptide_msgs::Dvl>("/state/dvl2", 1);

  // Load relative positions between DVL and COM from YAML file
  DVLProcessor::LoadParam<string>("properties_file", properties_file);
  properties = YAML::LoadFile(properties_file);
  DVLProcessor::LoadDVLProperties();
}

template <typename T>
void DVLProcessor::LoadParam(string param, T &var)
{
  try
  {
    if (!nh.getParam(param, var))
    {
      throw 0;
    }
  }
  catch (int e)
  {
    string ns = nh.getNamespace();
    ROS_ERROR("DVL Processor Namespace: %s", ns.c_str());
    ROS_ERROR("Critical! Param \"%s/%s\" does not exist or is not accessed correctly. SHutting down.", ns.c_str(), param.c_str());
    ros::shutdown();
  }
}

void DVLProcessor::LoadDVLProperties()
{
  for (int i = 0; i < 3; i++)
    dvl_position(i) = properties["properties"]["dvl"][i].as<double>() - properties["properties"]["center_of_mass"][i].as<double>();
  psi = properties["properties"]["dvl"][3].as<double>() * PI / 180;
}

void DVLProcessor::ImuCB(const riptide_msgs::Imu::ConstPtr &imu_msg)
{
  Vector3d angular_vel;
  angular_vel(0) = imu_msg->ang_vel_rad.x;
  angular_vel(1) = imu_msg->ang_vel_rad.y;
  angular_vel(2) = imu_msg->ang_vel_rad.z;
  relative_vel = angular_vel.cross(dvl_position);
  ROS_INFO(dvl_position);
}

void DVLProcessor::DvlCB(const nortek_dvl::Dvl::ConstPtr &dvl_msg)
{
  nortek_dvl::Dvl dvl_state(*dvl_msg);

  dvl_state.velocity.x = cos(psi) * dvl_msg->velocity.x + sin(psi) * dvl_msg->velocity.y - relative_vel(0);
  dvl_state.velocity.y = -sin(psi) * dvl_msg->velocity.x + cos(psi) * dvl_msg->velocity.y - relative_vel(1);
  dvl_state.velocity.z = dvl_msg->velocity.z - relative_vel(2);

  dvl_state_pub.publish(dvl_state);

  // riptide_msgs::Dvl dvl_state2(*dvl_state);

  // dvl_data_pub.publish(dvl_state2);

}<commit_msg>delete rosinfo<commit_after>#include "riptide_hardware/dvl_processor.h"

int main(int argc, char **argv)
{
  ros::init(argc, argv, "dvl_processor");
  DVLProcessor dp;
  ros::spin();
}

DVLProcessor::DVLProcessor() : nh("dvl_processor")
{
  imu_state_sub = nh.subscribe<riptide_msgs::Imu>("/state/imu", 1, &DVLProcessor::ImuCB, this);
  dvl_data_sub = nh.subscribe<nortek_dvl::Dvl>("/dvl/dvl", 1, &DVLProcessor::DvlCB, this);

  dvl_state_pub = nh.advertise<nortek_dvl::Dvl>("/state/dvl", 1);
  // dvl_data_pub = nh.advertise<riptide_msgs::Dvl>("/state/dvl2", 1);

  // Load relative positions between DVL and COM from YAML file
  DVLProcessor::LoadParam<string>("properties_file", properties_file);
  properties = YAML::LoadFile(properties_file);
  DVLProcessor::LoadDVLProperties();
}

template <typename T>
void DVLProcessor::LoadParam(string param, T &var)
{
  try
  {
    if (!nh.getParam(param, var))
    {
      throw 0;
    }
  }
  catch (int e)
  {
    string ns = nh.getNamespace();
    ROS_ERROR("DVL Processor Namespace: %s", ns.c_str());
    ROS_ERROR("Critical! Param \"%s/%s\" does not exist or is not accessed correctly. SHutting down.", ns.c_str(), param.c_str());
    ros::shutdown();
  }
}

void DVLProcessor::LoadDVLProperties()
{
  for (int i = 0; i < 3; i++)
    dvl_position(i) = properties["properties"]["dvl"][i].as<double>() - properties["properties"]["center_of_mass"][i].as<double>();
  psi = properties["properties"]["dvl"][3].as<double>() * PI / 180;
}

void DVLProcessor::ImuCB(const riptide_msgs::Imu::ConstPtr &imu_msg)
{
  Vector3d angular_vel;
  angular_vel(0) = imu_msg->ang_vel_rad.x;
  angular_vel(1) = imu_msg->ang_vel_rad.y;
  angular_vel(2) = imu_msg->ang_vel_rad.z;
  relative_vel = angular_vel.cross(dvl_position);
}

void DVLProcessor::DvlCB(const nortek_dvl::Dvl::ConstPtr &dvl_msg)
{
  nortek_dvl::Dvl dvl_state(*dvl_msg);

  dvl_state.velocity.x = cos(psi) * dvl_msg->velocity.x + sin(psi) * dvl_msg->velocity.y - relative_vel(0);
  dvl_state.velocity.y = -sin(psi) * dvl_msg->velocity.x + cos(psi) * dvl_msg->velocity.y - relative_vel(1);
  dvl_state.velocity.z = dvl_msg->velocity.z - relative_vel(2);

  dvl_state_pub.publish(dvl_state);

  // riptide_msgs::Dvl dvl_state2(*dvl_state);

  // dvl_data_pub.publish(dvl_state2);

}<|endoftext|>


<commit_before>#include "Threading.hpp"
#include "ThreadData.hpp"

#include "Config.hpp"
#include PLATFORM_PATH(PlatformSpecific_Threading.inl)
<commit_msg>-: Fix for commit 102<commit_after>#include "Threading.hpp"
#include "ThreadData.hpp"
#include <cassert>

#include "Config.hpp"
#include PLATFORM_PATH(PlatformSpecific_Threading.inl)
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file libheaptrack.cpp
 *
 * @brief Collect raw heaptrack data by overloading heap allocation functions.
 */

#include <cstdio>
#include <stdio_ext.h>
#include <cstdlib>

#include <atomic>
#include <unordered_map>
#include <string>
#include <tuple>
#include <memory>
#include <unordered_set>

#include <boost/algorithm/string/replace.hpp>

#include <dlfcn.h>
#include <link.h>

#include "tracetree.h"
#include "timer.h"

/**
 * uncomment this to get extended debug code for known pointers
 * there are still some malloc functions I'm missing apparently,
 * related to TLS and such I guess
 */
// #define DEBUG_MALLOC_PTRS

using namespace std;

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);
using dlclose_t = int (*) (void*);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;
dlclose_t real_dlclose = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

/**
 * Similar to std::lock_guard but operates on the internal stream lock of a FILE*.
 */
class LockGuard
{
public:
    LockGuard(FILE* file)
        : file(file)
    {
        flockfile(file);
    }

    ~LockGuard()
    {
        funlockfile(file);
    }

private:
    FILE* file;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

void prepare_fork();
void parent_fork();
void child_fork();

struct Data
{
    Data()
    {
        pthread_atfork(&prepare_fork, &parent_fork, &child_fork);

        string outputFileName = env("DUMP_HEAPTRACK_OUTPUT");
        if (outputFileName.empty()) {
            // env var might not be set when linked directly into an executable
            outputFileName = "heaptrack.$$";
        } else if (outputFileName == "-" || outputFileName == "stdout") {
            out = stdout;
        } else if (outputFileName == "stderr") {
            out = stderr;
        }

        if (!out) {
            boost::replace_all(outputFileName, "$$", to_string(getpid()));
            out = fopen(outputFileName.c_str(), "w");
            __fsetlocking(out, FSETLOCKING_BYCALLER);
        }

        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        // TODO: remember meta data about host application, such as cmdline, date of run, ...

        // cleanup environment to prevent tracing of child apps
        unsetenv("DUMP_HEAPTRACK_OUTPUT");
        unsetenv("LD_PRELOAD");

        timer.setInterval(1, 0);
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        if (out) {
            fclose(out);
        }
    }

    void updateModuleCache()
    {
        fprintf(out, "m -\n");
        foundExe = false;
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (!data->foundExe) {
                isExe = true;
                data->foundExe = true;
                ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                const uintptr_t addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                const uintptr_t addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                fprintf(data->out, "m %s %d %lx %lx\n", fileName, isExe, addressStart, addressEnd);
            }
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        Trace trace;
        if (!trace.fill()) {
            return;
        }

        LockGuard lock(out);
        if (lastTimerElapsed != timer.timesElapsed()) {
            lastTimerElapsed = timer.timesElapsed();
            fprintf(out, "c %lx\n", lastTimerElapsed);
        }
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        const size_t index = traceTree.index(trace, out);

#ifdef DEBUG_MALLOC_PTRS
        auto it = known.find(ptr);
        assert(it == known.end());
        known.insert(ptr);
#endif

        fprintf(out, "+ %lx %lx %lx\n", size, index, reinterpret_cast<uintptr_t>(ptr));
    }

    void handleFree(void* ptr)
    {
        LockGuard lock(out);

#ifdef DEBUG_MALLOC_PTRS
        auto it = known.find(ptr);
        assert(it != known.end());
        known.erase(it);
#endif

        fprintf(out, "- %lx\n", reinterpret_cast<uintptr_t>(ptr));
    }

    TraceTree traceTree;
    /**
     * Note: We use the C stdio API here for performance reasons.
     *       Esp. in multi-threaded environments this is much faster
     *       to produce non-per-line-interleaved output.
     */
    FILE* out = nullptr;

    size_t lastTimerElapsed = 0;
    Timer timer;

    bool foundExe = false;
#ifdef DEBUG_MALLOC_PTRS
    unordered_set<void*> known;
#endif

};

unique_ptr<Data> data;

void prepare_fork()
{
    // don't do any custom malloc handling while inside fork
    HandleGuard::inHandler = true;
}

void parent_fork()
{
    // the parent process can now continue its custom malloc tracking
    HandleGuard::inHandler = false;
}

void child_fork()
{
    // but the forked child process cleans up itself
    // this is important to prevent two processes writing to the same file
    if (data) {
        data->out = nullptr;
        data.reset(nullptr);
    }
    HandleGuard::inHandler = true;
}

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    if (data || HandleGuard::inHandler) {
        fprintf(stderr, "initialization recursion detected\n");
        abort();
    }

    HandleGuard guard;

    real_calloc = &dummy_calloc;
    real_calloc = findReal<calloc_t>("calloc");
    real_dlopen = findReal<dlopen_t>("dlopen");
    real_dlclose = findReal<dlclose_t>("dlclose");
    real_malloc = findReal<malloc_t>("malloc");
    real_free = findReal<free_t>("free");
    real_realloc = findReal<realloc_t>("realloc");
    real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
    real_valloc = findReal<valloc_t>("valloc");
    real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

    if (unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD)) {
        fprintf(stderr, "Failed to enable per-thread libunwind caching.\n");
    }
    if (unw_set_cache_log_size(unw_local_addr_space, 10)) {
        fprintf(stderr, "Failed to set libunwind cache size.\n");
    }

    data.reset(new Data);
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    // call handler before handing over the real free implementation
    // to ensure the ptr is not reused in-between and thus the output
    // stays consistent
    if (ptr && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleFree(ptr);
    }

    real_free(ptr);
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        if (ptr) {
            data->handleFree(ptr);
        }
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

int dlclose(void *handle)
{
    if (!real_dlclose) {
        init();
    }

    int ret = real_dlclose(handle);

    if (!ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<commit_msg>Ensure we only ever initialize once.<commit_after>/*
 * Copyright 2014 Milian Wolff <mail@milianw.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Library General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/**
 * @file libheaptrack.cpp
 *
 * @brief Collect raw heaptrack data by overloading heap allocation functions.
 */

#include <cstdio>
#include <stdio_ext.h>
#include <cstdlib>

#include <atomic>
#include <unordered_map>
#include <string>
#include <tuple>
#include <memory>
#include <unordered_set>
#include <mutex>

#include <boost/algorithm/string/replace.hpp>

#include <dlfcn.h>
#include <link.h>

#include "tracetree.h"
#include "timer.h"

/**
 * uncomment this to get extended debug code for known pointers
 * there are still some malloc functions I'm missing apparently,
 * related to TLS and such I guess
 */
// #define DEBUG_MALLOC_PTRS

using namespace std;

namespace {

using malloc_t = void* (*) (size_t);
using free_t = void (*) (void*);
using realloc_t = void* (*) (void*, size_t);
using calloc_t = void* (*) (size_t, size_t);
using posix_memalign_t = int (*) (void **, size_t, size_t);
using valloc_t = void* (*) (size_t);
using aligned_alloc_t = void* (*) (size_t, size_t);
using dlopen_t = void* (*) (const char*, int);
using dlclose_t = int (*) (void*);

malloc_t real_malloc = nullptr;
free_t real_free = nullptr;
realloc_t real_realloc = nullptr;
calloc_t real_calloc = nullptr;
posix_memalign_t real_posix_memalign = nullptr;
valloc_t real_valloc = nullptr;
aligned_alloc_t real_aligned_alloc = nullptr;
dlopen_t real_dlopen = nullptr;
dlclose_t real_dlclose = nullptr;

// threadsafe stuff
atomic<bool> moduleCacheDirty(true);

struct HandleGuard
{
    HandleGuard()
        : wasLocked(inHandler)
    {
        inHandler = true;
    }

    ~HandleGuard()
    {
        inHandler = wasLocked;
    }

    const bool wasLocked;
    static thread_local bool inHandler;
};

/**
 * Similar to std::lock_guard but operates on the internal stream lock of a FILE*.
 */
class LockGuard
{
public:
    LockGuard(FILE* file)
        : file(file)
    {
        flockfile(file);
    }

    ~LockGuard()
    {
        funlockfile(file);
    }

private:
    FILE* file;
};

thread_local bool HandleGuard::inHandler = false;

string env(const char* variable)
{
    const char* value = getenv(variable);
    return value ? string(value) : string();
}

void prepare_fork();
void parent_fork();
void child_fork();

struct Data
{
    Data()
    {
        pthread_atfork(&prepare_fork, &parent_fork, &child_fork);

        string outputFileName = env("DUMP_HEAPTRACK_OUTPUT");
        if (outputFileName.empty()) {
            // env var might not be set when linked directly into an executable
            outputFileName = "heaptrack.$$";
        } else if (outputFileName == "-" || outputFileName == "stdout") {
            out = stdout;
        } else if (outputFileName == "stderr") {
            out = stderr;
        }

        if (!out) {
            boost::replace_all(outputFileName, "$$", to_string(getpid()));
            out = fopen(outputFileName.c_str(), "w");
            __fsetlocking(out, FSETLOCKING_BYCALLER);
        }

        if (!out) {
            fprintf(stderr, "Failed to open output file: %s\n", outputFileName.c_str());
            exit(1);
        }

        // TODO: remember meta data about host application, such as cmdline, date of run, ...

        // cleanup environment to prevent tracing of child apps
        unsetenv("DUMP_HEAPTRACK_OUTPUT");
        unsetenv("LD_PRELOAD");

        timer.setInterval(1, 0);
    }

    ~Data()
    {
        HandleGuard::inHandler = true;
        if (out) {
            fclose(out);
        }
    }

    void updateModuleCache()
    {
        fprintf(out, "m -\n");
        foundExe = false;
        dl_iterate_phdr(dlopen_notify_callback, this);
        moduleCacheDirty = false;
    }

    /**
     * Mostly copied from vogl's src/libbacktrace/btrace.cpp
     */
    static int dlopen_notify_callback(struct dl_phdr_info *info, size_t /*size*/, void *_data)
    {
        auto data = reinterpret_cast<Data*>(_data);
        bool isExe = false;
        const char *fileName = info->dlpi_name;
        const int BUF_SIZE = 1024;
        char buf[BUF_SIZE];
        // If we don't have a filename and we haven't added our main exe yet, do it now.
        if (!fileName || !fileName[0]) {
            if (!data->foundExe) {
                isExe = true;
                data->foundExe = true;
                ssize_t ret = readlink("/proc/self/exe", buf, sizeof(buf));
                if ((ret > 0) && (ret < (ssize_t)sizeof(buf))) {
                    buf[ret] = 0;
                    fileName = buf;
                }
            }
            if (!fileName || !fileName[0]) {
                return 0;
            }
        }

        for (int i = 0; i < info->dlpi_phnum; i++) {
            if (info->dlpi_phdr[i].p_type == PT_LOAD) {
                const uintptr_t addressStart = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
                const uintptr_t addressEnd = addressStart + info->dlpi_phdr[i].p_memsz;
                fprintf(data->out, "m %s %d %lx %lx\n", fileName, isExe, addressStart, addressEnd);
            }
        }

        return 0;
    }

    void handleMalloc(void* ptr, size_t size)
    {
        Trace trace;
        if (!trace.fill()) {
            return;
        }

        LockGuard lock(out);
        if (lastTimerElapsed != timer.timesElapsed()) {
            lastTimerElapsed = timer.timesElapsed();
            fprintf(out, "c %lx\n", lastTimerElapsed);
        }
        if (moduleCacheDirty) {
            updateModuleCache();
        }
        const size_t index = traceTree.index(trace, out);

#ifdef DEBUG_MALLOC_PTRS
        auto it = known.find(ptr);
        assert(it == known.end());
        known.insert(ptr);
#endif

        fprintf(out, "+ %lx %lx %lx\n", size, index, reinterpret_cast<uintptr_t>(ptr));
    }

    void handleFree(void* ptr)
    {
        LockGuard lock(out);

#ifdef DEBUG_MALLOC_PTRS
        auto it = known.find(ptr);
        assert(it != known.end());
        known.erase(it);
#endif

        fprintf(out, "- %lx\n", reinterpret_cast<uintptr_t>(ptr));
    }

    TraceTree traceTree;
    /**
     * Note: We use the C stdio API here for performance reasons.
     *       Esp. in multi-threaded environments this is much faster
     *       to produce non-per-line-interleaved output.
     */
    FILE* out = nullptr;

    size_t lastTimerElapsed = 0;
    Timer timer;

    bool foundExe = false;
#ifdef DEBUG_MALLOC_PTRS
    unordered_set<void*> known;
#endif

};

unique_ptr<Data> data;

void prepare_fork()
{
    // don't do any custom malloc handling while inside fork
    HandleGuard::inHandler = true;
}

void parent_fork()
{
    // the parent process can now continue its custom malloc tracking
    HandleGuard::inHandler = false;
}

void child_fork()
{
    // but the forked child process cleans up itself
    // this is important to prevent two processes writing to the same file
    if (data) {
        data->out = nullptr;
        data.reset(nullptr);
    }
    HandleGuard::inHandler = true;
}

template<typename T>
T findReal(const char* name)
{
    auto ret = dlsym(RTLD_NEXT, name);
    if (!ret) {
        fprintf(stderr, "Could not find original function %s\n", name);
        abort();
    }
    return reinterpret_cast<T>(ret);
}

/**
 * Dummy implementation, since the call to dlsym from findReal triggers a call to calloc.
 *
 * This is only called at startup and will eventually be replaced by the "proper" calloc implementation.
 */
void* dummy_calloc(size_t num, size_t size)
{
    const size_t MAX_SIZE = 1024;
    static char* buf[MAX_SIZE];
    static size_t offset = 0;
    if (!offset) {
        memset(buf, 0, MAX_SIZE);
    }
    size_t oldOffset = offset;
    offset += num * size;
    if (offset >= MAX_SIZE) {
        fprintf(stderr, "failed to initialize, dummy calloc buf size exhausted: %lu requested, %lu available\n", offset, MAX_SIZE);
        abort();
    }
    return buf + oldOffset;
}

void init()
{
    static once_flag once;
    call_once(once, [] {
        if (data || HandleGuard::inHandler) {
            fprintf(stderr, "initialization recursion detected\n");
            abort();
        }

        HandleGuard guard;

        real_calloc = &dummy_calloc;
        real_calloc = findReal<calloc_t>("calloc");
        real_dlopen = findReal<dlopen_t>("dlopen");
        real_dlclose = findReal<dlclose_t>("dlclose");
        real_malloc = findReal<malloc_t>("malloc");
        real_free = findReal<free_t>("free");
        real_realloc = findReal<realloc_t>("realloc");
        real_posix_memalign = findReal<posix_memalign_t>("posix_memalign");
        real_valloc = findReal<valloc_t>("valloc");
        real_aligned_alloc = findReal<aligned_alloc_t>("aligned_alloc");

        if (unw_set_caching_policy(unw_local_addr_space, UNW_CACHE_PER_THREAD)) {
            fprintf(stderr, "Failed to enable per-thread libunwind caching.\n");
        }
        if (unw_set_cache_log_size(unw_local_addr_space, 10)) {
            fprintf(stderr, "Failed to set libunwind cache size.\n");
        }

        data.reset(new Data);
    });
}

}

extern "C" {

/// TODO: memalign, pvalloc, ...?

void* malloc(size_t size)
{
    if (!real_malloc) {
        init();
    }

    void* ret = real_malloc(size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void free(void* ptr)
{
    if (!real_free) {
        init();
    }

    // call handler before handing over the real free implementation
    // to ensure the ptr is not reused in-between and thus the output
    // stays consistent
    if (ptr && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleFree(ptr);
    }

    real_free(ptr);
}

void* realloc(void* ptr, size_t size)
{
    if (!real_realloc) {
        init();
    }

    void* ret = real_realloc(ptr, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        if (ptr) {
            data->handleFree(ptr);
        }
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* calloc(size_t num, size_t size)
{
    if (!real_calloc) {
        init();
    }

    void* ret = real_calloc(num, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, num*size);
    }

    return ret;
}

int posix_memalign(void **memptr, size_t alignment, size_t size)
{
    if (!real_posix_memalign) {
        init();
    }

    int ret = real_posix_memalign(memptr, alignment, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(*memptr, size);
    }

    return ret;
}

void* aligned_alloc(size_t alignment, size_t size)
{
    if (!real_aligned_alloc) {
        init();
    }

    void* ret = real_aligned_alloc(alignment, size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void* valloc(size_t size)
{
    if (!real_valloc) {
        init();
    }

    void* ret = real_valloc(size);

    if (ret && !HandleGuard::inHandler && data) {
        HandleGuard guard;
        data->handleMalloc(ret, size);
    }

    return ret;
}

void *dlopen(const char *filename, int flag)
{
    if (!real_dlopen) {
        init();
    }

    void* ret = real_dlopen(filename, flag);

    if (ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

int dlclose(void *handle)
{
    if (!real_dlclose) {
        init();
    }

    int ret = real_dlclose(handle);

    if (!ret) {
        moduleCacheDirty = true;
    }

    return ret;
}

}
<|endoftext|>


<commit_before><commit_msg>ULTRA RAINBOW SUPERSONIC THREEDEE (u aint never seen nuthin like dis<commit_after><|endoftext|>


<commit_before>#include "VersatileFile.h"

VersatileFile::VersatileFile(const QString& file_name)
	: file_name_(file_name)
{
	if (!isLocal())
	{
		socket_ = new QSslSocket();
		socket_->setSocketOption(QAbstractSocket::KeepAliveOption, 1);

		server_path_ = getServerPath();
		host_name_ = getHostName();
		server_port_ = getPortNumber();
		file_size_ = getFileSize();
	}
}

VersatileFile::~VersatileFile()
{
}

bool VersatileFile::open(QIODevice::OpenMode mode)
{
	if (isLocal())
	{
		local_source_ = QSharedPointer<QFile>(new QFile(file_name_));
		local_source_.data()->open(mode);
		return local_source_.data()->isOpen();
	}

	cursor_position_ = 0;
	remote_source_ = QSharedPointer<QSslSocket>(socket_);
	remote_source_.data()->open(mode);
	return remote_source_.data()->isOpen();
}

bool VersatileFile::open(FILE* f, QIODevice::OpenMode ioFlags)
{
	if (isLocal())
	{
		local_source_ = QSharedPointer<QFile>(new QFile(file_name_));
		local_source_.data()->open(f, ioFlags);
		return local_source_.data()->isOpen();
	}
	return false;
}

QIODevice::OpenMode VersatileFile::openMode() const
{
	if (isLocal()) return local_source_.data()->openMode();
	return remote_source_.data()->openMode();
}

bool VersatileFile::isOpen() const
{
	if (isLocal()) return local_source_.data()->isOpen();
	return remote_source_.data()->isOpen();
}

bool VersatileFile::isReadable() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->isReadable();
	return remote_source_.data()->isReadable();
}

QByteArray VersatileFile::readAll()
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->readAll();
	return readResponseWithoutHeaders();
}

QByteArray VersatileFile::readLine(qint64 maxlen)
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->readLine(maxlen);
	return readLineWithoutHeaders();
}

bool VersatileFile::atEnd() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->atEnd();
	return (cursor_position_ >= file_size_);
}

bool VersatileFile::exists()
{
	if (!local_source_.isNull()) return local_source_.data()->exists();
	return (file_size_ > 0);
}

void VersatileFile::close()
{
	if (!local_source_.isNull())
	{
		if (local_source_.data()->isOpen()) local_source_.data()->close();
	}
	if (!remote_source_.isNull())
	{
		if (remote_source_.data()->isOpen()) remote_source_.data()->close();
	}
}

qint64 VersatileFile::pos() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->pos();
	return cursor_position_;
}

qint64 VersatileFile::size() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->size();
	return file_size_;
}

QString VersatileFile::fileName() const
{
	return file_name_;
}

void VersatileFile::checkIfOpen() const
{
	if (isLocal())
	{
		if (local_source_.isNull()) THROW(FileAccessException, "Local file is not set!");
		if (!local_source_.data()->isOpen()) THROW(FileAccessException, "Local file is not open!");
	}
	else
	{
		if (remote_source_.isNull()) THROW(FileAccessException, "Remote file is not set!");
		if (!remote_source_.data()->isOpen()) THROW(FileAccessException, "Remote file is not open!");
	}
}

bool VersatileFile::isLocal() const
{
	return (!file_name_.startsWith("http", Qt::CaseInsensitive));
}

QString VersatileFile::getServerPath()
{
	QString server_path = file_name_;
	server_path = server_path.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> parts = server_path.split("/");
	if (parts.size() < 2) server_path = server_path.replace(parts.takeFirst(), "", Qt::CaseInsensitive);
	return server_path;
}

QString VersatileFile::getHostName()
{
	QString host_name = file_name_;
	host_name = host_name.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> url_parts = host_name.split("/");
	if (url_parts.size() > 1) host_name = url_parts.takeFirst();
	QList<QString> host_name_parts = host_name.split(":");
	if (host_name_parts.size()>1) host_name = host_name_parts.takeFirst();
	return host_name;
}

quint16 VersatileFile::getPortNumber()
{
	qint16 port_number = 443; // default HTTPS port
	QString host_name = file_name_;
	host_name = host_name.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> url_parts = host_name.split("/");
	if (url_parts.size() > 1) host_name = url_parts.takeFirst();
	QList<QString> host_name_parts = host_name.split(":");
	if (host_name_parts.size()>1) port_number = host_name_parts.takeLast().toInt();
	return port_number;
}

QByteArray VersatileFile::createHeadRequestText()
{
	QByteArray payload;
	payload.append("HEAD ");
	payload.append(server_path_);
	payload.append(" HTTP/1.1\r\n");
	payload.append("Host: ");
	payload.append(host_name_ + ":");
	payload.append(server_port_);
	payload.append("\r\n");
	payload.append("Connection: keep-alive\r\n");
	payload.append("\r\n");
	return payload;
}

QByteArray VersatileFile::createGetRequestText()
{
	QByteArray payload;
	payload.append("GET ");
	payload.append(server_path_);
	payload.append(" HTTP/1.1\r\n");
	payload.append("Host: ");
	payload.append(host_name_ + ":");
	payload.append(server_port_);
	payload.append("\r\n");
	payload.append("Connection: keep-alive\r\n");
	payload.append("\r\n");
	return payload;
}

void VersatileFile::initiateRequest(const QByteArray& http_request)
{
	socket_->connectToHostEncrypted(host_name_, server_port_);
	socket_->ignoreSslErrors();
	socket_->waitForConnected();
	socket_->waitForEncrypted();

	socket_->open(QIODevice::ReadWrite);

	socket_->write(http_request);
	socket_->flush();
	socket_->waitForBytesWritten();
}

QByteArray VersatileFile::readAllViaSocket(const QByteArray& http_request)
{
	if (socket_->state() != QSslSocket::SocketState::ConnectedState)
	{
		initiateRequest(http_request);
	}

	QByteArray response;
	while(socket_->waitForReadyRead())
	{
		while(socket_->bytesAvailable())
		{
			response.append(socket_->readAll());
			cursor_position_ = response.length();
		}
	}

	return response;
}

QByteArray VersatileFile::readLineViaSocket(const QByteArray& http_request, qint64 maxlen)
{
	if (buffer_.size() > 0)
	{
		QByteArray result_line = buffer_.first();
		buffer_.removeFirst();
		cursor_position_ = cursor_position_ + result_line.length();
		return result_line;
	}

	if (socket_->state() != QSslSocket::SocketState::ConnectedState)
	{
		initiateRequest(http_request);
		bool found_headers = false;
		while(socket_->waitForReadyRead())
		{
			while(socket_->bytesAvailable())
			{
				QString line = socket_->readLine(maxlen);
				if (line.trimmed().length() == 0)
				{
					found_headers = true;
					break;
				}
			}
			if (found_headers) break;
		}
	}

	QByteArray result_line;
	bool found_line = false;

	while((socket_->waitForReadyRead()) || (socket_->bytesAvailable()))
	{
		if (socket_->canReadLine())
		{
			found_line = true;
			result_line = socket_->readLine(maxlen);
			cursor_position_ = cursor_position_ + result_line.length();
		}
		if(socket_->bytesAvailable())
		{
			while (socket_->canReadLine())
			{
				buffer_.append(socket_->readLine(maxlen));
			}
		}
		if (found_line)
		{
			return result_line;
		}
	}

	return "";
}

qint64 VersatileFile::getFileSize()
{
	QByteArray response = readAllViaSocket(createHeadRequestText());
	cursor_position_ = 0;
	QTextStream stream(response);
	while(!stream.atEnd())
	{
		QString line = stream.readLine();
		if (line.startsWith("Content-Length", Qt::CaseInsensitive))
		{
			QList<QString> parts = line.split(":");
			if (parts.size() > 1) return parts.takeLast().trimmed().toLongLong();
		}
	}

	return 0;
}

QByteArray VersatileFile::readResponseWithoutHeaders()
{
	QByteArray response = readAllViaSocket(createGetRequestText());
	QTextStream stream(response);

	qint64 pos = 0;
	while(!stream.atEnd())
	{
		QString line = stream.readLine();
		pos = pos + line.length() ; // end of line characters (\r\n) separate headers from the body
		if (line.length() == 0)
		{
			break;
		}
	}
	return response.mid(pos);
}

QByteArray VersatileFile::readLineWithoutHeaders(qint64 maxlen)
{
	QByteArray response = readLineViaSocket(createGetRequestText(), maxlen);
	return response;
}

<commit_msg>Fixed reading after the end of file issue<commit_after>#include "VersatileFile.h"

VersatileFile::VersatileFile(const QString& file_name)
	: file_name_(file_name)
{
	if (!isLocal())
	{
		socket_ = new QSslSocket();
		socket_->setSocketOption(QAbstractSocket::KeepAliveOption, 1);

		server_path_ = getServerPath();
		host_name_ = getHostName();
		server_port_ = getPortNumber();
		file_size_ = getFileSize();
	}
}

VersatileFile::~VersatileFile()
{
}

bool VersatileFile::open(QIODevice::OpenMode mode)
{
	if (isLocal())
	{
		local_source_ = QSharedPointer<QFile>(new QFile(file_name_));
		local_source_.data()->open(mode);
		return local_source_.data()->isOpen();
	}

	cursor_position_ = 0;
	remote_source_ = QSharedPointer<QSslSocket>(socket_);
	remote_source_.data()->open(mode);
	return remote_source_.data()->isOpen();
}

bool VersatileFile::open(FILE* f, QIODevice::OpenMode ioFlags)
{
	if (isLocal())
	{
		local_source_ = QSharedPointer<QFile>(new QFile(file_name_));
		local_source_.data()->open(f, ioFlags);
		return local_source_.data()->isOpen();
	}
	return false;
}

QIODevice::OpenMode VersatileFile::openMode() const
{
	if (isLocal()) return local_source_.data()->openMode();
	return remote_source_.data()->openMode();
}

bool VersatileFile::isOpen() const
{
	if (isLocal()) return local_source_.data()->isOpen();
	return remote_source_.data()->isOpen();
}

bool VersatileFile::isReadable() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->isReadable();
	return remote_source_.data()->isReadable();
}

QByteArray VersatileFile::readAll()
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->readAll();
	return readResponseWithoutHeaders();
}

QByteArray VersatileFile::readLine(qint64 maxlen)
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->readLine(maxlen);
	return readLineWithoutHeaders();
}

bool VersatileFile::atEnd() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->atEnd();
	return (cursor_position_ >= file_size_);
}

bool VersatileFile::exists()
{
	if (!local_source_.isNull()) return local_source_.data()->exists();
	return (file_size_ > 0);
}

void VersatileFile::close()
{
	if (!local_source_.isNull())
	{
		if (local_source_.data()->isOpen()) local_source_.data()->close();
	}
	if (!remote_source_.isNull())
	{
		if (remote_source_.data()->isOpen()) remote_source_.data()->close();
	}
}

qint64 VersatileFile::pos() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->pos();
	return cursor_position_;
}

qint64 VersatileFile::size() const
{
	checkIfOpen();
	if (isLocal()) return local_source_.data()->size();
	return file_size_;
}

QString VersatileFile::fileName() const
{
	return file_name_;
}

void VersatileFile::checkIfOpen() const
{
	if (isLocal())
	{
		if (local_source_.isNull()) THROW(FileAccessException, "Local file is not set!");
		if (!local_source_.data()->isOpen()) THROW(FileAccessException, "Local file is not open!");
	}
	else
	{
		if (remote_source_.isNull()) THROW(FileAccessException, "Remote file is not set!");
		if (!remote_source_.data()->isOpen()) THROW(FileAccessException, "Remote file is not open!");
	}
}

bool VersatileFile::isLocal() const
{
	return (!file_name_.startsWith("http", Qt::CaseInsensitive));
}

QString VersatileFile::getServerPath()
{
	QString server_path = file_name_;
	server_path = server_path.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> parts = server_path.split("/");
	if (parts.size() < 2) server_path = server_path.replace(parts.takeFirst(), "", Qt::CaseInsensitive);
	return server_path;
}

QString VersatileFile::getHostName()
{
	QString host_name = file_name_;
	host_name = host_name.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> url_parts = host_name.split("/");
	if (url_parts.size() > 1) host_name = url_parts.takeFirst();
	QList<QString> host_name_parts = host_name.split(":");
	if (host_name_parts.size()>1) host_name = host_name_parts.takeFirst();
	return host_name;
}

quint16 VersatileFile::getPortNumber()
{
	qint16 port_number = 443; // default HTTPS port
	QString host_name = file_name_;
	host_name = host_name.replace("https://", "", Qt::CaseInsensitive);
	QList<QString> url_parts = host_name.split("/");
	if (url_parts.size() > 1) host_name = url_parts.takeFirst();
	QList<QString> host_name_parts = host_name.split(":");
	if (host_name_parts.size()>1) port_number = host_name_parts.takeLast().toInt();
	return port_number;
}

QByteArray VersatileFile::createHeadRequestText()
{
	QByteArray payload;
	payload.append("HEAD ");
	payload.append(server_path_);
	payload.append(" HTTP/1.1\r\n");
	payload.append("Host: ");
	payload.append(host_name_ + ":");
	payload.append(server_port_);
	payload.append("\r\n");
	payload.append("Connection: keep-alive\r\n");
	payload.append("\r\n");
	return payload;
}

QByteArray VersatileFile::createGetRequestText()
{
	QByteArray payload;
	payload.append("GET ");
	payload.append(server_path_);
	payload.append(" HTTP/1.1\r\n");
	payload.append("Host: ");
	payload.append(host_name_ + ":");
	payload.append(server_port_);
	payload.append("\r\n");
	payload.append("Connection: keep-alive\r\n");
	payload.append("\r\n");
	return payload;
}

void VersatileFile::initiateRequest(const QByteArray& http_request)
{
	socket_->connectToHostEncrypted(host_name_, server_port_);
	socket_->ignoreSslErrors();
	socket_->waitForConnected();
	socket_->waitForEncrypted();

	socket_->open(QIODevice::ReadWrite);

	socket_->write(http_request);
	socket_->flush();
	socket_->waitForBytesWritten();
}

QByteArray VersatileFile::readAllViaSocket(const QByteArray& http_request)
{
	if (socket_->state() != QSslSocket::SocketState::ConnectedState)
	{
		initiateRequest(http_request);
	}

	QByteArray response;
	while(socket_->waitForReadyRead())
	{
		while(socket_->bytesAvailable())
		{
			response.append(socket_->readAll());
			cursor_position_ = response.length();
		}
	}

	return response;
}

QByteArray VersatileFile::readLineViaSocket(const QByteArray& http_request, qint64 maxlen)
{
	if (this->atEnd()) return "";

	if (buffer_.size() > 0)
	{
		QByteArray result_line = buffer_.first();
		buffer_.removeFirst();
		cursor_position_ = cursor_position_ + result_line.length();
		return result_line;
	}

	if (socket_->state() != QSslSocket::SocketState::ConnectedState)
	{
		initiateRequest(http_request);
		bool found_headers = false;
		while(socket_->waitForReadyRead())
		{
			while(socket_->bytesAvailable())
			{
				QString line = socket_->readLine(maxlen);
				if (line.trimmed().length() == 0)
				{
					found_headers = true;
					break;
				}
			}
			if (found_headers) break;
		}
	}

	QByteArray result_line;
	bool found_line = false;

	while((socket_->waitForReadyRead()) || (socket_->bytesAvailable()))
	{
		if (socket_->canReadLine())
		{
			found_line = true;
			result_line = socket_->readLine(maxlen);
			cursor_position_ = cursor_position_ + result_line.length();
		}
		if(socket_->bytesAvailable())
		{
			while (socket_->canReadLine())
			{
				buffer_.append(socket_->readLine(maxlen));
			}
		}
		if (found_line)
		{
			return result_line;
		}
	}

	return "";
}

qint64 VersatileFile::getFileSize()
{
	QByteArray response = readAllViaSocket(createHeadRequestText());
	cursor_position_ = 0;
	QTextStream stream(response);
	while(!stream.atEnd())
	{
		QString line = stream.readLine();
		if (line.startsWith("Content-Length", Qt::CaseInsensitive))
		{
			QList<QString> parts = line.split(":");
			if (parts.size() > 1) return parts.takeLast().trimmed().toLongLong();
		}
	}

	return 0;
}

QByteArray VersatileFile::readResponseWithoutHeaders()
{
	QByteArray response = readAllViaSocket(createGetRequestText());
	QTextStream stream(response);

	qint64 pos = 0;
	while(!stream.atEnd())
	{
		QString line = stream.readLine();
		pos = pos + line.length() ; // end of line characters (\r\n) separate headers from the body
		if (line.length() == 0)
		{
			break;
		}
	}
	return response.mid(pos);
}

QByteArray VersatileFile::readLineWithoutHeaders(qint64 maxlen)
{
	QByteArray response = readLineViaSocket(createGetRequestText(), maxlen);
	return response;
}

<|endoftext|>