<commit_before>#include <gtest/gtest.h>

#include <parser.h>

using namespace marklar;

TEST(ParserTest, BasicFunction) {
	const auto testProgram =
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, SkipperStart) {
	// Has a newline before the function
	const auto testProgram = R"mrk(
		i32 main() {
			return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, BasicComment) {
	const auto testProgram =
		"// This is a comment\n"
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, ComplexComment) {
	const auto testProgram =
		"//// Blah //a//a//a This is a comment /\n"
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, InvalidComment) {
	const auto testProgram =
		"a // This is a comment\n"
		"i32 main() {"
		"}";

	EXPECT_FALSE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl_NameCheck1) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i09za_ = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl_NameCheck2) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i' = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionMultiDecl) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 0;"
		"  i32 j = 0;"
		"  i32 k = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionDeclAssign) {
	const auto testProgram =
		"i32 main() {"
		"  i32 r = 1 + 2;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionMultiDeclAssign) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 1 + 2;"
		"  i32 j = i + 2;"
		"  i32 k = i + j;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionReturn) {
	const auto testProgram =
		"i32 main() {"
		"  return 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionReturnComplex) {
	const auto testProgram =
		"i32 main() {"
		"  return a + b + c + 0 + 1 + d;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, MultipleFunction) {
	const auto testProgram =
		"i32 foo() {}"
		"i32 main() {}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, MultipleComplexFunction) {
	const auto testProgram =
		"i32 bar() {"
		"  i32 a = 0;"
		"  i32 b = 2;"
		"  return a + b + 0;"
		"}"
		"i32 foo() {"
		"  return a + 0;"
		"}"
		"i32 main() {"
		"  return 0 + 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionArgs) {
	const auto testProgram =
		"i32 main(i32 a, i32 b) {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCall) {
	const auto testProgram =
		"i32 foo() {}"
		"i32 main() {"
		"  foo();"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCallArgs) {
	const auto testProgram =
		"i32 foo(i32 a) {}"
		"i32 main() {"
		"  foo(45);"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCallArgsComplex) {
	const auto testProgram =
		"i32 bar(i32 a, i32 b) {}"
		"i32 foo(i32 a) {"
		"  return bar(a, 5);"
		"}"
		"i32 main() {"
		"  return foo(45);"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionIfStmt) {
	const auto testProgram =
		"i32 main() {"
		"  if (i < 4) {"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionIfElseStmt) {
	const auto testProgram =
		"i32 main() {"
		"  if (i < 4) {"
		"  } else {"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Assignment) {
	const auto testProgram =
		"i32 main() {"
		"  i32 a = 0;"
		"  a = a + 1;"
		"  return a;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, WhileStmt) {
	const auto testProgram =
		"i32 main() {"
		"  while (i < 4) {"
		"    if (i > 5) {"
		"    } else {"
		"    }"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, LogicalOR) {
	const auto testProgram =
		"i32 main() {"
		"  i32 a = 0;"
		"  i32 b = 0;"
		"  if (a || b) {"
		"    return 2;"
		"  }"
		"  return 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Division) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 5 / 3;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Subtraction) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 5 - 3;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, RightShift) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 257 >> 8;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Multiplication) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 8 * 4;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, ComplexEulerProblem1) {
	const auto testProgram =
		"i32 main() {"
		"  i32 sum = 0;"
		"  i32 i = 0;"
		"  while (i < 1000) {"
		"    if (((i % 5) == 0) || ((i % 3) == 0)) {"
		"      sum = sum + i;"
		"    }"
		"    i = i + 1;"
		"  }"
		"  return sum;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FuncCallInIfStmt) {
	const auto testProgram =
		"i32 func1(i32 a) {"
		"  return 0;"
		"}"
		"i32 main() {"
		"  if (func1(45) > 0) {"
		"    return 1;"
		"  }"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, LogicalAnd) {
	const auto testProgram =
		"i32 main() {"
		"  while ((0 != 1) && (0 != 1)) {"
		"    return 1;"
		"  }"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, String) {
	const auto testProgram =
		"i32 main() {"
		"  printf(\"string test\");"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, PrimitiveType_i64) {
	const auto testProgram = R"mrk(
		i64 main() {
		  return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, UserDefinedType_Basic) {
	const auto testProgram = R"mrk(
		type MyType {
			i64 a;
			i64 b;
		}

		i64 main() {
		  return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, UserDefinedType_UseBasic) {
	const auto testProgram = R"mrk(
		type MyType {
			i64 a;
			i64 b;
		}

		i64 main() {
			MyType t;

			return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, UserDefinedType_UseComplex) {
	const auto testProgram = R"mrk(
		type MyType {
			i64 a;
			i64 b;
		}

		i64 main() {
			MyType t;
			t.a = 1;
			t.b = 3;

			return t.b;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

<commit_msg>Removed broken test<commit_after>#include <gtest/gtest.h>

#include <parser.h>

using namespace marklar;

TEST(ParserTest, BasicFunction) {
	const auto testProgram =
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, SkipperStart) {
	// Has a newline before the function
	const auto testProgram = R"mrk(
		i32 main() {
			return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, BasicComment) {
	const auto testProgram =
		"// This is a comment\n"
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, ComplexComment) {
	const auto testProgram =
		"//// Blah //a//a//a This is a comment /\n"
		"i32 main() {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, InvalidComment) {
	const auto testProgram =
		"a // This is a comment\n"
		"i32 main() {"
		"}";

	EXPECT_FALSE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl_NameCheck1) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i09za_ = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionSingleDecl_NameCheck2) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i' = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionMultiDecl) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 0;"
		"  i32 j = 0;"
		"  i32 k = 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionDeclAssign) {
	const auto testProgram =
		"i32 main() {"
		"  i32 r = 1 + 2;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionMultiDeclAssign) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 1 + 2;"
		"  i32 j = i + 2;"
		"  i32 k = i + j;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionReturn) {
	const auto testProgram =
		"i32 main() {"
		"  return 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionReturnComplex) {
	const auto testProgram =
		"i32 main() {"
		"  return a + b + c + 0 + 1 + d;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, MultipleFunction) {
	const auto testProgram =
		"i32 foo() {}"
		"i32 main() {}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, MultipleComplexFunction) {
	const auto testProgram =
		"i32 bar() {"
		"  i32 a = 0;"
		"  i32 b = 2;"
		"  return a + b + 0;"
		"}"
		"i32 foo() {"
		"  return a + 0;"
		"}"
		"i32 main() {"
		"  return 0 + 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionArgs) {
	const auto testProgram =
		"i32 main(i32 a, i32 b) {"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCall) {
	const auto testProgram =
		"i32 foo() {}"
		"i32 main() {"
		"  foo();"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCallArgs) {
	const auto testProgram =
		"i32 foo(i32 a) {}"
		"i32 main() {"
		"  foo(45);"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionCallArgsComplex) {
	const auto testProgram =
		"i32 bar(i32 a, i32 b) {}"
		"i32 foo(i32 a) {"
		"  return bar(a, 5);"
		"}"
		"i32 main() {"
		"  return foo(45);"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionIfStmt) {
	const auto testProgram =
		"i32 main() {"
		"  if (i < 4) {"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FunctionIfElseStmt) {
	const auto testProgram =
		"i32 main() {"
		"  if (i < 4) {"
		"  } else {"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Assignment) {
	const auto testProgram =
		"i32 main() {"
		"  i32 a = 0;"
		"  a = a + 1;"
		"  return a;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, WhileStmt) {
	const auto testProgram =
		"i32 main() {"
		"  while (i < 4) {"
		"    if (i > 5) {"
		"    } else {"
		"    }"
		"  }"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, LogicalOR) {
	const auto testProgram =
		"i32 main() {"
		"  i32 a = 0;"
		"  i32 b = 0;"
		"  if (a || b) {"
		"    return 2;"
		"  }"
		"  return 1;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Division) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 5 / 3;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Subtraction) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 5 - 3;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, RightShift) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 257 >> 8;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, Multiplication) {
	const auto testProgram =
		"i32 main() {"
		"  i32 i = 8 * 4;"
		"  return i;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, ComplexEulerProblem1) {
	const auto testProgram =
		"i32 main() {"
		"  i32 sum = 0;"
		"  i32 i = 0;"
		"  while (i < 1000) {"
		"    if (((i % 5) == 0) || ((i % 3) == 0)) {"
		"      sum = sum + i;"
		"    }"
		"    i = i + 1;"
		"  }"
		"  return sum;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, FuncCallInIfStmt) {
	const auto testProgram =
		"i32 func1(i32 a) {"
		"  return 0;"
		"}"
		"i32 main() {"
		"  if (func1(45) > 0) {"
		"    return 1;"
		"  }"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, LogicalAnd) {
	const auto testProgram =
		"i32 main() {"
		"  while ((0 != 1) && (0 != 1)) {"
		"    return 1;"
		"  }"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, String) {
	const auto testProgram =
		"i32 main() {"
		"  printf(\"string test\");"
		"  return 0;"
		"}";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, PrimitiveType_i64) {
	const auto testProgram = R"mrk(
		i64 main() {
		  return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, UserDefinedType_Basic) {
	const auto testProgram = R"mrk(
		type MyType {
			i64 a;
			i64 b;
		}

		i64 main() {
		  return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}

TEST(ParserTest, UserDefinedType_UseBasic) {
	const auto testProgram = R"mrk(
		type MyType {
			i64 a;
			i64 b;
		}

		i64 main() {
			MyType t;

			return 0;
		}
	)mrk";

	EXPECT_TRUE(parse(testProgram));
}
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2007 by Lothar May                                      *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <net/socket_helper.h>
#include <net/servermanager.h>
#include <net/servercontext.h>
#include <net/ircthread.h>
#include <net/connectdata.h>
#include <net/serverlobbythread.h>
#include <net/serveracceptthread.h>
#include <net/serverexception.h>
#include <net/socket_msg.h>
#include <net/socket_startup.h>
#include <core/loghelper.h>

#include <boost/bind.hpp>
#include <boost/algorithm/string/predicate.hpp>

#define SERVER_RESTART_IRC_BOT_INTERVAL_SEC			86400	// 1 day

using namespace std;

ServerManager::ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager)
: m_gui(gui), m_playerConfig(config), m_avatarManager(avatarManager)
{
}

ServerManager::~ServerManager()
{
}

void
ServerManager::Init(unsigned serverPort, bool ipv6, ServerNetworkMode mode, const string &pwd, const string &logDir, boost::shared_ptr<IrcThread> ircThread)
{
	m_lobbyThread.reset(new ServerLobbyThread(GetGui(), m_playerConfig, m_avatarManager));
	GetLobbyThread().Init(pwd, logDir);

	if (mode & NETWORK_MODE_TCP)
	{
		boost::shared_ptr<ServerAcceptThread> tcpAcceptThread(new ServerAcceptThread(GetGui()));
		tcpAcceptThread->Init(serverPort, ipv6, false, pwd, logDir, m_lobbyThread);
		m_acceptThreadPool.push_back(tcpAcceptThread);
	}
	if (mode & NETWORK_MODE_SCTP)
	{
		boost::shared_ptr<ServerAcceptThread> sctpAcceptThread(new ServerAcceptThread(GetGui()));
		sctpAcceptThread->Init(serverPort, ipv6, true, pwd, logDir, m_lobbyThread);
		m_acceptThreadPool.push_back(sctpAcceptThread);
	}
	m_ircThread = ircThread;
}

GuiInterface &
ServerManager::GetGui()
{
	return m_gui;
}

void
ServerManager::SignalIrcConnect(const std::string &server)
{
	LOG_MSG("Connected to IRC server " << server << ".");
}

void
ServerManager::SignalIrcSelfJoined(const std::string &nickName, const std::string &channel)
{
	LOG_MSG("Joined IRC channel " << channel << " as user " << nickName << ".");
	m_ircNick = nickName;
}

void
ServerManager::SignalIrcChatMsg(const std::string &nickName, const std::string &msg)
{
	if (m_ircThread)
	{
		istringstream msgStream(msg);
		string target;
		msgStream >> target;
		if (boost::algorithm::iequals(target, m_ircNick + ":"))
		{
			string command;
			msgStream >> command;
			if (command == "kick")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string playerName(msgStream.str().substr(msgStream.tellg()));
				if (!playerName.empty())
				{
					if (GetLobbyThread().KickPlayerByName(playerName))
						m_ircThread->SendChatMessage(nickName + ": Successfully kicked player \"" + playerName + "\" from the server.");
					else
						m_ircThread->SendChatMessage(nickName + ": Player \"" + playerName + "\" was not found on the server.");
				}
			}
			else if (command == "stat")
			{
				ServerStats tmpStats = GetLobbyThread().GetStats();
				{
					boost::posix_time::time_duration timeDiff(boost::posix_time::second_clock::local_time() - GetLobbyThread().GetStartTime());
					ostringstream statStream;
					statStream
						<< "Server uptime................ " << timeDiff.hours() / 24 << " days " << timeDiff.hours() % 24 << " hours " << timeDiff.minutes() << " minutes " << timeDiff.seconds() << " seconds";
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Players currently on Server.. " << tmpStats.numberOfPlayersOnServer;
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Games currently open......... " << tmpStats.numberOfGamesOpen;
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Total players ever logged in. " << tmpStats.totalPlayersEverLoggedIn
						<< "    (Max at a time: " << tmpStats.maxPlayersLoggedIn << ")";
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Total games ever open........ " << tmpStats.totalGamesEverCreated
						<< "    (Max at a time: " << tmpStats.maxGamesOpen << ")";
					m_ircThread->SendChatMessage(statStream.str());
				}
			}
			else if (command == "chat")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string chat(msgStream.str().substr(msgStream.tellg()));
				if (!chat.empty())
				{
					GetLobbyThread().SendGlobalChat(chat);
					m_ircThread->SendChatMessage(nickName + ": Global chat message sent.");
				}
				else
					m_ircThread->SendChatMessage(nickName + ": Invalid message.");
			}
			else if (command == "msg")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string message(msgStream.str().substr(msgStream.tellg()));
				if (!message.empty())
				{
					GetLobbyThread().SendGlobalMsgBox(message);
					m_ircThread->SendChatMessage(nickName + ": Global message box sent.");
				}
				else
					m_ircThread->SendChatMessage(nickName + ": Invalid message.");
			}
			else
				m_ircThread->SendChatMessage(nickName + ": Invalid command \"" + command + "\".");
		}
	}
}

void
ServerManager::SignalIrcError(int errorCode)
{
	LOG_MSG("IRC error " << errorCode << ".");
}

void
ServerManager::SignalIrcServerError(int errorCode)
{
	LOG_MSG("IRC server error " << errorCode << ".");
}

void
ServerManager::RunAll()
{
	if (m_ircThread)
		m_ircThread->Run();
	GetLobbyThread().Run();
	for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::Run));
}

void
ServerManager::Process()
{
	if (m_ircRestartTimer.elapsed().total_seconds() > SERVER_RESTART_IRC_BOT_INTERVAL_SEC)
	{
		if (m_ircThread)
		{
			m_ircThread->SignalTermination();
			if (m_ircThread->Join(NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC))
			{
				boost::shared_ptr<IrcThread> tmpIrcThread(new IrcThread(*m_ircThread));
				tmpIrcThread->Run();
				m_ircThread = tmpIrcThread;
			}
		}
		m_ircRestartTimer.reset();
		m_ircRestartTimer.start();
	}
}

void
ServerManager::SignalTerminationAll()
{
	if (m_ircThread)
		m_ircThread->SignalTermination();
	GetLobbyThread().SignalTermination();
	for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::SignalTermination));
}

bool
ServerManager::JoinAll(bool wait)
{
	if (m_ircThread)
		m_ircThread->Join(wait ? NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC : 0);
	bool lobbyThreadTerminated = GetLobbyThread().Join(wait ? NET_LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC : 0);
	bool allAcceptThreadsTerminated = true;
	AcceptThreadList::iterator i = m_acceptThreadPool.begin();
	AcceptThreadList::iterator end = m_acceptThreadPool.end();
	while (i != end)
	{
		if (!(*i)->Join(wait ? NET_ACCEPT_THREAD_TERMINATE_TIMEOUT_MSEC : 0))
			allAcceptThreadsTerminated = false;
		++i;
	}
	return lobbyThreadTerminated || allAcceptThreadsTerminated;
}

ServerLobbyThread &
ServerManager::GetLobbyThread()
{
	assert(m_lobbyThread.get());
	return *m_lobbyThread;
}

<commit_msg>Restrict message sizes.<commit_after>/***************************************************************************
 *   Copyright (C) 2007 by Lothar May                                      *
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include <net/socket_helper.h>
#include <net/servermanager.h>
#include <net/servercontext.h>
#include <net/ircthread.h>
#include <net/connectdata.h>
#include <net/serverlobbythread.h>
#include <net/serveracceptthread.h>
#include <net/serverexception.h>
#include <net/socket_msg.h>
#include <net/socket_startup.h>
#include <core/loghelper.h>

#include <boost/bind.hpp>
#include <boost/algorithm/string/predicate.hpp>

#define SERVER_RESTART_IRC_BOT_INTERVAL_SEC			86400	// 1 day

using namespace std;

ServerManager::ServerManager(GuiInterface &gui, ConfigFile *config, AvatarManager &avatarManager)
: m_gui(gui), m_playerConfig(config), m_avatarManager(avatarManager)
{
}

ServerManager::~ServerManager()
{
}

void
ServerManager::Init(unsigned serverPort, bool ipv6, ServerNetworkMode mode, const string &pwd, const string &logDir, boost::shared_ptr<IrcThread> ircThread)
{
	m_lobbyThread.reset(new ServerLobbyThread(GetGui(), m_playerConfig, m_avatarManager));
	GetLobbyThread().Init(pwd, logDir);

	if (mode & NETWORK_MODE_TCP)
	{
		boost::shared_ptr<ServerAcceptThread> tcpAcceptThread(new ServerAcceptThread(GetGui()));
		tcpAcceptThread->Init(serverPort, ipv6, false, pwd, logDir, m_lobbyThread);
		m_acceptThreadPool.push_back(tcpAcceptThread);
	}
	if (mode & NETWORK_MODE_SCTP)
	{
		boost::shared_ptr<ServerAcceptThread> sctpAcceptThread(new ServerAcceptThread(GetGui()));
		sctpAcceptThread->Init(serverPort, ipv6, true, pwd, logDir, m_lobbyThread);
		m_acceptThreadPool.push_back(sctpAcceptThread);
	}
	m_ircThread = ircThread;
}

GuiInterface &
ServerManager::GetGui()
{
	return m_gui;
}

void
ServerManager::SignalIrcConnect(const std::string &server)
{
	LOG_MSG("Connected to IRC server " << server << ".");
}

void
ServerManager::SignalIrcSelfJoined(const std::string &nickName, const std::string &channel)
{
	LOG_MSG("Joined IRC channel " << channel << " as user " << nickName << ".");
	m_ircNick = nickName;
}

void
ServerManager::SignalIrcChatMsg(const std::string &nickName, const std::string &msg)
{
	if (m_ircThread)
	{
		istringstream msgStream(msg);
		string target;
		msgStream >> target;
		if (boost::algorithm::iequals(target, m_ircNick + ":"))
		{
			string command;
			msgStream >> command;
			if (command == "kick")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string playerName(msgStream.str().substr(msgStream.tellg()));
				if (!playerName.empty())
				{
					if (GetLobbyThread().KickPlayerByName(playerName))
						m_ircThread->SendChatMessage(nickName + ": Successfully kicked player \"" + playerName + "\" from the server.");
					else
						m_ircThread->SendChatMessage(nickName + ": Player \"" + playerName + "\" was not found on the server.");
				}
			}
			else if (command == "stat")
			{
				ServerStats tmpStats = GetLobbyThread().GetStats();
				{
					boost::posix_time::time_duration timeDiff(boost::posix_time::second_clock::local_time() - GetLobbyThread().GetStartTime());
					ostringstream statStream;
					statStream
						<< "Server uptime................ " << timeDiff.hours() / 24 << " days " << timeDiff.hours() % 24 << " hours " << timeDiff.minutes() << " minutes " << timeDiff.seconds() << " seconds";
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Players currently on Server.. " << tmpStats.numberOfPlayersOnServer;
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Games currently open......... " << tmpStats.numberOfGamesOpen;
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Total players ever logged in. " << tmpStats.totalPlayersEverLoggedIn
						<< "    (Max at a time: " << tmpStats.maxPlayersLoggedIn << ")";
					m_ircThread->SendChatMessage(statStream.str());
				}
				{
					ostringstream statStream;
					statStream
						<< "Total games ever open........ " << tmpStats.totalGamesEverCreated
						<< "    (Max at a time: " << tmpStats.maxGamesOpen << ")";
					m_ircThread->SendChatMessage(statStream.str());
				}
			}
			else if (command == "chat")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string chat(msgStream.str().substr(msgStream.tellg()));
				if (!chat.empty() && chat.size() < MAX_CHAT_TEXT_SIZE)
				{
					GetLobbyThread().SendGlobalChat(chat);
					m_ircThread->SendChatMessage(nickName + ": Global chat message sent.");
				}
				else
					m_ircThread->SendChatMessage(nickName + ": Invalid message.");
			}
			else if (command == "msg")
			{
				while (msgStream.peek() == ' ')
					msgStream.get();
				string message(msgStream.str().substr(msgStream.tellg()));
				if (!message.empty() && message.size() < MAX_CHAT_TEXT_SIZE)
				{
					GetLobbyThread().SendGlobalMsgBox(message);
					m_ircThread->SendChatMessage(nickName + ": Global message box sent.");
				}
				else
					m_ircThread->SendChatMessage(nickName + ": Invalid message.");
			}
			else
				m_ircThread->SendChatMessage(nickName + ": Invalid command \"" + command + "\".");
		}
	}
}

void
ServerManager::SignalIrcError(int errorCode)
{
	LOG_MSG("IRC error " << errorCode << ".");
}

void
ServerManager::SignalIrcServerError(int errorCode)
{
	LOG_MSG("IRC server error " << errorCode << ".");
}

void
ServerManager::RunAll()
{
	if (m_ircThread)
		m_ircThread->Run();
	GetLobbyThread().Run();
	for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::Run));
}

void
ServerManager::Process()
{
	if (m_ircRestartTimer.elapsed().total_seconds() > SERVER_RESTART_IRC_BOT_INTERVAL_SEC)
	{
		if (m_ircThread)
		{
			m_ircThread->SignalTermination();
			if (m_ircThread->Join(NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC))
			{
				boost::shared_ptr<IrcThread> tmpIrcThread(new IrcThread(*m_ircThread));
				tmpIrcThread->Run();
				m_ircThread = tmpIrcThread;
			}
		}
		m_ircRestartTimer.reset();
		m_ircRestartTimer.start();
	}
}

void
ServerManager::SignalTerminationAll()
{
	if (m_ircThread)
		m_ircThread->SignalTermination();
	GetLobbyThread().SignalTermination();
	for_each(m_acceptThreadPool.begin(), m_acceptThreadPool.end(), boost::mem_fn(&ServerAcceptThread::SignalTermination));
}

bool
ServerManager::JoinAll(bool wait)
{
	if (m_ircThread)
		m_ircThread->Join(wait ? NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC : 0);
	bool lobbyThreadTerminated = GetLobbyThread().Join(wait ? NET_LOBBY_THREAD_TERMINATE_TIMEOUT_MSEC : 0);
	bool allAcceptThreadsTerminated = true;
	AcceptThreadList::iterator i = m_acceptThreadPool.begin();
	AcceptThreadList::iterator end = m_acceptThreadPool.end();
	while (i != end)
	{
		if (!(*i)->Join(wait ? NET_ACCEPT_THREAD_TERMINATE_TIMEOUT_MSEC : 0))
			allAcceptThreadsTerminated = false;
		++i;
	}
	return lobbyThreadTerminated || allAcceptThreadsTerminated;
}

ServerLobbyThread &
ServerManager::GetLobbyThread()
{
	assert(m_lobbyThread.get());
	return *m_lobbyThread;
}

<|endoftext|>


<commit_before>/*
 *
 *  D-Bus++ - C++ bindings for D-Bus
 *
 *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
 *
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <iostream>
#include <cstdlib>

#include "generator_utils.h"

using namespace std;

const char *tab = "    ";

const char *header = "\n\
/*\n\
 *	This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!\n\
 */\n\
\n\
";

const char *dbus_includes = "\n\
#include <dbus-c++/dbus.h>\n\
#include <cassert>\n\
";

void underscorize(string &str)
{
	for (unsigned int i = 0; i < str.length(); ++i)
	{
		if (!isalpha(str[i]) && !isdigit(str[i])) str[i] = '_';
	}
}

string stub_name(string name)
{
	underscorize(name);

	return "_" + name + "_stub";
}

const char *atomic_type_to_string(char t)
{
	static struct { char type; const char *name; } atos[] =
	{
		{ 'y', "uint8_t" },
		{ 'b', "bool" },
		{ 'n', "int16_t" },
		{ 'q', "uint16_t" },
		{ 'i', "int32_t" },
		{ 'u', "uint32_t" },
		{ 'x', "int64_t" },
		{ 't', "uint64_t" },
		{ 'd', "double" },
		{ 's', "std::string" },
		{ 'o', "::DBus::Path" },
		{ 'g', "::DBus::Signature" },
		{ 'v', "::DBus::Variant" },
		{ '\0', "" }
	};
	int i;

	for (i = 0; atos[i].type; ++i)
	{
		if (atos[i].type == t) break;
	}
	return atos[i].name;
}

void _parse_signature(const string &signature, string &type, unsigned int &i)
{
  cout << "signature: " << signature << endl;
  cout << "type: " << type << endl;
  cout << "i: " << i << ", signature[i]: " << signature[i] << endl;

	for (; i < signature.length(); ++i)
	{
		switch (signature[i])
		{
			case 'a':
			{
				switch (signature[++i])
				{
					case '{':
					{
						type += "std::map< ";
            ++i;
            _parse_signature(signature, type, i);
            type += " >";

						break;
					}
					case '(':
					{
						type += "std::vector< ::DBus::Struct< ";
            ++i;
            _parse_signature(signature, type, i);
            type += " > >";

						break;
					}
					default:
					{
						type += "std::vector< ";
            _parse_signature(signature, type, i);

            type += " >";

						break;
					}
                 }

				if (i+1 < signature.length() && signature[i+1] != ')' && signature[i+1] != '}')
				{
					type += ", ";
				}

				break;
			}
      case '(':
      {
        type += "::DBus::Struct< ";
        ++i;

        _parse_signature(signature, type, i);

        type += " >";
        break;
      }
			case ')':
			case '}':
			{
        return;
			}
			default:
			{
				const char *atom = atomic_type_to_string(signature[i]);
				if (!atom)
				{
					cerr << "invalid signature" << endl;
					exit(-1);
				}
				type += atom;

				if (i+1 < signature.length() && signature[i+1] != ')' && signature[i+1] != '}')
				{
					type += ", ";
				}

				break;
			}
		}
	}
}

string signature_to_type(const string &signature)
{
	string type;
	unsigned int i = 0;
	_parse_signature(signature, type, i);
	return type;
}
<commit_msg>Fix code generator: add always a comma after each signature argument.<commit_after>/*
 *
 *  D-Bus++ - C++ bindings for D-Bus
 *
 *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
 *
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <iostream>
#include <cstdlib>

#include "generator_utils.h"

using namespace std;

const char *tab = "    ";

const char *header = "\n\
/*\n\
 *	This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!\n\
 */\n\
\n\
";

const char *dbus_includes = "\n\
#include <dbus-c++/dbus.h>\n\
#include <cassert>\n\
";

void underscorize(string &str)
{
	for (unsigned int i = 0; i < str.length(); ++i)
	{
		if (!isalpha(str[i]) && !isdigit(str[i])) str[i] = '_';
	}
}

string stub_name(string name)
{
	underscorize(name);

	return "_" + name + "_stub";
}

const char *atomic_type_to_string(char t)
{
	static struct { char type; const char *name; } atos[] =
	{
		{ 'y', "uint8_t" },
		{ 'b', "bool" },
		{ 'n', "int16_t" },
		{ 'q', "uint16_t" },
		{ 'i', "int32_t" },
		{ 'u', "uint32_t" },
		{ 'x', "int64_t" },
		{ 't', "uint64_t" },
		{ 'd', "double" },
		{ 's', "std::string" },
		{ 'o', "::DBus::Path" },
		{ 'g', "::DBus::Signature" },
		{ 'v', "::DBus::Variant" },
		{ '\0', "" }
	};
	int i;

	for (i = 0; atos[i].type; ++i)
	{
		if (atos[i].type == t) break;
	}
	return atos[i].name;
}

void _parse_signature(const string &signature, string &type, unsigned int &i)
{
  cout << "signature: " << signature << endl;
  cout << "type: " << type << endl;
  cout << "i: " << i << ", signature[i]: " << signature[i] << endl;

	for (; i < signature.length(); ++i)
	{
		switch (signature[i])
		{
			case 'a':
			{
				switch (signature[++i])
				{
					case '{':
					{
						type += "std::map< ";
            ++i;
            _parse_signature(signature, type, i);
            type += " >";

						break;
					}
					case '(':
					{
						type += "std::vector< ::DBus::Struct< ";
            ++i;
            _parse_signature(signature, type, i);
            type += " > >";

						break;
					}
					default:
					{
						type += "std::vector< ";
            _parse_signature(signature, type, i);

            type += " >";

						break;
					}
                 }
				break;
			}
      case '(':
      {
        type += "::DBus::Struct< ";
        ++i;

        _parse_signature(signature, type, i);

        type += " >";
        break;
      }
			case ')':
			case '}':
			{
        return;
			}
			default:
			{
				const char *atom = atomic_type_to_string(signature[i]);
				if (!atom)
				{
					cerr << "invalid signature" << endl;
					exit(-1);
				}
				type += atom;

				break;
			}
		}

				if (i+1 < signature.length() && signature[i+1] != ')' && signature[i+1] != '}')
				{
					type += ", ";
				}
	}
}

string signature_to_type(const string &signature)
{
	string type;
	unsigned int i = 0;
	_parse_signature(signature, type, i);
	return type;
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef QUEUEDITEM_HH
#define QUEUEDITEM_HH 1

#include "common.hh"
#include "item.hh"
#include "stats.hh"

enum queue_operation {
    queue_op_set,
    queue_op_del,
    queue_op_flush,
    queue_op_empty,
    queue_op_commit,
    queue_op_checkpoint_start,
    queue_op_checkpoint_end,
    queue_op_online_update_start,
    queue_op_online_update_end,
    queue_op_online_update_revert
};

typedef enum {
    vbucket_del_success,
    vbucket_del_fail,
    vbucket_del_invalid
} vbucket_del_result;

/**
 * Representation of an item queued for persistence or tap.
 */
class QueuedItem : public RCValue {
public:
    QueuedItem(const std::string &k, const uint16_t vb, enum queue_operation o,
               const uint16_t vb_version = -1, const int64_t rid = -1, const uint32_t f = 0,
               const time_t expiry_time = 0, const uint64_t cv = 0, uint32_t seqno = 1)
        : op(o),vbucket_version(vb_version), ejectValue(false), queued(ep_current_time()),
          dirtied(ep_current_time()), item(k, f, expiry_time, NULL, 0, cv, rid, vb)
    {
        ObjectRegistry::onCreateQueuedItem(this);
        item.setSeqno(seqno);
    }

    QueuedItem(const std::string &k, value_t v, const uint16_t vb, enum queue_operation o,
               const uint16_t vb_version = -1, const int64_t rid = -1, const uint32_t f = 0,
               const time_t expiry_time = 0, const uint64_t cv = 0, uint32_t seqno = 1)
        : op(o), vbucket_version(vb_version), ejectValue(false), queued(ep_current_time()),
          dirtied(ep_current_time()), item(k, f, expiry_time, v, cv, rid, vb)
    {
        ObjectRegistry::onCreateQueuedItem(this);
        item.setSeqno(seqno);
    }

    ~QueuedItem() {
        ObjectRegistry::onDeleteQueuedItem(this);
    }

    const std::string &getKey(void) const { return item.getKey(); }
    uint16_t getVBucketId(void) const { return item.getVBucketId(); }
    uint16_t getVBucketVersion(void) const { return vbucket_version; }
    uint32_t getQueuedTime(void) const { return queued; }
    enum queue_operation getOperation(void) const { return op; }
    int64_t getRowId() const { return item.getId(); }
    uint32_t getDirtiedTime() const { return dirtied; }
    uint32_t getFlags() const { return item.getFlags(); }
    time_t getExpiryTime() const { return item.getExptime(); }
    uint64_t getCas() const { return item.getCas(); }
    value_t getValue() const { return item.getValue(); }
    Item &getItem() { return item; }

    void setEjectValue(bool val) {
        ejectValue = val;
    }

    bool isEjectValue() {
        return ejectValue;
    }

    void setQueuedTime(uint32_t queued_time) {
        queued = queued_time;
    }

    void setOperation(enum queue_operation o) {
        op = o;
    }

    bool operator <(const QueuedItem &other) const {
        return getVBucketId() == other.getVBucketId() ?
            getKey() < other.getKey() : getVBucketId() < other.getVBucketId();
    }

    size_t size() {
        return sizeof(QueuedItem) + getKey().size() + getValue()->getSize();
    }

private:
    enum queue_operation op;
    uint16_t vbucket_version;
    bool ejectValue : 1;
    uint32_t queued;
    // Additional variables below are required to support the checkpoint and cursors
    // as memory hashtable always contains the latest value and latest meta data for each key.
    uint32_t dirtied;
    Item item;

    DISALLOW_COPY_AND_ASSIGN(QueuedItem);
};

typedef RCPtr<QueuedItem> queued_item;

/**
 * Order QueuedItem objects pointed by shared_ptr by their keys.
 */
class CompareQueuedItemsByKey {
public:
    CompareQueuedItemsByKey() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getKey() < i2->getKey();
    }
};

/**
 * Order QueuedItem objects by their row ids.
 */
class CompareQueuedItemsByRowId {
public:
    CompareQueuedItemsByRowId() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getRowId() < i2->getRowId();
    }
};

/**
 * Order QueuedItem objects by their vbucket then row ids.
 */
class CompareQueuedItemsByVBAndRowId {
public:
    CompareQueuedItemsByVBAndRowId() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getVBucketId() == i2->getVBucketId()
            ? i1->getRowId() < i2->getRowId()
            : i1->getVBucketId() < i2->getVBucketId();
    }
};

/**
 * Compare two Schwartzian-transformed QueuedItems.
 */
template <typename T>
class TaggedQueuedItemComparator {
public:
    TaggedQueuedItemComparator() {}

    bool operator()(std::pair<T, queued_item> i1, std::pair<T, queued_item> i2) {
        return (i1.first == i2.first)
            ? (i1.second->getRowId() < i2.second->getRowId())
            : (i1 < i2);
    }
};

#endif /* QUEUEDITEM_HH */
<commit_msg>Reorder the QueuedItem structure.<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
#ifndef QUEUEDITEM_HH
#define QUEUEDITEM_HH 1

#include "common.hh"
#include "item.hh"
#include "stats.hh"

enum queue_operation {
    queue_op_set,
    queue_op_del,
    queue_op_flush,
    queue_op_empty,
    queue_op_commit,
    queue_op_checkpoint_start,
    queue_op_checkpoint_end,
    queue_op_online_update_start,
    queue_op_online_update_end,
    queue_op_online_update_revert
};

typedef enum {
    vbucket_del_success,
    vbucket_del_fail,
    vbucket_del_invalid
} vbucket_del_result;

/**
 * Representation of an item queued for persistence or tap.
 */
class QueuedItem : public RCValue {
public:
    QueuedItem(const std::string &k, const uint16_t vb, enum queue_operation o,
               const uint16_t vb_version = -1, const int64_t rid = -1, const uint32_t f = 0,
               const time_t expiry_time = 0, const uint64_t cv = 0, uint32_t seqno = 1)
        : item(k, f, expiry_time, NULL, 0, cv, rid, vb),
          queued(ep_current_time()), dirtied(ep_current_time()),
          op(o), vbucket_version(vb_version), ejectValue(false)
    {
        ObjectRegistry::onCreateQueuedItem(this);
        item.setSeqno(seqno);
    }

    QueuedItem(const std::string &k, value_t v, const uint16_t vb, enum queue_operation o,
               const uint16_t vb_version = -1, const int64_t rid = -1, const uint32_t f = 0,
               const time_t expiry_time = 0, const uint64_t cv = 0, uint32_t seqno = 1)
        : item(k, f, expiry_time, v, cv, rid, vb),
          queued(ep_current_time()), dirtied(ep_current_time()),
          op(o), vbucket_version(vb_version), ejectValue(false)
    {
        ObjectRegistry::onCreateQueuedItem(this);
        item.setSeqno(seqno);
    }

    ~QueuedItem() {
        ObjectRegistry::onDeleteQueuedItem(this);
    }

    const std::string &getKey(void) const { return item.getKey(); }
    uint16_t getVBucketId(void) const { return item.getVBucketId(); }
    uint16_t getVBucketVersion(void) const { return vbucket_version; }
    uint32_t getQueuedTime(void) const { return queued; }
    enum queue_operation getOperation(void) const { return op; }
    int64_t getRowId() const { return item.getId(); }
    uint32_t getDirtiedTime() const { return dirtied; }
    uint32_t getFlags() const { return item.getFlags(); }
    time_t getExpiryTime() const { return item.getExptime(); }
    uint64_t getCas() const { return item.getCas(); }
    value_t getValue() const { return item.getValue(); }
    Item &getItem() { return item; }

    void setEjectValue(bool val) {
        ejectValue = val;
    }

    bool isEjectValue() {
        return ejectValue;
    }

    void setQueuedTime(uint32_t queued_time) {
        queued = queued_time;
    }

    void setOperation(enum queue_operation o) {
        op = o;
    }

    bool operator <(const QueuedItem &other) const {
        return getVBucketId() == other.getVBucketId() ?
            getKey() < other.getKey() : getVBucketId() < other.getVBucketId();
    }

    size_t size() {
        return sizeof(QueuedItem) + getKey().size() + getValue()->getSize();
    }

private:
    Item item;
    uint32_t queued;
    uint32_t dirtied;
    enum queue_operation op;
    uint16_t vbucket_version;
    bool ejectValue : 1;

    DISALLOW_COPY_AND_ASSIGN(QueuedItem);
};

typedef RCPtr<QueuedItem> queued_item;

/**
 * Order QueuedItem objects pointed by shared_ptr by their keys.
 */
class CompareQueuedItemsByKey {
public:
    CompareQueuedItemsByKey() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getKey() < i2->getKey();
    }
};

/**
 * Order QueuedItem objects by their row ids.
 */
class CompareQueuedItemsByRowId {
public:
    CompareQueuedItemsByRowId() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getRowId() < i2->getRowId();
    }
};

/**
 * Order QueuedItem objects by their vbucket then row ids.
 */
class CompareQueuedItemsByVBAndRowId {
public:
    CompareQueuedItemsByVBAndRowId() {}
    bool operator()(const queued_item &i1, const queued_item &i2) {
        return i1->getVBucketId() == i2->getVBucketId()
            ? i1->getRowId() < i2->getRowId()
            : i1->getVBucketId() < i2->getVBucketId();
    }
};

/**
 * Compare two Schwartzian-transformed QueuedItems.
 */
template <typename T>
class TaggedQueuedItemComparator {
public:
    TaggedQueuedItemComparator() {}

    bool operator()(std::pair<T, queued_item> i1, std::pair<T, queued_item> i2) {
        return (i1.first == i2.first)
            ? (i1.second->getRowId() < i2.second->getRowId())
            : (i1 < i2);
    }
};

#endif /* QUEUEDITEM_HH */
<|endoftext|>


<commit_before>#include "Halide.h"
#include "wrapper_tutorial_04A.h"
#include <tiramisu/utils.h>
#include <cstdlib>
#include <iostream>

#define NN 1000

int main(int, char **)
{
    Halide::Buffer<uint8_t> A_buf(NN, NN);
    Halide::Buffer<uint8_t> B_buf(NN, NN);
    // Initialize matrices with pseudorandom values:
    for (int i = 0; i < NN; i++) {
        for (int j = 0; j < NN; j++) {
            A_buf(j, i) = (i + 3) * (j + 1);
            B_buf(j, i) = (i + 1) * j + 2;
        }
    }

    // Output
    Halide::Buffer<uint8_t> C1_buf(NN, NN);

    matmul(A_buf.raw_buffer(), B_buf.raw_buffer(), C1_buf.raw_buffer());

    // Reference matrix multiplication
    Halide::Buffer<uint8_t> C2_buf(NN, NN);
    init_buffer(C2_buf, (uint8_t)0);

    for (int i = 0; i < NN; i++) {
        for (int j = 0; j < NN; j++) {
            for (int k = 0; k < NN; k++) {
                // Note that indices are flipped (see tutorial 2)
                C2_buf(j, i) += A_buf(k, i) * B_buf(j, k);
            }
        }
    }

    compare_buffers("matmul", C1_buf, C2_buf);

    return 0;
}
<commit_msg>Fixing tutorial_04A<commit_after>#include "Halide.h"
#include "wrapper_tutorial_04A.h"
#include <tiramisu/utils.h>
#include <cstdlib>
#include <iostream>

#define NN 100

int main(int, char **)
{
    Halide::Buffer<uint8_t> A_buf(NN, NN);
    Halide::Buffer<uint8_t> B_buf(NN, NN);
    // Initialize matrices with pseudorandom values:
    for (int i = 0; i < NN; i++) {
        for (int j = 0; j < NN; j++) {
            A_buf(j, i) = (i + 3) * (j + 1);
            B_buf(j, i) = (i + 1) * j + 2;
        }
    }

    // Output
    Halide::Buffer<uint8_t> C1_buf(NN, NN);

    matmul(A_buf.raw_buffer(), B_buf.raw_buffer(), C1_buf.raw_buffer());

    // Reference matrix multiplication
    Halide::Buffer<uint8_t> C2_buf(NN, NN);
    init_buffer(C2_buf, (uint8_t)0);

    for (int i = 0; i < NN; i++) {
        for (int j = 0; j < NN; j++) {
            for (int k = 0; k < NN; k++) {
                // Note that indices are flipped (see tutorial 2)
                C2_buf(j, i) += A_buf(k, i) * B_buf(j, k);
            }
        }
    }

    compare_buffers("matmul", C1_buf, C2_buf);

    return 0;
}
<|endoftext|>


<commit_before>#include "drivers/ublox_neo7.hpp"

#include <cstdlib>
#include <cstring>

#include "chprintf.h"
#include "unit_config.hpp"

const char NMEA_LF = '\n';
const char *NMEA_DELIMS = ",\0";

struct GPGLLMessage {
  float lon;
  char lonDir;
  float lat;
  char latDir;
  float utc;
  char valid;
};

void UBloxNEO7::init() {
}

GPSReading UBloxNEO7::readGPS() {
  // Read all available bytes until the newline character. NMEA dictates that
  // messages should end with a CRLF, but we'll only look for the LF.
  std::size_t len = readUntil(NMEA_LF);

  // Check if a full line is ready to be processed
  if(len > 0) {
    char *start = reinterpret_cast<char *>(rxbuf.data());

    // Skip over the leading "$"
    start += 1;

    char *token = std::strtok(start, NMEA_DELIMS);

    // Only care about GPGLL messages
    if(std::strcmp("GPGLL", token) == 0) {
      GPGLLMessage message;
      int position = 0;

      while(token != nullptr) {
        token = std::strtok(nullptr, NMEA_DELIMS);

        switch(position++) {
          case 0:
            message.lat = atof(token);
            break;
          case 1:
            message.latDir = token[0];
            break;
          case 2:
            message.lon = atof(token);
            break;
          case 3:
            message.lonDir = token[0];
            break;
          case 4:
            message.utc = atof(token);
            break;
          case 5:
            message.valid = token[0];
            break;
        };
      }

      return GPSReading {
        .valid = message.valid,
        .lat = dmd2float(message.lat, message.latDir),
        .lon = dmd2float(message.lon, message.lonDir),
        .utc = message.utc
      };
    }
  } else {
    // TODO: Return previous message with old timestamp.
      return GPSReading {
        .valid = false,
        .lat = 0.0,
        .lon = 0.0,
        .utc = 0.0
      };
  }
}
<commit_msg>More checks on GPS data validity.<commit_after>#include "drivers/ublox_neo7.hpp"

#include <cstdlib>
#include <cstring>

#include "chprintf.h"
#include "unit_config.hpp"

const char NMEA_LF = '\n';
const char *NMEA_DELIMS = ",\0";

struct GPGLLMessage {
  float lon;
  char lonDir;
  float lat;
  char latDir;
  float utc;
  char valid;
};

void UBloxNEO7::init() {
}

GPSReading UBloxNEO7::readGPS() {
  // Read all available bytes until the newline character. NMEA dictates that
  // messages should end with a CRLF, but we'll only look for the LF.
  std::size_t len = readUntil(NMEA_LF);

  // Check if a full line is ready to be processed
  if(len > 0) {
    char *start = reinterpret_cast<char *>(rxbuf.data());

    // Skip over the leading "$"
    start += 1;

    char *token = std::strtok(start, NMEA_DELIMS);

    // Only care about GPGLL messages
    if(std::strcmp("GPGLL", token) == 0) {
      GPGLLMessage message;
      int position = 0;

      while(token != nullptr) {
        token = std::strtok(nullptr, NMEA_DELIMS);

        switch(position++) {
          case 0:
            message.lat = atof(token);
            break;
          case 1:
            message.latDir = token[0];
            break;
          case 2:
            message.lon = atof(token);
            break;
          case 3:
            message.lonDir = token[0];
            break;
          case 4:
            message.utc = atof(token);
            break;
          case 5:
            message.valid = token[0];
            break;
        };
      }

      return GPSReading {
        // Make sure we got all parts of the message. If fields are omitted in
        // the message then `strtok` will skip over repeated delimiters and the
        // above loop will complete before all delimiters were found.
        .valid = message.valid && position == 6,
        .lat = dmd2float(message.lat, message.latDir),
        .lon = dmd2float(message.lon, message.lonDir),
        .utc = message.utc
      };
    }
  } else {
    // TODO: Return previous message with old timestamp.
      return GPSReading {
        .valid = false,
        .lat = 0.0,
        .lon = 0.0,
        .utc = 0.0
      };
  }
}
<|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 .
 */

#ifndef SC_XMLCHANGETRACKINGEXPORTHELPER_HXX
#define SC_XMLCHANGETRACKINGEXPORTHELPER_HXX

#include <xmloff/xmltoken.hxx>
#include <list>
#include <map>
#include <tools/solar.h>
#include <com/sun/star/text/XText.hpp>
#include <rtl/ustrbuf.hxx>

class ScChangeAction;
class ScChangeTrack;
class ScXMLExport;
class ScCellValue;
class ScChangeActionDel;
class ScBigRange;
class ScEditEngineTextObj;
class String;

typedef std::list<ScChangeActionDel*> ScMyDeletionsList;
typedef std::map<sal_uLong, ScChangeAction*> ScChangeActionMap;

class ScChangeTrackingExportHelper
{
    ScXMLExport&    rExport;

    ScChangeTrack*  pChangeTrack;
    ScEditEngineTextObj* pEditTextObj;
    ScChangeActionMap* pDependings;
    rtl::OUString   sChangeIDPrefix;
    com::sun::star::uno::Reference<com::sun::star::text::XText> xText;

    rtl::OUString GetChangeID(const sal_uInt32 nActionNumber);
    void GetAcceptanceState(const ScChangeAction* pAction);

    void WriteBigRange(const ScBigRange& rBigRange, xmloff::token::XMLTokenEnum aName);
    void WriteChangeInfo(const ScChangeAction* pAction);
    void WriteGenerated(const ScChangeAction* pDependAction);
    void WriteDeleted(const ScChangeAction* pDependAction);
    void WriteDepending(const ScChangeAction* pDependAction);
    void WriteDependings(ScChangeAction* pAction);

    void WriteEmptyCell();
    void SetValueAttributes(const double& fValue, const String& sValue);
    void WriteValueCell(const ScCellValue& rCell, const OUString& sValue);
    void WriteStringCell(const ScCellValue& rCell);
    void WriteEditCell(const ScCellValue& rCell);
    void WriteFormulaCell(const ScCellValue& rCell, const OUString& sValue);
    void WriteCell(const ScCellValue& rCell, const OUString& sValue);

    void WriteContentChange(ScChangeAction* pAction);
    void AddInsertionAttributes(const ScChangeAction* pAction);
    void WriteInsertion(ScChangeAction* pAction);
    void AddDeletionAttributes(const ScChangeActionDel* pAction, const ScChangeActionDel* pLastAction);
    void WriteDeletionCells(ScChangeActionDel* pAction);
    void WriteCutOffs(const ScChangeActionDel* pAction);
    void WriteDeletion(ScChangeAction* pAction);
    void WriteMovement(ScChangeAction* pAction);
    void WriteRejection(ScChangeAction* pAction);

    void CollectCellAutoStyles(const ScCellValue& rCell);
    void CollectActionAutoStyles(ScChangeAction* pAction);
    void WorkWithChangeAction(ScChangeAction* pAction);
public:
    ScChangeTrackingExportHelper(ScXMLExport& rExport);
    ~ScChangeTrackingExportHelper();

    void CollectAutoStyles();
    void CollectAndWriteChanges();
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>WaE: 'ScCellValue' defined as a struct here but previously declared as a class<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 .
 */

#ifndef SC_XMLCHANGETRACKINGEXPORTHELPER_HXX
#define SC_XMLCHANGETRACKINGEXPORTHELPER_HXX

#include <xmloff/xmltoken.hxx>
#include <list>
#include <map>
#include <tools/solar.h>
#include <com/sun/star/text/XText.hpp>
#include <rtl/ustrbuf.hxx>

class ScChangeAction;
class ScChangeTrack;
class ScXMLExport;
struct ScCellValue;
class ScChangeActionDel;
class ScBigRange;
class ScEditEngineTextObj;
class String;

typedef std::list<ScChangeActionDel*> ScMyDeletionsList;
typedef std::map<sal_uLong, ScChangeAction*> ScChangeActionMap;

class ScChangeTrackingExportHelper
{
    ScXMLExport&    rExport;

    ScChangeTrack*  pChangeTrack;
    ScEditEngineTextObj* pEditTextObj;
    ScChangeActionMap* pDependings;
    rtl::OUString   sChangeIDPrefix;
    com::sun::star::uno::Reference<com::sun::star::text::XText> xText;

    rtl::OUString GetChangeID(const sal_uInt32 nActionNumber);
    void GetAcceptanceState(const ScChangeAction* pAction);

    void WriteBigRange(const ScBigRange& rBigRange, xmloff::token::XMLTokenEnum aName);
    void WriteChangeInfo(const ScChangeAction* pAction);
    void WriteGenerated(const ScChangeAction* pDependAction);
    void WriteDeleted(const ScChangeAction* pDependAction);
    void WriteDepending(const ScChangeAction* pDependAction);
    void WriteDependings(ScChangeAction* pAction);

    void WriteEmptyCell();
    void SetValueAttributes(const double& fValue, const String& sValue);
    void WriteValueCell(const ScCellValue& rCell, const OUString& sValue);
    void WriteStringCell(const ScCellValue& rCell);
    void WriteEditCell(const ScCellValue& rCell);
    void WriteFormulaCell(const ScCellValue& rCell, const OUString& sValue);
    void WriteCell(const ScCellValue& rCell, const OUString& sValue);

    void WriteContentChange(ScChangeAction* pAction);
    void AddInsertionAttributes(const ScChangeAction* pAction);
    void WriteInsertion(ScChangeAction* pAction);
    void AddDeletionAttributes(const ScChangeActionDel* pAction, const ScChangeActionDel* pLastAction);
    void WriteDeletionCells(ScChangeActionDel* pAction);
    void WriteCutOffs(const ScChangeActionDel* pAction);
    void WriteDeletion(ScChangeAction* pAction);
    void WriteMovement(ScChangeAction* pAction);
    void WriteRejection(ScChangeAction* pAction);

    void CollectCellAutoStyles(const ScCellValue& rCell);
    void CollectActionAutoStyles(ScChangeAction* pAction);
    void WorkWithChangeAction(ScChangeAction* pAction);
public:
    ScChangeTrackingExportHelper(ScXMLExport& rExport);
    ~ScChangeTrackingExportHelper();

    void CollectAutoStyles();
    void CollectAndWriteChanges();
};

#endif

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


<commit_before>#include "ImageFeed.hpp"
#include <openMVG/sfm/sfm_data.hpp>
#include <openMVG/sfm/sfm_data_io.hpp>
#include <openMVG/image/image_io.hpp>

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

#include <queue>
#include <iostream>
#include <fstream>
#include <exception>
#include <regex>
#include <iterator>
#include <string>

namespace openMVG{
namespace dataio{

class ImageFeed::FeederImpl
{
public:

  static bool isSupported(const std::string &ext);

  FeederImpl() : _isInit(false) {}

  FeederImpl(const std::string& imagePath, const std::string& calibPath);

  bool readImage(image::Image<image::RGBColor> &imageRGB,
                   cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                   std::string &imageName,
                   bool &hasIntrinsics);

  bool readImage(image::Image<unsigned char> &imageGray,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &imageName,
                     bool &hasIntrinsics);

  std::size_t nbFrames() const;

  bool goToFrame(const unsigned int frame);

  bool goToNextFrame();

  bool isInit() const {return _isInit;}

private:

  bool feedWithJson(image::Image<unsigned char> &imageGray,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &imageName,
                     bool &hasIntrinsics);

private:
  static const std::vector<std::string> supportedExtensions;

private:
  bool _isInit;
  bool _withCalibration;
  // It contains the images to be fed
  std::vector<std::string> _images;
  cameras::Pinhole_Intrinsic_Radial_K3 _camIntrinsics;

  bool _sfmMode = false;
  sfm::SfM_Data _sfmdata;
  sfm::Views::const_iterator _viewIterator;
  unsigned int _currentImageIndex = 0;
};

const std::vector<std::string> ImageFeed::FeederImpl::supportedExtensions = { ".jpg", ".jpeg", ".png", ".ppm" };

bool ImageFeed::FeederImpl::isSupported(const std::string &ext)
{
  const auto start = FeederImpl::supportedExtensions.begin();
  const auto end = FeederImpl::supportedExtensions.end();
  return(std::find(start, end, boost::to_lower_copy(ext)) != end);
}

ImageFeed::FeederImpl::FeederImpl(const std::string& imagePath, const std::string& calibPath)
: _isInit(false)
, _withCalibration(false)
{
  namespace bf = boost::filesystem;
//    OPENMVG_LOG_DEBUG(imagePath);
  // if it is a json, calibPath is neglected
  if(bf::is_regular_file(imagePath))
  {
    const std::string ext = bf::path(imagePath).extension().string();
    // if it is a sfmdata.json
    if(ext == ".json")
    {
      // load the json
      _isInit = sfm::Load(_sfmdata, imagePath, sfm::ESfM_Data(sfm::ESfM_Data::VIEWS | sfm::ESfM_Data::INTRINSICS));
      _viewIterator = _sfmdata.GetViews().begin();
      _sfmMode = true;
    }
    // if it is an image file
    else if(FeederImpl::isSupported(ext))
    {
      _images.push_back(imagePath);
      _withCalibration = !calibPath.empty();
      _sfmMode = false;
      _isInit = true;
    }
    // if it is an image file
    else if(ext == ".txt")
    {
      // we expect a simple txt file with a list of path to images relative to the
      // location of the txt file itself
      std::fstream fs(imagePath, std::ios::in);
      std::string line;
      // parse each line of the text file
      while(getline(fs, line))
      {
        // compose the file name as the base path of the inputPath and
        // the filename just read
        const std::string filename = (bf::path(imagePath).parent_path() / line).string();
        _images.push_back(filename);
      }
      // Close file
      fs.close();
      _withCalibration = !calibPath.empty();
      _sfmMode = false;
      _isInit = true;
    }
    else
    {
      // no other file format are supported
      throw std::invalid_argument("File or mode not yet implemented");
    }
  }
  else if(bf::is_directory(imagePath) || bf::is_directory(bf::path(imagePath).parent_path()))
  {
    std::string folder = imagePath;
    // Recover the pattern : img.@.png (for example)
    std::string filePattern;
    std::regex re;
    if(!bf::is_directory(imagePath))
    {
      filePattern = bf::path(imagePath).filename().string();
      folder = bf::path(imagePath).parent_path().string();
      OPENMVG_LOG_DEBUG("filePattern: " << filePattern);
      std::string regexStr = filePattern;
      // escape "."
      boost::algorithm::replace_all(regexStr, ".", "\\.");
      // recognize # as a digit
      boost::algorithm::replace_all(regexStr, "#", "[0-9]");
      // recognize @ as a sequence of digits
      boost::algorithm::replace_all(regexStr, "@", "[0-9]+");
      re = regexStr;
    }
    else
    {
      OPENMVG_LOG_DEBUG("folder without expression: " << imagePath);
    }
    OPENMVG_LOG_DEBUG("directory feedImage");
    // if it is a directory, list all the images and add them to the list
    bf::directory_iterator iterator(folder);
    // since some OS will provide the files in a random order, first store them
    // in a priority queue and then fill the _image queue with the alphabetical
    // order from the priority queue
    std::priority_queue<std::string,
                    std::vector<std::string>,
                    std::greater<std::string> > tmpSorter;
    for(; iterator != bf::directory_iterator(); ++iterator)
    {
      // get the extension of the current file to check whether it is an image
      const std::string ext = iterator->path().extension().string();
      if(FeederImpl::isSupported(ext))
      {
        const std::string filepath = iterator->path().string();
        const std::string filename = iterator->path().filename().string();
        // If we have a filePattern (a sequence of images), we have to match the regex.
        if(filePattern.empty() || std::regex_match(filename, re))
          tmpSorter.push(filepath);
      }
    }
    // put all the retrieve files inside the queue
    while(!tmpSorter.empty())
    {
      _images.push_back(tmpSorter.top());
      tmpSorter.pop();
    }

    _withCalibration = !calibPath.empty();
    _sfmMode = false;
    _isInit = true;
  }
  else
  {
    throw std::invalid_argument("File or mode not yet implemented");
  }

  // last thing: if _withCalibration is true it means that it is not a json and
  // a path to a calibration file has been passed
  // then load the calibration
  if(_withCalibration)
  {
    // load the calibration from calibPath
    readCalibrationFromFile(calibPath, _camIntrinsics);
  }
}

  bool ImageFeed::FeederImpl::readImage(image::Image<image::RGBColor> &imageRGB,
            cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
            std::string &imageName,
            bool &hasIntrinsics)
  {
    if(!_isInit)
    {
      OPENMVG_LOG_WARNING("Image feed is not initialized ");
      return false;
    }

    if(_images.empty())
      return false;

    if(_currentImageIndex >= _images.size())
      return false;

    imageName = _images[_currentImageIndex];
    OPENMVG_LOG_DEBUG(imageName);

    if(_sfmMode)
    {
      OPENMVG_LOG_WARNING("Error can't use SfM mode on RGB image " << imageName);
      throw std::invalid_argument("Error can't use SfM mode on RGB image " + imageName);
    }

    if(_withCalibration)
    {
      // get the calibration
      camIntrinsics = _camIntrinsics;
      hasIntrinsics = true;
    }
    else
    {
      hasIntrinsics = false;
    }

    if (!image::ReadImage(imageName.c_str(), &imageRGB))
    {
      OPENMVG_LOG_WARNING("Error while opening image " << imageName);
      throw std::invalid_argument("Error while opening image " + imageName);
    }
    return true;
  }

bool ImageFeed::FeederImpl::readImage(image::Image<unsigned char> &imageGray,
                   cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                   std::string &imageName,
                   bool &hasIntrinsics)
{
  if(!_isInit)
  {
    OPENMVG_LOG_WARNING("Image feed is not initialized ");
    return false;
  }

  // dealing with SFM mode
  if(_sfmMode)
  {
    return feedWithJson(imageGray, camIntrinsics, imageName, hasIntrinsics);
  }
  else
  {
    if(_images.empty())
      return false;
    if(_currentImageIndex >= _images.size())
      return false;

    if(_withCalibration)
    {
      // get the calibration
      camIntrinsics = _camIntrinsics;
      hasIntrinsics = true;
    }
    else
    {
      hasIntrinsics = false;
    }
    imageName = _images[_currentImageIndex];
    OPENMVG_LOG_DEBUG(imageName);
    if (!image::ReadImage(imageName.c_str(), &imageGray))
    {
      OPENMVG_LOG_WARNING("Error while opening image " << imageName);
      throw std::invalid_argument("Error while opening image " + imageName);
    }
    return true;
  }
  return true;
}

std::size_t ImageFeed::FeederImpl::nbFrames() const
{
  if(!_isInit)
    return 0;

  if(_sfmMode)
    return _sfmdata.GetViews().size();

  return _images.size();
}

bool ImageFeed::FeederImpl::goToFrame(const unsigned int frame)
{
  if(!_isInit)
  {
    _currentImageIndex = frame;
    OPENMVG_LOG_WARNING("Image feed is not initialized ");
    return false;
  }

  // Reconstruction mode
  if(_sfmMode)
  {
    if(frame >= _sfmdata.GetViews().size())
    {
      _viewIterator = _sfmdata.GetViews().end();
      OPENMVG_LOG_WARNING("The current frame is out of the range.");
      return false;
    }

    _viewIterator = _sfmdata.GetViews().begin();
    std::advance(_viewIterator, frame);
  }
  else
  {
    _currentImageIndex = frame;
    // Image list mode
    if(frame >= _images.size())
    {
      OPENMVG_LOG_WARNING("The current frame is out of the range.");
      return false;
    }
    OPENMVG_LOG_DEBUG("frame " << frame);
  }
  return true;
}

bool ImageFeed::FeederImpl::goToNextFrame()
{
  if(_sfmMode)
  {
    if(_viewIterator == _sfmdata.GetViews().end())
      return false;
    ++_viewIterator;
    if(_viewIterator == _sfmdata.GetViews().end())
      return false;
  }
  else
  {
    ++_currentImageIndex;
    OPENMVG_LOG_DEBUG("next frame " << _currentImageIndex);
    if(_currentImageIndex >= _images.size())
      return false;
  }
  return true;
}

bool ImageFeed::FeederImpl::feedWithJson(image::Image<unsigned char> &imageGray,
                   cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                   std::string &imageName,
                   bool &hasIntrinsics)
{
  // if there are no more images to process
  if(_viewIterator == _sfmdata.GetViews().end())
  {
    return false;
  }

  namespace bf = boost::filesystem;

  // get the image
  const std::string rootPath = _sfmdata.s_root_path;
  const sfm::View *view = _viewIterator->second.get();
  imageName = (bf::path(rootPath) / bf::path(view->s_Img_path)).string();
  if (!image::ReadImage(imageName.c_str(), &imageGray))
  {
    OPENMVG_LOG_WARNING("Error while opening image " << imageName);
    return false;
  }
  // get the associated Intrinsics
  if((view->id_intrinsic == UndefinedIndexT) || (!_sfmdata.GetIntrinsics().count(view->id_intrinsic)))
  {
    OPENMVG_LOG_DEBUG("Image "<< imageName << " does not have associated intrinsics");
    hasIntrinsics = false;
  }
  else
  {
    const cameras::IntrinsicBase * cam = _sfmdata.GetIntrinsics().at(view->id_intrinsic).get();
    if(cam->getType() != cameras::EINTRINSIC::PINHOLE_CAMERA_RADIAL3)
    {
      OPENMVG_LOG_WARNING("Only Pinhole_Intrinsic_Radial_K3 is supported");
      hasIntrinsics = false;
    }
    else
    {
      const cameras::Pinhole_Intrinsic_Radial_K3 * intrinsics = dynamic_cast<const cameras::Pinhole_Intrinsic_Radial_K3*>(cam) ;

      // simply copy values
      camIntrinsics = *intrinsics;
      hasIntrinsics = true;
    }
  }
  ++_viewIterator;
  return true;
}

/*******************************************************************************/
/*                     ImageFeed                                               */
/*******************************************************************************/

ImageFeed::ImageFeed() : _imageFeed(new FeederImpl()) { }

ImageFeed::ImageFeed(const std::string& imagePath, const std::string& calibPath)
    : _imageFeed( new FeederImpl(imagePath, calibPath) ) { }

bool ImageFeed::readImage(image::Image<image::RGBColor> &imageRGB,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &mediaPath,
                     bool &hasIntrinsics)
{
  return(_imageFeed->readImage(imageRGB, camIntrinsics, mediaPath, hasIntrinsics));
}

bool ImageFeed::readImage(image::Image<unsigned char> &imageGray,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &mediaPath,
                     bool &hasIntrinsics)
{
  return(_imageFeed->readImage(imageGray, camIntrinsics, mediaPath, hasIntrinsics));
}

std::size_t ImageFeed::nbFrames() const
{
  return _imageFeed->nbFrames();
}

bool ImageFeed::goToFrame(const unsigned int frame)
{
  return _imageFeed->goToFrame(frame);
}

bool ImageFeed::goToNextFrame()
{
  return _imageFeed->goToNextFrame();
}

bool ImageFeed::isInit() const
{
  return(_imageFeed->isInit());
}

bool ImageFeed::isSupported(const std::string &extension)
{
  std::string ext = boost::to_lower_copy(extension);
  if(ext == ".json" || ext == ".txt")
  {
    return true;
  }
  else
  {
    return FeederImpl::isSupported(ext);
  }
}

ImageFeed::~ImageFeed() { }

}//namespace dataio
}//namespace openMVG<commit_msg>[dataio] ImageFeed : template methods `readImage` and `feedWithJson`<commit_after>#include "ImageFeed.hpp"
#include <openMVG/sfm/sfm_data.hpp>
#include <openMVG/sfm/sfm_data_io.hpp>
#include <openMVG/image/image_io.hpp>

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

#include <queue>
#include <iostream>
#include <fstream>
#include <exception>
#include <regex>
#include <iterator>
#include <string>

namespace openMVG{
namespace dataio{

class ImageFeed::FeederImpl
{
public:

  static bool isSupported(const std::string &ext);

  FeederImpl() : _isInit(false) {}

  FeederImpl(const std::string& imagePath, const std::string& calibPath);

  template<typename T>
  bool readImage(image::Image<T> &image,
                   cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                   std::string &imageName,
                   bool &hasIntrinsics)
  {
    if(!_isInit)
    {
      OPENMVG_LOG_WARNING("Image feed is not initialized ");
      return false;
    }

    // dealing with SFM mode
    if(_sfmMode)
    {
      return feedWithJson(image, camIntrinsics, imageName, hasIntrinsics);
    }
    else
    {
      if(_images.empty())
        return false;
      if(_currentImageIndex >= _images.size())
        return false;

      if(_withCalibration)
      {
        // get the calibration
        camIntrinsics = _camIntrinsics;
        hasIntrinsics = true;
      }
      else
      {
        hasIntrinsics = false;
      }
      imageName = _images[_currentImageIndex];

      OPENMVG_LOG_DEBUG(imageName);

      if (!image::ReadImage(imageName.c_str(), &image))
      {
        OPENMVG_LOG_WARNING("Error while opening image " << imageName);
        throw std::invalid_argument("Error while opening image " + imageName);
      }
      return true;
    }
    return true;
  }

  std::size_t nbFrames() const;

  bool goToFrame(const unsigned int frame);

  bool goToNextFrame();

  bool isInit() const {return _isInit;}

private:

  template<typename T>
  bool feedWithJson(image::Image<T> &image,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &imageName,
                     bool &hasIntrinsics)
  {
    // if there are no more images to process
    if(_viewIterator == _sfmdata.GetViews().end())
    {
      return false;
    }

    namespace bf = boost::filesystem;

    // get the image
    const std::string rootPath = _sfmdata.s_root_path;
    const sfm::View *view = _viewIterator->second.get();
    imageName = (bf::path(rootPath) / bf::path(view->s_Img_path)).string();
    if (!image::ReadImage(imageName.c_str(), &image))
    {
      OPENMVG_LOG_WARNING("Error while opening image " << imageName);
      return false;
    }
    // get the associated Intrinsics
    if((view->id_intrinsic == UndefinedIndexT) || (!_sfmdata.GetIntrinsics().count(view->id_intrinsic)))
    {
      OPENMVG_LOG_DEBUG("Image "<< imageName << " does not have associated intrinsics");
      hasIntrinsics = false;
    }
    else
    {
      const cameras::IntrinsicBase * cam = _sfmdata.GetIntrinsics().at(view->id_intrinsic).get();
      if(cam->getType() != cameras::EINTRINSIC::PINHOLE_CAMERA_RADIAL3)
      {
        OPENMVG_LOG_WARNING("Only Pinhole_Intrinsic_Radial_K3 is supported");
        hasIntrinsics = false;
      }
      else
      {
        const cameras::Pinhole_Intrinsic_Radial_K3 * intrinsics = dynamic_cast<const cameras::Pinhole_Intrinsic_Radial_K3*>(cam) ;

        // simply copy values
        camIntrinsics = *intrinsics;
        hasIntrinsics = true;
      }
    }
    ++_viewIterator;
    return true;
  }

private:
  static const std::vector<std::string> supportedExtensions;

private:
  bool _isInit;
  bool _withCalibration;
  // It contains the images to be fed
  std::vector<std::string> _images;
  cameras::Pinhole_Intrinsic_Radial_K3 _camIntrinsics;

  bool _sfmMode = false;
  sfm::SfM_Data _sfmdata;
  sfm::Views::const_iterator _viewIterator;
  unsigned int _currentImageIndex = 0;
};

const std::vector<std::string> ImageFeed::FeederImpl::supportedExtensions = { ".jpg", ".jpeg", ".png", ".ppm" };

bool ImageFeed::FeederImpl::isSupported(const std::string &ext)
{
  const auto start = FeederImpl::supportedExtensions.begin();
  const auto end = FeederImpl::supportedExtensions.end();
  return(std::find(start, end, boost::to_lower_copy(ext)) != end);
}

ImageFeed::FeederImpl::FeederImpl(const std::string& imagePath, const std::string& calibPath)
: _isInit(false)
, _withCalibration(false)
{
  namespace bf = boost::filesystem;
//    OPENMVG_LOG_DEBUG(imagePath);
  // if it is a json, calibPath is neglected
  if(bf::is_regular_file(imagePath))
  {
    const std::string ext = bf::path(imagePath).extension().string();
    // if it is a sfmdata.json
    if(ext == ".json")
    {
      // load the json
      _isInit = sfm::Load(_sfmdata, imagePath, sfm::ESfM_Data(sfm::ESfM_Data::VIEWS | sfm::ESfM_Data::INTRINSICS));
      _viewIterator = _sfmdata.GetViews().begin();
      _sfmMode = true;
    }
    // if it is an image file
    else if(FeederImpl::isSupported(ext))
    {
      _images.push_back(imagePath);
      _withCalibration = !calibPath.empty();
      _sfmMode = false;
      _isInit = true;
    }
    // if it is an image file
    else if(ext == ".txt")
    {
      // we expect a simple txt file with a list of path to images relative to the
      // location of the txt file itself
      std::fstream fs(imagePath, std::ios::in);
      std::string line;
      // parse each line of the text file
      while(getline(fs, line))
      {
        // compose the file name as the base path of the inputPath and
        // the filename just read
        const std::string filename = (bf::path(imagePath).parent_path() / line).string();
        _images.push_back(filename);
      }
      // Close file
      fs.close();
      _withCalibration = !calibPath.empty();
      _sfmMode = false;
      _isInit = true;
    }
    else
    {
      // no other file format are supported
      throw std::invalid_argument("File or mode not yet implemented");
    }
  }
  else if(bf::is_directory(imagePath) || bf::is_directory(bf::path(imagePath).parent_path()))
  {
    std::string folder = imagePath;
    // Recover the pattern : img.@.png (for example)
    std::string filePattern;
    std::regex re;
    if(!bf::is_directory(imagePath))
    {
      filePattern = bf::path(imagePath).filename().string();
      folder = bf::path(imagePath).parent_path().string();
      OPENMVG_LOG_DEBUG("filePattern: " << filePattern);
      std::string regexStr = filePattern;
      // escape "."
      boost::algorithm::replace_all(regexStr, ".", "\\.");
      // recognize # as a digit
      boost::algorithm::replace_all(regexStr, "#", "[0-9]");
      // recognize @ as a sequence of digits
      boost::algorithm::replace_all(regexStr, "@", "[0-9]+");
      re = regexStr;
    }
    else
    {
      OPENMVG_LOG_DEBUG("folder without expression: " << imagePath);
    }
    OPENMVG_LOG_DEBUG("directory feedImage");
    // if it is a directory, list all the images and add them to the list
    bf::directory_iterator iterator(folder);
    // since some OS will provide the files in a random order, first store them
    // in a priority queue and then fill the _image queue with the alphabetical
    // order from the priority queue
    std::priority_queue<std::string,
                    std::vector<std::string>,
                    std::greater<std::string> > tmpSorter;
    for(; iterator != bf::directory_iterator(); ++iterator)
    {
      // get the extension of the current file to check whether it is an image
      const std::string ext = iterator->path().extension().string();
      if(FeederImpl::isSupported(ext))
      {
        const std::string filepath = iterator->path().string();
        const std::string filename = iterator->path().filename().string();
        // If we have a filePattern (a sequence of images), we have to match the regex.
        if(filePattern.empty() || std::regex_match(filename, re))
          tmpSorter.push(filepath);
      }
    }
    // put all the retrieve files inside the queue
    while(!tmpSorter.empty())
    {
      _images.push_back(tmpSorter.top());
      tmpSorter.pop();
    }

    _withCalibration = !calibPath.empty();
    _sfmMode = false;
    _isInit = true;
  }
  else
  {
    throw std::invalid_argument("File or mode not yet implemented");
  }

  // last thing: if _withCalibration is true it means that it is not a json and
  // a path to a calibration file has been passed
  // then load the calibration
  if(_withCalibration)
  {
    // load the calibration from calibPath
    readCalibrationFromFile(calibPath, _camIntrinsics);
  }
}

std::size_t ImageFeed::FeederImpl::nbFrames() const
{
  if(!_isInit)
    return 0;

  if(_sfmMode)
    return _sfmdata.GetViews().size();

  return _images.size();
}

bool ImageFeed::FeederImpl::goToFrame(const unsigned int frame)
{
  if(!_isInit)
  {
    _currentImageIndex = frame;
    OPENMVG_LOG_WARNING("Image feed is not initialized ");
    return false;
  }

  // Reconstruction mode
  if(_sfmMode)
  {
    if(frame >= _sfmdata.GetViews().size())
    {
      _viewIterator = _sfmdata.GetViews().end();
      OPENMVG_LOG_WARNING("The current frame is out of the range.");
      return false;
    }

    _viewIterator = _sfmdata.GetViews().begin();
    std::advance(_viewIterator, frame);
  }
  else
  {
    _currentImageIndex = frame;
    // Image list mode
    if(frame >= _images.size())
    {
      OPENMVG_LOG_WARNING("The current frame is out of the range.");
      return false;
    }
    OPENMVG_LOG_DEBUG("frame " << frame);
  }
  return true;
}

bool ImageFeed::FeederImpl::goToNextFrame()
{
  if(_sfmMode)
  {
    if(_viewIterator == _sfmdata.GetViews().end())
      return false;
    ++_viewIterator;
    if(_viewIterator == _sfmdata.GetViews().end())
      return false;
  }
  else
  {
    ++_currentImageIndex;
    OPENMVG_LOG_DEBUG("next frame " << _currentImageIndex);
    if(_currentImageIndex >= _images.size())
      return false;
  }
  return true;
}

/*******************************************************************************/
/*                     ImageFeed                                               */
/*******************************************************************************/

ImageFeed::ImageFeed() : _imageFeed(new FeederImpl()) { }

ImageFeed::ImageFeed(const std::string& imagePath, const std::string& calibPath)
    : _imageFeed( new FeederImpl(imagePath, calibPath) ) { }

bool ImageFeed::readImage(image::Image<image::RGBColor> &imageRGB,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &mediaPath,
                     bool &hasIntrinsics)
{
  return(_imageFeed->readImage(imageRGB, camIntrinsics, mediaPath, hasIntrinsics));
}

bool ImageFeed::readImage(image::Image<unsigned char> &imageGray,
                     cameras::Pinhole_Intrinsic_Radial_K3 &camIntrinsics,
                     std::string &mediaPath,
                     bool &hasIntrinsics)
{
  return(_imageFeed->readImage(imageGray, camIntrinsics, mediaPath, hasIntrinsics));
}

std::size_t ImageFeed::nbFrames() const
{
  return _imageFeed->nbFrames();
}

bool ImageFeed::goToFrame(const unsigned int frame)
{
  return _imageFeed->goToFrame(frame);
}

bool ImageFeed::goToNextFrame()
{
  return _imageFeed->goToNextFrame();
}

bool ImageFeed::isInit() const
{
  return(_imageFeed->isInit());
}

bool ImageFeed::isSupported(const std::string &extension)
{
  std::string ext = boost::to_lower_copy(extension);
  if(ext == ".json" || ext == ".txt")
  {
    return true;
  }
  else
  {
    return FeederImpl::isSupported(ext);
  }
}

ImageFeed::~ImageFeed() { }

}//namespace dataio
}//namespace openMVG
<|endoftext|>