<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifndef CLIENT_ONLY

#include "server.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "../Interface/ThreadPool.h"
#include "server_get.h"
#include "database.h"
#include "../Interface/SettingsReader.h"
#include "server_status.h"
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include "InternetServiceConnector.h"
#include "../Interface/PipeThrottler.h"
#include <memory.h>

const unsigned int waittime=50*1000; //1 min
const int max_offline=5;

IPipeThrottler *BackupServer::global_internet_throttler=NULL;
IPipeThrottler *BackupServer::global_local_throttler=NULL;
IMutex *BackupServer::throttle_mutex=NULL;

BackupServer::BackupServer(IPipe *pExitpipe)
{
	throttle_mutex=Server->createMutex();
	exitpipe=pExitpipe;

	if(Server->getServerParameter("internet_test_mode")=="true")
		internet_test_mode=true;
	else
		internet_test_mode=false;
}

BackupServer::~BackupServer()
{
	Server->destroy(throttle_mutex);
}

void BackupServer::operator()(void)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER);
	ISettingsReader *settings=Server->createDBSettingsReader(Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER), "settings_db.settings");

#ifdef _WIN32
	std::wstring tmpdir;
	if(settings->getValue(L"tmpdir", &tmpdir) && !tmpdir.empty())
	{
		os_remove_nonempty_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		Server->setTemporaryDirectory(tmpdir+os_file_sep()+L"urbackup_tmp");
	}
	else
	{
		wchar_t tmpp[MAX_PATH];
		DWORD l;
		if((l=GetTempPathW(MAX_PATH, tmpp))==0 || l>MAX_PATH )
		{
			wcscpy_s(tmpp,L"C:\\");
		}

		std::wstring w_tmp=tmpp;

		if(!w_tmp.empty() && w_tmp[w_tmp.size()-1]=='\\')
		{
			w_tmp.erase(w_tmp.size()-1, 1);		}

		os_remove_nonempty_dir(w_tmp+os_file_sep()+L"urbackup_tmp");
		os_create_dir(w_tmp+os_file_sep()+L"urbackup_tmp");
		Server->setTemporaryDirectory(w_tmp+os_file_sep()+L"urbackup_tmp");
	}
#endif

	q_get_extra_hostnames=db->Prepare("SELECT id,hostname FROM settings_db.extra_clients");
	q_update_extra_ip=db->Prepare("UPDATE settings_db.extra_clients SET lastip=? WHERE id=?");

	FileClient fc;

	Server->wait(1000);

	while(true)
	{
		findClients(fc);
		startClients(fc);

		if(!ServerStatus::isActive() && settings->getValue("autoshutdown", "false")=="true")
		{
			writestring("true", "urbackup/shutdown_now");
#ifdef _WIN32
			ExitWindowsEx(EWX_POWEROFF|EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER );
#endif
		}

		std::string r;
		exitpipe->Read(&r, waittime);
		if(r=="exit")
		{
			removeAllClients();
			exitpipe->Write("ok");
			Server->destroy(settings);
			db->destroyAllQueries();
			delete this;
			return;
		}
	}
}

void BackupServer::findClients(FileClient &fc)
{
	db_results res=q_get_extra_hostnames->Read();
	q_get_extra_hostnames->Reset();

	std::vector<in_addr> addr_hints;

	for(size_t i=0;i<res.size();++i)
	{
		unsigned int dest;
		bool b=os_lookuphostname(Server->ConvertToUTF8(res[i][L"hostname"]), &dest);
		if(b)
		{
			q_update_extra_ip->Bind((_i64)dest);
			q_update_extra_ip->Bind(res[i][L"id"]);
			q_update_extra_ip->Write();
			q_update_extra_ip->Reset();

			in_addr tmp;
			tmp.s_addr=dest;
			addr_hints.push_back(tmp);
		}
	}

	_u32 rc=fc.GetServers(true, addr_hints);
	while(rc==ERR_CONTINUE)
	{
		Server->wait(50);
		rc=fc.GetServers(false, addr_hints);
	}

	if(rc==ERR_ERROR)
	{
		Server->Log("Error in BackupServer::findClients rc==ERR_ERROR",LL_ERROR);
	}
}

void BackupServer::startClients(FileClient &fc)
{
	std::vector<std::wstring> names;
	std::vector<sockaddr_in> servers;

	if(!internet_test_mode)
	{
		names=fc.getServerNames();
		servers=fc.getServers();
	}

	std::vector<bool> inetclient;
	inetclient.resize(names.size());
	std::fill(inetclient.begin(), inetclient.end(), false);
	std::vector<std::string> anames=InternetServiceConnector::getOnlineClients();
	for(size_t i=0;i<anames.size();++i)
	{
		names.push_back(Server->ConvertToUnicode(anames[i]));
		inetclient.push_back(true);
		sockaddr_in n;
		memset(&n, 0, sizeof(sockaddr_in));
		servers.push_back(n);
	}

	for(size_t i=0;i<names.size();++i)
	{
		names[i]=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(names[i])));
		std::map<std::wstring, SClient>::iterator it=clients.find(names[i]);
		if( it==clients.end() )
		{
			if(inetclient[i]==true)
			{
				bool skip=false;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[i]==names[j] && inetclient[j]==false)
					{
						skip=true;
						break;
					}
				}
				if(skip)
					continue;
			}

			Server->Log(L"New Backupclient: "+names[i]);
			ServerStatus::setOnline(names[i], true);
			IPipe *np=Server->createMemoryPipe();

			BackupServerGet *client=new BackupServerGet(np, servers[i], names[i], inetclient[i]);
			Server->getThreadPool()->execute(client);

			SClient c;
			c.pipe=np;
			c.offlinecount=0;
			c.addr=servers[i];
			c.internet_connection=inetclient[i];

			ServerStatus::setIP(names[i], c.addr.sin_addr.s_addr);

			clients.insert(std::pair<std::wstring, SClient>(names[i], c) );
		}
		else if(it->second.offlinecount<max_offline)
		{
			bool found_lan=false;
			if(inetclient[i]==false && it->second.internet_connection==true)
			{
				found_lan=true;
			}

			if(it->second.addr.sin_addr.s_addr==servers[i].sin_addr.s_addr && !found_lan)
			{
				it->second.offlinecount=0;
			}
			else
			{
				bool none_fits=true;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[j]==names[i] && it->second.addr.sin_addr.s_addr==servers[j].sin_addr.s_addr)
					{
						none_fits=false;
						break;
					}
				}
				if(none_fits || found_lan)
				{
					it->second.addr=servers[i];
					std::string msg;
					msg.resize(7+sizeof(sockaddr_in)+1);
					msg[0]='a'; msg[1]='d'; msg[2]='d'; msg[3]='r'; msg[4]='e'; msg[5]='s'; msg[6]='s';
					memcpy(&msg[7], &it->second.addr, sizeof(sockaddr_in));
					msg[7+sizeof(sockaddr_in)]=(inetclient[i]==true?1:0);
					it->second.pipe->Write(msg);

					char *ip=(char*)&it->second.addr.sin_addr.s_addr;

					Server->Log("New client address: "+nconvert((unsigned char)ip[0])+"."+nconvert((unsigned char)ip[1])+"."+nconvert((unsigned char)ip[2])+"."+nconvert((unsigned char)ip[3]), LL_INFO);

					ServerStatus::setIP(names[i], it->second.addr.sin_addr.s_addr);

					it->second.offlinecount=0;
				}
			}
		}
	}

	bool c=true;
	size_t maxi=0;
	while(c && !clients.empty())
	{
		c=false;

		size_t i_c=0;
		for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
		{
			bool found=false;
			for(size_t i=0;i<names.size();++i)
			{
				if( it->first==names[i] )
				{
					found=true;
					break;
				}
			}
			if( found==false || it->second.offlinecount>max_offline)
			{
				if(it->second.offlinecount==max_offline)
				{
					Server->Log(L"Client exitet: "+it->first);
					it->second.pipe->Write("exit");
					++it->second.offlinecount;
					ServerStatus::setOnline(it->first, false);
				}
				else if(it->second.offlinecount>max_offline)
				{
					std::string msg;
					std::vector<std::string> msgs;
					while(it->second.pipe->Read(&msg,0)>0)
					{
						if(msg!="ok")
						{
							msgs.push_back(msg);
						}
						else
						{
							Server->Log(L"Client finished: "+it->first);
							ServerStatus::setDone(it->first, true);
							Server->destroy(it->second.pipe);
							clients.erase(it);
							maxi=i_c;
							c=true;
							break;
						}
					}
					if( c==false )
					{
						for(size_t i=0;i<msgs.size();++i)
						{
							it->second.pipe->Write(msgs[i]);
						}
					}
					else
					{
						break;
					}
				}
				else if(i_c>=maxi)
				{
					SStatusAction s_action=ServerStatus::getStatus(it->first).statusaction;

					if(s_action==sa_none)
					{
						++it->second.offlinecount;
					}
				}
			}
			++i_c;
		}
	}
}

void BackupServer::removeAllClients(void)
{
	for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
	{
		it->second.pipe->Write("exitnow");
		std::string msg;
		while(msg!="ok")
		{
			it->second.pipe->Read(&msg);
			it->second.pipe->Write(msg.c_str());
			Server->wait(500);
		}
		Server->destroy(it->second.pipe);
	}
}

IPipeThrottler *BackupServer::getGlobalInternetThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_internet_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_internet_throttler==NULL)
	{
		global_internet_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_internet_throttler->changeThrottleLimit(speed_bps);
	}
	return global_internet_throttler;
}

IPipeThrottler *BackupServer::getGlobalLocalThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_local_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_local_throttler==NULL)
	{
		global_local_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_local_throttler->changeThrottleLimit(speed_bps);
	}
	return global_local_throttler;
}

void BackupServer::cleanupThrottlers(void)
{
	if(global_internet_throttler!=NULL)
	{
		Server->destroy(global_internet_throttler);
	}
	if(global_local_throttler!=NULL)
	{
		Server->destroy(global_local_throttler);
	}
}

#endif //CLIENT_ONLY
<commit_msg>Retry creating urbackup directory in temporary file directory<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011  Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#ifndef CLIENT_ONLY

#include "server.h"
#include "../Interface/Server.h"
#include "../Interface/Database.h"
#include "../Interface/ThreadPool.h"
#include "server_get.h"
#include "database.h"
#include "../Interface/SettingsReader.h"
#include "server_status.h"
#include "../stringtools.h"
#include "../urbackupcommon/os_functions.h"
#include "InternetServiceConnector.h"
#include "../Interface/PipeThrottler.h"
#include <memory.h>

const unsigned int waittime=50*1000; //1 min
const int max_offline=5;

IPipeThrottler *BackupServer::global_internet_throttler=NULL;
IPipeThrottler *BackupServer::global_local_throttler=NULL;
IMutex *BackupServer::throttle_mutex=NULL;

BackupServer::BackupServer(IPipe *pExitpipe)
{
	throttle_mutex=Server->createMutex();
	exitpipe=pExitpipe;

	if(Server->getServerParameter("internet_test_mode")=="true")
		internet_test_mode=true;
	else
		internet_test_mode=false;
}

BackupServer::~BackupServer()
{
	Server->destroy(throttle_mutex);
}

void BackupServer::operator()(void)
{
	IDatabase *db=Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER);
	ISettingsReader *settings=Server->createDBSettingsReader(Server->getDatabase(Server->getThreadID(),URBACKUPDB_SERVER), "settings_db.settings");

#ifdef _WIN32
	std::wstring tmpdir;
	if(settings->getValue(L"tmpdir", &tmpdir) && !tmpdir.empty())
	{
		os_remove_nonempty_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(tmpdir+os_file_sep()+L"urbackup_tmp");
	}
	else
	{
		wchar_t tmpp[MAX_PATH];
		DWORD l;
		if((l=GetTempPathW(MAX_PATH, tmpp))==0 || l>MAX_PATH )
		{
			wcscpy_s(tmpp,L"C:\\");
		}

		std::wstring w_tmp=tmpp;

		if(!w_tmp.empty() && w_tmp[w_tmp.size()-1]=='\\')
		{
			w_tmp.erase(w_tmp.size()-1, 1);		}

		os_remove_nonempty_dir(w_tmp+os_file_sep()+L"urbackup_tmp");
		if(!os_create_dir(w_tmp+os_file_sep()+L"urbackup_tmp"))
		{
			Server->wait(5000);
			os_create_dir(tmpdir+os_file_sep()+L"urbackup_tmp");
		}
		Server->setTemporaryDirectory(w_tmp+os_file_sep()+L"urbackup_tmp");
	}
#endif

	q_get_extra_hostnames=db->Prepare("SELECT id,hostname FROM settings_db.extra_clients");
	q_update_extra_ip=db->Prepare("UPDATE settings_db.extra_clients SET lastip=? WHERE id=?");

	FileClient fc;

	Server->wait(1000);

	while(true)
	{
		findClients(fc);
		startClients(fc);

		if(!ServerStatus::isActive() && settings->getValue("autoshutdown", "false")=="true")
		{
			writestring("true", "urbackup/shutdown_now");
#ifdef _WIN32
			ExitWindowsEx(EWX_POWEROFF|EWX_FORCEIFHUNG, SHTDN_REASON_MAJOR_APPLICATION|SHTDN_REASON_MINOR_OTHER );
#endif
		}

		std::string r;
		exitpipe->Read(&r, waittime);
		if(r=="exit")
		{
			removeAllClients();
			exitpipe->Write("ok");
			Server->destroy(settings);
			db->destroyAllQueries();
			delete this;
			return;
		}
	}
}

void BackupServer::findClients(FileClient &fc)
{
	db_results res=q_get_extra_hostnames->Read();
	q_get_extra_hostnames->Reset();

	std::vector<in_addr> addr_hints;

	for(size_t i=0;i<res.size();++i)
	{
		unsigned int dest;
		bool b=os_lookuphostname(Server->ConvertToUTF8(res[i][L"hostname"]), &dest);
		if(b)
		{
			q_update_extra_ip->Bind((_i64)dest);
			q_update_extra_ip->Bind(res[i][L"id"]);
			q_update_extra_ip->Write();
			q_update_extra_ip->Reset();

			in_addr tmp;
			tmp.s_addr=dest;
			addr_hints.push_back(tmp);
		}
	}

	_u32 rc=fc.GetServers(true, addr_hints);
	while(rc==ERR_CONTINUE)
	{
		Server->wait(50);
		rc=fc.GetServers(false, addr_hints);
	}

	if(rc==ERR_ERROR)
	{
		Server->Log("Error in BackupServer::findClients rc==ERR_ERROR",LL_ERROR);
	}
}

void BackupServer::startClients(FileClient &fc)
{
	std::vector<std::wstring> names;
	std::vector<sockaddr_in> servers;

	if(!internet_test_mode)
	{
		names=fc.getServerNames();
		servers=fc.getServers();
	}

	std::vector<bool> inetclient;
	inetclient.resize(names.size());
	std::fill(inetclient.begin(), inetclient.end(), false);
	std::vector<std::string> anames=InternetServiceConnector::getOnlineClients();
	for(size_t i=0;i<anames.size();++i)
	{
		names.push_back(Server->ConvertToUnicode(anames[i]));
		inetclient.push_back(true);
		sockaddr_in n;
		memset(&n, 0, sizeof(sockaddr_in));
		servers.push_back(n);
	}

	for(size_t i=0;i<names.size();++i)
	{
		names[i]=Server->ConvertToUnicode(conv_filename(Server->ConvertToUTF8(names[i])));
		std::map<std::wstring, SClient>::iterator it=clients.find(names[i]);
		if( it==clients.end() )
		{
			if(inetclient[i]==true)
			{
				bool skip=false;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[i]==names[j] && inetclient[j]==false)
					{
						skip=true;
						break;
					}
				}
				if(skip)
					continue;
			}

			Server->Log(L"New Backupclient: "+names[i]);
			ServerStatus::setOnline(names[i], true);
			IPipe *np=Server->createMemoryPipe();

			BackupServerGet *client=new BackupServerGet(np, servers[i], names[i], inetclient[i]);
			Server->getThreadPool()->execute(client);

			SClient c;
			c.pipe=np;
			c.offlinecount=0;
			c.addr=servers[i];
			c.internet_connection=inetclient[i];

			ServerStatus::setIP(names[i], c.addr.sin_addr.s_addr);

			clients.insert(std::pair<std::wstring, SClient>(names[i], c) );
		}
		else if(it->second.offlinecount<max_offline)
		{
			bool found_lan=false;
			if(inetclient[i]==false && it->second.internet_connection==true)
			{
				found_lan=true;
			}

			if(it->second.addr.sin_addr.s_addr==servers[i].sin_addr.s_addr && !found_lan)
			{
				it->second.offlinecount=0;
			}
			else
			{
				bool none_fits=true;
				for(size_t j=0;j<names.size();++j)
				{
					if(i!=j && names[j]==names[i] && it->second.addr.sin_addr.s_addr==servers[j].sin_addr.s_addr)
					{
						none_fits=false;
						break;
					}
				}
				if(none_fits || found_lan)
				{
					it->second.addr=servers[i];
					std::string msg;
					msg.resize(7+sizeof(sockaddr_in)+1);
					msg[0]='a'; msg[1]='d'; msg[2]='d'; msg[3]='r'; msg[4]='e'; msg[5]='s'; msg[6]='s';
					memcpy(&msg[7], &it->second.addr, sizeof(sockaddr_in));
					msg[7+sizeof(sockaddr_in)]=(inetclient[i]==true?1:0);
					it->second.pipe->Write(msg);

					char *ip=(char*)&it->second.addr.sin_addr.s_addr;

					Server->Log("New client address: "+nconvert((unsigned char)ip[0])+"."+nconvert((unsigned char)ip[1])+"."+nconvert((unsigned char)ip[2])+"."+nconvert((unsigned char)ip[3]), LL_INFO);

					ServerStatus::setIP(names[i], it->second.addr.sin_addr.s_addr);

					it->second.offlinecount=0;
				}
			}
		}
	}

	bool c=true;
	size_t maxi=0;
	while(c && !clients.empty())
	{
		c=false;

		size_t i_c=0;
		for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
		{
			bool found=false;
			for(size_t i=0;i<names.size();++i)
			{
				if( it->first==names[i] )
				{
					found=true;
					break;
				}
			}
			if( found==false || it->second.offlinecount>max_offline)
			{
				if(it->second.offlinecount==max_offline)
				{
					Server->Log(L"Client exitet: "+it->first);
					it->second.pipe->Write("exit");
					++it->second.offlinecount;
					ServerStatus::setOnline(it->first, false);
				}
				else if(it->second.offlinecount>max_offline)
				{
					std::string msg;
					std::vector<std::string> msgs;
					while(it->second.pipe->Read(&msg,0)>0)
					{
						if(msg!="ok")
						{
							msgs.push_back(msg);
						}
						else
						{
							Server->Log(L"Client finished: "+it->first);
							ServerStatus::setDone(it->first, true);
							Server->destroy(it->second.pipe);
							clients.erase(it);
							maxi=i_c;
							c=true;
							break;
						}
					}
					if( c==false )
					{
						for(size_t i=0;i<msgs.size();++i)
						{
							it->second.pipe->Write(msgs[i]);
						}
					}
					else
					{
						break;
					}
				}
				else if(i_c>=maxi)
				{
					SStatusAction s_action=ServerStatus::getStatus(it->first).statusaction;

					if(s_action==sa_none)
					{
						++it->second.offlinecount;
					}
				}
			}
			++i_c;
		}
	}
}

void BackupServer::removeAllClients(void)
{
	for(std::map<std::wstring, SClient>::iterator it=clients.begin();it!=clients.end();++it)
	{
		it->second.pipe->Write("exitnow");
		std::string msg;
		while(msg!="ok")
		{
			it->second.pipe->Read(&msg);
			it->second.pipe->Write(msg.c_str());
			Server->wait(500);
		}
		Server->destroy(it->second.pipe);
	}
}

IPipeThrottler *BackupServer::getGlobalInternetThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_internet_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_internet_throttler==NULL)
	{
		global_internet_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_internet_throttler->changeThrottleLimit(speed_bps);
	}
	return global_internet_throttler;
}

IPipeThrottler *BackupServer::getGlobalLocalThrottler(size_t speed_bps)
{
	IScopedLock lock(throttle_mutex);

	if(global_local_throttler==NULL && speed_bps==0 )
		return NULL;

	if(global_local_throttler==NULL)
	{
		global_local_throttler=Server->createPipeThrottler(speed_bps);
	}
	else
	{
		global_local_throttler->changeThrottleLimit(speed_bps);
	}
	return global_local_throttler;
}

void BackupServer::cleanupThrottlers(void)
{
	if(global_internet_throttler!=NULL)
	{
		Server->destroy(global_internet_throttler);
	}
	if(global_local_throttler!=NULL)
	{
		Server->destroy(global_local_throttler);
	}
}

#endif //CLIENT_ONLY
<|endoftext|>


<commit_before>//===-- OptionValueFileSpec.cpp ---------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/lldb-python.h"

#include "lldb/Interpreter/OptionValueFileSpec.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/State.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"

using namespace lldb;
using namespace lldb_private;

OptionValueFileSpec::OptionValueFileSpec () :
    OptionValue(),
    m_current_value (),
    m_default_value (),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value) :
    OptionValue(),
    m_current_value (value),
    m_default_value (value),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

OptionValueFileSpec::OptionValueFileSpec (const FileSpec &current_value,
                                          const FileSpec &default_value) :
    OptionValue(),
    m_current_value (current_value),
    m_default_value (default_value),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

void
OptionValueFileSpec::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
{
    if (dump_mask & eDumpOptionType)
        strm.Printf ("(%s)", GetTypeAsCString ());
    if (dump_mask & eDumpOptionValue)
    {
        if (dump_mask & eDumpOptionType)
            strm.PutCString (" = ");

        if (m_current_value)
        {
            strm << '"' << m_current_value.GetPath().c_str() << '"';
        }
    }
}

Error
OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
                                          VarSetOperationType op)
{
    Error error;
    switch (op)
    {
    case eVarSetOperationClear:
        Clear ();
        break;

    case eVarSetOperationReplace:
    case eVarSetOperationAssign:
        if (value_cstr && value_cstr[0])
        {
            m_value_was_set = true;
            m_current_value.SetFile(value_cstr, true);
        }
        else
        {
            error.SetErrorString("invalid value string");
        }
        break;

    case eVarSetOperationInsertBefore:
    case eVarSetOperationInsertAfter:
    case eVarSetOperationRemove:
    case eVarSetOperationAppend:
    case eVarSetOperationInvalid:
        error = OptionValue::SetValueFromCString (value_cstr, op);
        break;
    }
    return error;
}

lldb::OptionValueSP
OptionValueFileSpec::DeepCopy () const
{
    return OptionValueSP(new OptionValueFileSpec(*this));
}

size_t
OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter,
                                   const char *s,
                                   int match_start_point,
                                   int max_return_elements,
                                   bool &word_complete,
                                   StringList &matches)
{
    word_complete = false;
    matches.Clear();
    CommandCompletions::InvokeCommonCompletionCallbacks (interpreter,
                                                         m_completion_mask,
                                                         s,
                                                         match_start_point,
                                                         max_return_elements,
                                                         NULL,
                                                         word_complete,
                                                         matches);
    return matches.GetSize();
}

const lldb::DataBufferSP &
OptionValueFileSpec::GetFileContents(bool null_terminate)
{
    if (!m_data_sp && m_current_value)
    {
        if (null_terminate)
            m_data_sp = m_current_value.ReadFileContentsAsCString();
        else
            m_data_sp = m_current_value.ReadFileContents();
    }
    return m_data_sp;
}

<commit_msg>Change OptionValueFileSpec::SetValueFromCString to strip off whitespace, single-quote and double-quotemarks from around file paths specified to settings like target.expr-prefix or target.process.python-os-plugin-path. <rdar://problem/14970457> <commit_after>//===-- OptionValueFileSpec.cpp ---------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/lldb-python.h"

#include "lldb/Interpreter/OptionValueFileSpec.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/State.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandCompletions.h"

using namespace lldb;
using namespace lldb_private;

OptionValueFileSpec::OptionValueFileSpec () :
    OptionValue(),
    m_current_value (),
    m_default_value (),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value) :
    OptionValue(),
    m_current_value (value),
    m_default_value (value),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

OptionValueFileSpec::OptionValueFileSpec (const FileSpec &current_value,
                                          const FileSpec &default_value) :
    OptionValue(),
    m_current_value (current_value),
    m_default_value (default_value),
    m_data_sp(),
    m_completion_mask (CommandCompletions::eDiskFileCompletion)
{
}

void
OptionValueFileSpec::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
{
    if (dump_mask & eDumpOptionType)
        strm.Printf ("(%s)", GetTypeAsCString ());
    if (dump_mask & eDumpOptionValue)
    {
        if (dump_mask & eDumpOptionType)
            strm.PutCString (" = ");

        if (m_current_value)
        {
            strm << '"' << m_current_value.GetPath().c_str() << '"';
        }
    }
}

Error
OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
                                          VarSetOperationType op)
{
    Error error;
    switch (op)
    {
    case eVarSetOperationClear:
        Clear ();
        break;

    case eVarSetOperationReplace:
    case eVarSetOperationAssign:
        if (value_cstr && value_cstr[0])
        {
            // The setting value may have whitespace, double-quotes, or single-quotes around the file
            // path to indicate that internal spaces are not word breaks.  Strip off any ws & quotes
            // from the start and end of the file path - we aren't doing any word // breaking here so
            // the quoting is unnecessary.  NB this will cause a problem if someone tries to specify
            // a file path that legitimately begins or ends with a " or ' character, or whitespace.
            std::string filepath(value_cstr);
            auto prefix_chars_to_trim = filepath.find_first_not_of ("\"' \t");
            if (prefix_chars_to_trim != std::string::npos && prefix_chars_to_trim > 0)
                filepath.erase(0, prefix_chars_to_trim);
            auto suffix_chars_to_trim = filepath.find_last_not_of ("\"' \t");
            if (suffix_chars_to_trim != std::string::npos && suffix_chars_to_trim < filepath.size())
                filepath.erase (suffix_chars_to_trim + 1);

            m_value_was_set = true;
            m_current_value.SetFile(filepath.c_str(), true);
        }
        else
        {
            error.SetErrorString("invalid value string");
        }
        break;

    case eVarSetOperationInsertBefore:
    case eVarSetOperationInsertAfter:
    case eVarSetOperationRemove:
    case eVarSetOperationAppend:
    case eVarSetOperationInvalid:
        error = OptionValue::SetValueFromCString (value_cstr, op);
        break;
    }
    return error;
}

lldb::OptionValueSP
OptionValueFileSpec::DeepCopy () const
{
    return OptionValueSP(new OptionValueFileSpec(*this));
}

size_t
OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter,
                                   const char *s,
                                   int match_start_point,
                                   int max_return_elements,
                                   bool &word_complete,
                                   StringList &matches)
{
    word_complete = false;
    matches.Clear();
    CommandCompletions::InvokeCommonCompletionCallbacks (interpreter,
                                                         m_completion_mask,
                                                         s,
                                                         match_start_point,
                                                         max_return_elements,
                                                         NULL,
                                                         word_complete,
                                                         matches);
    return matches.GetSize();
}

const lldb::DataBufferSP &
OptionValueFileSpec::GetFileContents(bool null_terminate)
{
    if (!m_data_sp && m_current_value)
    {
        if (null_terminate)
            m_data_sp = m_current_value.ReadFileContentsAsCString();
        else
            m_data_sp = m_current_value.ReadFileContents();
    }
    return m_data_sp;
}

<|endoftext|>


<commit_before>//===- DAGISelEmitter.cpp - Generate an instruction selector --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a DAG instruction selector.
//
//===----------------------------------------------------------------------===//

#include "CodeGenDAGPatterns.h"
#include "DAGISelMatcher.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;

namespace {
/// DAGISelEmitter - The top-level class which coordinates construction
/// and emission of the instruction selector.
class DAGISelEmitter {
  CodeGenDAGPatterns CGP;
public:
  explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {}
  void run(raw_ostream &OS);
};
} // End anonymous namespace

//===----------------------------------------------------------------------===//
// DAGISelEmitter Helper methods
//

/// getResultPatternCost - Compute the number of instructions for this pattern.
/// This is a temporary hack.  We should really include the instruction
/// latencies in this calculation.
static unsigned getResultPatternCost(TreePatternNode *P,
                                     CodeGenDAGPatterns &CGP) {
  if (P->isLeaf()) return 0;

  unsigned Cost = 0;
  Record *Op = P->getOperator();
  if (Op->isSubClassOf("Instruction")) {
    Cost++;
    CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
    if (II.usesCustomInserter)
      Cost += 10;
  }
  for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
    Cost += getResultPatternCost(P->getChild(i), CGP);
  return Cost;
}

/// getResultPatternCodeSize - Compute the code size of instructions for this
/// pattern.
static unsigned getResultPatternSize(TreePatternNode *P,
                                     CodeGenDAGPatterns &CGP) {
  if (P->isLeaf()) return 0;

  unsigned Cost = 0;
  Record *Op = P->getOperator();
  if (Op->isSubClassOf("Instruction")) {
    Cost += Op->getValueAsInt("CodeSize");
  }
  for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
    Cost += getResultPatternSize(P->getChild(i), CGP);
  return Cost;
}

namespace {
// PatternSortingPredicate - return true if we prefer to match LHS before RHS.
// In particular, we want to match maximal patterns first and lowest cost within
// a particular complexity first.
struct PatternSortingPredicate {
  PatternSortingPredicate(CodeGenDAGPatterns &cgp) : CGP(cgp) {}
  CodeGenDAGPatterns &CGP;

  bool operator()(const PatternToMatch *LHS, const PatternToMatch *RHS) {
    const TreePatternNode *LHSSrc = LHS->getSrcPattern();
    const TreePatternNode *RHSSrc = RHS->getSrcPattern();

    if (LHSSrc->getNumTypes() != 0 && RHSSrc->getNumTypes() != 0 &&
        LHSSrc->getType(0) != RHSSrc->getType(0)) {
      MVT::SimpleValueType V1 = LHSSrc->getType(0), V2 = RHSSrc->getType(0);
      if (MVT(V1).isVector() != MVT(V2).isVector())
        return MVT(V2).isVector();

      if (MVT(V1).isFloatingPoint() != MVT(V2).isFloatingPoint())
        return MVT(V2).isFloatingPoint();
    }

    // Otherwise, if the patterns might both match, sort based on complexity,
    // which means that we prefer to match patterns that cover more nodes in the
    // input over nodes that cover fewer.
    unsigned LHSSize = LHS->getPatternComplexity(CGP);
    unsigned RHSSize = RHS->getPatternComplexity(CGP);
    if (LHSSize > RHSSize) return true;   // LHS -> bigger -> less cost
    if (LHSSize < RHSSize) return false;

    // If the patterns have equal complexity, compare generated instruction cost
    unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), CGP);
    unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP);
    if (LHSCost < RHSCost) return true;
    if (LHSCost > RHSCost) return false;

    unsigned LHSPatSize = getResultPatternSize(LHS->getDstPattern(), CGP);
    unsigned RHSPatSize = getResultPatternSize(RHS->getDstPattern(), CGP);
    if (LHSPatSize < RHSPatSize) return true;
    if (LHSPatSize > RHSPatSize) return false;

    // Sort based on the UID of the pattern, giving us a deterministic ordering
    // if all other sorting conditions fail.
    assert(LHS == RHS || LHS->ID != RHS->ID);
    return LHS->ID < RHS->ID;
  }
};
} // End anonymous namespace

void DAGISelEmitter::run(raw_ostream &OS) {
  emitSourceFileHeader("DAG Instruction Selector for the " +
                       CGP.getTargetInfo().getName() + " target", OS);

  OS << "// *** NOTE: This file is #included into the middle of the target\n"
     << "// *** instruction selector class.  These functions are really "
     << "methods.\n\n";

  DEBUG(errs() << "\n\nALL PATTERNS TO MATCH:\n\n";
        for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(),
             E = CGP.ptm_end(); I != E; ++I) {
          errs() << "PATTERN: ";   I->getSrcPattern()->dump();
          errs() << "\nRESULT:  "; I->getDstPattern()->dump();
          errs() << "\n";
        });

  // Add all the patterns to a temporary list so we can sort them.
  std::vector<const PatternToMatch*> Patterns;
  for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end();
       I != E; ++I)
    Patterns.push_back(&*I);

  // We want to process the matches in order of minimal cost.  Sort the patterns
  // so the least cost one is at the start.
  std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate(CGP));

  // Convert each variant of each pattern into a Matcher.
  std::vector<Matcher*> PatternMatchers;
  for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
    for (unsigned Variant = 0; ; ++Variant) {
      if (Matcher *M = ConvertPatternToMatcher(*Patterns[i], Variant, CGP))
        PatternMatchers.push_back(M);
      else
        break;
    }
  }

  Matcher *TheMatcher = new ScopeMatcher(&PatternMatchers[0],
                                         PatternMatchers.size());

  TheMatcher = OptimizeMatcher(TheMatcher, CGP);
  //Matcher->dump();
  EmitMatcherTable(TheMatcher, CGP, OS);
  delete TheMatcher;
}

namespace llvm {

void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {
  DAGISelEmitter(RK).run(OS);
}

} // End llvm namespace
<commit_msg>Fix pattern sort in DAGISelEmitter.cpp<commit_after>//===- DAGISelEmitter.cpp - Generate an instruction selector --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a DAG instruction selector.
//
//===----------------------------------------------------------------------===//

#include "CodeGenDAGPatterns.h"
#include "DAGISelMatcher.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace llvm;

namespace {
/// DAGISelEmitter - The top-level class which coordinates construction
/// and emission of the instruction selector.
class DAGISelEmitter {
  CodeGenDAGPatterns CGP;
public:
  explicit DAGISelEmitter(RecordKeeper &R) : CGP(R) {}
  void run(raw_ostream &OS);
};
} // End anonymous namespace

//===----------------------------------------------------------------------===//
// DAGISelEmitter Helper methods
//

/// getResultPatternCost - Compute the number of instructions for this pattern.
/// This is a temporary hack.  We should really include the instruction
/// latencies in this calculation.
static unsigned getResultPatternCost(TreePatternNode *P,
                                     CodeGenDAGPatterns &CGP) {
  if (P->isLeaf()) return 0;

  unsigned Cost = 0;
  Record *Op = P->getOperator();
  if (Op->isSubClassOf("Instruction")) {
    Cost++;
    CodeGenInstruction &II = CGP.getTargetInfo().getInstruction(Op);
    if (II.usesCustomInserter)
      Cost += 10;
  }
  for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
    Cost += getResultPatternCost(P->getChild(i), CGP);
  return Cost;
}

/// getResultPatternCodeSize - Compute the code size of instructions for this
/// pattern.
static unsigned getResultPatternSize(TreePatternNode *P,
                                     CodeGenDAGPatterns &CGP) {
  if (P->isLeaf()) return 0;

  unsigned Cost = 0;
  Record *Op = P->getOperator();
  if (Op->isSubClassOf("Instruction")) {
    Cost += Op->getValueAsInt("CodeSize");
  }
  for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i)
    Cost += getResultPatternSize(P->getChild(i), CGP);
  return Cost;
}

namespace {
// PatternSortingPredicate - return true if we prefer to match LHS before RHS.
// In particular, we want to match maximal patterns first and lowest cost within
// a particular complexity first.
struct PatternSortingPredicate {
  PatternSortingPredicate(CodeGenDAGPatterns &cgp) : CGP(cgp) {}
  CodeGenDAGPatterns &CGP;

  bool operator()(const PatternToMatch *LHS, const PatternToMatch *RHS) {
    const TreePatternNode *LHSSrc = LHS->getSrcPattern();
    const TreePatternNode *RHSSrc = RHS->getSrcPattern();

    MVT LHSVT = (LHSSrc->getNumTypes() != 0 ? LHSSrc->getType(0) : MVT::Other);
    MVT RHSVT = (RHSSrc->getNumTypes() != 0 ? RHSSrc->getType(0) : MVT::Other);
    if (LHSVT.isVector() != RHSVT.isVector())
      return RHSVT.isVector();

    if (LHSVT.isFloatingPoint() != RHSVT.isFloatingPoint())
      return RHSVT.isFloatingPoint();

    // Otherwise, if the patterns might both match, sort based on complexity,
    // which means that we prefer to match patterns that cover more nodes in the
    // input over nodes that cover fewer.
    unsigned LHSSize = LHS->getPatternComplexity(CGP);
    unsigned RHSSize = RHS->getPatternComplexity(CGP);
    if (LHSSize > RHSSize) return true;   // LHS -> bigger -> less cost
    if (LHSSize < RHSSize) return false;

    // If the patterns have equal complexity, compare generated instruction cost
    unsigned LHSCost = getResultPatternCost(LHS->getDstPattern(), CGP);
    unsigned RHSCost = getResultPatternCost(RHS->getDstPattern(), CGP);
    if (LHSCost < RHSCost) return true;
    if (LHSCost > RHSCost) return false;

    unsigned LHSPatSize = getResultPatternSize(LHS->getDstPattern(), CGP);
    unsigned RHSPatSize = getResultPatternSize(RHS->getDstPattern(), CGP);
    if (LHSPatSize < RHSPatSize) return true;
    if (LHSPatSize > RHSPatSize) return false;

    // Sort based on the UID of the pattern, giving us a deterministic ordering
    // if all other sorting conditions fail.
    assert(LHS == RHS || LHS->ID != RHS->ID);
    return LHS->ID < RHS->ID;
  }
};
} // End anonymous namespace

void DAGISelEmitter::run(raw_ostream &OS) {
  emitSourceFileHeader("DAG Instruction Selector for the " +
                       CGP.getTargetInfo().getName() + " target", OS);

  OS << "// *** NOTE: This file is #included into the middle of the target\n"
     << "// *** instruction selector class.  These functions are really "
     << "methods.\n\n";

  DEBUG(errs() << "\n\nALL PATTERNS TO MATCH:\n\n";
        for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(),
             E = CGP.ptm_end(); I != E; ++I) {
          errs() << "PATTERN: ";   I->getSrcPattern()->dump();
          errs() << "\nRESULT:  "; I->getDstPattern()->dump();
          errs() << "\n";
        });

  // Add all the patterns to a temporary list so we can sort them.
  std::vector<const PatternToMatch*> Patterns;
  for (CodeGenDAGPatterns::ptm_iterator I = CGP.ptm_begin(), E = CGP.ptm_end();
       I != E; ++I)
    Patterns.push_back(&*I);

  // We want to process the matches in order of minimal cost.  Sort the patterns
  // so the least cost one is at the start.
  std::sort(Patterns.begin(), Patterns.end(), PatternSortingPredicate(CGP));

  // Convert each variant of each pattern into a Matcher.
  std::vector<Matcher*> PatternMatchers;
  for (unsigned i = 0, e = Patterns.size(); i != e; ++i) {
    for (unsigned Variant = 0; ; ++Variant) {
      if (Matcher *M = ConvertPatternToMatcher(*Patterns[i], Variant, CGP))
        PatternMatchers.push_back(M);
      else
        break;
    }
  }

  Matcher *TheMatcher = new ScopeMatcher(&PatternMatchers[0],
                                         PatternMatchers.size());

  TheMatcher = OptimizeMatcher(TheMatcher, CGP);
  //Matcher->dump();
  EmitMatcherTable(TheMatcher, CGP, OS);
  delete TheMatcher;
}

namespace llvm {

void EmitDAGISel(RecordKeeper &RK, raw_ostream &OS) {
  DAGISelEmitter(RK).run(OS);
}

} // End llvm namespace
<|endoftext|>


<commit_before>#include "girl_x.h"
#include "lua_var_scope.h"
#include "../table/table.h"

namespace saki
{

GirlX::GirlX(Who who, std::string luaCode)
    : Girl(who, Girl::Id::CUSTOM)
{
    setupLuaGlobal();

    runInGirlEnv(luaCode);
}

GirlX::GirlX(const GirlX &copy)
    : Girl(copy)
{
    // TODO
    // support cloning Lua state to enable skills inside future vision
    // strategy:
    // - Copy everything reachable from the 'girldata' table
    // - Ignore metatables
    //     - Userdata metatables are generated by fixed steps
    // - Ignore coroutines
    // - Deep copy all GC object
    // - Smartize Objects whose lifetime managed by C++
    // - Copy C functions (i.e. pointers), deep copy their upvalues
    // - Copy Lua functions by lua_dump, deep copy their upvalues
    // - Type-switch userdatas, use C++ copy ctor to copy them
    // deep copy should detect cycle

//    setupLuaGlobal();
//    cloneLuaTable(mLua["girldata"], const_cast<GirlX &>(copy).mLua["girldata"]);
}

std::unique_ptr<Girl> GirlX::clone() const
{
    return std::make_unique<GirlX>(*this);
}

void GirlX::onDraw(const Table &table, Mount &mount, Who who, bool rinshan)
{
    sol::object cb = mGirlEnv["ondraw"];
    if (!cb.is<sol::function>())
        return;

    LuaVarScope scope(
        mGirlEnv,
        "game", &table,
        "mount", &mount,
        "who", who,
        "rinshan", rinshan
    );

    (void) scope;

    runInGirlEnv("ondraw()");
    popUpIfAny(table);
}

std::string GirlX::popUpStr() const
{
    std::ostringstream oss;
    oss << "Lua";
    oss << mErrStream.str();
    return oss.str();
}

void GirlX::onTableEvent(const Table &table, const TableEvent &event)
{
    if (event.type() == TableEvent::Type::TABLE_STARTED)
        popUpIfAny(table);
}

void GirlX::setupLuaGlobal()
{
    mLua.open_libraries();

    mLua.script(R"(
        girldata = {}
        girl = {
            math = math,
            table = table,
            string = string,
            pairs = pairs,
            ipairs = ipairs,
            print = function(...)
                for _, v in ipairs({...}) do
                    girl.printone(v)
                    girl.printone(" ")
                end
                girl.printone("\n")
            end,
            __index = function(t, k)
                return girldata[k]
            end,
            __newindex = function(t, k, v)
                girldata[k] = v
            end
        }
        girl.math.random = nil
        girl.math.randomseed = nil
    )");

    mGirlEnv = mLua["girl"];

    setupLuaClasses();
    mGirlEnv["self"] = mSelf;
    mGirlEnv["printone"] = [this](sol::reference ref) {
        std::string str = mLua["tostring"](ref);
        mErrStream << str;
    };

    mGirlEnv[sol::metatable_key] = mGirlEnv;
}

void GirlX::setupLuaClasses()
{
    setupLuaTile();
    setupLuaWho();
    setupLuaMeld();
    setupLuaMount();
    setupLuaTileCount();
    setupLuaHand();
    setupLuaGame();
}

void GirlX::setupLuaTile()
{
    mGirlEnv.new_enum<Suit>(
        "Suit", {
            { "M", Suit::M },
            { "P", Suit::P },
            { "S", Suit::S },
            { "F", Suit::F },
            { "Y", Suit::Y }
        }
    );

    mGirlEnv.new_usertype<T34>(
        "T34",
        sol::meta_function::construct, sol::factories(
            [this](int ti) {
                if (ti < 0 || ti >= 34) {
                    mLua["error"]("invalid T34 id");
                    return T34();
                }

                return T34(ti);
            },
            [this](Suit s, int v) {
                if (!(1 <= v && v <= 9)) {
                    mLua["error"]("invalid T34 val");
                    return T34();
                }

                return T34(s, v);
            },
            [this](const std::string s) {
                static const std::array<std::string, 34> dict {
                    "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m",
                    "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p",
                    "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
                    "1f", "2f", "3f", "4f", "1y", "2y", "3y"
                };

                auto it = std::find(dict.begin(), dict.end(), s);
                if (it == dict.end()) {
                    mLua["error"]("invalid T34 string");
                    return T34();
                }

                return T34(it - dict.begin());
            }
        ),
        "id34", &T34::id34,
        "isyakuhai", &T34::isYakuhai,
        sol::meta_function::to_string, &T34::str,
        "all", sol::var(std::vector<T34>(tiles34::ALL34.begin(), tiles34::ALL34.end()))
    );
}

void GirlX::setupLuaWho()
{
    mGirlEnv.new_usertype<Who>(
        "Who",
        "right", &Who::right,
        "cross", &Who::cross,
        "left", &Who::left,
        sol::meta_function::to_string, &Who::index,
        sol::meta_function::equal_to, &Who::operator==
    );
}

void GirlX::setupLuaMeld()
{
    mGirlEnv.new_usertype<M37>(
        "M37",
        "type", &M37::type,
        sol::meta_function::index, &M37::operator[]
    );

    sol::table m37 = mGirlEnv["M37"];
    m37.new_enum<M37::Type>(
        "Type", {
            { "CHII", M37::Type::CHII },
            { "PON", M37::Type::PON },
            { "DAIMINKAN", M37::Type::DAIMINKAN },
            { "ANKAN", M37::Type::ANKAN },
            { "KAKAN", M37::Type::KAKAN }
        }
    );
}

void GirlX::setupLuaMount()
{
    mGirlEnv.new_usertype<Mount>(
        "Mount",
        "lighta", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightA(t, mk);
            }
        )
    );
}

void GirlX::setupLuaTileCount()
{
    mGirlEnv.new_usertype<TileCount>(
        "Tilecount",
        "ct", sol::overload(
            [](const TileCount &tc, T34 t) {
                return tc.ct(t);
            },
            [](const TileCount &tc, Suit s) {
                return tc.ct(s);
            }
        )
    );
}

void GirlX::setupLuaHand()
{
    mGirlEnv.new_usertype<Hand>(
        "Hand",
        "closed", &Hand::closed,
        "ct", &Hand::ct,
        "ready", &Hand::ready,
        "step", &Hand::step,
        "step4", &Hand::step4,
        "step7", &Hand::step7,
        "step13", &Hand::step13,
        "effa", &Hand::effA,
        "effa4", &Hand::effA4,
        "ismenzen", &Hand::isMenzen,
        "barks", &Hand::barks
    );
}

void GirlX::setupLuaGame()
{
    mGirlEnv.new_usertype<Table>(
        "Game",
        "gethand", &Table::getHand,
        "getround", &Table::getRound,
        "getextraround", &Table::getExtraRound,
        "getdealer", &Table::getDealer,
        "getselfwind", &Table::getSelfWind,
        "getroundwind", &Table::getRoundWind
    );
}

void GirlX::addError(const char *what)
{
    mErrStream << what << '\n';
}

void GirlX::runInGirlEnv(const std::string_view &code)
{
    try {
        mLua.safe_script(code, mGirlEnv);
    } catch (const sol::error &e) {
        addError(e.what());
    }
}

void GirlX::popUpIfAny(const Table &table)
{
    if (mErrStream.tellp() > 0) {
        table.popUp(mSelf);
        mErrStream.str("");
    }
}

} // namespace saki
<commit_msg>fix nil-ignored in lua print func<commit_after>#include "girl_x.h"
#include "lua_var_scope.h"
#include "../table/table.h"

namespace saki
{

GirlX::GirlX(Who who, std::string luaCode)
    : Girl(who, Girl::Id::CUSTOM)
{
    setupLuaGlobal();

    runInGirlEnv(luaCode);
}

GirlX::GirlX(const GirlX &copy)
    : Girl(copy)
{
    // TODO
    // support cloning Lua state to enable skills inside future vision
    // strategy:
    // - Copy everything reachable from the 'girldata' table
    // - Ignore metatables
    //     - Userdata metatables are generated by fixed steps
    // - Ignore coroutines
    // - Deep copy all GC object
    // - Smartize Objects whose lifetime managed by C++
    // - Copy C functions (i.e. pointers), deep copy their upvalues
    // - Copy Lua functions by lua_dump, deep copy their upvalues
    // - Type-switch userdatas, use C++ copy ctor to copy them
    // deep copy should detect cycle

//    setupLuaGlobal();
//    cloneLuaTable(mLua["girldata"], const_cast<GirlX &>(copy).mLua["girldata"]);
}

std::unique_ptr<Girl> GirlX::clone() const
{
    return std::make_unique<GirlX>(*this);
}

void GirlX::onDraw(const Table &table, Mount &mount, Who who, bool rinshan)
{
    sol::object cb = mGirlEnv["ondraw"];
    if (!cb.is<sol::function>())
        return;

    LuaVarScope scope(
        mGirlEnv,
        "game", &table,
        "mount", &mount,
        "who", who,
        "rinshan", rinshan
    );

    (void) scope;

    runInGirlEnv("ondraw()");
    popUpIfAny(table);
}

std::string GirlX::popUpStr() const
{
    std::ostringstream oss;
    oss << "Lua";
    oss << mErrStream.str();
    return oss.str();
}

void GirlX::onTableEvent(const Table &table, const TableEvent &event)
{
    if (event.type() == TableEvent::Type::TABLE_STARTED)
        popUpIfAny(table);
}

void GirlX::setupLuaGlobal()
{
    mLua.open_libraries();

    mLua.script(R"(
        girldata = {}
        girl = {
            math = math,
            table = table,
            string = string,
            pairs = pairs,
            ipairs = ipairs,
            print = function(...)
                local args = table.pack(...)
                for i = 1, args.n do
                    girl.printone(args[i])
                    girl.printone(" ")
                end
                girl.printone("\n")
            end,
            __index = function(t, k)
                return girldata[k]
            end,
            __newindex = function(t, k, v)
                girldata[k] = v
            end
        }
        girl.math.random = nil
        girl.math.randomseed = nil
    )");

    mGirlEnv = mLua["girl"];

    setupLuaClasses();
    mGirlEnv["self"] = mSelf;
    mGirlEnv["printone"] = [this](sol::reference ref) {
        std::string str = mLua["tostring"](ref);
        mErrStream << str;
    };

    mGirlEnv[sol::metatable_key] = mGirlEnv;
}

void GirlX::setupLuaClasses()
{
    setupLuaTile();
    setupLuaWho();
    setupLuaMeld();
    setupLuaMount();
    setupLuaTileCount();
    setupLuaHand();
    setupLuaGame();
}

void GirlX::setupLuaTile()
{
    mGirlEnv.new_enum<Suit>(
        "Suit", {
            { "M", Suit::M },
            { "P", Suit::P },
            { "S", Suit::S },
            { "F", Suit::F },
            { "Y", Suit::Y }
        }
    );

    mGirlEnv.new_usertype<T34>(
        "T34",
        sol::meta_function::construct, sol::factories(
            [this](int ti) {
                if (ti < 0 || ti >= 34) {
                    mLua["error"]("invalid T34 id");
                    return T34();
                }

                return T34(ti);
            },
            [this](Suit s, int v) {
                if (!(1 <= v && v <= 9)) {
                    mLua["error"]("invalid T34 val");
                    return T34();
                }

                return T34(s, v);
            },
            [this](const std::string s) {
                static const std::array<std::string, 34> dict {
                    "1m", "2m", "3m", "4m", "5m", "6m", "7m", "8m", "9m",
                    "1p", "2p", "3p", "4p", "5p", "6p", "7p", "8p", "9p",
                    "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s", "9s",
                    "1f", "2f", "3f", "4f", "1y", "2y", "3y"
                };

                auto it = std::find(dict.begin(), dict.end(), s);
                if (it == dict.end()) {
                    mLua["error"]("invalid T34 string");
                    return T34();
                }

                return T34(it - dict.begin());
            }
        ),
        "id34", &T34::id34,
        "isyakuhai", &T34::isYakuhai,
        sol::meta_function::to_string, &T34::str,
        "all", sol::var(std::vector<T34>(tiles34::ALL34.begin(), tiles34::ALL34.end()))
    );
}

void GirlX::setupLuaWho()
{
    mGirlEnv.new_usertype<Who>(
        "Who",
        "right", &Who::right,
        "cross", &Who::cross,
        "left", &Who::left,
        sol::meta_function::to_string, &Who::index,
        sol::meta_function::equal_to, &Who::operator==
    );
}

void GirlX::setupLuaMeld()
{
    mGirlEnv.new_usertype<M37>(
        "M37",
        "type", &M37::type,
        sol::meta_function::index, &M37::operator[]
    );

    sol::table m37 = mGirlEnv["M37"];
    m37.new_enum<M37::Type>(
        "Type", {
            { "CHII", M37::Type::CHII },
            { "PON", M37::Type::PON },
            { "DAIMINKAN", M37::Type::DAIMINKAN },
            { "ANKAN", M37::Type::ANKAN },
            { "KAKAN", M37::Type::KAKAN }
        }
    );
}

void GirlX::setupLuaMount()
{
    mGirlEnv.new_usertype<Mount>(
        "Mount",
        "lighta", sol::overload(
            [](Mount &mount, T34 t, int mk, bool rin) {
                mount.lightA(t, mk, rin);
            },
            [](Mount &mount, T34 t, int mk) {
                mount.lightA(t, mk);
            }
        )
    );
}

void GirlX::setupLuaTileCount()
{
    mGirlEnv.new_usertype<TileCount>(
        "Tilecount",
        "ct", sol::overload(
            [](const TileCount &tc, T34 t) {
                return tc.ct(t);
            },
            [](const TileCount &tc, Suit s) {
                return tc.ct(s);
            }
        )
    );
}

void GirlX::setupLuaHand()
{
    mGirlEnv.new_usertype<Hand>(
        "Hand",
        "closed", &Hand::closed,
        "ct", &Hand::ct,
        "ready", &Hand::ready,
        "step", &Hand::step,
        "step4", &Hand::step4,
        "step7", &Hand::step7,
        "step13", &Hand::step13,
        "effa", &Hand::effA,
        "effa4", &Hand::effA4,
        "ismenzen", &Hand::isMenzen,
        "barks", &Hand::barks
    );
}

void GirlX::setupLuaGame()
{
    mGirlEnv.new_usertype<Table>(
        "Game",
        "gethand", &Table::getHand,
        "getround", &Table::getRound,
        "getextraround", &Table::getExtraRound,
        "getdealer", &Table::getDealer,
        "getselfwind", &Table::getSelfWind,
        "getroundwind", &Table::getRoundWind
    );
}

void GirlX::addError(const char *what)
{
    mErrStream << what << '\n';
}

void GirlX::runInGirlEnv(const std::string_view &code)
{
    try {
        mLua.safe_script(code, mGirlEnv);
    } catch (const sol::error &e) {
        addError(e.what());
    }
}

void GirlX::popUpIfAny(const Table &table)
{
    if (mErrStream.tellp() > 0) {
        table.popUp(mSelf);
        mErrStream.str("");
    }
}

} // namespace saki
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include <com/sun/star/lang/DisposedException.hpp>

#include <vcl/svapp.hxx>

#include <cppuhelper/implbase3.hxx>
#include <cppuhelper/implbase4.hxx>

#include <vector>

using ::rtl::OUString;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::beans;

// -----------------------------------------------------------------------

namespace vcl
{

class DisplayInfo : public ::cppu::WeakAggImplHelper3< XPropertySet, XPropertySetInfo, XServiceInfo >
{
public:
    DisplayInfo( sal_uInt32 nDisplayScreen );

    // XPropertySet
    virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw (RuntimeException);
    virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
    virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);

    // XPropertySetInfo
    virtual Sequence< Property > SAL_CALL getProperties() throw (RuntimeException);
    virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
    virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException);

private:
    sal_uInt32 mnDisplayScreen;
};

static const char* pScreenAreaName = "ScreenArea";
static const char* pWorkAreaName = "WorkArea";
static const char* pScreenName = "ScreenName";

// --------------------------------------------------------------------

DisplayInfo::DisplayInfo( sal_uInt32 nDisplayScreen )
: mnDisplayScreen( nDisplayScreen )
{
}

// XPropertySet
Reference< XPropertySetInfo > SAL_CALL DisplayInfo::getPropertySetInfo() throw (RuntimeException)
{
    return this;
}

void SAL_CALL DisplayInfo::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
    throw PropertyVetoException();
}

Any SAL_CALL DisplayInfo::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
    Rectangle aRect;
    if( PropertyName.equalsAscii( pScreenAreaName ) )
    {
        aRect = Application::GetScreenPosSizePixel( mnDisplayScreen );
    }
    else if( PropertyName.equalsAscii( pWorkAreaName ) )
    {
        aRect = Application::GetWorkAreaPosSizePixel( mnDisplayScreen );
    }
    else if( PropertyName.equalsAscii( pScreenName ) )
    {
        return Any( Application::GetDisplayScreenName( mnDisplayScreen ) );
    }
    else
        throw UnknownPropertyException();

    return Any( com::sun::star::awt::Rectangle( aRect.Left(), aRect.Top(), aRect.getWidth(), aRect.getHeight() ) );
}

void SAL_CALL DisplayInfo::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}

// XPropertySetInfo
Sequence< Property > SAL_CALL DisplayInfo::getProperties() throw (RuntimeException)
{
    Sequence< Property > aProps(2);
    aProps[0] = getPropertyByName( OUString::createFromAscii( pScreenAreaName ) );
    aProps[1] = getPropertyByName( OUString::createFromAscii( pWorkAreaName ) );
    return aProps;
}

Property SAL_CALL DisplayInfo::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
{
    if( aName.equalsAscii( pScreenAreaName ) ||
        aName.equalsAscii( pWorkAreaName ) )
        return Property( aName, 0, ::getCppuType( (::com::sun::star::awt::Rectangle const *)0 ), PropertyAttribute::READONLY );
    throw UnknownPropertyException();
}

::sal_Bool SAL_CALL DisplayInfo::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
{
    return Name.equalsAscii( pScreenAreaName ) ||
           Name.equalsAscii( pWorkAreaName );
}

// XServiceInfo
OUString SAL_CALL DisplayInfo::getImplementationName() throw (RuntimeException)
{
    return OUString(RTL_CONSTASCII_USTRINGPARAM("vcl::DisplayInfo"));
}

::sal_Bool SAL_CALL DisplayInfo::supportsService( const OUString& ServiceName ) throw (RuntimeException)
{
    Sequence< OUString > aSN( getSupportedServiceNames() );
    for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
    {
        if( aSN[nService] == ServiceName )
            return sal_True;
    }
    return sal_False;
}

Sequence< OUString > SAL_CALL DisplayInfo::getSupportedServiceNames() throw (RuntimeException)
{
    OUString aServiceName(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.DisplayInfo"));
    return Sequence< OUString >(&aServiceName, 1);
}

// ====================================================================

class DisplayAccess : public ::cppu::WeakAggImplHelper4< XPropertySet, XPropertySetInfo, XIndexAccess, XServiceInfo >
{
public:
    DisplayAccess ();

    // XPropertySet
    virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw (RuntimeException);
    virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
    virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);

    // XPropertySetInfo
    virtual Sequence< Property > SAL_CALL getProperties() throw (RuntimeException);
    virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
    virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);

    // XIndexAccess
    virtual ::sal_Int32 SAL_CALL getCount() throw (RuntimeException);
    virtual Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException);

    // XElementAccess
    virtual Type SAL_CALL getElementType() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL hasElements() throw (RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException);
};

Sequence< OUString > DisplayAccess_getSupportedServiceNames()
{
    OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) );
    return Sequence< OUString >( &aServiceName, 1 );
}

OUString DisplayAccess_getImplementationName()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( "vcl::DisplayAccess" ) );
}

Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory >&  )
{
    return static_cast< ::cppu::OWeakObject * >( new DisplayAccess );
}

DisplayAccess::DisplayAccess()
{
}

static const char* pUnifiedDisplayName = "IsUnifiedDisplay";
static const char* pDefaultDisplayName = "DefaultDisplay";
static const char* pBuiltInDisplayName = "BuiltInDisplay";
static const char* pExternalDisplayName = "ExternalDisplay";

// XPropertySet
Reference< XPropertySetInfo > SAL_CALL DisplayAccess::getPropertySetInfo() throw (RuntimeException)
{
    return this;
}

void SAL_CALL DisplayAccess::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
    throw PropertyVetoException();
}

Any SAL_CALL DisplayAccess::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
    Any aRet;
    if( PropertyName.equalsAscii( pUnifiedDisplayName ) )
    {
        aRet <<= sal_Bool( Application::IsUnifiedDisplay() );
    }
    else if( PropertyName.equalsAscii( pDefaultDisplayName ) || // Unhelpful name, legacy setting
             PropertyName.equalsAscii( pBuiltInDisplayName ) )
    {
        aRet <<= sal_Int32( Application::GetDisplayBuiltInScreen() );
    }
    else if( PropertyName.equalsAscii( pExternalDisplayName ) )
    {
        // This is really unpleasant, in theory we could have multiple
        // external displays etc.
        sal_Int32 nExternal(0);
        switch (Application::GetDisplayBuiltInScreen())
        {
        case 0:
            nExternal = 1;
            break;
        case 1:
            nExternal = 0;
            break;
        default:
            // When the built-in display is neither 0 nor 1
            // then place the full-screen presentation on the
            // first available screen.
            nExternal = 0;
            break;
        }
        aRet <<= nExternal;
    }
    else
        throw UnknownPropertyException();

    return aRet;
}

void SAL_CALL DisplayAccess::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}

// XPropertySetInfo
Sequence< Property > SAL_CALL DisplayAccess::getProperties() throw (RuntimeException)
{
    Sequence< Property > aProps(4);
    aProps[0] = getPropertyByName( OUString::createFromAscii( pUnifiedDisplayName ) );
    aProps[1] = getPropertyByName( OUString::createFromAscii( pDefaultDisplayName ) );
    aProps[2] = getPropertyByName( OUString::createFromAscii( pBuiltInDisplayName ) );
    aProps[3] = getPropertyByName( OUString::createFromAscii( pExternalDisplayName ) );
    return aProps;
}

Property SAL_CALL DisplayAccess::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
{
    if( aName.equalsAscii( pUnifiedDisplayName ) )
        return Property( aName, 0, ::getCppuType( (sal_Bool const *)0 ), PropertyAttribute::READONLY );

    if( aName.equalsAscii( pDefaultDisplayName ) ||
        aName.equalsAscii( pBuiltInDisplayName ) ||
        aName.equalsAscii( pExternalDisplayName ) )
        return Property( aName, 0, ::getCppuType( (sal_Int32 const *)0 ), PropertyAttribute::READONLY );

    throw UnknownPropertyException();
}

::sal_Bool SAL_CALL DisplayAccess::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
{
    return Name.equalsAscii( pUnifiedDisplayName ) ||
           Name.equalsAscii( pDefaultDisplayName ) ||
           Name.equalsAscii( pBuiltInDisplayName ) ||
           Name.equalsAscii( pExternalDisplayName );
}

// XIndexAccess
::sal_Int32 SAL_CALL DisplayAccess::getCount() throw (RuntimeException)
{
    return Application::GetScreenCount();
}

Any SAL_CALL DisplayAccess::getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
{
    if( (Index < 0) || (Index >= getCount()) )
        throw IndexOutOfBoundsException();

    return makeAny( Reference< XPropertySet >( new DisplayInfo( Index ) ) );
}

// XElementAccess
Type SAL_CALL DisplayAccess::getElementType() throw (RuntimeException)
{
    return XPropertySet::static_type();
}

::sal_Bool SAL_CALL DisplayAccess::hasElements() throw (RuntimeException)
{
    return true;
}

// XServiceInfo
OUString SAL_CALL DisplayAccess::getImplementationName() throw (RuntimeException)
{
    return DisplayAccess_getImplementationName();
}

::sal_Bool SAL_CALL DisplayAccess::supportsService( const OUString& ServiceName ) throw (RuntimeException)
{
    Sequence< OUString > aSN( DisplayAccess_getSupportedServiceNames() );
    for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
    {
        if( aSN[nService] == ServiceName )
            return sal_True;
    }
    return sal_False;
}

Sequence< OUString > SAL_CALL DisplayAccess::getSupportedServiceNames() throw (RuntimeException)
{
    return DisplayAccess_getSupportedServiceNames();
}

} // namespace vcl

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>Drop unused #include<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#include <com/sun/star/container/XIndexAccess.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include <com/sun/star/lang/DisposedException.hpp>

#include <vcl/svapp.hxx>

#include <cppuhelper/implbase3.hxx>
#include <cppuhelper/implbase4.hxx>

using ::rtl::OUString;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::beans;

// -----------------------------------------------------------------------

namespace vcl
{

class DisplayInfo : public ::cppu::WeakAggImplHelper3< XPropertySet, XPropertySetInfo, XServiceInfo >
{
public:
    DisplayInfo( sal_uInt32 nDisplayScreen );

    // XPropertySet
    virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw (RuntimeException);
    virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
    virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);

    // XPropertySetInfo
    virtual Sequence< Property > SAL_CALL getProperties() throw (RuntimeException);
    virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
    virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException);

private:
    sal_uInt32 mnDisplayScreen;
};

static const char* pScreenAreaName = "ScreenArea";
static const char* pWorkAreaName = "WorkArea";
static const char* pScreenName = "ScreenName";

// --------------------------------------------------------------------

DisplayInfo::DisplayInfo( sal_uInt32 nDisplayScreen )
: mnDisplayScreen( nDisplayScreen )
{
}

// XPropertySet
Reference< XPropertySetInfo > SAL_CALL DisplayInfo::getPropertySetInfo() throw (RuntimeException)
{
    return this;
}

void SAL_CALL DisplayInfo::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
    throw PropertyVetoException();
}

Any SAL_CALL DisplayInfo::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
    Rectangle aRect;
    if( PropertyName.equalsAscii( pScreenAreaName ) )
    {
        aRect = Application::GetScreenPosSizePixel( mnDisplayScreen );
    }
    else if( PropertyName.equalsAscii( pWorkAreaName ) )
    {
        aRect = Application::GetWorkAreaPosSizePixel( mnDisplayScreen );
    }
    else if( PropertyName.equalsAscii( pScreenName ) )
    {
        return Any( Application::GetDisplayScreenName( mnDisplayScreen ) );
    }
    else
        throw UnknownPropertyException();

    return Any( com::sun::star::awt::Rectangle( aRect.Left(), aRect.Top(), aRect.getWidth(), aRect.getHeight() ) );
}

void SAL_CALL DisplayInfo::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayInfo::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}

// XPropertySetInfo
Sequence< Property > SAL_CALL DisplayInfo::getProperties() throw (RuntimeException)
{
    Sequence< Property > aProps(2);
    aProps[0] = getPropertyByName( OUString::createFromAscii( pScreenAreaName ) );
    aProps[1] = getPropertyByName( OUString::createFromAscii( pWorkAreaName ) );
    return aProps;
}

Property SAL_CALL DisplayInfo::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
{
    if( aName.equalsAscii( pScreenAreaName ) ||
        aName.equalsAscii( pWorkAreaName ) )
        return Property( aName, 0, ::getCppuType( (::com::sun::star::awt::Rectangle const *)0 ), PropertyAttribute::READONLY );
    throw UnknownPropertyException();
}

::sal_Bool SAL_CALL DisplayInfo::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
{
    return Name.equalsAscii( pScreenAreaName ) ||
           Name.equalsAscii( pWorkAreaName );
}

// XServiceInfo
OUString SAL_CALL DisplayInfo::getImplementationName() throw (RuntimeException)
{
    return OUString(RTL_CONSTASCII_USTRINGPARAM("vcl::DisplayInfo"));
}

::sal_Bool SAL_CALL DisplayInfo::supportsService( const OUString& ServiceName ) throw (RuntimeException)
{
    Sequence< OUString > aSN( getSupportedServiceNames() );
    for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
    {
        if( aSN[nService] == ServiceName )
            return sal_True;
    }
    return sal_False;
}

Sequence< OUString > SAL_CALL DisplayInfo::getSupportedServiceNames() throw (RuntimeException)
{
    OUString aServiceName(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.DisplayInfo"));
    return Sequence< OUString >(&aServiceName, 1);
}

// ====================================================================

class DisplayAccess : public ::cppu::WeakAggImplHelper4< XPropertySet, XPropertySetInfo, XIndexAccess, XServiceInfo >
{
public:
    DisplayAccess ();

    // XPropertySet
    virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() throw (RuntimeException);
    virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
    virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException);

    // XPropertySetInfo
    virtual Sequence< Property > SAL_CALL getProperties() throw (RuntimeException);
    virtual Property SAL_CALL getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException);
    virtual ::sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) throw (RuntimeException);

    // XIndexAccess
    virtual ::sal_Int32 SAL_CALL getCount() throw (RuntimeException);
    virtual Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException);

    // XElementAccess
    virtual Type SAL_CALL getElementType() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL hasElements() throw (RuntimeException);

    // XServiceInfo
    virtual OUString SAL_CALL getImplementationName() throw (RuntimeException);
    virtual ::sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) throw (RuntimeException);
    virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() throw (RuntimeException);
};

Sequence< OUString > DisplayAccess_getSupportedServiceNames()
{
    OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.awt.DisplayAccess" ) );
    return Sequence< OUString >( &aServiceName, 1 );
}

OUString DisplayAccess_getImplementationName()
{
    return OUString( RTL_CONSTASCII_USTRINGPARAM( "vcl::DisplayAccess" ) );
}

Reference< XInterface > SAL_CALL DisplayAccess_createInstance( const Reference< XMultiServiceFactory >&  )
{
    return static_cast< ::cppu::OWeakObject * >( new DisplayAccess );
}

DisplayAccess::DisplayAccess()
{
}

static const char* pUnifiedDisplayName = "IsUnifiedDisplay";
static const char* pDefaultDisplayName = "DefaultDisplay";
static const char* pBuiltInDisplayName = "BuiltInDisplay";
static const char* pExternalDisplayName = "ExternalDisplay";

// XPropertySet
Reference< XPropertySetInfo > SAL_CALL DisplayAccess::getPropertySetInfo() throw (RuntimeException)
{
    return this;
}

void SAL_CALL DisplayAccess::setPropertyValue( const OUString& /*aPropertyName* */, const Any& /*aValue*/ ) throw (UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
{
    throw PropertyVetoException();
}

Any SAL_CALL DisplayAccess::getPropertyValue( const OUString& PropertyName ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException)
{
    Any aRet;
    if( PropertyName.equalsAscii( pUnifiedDisplayName ) )
    {
        aRet <<= sal_Bool( Application::IsUnifiedDisplay() );
    }
    else if( PropertyName.equalsAscii( pDefaultDisplayName ) || // Unhelpful name, legacy setting
             PropertyName.equalsAscii( pBuiltInDisplayName ) )
    {
        aRet <<= sal_Int32( Application::GetDisplayBuiltInScreen() );
    }
    else if( PropertyName.equalsAscii( pExternalDisplayName ) )
    {
        // This is really unpleasant, in theory we could have multiple
        // external displays etc.
        sal_Int32 nExternal(0);
        switch (Application::GetDisplayBuiltInScreen())
        {
        case 0:
            nExternal = 1;
            break;
        case 1:
            nExternal = 0;
            break;
        default:
            // When the built-in display is neither 0 nor 1
            // then place the full-screen presentation on the
            // first available screen.
            nExternal = 0;
            break;
        }
        aRet <<= nExternal;
    }
    else
        throw UnknownPropertyException();

    return aRet;
}

void SAL_CALL DisplayAccess::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}
void SAL_CALL DisplayAccess::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) throw (UnknownPropertyException, WrappedTargetException, RuntimeException) {}

// XPropertySetInfo
Sequence< Property > SAL_CALL DisplayAccess::getProperties() throw (RuntimeException)
{
    Sequence< Property > aProps(4);
    aProps[0] = getPropertyByName( OUString::createFromAscii( pUnifiedDisplayName ) );
    aProps[1] = getPropertyByName( OUString::createFromAscii( pDefaultDisplayName ) );
    aProps[2] = getPropertyByName( OUString::createFromAscii( pBuiltInDisplayName ) );
    aProps[3] = getPropertyByName( OUString::createFromAscii( pExternalDisplayName ) );
    return aProps;
}

Property SAL_CALL DisplayAccess::getPropertyByName( const OUString& aName ) throw (UnknownPropertyException, RuntimeException)
{
    if( aName.equalsAscii( pUnifiedDisplayName ) )
        return Property( aName, 0, ::getCppuType( (sal_Bool const *)0 ), PropertyAttribute::READONLY );

    if( aName.equalsAscii( pDefaultDisplayName ) ||
        aName.equalsAscii( pBuiltInDisplayName ) ||
        aName.equalsAscii( pExternalDisplayName ) )
        return Property( aName, 0, ::getCppuType( (sal_Int32 const *)0 ), PropertyAttribute::READONLY );

    throw UnknownPropertyException();
}

::sal_Bool SAL_CALL DisplayAccess::hasPropertyByName( const OUString& Name ) throw (RuntimeException)
{
    return Name.equalsAscii( pUnifiedDisplayName ) ||
           Name.equalsAscii( pDefaultDisplayName ) ||
           Name.equalsAscii( pBuiltInDisplayName ) ||
           Name.equalsAscii( pExternalDisplayName );
}

// XIndexAccess
::sal_Int32 SAL_CALL DisplayAccess::getCount() throw (RuntimeException)
{
    return Application::GetScreenCount();
}

Any SAL_CALL DisplayAccess::getByIndex( ::sal_Int32 Index ) throw (IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
{
    if( (Index < 0) || (Index >= getCount()) )
        throw IndexOutOfBoundsException();

    return makeAny( Reference< XPropertySet >( new DisplayInfo( Index ) ) );
}

// XElementAccess
Type SAL_CALL DisplayAccess::getElementType() throw (RuntimeException)
{
    return XPropertySet::static_type();
}

::sal_Bool SAL_CALL DisplayAccess::hasElements() throw (RuntimeException)
{
    return true;
}

// XServiceInfo
OUString SAL_CALL DisplayAccess::getImplementationName() throw (RuntimeException)
{
    return DisplayAccess_getImplementationName();
}

::sal_Bool SAL_CALL DisplayAccess::supportsService( const OUString& ServiceName ) throw (RuntimeException)
{
    Sequence< OUString > aSN( DisplayAccess_getSupportedServiceNames() );
    for( sal_Int32 nService = 0; nService < aSN.getLength(); nService++ )
    {
        if( aSN[nService] == ServiceName )
            return sal_True;
    }
    return sal_False;
}

Sequence< OUString > SAL_CALL DisplayAccess::getSupportedServiceNames() throw (RuntimeException)
{
    return DisplayAccess_getSupportedServiceNames();
}

} // namespace vcl

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Time:  O(1), per move.
// Space: O(n^2)

class TicTacToe {
public:
    /** Initialize your data structure here. */
    TicTacToe(int n) : rows_(n, {0, 0}), cols_(n, {0, 0}),
                       diagonal_(2, 0), anti_diagonal_(2, 0) {
    }

    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    int move(int row, int col, int player) {
        const int i = player - 1;
        ++rows_[row][i], ++cols_[col][i];
        if (row == col) {
            ++diagonal_[i];
        }
        if (col  == rows_.size() - row - 1) {
            ++anti_diagonal_[i];
        }
        if (rows_[row][i] == rows_.size() ||
            cols_[col][i] == cols_.size() ||
            diagonal_[i] == rows_.size() ||
            anti_diagonal_[i] == cols_.size()) {
            return player;
        }
        return 0;
    }

private:
    vector<vector<int>> rows_, cols_;
    vector<int> diagonal_, anti_diagonal_;
};

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */
<commit_msg>Update design-tic-tac-toe.cpp<commit_after>// Time:  O(1), per move.
// Space: O(n^2)

class TicTacToe {
public:
    /** Initialize your data structure here. */
    TicTacToe(int n) : rows_(n, {0, 0}), cols_(n, {0, 0}),
                       diagonal_(2, 0), anti_diagonal_(2, 0) {
    }

    /** Player {player} makes a move at ({row}, {col}).
        @param row The row of the board.
        @param col The column of the board.
        @param player The player, can be either 1 or 2.
        @return The current winning condition, can be either:
                0: No one wins.
                1: Player 1 wins.
                2: Player 2 wins. */
    int move(int row, int col, int player) {
        const int i = player - 1;
        ++rows_[row][i], ++cols_[col][i];
        if (row == col) {
            ++diagonal_[i];
        }
        if (col == rows_.size() - row - 1) {
            ++anti_diagonal_[i];
        }
        if (rows_[row][i] == rows_.size() ||
            cols_[col][i] == cols_.size() ||
            diagonal_[i] == rows_.size() ||
            anti_diagonal_[i] == cols_.size()) {
            return player;
        }
        return 0;
    }

private:
    vector<vector<int>> rows_, cols_;
    vector<int> diagonal_, anti_diagonal_;
};

/**
 * Your TicTacToe object will be instantiated and called as such:
 * TicTacToe obj = new TicTacToe(n);
 * int param_1 = obj.move(row,col,player);
 */
<|endoftext|>