<commit_before>#include <Socket/SocketSerialized.hpp>
#include <Socket/define.hpp>

namespace ntw {

SocketSerialized::SocketSerialized(Socket::Dommaine dommaine,Socket::Type type,int protocole): Serializer(255), Socket(dommaine,type,protocole), status(0)
{
    //reserver les 2 premier bits pour la taille
    _cursor_end =_cursor_begin = 4;
    //is_send=false;
};

SocketSerialized::SocketSerialized(Socket&& s) : Serializer(255)
{
    std::swap(s.sock,sock);
    std::swap(s.sock_cfg,sock_cfg);
    _cursor_end =_cursor_begin = 4;
};

void SocketSerialized::send()
{
    //écrire la taille dans les 2 premier oct
    uint16_t size = _cursor_end - _cursor_begin;
    uint8_t *d = (uint8_t *)&size;
    #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    _buffer[_cursor_begin - 4] = d[0];
    _buffer[_cursor_begin - 3] = d[1];
    #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    _buffer[_cursor_begin - 4] = d[1];
    _buffer[_cursor_begin - 3] = d[0];
    #else
    #error "byte orden not suported (PDP endian)"
    #endif

    {
        uint16_t st = status;
        d = (uint8_t*)&st;
        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        _buffer[_cursor_begin - 2] = d[0];
        _buffer[_cursor_begin - 1] = d[1];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        _buffer[_cursor_begin - 2] = d[1];
        _buffer[_cursor_begin - 1] = d[0];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
    }
    //envoyer
    //std::cout<<"send: "<<*this<<std::endl;
    int res = Socket::send(_buffer+_cursor_begin-4, 4+size);
    std::cout<<"Send : "<<res<<"/"<<int(4+size)<<std::endl;
    //reset
    //clear();
};

int SocketSerialized::receive()
{
    //recuperer la taille dans les 4 premier oct
    int res = Socket::receive(_buffer,4);
    if (res > 0)
    {
        uint8_t d[2];
        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        d[0]= _buffer[0];
        d[1]= _buffer[1];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        d[1]= _buffer[0];
        d[0]= _buffer[1];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
        uint16_t size = *(uint16_t*)&d;

        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        d[0]= _buffer[2];
        d[1]= _buffer[3];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        d[1]= _buffer[2];
        d[0]= _buffer[3];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
        status = *(uint16_t*)&d;

        //reset
        if (int(_buffer_size) < 4+size)
            resize(4+size);
        //else _buffer_size ne change pas
        _cursor_begin = 4;
        _cursor_end = 4+size;
        //remplacer le buffer
        if(size>0)
        {
            int recv_left = size;
            int recv = 0;
            while(recv_left > 0)
            {
                recv = Socket::receive(_buffer+4+recv,recv_left);
                std::cout<<"Recv size: "<<recv<<std::endl;
                res+=recv;
                recv_left -=recv;
            }
        }
    }
    else
    {
        clear();
        setStatus(NTW_STOP_CONNEXION);
    }
    //std::cout<<"recv: "<<*this<<std::endl;
    std::cout<<"Recv real: "<<res<<std::endl;
    return res;
};

void SocketSerialized::setStatus(short int st)
{
    status = st;
}

short int SocketSerialized::getStatus()const
{
    return status;
}

void SocketSerialized::clear()
{
    _cursor_begin = _cursor_end = 4;
}

std::ostream& operator<<(std::ostream& output,const SocketSerialized& self)
{
    output<<"["<<self.size()<<":"<<self.status<<"]";
    for(unsigned int i=self._cursor_begin; i<self._cursor_end;++i)
    {
        if(self._buffer[i] < 33 or self._buffer[i] >126)
            output<<"<"<<(int)self._buffer[i]<<">";
        else
            output<<"'"<<(char)self._buffer[i]<<"'";
    }
    return output;
};

};
<commit_msg>test fix bug<commit_after>#include <Socket/SocketSerialized.hpp>
#include <Socket/define.hpp>

namespace ntw {

SocketSerialized::SocketSerialized(Socket::Dommaine dommaine,Socket::Type type,int protocole): Serializer(255), Socket(dommaine,type,protocole), status(0)
{
    //reserver les 2 premier bits pour la taille
    _cursor_end =_cursor_begin = 4;
    //is_send=false;
};

SocketSerialized::SocketSerialized(Socket&& s) : Serializer(255)
{
    std::swap(s.sock,sock);
    std::swap(s.sock_cfg,sock_cfg);
    _cursor_end =_cursor_begin = 4;
};

void SocketSerialized::send()
{
    //écrire la taille dans les 2 premier oct
    uint16_t size = _cursor_end - _cursor_begin;
    uint8_t *d = (uint8_t *)&size;
    #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
    _buffer[_cursor_begin - 4] = d[0];
    _buffer[_cursor_begin - 3] = d[1];
    #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
    _buffer[_cursor_begin - 4] = d[1];
    _buffer[_cursor_begin - 3] = d[0];
    #else
    #error "byte orden not suported (PDP endian)"
    #endif

    {
        uint16_t st = status;
        d = (uint8_t*)&st;
        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        _buffer[_cursor_begin - 2] = d[0];
        _buffer[_cursor_begin - 1] = d[1];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        _buffer[_cursor_begin - 2] = d[1];
        _buffer[_cursor_begin - 1] = d[0];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
    }
    //envoyer
    //std::cout<<"send: "<<*this<<std::endl;
    int res = Socket::send(_buffer+_cursor_begin-4, 4+size);
    std::cout<<"Send : "<<res<<"/"<<int(4+size)<<std::endl;
    //reset
    //clear();
};

int SocketSerialized::receive()
{
    //recuperer la taille dans les 4 premier oct
    int res = Socket::receive(_buffer,4);
    if (res > 0)
    {
        uint8_t d[2];
        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        d[0]= _buffer[0];
        d[1]= _buffer[1];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        d[1]= _buffer[0];
        d[0]= _buffer[1];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
        uint16_t size = *(uint16_t*)&d;

        #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        d[0]= _buffer[2];
        d[1]= _buffer[3];
        #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
        d[1]= _buffer[2];
        d[0]= _buffer[3];
        #else
        #error "byte orden not suported (PDP endian)"
        #endif
        status = *(uint16_t*)&d;

        //reset
        if (int(_buffer_size) < 4+size)
            resize(4+size);
        //else _buffer_size ne change pas
        _cursor_begin = 4;
        _cursor_end = 4+size;
        //remplacer le buffer
        if(size>0)
        {
            int recv_left = size;
            int recv = 0;
            while(recv_left > 0)
            {
                recv = Socket::receive(_buffer+res,recv_left-recv);
                if(recv<0)
                    break;
                std::cout<<"Recv size: "<<recv<<std::endl;
                res+=recv;
                recv_left -=recv;
            }
        }
    }
    else
    {
        clear();
        setStatus(NTW_STOP_CONNEXION);
    }
    //std::cout<<"recv: "<<*this<<std::endl;
    std::cout<<"Recv real: "<<res<<std::endl;
    return res;
};

void SocketSerialized::setStatus(short int st)
{
    status = st;
}

short int SocketSerialized::getStatus()const
{
    return status;
}

void SocketSerialized::clear()
{
    _cursor_begin = _cursor_end = 4;
}

std::ostream& operator<<(std::ostream& output,const SocketSerialized& self)
{
    output<<"["<<self.size()<<":"<<self.status<<"]";
    for(unsigned int i=self._cursor_begin; i<self._cursor_end;++i)
    {
        if(self._buffer[i] < 33 or self._buffer[i] >126)
            output<<"<"<<(int)self._buffer[i]<<">";
        else
            output<<"'"<<(char)self._buffer[i]<<"'";
    }
    return output;
};

};
<|endoftext|>


<commit_before>#include "Play.hpp"

#include <functional>

#include "../../ResourceManager/AssetManager.hpp"

/* GUI headers */
#include "../../GUI/Containers/Column.hpp"
#include "../../GUI/Containers/Row.hpp"
#include "../../GUI/Widgets/Label.hpp"
#include "../../GUI/Widgets/Button.hpp"
#include "../../GUI/Widgets/Spacer.hpp"

/* Worlds */
#include "../../World/Worlds/TestWorld.hpp"

namespace swift
{
	Play::Play(sf::RenderWindow& win, AssetManager& am, Settings& set, Settings& dic)
		:	State(win, am, set, dic),
		    state(SubState::Play),
			activeWorld(nullptr),
			player(nullptr)
	{
		returnType = State::Type::Play;
	}

	Play::~Play()
	{
		for(auto& w : worlds)
		{
			w->save("");
			delete w;
		}
	}

	void Play::setup()
	{
		window.setKeyRepeatEnabled(false);

		worlds.emplace_back(new TestWorld({800, 600}, assets));
		activeWorld = worlds[0];

		setupKeyBindings();

		// setup pause menu GUI
		std::string resume = "Resume";
		dictionary.get("resumeButton", resume);
		cstr::Column& pauseColumn = pauseMenu.addContainer(new cstr::Column({static_cast<int>(window.getSize().x) / 2 - 50, static_cast<int>(window.getSize().y / 2) - 50, 100, 125}, false));
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			state = SubState::Play;
		})).setString(resume, assets.getFont("./data/fonts/segoeuisl.ttf"));

		pauseColumn.addWidget(new cstr::Spacer({100, 25}));

		std::string mainMenu = "Main Menu";
		dictionary.get("mainMenuButton", mainMenu);
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			returnType = State::Type::MainMenu;
		})).setString(mainMenu, assets.getFont("./data/fonts/segoeuisl.ttf"));

		// setup player
		player = activeWorld->addEntity();
		player->add<Drawable>();
		player->add<Physical>();
		player->add<Name>();
		player->get<Name>()->name = "player";
		player->add<Movable>();

		player->get<Drawable>()->sprite.setTexture(assets.getTexture("./data/textures/guy.png"));
		player->get<Drawable>()->sprite.setScale({0.5f, (player->get<Drawable>()->sprite.getGlobalBounds().height - 16) / player->get<Drawable>()->sprite.getGlobalBounds().height});

		player->get<Physical>()->position = {400, 300};
		player->get<Physical>()->size = {static_cast<unsigned>(player->get<Drawable>()->sprite.getGlobalBounds().width),
										static_cast<unsigned>(player->get<Drawable>()->sprite.getGlobalBounds().height)};

		player->get<Movable>()->moveVelocity = 100;

		// setup world
		activeWorld->load("./data/saves/default/maze.world");
		activeWorld->tilemap.loadFile("./data/maps/maze.map");
		activeWorld->tilemap.loadTexture(assets.getTexture(activeWorld->tilemap.getTextureFile()));
	}

	void Play::handleEvent(sf::Event& event)
	{
		switch(state)
		{
			case SubState::Play:
				hud.update(event);
				break;
			case SubState::Pause:
				pauseMenu.update(event);
				break;
			default:
				break;
		}

		keyboard(event);
		mouse(event);
	}

	void Play::update(sf::Time dt)
	{
		switch(state)
		{
			case SubState::Play:
				activeWorld->update(dt.asSeconds());
				break;
			case SubState::Pause:
				break;
		}
	}

	void Play::draw(float /*e*/)
	{
		switch(state)
		{
			case SubState::Play:
				activeWorld->drawWorld(window);

				activeWorld->drawEntities(window);

				window.draw(hud);
				break;
			case SubState::Pause:
				window.draw(pauseMenu);
				break;
			default:
				break;
		}
	}

	bool Play::switchFrom()
	{
		return returnType != State::Type::Play;
	}

	State::Type Play::finish()
	{
		return returnType;
	}

	void Play::setupKeyBindings()
	{
		keyboard.newBinding("PauseMenu", sf::Keyboard::Escape, [&]()
		{
			state = (state == SubState::Pause) ? SubState::Play : SubState::Pause;
		}, false);

		// move up press and release
		keyboard.newBinding("moveUpStart", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveUpStop", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, false);

		// move down press and release
		keyboard.newBinding("moveDownStart", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveDownStop", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, false);

		// move left press and release
		keyboard.newBinding("moveLeftStart", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveLeftStop", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, false);

		// move right press and release
		keyboard.newBinding("moveRightStart", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveRightStop", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, false);
	}
}
<commit_msg>Removed old player init code. Player is now first Entity in the World save file<commit_after>#include "Play.hpp"

#include <functional>

#include "../../ResourceManager/AssetManager.hpp"

/* GUI headers */
#include "../../GUI/Containers/Column.hpp"
#include "../../GUI/Containers/Row.hpp"
#include "../../GUI/Widgets/Label.hpp"
#include "../../GUI/Widgets/Button.hpp"
#include "../../GUI/Widgets/Spacer.hpp"

/* Worlds */
#include "../../World/Worlds/TestWorld.hpp"

namespace swift
{
	Play::Play(sf::RenderWindow& win, AssetManager& am, Settings& set, Settings& dic)
		:	State(win, am, set, dic),
		    state(SubState::Play),
			activeWorld(nullptr),
			player(nullptr)
	{
		returnType = State::Type::Play;
	}

	Play::~Play()
	{
		for(auto& w : worlds)
			delete w;
	}

	void Play::setup()
	{
		window.setKeyRepeatEnabled(false);

		worlds.emplace_back(new TestWorld("testWorld", {800, 600}, assets));
		activeWorld = worlds[0];

		setupKeyBindings();

		// setup pause menu GUI
		std::string resume = "Resume";
		dictionary.get("resumeButton", resume);
		cstr::Column& pauseColumn = pauseMenu.addContainer(new cstr::Column({static_cast<int>(window.getSize().x) / 2 - 50, static_cast<int>(window.getSize().y / 2) - 50, 100, 125}, false));
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			state = SubState::Play;
		})).setString(resume, assets.getFont("./data/fonts/segoeuisl.ttf"));

		pauseColumn.addWidget(new cstr::Spacer({100, 25}));

		std::string mainMenu = "Main Menu";
		dictionary.get("mainMenuButton", mainMenu);
		pauseColumn.addWidget(new cstr::Button({100, 50}, assets.getTexture("./data/textures/button.png"), [&]()
		{
			returnType = State::Type::MainMenu;
		})).setString(mainMenu, assets.getFont("./data/fonts/segoeuisl.ttf"));

		// setup world
		activeWorld->tilemap.loadFile("./data/maps/maze.map");
		activeWorld->tilemap.loadTexture(assets.getTexture(activeWorld->tilemap.getTextureFile()));
		activeWorld->load("./data/saves/maze.world");
		player = activeWorld->getEntities()[0];
		activeWorld->addScript("./data/scripts/quest.lua");
		assets.getScript("./data/scripts/quest.lua").start();
	}

	void Play::handleEvent(sf::Event& event)
	{
		switch(state)
		{
			case SubState::Play:
				hud.update(event);
				break;
			case SubState::Pause:
				pauseMenu.update(event);
				break;
			default:
				break;
		}

		keyboard(event);
		mouse(event);
	}

	void Play::update(sf::Time dt)
	{
		switch(state)
		{
			case SubState::Play:
				activeWorld->update(dt.asSeconds());
				break;
			case SubState::Pause:
				break;
		}
	}

	void Play::draw(float /*e*/)
	{
		switch(state)
		{
			case SubState::Play:
				activeWorld->drawWorld(window);

				activeWorld->drawEntities(window);

				window.draw(hud);
				break;
			case SubState::Pause:
				window.draw(pauseMenu);
				break;
			default:
				break;
		}
	}

	bool Play::switchFrom()
	{
		return returnType != State::Type::Play;
	}

	State::Type Play::finish()
	{
		return returnType;
	}

	void Play::setupKeyBindings()
	{
		keyboard.newBinding("PauseMenu", sf::Keyboard::Escape, [&]()
		{
			state = (state == SubState::Pause) ? SubState::Play : SubState::Pause;
		}, false);

		// move up press and release
		keyboard.newBinding("moveUpStart", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveUpStop", sf::Keyboard::Up, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, false);

		// move down press and release
		keyboard.newBinding("moveDownStart", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, player->get<Movable>()->moveVelocity};
		}, true);

		keyboard.newBinding("moveDownStop", sf::Keyboard::Down, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {0, -player->get<Movable>()->moveVelocity};
		}, false);

		// move left press and release
		keyboard.newBinding("moveLeftStart", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveLeftStop", sf::Keyboard::Left, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, false);

		// move right press and release
		keyboard.newBinding("moveRightStart", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {player->get<Movable>()->moveVelocity, 0};
		}, true);

		keyboard.newBinding("moveRightStop", sf::Keyboard::Right, [&]()
		{
			if(player)
				if(player->has<Movable>())
					player->get<Movable>()->velocity += {-player->get<Movable>()->moveVelocity, 0};
		}, false);
	}
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER

void fn1();
void fn2();
void fn3();
void fn4();
void fn5();
void fn6();

int Arg;

// CHECK-LABEL: define void @{{.+}}gtid_test
void gtid_test() {
// CHECK:  call void {{.+}}* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, {{.+}}* [[GTID_TEST_REGION1:@.+]] to void
#pragma omp parallel
#pragma omp parallel if (false)
  gtid_test();
// CHECK: ret void
}

// CHECK: define internal void [[GTID_TEST_REGION1]](i{{.+}}* [[GTID_PARAM:%.+]], i
// CHECK: store i{{[0-9]+}}* [[GTID_PARAM]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]],
// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: call void [[GTID_TEST_REGION2:@.+]](i{{[0-9]+}}* [[GTID_ADDR]]
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
// CHECK: ret void

// CHECK: define internal void [[GTID_TEST_REGION2]](
// CHECK: call void @{{.+}}gtid_test
// CHECK: ret void

template <typename T>
int tmain(T Arg) {
#pragma omp parallel if (true)
  fn1();
#pragma omp parallel if (false)
  fn2();
#pragma omp parallel if (Arg)
  fn3();
  return 0;
}

// CHECK-LABEL: define {{.*}}i{{[0-9]+}} @main()
int main() {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN4:@.+]] to void
#pragma omp parallel if (true)
  fn4();
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN5:@.+]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
#pragma omp parallel if (false)
  fn5();

// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
// CHECK: [[OMP_THEN]]
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN6:@.+]] to void
// CHECK: br label %[[OMP_END:.+]]
// CHECK: [[OMP_ELSE]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 %0)
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN6]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br label %[[OMP_END]]
// CHECK: [[OMP_END]]
#pragma omp parallel if (Arg)
  fn6();
  // CHECK: = call i{{.+}} @{{.+}}tmain
  return tmain(Arg);
}

// CHECK: define internal void [[CAP_FN4]]
// CHECK: call void @{{.+}}fn4
// CHECK: ret void

// CHECK: define internal void [[CAP_FN5]]
// CHECK: call void @{{.+}}fn5
// CHECK: ret void

// CHECK: define internal void [[CAP_FN6]]
// CHECK: call void @{{.+}}fn6
// CHECK: ret void

// CHECK-LABEL: define {{.+}} @{{.+}}tmain
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN1:@.+]] to void
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN2:@.+]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
// CHECK: [[OMP_THEN]]
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN3:@.+]] to void
// CHECK: br label %[[OMP_END:.+]]
// CHECK: [[OMP_ELSE]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 %0)
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN3]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br label %[[OMP_END]]
// CHECK: [[OMP_END]]

// CHECK: define internal void [[CAP_FN1]]
// CHECK: call void @{{.+}}fn1
// CHECK: ret void

// CHECK: define internal void [[CAP_FN2]]
// CHECK: call void @{{.+}}fn2
// CHECK: ret void

// CHECK: define internal void [[CAP_FN3]]
// CHECK: call void @{{.+}}fn3
// CHECK: ret void

#endif
<commit_msg>Fix test OpenMP/parallel_if_codegen.cpp.<commit_after>// RUN: %clang_cc1 -verify -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -std=c++11 -triple %itanium_abi_triple -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp=libiomp5 -x c++ -triple %itanium_abi_triple -std=c++11 -include-pch %t -verify %s -emit-llvm -o - | FileCheck --check-prefix=CHECK %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER

void fn1();
void fn2();
void fn3();
void fn4();
void fn5();
void fn6();

int Arg;

// CHECK-LABEL: define void @{{.+}}gtid_test
void gtid_test() {
// CHECK:  call void {{.+}}* @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, {{.+}}* [[GTID_TEST_REGION1:@.+]] to void
#pragma omp parallel
#pragma omp parallel if (false)
  gtid_test();
// CHECK: ret void
}

// CHECK: define internal void [[GTID_TEST_REGION1]](i{{.+}}* [[GTID_PARAM:%.+]], i
// CHECK: store i{{[0-9]+}}* [[GTID_PARAM]], i{{[0-9]+}}** [[GTID_ADDR_REF:%.+]],
// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: [[GTID:%.+]] = load i{{[0-9]+}}* [[GTID_ADDR]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
// CHECK: [[GTID_ADDR:%.+]] = load i{{[0-9]+}}** [[GTID_ADDR_REF]]
// CHECK: call void [[GTID_TEST_REGION2:@.+]](i{{[0-9]+}}* [[GTID_ADDR]]
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i{{.+}} [[GTID]])
// CHECK: ret void

// CHECK: define internal void [[GTID_TEST_REGION2]](
// CHECK: call void @{{.+}}gtid_test
// CHECK: ret void

template <typename T>
int tmain(T Arg) {
#pragma omp parallel if (true)
  fn1();
#pragma omp parallel if (false)
  fn2();
#pragma omp parallel if (Arg)
  fn3();
  return 0;
}

// CHECK-LABEL: define {{.*}}i{{[0-9]+}} @main()
int main() {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN4:@.+]] to void
#pragma omp parallel if (true)
  fn4();
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN5:@.+]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
#pragma omp parallel if (false)
  fn5();

// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
// CHECK: [[OMP_THEN]]
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN6:@.+]] to void
// CHECK: br label %[[OMP_END:.+]]
// CHECK: [[OMP_ELSE]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN6]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br label %[[OMP_END]]
// CHECK: [[OMP_END]]
#pragma omp parallel if (Arg)
  fn6();
  // CHECK: = call i{{.+}} @{{.+}}tmain
  return tmain(Arg);
}

// CHECK: define internal void [[CAP_FN4]]
// CHECK: call void @{{.+}}fn4
// CHECK: ret void

// CHECK: define internal void [[CAP_FN5]]
// CHECK: call void @{{.+}}fn5
// CHECK: ret void

// CHECK: define internal void [[CAP_FN6]]
// CHECK: call void @{{.+}}fn6
// CHECK: ret void

// CHECK-LABEL: define {{.+}} @{{.+}}tmain
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN1:@.+]] to void
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN2:@.+]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br i1 %{{.+}}, label %[[OMP_THEN:.+]], label %[[OMP_ELSE:.+]]
// CHECK: [[OMP_THEN]]
// CHECK: call void {{.+}} @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{.+}} 1, void {{.+}}* [[CAP_FN3:@.+]] to void
// CHECK: br label %[[OMP_END:.+]]
// CHECK: [[OMP_ELSE]]
// CHECK: call void @__kmpc_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: store i32 [[GTID]], i32* [[GTID_ADDR:%.+]],
// CHECK: call void [[CAP_FN3]](i32* [[GTID_ADDR]],
// CHECK: call void @__kmpc_end_serialized_parallel(%{{.+}}* @{{.+}}, i32 [[GTID]])
// CHECK: br label %[[OMP_END]]
// CHECK: [[OMP_END]]

// CHECK: define internal void [[CAP_FN1]]
// CHECK: call void @{{.+}}fn1
// CHECK: ret void

// CHECK: define internal void [[CAP_FN2]]
// CHECK: call void @{{.+}}fn2
// CHECK: ret void

// CHECK: define internal void [[CAP_FN3]]
// CHECK: call void @{{.+}}fn3
// CHECK: ret void

#endif
<|endoftext|>


<commit_before>#include "game.hpp"

int Game::startGame() {
	std::string str;
	uciHandler("position startpos");

	while(true) {
		std::getline(std::cin, str);

		if(!uciHandler(str)) {
			return 0;
		};
	}
}

void Game::goFixedDepth() {
	++hashAge;

	if(option.UCI_AnalyseMode || abs(bestScore) >= (WHITE_WIN - 100)) {
		clearCash();
	}

	stopped = false;
	std::vector<uint64_t>hash;

	nodesCounter = 0;
	int max_depth_global = max_depth;
	max_depth = 1;

	start_timer = clock();
	hasBestMove = false;

	BitMove moveCritical = game_board.getRandomMove();
	bestMove = moveCritical;
	hasBestMove = true;
	bestScore = 0;

	for(; max_depth <= max_depth_global; ++max_depth) {
		flattenHistory();

		negamax(game_board, -WHITE_WIN, WHITE_WIN, max_depth, 0, FIXED_DEPTH, false, true);

		hasBestMove = true;

		if((abs(bestScore) >= (WHITE_WIN - 100) && max_depth_global < 99) || stopped) {
			break;
		}
	}

	end_timer = clock();

	if(hasBestMove) {
		std::cout << "bestmove " << bestMove.getMoveString() << std::endl;
	}
}

void Game::goFixedTime(int64_t tm, bool tournamentTimeControll) {
	tm -= option.moveOverhead;
	tm = std::max(tm, (int64_t)10);

	++hashAge;
	stopped = false;

	time = tm;
	timer.start();

	if(option.UCI_AnalyseMode || abs(bestScore) >= (WHITE_WIN - 100)) {
		clearCash();
	}

	std::vector<uint64_t>hash;

	nodesCounter = 0;

	start_timer = clock();
	hasBestMove = false;

	BitMove moveCritical = game_board.getRandomMove();
	bestMove = moveCritical;
	bestScore = 0;
	hasBestMove = true;
	max_depth = 1;

	std::vector<BitMove> bestPV;
	int window = 30;
	int a = -window, b = window;

	for(; timer.getTime() < time; ) {
		flattenHistory();

		if(tournamentTimeControll) {
			if(timer.getTime() * 2 >= time) {
				break;
			}

			if(max_depth == 1) {
				game_board.bitBoardMoveGenerator(moveArray[0], stress);
				BitMove mv;
				uint8_t color;
				if(game_board.currentState.whiteMove) {
					color = WHITE;
				} else {
					color = BLACK;
				}
				int count = 0;
				for(unsigned int i = 0; i < moveArray[0].moveArray.size(); ++i) {
					game_board.move(moveArray[0].moveArray[i]);
					if(!game_board.inCheck(color)) {
						++count;
						mv = moveArray[0].moveArray[i];
					}

					game_board.goBack();
				}

				if(count == 1) {
					bestMove = mv;
					break;
				}
			}
		}

		//negamax(game_board, -WHITE_WIN, WHITE_WIN, max_depth, 0, FIXED_TIME, false, true);

		int f = negamax(game_board, a, b, max_depth, 0, FIXED_TIME, false, true);

		if(f <= a) {
			f = negamax(game_board, -WHITE_WIN, a, max_depth, 0, FIXED_TIME, false, true);
		} else if(f >= b) {
			f = negamax(game_board, b, WHITE_WIN, max_depth, 0, FIXED_TIME, false, true);
		}

		a = f - window;
		b = f + window;

		if(stopped) {
			break;
		}

		hasBestMove = true;
		++max_depth;
	}

	end_timer = clock();

	if(hasBestMove) {
		std::cout << "bestmove " << bestMove.getMoveString() << std::endl;
	}
}

void Game::goTournament() {
	double tm, inc;
	if(game_board.currentState.whiteMove) {
		tm = wtime;
		inc = winc;
	} else {
		tm = btime;
		inc = binc;
	}

	double k;

	int figuresNumber = game_board.popcount64(game_board.currentState.white_bit_mask | game_board.currentState.black_bit_mask);

	if(movestogoEnable) {
		k = movestogo;
		goFixedTime(tm / (k + 1) + inc / 2, true);
	} else {
		k = 40 - (32 - figuresNumber);
		goFixedTime(tm / k + inc / 2 - 100, true);
	}
}

bool Game::move(std::string mv) {
	MoveArray moves;
	game_board.bitBoardMoveGenerator(moves, stress);
	for(unsigned int i = 0; i < moves.count; ++i) {
		if(moves.moveArray[i].getMoveString() == mv) {
			game_board.move(moves.moveArray[i]);
			uint8_t color;

			if(game_board.currentState.whiteMove) {
				color = BLACK;
			} else {
				color = WHITE;
			}

			if(game_board.inCheck(color)) {
				game_board.goBack();
				continue;
			}

			++hash_decrement;

			return true;
		}
	}

	return false;
}
<commit_msg>Реализовано aspiration window<commit_after>#include "game.hpp"

int Game::startGame() {
	std::string str;
	uciHandler("position startpos");

	while(true) {
		std::getline(std::cin, str);

		if(!uciHandler(str)) {
			return 0;
		};
	}
}

void Game::goFixedDepth() {
	++hashAge;

	if(option.UCI_AnalyseMode || abs(bestScore) >= (WHITE_WIN - 100)) {
		clearCash();
	}

	stopped = false;
	std::vector<uint64_t>hash;

	nodesCounter = 0;
	int max_depth_global = max_depth;
	max_depth = 1;

	start_timer = clock();
	hasBestMove = false;

	BitMove moveCritical = game_board.getRandomMove();
	bestMove = moveCritical;
	hasBestMove = true;
	bestScore = 0;

	int window = 30;
	int a = -window, b = window;

	for(; max_depth <= max_depth_global; ++max_depth) {
		flattenHistory();

		int f = negamax(game_board, a, b, max_depth, 0, FIXED_DEPTH, false, true);

		if(f <= a) {
			f = negamax(game_board, -WHITE_WIN, a, max_depth, 0, FIXED_DEPTH, false, true);
		} else if(f >= b) {
			f = negamax(game_board, b, WHITE_WIN, max_depth, 0, FIXED_DEPTH, false, true);
		}

		a = f - window;
		b = f + window;

		hasBestMove = true;

		if((abs(bestScore) >= (WHITE_WIN - 100) && max_depth_global < 99) || stopped) {
			break;
		}
	}

	end_timer = clock();

	if(hasBestMove) {
		std::cout << "bestmove " << bestMove.getMoveString() << std::endl;
	}
}

void Game::goFixedTime(int64_t tm, bool tournamentTimeControll) {
	tm -= option.moveOverhead;
	tm = std::max(tm, (int64_t)10);

	++hashAge;
	stopped = false;

	time = tm;
	timer.start();

	if(option.UCI_AnalyseMode || abs(bestScore) >= (WHITE_WIN - 100)) {
		clearCash();
	}

	std::vector<uint64_t>hash;

	nodesCounter = 0;

	start_timer = clock();
	hasBestMove = false;

	BitMove moveCritical = game_board.getRandomMove();
	bestMove = moveCritical;
	bestScore = 0;
	hasBestMove = true;
	max_depth = 1;

	std::vector<BitMove> bestPV;
	int window = 30;
	int a = -window, b = window;

	for(; timer.getTime() < time; ) {
		flattenHistory();

		if(tournamentTimeControll) {
			if(timer.getTime() * 2 >= time) {
				break;
			}

			if(max_depth == 1) {
				game_board.bitBoardMoveGenerator(moveArray[0], stress);
				BitMove mv;
				uint8_t color;
				if(game_board.currentState.whiteMove) {
					color = WHITE;
				} else {
					color = BLACK;
				}
				int count = 0;
				for(unsigned int i = 0; i < moveArray[0].moveArray.size(); ++i) {
					game_board.move(moveArray[0].moveArray[i]);
					if(!game_board.inCheck(color)) {
						++count;
						mv = moveArray[0].moveArray[i];
					}

					game_board.goBack();
				}

				if(count == 1) {
					bestMove = mv;
					break;
				}
			}
		}

		int f = negamax(game_board, a, b, max_depth, 0, FIXED_TIME, false, true);

		if(f <= a) {
			f = negamax(game_board, -WHITE_WIN, a, max_depth, 0, FIXED_TIME, false, true);
		} else if(f >= b) {
			f = negamax(game_board, b, WHITE_WIN, max_depth, 0, FIXED_TIME, false, true);
		}

		a = f - window;
		b = f + window;

		if(stopped) {
			break;
		}

		hasBestMove = true;
		++max_depth;
	}

	end_timer = clock();

	if(hasBestMove) {
		std::cout << "bestmove " << bestMove.getMoveString() << std::endl;
	}
}

void Game::goTournament() {
	double tm, inc;
	if(game_board.currentState.whiteMove) {
		tm = wtime;
		inc = winc;
	} else {
		tm = btime;
		inc = binc;
	}

	double k;

	int figuresNumber = game_board.popcount64(game_board.currentState.white_bit_mask | game_board.currentState.black_bit_mask);

	if(movestogoEnable) {
		k = movestogo;
		goFixedTime(tm / (k + 1) + inc / 2, true);
	} else {
		k = 40 - (32 - figuresNumber);
		goFixedTime(tm / k + inc / 2 - 100, true);
	}
}

bool Game::move(std::string mv) {
	MoveArray moves;
	game_board.bitBoardMoveGenerator(moves, stress);
	for(unsigned int i = 0; i < moves.count; ++i) {
		if(moves.moveArray[i].getMoveString() == mv) {
			game_board.move(moves.moveArray[i]);
			uint8_t color;

			if(game_board.currentState.whiteMove) {
				color = BLACK;
			} else {
				color = WHITE;
			}

			if(game_board.inCheck(color)) {
				game_board.goBack();
				continue;
			}

			++hash_decrement;

			return true;
		}
	}

	return false;
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(FUNCTIONNORMALIZE_HEADER_GUARD_1357924680)
#define FUNCTIONNORMALIZE_HEADER_GUARD_1357924680

// Base header file.  Must be first.
#include <XPath/XPathDefinitions.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

// Base class header file...
#include <XPath/FunctionDefaultStringArgument.hpp>

#include <XPath/NodeRefListBase.hpp>
#include <XPath/XObject.hpp>
#include <XPath/XObjectFactory.hpp>
#include <XPath/XPathExecutionContext.hpp>

/**
 * XPath implementation of "normalize-space" function.
 */
//
// These are all inline, even though
// there are virtual functions, because we expect that they will only be
// needed by the XPath class.
class XALAN_XPATH_EXPORT FunctionNormalizeSpace : public FunctionDefaultStringArgument
{
public:

	// These methods are inherited from FunctionDefaultStringArgument ...

	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								/* opPos */,
			const XObjectArgVectorType&		args)
	{
		XalanDOMString	theSourceString;

		if(args.size() > 2)
		{
			executionContext.error("The normalize-space() function takes zero arguments or one argument!",
								   context);

			// Dummy return...
			return 0;
		}
		else if (args.size() == 1)
		{
			return normalize(executionContext, args[0]->str());
		}
		else if (context == 0)
		{
			executionContext.error("The normalize-space() function requires a non-null context node!",
								   context);

			// Dummy return...
			return 0;
		}
		else
		{
			return normalize(executionContext, getDefaultStringArgument(executionContext, *context));
		}
	}

#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionNormalizeSpace*
#endif
	clone() const
	{
		return new FunctionNormalizeSpace(*this);
	}

private:

	XObject*
	normalize(
			XPathExecutionContext&	executionContext,
			const XalanDOMString&	theString)
	{
		const unsigned int		theStringLength = length(theString);

		XalanDOMChar			thePreviousChar = 0;

		// A vector to contain the new characters.  We'll use it to construct
		// the result string.
#if !defined(XALAN_NO_NAMESPACES)
		using std::vector;
#endif

#if defined(XALAN_NO_NAMESPACES)
		typedef vector<XalanDOMChar>		VectorType;
#else
		typedef std::vector<XalanDOMChar>	VectorType;
#endif

		// A vector to contain the result.
		VectorType				theVector;

		// The result string can only be as large as the source string, so
		// just reserve the space now.
		theVector.reserve(theStringLength);

		// OK, strip out any multiple spaces...
		for (unsigned int i = 0; i < theStringLength; i++)
		{
			const XalanDOMChar	theCurrentChar = charAt(theString, i);

			if (isXMLWhitespace(theCurrentChar) == true)
			{
				// If the previous character wasn't a space, and we've
				// encountered some non-space characters, then push the
				// space.
				if (isXMLWhitespace(thePreviousChar) == false && theVector.size() > 0)
				{
					theVector.push_back(XalanDOMChar(XalanUnicode::charSpace));
				}
			}
			else
			{
				theVector.push_back(theCurrentChar);
			}

			thePreviousChar = theCurrentChar;
		}

		const VectorType::size_type		theSize = theVector.size();

		if (theSize == 0)
		{
			return executionContext.getXObjectFactory().createString(XalanDOMString());
		}
		else
		{
			if (isXMLWhitespace(theVector.back()) == true)
			{
				// The last character is a space, so remove it
				theVector.pop_back();
			}

			return executionContext.getXObjectFactory().createString(XalanDOMString(theVector.begin(), theSize));
		}
	}

	// Not implemented...
	FunctionNormalizeSpace&
	operator=(const FunctionNormalizeSpace&);

	bool
	operator==(const FunctionNormalizeSpace&) const;
};

#endif	// FUNCTIONNORMALIZE_HEADER_GUARD_1357924680
<commit_msg>Changed how trailing whitespace is handled.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(FUNCTIONNORMALIZE_HEADER_GUARD_1357924680)
#define FUNCTIONNORMALIZE_HEADER_GUARD_1357924680

// Base header file.  Must be first.
#include <XPath/XPathDefinitions.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanUnicode.hpp>

// Base class header file...
#include <XPath/FunctionDefaultStringArgument.hpp>

#include <XPath/NodeRefListBase.hpp>
#include <XPath/XObject.hpp>
#include <XPath/XObjectFactory.hpp>
#include <XPath/XPathExecutionContext.hpp>

/**
 * XPath implementation of "normalize-space" function.
 */
//
// These are all inline, even though
// there are virtual functions, because we expect that they will only be
// needed by the XPath class.
class XALAN_XPATH_EXPORT FunctionNormalizeSpace : public FunctionDefaultStringArgument
{
public:

	// These methods are inherited from FunctionDefaultStringArgument ...

	virtual XObject*
	execute(
			XPathExecutionContext&			executionContext,
			XalanNode*						context,
			int								/* opPos */,
			const XObjectArgVectorType&		args)
	{
		XalanDOMString	theSourceString;

		if(args.size() > 2)
		{
			executionContext.error("The normalize-space() function takes zero arguments or one argument!",
								   context);

			// Dummy return...
			return 0;
		}
		else if (args.size() == 1)
		{
			return normalize(executionContext, args[0]->str());
		}
		else if (context == 0)
		{
			executionContext.error("The normalize-space() function requires a non-null context node!",
								   context);

			// Dummy return...
			return 0;
		}
		else
		{
			return normalize(executionContext, getDefaultStringArgument(executionContext, *context));
		}
	}

#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
	virtual Function*
#else
	virtual FunctionNormalizeSpace*
#endif
	clone() const
	{
		return new FunctionNormalizeSpace(*this);
	}

private:

	XObject*
	normalize(
			XPathExecutionContext&	executionContext,
			const XalanDOMString&	theString)
	{
		const unsigned int		theStringLength = length(theString);

		XalanDOMChar			thePreviousChar = 0;

		// A vector to contain the new characters.  We'll use it to construct
		// the result string.
#if !defined(XALAN_NO_NAMESPACES)
		using std::vector;
#endif

#if defined(XALAN_NO_NAMESPACES)
		typedef vector<XalanDOMChar>		VectorType;
#else
		typedef std::vector<XalanDOMChar>	VectorType;
#endif

		// A vector to contain the result.
		VectorType				theVector;

		// The result string can only be as large as the source string, so
		// just reserve the space now.
		theVector.reserve(theStringLength);

		// OK, strip out any multiple spaces...
		for (unsigned int i = 0; i < theStringLength; i++)
		{
			const XalanDOMChar	theCurrentChar = charAt(theString, i);

			if (isXMLWhitespace(theCurrentChar) == true)
			{
				// If the previous character wasn't a space, and we've
				// encountered some non-space characters, then push the
				// space.
				if (isXMLWhitespace(thePreviousChar) == false && theVector.size() > 0)
				{
					theVector.push_back(XalanDOMChar(XalanUnicode::charSpace));
				}
			}
			else
			{
				theVector.push_back(theCurrentChar);
			}

			thePreviousChar = theCurrentChar;
		}

		VectorType::size_type	theSize = theVector.size();

		if (theSize == 0)
		{
			return executionContext.getXObjectFactory().createString(XalanDOMString());
		}
		else
		{
			if (isXMLWhitespace(theVector.back()) == true)
			{
				// The last character is a space, so remove it
				--theSize;
			}

			return executionContext.getXObjectFactory().createString(XalanDOMString(theVector.begin(), theSize));
		}
	}

	// Not implemented...
	FunctionNormalizeSpace&
	operator=(const FunctionNormalizeSpace&);

	bool
	operator==(const FunctionNormalizeSpace&) const;
};

#endif	// FUNCTIONNORMALIZE_HEADER_GUARD_1357924680
<|endoftext|>


<commit_before><commit_msg>Fixed assets tests when all assets removed<commit_after><|endoftext|>


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

#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <vector>
#include <cassert>

#include <LoggingKit/LoggingKit.h>
#include <Core/ConfigChange.h>
#include <Core/Config.h>

namespace Passenger {
namespace Core {

using namespace std;

struct ConfigChangeRequest {
	Json::Value updates;
	PrepareConfigChangeCallback prepareCallback;
	CommitConfigChangeCallback commitCallback;
	unsigned int counter;
	vector<ConfigKit::Error> errors;

	boost::scoped_ptr<ConfigKit::Store> config;
	LoggingKit::ConfigChangeRequest forLoggingKit;
	SecurityUpdateChecker::ConfigChangeRequest forSecurityUpdateChecker;
	vector<ServerKit::ConfigChangeRequest *> forControllerServerKit;
	vector<Controller::ConfigChangeRequest *> forController;
	ServerKit::ConfigChangeRequest forApiServerKit;
	ApiServer::ConfigChangeRequest forApiServer;
	AdminPanelConnector::ConfigChangeRequest forAdminPanelConnector;

	ConfigChangeRequest()
		: counter(0)
		{ }

	~ConfigChangeRequest() {
		{
			vector<ServerKit::ConfigChangeRequest *>::iterator it;
			for (it = forControllerServerKit.begin(); it != forControllerServerKit.end(); it++) {
				delete *it;
			}
		}
		{
			vector<Controller::ConfigChangeRequest *>::iterator it;
			for (it = forController.begin(); it != forController.end(); it++) {
				delete *it;
			}
		}
	}
};

/**************** Functions: prepare config change ****************/

static void
asyncPrepareConfigChangeCompletedOne(ConfigChangeRequest *req) {
	assert(req->counter > 0);
	req->counter--;
	if (req->counter == 0) {
		req->errors = ConfigKit::deduplicateErrors(req->errors);
		if (req->errors.empty()) {
			P_INFO("Changing configuration: " << req->updates.toStyledString());
		} else {
			P_ERROR("Error changing configuration: " << ConfigKit::toString(req->errors)
				<< "\nThe proposed configuration was: " << req->updates.toStyledString());
		}
		oxt::thread(boost::bind(req->prepareCallback, req->errors, req),
			"Core config callback thread",
			128 * 1024);
	}
}

static void
asyncPrepareConfigChangeForController(unsigned int i, const Json::Value &updates, ConfigChangeRequest *req) {
	ThreadWorkingObjects *two = &workingObjects->threadWorkingObjects[i];
	vector<ConfigKit::Error> errors1, errors2;

	req->forControllerServerKit[i] = new ServerKit::ConfigChangeRequest();
	ConfigKit::prepareConfigChangeForSubComponent(
		*two->serverKitContext, coreSchema->controllerServerKit.translator,
		req->config->inspectEffectiveValues(),
		errors1, *req->forControllerServerKit[i]);

	req->forController[i] = new Controller::ConfigChangeRequest();
	ConfigKit::prepareConfigChangeForSubComponent(
		*two->controller, coreSchema->controller.translator,
		req->config->inspectEffectiveValues(),
		errors2, *req->forController[i]);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForController(" << i << "): counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), errors1.begin(), errors1.end());
	req->errors.insert(req->errors.begin(), errors2.begin(), errors2.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

static void
asyncPrepareConfigChangeForApiServer(const Json::Value &updates, ConfigChangeRequest *req) {
	vector<ConfigKit::Error> errors1, errors2;

	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->apiWorkingObjects.serverKitContext,
		coreSchema->apiServerKit.translator,
		req->config->inspectEffectiveValues(),
		errors1, req->forApiServerKit);
	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->apiWorkingObjects.apiServer,
		coreSchema->apiServer.translator,
		req->config->inspectEffectiveValues(),
		errors2, req->forApiServer);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForApiServer: counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), errors1.begin(), errors1.end());
	req->errors.insert(req->errors.begin(), errors2.begin(), errors2.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

static void
asyncPrepareConfigChangeForAdminPanelConnectorDone(const vector<ConfigKit::Error> &errors,
	AdminPanelConnector::ConfigChangeRequest &_, ConfigChangeRequest *req)
{
	vector<ConfigKit::Error> translatedErrors = coreSchema->adminPanelConnector.translator.reverseTranslate(errors);
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForAdminPanelConnectorDone: counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), translatedErrors.begin(), translatedErrors.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

//
//

void
asyncPrepareConfigChange(const Json::Value &updates, ConfigChangeRequest *req,
	const PrepareConfigChangeCallback &callback)
{
	P_DEBUG("Preparing configuration change: " << updates.toStyledString());
	WorkingObjects *wo = workingObjects;
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);

	req->updates = updates;
	req->prepareCallback = callback;
	req->counter++;

	req->config.reset(new ConfigKit::Store(*coreConfig, updates, req->errors));
	if (!req->errors.empty()) {
		asyncPrepareConfigChangeCompletedOne(req);
		return;
	}

	ConfigKit::prepareConfigChangeForSubComponent(
		*LoggingKit::context, coreSchema->loggingKit.translator,
		req->config->inspectEffectiveValues(),
		req->errors, req->forLoggingKit);
	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->securityUpdateChecker,
		coreSchema->securityUpdateChecker.translator,
		req->config->inspectEffectiveValues(),
		req->errors, req->forSecurityUpdateChecker);

	req->forControllerServerKit.resize(wo->threadWorkingObjects.size(), NULL);
	req->forController.resize(wo->threadWorkingObjects.size(), NULL);
	for (unsigned int i = 0; i < wo->threadWorkingObjects.size(); i++) {
		ThreadWorkingObjects *two = &wo->threadWorkingObjects[i];
		req->counter++;
		two->bgloop->safe->runLater(boost::bind(asyncPrepareConfigChangeForController,
			i, updates, req));
	}

	if (wo->apiWorkingObjects.apiServer != NULL) {
		req->counter++;
		wo->apiWorkingObjects.bgloop->safe->runLater(boost::bind(
			asyncPrepareConfigChangeForApiServer, updates, req));
	}

	if (wo->adminPanelConnector != NULL) {
		req->counter++;
		wo->adminPanelConnector->asyncPrepareConfigChange(
			coreSchema->adminPanelConnector.translator.translate(updates),
			req->forAdminPanelConnector,
			boost::bind(asyncPrepareConfigChangeForAdminPanelConnectorDone,
				boost::placeholders::_1, boost::placeholders::_2, req));
	}

	/***************/
	/***************/

	asyncPrepareConfigChangeCompletedOne(req);
}

/**************** Functions: commit config change ****************/

static void
asyncCommitConfigChangeCompletedOne(ConfigChangeRequest *req) {
	assert(req->counter > 0);
	req->counter--;
	if (req->counter == 0) {
		oxt::thread(boost::bind(req->commitCallback, req),
			"Core config callback thread",
			128 * 1024);
	}
}

static void
asyncCommitConfigChangeForController(unsigned int i, ConfigChangeRequest *req) {
	ThreadWorkingObjects *two = &workingObjects->threadWorkingObjects[i];

	two->serverKitContext->commitConfigChange(*req->forControllerServerKit[i]);
	two->controller->commitConfigChange(*req->forController[i]);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForController(" << i << "): counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

static void
asyncCommitConfigChangeForApiServer(ConfigChangeRequest *req) {
	ApiWorkingObjects *awo = &workingObjects->apiWorkingObjects;

	awo->serverKitContext->commitConfigChange(req->forApiServerKit);
	awo->apiServer->commitConfigChange(req->forApiServer);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForApiServer: counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

static void
asyncCommitConfigChangeForAdminPanelConnectorDone(AdminPanelConnector::ConfigChangeRequest &_,
	ConfigChangeRequest *req)
{
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForAdminPanelConnectorDone: counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

//
//

void
asyncCommitConfigChange(ConfigChangeRequest *req, const CommitConfigChangeCallback &callback)
	BOOST_NOEXCEPT_OR_NOTHROW
{
	WorkingObjects *wo = workingObjects;
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);

	req->commitCallback = callback;
	req->counter++;

	{
		boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
		coreConfig->swap(*req->config);
	}
	LoggingKit::context->commitConfigChange(req->forLoggingKit);
	workingObjects->securityUpdateChecker->commitConfigChange(
		req->forSecurityUpdateChecker);

	wo->appPool->setMax(coreConfig->get("max_pool_size").asInt());
	wo->appPool->setMaxIdleTime(coreConfig->get("pool_idle_time").asInt() * 1000000ULL);
	wo->appPool->enableSelfChecking(coreConfig->get("pool_selfchecks").asBool());

	for (unsigned int i = 0; i < wo->threadWorkingObjects.size(); i++) {
		ThreadWorkingObjects *two = &wo->threadWorkingObjects[i];
		req->counter++;
		two->bgloop->safe->runLater(boost::bind(asyncCommitConfigChangeForController,
			i, req));
	}

	if (wo->apiWorkingObjects.apiServer != NULL) {
		req->counter++;
		wo->apiWorkingObjects.bgloop->safe->runLater(boost::bind(
			asyncCommitConfigChangeForApiServer, req));
	}

	if (wo->adminPanelConnector != NULL) {
		req->counter++;
		wo->adminPanelConnector->asyncCommitConfigChange(
			req->forAdminPanelConnector,
			boost::bind(asyncCommitConfigChangeForAdminPanelConnectorDone,
				boost::placeholders::_1, req));
	}

	/***************/
	/***************/

	asyncCommitConfigChangeCompletedOne(req);
}

/**************** Functions: miscellaneous ****************/

inline ConfigChangeRequest *
createConfigChangeRequest() {
	return new ConfigChangeRequest();
}

inline void
freeConfigChangeRequest(ConfigChangeRequest *req) {
	delete req;
}

Json::Value
inspectConfig() {
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	return coreConfig->inspect();
}

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

#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <vector>
#include <cassert>

#include <LoggingKit/LoggingKit.h>
#include <Core/ConfigChange.h>
#include <Core/Config.h>

namespace Passenger {
namespace Core {

using namespace std;

struct ConfigChangeRequest {
	Json::Value updates;
	PrepareConfigChangeCallback prepareCallback;
	CommitConfigChangeCallback commitCallback;
	unsigned int counter;
	vector<ConfigKit::Error> errors;

	boost::scoped_ptr<ConfigKit::Store> config;
	LoggingKit::ConfigChangeRequest forLoggingKit;
	SecurityUpdateChecker::ConfigChangeRequest forSecurityUpdateChecker;
	vector<ServerKit::ConfigChangeRequest *> forControllerServerKit;
	vector<Controller::ConfigChangeRequest *> forController;
	ServerKit::ConfigChangeRequest forApiServerKit;
	ApiServer::ConfigChangeRequest forApiServer;
	AdminPanelConnector::ConfigChangeRequest forAdminPanelConnector;

	ConfigChangeRequest()
		: counter(0)
		{ }

	~ConfigChangeRequest() {
		{
			vector<ServerKit::ConfigChangeRequest *>::iterator it;
			for (it = forControllerServerKit.begin(); it != forControllerServerKit.end(); it++) {
				delete *it;
			}
		}
		{
			vector<Controller::ConfigChangeRequest *>::iterator it;
			for (it = forController.begin(); it != forController.end(); it++) {
				delete *it;
			}
		}
	}
};

/**************** Functions: prepare config change ****************/

static void
asyncPrepareConfigChangeCompletedOne(ConfigChangeRequest *req) {
	assert(req->counter > 0);
	req->counter--;
	if (req->counter == 0) {
		req->errors = ConfigKit::deduplicateErrors(req->errors);
		if (req->errors.empty()) {
			P_INFO("Changing configuration: " << req->updates.toStyledString());
		} else {
			P_ERROR("Error changing configuration: " << ConfigKit::toString(req->errors)
				<< "\nThe proposed configuration was: " << req->updates.toStyledString());
		}
		oxt::thread(boost::bind(req->prepareCallback, req->errors, req),
			"Core config callback thread",
			128 * 1024);
	}
}

static void
asyncPrepareConfigChangeForController(unsigned int i, const Json::Value &updates, ConfigChangeRequest *req) {
	ThreadWorkingObjects *two = &workingObjects->threadWorkingObjects[i];
	vector<ConfigKit::Error> errors1, errors2;

	req->forControllerServerKit[i] = new ServerKit::ConfigChangeRequest();
	ConfigKit::prepareConfigChangeForSubComponent(
		*two->serverKitContext, coreSchema->controllerServerKit.translator,
		req->config->inspectEffectiveValues(),
		errors1, *req->forControllerServerKit[i]);

	req->forController[i] = new Controller::ConfigChangeRequest();
	ConfigKit::prepareConfigChangeForSubComponent(
		*two->controller, coreSchema->controller.translator,
		req->config->inspectEffectiveValues(),
		errors2, *req->forController[i]);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForController(" << i << "): counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), errors1.begin(), errors1.end());
	req->errors.insert(req->errors.begin(), errors2.begin(), errors2.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

static void
asyncPrepareConfigChangeForApiServer(const Json::Value &updates, ConfigChangeRequest *req) {
	vector<ConfigKit::Error> errors1, errors2;

	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->apiWorkingObjects.serverKitContext,
		coreSchema->apiServerKit.translator,
		req->config->inspectEffectiveValues(),
		errors1, req->forApiServerKit);
	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->apiWorkingObjects.apiServer,
		coreSchema->apiServer.translator,
		req->config->inspectEffectiveValues(),
		errors2, req->forApiServer);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForApiServer: counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), errors1.begin(), errors1.end());
	req->errors.insert(req->errors.begin(), errors2.begin(), errors2.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

static void
asyncPrepareConfigChangeForAdminPanelConnectorDone(const vector<ConfigKit::Error> &errors,
	AdminPanelConnector::ConfigChangeRequest &_, ConfigChangeRequest *req)
{
	vector<ConfigKit::Error> translatedErrors = coreSchema->adminPanelConnector.translator.reverseTranslate(errors);
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncPrepareConfigChangeForAdminPanelConnectorDone: counter "
		<< req->counter << " -> " << (req->counter - 1));
	req->errors.insert(req->errors.begin(), translatedErrors.begin(), translatedErrors.end());
	asyncPrepareConfigChangeCompletedOne(req);
}

//
//

void
asyncPrepareConfigChange(const Json::Value &updates, ConfigChangeRequest *req,
	const PrepareConfigChangeCallback &callback)
{
	P_DEBUG("Preparing configuration change: " << updates.toStyledString());
	WorkingObjects *wo = workingObjects;
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);

	req->updates = updates;
	req->prepareCallback = callback;
	req->counter++;

	req->config.reset(new ConfigKit::Store(*coreConfig, updates, req->errors));
	if (!req->errors.empty()) {
		asyncPrepareConfigChangeCompletedOne(req);
		return;
	}

	ConfigKit::prepareConfigChangeForSubComponent(
		*LoggingKit::context, coreSchema->loggingKit.translator,
		req->config->inspectEffectiveValues(),
		req->errors, req->forLoggingKit);
	ConfigKit::prepareConfigChangeForSubComponent(
		*workingObjects->securityUpdateChecker,
		coreSchema->securityUpdateChecker.translator,
		req->config->inspectEffectiveValues(),
		req->errors, req->forSecurityUpdateChecker);

	req->forControllerServerKit.resize(wo->threadWorkingObjects.size(), NULL);
	req->forController.resize(wo->threadWorkingObjects.size(), NULL);
	for (unsigned int i = 0; i < wo->threadWorkingObjects.size(); i++) {
		ThreadWorkingObjects *two = &wo->threadWorkingObjects[i];
		req->counter++;
		two->bgloop->safe->runLater(boost::bind(asyncPrepareConfigChangeForController,
			i, updates, req));
	}

	if (wo->apiWorkingObjects.apiServer != NULL) {
		req->counter++;
		wo->apiWorkingObjects.bgloop->safe->runLater(boost::bind(
			asyncPrepareConfigChangeForApiServer, updates, req));
	}

	if (wo->adminPanelConnector != NULL) {
		req->counter++;
		wo->adminPanelConnector->asyncPrepareConfigChange(
			coreSchema->adminPanelConnector.translator.translate(updates),
			req->forAdminPanelConnector,
			boost::bind(asyncPrepareConfigChangeForAdminPanelConnectorDone,
				boost::placeholders::_1, boost::placeholders::_2, req));
	}

	/***************/
	/***************/

	asyncPrepareConfigChangeCompletedOne(req);
}

/**************** Functions: commit config change ****************/

static void
asyncCommitConfigChangeCompletedOne(ConfigChangeRequest *req) {
	assert(req->counter > 0);
	req->counter--;
	if (req->counter == 0) {
		oxt::thread(boost::bind(req->commitCallback, req),
			"Core config callback thread",
			128 * 1024);
	}
}

static void
asyncCommitConfigChangeForController(unsigned int i, ConfigChangeRequest *req) {
	ThreadWorkingObjects *two = &workingObjects->threadWorkingObjects[i];

	two->serverKitContext->commitConfigChange(*req->forControllerServerKit[i]);
	two->controller->commitConfigChange(*req->forController[i]);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForController(" << i << "): counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

static void
asyncCommitConfigChangeForApiServer(ConfigChangeRequest *req) {
	ApiWorkingObjects *awo = &workingObjects->apiWorkingObjects;

	awo->serverKitContext->commitConfigChange(req->forApiServerKit);
	awo->apiServer->commitConfigChange(req->forApiServer);

	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForApiServer: counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

static void
asyncCommitConfigChangeForAdminPanelConnectorDone(AdminPanelConnector::ConfigChangeRequest &_,
	ConfigChangeRequest *req)
{
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	P_DEBUG("asyncCommitConfigChangeForAdminPanelConnectorDone: counter "
		<< req->counter << " -> " << (req->counter - 1));
	asyncCommitConfigChangeCompletedOne(req);
}

//
//

void
asyncCommitConfigChange(ConfigChangeRequest *req, const CommitConfigChangeCallback &callback)
	BOOST_NOEXCEPT_OR_NOTHROW
{
	WorkingObjects *wo = workingObjects;
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);

	req->commitCallback = callback;
	req->counter++;

	coreConfig->swap(*req->config);
	LoggingKit::context->commitConfigChange(req->forLoggingKit);
	workingObjects->securityUpdateChecker->commitConfigChange(
		req->forSecurityUpdateChecker);

	wo->appPool->setMax(coreConfig->get("max_pool_size").asInt());
	wo->appPool->setMaxIdleTime(coreConfig->get("pool_idle_time").asInt() * 1000000ULL);
	wo->appPool->enableSelfChecking(coreConfig->get("pool_selfchecks").asBool());

	for (unsigned int i = 0; i < wo->threadWorkingObjects.size(); i++) {
		ThreadWorkingObjects *two = &wo->threadWorkingObjects[i];
		req->counter++;
		two->bgloop->safe->runLater(boost::bind(asyncCommitConfigChangeForController,
			i, req));
	}

	if (wo->apiWorkingObjects.apiServer != NULL) {
		req->counter++;
		wo->apiWorkingObjects.bgloop->safe->runLater(boost::bind(
			asyncCommitConfigChangeForApiServer, req));
	}

	if (wo->adminPanelConnector != NULL) {
		req->counter++;
		wo->adminPanelConnector->asyncCommitConfigChange(
			req->forAdminPanelConnector,
			boost::bind(asyncCommitConfigChangeForAdminPanelConnectorDone,
				boost::placeholders::_1, req));
	}

	/***************/
	/***************/

	asyncCommitConfigChangeCompletedOne(req);
}

/**************** Functions: miscellaneous ****************/

inline ConfigChangeRequest *
createConfigChangeRequest() {
	return new ConfigChangeRequest();
}

inline void
freeConfigChangeRequest(ConfigChangeRequest *req) {
	delete req;
}

Json::Value
inspectConfig() {
	boost::lock_guard<boost::mutex> l(workingObjects->configSyncher);
	return coreConfig->inspect();
}

} // namespace Core
} // namespace Passenger
<|endoftext|>


<commit_before>#pragma once

#include <i3ipc++/ipc.hpp>

#include "config.hpp"
#include "components/config.hpp"
#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
#include "modules/meta.hpp"
#include "utils/i3.hpp"
#include "utils/io.hpp"

LEMONBUDDY_NS

namespace modules {
  // meta types {{{

  enum class i3_flag {
    WORKSPACE_NONE,
    WORKSPACE_FOCUSED,
    WORKSPACE_UNFOCUSED,
    WORKSPACE_VISIBLE,
    WORKSPACE_URGENT,
  };

  struct i3_workspace {
    int index;
    i3_flag flag;
    label_t label;

    i3_workspace(int index_, i3_flag flag_, label_t&& label_)
        : index(index_), flag(flag_), label(forward<decltype(label_)>(label_)) {}

    operator bool() {
      return label && *label;
    }
  };

  using i3_workspace_t = unique_ptr<i3_workspace>;

  // }}}

  class i3_module : public event_module<i3_module> {
   public:
    using event_module::event_module;

    ~i3_module() {
      // Shutdown ipc connection {{{

      try {
        shutdown(m_ipc.get_event_socket_fd(), SHUT_RD);
        shutdown(m_ipc.get_main_socket_fd(), SHUT_RD);
      } catch (const std::exception& err) {
      }

      // }}}
    }

    void setup() {
      // Load configuration values {{{

      GET_CONFIG_VALUE(name(), m_indexsort, "index-sort");
      GET_CONFIG_VALUE(name(), m_pinworkspaces, "pin-workspaces");
      GET_CONFIG_VALUE(name(), m_strip_wsnumbers, "strip-wsnumbers");
      GET_CONFIG_VALUE(name(), m_wsname_maxlen, "wsname-maxlen");

      // }}}
      // Add formats and create components {{{

      m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE});

      if (m_formatter->has(TAG_LABEL_STATE)) {
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_FOCUSED,
            get_optional_config_label(m_conf, name(), "label-focused", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_UNFOCUSED,
            get_optional_config_label(m_conf, name(), "label-unfocused", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_VISIBLE,
            get_optional_config_label(m_conf, name(), "label-visible", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_URGENT,
            get_optional_config_label(m_conf, name(), "label-urgent", DEFAULT_WS_LABEL)));
      }

      m_icons = iconset_t{new iconset()};
      m_icons->add(
          DEFAULT_WS_ICON, icon_t{new icon(m_conf.get<string>(name(), DEFAULT_WS_ICON, ""))});

      // }}}
      // Add formats and create components {{{

      for (auto workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
        auto vec = string_util::split(workspace, ';');
        if (vec.size() == 2)
          m_icons->add(vec[0], icon_t{new icon{vec[1]}});
      }

      // }}}
      // Subscribe to ipc events {{{

      try {
        m_ipc.subscribe(i3ipc::ET_WORKSPACE);
        m_ipc.prepare_to_event_handling();
      } catch (std::runtime_error& e) {
        throw module_error(e.what());
      }

      // }}}
    }

    bool has_event() {
      // Wait for ipc events {{{

      try {
        m_ipc.handle_event();
        return true;
      } catch (const std::exception& err) {
        m_log.err("%s: Error while handling ipc event, stopping module...", name());
        m_log.err("%s: %s", name(), err.what());
        stop();
        return false;
      }

      // }}}
    }

    bool update() {
      // Refresh workspace data {{{

      m_workspaces.clear();
      i3_util::connection_t ipc;

      try {
        auto workspaces = ipc.get_workspaces();
        vector<shared_ptr<i3ipc::workspace_t>> sorted = workspaces;
        string focused_output;

        for (auto&& workspace : workspaces)
          if (workspace->focused) {
            focused_output = workspace->output;
            break;
          }

        if (m_indexsort) {
          using ws_t = shared_ptr<i3ipc::workspace_t>;
          // clang-format off
          sort(sorted.begin(), sorted.end(), [](ws_t ws1, ws_t ws2){
              return ws1->num < ws2->num;
          });
          // clang-format on
        }

        for (auto&& workspace : sorted) {
          if (m_pinworkspaces && workspace->output != m_bar.monitor->name)
            continue;

          auto flag = i3_flag::WORKSPACE_NONE;
          if (workspace->focused)
            flag = i3_flag::WORKSPACE_FOCUSED;
          else if (workspace->urgent)
            flag = i3_flag::WORKSPACE_URGENT;
          else if (!workspace->visible || (workspace->visible && workspace->output != focused_output))
            flag = i3_flag::WORKSPACE_UNFOCUSED;
          else
            flag = i3_flag::WORKSPACE_VISIBLE;

          string wsname{workspace->name};

          if (m_strip_wsnumbers) {
            auto index = string_util::split(wsname, ':');

            if (index.size() == 2) {
              wsname = index[1];
            }
          }

          if (m_wsname_maxlen > 0 && wsname.length() > m_wsname_maxlen)
            wsname.erase(m_wsname_maxlen);

          auto icon = m_icons->get(workspace->name, DEFAULT_WS_ICON);
          auto label = m_statelabels.find(flag)->second->clone();

          label->replace_token("%output%", workspace->output);
          label->replace_token("%name%", wsname);
          label->replace_token("%icon%", icon->m_text);
          label->replace_token("%index%", to_string(workspace->num));
          m_workspaces.emplace_back(make_unique<i3_workspace>(workspace->num, flag, std::move(label)));
        }

        return true;
      } catch (const std::exception& err) {
        m_log.err("%s: %s", name(), err.what());
        return false;
      }

      // }}}
    }

    bool build(builder* builder, string tag) {
      // Output workspace info {{{

      if (tag != TAG_LABEL_STATE)
        return false;

      for (auto&& ws : m_workspaces) {
        builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLL_DOWN);
        builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLL_UP);
        builder->cmd(mousebtn::LEFT, string{EVENT_CLICK} + to_string(ws.get()->index));
        builder->node(ws.get()->label);
        builder->cmd_close(true);
      }
      return true;

      // }}}
    }

    bool handle_event(string cmd) {
      // Send ipc commands {{{

      if (cmd.compare(0, 2, EVENT_PREFIX) != 0)
        return false;

      try {
        i3_util::connection_t ipc;

        if (cmd.compare(0, strlen(EVENT_CLICK), EVENT_CLICK) == 0) {
          m_log.info("%s: Sending workspace focus command to ipc handler", name());
          ipc.send_command("workspace number " + cmd.substr(strlen(EVENT_CLICK)));
        } else if (cmd.compare(0, strlen(EVENT_SCROLL_DOWN), EVENT_SCROLL_DOWN) == 0) {
          m_log.info("%s: Sending workspace prev command to ipc handler", name());
          ipc.send_command("workspace next");
        } else if (cmd.compare(0, strlen(EVENT_SCROLL_UP), EVENT_SCROLL_UP) == 0) {
          m_log.info("%s: Sending workspace next command to ipc handler", name());
          ipc.send_command("workspace prev");
        }
      } catch (const std::exception& err) {
        m_log.err("%s: %s", name(), err.what());
      }

      return true;

      // }}}
    }

    bool receive_events() const {
      return true;
    }

   private:
    static constexpr auto DEFAULT_WS_ICON = "ws-icon-default";
    static constexpr auto DEFAULT_WS_LABEL = "%icon% %name%";
    static constexpr auto TAG_LABEL_STATE = "<label-state>";

    static constexpr auto EVENT_PREFIX = "i3";
    static constexpr auto EVENT_CLICK = "i3-wsfocus-";
    static constexpr auto EVENT_SCROLL_UP = "i3-wsnext";
    static constexpr auto EVENT_SCROLL_DOWN = "i3-wsprev";

    map<i3_flag, label_t> m_statelabels;
    vector<i3_workspace_t> m_workspaces;
    iconset_t m_icons;

    bool m_indexsort = false;
    bool m_pinworkspaces = false;
    bool m_strip_wsnumbers = false;
    size_t m_wsname_maxlen = 0;

    i3_util::connection_t m_ipc;
  };
}

LEMONBUDDY_NS_END
<commit_msg>Scroll through workspaces on same monitor only<commit_after>#pragma once

#include <i3ipc++/ipc.hpp>

#include "config.hpp"
#include "components/config.hpp"
#include "drawtypes/iconset.hpp"
#include "drawtypes/label.hpp"
#include "modules/meta.hpp"
#include "utils/i3.hpp"
#include "utils/io.hpp"

LEMONBUDDY_NS

namespace modules {
  // meta types {{{

  enum class i3_flag {
    WORKSPACE_NONE,
    WORKSPACE_FOCUSED,
    WORKSPACE_UNFOCUSED,
    WORKSPACE_VISIBLE,
    WORKSPACE_URGENT,
  };

  struct i3_workspace {
    int index;
    i3_flag flag;
    label_t label;

    i3_workspace(int index_, i3_flag flag_, label_t&& label_)
        : index(index_), flag(flag_), label(forward<decltype(label_)>(label_)) {}

    operator bool() {
      return label && *label;
    }
  };

  using i3_workspace_t = unique_ptr<i3_workspace>;

  // }}}

  class i3_module : public event_module<i3_module> {
   public:
    using event_module::event_module;

    ~i3_module() {
      // Shutdown ipc connection {{{

      try {
        shutdown(m_ipc.get_event_socket_fd(), SHUT_RD);
        shutdown(m_ipc.get_main_socket_fd(), SHUT_RD);
      } catch (const std::exception& err) {
      }

      // }}}
    }

    void setup() {
      // Load configuration values {{{

      GET_CONFIG_VALUE(name(), m_indexsort, "index-sort");
      GET_CONFIG_VALUE(name(), m_pinworkspaces, "pin-workspaces");
      GET_CONFIG_VALUE(name(), m_strip_wsnumbers, "strip-wsnumbers");
      GET_CONFIG_VALUE(name(), m_wsname_maxlen, "wsname-maxlen");

      // }}}
      // Add formats and create components {{{

      m_formatter->add(DEFAULT_FORMAT, TAG_LABEL_STATE, {TAG_LABEL_STATE});

      if (m_formatter->has(TAG_LABEL_STATE)) {
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_FOCUSED,
            get_optional_config_label(m_conf, name(), "label-focused", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_UNFOCUSED,
            get_optional_config_label(m_conf, name(), "label-unfocused", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_VISIBLE,
            get_optional_config_label(m_conf, name(), "label-visible", DEFAULT_WS_LABEL)));
        m_statelabels.insert(make_pair(i3_flag::WORKSPACE_URGENT,
            get_optional_config_label(m_conf, name(), "label-urgent", DEFAULT_WS_LABEL)));
      }

      m_icons = iconset_t{new iconset()};
      m_icons->add(
          DEFAULT_WS_ICON, icon_t{new icon(m_conf.get<string>(name(), DEFAULT_WS_ICON, ""))});

      // }}}
      // Add formats and create components {{{

      for (auto workspace : m_conf.get_list<string>(name(), "ws-icon", {})) {
        auto vec = string_util::split(workspace, ';');
        if (vec.size() == 2)
          m_icons->add(vec[0], icon_t{new icon{vec[1]}});
      }

      // }}}
      // Subscribe to ipc events {{{

      try {
        m_ipc.subscribe(i3ipc::ET_WORKSPACE);
        m_ipc.prepare_to_event_handling();
      } catch (std::runtime_error& e) {
        throw module_error(e.what());
      }

      // }}}
    }

    bool has_event() {
      // Wait for ipc events {{{

      try {
        m_ipc.handle_event();
        return true;
      } catch (const std::exception& err) {
        m_log.err("%s: Error while handling ipc event, stopping module...", name());
        m_log.err("%s: %s", name(), err.what());
        stop();
        return false;
      }

      // }}}
    }

    bool update() {
      // Refresh workspace data {{{

      m_workspaces.clear();
      i3_util::connection_t ipc;

      try {
        auto workspaces = ipc.get_workspaces();
        vector<shared_ptr<i3ipc::workspace_t>> sorted = workspaces;
        string focused_output;

        for (auto&& workspace : workspaces)
          if (workspace->focused) {
            focused_output = workspace->output;
            break;
          }

        if (m_indexsort) {
          using ws_t = shared_ptr<i3ipc::workspace_t>;
          // clang-format off
          sort(sorted.begin(), sorted.end(), [](ws_t ws1, ws_t ws2){
              return ws1->num < ws2->num;
          });
          // clang-format on
        }

        for (auto&& workspace : sorted) {
          if (m_pinworkspaces && workspace->output != m_bar.monitor->name)
            continue;

          auto flag = i3_flag::WORKSPACE_NONE;
          if (workspace->focused)
            flag = i3_flag::WORKSPACE_FOCUSED;
          else if (workspace->urgent)
            flag = i3_flag::WORKSPACE_URGENT;
          else if (!workspace->visible || (workspace->visible && workspace->output != focused_output))
            flag = i3_flag::WORKSPACE_UNFOCUSED;
          else
            flag = i3_flag::WORKSPACE_VISIBLE;

          string wsname{workspace->name};

          if (m_strip_wsnumbers) {
            auto index = string_util::split(wsname, ':');

            if (index.size() == 2) {
              wsname = index[1];
            }
          }

          if (m_wsname_maxlen > 0 && wsname.length() > m_wsname_maxlen)
            wsname.erase(m_wsname_maxlen);

          auto icon = m_icons->get(workspace->name, DEFAULT_WS_ICON);
          auto label = m_statelabels.find(flag)->second->clone();

          label->replace_token("%output%", workspace->output);
          label->replace_token("%name%", wsname);
          label->replace_token("%icon%", icon->m_text);
          label->replace_token("%index%", to_string(workspace->num));
          m_workspaces.emplace_back(make_unique<i3_workspace>(workspace->num, flag, std::move(label)));
        }

        return true;
      } catch (const std::exception& err) {
        m_log.err("%s: %s", name(), err.what());
        return false;
      }

      // }}}
    }

    bool build(builder* builder, string tag) {
      // Output workspace info {{{

      if (tag != TAG_LABEL_STATE)
        return false;

      for (auto&& ws : m_workspaces) {
        builder->cmd(mousebtn::SCROLL_DOWN, EVENT_SCROLL_DOWN);
        builder->cmd(mousebtn::SCROLL_UP, EVENT_SCROLL_UP);
        builder->cmd(mousebtn::LEFT, string{EVENT_CLICK} + to_string(ws.get()->index));
        builder->node(ws.get()->label);
        builder->cmd_close(true);
      }
      return true;

      // }}}
    }

    bool handle_event(string cmd) {
      // Send ipc commands {{{

      if (cmd.compare(0, 2, EVENT_PREFIX) != 0)
        return false;

      try {
        i3_util::connection_t ipc;

        if (cmd.compare(0, strlen(EVENT_CLICK), EVENT_CLICK) == 0) {
          m_log.info("%s: Sending workspace focus command to ipc handler", name());
          ipc.send_command("workspace number " + cmd.substr(strlen(EVENT_CLICK)));
        } else if (cmd.compare(0, strlen(EVENT_SCROLL_DOWN), EVENT_SCROLL_DOWN) == 0) {
          m_log.info("%s: Sending workspace prev command to ipc handler", name());
          ipc.send_command("workspace next_on_output");
        } else if (cmd.compare(0, strlen(EVENT_SCROLL_UP), EVENT_SCROLL_UP) == 0) {
          m_log.info("%s: Sending workspace next command to ipc handler", name());
          ipc.send_command("workspace prev_on_output");
        }
      } catch (const std::exception& err) {
        m_log.err("%s: %s", name(), err.what());
      }

      return true;

      // }}}
    }

    bool receive_events() const {
      return true;
    }

   private:
    static constexpr auto DEFAULT_WS_ICON = "ws-icon-default";
    static constexpr auto DEFAULT_WS_LABEL = "%icon% %name%";
    static constexpr auto TAG_LABEL_STATE = "<label-state>";

    static constexpr auto EVENT_PREFIX = "i3";
    static constexpr auto EVENT_CLICK = "i3-wsfocus-";
    static constexpr auto EVENT_SCROLL_UP = "i3-wsnext";
    static constexpr auto EVENT_SCROLL_DOWN = "i3-wsprev";

    map<i3_flag, label_t> m_statelabels;
    vector<i3_workspace_t> m_workspaces;
    iconset_t m_icons;

    bool m_indexsort = false;
    bool m_pinworkspaces = false;
    bool m_strip_wsnumbers = false;
    size_t m_wsname_maxlen = 0;

    i3_util::connection_t m_ipc;
  };
}

LEMONBUDDY_NS_END
<|endoftext|>