<commit_before>#include <windows.h>

#include <gl\gl.h>

#include "Settings.h"
#include "Main.h"
#include "VideoBase.h"
#include "Loader.h"
#include "Window.h"
#include "Text.h"
#include "Info.h"
#include "Error.h"
#include "GamePlay.h"

#define SPLASH_RESOURCE NULL
#define SPLASH_FILE "SPLASH.JPG"

#define SPLASH_FONT_NAME "Arial"
#define SPLASH_FONT_SIZE 24
#define SPLASH_FONT_BOLD false
#define SPLASH_FONT_ITALIC true
#define SPLASH_FONT_UNDERLINE false
#define SPLASH_FONT_STRIKEOUT false
#define SPLASH_FONT_THICKNESS 0.1f

#define SPLASH_TEXT_X 16.0f
#define SPLASH_TEXT_Y 16.0f
#define SPLASH_TEXT_COLOR_R 0.75f
#define SPLASH_TEXT_COLOR_G 0.75f
#define SPLASH_TEXT_COLOR_B 1.00f

#define RESTART_ALLOWED true
#define RESTART_TIME 10.0f

int CGamePlay::splash_tex=0;
char CGamePlay::load_text[256];
CBody CGamePlay::mainbody;
CCamera CGamePlay::camera;
CStarMap CGamePlay::starmap;
CClock CGamePlay::clock;
CLensFlare CGamePlay::lensflare;
bool CGamePlay::flares=false;
bool CGamePlay::planetinfo=false;
CText CGamePlay::splashtext;
CInfo CGamePlay::info;

CGamePlay::CGamePlay()
{
}

CGamePlay::~CGamePlay()
{
}

bool CGamePlay::Init()
{
	if (!splashtext.BuildOutlineFont(	SPLASH_FONT_NAME,
										SPLASH_FONT_SIZE,
										SPLASH_FONT_BOLD,
										SPLASH_FONT_ITALIC,
										SPLASH_FONT_UNDERLINE,
										SPLASH_FONT_STRIKEOUT,
										0.1f))
		CError::LogError(WARNING_CODE,"Failed to load the splash text font - ignoring.");
	if (!InitScene())
	{
		if (UserAbortedLoad())
			OnUserAbortLoad();
		else
			CError::LogError(ERROR_CODE,"Unable to load scene critical data - aborting.");
		DestroyScene();
		return false;
	}
	splashtext.Free();
	return true;
}

void CGamePlay::ShutDown()
{
	DestroyScene();
}

bool CGamePlay::LoadSplash()
{
	CLoader loader;
	loader.WithResource(SPLASH_RESOURCE);
	splash_tex=loader.LoadTexture(SPLASH_FILE,NULL,false);
	return (splash_tex>0);
}

void CGamePlay::FreeSplash()
{
	glDeleteTextures(1,(GLuint*)&splash_tex);
	splash_tex=0;
}

void CGamePlay::InitLight()
{
	GLfloat LightAmbient[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1,GL_AMBIENT,LightAmbient);
	glLightfv(GL_LIGHT1,GL_DIFFUSE,LightDiffuse);
	glLightfv(GL_LIGHT1,GL_SPECULAR,LightSpecular);
	glEnable(GL_LIGHT1);
}

void CGamePlay::OnUserAbortLoad()
{
	// log new error
	CError::LogError(ERROR_CODE,"User aborted load.");
	// get first error, and if it's "user abort", clear the log so it's not printed
	if (CError::ErrorsOccured())
	{
		int code;
		char string[ERROR_MAXLEN];
		CError::Rewind();
		CError::GetNextError(&code,string);
		strlwr(string);
		if (strstr(string,"user") && strstr(string,"abort"))
			CError::Clear();
	}
}

bool CGamePlay::UserAbortedLoad()
{
	static bool userabort=false;
	if (!userabort)
		userabort=!MessagePump();
	return userabort;
}

bool CGamePlay::InitScene()
{
	SetSplashText("Loading splash screen... ");
	if (!LoadSplash())
		CError::LogError(WARNING_CODE,"Failed to load the splash screen - ignoring.");

	{
		SetSplashText("Loading bodies... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!mainbody.Load())
		{
			CError::LogError(ERROR_CODE,"Failed to load the bodies - aborting.");
			return false;
		}
	}

	flares=CVideoBase::GetOptLensFlares();
	if (flares)
	{
		SetSplashText("Loading lens flares... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!lensflare.Load(&mainbody))
		{
			CError::LogError(WARNING_CODE,"Failed to load the lens flares - ignoring.");
			flares=false;
		}
	}

	planetinfo=(CSettings::PlanetInfo==TRUE);
	if (planetinfo)
	{
		SetSplashText("Loading info text font... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!info.Load())
		{
			CError::LogError(WARNING_CODE,"Failed to load the planet info - ignoring.");
			planetinfo=false;
		}
	}

	{
		SetSplashText("Loading starmap... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!starmap.Load())
			CError::LogError(WARNING_CODE,"Failed to load the starmap - ignoring.");
	}

	if (CSettings::ClockOn)
	{
		SetSplashText("Loading clock... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!clock.Load())
			CError::LogError(WARNING_CODE,"Failed to load the clock - ignoring.");
	}

	SetSplashText("Done.");

	srand((unsigned int)timeGetTime());
	InitLight();
	camera.Init(&mainbody,(planetinfo?&info:NULL));
	return FadeOutSplash();
}

void CGamePlay::DestroyScene()
{
	starmap.Free();
	lensflare.Free();
	flares=false;
	if (CSettings::ClockOn)
		clock.Free();
	mainbody.Destroy();
	FreeSplash();
	info.Free();
	planetinfo=false;
}

void CGamePlay::UpdateScene()
{
	float seconds;
	static DWORD starttime=timeGetTime();
	int milidelta;
	milidelta=(timeGetTime()-starttime);
	seconds=milidelta*0.001f;
	mainbody.Update(seconds);
	camera.Update(seconds);
	if (flares)
		lensflare.UpdateTime(seconds);
	if (planetinfo)
		info.Update(seconds);
	if (CSettings::ClockOn==TRUE && milidelta>=500)
		clock.Update();
	if (RESTART_ALLOWED)
	{
		if (seconds>=max(RESTART_TIME,CAMERA_INIT_FADE_TIME))
		{
			mainbody.Restart();
			camera.Restart(seconds);
			if (flares)
				lensflare.Restart();
			if (planetinfo)
				info.Restart();
			starttime=starttime+milidelta;
		}
	}
}

void CGamePlay::DrawScene()
{
	GLfloat LightPosition[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	camera.ApplyRotation();
	starmap.Draw();
	camera.ApplyTranslation();
	glLightfv(GL_LIGHT1,GL_POSITION,LightPosition);
	mainbody.Draw(flares?&lensflare:NULL);
	if (flares)
	{
		lensflare.Draw();
	}
	if (planetinfo || CSettings::ClockOn)
	{
		Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
		if (planetinfo)
			info.Draw();
		if (CSettings::ClockOn)
			clock.Draw();
		Restore3D();
	}
	camera.DrawFade();
}

void CGamePlay::Frame()
{
	UpdateScene();
	SwapBuffers(wglGetCurrentDC());
	DrawScene();
	glFlush();
}

void CGamePlay::Prepare2D(int width, int height)
{
	glPushAttrib(GL_ENABLE_BIT);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0,width,0,height);
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::Restore3D()
{
	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::UpdateSplash(const char *subtext)
{
	char text[256];
	strcpy(text,load_text);
	strcat(text,subtext);
	DrawSplash(text);
}

void CGamePlay::RenderSplashInner(const char *text)
{
	float w=800.0f;
	float h=600.0f;
	glLoadIdentity();
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	if (splash_tex>0)
	{
		glEnable(GL_TEXTURE_2D);
		glColor4f(1,1,1,1);
		glBindTexture(GL_TEXTURE_2D,splash_tex);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0,0.25f);
			glVertex2f(0,0);
			glTexCoord2f(1,0.25f);
			glVertex2f(w,0);
			glTexCoord2f(1,1);
			glVertex2f(w,h);
			glTexCoord2f(0,1);
			glVertex2f(0,h);
		}
		glEnd();
	}
	glDisable(GL_TEXTURE_2D);
	glTranslatef(SPLASH_TEXT_X,SPLASH_TEXT_Y,0.0f);
	glScalef(SPLASH_FONT_SIZE,SPLASH_FONT_SIZE,SPLASH_FONT_SIZE);
	glColor4f(SPLASH_TEXT_COLOR_R,SPLASH_TEXT_COLOR_G,SPLASH_TEXT_COLOR_B,1);
	splashtext.Print(text);
}

void CGamePlay::DrawSplash(const char *text)
{
	Prepare2D(800,600);
	glPushAttrib(GL_POLYGON_BIT);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	RenderSplashInner(text);
	glPopAttrib();
	Restore3D();
	glFlush();
	SwapBuffers(wglGetCurrentDC());
}

void CGamePlay::SetSplashText(const char *text)
{
	strcpy(load_text,text);
	DrawSplash(text);
}

bool CGamePlay::FadeOutSplash()
{
	int starttime=timeGetTime();
	float seconds;
	do
	{
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		seconds=(float)(timeGetTime()-starttime)*0.001f;
		float alpha=min(seconds/CAMERA_INIT_FADE_TIME,1.0f);
		{
			Prepare2D(800,600);
			glPushAttrib(GL_POLYGON_BIT);
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
			RenderSplashInner(load_text);
			glLoadIdentity();
			glDisable(GL_DEPTH_TEST);
			glEnable(GL_BLEND);
			glColor4f(0,0,0,alpha);
			glBegin(GL_QUADS);
			{
				glVertex2f(0,0);
				glVertex2f(800,0);
				glVertex2f(800,600);
				glVertex2f(0,600);
			}
			glEnd();
			glPopAttrib();
			Restore3D();
			glFlush();
			SwapBuffers(wglGetCurrentDC());
		}
	}
	while (seconds<CAMERA_INIT_FADE_TIME);
	return true;
}
<commit_msg>Cosmetics.<commit_after>#include <windows.h>

#include <gl\gl.h>

#include "Settings.h"
#include "Main.h"
#include "VideoBase.h"
#include "Loader.h"
#include "Window.h"
#include "Text.h"
#include "Info.h"
#include "Error.h"
#include "GamePlay.h"

#define SPLASH_RESOURCE NULL
#define SPLASH_FILE "SPLASH.JPG"

#define SPLASH_FONT_NAME "Arial"
#define SPLASH_FONT_SIZE 24
#define SPLASH_FONT_BOLD false
#define SPLASH_FONT_ITALIC true
#define SPLASH_FONT_UNDERLINE false
#define SPLASH_FONT_STRIKEOUT false
#define SPLASH_FONT_THICKNESS 0.1f

#define SPLASH_TEXT_X 16.0f
#define SPLASH_TEXT_Y 16.0f
#define SPLASH_TEXT_COLOR_R 0.75f
#define SPLASH_TEXT_COLOR_G 0.75f
#define SPLASH_TEXT_COLOR_B 1.00f

#define RESTART_ALLOWED true
#define RESTART_TIME 10.0f

int CGamePlay::splash_tex=0;
char CGamePlay::load_text[256];
CBody CGamePlay::mainbody;
CCamera CGamePlay::camera;
CStarMap CGamePlay::starmap;
CClock CGamePlay::clock;
CLensFlare CGamePlay::lensflare;
bool CGamePlay::flares=false;
bool CGamePlay::planetinfo=false;
CText CGamePlay::splashtext;
CInfo CGamePlay::info;

CGamePlay::CGamePlay()
{
}

CGamePlay::~CGamePlay()
{
}

bool CGamePlay::Init()
{
	if (!splashtext.BuildOutlineFont(	SPLASH_FONT_NAME,
										SPLASH_FONT_SIZE,
										SPLASH_FONT_BOLD,
										SPLASH_FONT_ITALIC,
										SPLASH_FONT_UNDERLINE,
										SPLASH_FONT_STRIKEOUT,
										0.1f))
		CError::LogError(WARNING_CODE,"Failed to load the splash text font - ignoring.");
	if (!InitScene())
	{
		if (UserAbortedLoad())
			OnUserAbortLoad();
		else
			CError::LogError(ERROR_CODE,"Unable to load scene critical data - aborting.");
		DestroyScene();
		return false;
	}
	splashtext.Free();
	return true;
}

void CGamePlay::ShutDown()
{
	DestroyScene();
}

bool CGamePlay::LoadSplash()
{
	CLoader loader;
	loader.WithResource(SPLASH_RESOURCE);
	splash_tex=loader.LoadTexture(SPLASH_FILE,NULL,false);
	return (splash_tex>0);
}

void CGamePlay::FreeSplash()
{
	glDeleteTextures(1,(GLuint*)&splash_tex);
	splash_tex=0;
}

void CGamePlay::InitLight()
{
	GLfloat LightAmbient[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightDiffuse[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	GLfloat LightSpecular[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1,GL_AMBIENT,LightAmbient);
	glLightfv(GL_LIGHT1,GL_DIFFUSE,LightDiffuse);
	glLightfv(GL_LIGHT1,GL_SPECULAR,LightSpecular);
	glEnable(GL_LIGHT1);
}

void CGamePlay::OnUserAbortLoad()
{
	// log new error
	CError::LogError(ERROR_CODE,"User aborted load.");
	// get first error, and if it's "user abort", clear the log so it's not printed
	if (CError::ErrorsOccured())
	{
		int code;
		char string[ERROR_MAXLEN];
		CError::Rewind();
		CError::GetNextError(&code,string);
		strlwr(string);
		if (strstr(string,"user") && strstr(string,"abort"))
			CError::Clear();
	}
}

bool CGamePlay::UserAbortedLoad()
{
	static bool userabort=false;
	if (!userabort)
		userabort=!MessagePump();
	return userabort;
}

bool CGamePlay::InitScene()
{
	{
		SetSplashText("Loading splash screen... ");
		if (!LoadSplash())
			CError::LogError(WARNING_CODE,"Failed to load the splash screen - ignoring.");
	}

	{
		SetSplashText("Loading bodies... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!mainbody.Load())
		{
			CError::LogError(ERROR_CODE,"Failed to load the bodies - aborting.");
			return false;
		}
	}

	flares=CVideoBase::GetOptLensFlares();
	if (flares)
	{
		SetSplashText("Loading lens flares... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!lensflare.Load(&mainbody))
		{
			CError::LogError(WARNING_CODE,"Failed to load the lens flares - ignoring.");
			flares=false;
		}
	}

	planetinfo=(CSettings::PlanetInfo==TRUE);
	if (planetinfo)
	{
		SetSplashText("Loading info text font... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!info.Load())
		{
			CError::LogError(WARNING_CODE,"Failed to load the planet info - ignoring.");
			planetinfo=false;
		}
	}

	{
		SetSplashText("Loading starmap... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!starmap.Load())
			CError::LogError(WARNING_CODE,"Failed to load the starmap - ignoring.");
	}

	if (CSettings::ClockOn)
	{
		SetSplashText("Loading clock... ");
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		if (!clock.Load())
			CError::LogError(WARNING_CODE,"Failed to load the clock - ignoring.");
	}

	SetSplashText("Done.");

	srand((unsigned int)timeGetTime());
	InitLight();
	camera.Init(&mainbody,(planetinfo?&info:NULL));
	return FadeOutSplash();
}

void CGamePlay::DestroyScene()
{
	starmap.Free();
	lensflare.Free();
	flares=false;
	if (CSettings::ClockOn)
		clock.Free();
	mainbody.Destroy();
	FreeSplash();
	info.Free();
	planetinfo=false;
}

void CGamePlay::UpdateScene()
{
	float seconds;
	static DWORD starttime=timeGetTime();
	int milidelta;
	milidelta=(timeGetTime()-starttime);
	seconds=milidelta*0.001f;
	mainbody.Update(seconds);
	camera.Update(seconds);
	if (flares)
		lensflare.UpdateTime(seconds);
	if (planetinfo)
		info.Update(seconds);
	if (CSettings::ClockOn==TRUE && milidelta>=500)
		clock.Update();
	if (RESTART_ALLOWED)
	{
		if (seconds>=max(RESTART_TIME,CAMERA_INIT_FADE_TIME))
		{
			mainbody.Restart();
			camera.Restart(seconds);
			if (flares)
				lensflare.Restart();
			if (planetinfo)
				info.Restart();
			starttime=starttime+milidelta;
		}
	}
}

void CGamePlay::DrawScene()
{
	GLfloat LightPosition[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
	camera.ApplyRotation();
	starmap.Draw();
	camera.ApplyTranslation();
	glLightfv(GL_LIGHT1,GL_POSITION,LightPosition);
	mainbody.Draw(flares?&lensflare:NULL);
	if (flares)
	{
		lensflare.Draw();
	}
	if (planetinfo || CSettings::ClockOn)
	{
		Prepare2D(CWindow::GetWidth(),CWindow::GetHeight());
		if (planetinfo)
			info.Draw();
		if (CSettings::ClockOn)
			clock.Draw();
		Restore3D();
	}
	camera.DrawFade();
}

void CGamePlay::Frame()
{
	UpdateScene();
	SwapBuffers(wglGetCurrentDC());
	DrawScene();
	glFlush();
}

void CGamePlay::Prepare2D(int width, int height)
{
	glPushAttrib(GL_ENABLE_BIT);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(0,width,0,height);
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::Restore3D()
{
	glPopAttrib();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

void CGamePlay::UpdateSplash(const char *subtext)
{
	char text[256];
	strcpy(text,load_text);
	strcat(text,subtext);
	DrawSplash(text);
}

void CGamePlay::RenderSplashInner(const char *text)
{
	float w=800.0f;
	float h=600.0f;
	glLoadIdentity();
	glDisable(GL_LIGHTING);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);
	if (splash_tex>0)
	{
		glEnable(GL_TEXTURE_2D);
		glColor4f(1,1,1,1);
		glBindTexture(GL_TEXTURE_2D,splash_tex);
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0,0.25f);
			glVertex2f(0,0);
			glTexCoord2f(1,0.25f);
			glVertex2f(w,0);
			glTexCoord2f(1,1);
			glVertex2f(w,h);
			glTexCoord2f(0,1);
			glVertex2f(0,h);
		}
		glEnd();
	}
	glDisable(GL_TEXTURE_2D);
	glTranslatef(SPLASH_TEXT_X,SPLASH_TEXT_Y,0.0f);
	glScalef(SPLASH_FONT_SIZE,SPLASH_FONT_SIZE,SPLASH_FONT_SIZE);
	glColor4f(SPLASH_TEXT_COLOR_R,SPLASH_TEXT_COLOR_G,SPLASH_TEXT_COLOR_B,1);
	splashtext.Print(text);
}

void CGamePlay::DrawSplash(const char *text)
{
	Prepare2D(800,600);
	glPushAttrib(GL_POLYGON_BIT);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
	RenderSplashInner(text);
	glPopAttrib();
	Restore3D();
	glFlush();
	SwapBuffers(wglGetCurrentDC());
}

void CGamePlay::SetSplashText(const char *text)
{
	strcpy(load_text,text);
	DrawSplash(text);
}

bool CGamePlay::FadeOutSplash()
{
	int starttime=timeGetTime();
	float seconds;
	do
	{
		if (UserAbortedLoad())
		{
			OnUserAbortLoad();
			return false;
		}
		seconds=(float)(timeGetTime()-starttime)*0.001f;
		float alpha=min(seconds/CAMERA_INIT_FADE_TIME,1.0f);
		{
			Prepare2D(800,600);
			glPushAttrib(GL_POLYGON_BIT);
			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
			RenderSplashInner(load_text);
			glLoadIdentity();
			glDisable(GL_DEPTH_TEST);
			glEnable(GL_BLEND);
			glColor4f(0,0,0,alpha);
			glBegin(GL_QUADS);
			{
				glVertex2f(0,0);
				glVertex2f(800,0);
				glVertex2f(800,600);
				glVertex2f(0,600);
			}
			glEnd();
			glPopAttrib();
			Restore3D();
			glFlush();
			SwapBuffers(wglGetCurrentDC());
		}
	}
	while (seconds<CAMERA_INIT_FADE_TIME);
	return true;
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors

// 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.

#ifndef SOL_OBJECT_HPP
#define SOL_OBJECT_HPP

#include "reference.hpp"
#include "userdata.hpp"
#include "stack.hpp"
#include "variadic_args.hpp"

namespace sol {
template <typename base_t>
class basic_object : public base_t {
private:
    template<typename T>
    decltype(auto) as_stack(std::true_type) const {
        return stack::get<T>(lua_state(), base_t::stack_index());
    }

    template<typename T>
    decltype(auto) as_stack(std::false_type) const {
        base_t::push();
        return stack::pop<T>(lua_state());
    }

    template<typename T>
    bool is_stack(std::true_type) const {
        return stack::check<T>(lua_state(), base_t::stack_index(), no_panic);
    }

    template<typename T>
    bool is_stack(std::false_type) const {
        auto pp = stack::push_pop(*this);
        return stack::check<T>(lua_state(), -1, no_panic);
    }

public:
    basic_object() noexcept = default;
    template <typename T, meta::EnableIf<meta::Not<std::is_same<meta::Unqualified<T>, basic_object>>, std::is_base_of<base_t, meta::Unqualified<T>>> = 0>
    basic_object(T&& r) : base_t(std::forward<T>(r)) {}
    basic_object(nil_t r) : base_t(r) {}
    basic_object(const basic_object&) = default;
    basic_object(basic_object&&) = default;
    basic_object& operator=(const basic_object&) = default;
    basic_object& operator=(basic_object&&) = default;
    basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
    basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
    basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}

    template<typename T>
    decltype(auto) as() const {
        return as_stack<T>( std::is_same<base_t, stack_reference>() );
    }

    template<typename T>
    bool is() const {
        if (!base_t::valid())
            return false;
        return is_stack<T>(std::is_same<base_t, stack_reference>());
    }
};

template <typename T>
object make_object(lua_State* L, T&& value) {
    int backpedal = stack::push(L, std::forward<T>(value));
    object r = stack::get<object>(L, -backpedal);
    lua_pop(L, backpedal);
    return r;
}

template <typename T, typename... Args>
object make_object(lua_State* L, Args&&... args) {
    int backpedal = stack::push<T>(L, std::forward<Args>(args)...);
    object r = stack::get<sol::object>(L, -backpedal);
    lua_pop(L, backpedal);
    return r;
}

inline bool operator==(const object& lhs, const nil_t&) {
    return !lhs.valid();
}

inline bool operator==(const nil_t&, const object& rhs) {
    return !rhs.valid();
}

inline bool operator!=(const object& lhs, const nil_t&) {
    return lhs.valid();
}

inline bool operator!=(const nil_t&, const object& rhs) {
    return rhs.valid();
}
} // sol

#endif // SOL_OBJECT_HPP
<commit_msg>base_t templated<commit_after>// The MIT License (MIT)

// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors

// 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.

#ifndef SOL_OBJECT_HPP
#define SOL_OBJECT_HPP

#include "reference.hpp"
#include "userdata.hpp"
#include "stack.hpp"
#include "variadic_args.hpp"

namespace sol {
template <typename base_t>
class basic_object : public base_t {
private:
    template<typename T>
    decltype(auto) as_stack(std::true_type) const {
        return stack::get<T>(base_t::lua_state(), base_t::stack_index());
    }

    template<typename T>
    decltype(auto) as_stack(std::false_type) const {
        base_t::push();
        return stack::pop<T>(base_t::lua_state());
    }

    template<typename T>
    bool is_stack(std::true_type) const {
        return stack::check<T>(base_t::lua_state(), base_t::stack_index(), no_panic);
    }

    template<typename T>
    bool is_stack(std::false_type) const {
        auto pp = stack::push_pop(*this);
        return stack::check<T>(base_t::lua_state(), -1, no_panic);
    }

public:
    basic_object() noexcept = default;
    template <typename T, meta::EnableIf<meta::Not<std::is_same<meta::Unqualified<T>, basic_object>>, std::is_base_of<base_t, meta::Unqualified<T>>> = 0>
    basic_object(T&& r) : base_t(std::forward<T>(r)) {}
    basic_object(nil_t r) : base_t(r) {}
    basic_object(const basic_object&) = default;
    basic_object(basic_object&&) = default;
    basic_object& operator=(const basic_object&) = default;
    basic_object& operator=(basic_object&&) = default;
    basic_object(const stack_reference& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
    basic_object(stack_reference&& r) noexcept : basic_object(r.lua_state(), r.stack_index()) {}
    basic_object(lua_State* L, int index = -1) noexcept : base_t(L, index) {}

    template<typename T>
    decltype(auto) as() const {
        return as_stack<T>( std::is_same<base_t, stack_reference>() );
    }

    template<typename T>
    bool is() const {
        if (!base_t::valid())
            return false;
        return is_stack<T>(std::is_same<base_t, stack_reference>());
    }
};

template <typename T>
object make_object(lua_State* L, T&& value) {
    int backpedal = stack::push(L, std::forward<T>(value));
    object r = stack::get<object>(L, -backpedal);
    lua_pop(L, backpedal);
    return r;
}

template <typename T, typename... Args>
object make_object(lua_State* L, Args&&... args) {
    int backpedal = stack::push<T>(L, std::forward<Args>(args)...);
    object r = stack::get<sol::object>(L, -backpedal);
    lua_pop(L, backpedal);
    return r;
}

inline bool operator==(const object& lhs, const nil_t&) {
    return !lhs.valid();
}

inline bool operator==(const nil_t&, const object& rhs) {
    return !rhs.valid();
}

inline bool operator!=(const object& lhs, const nil_t&) {
    return lhs.valid();
}

inline bool operator!=(const nil_t&, const object& rhs) {
    return rhs.valid();
}
} // sol

#endif // SOL_OBJECT_HPP
<|endoftext|>


<commit_before>/**
 * ZNC Notifo Module
 *
 * Allows the user to enter a Notifo user and API token, and sends
 * channel highlights and personal messages to Notifo.
 *
 * Copyright (c) 2011 John Reese
 * Licensed under the MIT license
 */

#define REQUIRESSL

#include "znc.h"
#include "Chan.h"
#include "User.h"
#include "Modules.h"

#if (!defined(VERSION_MAJOR) || !defined(VERSION_MINOR) || (VERSION_MAJOR == 0 && VERSION_MINOR < 72))
#error This module needs ZNC 0.072 or newer.
#endif

#define DEBUG_HOST 0
#define DEBUG_LOGGING 0

class CNotifoMod : public CModule
{
	protected:

		// Application name
		CString app;

		// Too lazy to add CString("\r\n\") everywhere
		CString crlf;

		// Host and URL to send messages to
		CString notifo_host;
		CString notifo_url;

		// User agent to use
		CString user_agent;

		// BASIC auth string, needs to be encoded each time username/secret is changed
		CString notifo_auth;

		// Configuration options
		MCString options;

	public:

		MODCONSTRUCTOR(CNotifoMod) {
			app = "ZNC";
			crlf = "\r\n";

#if DEBUG_HOST
			notifo_host = "notifo.leetcode.net";
			notifo_url = "/index.php";
#else
			notifo_host = "api.notifo.com";
			notifo_url = "/v1/send_notification";
#endif

			notifo_auth = "";
			user_agent = "ZNC To Notifo";

			// Notifo user account and secret
			options["username"] = "";
			options["secret"] = "";
		}
		virtual ~CNotifoMod() {}

	protected:

		/**
		 * Shorthand for encoding a string for a URL.
		 *
		 * @param str String to be encoded
		 * @return Encoded string
		 */
		CString urlencode(const CString& str)
		{
			return str.Escape_n(CString::EASCII, CString::EURL);
		}

		/**
		 * Re-encode the authentication credentials.
		 */
		void authencode()
		{
			// BASIC auth, base64-encoded username:password
			CString auth = options["username"] + CString(":") + options["secret"];
			notifo_auth = auth.Base64Encode_n();
		}

		/**
		 * Send a message to the currently-configured Notifo account.
		 * Requires (and assumes) that the user has already configured their
		 * username and API secret using the 'set' command.
		 *
		 * @param message Message to be sent to the user
		 * @param title Message title to use
		 */
		void send_message(const CString& message, const CString& title="New Message")
		{
			// POST body parameters for the request
			CString post = "to=" + urlencode(options["username"]);
			post += "&msg=" + urlencode(message);
			post += "&label=" + urlencode(app);
			post += "&title=" + urlencode(title);
			post += "&uri=" + urlencode(CString("http://notifo.leetcode.net/"));

			// Request headers and POST body
			CString request = "POST " + notifo_url + " HTTP/1.1" + crlf;
			request += "Host: " + notifo_host + crlf;
			request += "Content-Type: application/x-www-form-urlencoded" + crlf;
			request += "Content-Length: " + CString(post.length()) + crlf;
			request += "User-Agent: " + user_agent + crlf;
			request += "Authorization: Basic " + notifo_auth + crlf;
			request += crlf;
			request += post + crlf;

			// Create the socket connection, write to it, and add it to the queue
			CSocket *sock = new CSocket(this);
			sock->Connect(notifo_host, 443, true);
			sock->Write(request);
			sock->Close(Csock::CLT_AFTERWRITE);
			AddSocket(sock);

#if DEBUG_LOGGING
			// Log the HTTP request
			FILE *fh = fopen("/tmp/notifo.log", "a");
			fputs(request.c_str(), fh);
			fclose(fh);
#endif
		}

		/**
		 * Determine when to notify the user of a channel message.
		 *
		 * @param nick Nick that sent the message
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 * @return Notification should be sent
		 */
		bool notify_channel(const CNick& nick, const CChan& channel, const CString& message)
		{
			return false;
		}

		/**
		 * Determine when to notify the user of a private message.
		 *
		 * @param nick Nick that sent the message
		 * @return Notification should be sent
		 */
		bool notify_pm(const CNick& nick)
		{
			return true;
		}

	protected:

		/**
		 * Handle the plugin being loaded.  Retrieve plugin config values.
		 *
		 * @param args Plugin arguments
		 * @param message Message to show the user after loading
		 */
		bool OnLoad(const CString& args, CString& message)
		{
			for (MCString::iterator i = options.begin(); i != options.end(); i++)
			{
				options[i->first] = GetNV(i->first);
			}

			authencode();

			return true;
		}

		/**
		 * Handle channel messages.
		 *
		 * @param nick Nick that sent the message
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 */
		EModRet OnChanMsg(CNick& nick, CChan& channel, CString& message)
		{
			if (notify_channel(nick, channel, message))
			{
				CString title = "Highlight";
				CString msg = channel.GetName();
				msg += ": <" + nick.GetNick();
				msg += "> " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle channel actions.
		 *
		 * @param nick Nick that sent the action
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 */
		EModRet OnChanAction(CNick& nick, CChan& channel, CString& message)
		{
			if (notify_channel(nick, channel, message))
			{
				CString title = "Highlight";
				CString msg = channel.GetName();
				msg += ": " + nick.GetNick();
				msg += " " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle a private message.
		 *
		 * @param nick Nick that sent the message
		 * @param message Message contents
		 */
		EModRet OnPrivMsg(CNick& nick, CString& message)
		{
			if (notify_pm(nick))
			{
				CString title = "Private Message";
				CString msg = "From " + nick.GetNick();
				msg += ": " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle a private action.
		 *
		 * @param nick Nick that sent the action
		 * @param message Message contents
		 */
		EModRet OnPrivAction(CNick& nick, CString& message)
		{
			if (notify_pm(nick))
			{
				CString title = "Private Message";
				CString msg = "* " + nick.GetNick();
				msg += " " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle direct commands to the *notifo virtual user.
		 *
		 * @param command Command string
		 */
		void OnModCommand(const CString& command)
		{
			VCString tokens;
			int token_count = command.Split(" ", tokens, false);

			CString action = tokens[0].AsLower();

			// SET command
			if (action == "set")
			{
				if (token_count != 3)
				{
					PutModule("Usage: set <option> <value>");
					return;
				}

				CString option = tokens[1].AsLower();
				CString value = tokens[2];
				MCString::iterator pos = options.find(option);

				if (pos == options.end())
				{
					PutModule("Error: invalid option name");
				}
				else
				{
					options[option] = value;
					SetNV(option, value);

					authencode();
				}
			}
			// GET command
			else if (action == "get")
			{
				if (token_count != 2)
				{
					PutModule("Usage: get <option>");
					return;
				}

				CString option = tokens[1].AsLower();
				MCString::iterator pos = options.find(option);

				if (pos == options.end())
				{
					PutModule("Error: invalid option name");
				}
				else
				{
					PutModule(option + CString(": \"") + options[option] + CString("\""));
				}
			}
			// SEND command
			else if (action == "send")
			{
				CString message = command.Token(1, true, " ", true);
				send_message(message);
			}
			else
			{
				PutModule("Error: invalid command");
			}
		}
};

MODULEDEFS(CNotifoMod, "Send highlights and personal messages to a Notifo account")
<commit_msg>Implemented basic highlight matching against nick<commit_after>/**
 * ZNC Notifo Module
 *
 * Allows the user to enter a Notifo user and API token, and sends
 * channel highlights and personal messages to Notifo.
 *
 * Copyright (c) 2011 John Reese
 * Licensed under the MIT license
 */

#define REQUIRESSL

#include "znc.h"
#include "Chan.h"
#include "User.h"
#include "Modules.h"

#if (!defined(VERSION_MAJOR) || !defined(VERSION_MINOR) || (VERSION_MAJOR == 0 && VERSION_MINOR < 72))
#error This module needs ZNC 0.072 or newer.
#endif

#define DEBUG_HOST 0
#define DEBUG_LOGGING 0

class CNotifoMod : public CModule
{
	protected:

		// Application name
		CString app;

		// Too lazy to add CString("\r\n\") everywhere
		CString crlf;

		// BASIC auth string, needs to be encoded each time username/secret is changed
		CString notifo_auth;

		// Host and URL to send messages to
		CString notifo_host;
		CString notifo_url;

		// User agent to use
		CString user_agent;

		// User object
		CUser *user;

		// Configuration options
		MCString options;

	public:

		MODCONSTRUCTOR(CNotifoMod) {
			app = "ZNC";
			crlf = "\r\n";

#if DEBUG_HOST
			notifo_host = "notifo.leetcode.net";
			notifo_url = "/index.php";
#else
			notifo_host = "api.notifo.com";
			notifo_url = "/v1/send_notification";
#endif

			notifo_auth = "";
			user_agent = "ZNC To Notifo";

			// Current user
			user = GetUser();

			// Notifo user account and secret
			options["username"] = "";
			options["secret"] = "";
		}
		virtual ~CNotifoMod() {}

	protected:

		/**
		 * Shorthand for encoding a string for a URL.
		 *
		 * @param str String to be encoded
		 * @return Encoded string
		 */
		CString urlencode(const CString& str)
		{
			return str.Escape_n(CString::EASCII, CString::EURL);
		}

		/**
		 * Re-encode the authentication credentials.
		 */
		void authencode()
		{
			// BASIC auth, base64-encoded username:password
			CString auth = options["username"] + CString(":") + options["secret"];
			notifo_auth = auth.Base64Encode_n();
		}

		/**
		 * Send a message to the currently-configured Notifo account.
		 * Requires (and assumes) that the user has already configured their
		 * username and API secret using the 'set' command.
		 *
		 * @param message Message to be sent to the user
		 * @param title Message title to use
		 */
		void send_message(const CString& message, const CString& title="New Message")
		{
			// POST body parameters for the request
			CString post = "to=" + urlencode(options["username"]);
			post += "&msg=" + urlencode(message);
			post += "&label=" + urlencode(app);
			post += "&title=" + urlencode(title);
			post += "&uri=" + urlencode(CString("http://notifo.leetcode.net/"));

			// Request headers and POST body
			CString request = "POST " + notifo_url + " HTTP/1.1" + crlf;
			request += "Host: " + notifo_host + crlf;
			request += "Content-Type: application/x-www-form-urlencoded" + crlf;
			request += "Content-Length: " + CString(post.length()) + crlf;
			request += "User-Agent: " + user_agent + crlf;
			request += "Authorization: Basic " + notifo_auth + crlf;
			request += crlf;
			request += post + crlf;

			// Create the socket connection, write to it, and add it to the queue
			CSocket *sock = new CSocket(this);
			sock->Connect(notifo_host, 443, true);
			sock->Write(request);
			sock->Close(Csock::CLT_AFTERWRITE);
			AddSocket(sock);

#if DEBUG_LOGGING
			// Log the HTTP request
			FILE *fh = fopen("/tmp/notifo.log", "a");
			fputs(request.c_str(), fh);
			fclose(fh);
#endif
		}

		/**
		 * Determine if the given message matches any highlight rules.
		 *
		 * @param message Message contents
		 * @return True if message matches a highlight
		 */
		bool highlight(const CString& message)
		{
			CNick nick = user->GetIRCNick();

			if (message.find(nick.GetNick()) != string::npos)
			{
				return true;
			}

			return false;
		}

		/**
		 * Determine when to notify the user of a channel message.
		 *
		 * @param nick Nick that sent the message
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 * @return Notification should be sent
		 */
		bool notify_channel(const CNick& nick, const CChan& channel, const CString& message)
		{
			return highlight(message);
		}

		/**
		 * Determine when to notify the user of a private message.
		 *
		 * @param nick Nick that sent the message
		 * @return Notification should be sent
		 */
		bool notify_pm(const CNick& nick)
		{
			return true;
		}

	protected:

		/**
		 * Handle the plugin being loaded.  Retrieve plugin config values.
		 *
		 * @param args Plugin arguments
		 * @param message Message to show the user after loading
		 */
		bool OnLoad(const CString& args, CString& message)
		{
			for (MCString::iterator i = options.begin(); i != options.end(); i++)
			{
				options[i->first] = GetNV(i->first);
			}

			authencode();

			return true;
		}

		/**
		 * Handle channel messages.
		 *
		 * @param nick Nick that sent the message
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 */
		EModRet OnChanMsg(CNick& nick, CChan& channel, CString& message)
		{
			if (notify_channel(nick, channel, message))
			{
				CString title = "Highlight";
				CString msg = channel.GetName();
				msg += ": <" + nick.GetNick();
				msg += "> " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle channel actions.
		 *
		 * @param nick Nick that sent the action
		 * @param channel Channel the message was sent to
		 * @param message Message contents
		 */
		EModRet OnChanAction(CNick& nick, CChan& channel, CString& message)
		{
			if (notify_channel(nick, channel, message))
			{
				CString title = "Highlight";
				CString msg = channel.GetName();
				msg += ": " + nick.GetNick();
				msg += " " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle a private message.
		 *
		 * @param nick Nick that sent the message
		 * @param message Message contents
		 */
		EModRet OnPrivMsg(CNick& nick, CString& message)
		{
			if (notify_pm(nick))
			{
				CString title = "Private Message";
				CString msg = "From " + nick.GetNick();
				msg += ": " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle a private action.
		 *
		 * @param nick Nick that sent the action
		 * @param message Message contents
		 */
		EModRet OnPrivAction(CNick& nick, CString& message)
		{
			if (notify_pm(nick))
			{
				CString title = "Private Message";
				CString msg = "* " + nick.GetNick();
				msg += " " + message;

				send_message(msg, title);
			}

			return CONTINUE;
		}

		/**
		 * Handle direct commands to the *notifo virtual user.
		 *
		 * @param command Command string
		 */
		void OnModCommand(const CString& command)
		{
			VCString tokens;
			int token_count = command.Split(" ", tokens, false);

			CString action = tokens[0].AsLower();

			// SET command
			if (action == "set")
			{
				if (token_count != 3)
				{
					PutModule("Usage: set <option> <value>");
					return;
				}

				CString option = tokens[1].AsLower();
				CString value = tokens[2];
				MCString::iterator pos = options.find(option);

				if (pos == options.end())
				{
					PutModule("Error: invalid option name");
				}
				else
				{
					options[option] = value;
					SetNV(option, value);

					authencode();
				}
			}
			// GET command
			else if (action == "get")
			{
				if (token_count != 2)
				{
					PutModule("Usage: get <option>");
					return;
				}

				CString option = tokens[1].AsLower();
				MCString::iterator pos = options.find(option);

				if (pos == options.end())
				{
					PutModule("Error: invalid option name");
				}
				else
				{
					PutModule(option + CString(": \"") + options[option] + CString("\""));
				}
			}
			// SEND command
			else if (action == "send")
			{
				CString message = command.Token(1, true, " ", true);
				send_message(message);
			}
			else
			{
				PutModule("Error: invalid command");
			}
		}
};

MODULEDEFS(CNotifoMod, "Send highlights and personal messages to a Notifo account")
<|endoftext|>


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

#include "tools/render/processed_trace.h"

#include "absl/algorithm/container.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "tools/render/layout_constants.h"

namespace quic_trace {
namespace render {

namespace {

std::string FormatBandwidth(size_t total_bytes, uint64_t time_delta_us) {
  double rate = 8e6 * total_bytes / time_delta_us;

  const char* unit = "";
  for (const char* current_unit : {"k", "M", "G"}) {
    if (rate < 1e3) {
      break;
    }
    rate /= 1e3;
    unit = current_unit;
  }

  char buffer[16];
  snprintf(buffer, sizeof(buffer), "%.2f %sbps", rate, unit);
  return buffer;
}

std::string FormatPercentage(size_t numerator, size_t denominator) {
  double percentage = 100. * numerator / denominator;
  char buffer[8];
  snprintf(buffer, sizeof(buffer), "%.2f%%", percentage);
  return buffer;
}

std::string FormatTime(uint64_t time_us) {
  char buffer[16];
  snprintf(buffer, sizeof(buffer), "%.3fs", time_us / 1e6);
  return buffer;
}

std::string FormatRtt(uint64_t rtt_us) {
  if (rtt_us < 10 * 1000) {
    return absl::StrCat(rtt_us, "µs");
  }
  if (rtt_us < 1000 * 1000) {
    return absl::StrCat(rtt_us / 1000, "ms");
  }
  return FormatTime(rtt_us);
}

}  // namespace

void ProcessedTrace::AddPacket(TraceRenderer* renderer,
                               const Event& packet,
                               Interval interval,
                               PacketType type) {
  renderer->AddPacket(packet.time_us(), interval.offset, interval.size, type);
  rendered_packets_.push_back(
      RenderedPacket{Box{vec2(packet.time_us(), interval.offset),
                         vec2(kSentPacketDurationMs, interval.size)},
                     &packet});
}

ProcessedTrace::ProcessedTrace(std::unique_ptr<Trace> trace,
                               TraceRenderer* renderer) {
  renderer->PacketCountHint(trace->events_size());

  quic_trace::NumberingWithoutRetransmissions numbering;
  size_t largest_sent = 0;
  uint64_t largest_time = 0;
  for (const Event& event : trace->events()) {
    if (!event.has_time_us() || event.time_us() < largest_time) {
      LOG(FATAL)
          << "All events in the trace have to be sorted in chronological order";
    }
    largest_time = event.time_us();

    if (event.event_type() == PACKET_SENT) {
      Interval mapped = numbering.AssignTraceNumbering(event);
      AddPacket(renderer, event, mapped, PacketType::SENT);
      largest_sent =
          std::max<size_t>(mapped.offset + mapped.size, largest_sent);
    }
    if (event.event_type() == PACKET_RECEIVED) {
      for (const Frame& frame : event.frames()) {
        for (const AckBlock& range : frame.ack_info().acked_packets()) {
          for (size_t i = range.first_packet(); i <= range.last_packet(); i++) {
            if (!packets_acked_.insert(i).second) {
              continue;
            }
            Interval mapped = numbering.GetTraceNumbering(i);
            AddPacket(renderer, event, mapped, PacketType::ACKED);
            acks_.emplace(vec2(event.time_us(), mapped.offset), i);
            // Don't count spurious retransmissions as losses.
            packets_lost_.erase(i);
          }
        }
      }
    }
    if (event.event_type() == PACKET_LOST) {
      Interval mapped = numbering.GetTraceNumbering(event.packet_number());
      AddPacket(renderer, event, mapped, PacketType::LOST);
      packets_lost_.insert(event.packet_number());
    }
    if (event.event_type() == APPLICATION_LIMITED) {
      // Normally, we would use the size of the packet as height, but
      // app-limited events have no size, so we pick an arbitrary number (in
      // bytes).
      const size_t kAppLimitedHeigth = 800;
      AddPacket(renderer, event, Interval{largest_sent, kAppLimitedHeigth},
                PacketType::APP_LIMITED);
    }
  }

  renderer->FinishPackets();
  trace_ = std::move(trace);
}

bool ProcessedTrace::SummaryTable(Table* table,
                                  float start_time,
                                  float end_time) {
  auto compare = [](Event a, Event b) { return a.time_us() < b.time_us(); };
  Event key_event;

  key_event.set_time_us(start_time);
  auto start_it = absl::c_lower_bound(trace_->events(), key_event, compare);

  key_event.set_time_us(end_time);
  auto end_it = absl::c_upper_bound(trace_->events(), key_event, compare);

  if (start_it > end_it) {
    return false;
  }

  // TODO(vasilvv): add actually useful information.
  size_t count_sent = 0;
  size_t bytes_sent = 0;
  size_t bytes_sent_acked = 0;
  size_t bytes_sent_lost = 0;
  for (auto it = start_it; it != end_it; it++) {
    switch (it->event_type()) {
      case PACKET_SENT:
        count_sent++;
        bytes_sent += it->packet_size();
        if (packets_acked_.count(it->packet_number()) > 0) {
          bytes_sent_acked += it->packet_size();
        }
        if (packets_lost_.count(it->packet_number()) > 0) {
          bytes_sent_lost += it->packet_size();
        }
        break;
      default:
        break;
    };
  }

  table->AddHeader("Selection summary");
  table->AddRow("#sent", absl::StrCat(count_sent));
  table->AddRow("Send rate",
                FormatBandwidth(bytes_sent, end_time - start_time));
  table->AddRow("Goodput",
                FormatBandwidth(bytes_sent_acked, end_time - start_time));
  table->AddRow("Loss rate", FormatPercentage(bytes_sent_lost, bytes_sent));
  return true;
}

ProcessedTrace::PacketSearchResult ProcessedTrace::FindPacketContainingPoint(
    vec2 point,
    vec2 margin) {
  RenderedPacket key{Box(), nullptr};

  key.box.origin.x = point.x - kSentPacketDurationMs - margin.x;
  auto start_it = absl::c_lower_bound(rendered_packets_, key);

  key.box.origin.x = point.x + kSentPacketDurationMs + margin.x;
  auto end_it = absl::c_upper_bound(rendered_packets_, key);

  if (start_it > end_it) {
    return PacketSearchResult();
  }

  auto closest_box = end_it;
  float closest_distance;
  for (auto it = start_it; it != end_it; it++) {
    Box target_box{it->box.origin - margin, it->box.size + 2 * margin};
    if (IsInside(point, target_box)) {
      float distance = DistanceSquared(point, BoxCenter(target_box));
      if (closest_box == end_it || distance < closest_distance) {
        closest_box = it;
        closest_distance = distance;
      }
    }
  }
  if (closest_box != end_it) {
    PacketSearchResult result;
    result.index = closest_box - rendered_packets_.cbegin();
    result.as_rendered = &closest_box->box;
    result.event = closest_box->packet;
    return result;
  }

  return PacketSearchResult();
}

namespace {
const char* EncryptionLevelToString(EncryptionLevel level) {
  switch (level) {
    case ENCRYPTION_INITIAL:
      return "Initial";
    case ENCRYPTION_HANDSHAKE:
      return "Handshake";
    case ENCRYPTION_0RTT:
      return "0-RTT";
    case ENCRYPTION_1RTT:
      return "1-RTT";

    case ENCRYPTION_UNKNOWN:
    default:
      return "???";
  }
}

constexpr int kMaxAckBlocksShown = 3;
std::string AckSummary(const AckInfo& ack) {
  if (ack.acked_packets_size() == 0) {
    return "";
  }

  bool overflow = false;
  int blocks_to_show = ack.acked_packets_size();
  if (blocks_to_show > kMaxAckBlocksShown) {
    blocks_to_show = kMaxAckBlocksShown;
    overflow = true;
  }

  std::vector<std::string> ack_ranges;
  for (int i = 0; i < blocks_to_show; i++) {
    const AckBlock& block = ack.acked_packets(i);
    if (block.first_packet() == block.last_packet()) {
      ack_ranges.push_back(absl::StrCat(block.first_packet()));
    } else {
      ack_ranges.push_back(
          absl::StrCat(block.first_packet(), ":", block.last_packet()));
    }
  }

  std::string result = absl::StrJoin(ack_ranges, ", ");
  if (overflow) {
    absl::StrAppend(&result, "...");
  }
  return result;
}
}  // namespace

void ProcessedTrace::FillTableForPacket(Table* table,
                                        const Box* as_rendered,
                                        const Event* packet) {
  switch (packet->event_type()) {
    case PACKET_SENT:
      table->AddHeader(absl::StrCat("Sent packet #", packet->packet_number()));
      break;
    case PACKET_RECEIVED: {
      std::string packet_acked = "???";
      auto it = acks_.find(as_rendered->origin);
      if (it != acks_.end()) {
        packet_acked = absl::StrCat(it->second);
      }
      table->AddHeader(absl::StrCat("Ack for packet #", packet_acked));
      break;
    }
    case PACKET_LOST:
      table->AddHeader(absl::StrCat("Lost packet #", packet->packet_number()));
      break;
    case APPLICATION_LIMITED:
      table->AddHeader("Application limited");
      break;
    default:
      return;
  }

  table->AddRow("Time", FormatTime(packet->time_us()));

  if (packet->event_type() == PACKET_SENT) {
    table->AddRow("Size", absl::StrCat(packet->packet_size(), "bytes"));
    table->AddRow("Encryption",
                  EncryptionLevelToString(packet->encryption_level()));

    table->AddHeader("Frame list");
    for (const Frame& frame : packet->frames()) {
      switch (frame.frame_type()) {
        case STREAM:
          table->AddRow(
              "Stream",
              absl::StrCat("#", frame.stream_frame_info().stream_id(), ": ",
                           frame.stream_frame_info().offset(), "-",
                           frame.stream_frame_info().offset() +
                               frame.stream_frame_info().length(),
                           " (", frame.stream_frame_info().length(), ")"));
          break;
        case RESET_STREAM:
          table->AddRow(
              "Reset stream",
              absl::StrCat("#", frame.reset_stream_info().stream_id()));
          break;
        case CONNECTION_CLOSE:
          table->AddRow(
              "Connection close",
              absl::StrCat(absl::Hex(frame.close_info().error_code())));
          break;
        case PING:
          table->AddRow("Ping", "");
          break;
        case BLOCKED:
          table->AddRow("Blocked", "");
          break;
        case STREAM_BLOCKED:
          table->AddRow("Stream blocked",
                        absl::StrCat(frame.flow_control_info().stream_id()));
          break;
        case ACK:
          table->AddRow("Ack", AckSummary(frame.ack_info()));
          break;
        default:
          table->AddRow("Unknown", "");
          break;
      }
    }
  }

  if (packet->has_transport_state()) {
    const TransportState& state = packet->transport_state();
    table->AddHeader("Transport state");
    if (state.has_last_rtt_us()) {
      table->AddRow("RTT", FormatRtt(state.last_rtt_us()));
    }
    if (state.has_smoothed_rtt_us()) {
      table->AddRow("SRTT", FormatRtt(state.smoothed_rtt_us()));
    }
    if (state.has_min_rtt_us()) {
      table->AddRow("Min RTT", FormatRtt(state.min_rtt_us()));
    }
    if (state.has_in_flight_bytes()) {
      table->AddRow("In flight",
                    absl::StrCat(state.in_flight_bytes(), " bytes"));
    }
    if (state.has_cwnd_bytes()) {
      table->AddRow("CWND", absl::StrCat(state.cwnd_bytes(), " bytes"));
    }
    if (state.has_pacing_rate_bps()) {
      table->AddRow("Pacing rate",
                    FormatBandwidth(state.pacing_rate_bps(), 8000 * 1000));
    }
    if (state.has_congestion_control_state()) {
      // Truncate CC state strings longer than 80 characters.
      const int kMaxLen = 80;
      std::string ccstate = state.congestion_control_state();
      if (ccstate.length() > kMaxLen) {
        ccstate = ccstate.substr(0, kMaxLen) + "...";
      }
      table->AddRow("CC State", ccstate);
    }
  }
}

absl::optional<Box> ProcessedTrace::BoundContainedPackets(Box boundary) {
  RenderedPacket key{Box(), nullptr};

  key.box.origin.x = boundary.origin.x;
  auto range_start = absl::c_lower_bound(rendered_packets_, key);

  key.box.origin.x =
      boundary.origin.x + boundary.size.x + kSentPacketDurationMs;
  auto range_end = absl::c_upper_bound(rendered_packets_, key);

  if (range_start == rendered_packets_.end() ||
      range_end == rendered_packets_.end() || range_start > range_end) {
    return absl::nullopt;
  }

  absl::optional<Box> result;
  for (auto it = range_start; it <= range_end; it++) {
    if (IsInside(it->box, boundary)) {
      result = result.has_value() ? BoundingBox(*result, it->box) : it->box;
    }
  }
  return result;
}

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

#include "tools/render/processed_trace.h"

#include "absl/algorithm/container.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "tools/render/layout_constants.h"

namespace quic_trace {
namespace render {

namespace {

std::string FormatBandwidth(size_t total_bytes, uint64_t time_delta_us) {
  double rate = 8e6 * total_bytes / time_delta_us;

  const char* unit = "";
  for (const char* current_unit : {"k", "M", "G"}) {
    if (rate < 1e3) {
      break;
    }
    rate /= 1e3;
    unit = current_unit;
  }

  char buffer[16];
  snprintf(buffer, sizeof(buffer), "%.2f %sbps", rate, unit);
  return buffer;
}

std::string FormatPercentage(size_t numerator, size_t denominator) {
  double percentage = 100. * numerator / denominator;
  char buffer[8];
  snprintf(buffer, sizeof(buffer), "%.2f%%", percentage);
  return buffer;
}

std::string FormatTime(uint64_t time_us) {
  char buffer[16];
  snprintf(buffer, sizeof(buffer), "%.3fs", time_us / 1e6);
  return buffer;
}

std::string FormatRtt(uint64_t rtt_us) {
  if (rtt_us < 10 * 1000) {
    return absl::StrCat(rtt_us, "µs");
  }
  if (rtt_us < 1000 * 1000) {
    return absl::StrCat(rtt_us / 1000, "ms");
  }
  return FormatTime(rtt_us);
}

}  // namespace

void ProcessedTrace::AddPacket(TraceRenderer* renderer,
                               const Event& packet,
                               Interval interval,
                               PacketType type) {
  renderer->AddPacket(packet.time_us(), interval.offset, interval.size, type);
  rendered_packets_.push_back(
      RenderedPacket{Box{vec2(packet.time_us(), interval.offset),
                         vec2(kSentPacketDurationMs, interval.size)},
                     &packet});
}

ProcessedTrace::ProcessedTrace(std::unique_ptr<Trace> trace,
                               TraceRenderer* renderer) {
  renderer->PacketCountHint(trace->events_size());

  quic_trace::NumberingWithoutRetransmissions numbering;
  size_t largest_sent = 0;
  uint64_t largest_time = 0;
  for (const Event& event : trace->events()) {
    if (!event.has_time_us() || event.time_us() < largest_time) {
      LOG(FATAL)
          << "All events in the trace have to be sorted in chronological order";
    }
    largest_time = event.time_us();

    if (event.event_type() == PACKET_SENT) {
      Interval mapped = numbering.AssignTraceNumbering(event);
      AddPacket(renderer, event, mapped, PacketType::SENT);
      largest_sent =
          std::max<size_t>(mapped.offset + mapped.size, largest_sent);
    }
    if (event.event_type() == PACKET_RECEIVED) {
      for (const Frame& frame : event.frames()) {
        for (const AckBlock& range : frame.ack_info().acked_packets()) {
          for (size_t i = range.first_packet(); i <= range.last_packet(); i++) {
            if (!packets_acked_.insert(i).second) {
              continue;
            }
            Interval mapped = numbering.GetTraceNumbering(i);
            AddPacket(renderer, event, mapped, PacketType::ACKED);
            acks_.emplace(vec2(event.time_us(), mapped.offset), i);
            // Don't count spurious retransmissions as losses.
            packets_lost_.erase(i);
          }
        }
      }
    }
    if (event.event_type() == PACKET_LOST) {
      Interval mapped = numbering.GetTraceNumbering(event.packet_number());
      AddPacket(renderer, event, mapped, PacketType::LOST);
      packets_lost_.insert(event.packet_number());
    }
    if (event.event_type() == APPLICATION_LIMITED) {
      // Normally, we would use the size of the packet as height, but
      // app-limited events have no size, so we pick an arbitrary number (in
      // bytes).
      const size_t kAppLimitedHeigth = 800;
      AddPacket(renderer, event, Interval{largest_sent, kAppLimitedHeigth},
                PacketType::APP_LIMITED);
    }
  }

  renderer->FinishPackets();
  trace_ = std::move(trace);
}

bool ProcessedTrace::SummaryTable(Table* table,
                                  float start_time,
                                  float end_time) {
  auto compare = [](Event a, Event b) { return a.time_us() < b.time_us(); };
  Event key_event;

  key_event.set_time_us(start_time);
  auto start_it = absl::c_lower_bound(trace_->events(), key_event, compare);

  key_event.set_time_us(end_time);
  auto end_it = absl::c_upper_bound(trace_->events(), key_event, compare);

  if (start_it > end_it) {
    return false;
  }

  // TODO(vasilvv): add actually useful information.
  size_t count_sent = 0;
  size_t bytes_sent = 0;
  size_t bytes_sent_acked = 0;
  size_t bytes_sent_lost = 0;
  for (auto it = start_it; it != end_it; it++) {
    switch (it->event_type()) {
      case PACKET_SENT:
        count_sent++;
        bytes_sent += it->packet_size();
        if (packets_acked_.count(it->packet_number()) > 0) {
          bytes_sent_acked += it->packet_size();
        }
        if (packets_lost_.count(it->packet_number()) > 0) {
          bytes_sent_lost += it->packet_size();
        }
        break;
      default:
        break;
    };
  }

  table->AddHeader("Selection summary");
  table->AddRow("#sent", absl::StrCat(count_sent));
  table->AddRow("Send rate",
                FormatBandwidth(bytes_sent, end_time - start_time));
  table->AddRow("Goodput",
                FormatBandwidth(bytes_sent_acked, end_time - start_time));
  table->AddRow("Loss rate", FormatPercentage(bytes_sent_lost, bytes_sent));
  return true;
}

ProcessedTrace::PacketSearchResult ProcessedTrace::FindPacketContainingPoint(
    vec2 point,
    vec2 margin) {
  RenderedPacket key{Box(), nullptr};

  key.box.origin.x = point.x - kSentPacketDurationMs - margin.x;
  auto start_it = absl::c_lower_bound(rendered_packets_, key);

  key.box.origin.x = point.x + kSentPacketDurationMs + margin.x;
  auto end_it = absl::c_upper_bound(rendered_packets_, key);

  if (start_it > end_it) {
    return PacketSearchResult();
  }

  auto closest_box = end_it;
  float closest_distance;
  for (auto it = start_it; it != end_it; it++) {
    Box target_box{it->box.origin - margin, it->box.size + 2 * margin};
    if (IsInside(point, target_box)) {
      float distance = DistanceSquared(point, BoxCenter(target_box));
      if (closest_box == end_it || distance < closest_distance) {
        closest_box = it;
        closest_distance = distance;
      }
    }
  }
  if (closest_box != end_it) {
    PacketSearchResult result;
    result.index = closest_box - rendered_packets_.cbegin();
    result.as_rendered = &closest_box->box;
    result.event = closest_box->packet;
    return result;
  }

  return PacketSearchResult();
}

namespace {
const char* EncryptionLevelToString(EncryptionLevel level) {
  switch (level) {
    case ENCRYPTION_INITIAL:
      return "Initial";
    case ENCRYPTION_HANDSHAKE:
      return "Handshake";
    case ENCRYPTION_0RTT:
      return "0-RTT";
    case ENCRYPTION_1RTT:
      return "1-RTT";

    case ENCRYPTION_UNKNOWN:
    default:
      return "???";
  }
}

constexpr int kMaxAckBlocksShown = 3;
std::string AckSummary(const AckInfo& ack) {
  if (ack.acked_packets_size() == 0) {
    return "";
  }

  bool overflow = false;
  int blocks_to_show = ack.acked_packets_size();
  if (blocks_to_show > kMaxAckBlocksShown) {
    blocks_to_show = kMaxAckBlocksShown;
    overflow = true;
  }

  std::vector<std::string> ack_ranges;
  for (int i = 0; i < blocks_to_show; i++) {
    const AckBlock& block = ack.acked_packets(i);
    if (block.first_packet() == block.last_packet()) {
      ack_ranges.push_back(absl::StrCat(block.first_packet()));
    } else {
      ack_ranges.push_back(
          absl::StrCat(block.first_packet(), ":", block.last_packet()));
    }
  }

  std::string result = absl::StrJoin(ack_ranges, ", ");
  if (overflow) {
    absl::StrAppend(&result, "...");
  }
  return result;
}
}  // namespace

void ProcessedTrace::FillTableForPacket(Table* table,
                                        const Box* as_rendered,
                                        const Event* packet) {
  switch (packet->event_type()) {
    case PACKET_SENT:
      table->AddHeader(absl::StrCat("Sent packet #", packet->packet_number()));
      break;
    case PACKET_RECEIVED: {
      std::string packet_acked = "???";
      auto it = acks_.find(as_rendered->origin);
      if (it != acks_.end()) {
        packet_acked = absl::StrCat(it->second);
      }
      table->AddHeader(absl::StrCat("Ack for packet #", packet_acked));
      break;
    }
    case PACKET_LOST:
      table->AddHeader(absl::StrCat("Lost packet #", packet->packet_number()));
      break;
    case APPLICATION_LIMITED:
      table->AddHeader("Application limited");
      break;
    default:
      return;
  }

  table->AddRow("Time", FormatTime(packet->time_us()));

  if (packet->event_type() == PACKET_SENT) {
    table->AddRow("Size", absl::StrCat(packet->packet_size(), " bytes"));
    table->AddRow("Encryption",
                  EncryptionLevelToString(packet->encryption_level()));

    table->AddHeader("Frame list");
    for (const Frame& frame : packet->frames()) {
      switch (frame.frame_type()) {
        case STREAM:
          table->AddRow(
              "Stream",
              absl::StrCat("#", frame.stream_frame_info().stream_id(), ": ",
                           frame.stream_frame_info().offset(), "-",
                           frame.stream_frame_info().offset() +
                               frame.stream_frame_info().length(),
                           " (", frame.stream_frame_info().length(), ")"));
          break;
        case RESET_STREAM:
          table->AddRow(
              "Reset stream",
              absl::StrCat("#", frame.reset_stream_info().stream_id()));
          break;
        case CONNECTION_CLOSE:
          table->AddRow(
              "Connection close",
              absl::StrCat(absl::Hex(frame.close_info().error_code())));
          break;
        case PING:
          table->AddRow("Ping", "");
          break;
        case BLOCKED:
          table->AddRow("Blocked", "");
          break;
        case STREAM_BLOCKED:
          table->AddRow("Stream blocked",
                        absl::StrCat(frame.flow_control_info().stream_id()));
          break;
        case ACK:
          table->AddRow("Ack", AckSummary(frame.ack_info()));
          break;
        default:
          table->AddRow("Unknown", "");
          break;
      }
    }
  }

  if (packet->has_transport_state()) {
    const TransportState& state = packet->transport_state();
    table->AddHeader("Transport state");
    if (state.has_last_rtt_us()) {
      table->AddRow("RTT", FormatRtt(state.last_rtt_us()));
    }
    if (state.has_smoothed_rtt_us()) {
      table->AddRow("SRTT", FormatRtt(state.smoothed_rtt_us()));
    }
    if (state.has_min_rtt_us()) {
      table->AddRow("Min RTT", FormatRtt(state.min_rtt_us()));
    }
    if (state.has_in_flight_bytes()) {
      table->AddRow("In flight",
                    absl::StrCat(state.in_flight_bytes(), " bytes"));
    }
    if (state.has_cwnd_bytes()) {
      table->AddRow("CWND", absl::StrCat(state.cwnd_bytes(), " bytes"));
    }
    if (state.has_pacing_rate_bps()) {
      table->AddRow("Pacing rate",
                    FormatBandwidth(state.pacing_rate_bps(), 8000 * 1000));
    }
    if (state.has_congestion_control_state()) {
      // Truncate CC state strings longer than 80 characters.
      const int kMaxLen = 80;
      std::string ccstate = state.congestion_control_state();
      if (ccstate.length() > kMaxLen) {
        ccstate = ccstate.substr(0, kMaxLen) + "...";
      }
      table->AddRow("CC State", ccstate);
    }
  }
}

absl::optional<Box> ProcessedTrace::BoundContainedPackets(Box boundary) {
  RenderedPacket key{Box(), nullptr};

  key.box.origin.x = boundary.origin.x;
  auto range_start = absl::c_lower_bound(rendered_packets_, key);

  key.box.origin.x =
      boundary.origin.x + boundary.size.x + kSentPacketDurationMs;
  auto range_end = absl::c_upper_bound(rendered_packets_, key);

  if (range_start == rendered_packets_.end() ||
      range_end == rendered_packets_.end() || range_start > range_end) {
    return absl::nullopt;
  }

  absl::optional<Box> result;
  for (auto it = range_start; it <= range_end; it++) {
    if (IsInside(it->box, boundary)) {
      result = result.has_value() ? BoundingBox(*result, it->box) : it->box;
    }
  }
  return result;
}

}  // namespace render
}  // namespace quic_trace
<|endoftext|>


<commit_before>/*

* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/

#include "SkTypes.h"
#include "SkTHash.h"
#include "Timer.h"
#include "Window_unix.h"
#include "../Application.h"

using sk_app::Application;

void finishWindow(sk_app::Window_unix* win) {
    win->finishResize();
    win->finishPaint();
}

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

    Display* display = XOpenDisplay(nullptr);

    Application* app = Application::Create(argc, argv, (void*)display);

    // Get the file descriptor for the X display
    int x11_fd = ConnectionNumber(display);
    int count = x11_fd + 1;

    SkTHashSet<sk_app::Window_unix*> pendingWindows;
    bool done = false;
    while (!done) {
        // Create a file description set containing x11_fd
        fd_set in_fds;
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);

        // Set a sleep timer
        struct timeval tv;
        tv.tv_usec = 100;
        tv.tv_sec = 0;

        while (!XPending(display)) {
            // Wait for an event on the file descriptor or for timer expiration
            (void) select(count, &in_fds, nullptr, nullptr, &tv);
        }

        // Handle XEvents (if any) and flush the input
        int count = XPending(display);
        while (count-- && !done) {
            XEvent event;
            XNextEvent(display, &event);

            sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window);
            if (!win) {
                continue;
            }

            // paint and resize events get collapsed
            switch (event.type) {
            case Expose:
                win->markPendingPaint();
                pendingWindows.add(win);
                break;
            case ConfigureNotify:
                win->markPendingResize(event.xconfigurerequest.width,
                                       event.xconfigurerequest.height);
                pendingWindows.add(win);
                break;
            default:
                if (win->handleEvent(event)) {
                    done = true;
                }
                break;
            }
        }

        pendingWindows.foreach(finishWindow);
        if (pendingWindows.count() > 0) {
            app->onIdle();
        }
        pendingWindows.reset();

        XFlush(display);
    }

    delete app;

    XCloseDisplay(display);

    return 0;
}
<commit_msg>Call XInitThreads in sk_app startup<commit_after>/*

* Copyright 2016 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/

#include "SkTypes.h"
#include "SkTHash.h"
#include "Timer.h"
#include "Window_unix.h"
#include "../Application.h"

using sk_app::Application;

void finishWindow(sk_app::Window_unix* win) {
    win->finishResize();
    win->finishPaint();
}

int main(int argc, char**argv) {
    XInitThreads();
    Display* display = XOpenDisplay(nullptr);

    Application* app = Application::Create(argc, argv, (void*)display);

    // Get the file descriptor for the X display
    int x11_fd = ConnectionNumber(display);
    int count = x11_fd + 1;

    SkTHashSet<sk_app::Window_unix*> pendingWindows;
    bool done = false;
    while (!done) {
        // Create a file description set containing x11_fd
        fd_set in_fds;
        FD_ZERO(&in_fds);
        FD_SET(x11_fd, &in_fds);

        // Set a sleep timer
        struct timeval tv;
        tv.tv_usec = 100;
        tv.tv_sec = 0;

        while (!XPending(display)) {
            // Wait for an event on the file descriptor or for timer expiration
            (void) select(count, &in_fds, nullptr, nullptr, &tv);
        }

        // Handle XEvents (if any) and flush the input
        int count = XPending(display);
        while (count-- && !done) {
            XEvent event;
            XNextEvent(display, &event);

            sk_app::Window_unix* win = sk_app::Window_unix::gWindowMap.find(event.xany.window);
            if (!win) {
                continue;
            }

            // paint and resize events get collapsed
            switch (event.type) {
            case Expose:
                win->markPendingPaint();
                pendingWindows.add(win);
                break;
            case ConfigureNotify:
                win->markPendingResize(event.xconfigurerequest.width,
                                       event.xconfigurerequest.height);
                pendingWindows.add(win);
                break;
            default:
                if (win->handleEvent(event)) {
                    done = true;
                }
                break;
            }
        }

        pendingWindows.foreach(finishWindow);
        if (pendingWindows.count() > 0) {
            app->onIdle();
        }
        pendingWindows.reset();

        XFlush(display);
    }

    delete app;

    XCloseDisplay(display);

    return 0;
}
<|endoftext|>


<commit_before>#include "projet.h"
#include <QtDebug>
#include <QProcess>

Projet::Projet(QString &name, QDir &workspace, QFile &video, int frequence)
{
    if(workspace.exists() && video.exists() && workspace.mkdir(name))
    {
        _project = new QDir(workspace.path()+"/"+name);
        qDebug() << _project->path();
        _project->mkdir("input");
        video.copy(_project->path()+"/input/video");
        _video = new QFile(_project->path()+"/input/video");

        QProcess process;
        process.startDetached("avconv -i " + _project->path() +"/input/video -vsync 1 -r 8 -y " + _project->path() + "/input/img%d.jpg");
    }
}
<commit_msg>Use exception<commit_after>#include "projet.h"
#include <QtDebug>
#include <QProcess>

Projet::Projet(QString &name, QDir &workspace, QFile &video, int frequence)
{
    if(workspace.exists())
    {
        if(video.exists())
        {
            if(workspace.mkdir(name))
            {
                _project = new QDir(workspace.path()+"/"+name);
                qDebug() << _project->path();
                _project->mkdir("input");
                video.copy(_project->path()+"/input/video");
                _video = new QFile(_project->path()+"/input/video");

                QProcess process;
                process.startDetached("avconv -i " + _project->path() +"/input/video -vsync 1 -r 8 -y " + _project->path() + "/input/img%d.jpg");
            }
            else
            {
                throw QString("Ce projet existe déjà");
            }
        }
        else
        {
            throw QString("La vidéo n'existe pas");
        }
    }
    else
    {
        throw QString("Le workspace n'existe pas");
    }
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <sstream>

#include "stream_iterator.hpp"
#include "templateio.hpp"
#include "profile.hpp"

using namespace std;

//============================================================================
// Logic Language Parser.
//
// A simple parser for a Prolog like language.

//----------------------------------------------------------------------------
// Syntactic Structure.
//
// A global set of names keeps string comparisons for atoms and varibles to
// a single iterator (pointer) comparison. A single type is used for atoms
// and structs, which is combined with a variable type in an expression
// supertype. Clauses combine heads and goals, and keep track of repeated
// variables in the head for efficient post-unification cycle checking.

using name_t = set<string>::const_iterator;

struct type_expression {
    virtual ostream& operator<< (ostream& out) const = 0;
};

struct type_variable : public type_expression {
    name_t const name;

    type_variable(name_t n) : name(n) {}

    virtual ostream& operator<< (ostream& out) const override {
        out << *name;
        return out;
    }
};

struct type_struct : public type_expression {
    name_t const name;
    vector<type_expression*> const args;

    template <typename As>
    type_struct(name_t n, As&& as) : name(n), args(forward<As>(as)) {}

    ostream& operator<< (ostream& out) const override {
        out << *name << "(";
        for (auto i = args.cbegin(); i != args.cend(); ++i) {
            (*i)->operator<<(out);
            auto j = i;
            if (++j != args.end()) {
                out << ", ";
            }
        }
        out << ")";
        return out;
    }
};

ostream& operator<< (ostream& out, type_expression* exp) {
    exp->operator<<(out);
    return out;
}

struct clause {
    type_struct* const head;
    vector<type_struct*> const impl;
    set<type_variable*> const reps;

    template <typename Is, typename Rs>
    clause(type_struct* h, Is&& is, Rs&& rs) : head(h), impl(forward<Is>(is)),
        reps(forward<Rs>(rs)) {}
};

ostream& operator<< (ostream& out, clause* cls) {
    cls->head->operator<<(out);
    auto f = cls->impl.cbegin();
    auto const l = cls->impl.cend();
    if (f != l) {
        out << " :-" << endl;
        for (auto i = f; i != l; ++i) {
            out << "\t";
            (*i)->operator<<(out);
            auto j = i;
            if (++j != l) {
                out << "," << endl;
            }
        }
    }
    out << ".";

    auto g = cls->reps.cbegin();
    auto const m = cls->reps.cend();
    if (g != m) {
        out << " [";
        for (auto i = g; i != m; ++i) {
            (*i)->operator<<(out);
            auto j = i;
            if (++j != m) {
                out << ", ";
            }
        }
        out << "]";
    }
    out << endl;

    return out;
}

//----------------------------------------------------------------------------
// Parser State
//
// Making this uncopyable prevents backtracking being used, as the 'attempt'
// combinator will try and make a copy of the inherited attribute for
// backtracking. This can be seen as a constraint on the parser (to ensure
// performance) or a safety measure to make sure we deal with copying if we
// want backtracking.

using var_t = map<string const*, type_variable*>::const_iterator;

struct parser_state {
    set<string> names; // global name table
    map<string const*, type_variable*> variables;
    set<type_variable*> repeated;
    set<type_variable*> repeated_in_goal;

    parser_state() {};
    parser_state(parser_state const&) = delete;
    parser_state& operator= (parser_state const&) = delete;

    name_t get_name(string const& name) {
        name_t const n = names.find(name);
        if (n == names.end()) {
            return names.insert(name).first;
        } else {
            return n;
        }
    }
};

//----------------------------------------------------------------------------
// Grammar
//
// Function objects get passed the results of the sub-parsers, along with the
// inherited attribute. As the parser-combinators are templated, the inherited
// attribute is whatever type is passed as the final argument to the parser.

struct return_variable {
    return_variable() {}
    void operator() (type_variable** res, string const& name, parser_state* st) const {
        name_t const n = st->get_name(name);
        var_t i = st->variables.find(&(*n));
        if (i == st->variables.end()) {
            type_variable* const var = new type_variable(n);
            st->variables.insert(make_pair(&(*n), var));
            *res = var;
        } else {
            st->repeated.insert(i->second);
            *res = i->second;
        }
    }
} const return_variable;

struct return_args {
    return_args() {}
    void operator() (vector<type_expression*>* res, int n, type_variable* var, type_struct* str, parser_state*) const {
        switch(n) {
            case 0:
                res->push_back(var);
                break;
            case 1:
                res->push_back(str);
                break;
        }
    }
} const return_args;

struct return_struct {
    return_struct() {}
    void operator() (type_struct** res, string const& name, vector<type_expression*>& args, parser_state* st) const {
        name_t n = st->get_name(name);
        *res = new type_struct(n, args);
    }
} const return_struct;

struct return_head {
    return_head() {}
    void operator() (type_struct** res, type_struct* str, parser_state* st) const {
        *res = str;
        st->repeated_in_goal = st->repeated;
    }
} const return_head;

struct return_goal {
    return_goal() {}
    void operator() (vector<type_struct*>* res, type_struct* impl, parser_state*) const {
        res->push_back(impl);
    }
} const return_goal;

struct return_clause {
    return_clause() {}
    void operator() (vector<clause*>* res, type_struct* head, vector<type_struct*>& impl, parser_state* st) const {
        res->push_back(new clause(head, impl, st->repeated_in_goal));
        st->variables.clear();
        st->repeated.clear();
        st->repeated_in_goal.clear();
    }
} const return_clause;

struct return_goals {
    return_goals() {}
    void operator() (vector<clause*>* res, vector<type_struct*>& impl, parser_state* st) const {
        vector<type_expression*> vars;
        for (auto v : st->variables) {
            vars.push_back(v.second);
        }
        res->push_back(new clause(
            new type_struct(st->get_name("goal"), vars), impl, set<type_variable*> {}
        ));

        st->variables.clear();
        st->repeated.clear();
        st->repeated_in_goal.clear();
    }
} const return_goals;

//----------------------------------------------------------------------------
// Parser
//
// The parsers and user grammar are all stateless, so can be const objects and
// still thread safe. The final composed parser is a regular procedure, all state
// is either in the state object passed in, or in the returned values.

auto const atom_tok = tokenise(accept(is_lower) && many(accept(is_alnum || is_char('_'))));
auto const var_tok = tokenise(accept(is_upper || is_char('_')) && many(accept(is_alnum || is_char('_'))));
auto const open_tok = tokenise(accept(is_char('(')));
auto const close_tok = tokenise(accept(is_char(')')));
auto const sep_tok = tokenise(accept(is_char(',')));
auto const impl_tok = tokenise(accept_str(":-"));
auto const end_tok = tokenise(accept(is_char('.')));
auto const comment_tok = tokenise(accept(is_char('#')) && many(accept(is_print)) && accept(is_eol));

// the "definitions" help clean up the EBNF output in error reports
auto const variable = define("variable", all(return_variable, var_tok));
auto const atom = define("atom", atom_tok);

// a function from a parser to a parser.
pstream_handle<type_struct*, parser_state> recursive_structure(pstream_handle<type_struct*, parser_state> const s) {
    return all(return_struct, atom, option(discard(open_tok)
        && sep_by(any(return_args, variable, s), discard(sep_tok))
        && discard(close_tok)));
}

// tie the recursive knot.
auto const structure = fix("struct", recursive_structure);

auto const comment = define("comment", discard(comment_tok));
auto const goals = define("goals", discard(impl_tok)
    && sep_by(all(return_goal, structure), discard(sep_tok)));
auto const query = define("query", all(return_goals, goals) && discard(end_tok));
auto const clause = define("clause", all(return_clause, all(return_head, structure), option(goals) && discard(end_tok)));

auto const program = strict("unexpected character", some(clause || query || comment));

struct expression_parser;

template <typename Range>
int parse(Range const &r) {
    auto const parser = first_token && program;
    decltype(parser)::result_type a {};
    typename Range::iterator i = r.first;
    parser_state st;

    profile<expression_parser> p;
    if (parser(i, r, &a, &st)) {
        cout << "OK" << endl;
    } else {
        cout << "FAIL" << endl;
    }

    cout << a << endl;

    return i - r.first;
}

//----------------------------------------------------------------------------
// The stream_range allows file iterators to be used like random_iterators
// and abstracts the difference between C++ stdlib streams and file_vectors.

int main(int const argc, char const *argv[]) {
    if (argc < 1) {
        cerr << "no input files" << endl;
    } else {
        for (int i = 1; i < argc; ++i) {
            profile<expression_parser>::reset();
            stream_range in(argv[i]);
            cout << argv[i] << endl;
            int const chars_read = parse(in);
            double const mb_per_s = static_cast<double>(chars_read) / static_cast<double>(profile<expression_parser>::report());
            cout << "parsed: " << mb_per_s << "MB/s" << endl;
        }
    }
}
<commit_msg>tidy parse function<commit_after>#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <sstream>

#include "stream_iterator.hpp"
#include "templateio.hpp"
#include "profile.hpp"

using namespace std;

//============================================================================
// Logic Language Parser.
//
// A simple parser for a Prolog like language.

//----------------------------------------------------------------------------
// Syntactic Structure.
//
// A global set of names keeps string comparisons for atoms and varibles to
// a single iterator (pointer) comparison. A single type is used for atoms
// and structs, which is combined with a variable type in an expression
// supertype. Clauses combine heads and goals, and keep track of repeated
// variables in the head for efficient post-unification cycle checking.

using name_t = set<string>::const_iterator;

struct type_expression {
    virtual ostream& operator<< (ostream& out) const = 0;
};

struct type_variable : public type_expression {
    name_t const name;

    type_variable(name_t n) : name(n) {}

    virtual ostream& operator<< (ostream& out) const override {
        out << *name;
        return out;
    }
};

struct type_struct : public type_expression {
    name_t const name;
    vector<type_expression*> const args;

    template <typename As>
    type_struct(name_t n, As&& as) : name(n), args(forward<As>(as)) {}

    ostream& operator<< (ostream& out) const override {
        out << *name << "(";
        for (auto i = args.cbegin(); i != args.cend(); ++i) {
            (*i)->operator<<(out);
            auto j = i;
            if (++j != args.end()) {
                out << ", ";
            }
        }
        out << ")";
        return out;
    }
};

ostream& operator<< (ostream& out, type_expression* exp) {
    exp->operator<<(out);
    return out;
}

struct clause {
    type_struct* const head;
    vector<type_struct*> const impl;
    set<type_variable*> const reps;

    template <typename Is, typename Rs>
    clause(type_struct* h, Is&& is, Rs&& rs) : head(h), impl(forward<Is>(is)),
        reps(forward<Rs>(rs)) {}
};

ostream& operator<< (ostream& out, clause* cls) {
    cls->head->operator<<(out);
    auto f = cls->impl.cbegin();
    auto const l = cls->impl.cend();
    if (f != l) {
        out << " :-" << endl;
        for (auto i = f; i != l; ++i) {
            out << "\t";
            (*i)->operator<<(out);
            auto j = i;
            if (++j != l) {
                out << "," << endl;
            }
        }
    }
    out << ".";

    auto g = cls->reps.cbegin();
    auto const m = cls->reps.cend();
    if (g != m) {
        out << " [";
        for (auto i = g; i != m; ++i) {
            (*i)->operator<<(out);
            auto j = i;
            if (++j != m) {
                out << ", ";
            }
        }
        out << "]";
    }
    out << endl;

    return out;
}

//----------------------------------------------------------------------------
// Parser State
//
// Making this uncopyable prevents backtracking being used, as the 'attempt'
// combinator will try and make a copy of the inherited attribute for
// backtracking. This can be seen as a constraint on the parser (to ensure
// performance) or a safety measure to make sure we deal with copying if we
// want backtracking.

using var_t = map<string const*, type_variable*>::const_iterator;

struct parser_state {
    set<string> names; // global name table
    map<string const*, type_variable*> variables;
    set<type_variable*> repeated;
    set<type_variable*> repeated_in_goal;

    parser_state() {};
    parser_state(parser_state const&) = delete;
    parser_state& operator= (parser_state const&) = delete;

    name_t get_name(string const& name) {
        name_t const n = names.find(name);
        if (n == names.end()) {
            return names.insert(name).first;
        } else {
            return n;
        }
    }
};

//----------------------------------------------------------------------------
// Grammar
//
// Function objects get passed the results of the sub-parsers, along with the
// inherited attribute. As the parser-combinators are templated, the inherited
// attribute is whatever type is passed as the final argument to the parser.

struct return_variable {
    return_variable() {}
    void operator() (type_variable** res, string const& name, parser_state* st) const {
        name_t const n = st->get_name(name);
        var_t i = st->variables.find(&(*n));
        if (i == st->variables.end()) {
            type_variable* const var = new type_variable(n);
            st->variables.insert(make_pair(&(*n), var));
            *res = var;
        } else {
            st->repeated.insert(i->second);
            *res = i->second;
        }
    }
} const return_variable;

struct return_args {
    return_args() {}
    void operator() (vector<type_expression*>* res, int n, type_variable* var, type_struct* str, parser_state*) const {
        switch(n) {
            case 0:
                res->push_back(var);
                break;
            case 1:
                res->push_back(str);
                break;
        }
    }
} const return_args;

struct return_struct {
    return_struct() {}
    void operator() (type_struct** res, string const& name, vector<type_expression*>& args, parser_state* st) const {
        name_t n = st->get_name(name);
        *res = new type_struct(n, args);
    }
} const return_struct;

struct return_head {
    return_head() {}
    void operator() (type_struct** res, type_struct* str, parser_state* st) const {
        *res = str;
        st->repeated_in_goal = st->repeated;
    }
} const return_head;

struct return_goal {
    return_goal() {}
    void operator() (vector<type_struct*>* res, type_struct* impl, parser_state*) const {
        res->push_back(impl);
    }
} const return_goal;

struct return_clause {
    return_clause() {}
    void operator() (vector<clause*>* res, type_struct* head, vector<type_struct*>& impl, parser_state* st) const {
        res->push_back(new clause(head, impl, st->repeated_in_goal));
        st->variables.clear();
        st->repeated.clear();
        st->repeated_in_goal.clear();
    }
} const return_clause;

struct return_goals {
    return_goals() {}
    void operator() (vector<clause*>* res, vector<type_struct*>& impl, parser_state* st) const {
        vector<type_expression*> vars;
        for (auto v : st->variables) {
            vars.push_back(v.second);
        }
        res->push_back(new clause(
            new type_struct(st->get_name("goal"), vars), impl, set<type_variable*> {}
        ));

        st->variables.clear();
        st->repeated.clear();
        st->repeated_in_goal.clear();
    }
} const return_goals;

//----------------------------------------------------------------------------
// Parser
//
// The parsers and user grammar are all stateless, so can be const objects and
// still thread safe. The final composed parser is a regular procedure, all state
// is either in the state object passed in, or in the returned values.

auto const atom_tok = tokenise(accept(is_lower) && many(accept(is_alnum || is_char('_'))));
auto const var_tok = tokenise(accept(is_upper || is_char('_')) && many(accept(is_alnum || is_char('_'))));
auto const open_tok = tokenise(accept(is_char('(')));
auto const close_tok = tokenise(accept(is_char(')')));
auto const sep_tok = tokenise(accept(is_char(',')));
auto const impl_tok = tokenise(accept_str(":-"));
auto const end_tok = tokenise(accept(is_char('.')));
auto const comment_tok = tokenise(accept(is_char('#')) && many(accept(is_print)) && accept(is_eol));

// the "definitions" help clean up the EBNF output in error reports
auto const variable = define("variable", all(return_variable, var_tok));
auto const atom = define("atom", atom_tok);

// a function from a parser to a parser.
pstream_handle<type_struct*, parser_state> recursive_structure(pstream_handle<type_struct*, parser_state> const s) {
    return all(return_struct, atom, option(discard(open_tok)
        && sep_by(any(return_args, variable, s), discard(sep_tok))
        && discard(close_tok)));
}

// tie the recursive knot.
auto const structure = fix("struct", recursive_structure);

auto const comment = define("comment", discard(comment_tok));
auto const goals = define("goals", discard(impl_tok)
    && sep_by(all(return_goal, structure), discard(sep_tok)));
auto const query = define("query", all(return_goals, goals) && discard(end_tok));
auto const clause = define("clause", all(return_clause, all(return_head, structure), option(goals) && discard(end_tok)));

auto const program = first_token && strict("unexpected character", some(clause || query || comment));

struct expression_parser;

template <typename Range>
int parse(Range const &r) {
    decltype(program)::result_type a {};
    typename Range::iterator i = r.first;
    parser_state st;

    profile<expression_parser> p;
    if (program(i, r, &a, &st)) {
        cout << "OK" << endl;
    } else {
        cout << "FAIL" << endl;
    }

    cout << a << endl;

    return i - r.first;
}

//----------------------------------------------------------------------------
// The stream_range allows file iterators to be used like random_iterators
// and abstracts the difference between C++ stdlib streams and file_vectors.

int main(int const argc, char const *argv[]) {
    if (argc < 1) {
        cerr << "no input files" << endl;
    } else {
        for (int i = 1; i < argc; ++i) {
            profile<expression_parser>::reset();
            stream_range in(argv[i]);
            cout << argv[i] << endl;
            int const chars_read = parse(in);
            double const mb_per_s = static_cast<double>(chars_read) / static_cast<double>(profile<expression_parser>::report());
            cout << "parsed: " << mb_per_s << "MB/s" << endl;
        }
    }
}
<|endoftext|>