<commit_before>/*
 * message queues
 *
 * Based on wine/server/queue.c
 * Copyright (C) 2000 Alexandre Julliard
 *
 * Modifications for ring3k
 * Copyright 2006-2009 Mike McCormack
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <new>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"

#include "ntcall.h"
#include "object.h"
#include "ntwin32.h"
#include "mem.h"
#include "debug.h"
#include "list.h"
#include "timer.h"
#include "win.h"
#include "queue.h"
#include "spy.h"

DEFAULT_DEBUG_CHANNEL(queue);

#include "object.inl"

CMSG::CMSG( HWND _hwnd, UINT _message, WPARAM _wparam, LPARAM _lparam ) :
	HWnd( _hwnd ),
	Message( _message ),
	WParam( _wparam ),
	LParam( _lparam )
{
	Time = TIMEOUT::GetTickCount();
}

THREAD_MESSAGE_QUEUE::THREAD_MESSAGE_QUEUE() :
	QuitMessage( 0 ),
	ExitCode( 0 )
{
}

THREAD_MESSAGE_QUEUE::~THREAD_MESSAGE_QUEUE()
{
	CMSG *msg;

	while ((msg = MsgList.Head()))
	{
		MsgList.Unlink( msg );
		delete msg;
	}
}

bool THREAD_MESSAGE_QUEUE::GetQuitMessage( MSG& msg )
{
	bool ret = QuitMessage;
	if (QuitMessage)
	{
		msg.message = WM_QUIT;
		msg.wParam = ExitCode;
		QuitMessage = false;
	}
	return ret;
}

bool THREAD_MESSAGE_QUEUE::GetPaintMessage( HWND Window, MSG& msg )
{
	WINDOW *win = WINDOW::FindWindowToRepaint( Window, Current );
	if (!win)
		return FALSE;

	msg.message = WM_PAINT;
	msg.time = TIMEOUT::GetTickCount();
	msg.hwnd = win->handle;

	return TRUE;
}

BOOLEAN THREAD_MESSAGE_QUEUE::IsSignalled( void )
{
	return FALSE;
}

void THREAD_MESSAGE_QUEUE::PostQuitMessage( ULONG ret )
{
	QuitMessage = true;
	ExitCode = ret;
}

BOOL THREAD_MESSAGE_QUEUE::PostMessage(
	HWND Window, UINT Message, WPARAM Wparam, LPARAM Lparam )
{
	MSG_WAITER *waiter = WaiterList.Head();
	if (waiter)
	{
		MSG& msg = waiter->Msg;
		msg.hwnd = Window;
		msg.message = Message;
		msg.wParam = Wparam;
		msg.lParam = Lparam;
		msg.time = TIMEOUT::GetTickCount();
		msg.pt.x = 0;
		msg.pt.y = 0;

		// remove from the list first
		WaiterList.Unlink( waiter );
		SetTimeout( 0 );

		// start the thread (might reschedule here )
		waiter->T->Start();

		return TRUE;
	}

	// no waiter, so store the message
	CMSG* msg = new CMSG( Window, Message, Wparam, Lparam );
	if (!msg)
		return FALSE;
	MsgList.Append( msg );

	// FIXME: wake up a thread that is waiting
	return TRUE;
}

// return true if we copied a message
bool THREAD_MESSAGE_QUEUE::GetPostedMessage( HWND Window, MSG& Message )
{
	CMSG *m = MsgList.Head();
	if (!m)
		return false;

	MsgList.Unlink( m );
	Message.hwnd = m->HWnd;
	Message.message = m->Message;
	Message.wParam = m->WParam;
	Message.lParam = m->LParam;
	Message.time = m->Time;
	Message.pt.x = 0;
	Message.pt.y = 0;
	delete m;

	return true;
}

MSG_WAITER::MSG_WAITER( MSG& m):
	Msg( m )
{
	T = Current;
}

WIN_TIMER::WIN_TIMER( HWND Window, UINT Identifier ) :
	HWnd( Window ),
	Id( Identifier ),
	LParam(0),
	Period(0)
{
	Expiry.QuadPart = 0LL;
}

WIN_TIMER* THREAD_MESSAGE_QUEUE::FindTimer( HWND Window, UINT Identifier )
{
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		WIN_TIMER *t = i;
		if (t->Id != Identifier)
			continue;
		if (t->HWnd != Window )
			continue;
		return t;
	}
	return NULL;
}

void WIN_TIMER::Reset()
{
	Expiry = TIMEOUT::CurrentTime();
	Expiry.QuadPart += Period*10000LL;
}

bool WIN_TIMER::Expired() const
{
	LARGE_INTEGER now = TIMEOUT::CurrentTime();
	return (now.QuadPart >= Expiry.QuadPart);
}

void THREAD_MESSAGE_QUEUE::TimerAdd( WIN_TIMER* timer )
{
	WIN_TIMER *t = NULL;

	// maintain list in order of expiry time
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		t = i;
		if (t->Expiry.QuadPart >= timer->Expiry.QuadPart)
			break;
	}
	if (t)
		TimerList.InsertBefore( t, timer );
	else
		TimerList.Append( timer );
}

bool THREAD_MESSAGE_QUEUE::GetTimerMessage( HWND Window, MSG& msg )
{
	LARGE_INTEGER now = TIMEOUT::CurrentTime();
	WIN_TIMER *t = NULL;
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		t = i;
		// stop searching after we reach a timer that has not expired
		if (t->Expiry.QuadPart > now.QuadPart)
			return false;
		if (Window == NULL || t->HWnd == Window)
			break;
	}

	if (!t)
		return false;

	// remove from the front of the queue
	TimerList.Unlink( t );

	msg.hwnd = t->HWnd;
	msg.message = WM_TIMER;
	msg.wParam = t->Id;
	msg.lParam = (UINT) t->LParam;
	msg.time = TIMEOUT::GetTickCount();
	msg.pt.x = 0;
	msg.pt.y = 0;

	// reset and add back to the queue
	t->Reset();
	TimerAdd( t );

	return true;
}

BOOLEAN THREAD_MESSAGE_QUEUE::SetTimer( HWND Window, UINT Identifier, UINT Elapse, PVOID TimerProc )
{
	WIN_TIMER* timer = FindTimer( Window, Identifier );
	if (timer)
		TimerList.Unlink( timer );
	else
		timer = new WIN_TIMER( Window, Identifier );
	TRACE("adding timer %p hwnd %p id %d\n", timer, Window, Identifier );
	timer->Period = Elapse;
	timer->LParam = TimerProc;
	TimerAdd( timer );
	return TRUE;
}

BOOLEAN THREAD_MESSAGE_QUEUE::KillTimer( HWND Window, UINT Identifier )
{
	WIN_TIMER* timer = FindTimer( Window, Identifier );
	if (!timer)
		return FALSE;
	TRACE("deleting timer %p hwnd %p id %d\n", timer, Window, Identifier );
	TimerList.Unlink( timer );
	delete timer;
	return TRUE;
}

bool THREAD_MESSAGE_QUEUE::GetMessageTimeout( HWND Window, LARGE_INTEGER& timeout )
{
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		WIN_TIMER *t = i;
		if (Window != NULL && t->HWnd != Window)
			continue;
		timeout = t->Expiry;
		return true;
	}
	return false;
}

// return true if we succeeded in copying a message
BOOLEAN THREAD_MESSAGE_QUEUE::GetMessageNoWait(
	MSG& Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	//trace("checking posted messages\n");
	if (GetPostedMessage( Window, Message ))
		return true;

	//trace("checking quit messages\n");
	if (GetQuitMessage( Message ))
		return true;

	//trace("checking paint messages\n");
	if (GetPaintMessage( Window, Message ))
		return true;

	//trace("checking timer messages\n");
	if (GetTimerMessage( Window, Message ))
		return true;

	return false;
}

void THREAD_MESSAGE_QUEUE::SignalTimeout()
{
	MSG_WAITER *waiter = WaiterList.Head();
	if (waiter)
	{
		WaiterList.Unlink( waiter );
		SetTimeout( 0 );

		// start the thread (might reschedule here )
		waiter->T->Start();
	}
}

BOOLEAN THREAD_MESSAGE_QUEUE::GetMessage(
	MSG& Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	if (GetMessageNoWait( Message, Window, MinMessage, MaxMessage))
		return true;

	LARGE_INTEGER t;
	if (GetMessageTimeout( Window, t ))
	{
		//trace("setting timeout %lld\n", t.QuadPart);
		SetTimeout( &t );
	}

	// wait for a message
	// a thread sending a message will restart us
	MSG_WAITER wait( Message );
	WaiterList.Append( &wait );
	Current->Stop();

	return !Current->IsTerminated();
}

BOOLEAN NTAPI NtUserGetMessage(PMSG Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	// no input queue...
	THREAD_MESSAGE_QUEUE* queue = Current->Queue;
	if (!queue)
		return FALSE;

	NTSTATUS r = VerifyForWrite( Message, sizeof *Message );
	if (r != STATUS_SUCCESS)
		return FALSE;

	MSG msg;
	memset( &msg, 0, sizeof msg );
	if (queue->GetMessage( msg, Window, MinMessage, MaxMessage ))
		CopyToUser( Message, &msg, sizeof msg );

	if (OptionTrace)
	{
		fprintf(stderr, "%lx.%lx: %s\n", Current->Process->Id, Current->GetID(), __FUNCTION__);
		fprintf(stderr, " msg.hwnd    = %p\n", msg.hwnd);
		fprintf(stderr, " msg.message = %08x (%s)\n", msg.message, GetMessageName(msg.message));
		fprintf(stderr, " msg.wParam  = %08x\n", msg.wParam);
		fprintf(stderr, " msg.lParam  = %08lx\n", msg.lParam);
		fprintf(stderr, " msg.time    = %08lx\n", msg.time);
		fprintf(stderr, " msg.pt.x    = %08lx\n", msg.pt.x);
		fprintf(stderr, " msg.pt.y    = %08lx\n", msg.pt.y);
	}

	return msg.message != WM_QUIT;
}

BOOLEAN NTAPI NtUserPostMessage( HWND Window, UINT Message, WPARAM Wparam, LPARAM Lparam )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->PostMessage( Window, Message, Wparam, Lparam );
}

BOOLEAN NTAPI NtUserPeekMessage( PMSG Message, HWND Window, UINT MaxMessage, UINT MinMessage, UINT Remove)
{
	THREAD_MESSAGE_QUEUE* queue = Current->Queue;
	if (!queue)
		return FALSE;

	NTSTATUS r = VerifyForWrite( Message, sizeof *Message );
	if (r != STATUS_SUCCESS)
		return FALSE;

	MSG msg;
	memset( &msg, 0, sizeof msg );
	BOOL ret = queue->GetMessageNoWait( msg, Window, MinMessage, MaxMessage );
	if (ret)
		CopyToUser( Message, &msg, sizeof msg );

	return ret;
}

UINT NTAPI NtUserSetTimer( HWND Window, UINT Identifier, UINT Elapse, PVOID TimerProc )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->SetTimer( Window, Identifier, Elapse, TimerProc );
}

BOOLEAN NTAPI NtUserKillTimer( HWND Window, UINT Identifier )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->KillTimer( Window, Identifier );
}
<commit_msg>kernel: Create input queue if it's missing in a call to GetMessage (used by Winlogon when running in setup mode). Leave a warning there, in case something misbehaves. But so far, Wine's behaviour is exactly that: creating message queue if it doesn't exist.<commit_after>/*
 * message queues
 *
 * Based on wine/server/queue.c
 * Copyright (C) 2000 Alexandre Julliard
 *
 * Modifications for ring3k
 * Copyright 2006-2009 Mike McCormack
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <new>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "winternl.h"

#include "ntcall.h"
#include "object.h"
#include "ntwin32.h"
#include "mem.h"
#include "debug.h"
#include "list.h"
#include "timer.h"
#include "win.h"
#include "queue.h"
#include "spy.h"

DEFAULT_DEBUG_CHANNEL(queue);

#include "object.inl"

CMSG::CMSG( HWND _hwnd, UINT _message, WPARAM _wparam, LPARAM _lparam ) :
	HWnd( _hwnd ),
	Message( _message ),
	WParam( _wparam ),
	LParam( _lparam )
{
	Time = TIMEOUT::GetTickCount();
}

THREAD_MESSAGE_QUEUE::THREAD_MESSAGE_QUEUE() :
	QuitMessage( 0 ),
	ExitCode( 0 )
{
}

THREAD_MESSAGE_QUEUE::~THREAD_MESSAGE_QUEUE()
{
	CMSG *msg;

	while ((msg = MsgList.Head()))
	{
		MsgList.Unlink( msg );
		delete msg;
	}
}

bool THREAD_MESSAGE_QUEUE::GetQuitMessage( MSG& msg )
{
	bool ret = QuitMessage;
	if (QuitMessage)
	{
		msg.message = WM_QUIT;
		msg.wParam = ExitCode;
		QuitMessage = false;
	}
	return ret;
}

bool THREAD_MESSAGE_QUEUE::GetPaintMessage( HWND Window, MSG& msg )
{
	WINDOW *win = WINDOW::FindWindowToRepaint( Window, Current );
	if (!win)
		return FALSE;

	msg.message = WM_PAINT;
	msg.time = TIMEOUT::GetTickCount();
	msg.hwnd = win->handle;

	return TRUE;
}

BOOLEAN THREAD_MESSAGE_QUEUE::IsSignalled( void )
{
	return FALSE;
}

void THREAD_MESSAGE_QUEUE::PostQuitMessage( ULONG ret )
{
	QuitMessage = true;
	ExitCode = ret;
}

BOOL THREAD_MESSAGE_QUEUE::PostMessage(
	HWND Window, UINT Message, WPARAM Wparam, LPARAM Lparam )
{
	MSG_WAITER *waiter = WaiterList.Head();
	if (waiter)
	{
		MSG& msg = waiter->Msg;
		msg.hwnd = Window;
		msg.message = Message;
		msg.wParam = Wparam;
		msg.lParam = Lparam;
		msg.time = TIMEOUT::GetTickCount();
		msg.pt.x = 0;
		msg.pt.y = 0;

		// remove from the list first
		WaiterList.Unlink( waiter );
		SetTimeout( 0 );

		// start the thread (might reschedule here )
		waiter->T->Start();

		return TRUE;
	}

	// no waiter, so store the message
	CMSG* msg = new CMSG( Window, Message, Wparam, Lparam );
	if (!msg)
		return FALSE;
	MsgList.Append( msg );

	// FIXME: wake up a thread that is waiting
	return TRUE;
}

// return true if we copied a message
bool THREAD_MESSAGE_QUEUE::GetPostedMessage( HWND Window, MSG& Message )
{
	CMSG *m = MsgList.Head();
	if (!m)
		return false;

	MsgList.Unlink( m );
	Message.hwnd = m->HWnd;
	Message.message = m->Message;
	Message.wParam = m->WParam;
	Message.lParam = m->LParam;
	Message.time = m->Time;
	Message.pt.x = 0;
	Message.pt.y = 0;
	delete m;

	return true;
}

MSG_WAITER::MSG_WAITER( MSG& m):
	Msg( m )
{
	T = Current;
}

WIN_TIMER::WIN_TIMER( HWND Window, UINT Identifier ) :
	HWnd( Window ),
	Id( Identifier ),
	LParam(0),
	Period(0)
{
	Expiry.QuadPart = 0LL;
}

WIN_TIMER* THREAD_MESSAGE_QUEUE::FindTimer( HWND Window, UINT Identifier )
{
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		WIN_TIMER *t = i;
		if (t->Id != Identifier)
			continue;
		if (t->HWnd != Window )
			continue;
		return t;
	}
	return NULL;
}

void WIN_TIMER::Reset()
{
	Expiry = TIMEOUT::CurrentTime();
	Expiry.QuadPart += Period*10000LL;
}

bool WIN_TIMER::Expired() const
{
	LARGE_INTEGER now = TIMEOUT::CurrentTime();
	return (now.QuadPart >= Expiry.QuadPart);
}

void THREAD_MESSAGE_QUEUE::TimerAdd( WIN_TIMER* timer )
{
	WIN_TIMER *t = NULL;

	// maintain list in order of expiry time
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		t = i;
		if (t->Expiry.QuadPart >= timer->Expiry.QuadPart)
			break;
	}
	if (t)
		TimerList.InsertBefore( t, timer );
	else
		TimerList.Append( timer );
}

bool THREAD_MESSAGE_QUEUE::GetTimerMessage( HWND Window, MSG& msg )
{
	LARGE_INTEGER now = TIMEOUT::CurrentTime();
	WIN_TIMER *t = NULL;
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		t = i;
		// stop searching after we reach a timer that has not expired
		if (t->Expiry.QuadPart > now.QuadPart)
			return false;
		if (Window == NULL || t->HWnd == Window)
			break;
	}

	if (!t)
		return false;

	// remove from the front of the queue
	TimerList.Unlink( t );

	msg.hwnd = t->HWnd;
	msg.message = WM_TIMER;
	msg.wParam = t->Id;
	msg.lParam = (UINT) t->LParam;
	msg.time = TIMEOUT::GetTickCount();
	msg.pt.x = 0;
	msg.pt.y = 0;

	// reset and add back to the queue
	t->Reset();
	TimerAdd( t );

	return true;
}

BOOLEAN THREAD_MESSAGE_QUEUE::SetTimer( HWND Window, UINT Identifier, UINT Elapse, PVOID TimerProc )
{
	WIN_TIMER* timer = FindTimer( Window, Identifier );
	if (timer)
		TimerList.Unlink( timer );
	else
		timer = new WIN_TIMER( Window, Identifier );
	TRACE("adding timer %p hwnd %p id %d\n", timer, Window, Identifier );
	timer->Period = Elapse;
	timer->LParam = TimerProc;
	TimerAdd( timer );
	return TRUE;
}

BOOLEAN THREAD_MESSAGE_QUEUE::KillTimer( HWND Window, UINT Identifier )
{
	WIN_TIMER* timer = FindTimer( Window, Identifier );
	if (!timer)
		return FALSE;
	TRACE("deleting timer %p hwnd %p id %d\n", timer, Window, Identifier );
	TimerList.Unlink( timer );
	delete timer;
	return TRUE;
}

bool THREAD_MESSAGE_QUEUE::GetMessageTimeout( HWND Window, LARGE_INTEGER& timeout )
{
	for (WIN_TIMER_ITER i(TimerList); i; i.Next())
	{
		WIN_TIMER *t = i;
		if (Window != NULL && t->HWnd != Window)
			continue;
		timeout = t->Expiry;
		return true;
	}
	return false;
}

// return true if we succeeded in copying a message
BOOLEAN THREAD_MESSAGE_QUEUE::GetMessageNoWait(
	MSG& Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	//trace("checking posted messages\n");
	if (GetPostedMessage( Window, Message ))
		return true;

	//trace("checking quit messages\n");
	if (GetQuitMessage( Message ))
		return true;

	//trace("checking paint messages\n");
	if (GetPaintMessage( Window, Message ))
		return true;

	//trace("checking timer messages\n");
	if (GetTimerMessage( Window, Message ))
		return true;

	return false;
}

void THREAD_MESSAGE_QUEUE::SignalTimeout()
{
	MSG_WAITER *waiter = WaiterList.Head();
	if (waiter)
	{
		WaiterList.Unlink( waiter );
		SetTimeout( 0 );

		// start the thread (might reschedule here )
		waiter->T->Start();
	}
}

BOOLEAN THREAD_MESSAGE_QUEUE::GetMessage(
	MSG& Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	if (GetMessageNoWait( Message, Window, MinMessage, MaxMessage))
		return true;

	LARGE_INTEGER t;
	if (GetMessageTimeout( Window, t ))
	{
		//trace("setting timeout %lld\n", t.QuadPart);
		SetTimeout( &t );
	}

	// wait for a message
	// a thread sending a message will restart us
	MSG_WAITER wait( Message );
	WaiterList.Append( &wait );
	Current->Stop();

	return !Current->IsTerminated();
}

BOOLEAN NTAPI NtUserGetMessage(PMSG Message, HWND Window, ULONG MinMessage, ULONG MaxMessage)
{
	// create a thread message queue if necessary
	if (!Current->Queue)
	{
		WARN("Calling GetMessage for a thread without input queue, creating it!\n");
		Current->Queue = new THREAD_MESSAGE_QUEUE;
	}

	NTSTATUS r = VerifyForWrite( Message, sizeof *Message );
	if (r != STATUS_SUCCESS)
		return FALSE;

	MSG msg;
	memset( &msg, 0, sizeof msg );
	if (Current->Queue->GetMessage(msg, Window, MinMessage, MaxMessage))
		CopyToUser( Message, &msg, sizeof msg );

	if (OptionTrace)
	{
		fprintf(stderr, "%lx.%lx: %s\n", Current->Process->Id, Current->GetID(), __FUNCTION__);
		fprintf(stderr, " msg.hwnd    = %p\n", msg.hwnd);
		fprintf(stderr, " msg.message = %08x (%s)\n", msg.message, GetMessageName(msg.message));
		fprintf(stderr, " msg.wParam  = %08x\n", msg.wParam);
		fprintf(stderr, " msg.lParam  = %08lx\n", msg.lParam);
		fprintf(stderr, " msg.time    = %08lx\n", msg.time);
		fprintf(stderr, " msg.pt.x    = %08lx\n", msg.pt.x);
		fprintf(stderr, " msg.pt.y    = %08lx\n", msg.pt.y);
	}

	return msg.message != WM_QUIT;
}

BOOLEAN NTAPI NtUserPostMessage( HWND Window, UINT Message, WPARAM Wparam, LPARAM Lparam )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->PostMessage( Window, Message, Wparam, Lparam );
}

BOOLEAN NTAPI NtUserPeekMessage( PMSG Message, HWND Window, UINT MaxMessage, UINT MinMessage, UINT Remove)
{
	THREAD_MESSAGE_QUEUE* queue = Current->Queue;
	if (!queue)
		return FALSE;

	NTSTATUS r = VerifyForWrite( Message, sizeof *Message );
	if (r != STATUS_SUCCESS)
		return FALSE;

	MSG msg;
	memset( &msg, 0, sizeof msg );
	BOOL ret = queue->GetMessageNoWait( msg, Window, MinMessage, MaxMessage );
	if (ret)
		CopyToUser( Message, &msg, sizeof msg );

	return ret;
}

UINT NTAPI NtUserSetTimer( HWND Window, UINT Identifier, UINT Elapse, PVOID TimerProc )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->SetTimer( Window, Identifier, Elapse, TimerProc );
}

BOOLEAN NTAPI NtUserKillTimer( HWND Window, UINT Identifier )
{
	WINDOW *win = WindowFromHandle( Window );
	if (!win)
		return FALSE;

	THREAD*& thread = win->GetWinThread();
	assert(thread != NULL);

	return thread->Queue->KillTimer( Window, Identifier );
}
<|endoftext|>


<commit_before>/* simple hash table for kmail.  inspired by QDict */
/* Author: Ronen Tzur <rtzur@shani.net> */

#include "kmdict.h"

#include <string.h>

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

KMDict::KMDict(int size)
{
  init(size);
}

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

KMDict::~KMDict()
{
  clear();
}

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

void KMDict::init(int size)
{
  mSize = size;
  mVecs = new KMDictItem *[mSize];
  memset(mVecs, 0, mSize * sizeof(KMDictItem *));
}

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

void KMDict::clear()
{
  if (!mVecs)
    return;
  for (int i = 0; i < mSize; i++) {
    KMDictItem *item = mVecs[i];
    while (item) {
      KMDictItem *nextItem = item->next;
      delete item;
      item = nextItem;
    }
  }
  delete mVecs;
  mVecs = 0;
}

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

void KMDict::replace(long key, KMDictItem *item)
{
  item->key = key;
  int idx = (unsigned long)key % mSize; // insert in
  item->next = mVecs[idx];              // appropriate
  mVecs[idx] = item;                    // column
  removeFollowing(item, key);           // remove other items with same key
}

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

void KMDict::remove(long key)
{
  int idx = (unsigned long)key % mSize;
  KMDictItem *item = mVecs[idx];

  if (item) {
    if (item->key == key) {             // if first in the column
      mVecs[idx] = item->next;
      delete item;
    } else
      removeFollowing(item, key);       // if deep in the column
  }
}

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

void KMDict::removeFollowing(KMDictItem *item, long key)
{
  while (item) {
    KMDictItem *itemNext = item->next;
    if (itemNext && itemNext->key == key) {
      KMDictItem *itemNextNext = itemNext->next;
      delete itemNext;
      item->next = itemNextNext;
    } else
      item = itemNext;
  }
}

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

KMDictItem *KMDict::find(long key)
{
  int idx = (unsigned long)key % mSize;
  KMDictItem *item = mVecs[idx];
  while (item) {
    if (item->key == key)
      break;
    item = item->next;
  }
  return item;
}
<commit_msg>-  delete mVecs; +  delete [] mVecs;<commit_after>/* simple hash table for kmail.  inspired by QDict */
/* Author: Ronen Tzur <rtzur@shani.net> */

#include "kmdict.h"

#include <string.h>

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

KMDict::KMDict(int size)
{
  init(size);
}

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

KMDict::~KMDict()
{
  clear();
}

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

void KMDict::init(int size)
{
  mSize = size;
  mVecs = new KMDictItem *[mSize];
  memset(mVecs, 0, mSize * sizeof(KMDictItem *));
}

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

void KMDict::clear()
{
  if (!mVecs)
    return;
  for (int i = 0; i < mSize; i++) {
    KMDictItem *item = mVecs[i];
    while (item) {
      KMDictItem *nextItem = item->next;
      delete item;
      item = nextItem;
    }
  }
  delete [] mVecs;
  mVecs = 0;
}

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

void KMDict::replace(long key, KMDictItem *item)
{
  item->key = key;
  int idx = (unsigned long)key % mSize; // insert in
  item->next = mVecs[idx];              // appropriate
  mVecs[idx] = item;                    // column
  removeFollowing(item, key);           // remove other items with same key
}

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

void KMDict::remove(long key)
{
  int idx = (unsigned long)key % mSize;
  KMDictItem *item = mVecs[idx];

  if (item) {
    if (item->key == key) {             // if first in the column
      mVecs[idx] = item->next;
      delete item;
    } else
      removeFollowing(item, key);       // if deep in the column
  }
}

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

void KMDict::removeFollowing(KMDictItem *item, long key)
{
  while (item) {
    KMDictItem *itemNext = item->next;
    if (itemNext && itemNext->key == key) {
      KMDictItem *itemNextNext = itemNext->next;
      delete itemNext;
      item->next = itemNextNext;
    } else
      item = itemNext;
  }
}

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

KMDictItem *KMDict::find(long key)
{
  int idx = (unsigned long)key % mSize;
  KMDictItem *item = mVecs[idx];
  while (item) {
    if (item->key == key)
      break;
    item = item->next;
  }
  return item;
}
<|endoftext|>


<commit_before>#pragma once

#include <tuple>
#include <utility>
#include <core/function_traits.hpp>
#include <core/traits.hpp>
#include <core/tuple_meta.hpp>

namespace fc
{
template <class... ports>
struct mux_port;
template <class op>
struct unloaded_merge_port;
template <class op, class... ports>
struct loaded_merge_port;

struct default_tag {};
struct merge_tag {};
struct mux_tag {};

template <typename T>
struct port_traits
{
	using mux_category = default_tag;
};

template <class... ports>
struct port_traits<mux_port<ports...>>
{
	using mux_category = mux_tag;
};

template <class op>
struct port_traits<unloaded_merge_port<op>>
{
	using mux_category = merge_tag;
};

namespace detail
{
template <bool... vals>
constexpr bool any()
{
	bool values[] = {vals...};
	for (auto value : values)
		if (value)
			return true;
	return false;
}
template <typename... T>
constexpr bool always_false_fun(T...)
{
	return false;
}

template <bool... vals>
constexpr bool all()
{
	bool values[] = {vals...};
	for (auto value : values)
		if (!value)
			return false;
	return true;
}
} // namespace detail

template <class base>
struct node_aware;

struct many_to_many_tag {};
struct one_to_many_tag {};
struct many_to_one_tag {};

template <size_t left_ports, size_t right_ports>
struct mux_traits
{
	static_assert(
	    detail::always_false_fun(left_ports, right_ports),
	    "Only N->N, 1->N and N->1 connections possible between muxed ports. PS: don't try 1->1.");
};
template <size_t ports>
struct mux_traits<ports, ports>
{
	using connection_category = many_to_many_tag;
};
template <size_t ports>
struct mux_traits<ports, 1>
{
	using connection_category = many_to_one_tag;
};
template <size_t ports>
struct mux_traits<1, ports>
{
	using connection_category = one_to_many_tag;
};

template <class... port_ts>
struct mux_port
{
	std::tuple<port_ts...> ports;

private:
	template <class T>
	auto connect(T t, merge_tag)
	{
		static_assert(
		    detail::has_result_of_type<decltype(t.merge), decltype(std::declval<port_ts>()())...>(),
		    "The muxed ports can not be merged using the provided merge function.");
		static_assert(!detail::any<detail::is_derived_from<node_aware, port_ts>::value...>(),
		              "Merge port can not be used with node aware ports. See merge_node.");
		return loaded_merge_port<decltype(t.merge), port_ts...>{t.merge, std::move(ports)};
	}

	template <class other_mux>
	auto connect(other_mux&& other, mux_tag)
	{
		constexpr size_t this_ports = sizeof...(port_ts);
		constexpr size_t other_ports = std::tuple_size<decltype(other.ports)>::value;
		using connection_tag = typename mux_traits<this_ports, other_ports>::connection_category;
		return connect_mux(std::forward<other_mux>(other), connection_tag{});
	}

	template <class other_mux_port>
	auto connect_mux(other_mux_port&& other, many_to_many_tag)
	{
		auto pairwise_connect = [](auto&& l, auto&& r)
		{
			return std::forward<decltype(l)>(l) >> std::forward<decltype(r)>(r);
		};
		return fc::tuple::transform(std::move(ports), std::forward<other_mux_port>(other).ports,
		                            pairwise_connect);
	}

	template <class sink_t>
	auto connect_mux(mux_port<sink_t>&& other, many_to_one_tag)
	{
		sink_t&& sink = std::get<0>(std::move(other).ports);
		auto all_to_sink = [&sink](auto&& port)
		{
			return std::forward<decltype(port)>(port) >> static_cast<sink_t>(sink);
		};
		return fc::tuple::transform(std::move(ports), all_to_sink);
	}

	template <class other_mux_port>
	auto connect_mux(other_mux_port&& other, one_to_many_tag)
	{
		static_assert(
		    sizeof...(port_ts) == 1,
		    "(*this).ports should have a single port; if you are here, your logic must be wrong.");
		using src_t = typename std::tuple_element<0, decltype(ports)>::type;
		src_t&& src = std::get<0>(std::move(ports));
		auto src_to_all = [&src](auto&& port)
		{
			return static_cast<src_t>(src) >> std::forward<decltype(port)>(port);
		};
		return fc::tuple::transform(std::forward<other_mux_port>(other).ports, src_to_all);
	}

	template <class T>
	auto connect(T&& t, default_tag)
	{
		auto connect_to_copy = [&t](auto&& elem)
		{
			// t needs to be copied if it's not an lvalue ref, forward won't work because can't move
			// from smth multiple times.
			return std::forward<decltype(elem)>(elem) >> static_cast<T>(t);
		};
		return mux_from_tuple(fc::tuple::transform(std::move(ports), connect_to_copy));
	}

public:
	template <class T>
	auto operator>>(T&& t)
	{
		using decayed = std::decay_t<T>;
		using tag = typename fc::port_traits<decayed>::mux_category;
		return this->connect(std::forward<T>(t), tag{});
	}
};

template <class T, class... ports,
          class = std::enable_if_t<is_active_source<std::remove_reference_t<T>>{} &&
                                   detail::all<is_connectable<ports>{}...>()>>
auto operator>>(T&& src, mux_port<ports...> mux)
{
	return mux_port<T>{std::forward_as_tuple(std::forward<T>(src))} >> std::move(mux);
}

template <class... port_ts>
auto mux(port_ts&... ports)
{
	return mux_port<std::remove_const_t<port_ts>&...>{std::tie(ports...)};
}

template <class... conn_ts>
mux_port<conn_ts...> mux_from_tuple(std::tuple<conn_ts...> tuple_)
{
	return mux_port<conn_ts...>{std::move(tuple_)};
}

template <class merge_op>
struct unloaded_merge_port
{
	merge_op merge;
};

template <class merge_op, class... port_ts>
struct loaded_merge_port
{
	merge_op op;
	std::tuple<port_ts...> ports;

	auto operator()()
	{
		auto op = this->op;
		auto call_and_apply = [op](auto&&... src)
		{
			return op(std::forward<decltype(src)>(src)()...);
		};
		return tuple::invoke_function(call_and_apply, ports,
		                              std::make_index_sequence<sizeof...(port_ts)>{});
	}
};

template <class merge_op>
auto merge(merge_op op)
{
	return unloaded_merge_port<merge_op>{op};
}
} // namespace fc
<commit_msg>ports: mux: add API documentation.<commit_after>#pragma once

#include <tuple>
#include <utility>
#include <core/function_traits.hpp>
#include <core/traits.hpp>
#include <core/tuple_meta.hpp>

namespace fc
{
template <class... ports>
struct mux_port;
template <class op>
struct unloaded_merge_port;
template <class op, class... ports>
struct loaded_merge_port;

struct default_tag {};
struct merge_tag {};
struct mux_tag {};

/// Traits used to determine whether a muxed port is connecting to a muxed
/// port, a merge port or any other connectable object.
template <typename T>
struct port_traits
{
	using mux_category = default_tag;
};

template <class... ports>
struct port_traits<mux_port<ports...>>
{
	using mux_category = mux_tag;
};

template <class op>
struct port_traits<unloaded_merge_port<op>>
{
	using mux_category = merge_tag;
};

namespace detail
{
/// Helper: check if any of the passed bools are true.
template <bool... vals>
constexpr bool any()
{
	bool values[] = {vals...};
	for (auto value : values)
		if (value)
			return true;
	return false;
}

/** \brief Helper: return false regardless of what the parameters are.
 *
 * Useful for static_assert conditions in templates that are always invalid -
 * prevents them from firing before the template is instantiated.
 */
template <typename... T>
constexpr bool always_false_fun(T...)
{
	return false;
}

/// Helper: check if all of the passed bools are true.
template <bool... vals>
constexpr bool all()
{
	bool values[] = {vals...};
	for (auto value : values)
		if (!value)
			return false;
	return true;
}
} // namespace detail

template <class base>
struct node_aware;

struct many_to_many_tag {};
struct one_to_many_tag {};
struct many_to_one_tag {};

/// Trait used to determine how many muxed ports are being connected on each side.
template <size_t left_ports, size_t right_ports>
struct mux_traits
{
	static_assert(
	    detail::always_false_fun(left_ports, right_ports),
	    "Only N->N, 1->N and N->1 connections possible between muxed ports. PS: don't try 1->1.");
};
template <size_t ports>
struct mux_traits<ports, ports>
{
	using connection_category = many_to_many_tag;
};
template <size_t ports>
struct mux_traits<ports, 1>
{
	using connection_category = many_to_one_tag;
};
template <size_t ports>
struct mux_traits<1, ports>
{
	using connection_category = one_to_many_tag;
};

/** \brief A wrapper around multiple ports that simplifies establishing
 *         *identical* connections.
 *
 * Basically will lead to the following transformation:
 *
 *     mux(a,b,c) >> d       ===>      a >> d
 *                                     b >> d
 *                                     c >> d
 *
 * with special cases for mux(...) >> mux(...), and mux(...) >> merge_port.
 *
 * Mux ports can be used on both sides of a connection but need to be at the
 * ends of a connection chain. Mux ports don't fulfill the concept of
 * connectable (or active connectable for that matter) but they do have special
 * overloads of operator>> which allow them to participate in connections.
 */
template <class... port_ts>
struct mux_port
{
	std::tuple<port_ts...> ports;

private:
	/** \brief Overload for connecting to an unloaded_merge_port
	 *
	 * T is expected to be an instantiation of unloaded_merge_port.
	 * T and T.merge are assumed to be copyable.
	 *
	 * \returns loaded_merge_port with the supplied merge operation and the
	 *          ports previously held by *this.
	 */
	template <class T>
	auto connect(T t, merge_tag)
	{
		static_assert(
		    detail::has_result_of_type<decltype(t.merge), decltype(std::declval<port_ts>()())...>(),
		    "The muxed ports can not be merged using the provided merge function.");
		static_assert(!detail::any<detail::is_derived_from<node_aware, port_ts>::value...>(),
		              "Merge port can not be used with node aware ports. See merge_node.");
		return loaded_merge_port<decltype(t.merge), port_ts...>{t.merge, std::move(ports)};
	}

	/** \brief Overload for connecting to another muxed port.
	 *
	 * other_mux is expected to be an instantiation of mux_port, the ports
	 * in *this and in other should have compatible types.
	 * The amount of ports on both sides also needs to be compatible:
	 *
	 *   * N - N
	 *   * 1 - N
	 *   * N - 1
	 *
	 * for N > 1. The appropriate overload of connect_mux is selected using mux_traits.
	 */
	template <class other_mux>
	auto connect(other_mux&& other, mux_tag)
	{
		constexpr size_t this_ports = sizeof...(port_ts);
		constexpr size_t other_ports = std::tuple_size<decltype(other.ports)>::value;
		using connection_tag = typename mux_traits<this_ports, other_ports>::connection_category;
		return connect_mux(std::forward<other_mux>(other), connection_tag{});
	}

	/** \brief Connect each port in *this with each port in other.
	 *
	 * mux-mux connections should be the end of a connection chain.
	 * \returns (if used correctly) std::tuple<port_connections...>
	 */
	template <class other_mux_port>
	auto connect_mux(other_mux_port&& other, many_to_many_tag)
	{
		auto pairwise_connect = [](auto&& l, auto&& r)
		{
			return std::forward<decltype(l)>(l) >> std::forward<decltype(r)>(r);
		};
		return fc::tuple::transform(std::move(ports), std::forward<other_mux_port>(other).ports,
		                            pairwise_connect);
	}

	/** \brief Connect each port in *this with the one (sink) port in other.
	 *
	 * The sink port is copied if it was held by value inside other, or else it
	 * will be passed to the connection as an lvalue.
	 *
	 * \returns std::tuple<port_connections...>
	 */
	template <class sink_t>
	auto connect_mux(mux_port<sink_t>&& other, many_to_one_tag)
	{
		sink_t&& sink = std::get<0>(std::move(other).ports);
		auto all_to_sink = [&sink](auto&& port)
		{
			return std::forward<decltype(port)>(port) >> static_cast<sink_t>(sink);
		};
		return fc::tuple::transform(std::move(ports), all_to_sink);
	}

	/** \brief Connect each port in other with the (source) port in *this.
	 *
	 * The source port will be copied, for each connection, if it was held by
	 * value inside *this, otherwise it will be connected as an lvalue.
	 *
	 * \returns std::tuple<port_connections...>
	 */
	template <class other_mux_port>
	auto connect_mux(other_mux_port&& other, one_to_many_tag)
	{
		static_assert(
		    sizeof...(port_ts) == 1,
		    "(*this).ports should have a single port; if you are here, your logic must be wrong.");
		using src_t = typename std::tuple_element<0, decltype(ports)>::type;
		src_t&& src = std::get<0>(std::move(ports));
		auto src_to_all = [&src](auto&& port)
		{
			return static_cast<src_t>(src) >> std::forward<decltype(port)>(port);
		};
		return fc::tuple::transform(std::forward<other_mux_port>(other).ports, src_to_all);
	}

	/** \brief Overload for connecting all ports in *this with a connectable.
	 *
	 * \param T the connectable - will be copied unless it is an lvalue.
	 * \returns mux_port<connection...> (or mux_port<port_connection...>)
	 */
	template <class T>
	auto connect(T&& t, default_tag)
	{
		auto connect_to_copy = [&t](auto&& elem)
		{
			// t needs to be copied if it's not an lvalue ref, forward won't work because can't move
			// from smth multiple times.
			return std::forward<decltype(elem)>(elem) >> static_cast<T>(t);
		};
		return mux_from_tuple(fc::tuple::transform(std::move(ports), connect_to_copy));
	}

public:
	/// Function to forward to the correct connect overload based on the type of T.
	template <class T>
	auto operator>>(T&& t)
	{
		using decayed = std::decay_t<T>;
		using tag = typename fc::port_traits<decayed>::mux_category;
		return this->connect(std::forward<T>(t), tag{});
	}
};

/// Connect src with all ports in mux. Useful only with event_sources.
template <class T, class... ports,
          class = std::enable_if_t<is_active_source<std::remove_reference_t<T>>{} &&
                                   detail::all<is_connectable<ports>{}...>()>>
auto operator>>(T&& src, mux_port<ports...> mux)
{
	return mux_port<T>{std::forward_as_tuple(std::forward<T>(src))} >> std::move(mux);
}

/** \brief Create a mux port from lvalue references to the supplied ports.
 *
 * \params ports should be non-const lvalue references to ports.
 */
template <class... port_ts>
auto mux(port_ts&... ports)
{
	return mux_port<std::remove_const_t<port_ts>&...>{std::tie(ports...)};
}

template <class... conn_ts>
mux_port<conn_ts...> mux_from_tuple(std::tuple<conn_ts...> tuple_)
{
	return mux_port<conn_ts...>{std::move(tuple_)};
}

/// A merge port that is not connected to a mux_port yet. Think of this as a proxy.
template <class merge_op>
struct unloaded_merge_port
{
	merge_op merge;
};

/** \brief A merge_port with a merge operation and a set of ports (connectables).
 *
 * If a connectable is held by value then loaded_merge_port is the owner of
 * that connectable.
 */
template <class merge_op, class... port_ts>
struct loaded_merge_port
{
	merge_op op;
	std::tuple<port_ts...> ports;

	auto operator()()
	{
		auto op = this->op;
		auto call_and_apply = [op](auto&&... src)
		{
			return op(std::forward<decltype(src)>(src)()...);
		};
		return tuple::invoke_function(call_and_apply, ports,
		                              std::make_index_sequence<sizeof...(port_ts)>{});
	}
};

/// Create a merge_port proxy that only holds the merge operation.
template <class merge_op>
auto merge(merge_op op)
{
	return unloaded_merge_port<merge_op>{op};
}
} // namespace fc
<|endoftext|>


<commit_before>//! Copyright (c) 2014 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include "global.h"
#include "user_data.h"
#include "user_cache.h"

UserCache::UserCache(void)
  : redis_(static_cast<redisContext*>(NULL)) {
}

UserCache::~UserCache(void) {
}

bool UserCache::Init(const char* addr, int port) {
  struct timeval tv = {1, 500000};
  redis_ = util::SmartPtr<redisContext>(
      redisConnectWithTimeout(addr, port, tv),
      redisFree);

  if (NULL == redis_.Get() || 0 != redis_->err) {
    fprintf(stderr, "Connect to redis-server %s:%d FAILED\n", addr, port);
    return false;
  }

  return true;
}

void UserCache::Destroy(void) {
}

bool UserCache::Get(const std::string& account, UserData& data) {
  return true;
}

bool UserCache::Set(const std::string& account, const UserData& data) {
  return true;
}

bool UserCache::Del(const std::string& account) {
  return true;
}
<commit_msg>implementation of global user cache<commit_after>//! Copyright (c) 2014 ASMlover. All rights reserved.
//!
//! Redistribution and use in source and binary forms, with or without
//! modification, are permitted provided that the following conditions
//! are met:
//!
//!  * Redistributions of source code must retain the above copyright
//!    notice, this list ofconditions and the following disclaimer.
//!
//!  * Redistributions in binary form must reproduce the above copyright
//!    notice, this list of conditions and the following disclaimer in
//!    the documentation and/or other materialsprovided with the
//!    distribution.
//!
//! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
//! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
//! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
//! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
//! COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
//! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
//! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
//! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
//! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
//! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
//! POSSIBILITY OF SUCH DAMAGE.
#include "global.h"
#include "user_data.h"
#include "user_cache.h"

UserCache::UserCache(void)
  : redis_(static_cast<redisContext*>(NULL)) {
}

UserCache::~UserCache(void) {
}

bool UserCache::Init(const char* addr, int port) {
  struct timeval tv = {1, 500000};
  redis_ = util::SmartPtr<redisContext>(
      redisConnectWithTimeout(addr, port, tv),
      redisFree);

  if (NULL == redis_.Get() || 0 != redis_->err) {
    fprintf(stderr, "Connect to redis-server %s:%d FAILED\n", addr, port);
    return false;
  }

  return true;
}

void UserCache::Destroy(void) {
}

bool UserCache::Get(const std::string& account, UserData& data) {
  util::SmartPtr<redisReply> reply(
      static_cast<redisReply*>(redisCommand(
          redis_.Get(), "exists %s", account.c_str())),
      freeReplyObject);
  if (NULL == reply.Get())
    return false;

  if (REDIS_REPLY_INTEGER != reply->type)
    return false;
  if (0 == reply->integer)
    return false;

  reply = util::SmartPtr<redisReply>(
      static_cast<redisReply*>(redisCommand(
          redis_.Get(),
          "hmget %s "
          "account "
          "user_id "
          "user_name "
          "gender "
          "face "
          "level "
          "exp "
          "scores "
          "coins "
          "win_count "
          "lost_count "
          "flee_count "
          "win_streak "
          "play_time "
          "login_count "
          "reg_time "
          "reg_addr "
          "last_login_time "
          "last_login_addr",
          account.c_str())),
      freeReplyObject);
  if (REDIS_REPLY_ARRAY != reply->type)
    return false;

  data.account          = reply->element[0]->str;
  data.user_id          = atoi(reply->element[1]->str);
  data.user_name        = reply->element[2]->str;
  data.gender           = static_cast<UserData::GenderType>(
                            atoi(reply->element[3]->str));
  data.face             = atoi(reply->element[4]->str);
  data.level            = atoi(reply->element[5]->str);
  data.exp              = atoi(reply->element[6]->str);
  data.scores           = atoi(reply->element[7]->str);
  data.coins            = atoi(reply->element[8]->str);
  data.win_count        = atoi(reply->element[9]->str);
  data.lost_count       = atoi(reply->element[10]->str);
  data.flee_count       = atoi(reply->element[11]->str);
  data.win_streak       = atoi(reply->element[12]->str);
  data.play_time        = atoi(reply->element[13]->str);
  data.login_count      = atoi(reply->element[14]->str);
  data.reg_time         = atoi(reply->element[15]->str);
  data.reg_addr         = atoi(reply->element[16]->str);
  data.last_login_time  = atoi(reply->element[17]->str);
  data.last_login_addr  = atoi(reply->element[18]->str);

  return true;
}

bool UserCache::Set(const std::string& account, const UserData& data) {
  util::SmartPtr<redisReply> reply(
      static_cast<redisReply*>(redisCommand(
          redis_.Get(),
          "hmset %s "
          "account %s "
          "user_id %u "
          "user_name %s "
          "gender %u "
          "face %u "
          "level %u "
          "exp %u "
          "scores %u "
          "coins %u "
          "win_count %u "
          "lost_counta %u "
          "flee_count %u "
          "win_streak %u "
          "play_time %u "
          "login_count %u "
          "reg_time %u "
          "reg_addr %u "
          "last_login_time %u "
          "last_login_addr %u",
          data.account.c_str(),
          data.user_id,
          data.user_name.c_str(),
          data.gender,
          data.face,
          data.level,
          data.exp,
          data.scores,
          data.coins,
          data.win_count,
          data.lost_count,
          data.flee_count,
          data.win_streak,
          data.play_time,
          data.login_count,
          data.reg_time,
          data.reg_addr,
          data.last_login_time,
          data.last_login_addr)),
      freeReplyObject);

  if (0 == reply->len)
    return false;
  if (0 != strcmp("OK", reply->str))
    return false;

  return true;
}

bool UserCache::Del(const std::string& account) {
  util::SmartPtr<redisReply> reply(
      static_cast<redisReply*>(redisCommand(
          redis_.Get(), "del %s", account.c_str())),
      freeReplyObject);

  return (1 == reply->integer);
}
<|endoftext|>


<commit_before>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {   25001, bts::blockchain::block_id_type( "f5bbb4c5728d809e3d0877354964ea24e9961904" ) },
    {  120001, bts::blockchain::block_id_type( "1557fee97884c893aaebba9a1fed803e7fd005d9" ) },
    {  129601, bts::blockchain::block_id_type( "18bcec3430d35538470d7fddc2a51a28cb71fcde" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  187001, bts::blockchain::block_id_type( "72d06a6ba3e79c02327d8048852f9e51b6c8ea71" ) },
    {  237501, bts::blockchain::block_id_type( "42d7bb317f51082f7faffee3f7c79bf59f47acac" ) },
    {  549500, bts::blockchain::block_id_type( "e2e7d94a4076e051f882ee4587d3a1ba07b97db4" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<commit_msg>Update checkpoint<commit_after>#pragma once
#include <bts/blockchain/types.hpp>

namespace bts { namespace blockchain {

static std::map<uint32_t, bts::blockchain::block_id_type> CHECKPOINT_BLOCKS
{
    {       1, bts::blockchain::block_id_type( "8523e28fde6eed4eb749a84e28c9c7b56870c9cc" ) },
    {   25001, bts::blockchain::block_id_type( "f5bbb4c5728d809e3d0877354964ea24e9961904" ) },
    {  120001, bts::blockchain::block_id_type( "1557fee97884c893aaebba9a1fed803e7fd005d9" ) },
    {  129601, bts::blockchain::block_id_type( "18bcec3430d35538470d7fddc2a51a28cb71fcde" ) },
    {  172718, bts::blockchain::block_id_type( "e452dd44902bc86110923285da03ac12e8cfbe6f" ) },
    {  173585, bts::blockchain::block_id_type( "1d1695bc8ebd3ebae0168007afb2912269adbef1" ) },
    {  187001, bts::blockchain::block_id_type( "72d06a6ba3e79c02327d8048852f9e51b6c8ea71" ) },
    {  237501, bts::blockchain::block_id_type( "42d7bb317f51082f7faffee3f7c79bf59f47acac" ) },
    {  583500, bts::blockchain::block_id_type( "28daf0ea584f3988bf9449fe6119f9e69a4f0bb9" ) }
};

// Initialized in load_checkpoints()
static uint32_t LAST_CHECKPOINT_BLOCK_NUM = 0;

} } // bts::blockchain
<|endoftext|>


<commit_before>/**
 * @file
 */
#include "bi/visitor/Resolver.hpp"

#include "bi/visitor/Gatherer.hpp"
#include "bi/exception/all.hpp"

bi::Resolver::Resolver(Scope* scope) :
    inInputs(false),
    membershipScope(nullptr) {
  if (scope) {
    push(scope);
  }
}

bi::Resolver::~Resolver() {
  //
}

void bi::Resolver::modify(File* o) {
  if (o->state == File::RESOLVING) {
    throw CyclicImportException(o);
  } else if (o->state == File::UNRESOLVED) {
    o->state = File::RESOLVING;
    o->scope = new Scope();
    files.push(o);
    push(o->scope.get());
    o->imports = o->imports->accept(this);
    o->root = o->root->accept(this);
    undefer();
    pop();
    files.pop();
    o->state = File::RESOLVED;
  }
}

bi::Expression* bi::Resolver::modify(ExpressionList* o) {
  Modifier::modify(o);
  o->type = new TypeList(o->head->type->accept(&cloner),
      o->tail->type->accept(&cloner));
  o->type = o->type->accept(this);
  return o;
}

bi::Expression* bi::Resolver::modify(ParenthesesExpression* o) {
  Modifier::modify(o);
  o->type = new ParenthesesType(o->single->type->accept(&cloner));
  o->type = o->type->accept(this);
  return o;
}

bi::Expression* bi::Resolver::modify(Range* o) {
  Modifier::modify(o);
  return o;
}

bi::Expression* bi::Resolver::modify(Member* o) {
  o->left = o->left->accept(this);

  ModelReference* ref = dynamic_cast<ModelReference*>(o->left->type.get());
  if (ref) {
    membershipScope = ref->target->scope.get();
  } else {
    RandomType* random = dynamic_cast<RandomType*>(o->left->type.get());
    if (random) {
      membershipScope = random->scope.get();
    }
  }
  if (!membershipScope) {
    throw MemberException(o);
  }
  o->right = o->right->accept(this);
  o->type = o->right->type->accept(&cloner)->accept(this);
  return o;
}

bi::Expression* bi::Resolver::modify(This* o) {
  if (!model()) {
    throw ThisException(o);
  } else {
    Modifier::modify(o);
    o->type = new ModelReference(model()->name, new EmptyExpression(),
        nullptr, model());
  }
  return o;
}

bi::Expression* bi::Resolver::modify(BracketsExpression* o) {
  Modifier::modify(o);

  ModelReference* ref = dynamic_cast<ModelReference*>(o->single->type.get());
  assert(ref);  ///@todo Exception

  const int typeSize = ref->ndims;
  const int indexSize = o->brackets->tupleSize();
  const int indexDims = o->brackets->tupleDims();

  assert(typeSize == indexSize);  ///@todo Exception
  ref = new ModelReference(ref->name, indexDims);

  o->type = ref->accept(this);

  return o;
}

bi::Expression* bi::Resolver::modify(VarReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->type->assignable = o->target->type->assignable;

  /* substitute with random variable if possible */
  RandomReference* random = new RandomReference(o);
  try {
    random->accept(this);
  } catch (UnresolvedReferenceException e) {
    delete random;
    return o;
  }

  return random;
}

bi::Expression* bi::Resolver::modify(FuncReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->form = o->target->form;

  if (o->isAssignment()) {
    if (inInputs) {
      o->getLeft()->type->assignable = true;
    } else if (!o->getLeft()->type->assignable) {
      throw NotAssignableException(o);
    }
  }

  Gatherer<VarParameter> gatherer;
  o->target->parens->accept(&gatherer);
  for (auto iter = gatherer.gathered.begin(); iter != gatherer.gathered.end();
      ++iter) {
    o->args.push_back((*iter)->arg);
  }

  return o;
}

bi::Expression* bi::Resolver::modify(RandomReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->type->assignable = true;
  o->right->type = o->target->right->type->accept(&cloner)->accept(this);
  return o;
}

bi::Type* bi::Resolver::modify(ModelReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  return o;
}

bi::Expression* bi::Resolver::modify(VarParameter* o) {
  Modifier::modify(o);
  if (!inInputs) {
    o->type->assignable = true;
  }
  if (!o->name->isEmpty()) {
    top()->add(o);
  }
  return o;
}

bi::Expression* bi::Resolver::modify(FuncParameter* o) {
  push();
  inInputs = true;
  o->parens = o->parens->accept(this);
  inInputs = false;
  o->result = o->result->accept(this);
  o->type = o->result->type->accept(&cloner)->accept(this);
  defer(o->braces.get());
  o->scope = pop();
  top()->add(o);

  if (o->isAssignment()) {
    o->getLeft()->type->assignable = true;
  }

  Gatherer<VarParameter> gatherer1;
  o->parens->accept(&gatherer1);
  o->inputs = gatherer1.gathered;

  Gatherer<VarParameter> gatherer2;
  o->result->accept(&gatherer2);
  o->outputs = gatherer2.gathered;

  return o;
}

bi::Expression* bi::Resolver::modify(RandomParameter* o) {
  Modifier::modify(o);
  if (!inInputs && !o->left->type->assignable) {
    throw NotAssignableException(o->left.get());
  } else {
    o->left->type->assignable = true;
  }
  o->right->type->assignable = true;
  o->type = new RandomType(o->left->type->accept(&cloner),
      o->right->type->accept(&cloner));
  o->type->accept(this);

  if (!inInputs) {
    o->pull = new FuncReference(o->left->accept(&cloner), new Name("<~"),
        o->right->accept(&cloner));
    o->pull->accept(this);

    o->push = new FuncReference(o->left->accept(&cloner), new Name("~>"),
        o->right->accept(&cloner));
    o->push->accept(this);
  }

  top()->add(o);

  return o;
}

bi::Prog* bi::Resolver::modify(ProgParameter* o) {
  push();
  o->parens = o->parens->accept(this);
  defer(o->braces.get());
  o->scope = pop();
  top()->add(o);

  Gatherer<VarParameter> gatherer1;
  o->parens->accept(&gatherer1);
  o->inputs = gatherer1.gathered;

  return o;
}

bi::Type* bi::Resolver::modify(ModelParameter* o) {
  push();
  o->parens = o->parens->accept(this);
  o->base = o->base->accept(this);
  models.push(o);
  o->braces = o->braces->accept(this);
  models.pop();
  o->scope = pop();
  top()->add(o);

  if (*o->op != "=") {
    /* create constructor */
    Expression* parens1 = o->parens->accept(&cloner);
    VarParameter* result1 = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    o->constructor = new FuncParameter(o->name, parens1, result1,
        new EmptyExpression(), CONSTRUCTOR);
    o->constructor =
        dynamic_cast<FuncParameter*>(o->constructor->accept(this));
    assert(o->constructor);

    /* create assignment operator */
    Expression* right = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    Expression* left = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    Expression* parens2 = new ParenthesesExpression(
        new ExpressionList(left, right));
    Expression* result2 = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    o->assignment = new FuncParameter(new Name("<-"), parens2, result2,
        new EmptyExpression(), ASSIGNMENT_OPERATOR);
    o->assignment = dynamic_cast<FuncParameter*>(o->assignment->accept(this));
    assert(o->assignment);
  }

  return o;
}

bi::Statement* bi::Resolver::modify(Import* o) {
  o->file->accept(this);
  top()->import(o->file->scope.get());
  return o;
}

bi::Statement* bi::Resolver::modify(VarDeclaration* o) {
  Modifier::modify(o);
  o->param->type->assignable = true;
  return o;
}

bi::Statement* bi::Resolver::modify(Conditional* o) {
  push();
  Modifier::modify(o);
  o->scope = pop();
  ///@todo Check that condition is of type Boolean
  return o;
}

bi::Statement* bi::Resolver::modify(Loop* o) {
  push();
  Modifier::modify(o);
  o->scope = pop();
  ///@todo Check that condition is of type Boolean
  return o;
}

bi::Type* bi::Resolver::modify(RandomType* o) {
  push();
  Modifier::modify(o);

  o->x = new VarParameter(new Name("x"), o->left->accept(&cloner));
  o->x->accept(this);
  o->m = new VarParameter(new Name("m"), o->right->accept(&cloner));
  o->m->accept(this);

  o->scope = pop();
  return o;
}

bi::Scope* bi::Resolver::takeMembershipScope() {
  Scope* scope = membershipScope;
  membershipScope = nullptr;
  return scope;
}

bi::Scope* bi::Resolver::top() {
  return scopes.back();
}

void bi::Resolver::push(Scope* scope) {
  if (scope) {
    scopes.push_back(scope);
  } else {
    scopes.push_back(new Scope());
  }
}

bi::Scope* bi::Resolver::pop() {
  /* pre-conditions */
  assert(scopes.size() > 0);

  Scope* res = scopes.back();
  scopes.pop_back();
  return res;
}

template<class ReferenceType>
void bi::Resolver::resolve(ReferenceType* ref, Scope* scope) {
  if (scope) {
    /* use provided scope, usually a membership scope */
    ref->target = scope->resolve(ref);
  } else {
    /* use current stack of scopes */
    ref->target = nullptr;
    for (auto iter = scopes.rbegin(); !ref->target && iter != scopes.rend();
        ++iter) {
      ref->target = (*iter)->resolve(ref);
    }
  }
  if (!ref->target) {
    throw UnresolvedReferenceException(ref);
  }
}

void bi::Resolver::defer(Expression* o) {
  if (files.size() == 1) {
    /* can ignore bodies in imported files */
    defers.push_back(std::make_tuple(o, top(), model()));
  }
}

void bi::Resolver::undefer() {
  if (files.size() == 1) {
    auto iter = defers.begin();
    while (iter != defers.end()) {
      auto o = std::get<0>(*iter);
      auto scope = std::get<1>(*iter);
      auto model = std::get<2>(*iter);

      push(scope);
      models.push(model);
      o->accept(this);
      models.pop();
      pop();
      ++iter;
    }
    defers.clear();
  }
}

bi::ModelParameter* bi::Resolver::model() {
  if (models.empty()) {
    return nullptr;
  } else {
    return models.top();
  }
}

template void bi::Resolver::resolve(VarReference* ref, Scope* scope);
template void bi::Resolver::resolve(FuncReference* ref, Scope* scope);
template void bi::Resolver::resolve(RandomReference* ref, Scope* scope);
template void bi::Resolver::resolve(ModelReference* ref, Scope* scope);
<commit_msg>Member accesses (e.g. `m.x`) now inherit assignability of the object (i.e. `m`).<commit_after>/**
 * @file
 */
#include "bi/visitor/Resolver.hpp"

#include "bi/visitor/Gatherer.hpp"
#include "bi/exception/all.hpp"

bi::Resolver::Resolver(Scope* scope) :
    inInputs(false),
    membershipScope(nullptr) {
  if (scope) {
    push(scope);
  }
}

bi::Resolver::~Resolver() {
  //
}

void bi::Resolver::modify(File* o) {
  if (o->state == File::RESOLVING) {
    throw CyclicImportException(o);
  } else if (o->state == File::UNRESOLVED) {
    o->state = File::RESOLVING;
    o->scope = new Scope();
    files.push(o);
    push(o->scope.get());
    o->imports = o->imports->accept(this);
    o->root = o->root->accept(this);
    undefer();
    pop();
    files.pop();
    o->state = File::RESOLVED;
  }
}

bi::Expression* bi::Resolver::modify(ExpressionList* o) {
  Modifier::modify(o);
  o->type = new TypeList(o->head->type->accept(&cloner),
      o->tail->type->accept(&cloner));
  o->type = o->type->accept(this);
  return o;
}

bi::Expression* bi::Resolver::modify(ParenthesesExpression* o) {
  Modifier::modify(o);
  o->type = new ParenthesesType(o->single->type->accept(&cloner));
  o->type = o->type->accept(this);
  return o;
}

bi::Expression* bi::Resolver::modify(Range* o) {
  Modifier::modify(o);
  return o;
}

bi::Expression* bi::Resolver::modify(Member* o) {
  o->left = o->left->accept(this);

  ModelReference* ref = dynamic_cast<ModelReference*>(o->left->type.get());
  if (ref) {
    membershipScope = ref->target->scope.get();
  } else {
    RandomType* random = dynamic_cast<RandomType*>(o->left->type.get());
    if (random) {
      membershipScope = random->scope.get();
    }
  }
  if (!membershipScope) {
    throw MemberException(o);
  }
  o->right = o->right->accept(this);
  o->right->type->assignable = o->left->type->assignable;
  o->type = o->right->type->accept(&cloner)->accept(this);
  o->type->assignable = o->right->type->assignable;
  return o;
}

bi::Expression* bi::Resolver::modify(This* o) {
  if (!model()) {
    throw ThisException(o);
  } else {
    Modifier::modify(o);
    o->type = new ModelReference(model()->name, new EmptyExpression(),
        nullptr, model());
  }
  return o;
}

bi::Expression* bi::Resolver::modify(BracketsExpression* o) {
  Modifier::modify(o);

  ModelReference* ref = dynamic_cast<ModelReference*>(o->single->type.get());
  assert(ref);  ///@todo Exception

  const int typeSize = ref->ndims;
  const int indexSize = o->brackets->tupleSize();
  const int indexDims = o->brackets->tupleDims();

  assert(typeSize == indexSize);  ///@todo Exception
  ref = new ModelReference(ref->name, indexDims);

  o->type = ref->accept(this);

  return o;
}

bi::Expression* bi::Resolver::modify(VarReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->type->assignable = o->target->type->assignable;

  /* substitute with random variable if possible */
  RandomReference* random = new RandomReference(o);
  try {
    random->accept(this);
  } catch (UnresolvedReferenceException e) {
    delete random;
    return o;
  }

  return random;
}

bi::Expression* bi::Resolver::modify(FuncReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->form = o->target->form;

  if (o->isAssignment()) {
    if (inInputs) {
      o->getLeft()->type->assignable = true;
    } else if (!o->getLeft()->type->assignable) {
      throw NotAssignableException(o);
    }
  }

  Gatherer<VarParameter> gatherer;
  o->target->parens->accept(&gatherer);
  for (auto iter = gatherer.gathered.begin(); iter != gatherer.gathered.end();
      ++iter) {
    o->args.push_back((*iter)->arg);
  }

  return o;
}

bi::Expression* bi::Resolver::modify(RandomReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  o->type = o->target->type->accept(&cloner)->accept(this);
  o->type->assignable = true;
  o->right->type = o->target->right->type->accept(&cloner)->accept(this);
  return o;
}

bi::Type* bi::Resolver::modify(ModelReference* o) {
  Scope* membershipScope = takeMembershipScope();
  Modifier::modify(o);
  resolve(o, membershipScope);
  return o;
}

bi::Expression* bi::Resolver::modify(VarParameter* o) {
  Modifier::modify(o);
  if (!inInputs) {
    o->type->assignable = true;
  }
  if (!o->name->isEmpty()) {
    top()->add(o);
  }
  return o;
}

bi::Expression* bi::Resolver::modify(FuncParameter* o) {
  push();
  inInputs = true;
  o->parens = o->parens->accept(this);
  inInputs = false;
  o->result = o->result->accept(this);
  o->type = o->result->type->accept(&cloner)->accept(this);
  defer(o->braces.get());
  o->scope = pop();
  top()->add(o);

  if (o->isAssignment()) {
    o->getLeft()->type->assignable = true;
  }

  Gatherer<VarParameter> gatherer1;
  o->parens->accept(&gatherer1);
  o->inputs = gatherer1.gathered;

  Gatherer<VarParameter> gatherer2;
  o->result->accept(&gatherer2);
  o->outputs = gatherer2.gathered;

  return o;
}

bi::Expression* bi::Resolver::modify(RandomParameter* o) {
  Modifier::modify(o);
  if (!inInputs && !o->left->type->assignable) {
    throw NotAssignableException(o->left.get());
  } else {
    o->left->type->assignable = true;
  }
  o->right->type->assignable = true;
  o->type = new RandomType(o->left->type->accept(&cloner),
      o->right->type->accept(&cloner));
  o->type->accept(this);

  if (!inInputs) {
    o->pull = new FuncReference(o->left->accept(&cloner), new Name("<~"),
        o->right->accept(&cloner));
    o->pull->accept(this);

    o->push = new FuncReference(o->left->accept(&cloner), new Name("~>"),
        o->right->accept(&cloner));
    o->push->accept(this);
  }

  top()->add(o);

  return o;
}

bi::Prog* bi::Resolver::modify(ProgParameter* o) {
  push();
  o->parens = o->parens->accept(this);
  defer(o->braces.get());
  o->scope = pop();
  top()->add(o);

  Gatherer<VarParameter> gatherer1;
  o->parens->accept(&gatherer1);
  o->inputs = gatherer1.gathered;

  return o;
}

bi::Type* bi::Resolver::modify(ModelParameter* o) {
  push();
  o->parens = o->parens->accept(this);
  o->base = o->base->accept(this);
  models.push(o);
  o->braces = o->braces->accept(this);
  models.pop();
  o->scope = pop();
  top()->add(o);

  if (*o->op != "=") {
    /* create constructor */
    Expression* parens1 = o->parens->accept(&cloner);
    VarParameter* result1 = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    o->constructor = new FuncParameter(o->name, parens1, result1,
        new EmptyExpression(), CONSTRUCTOR);
    o->constructor =
        dynamic_cast<FuncParameter*>(o->constructor->accept(this));
    assert(o->constructor);

    /* create assignment operator */
    Expression* right = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    Expression* left = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    Expression* parens2 = new ParenthesesExpression(
        new ExpressionList(left, right));
    Expression* result2 = new VarParameter(new Name(),
        new ModelReference(o->name, 0, o));
    o->assignment = new FuncParameter(new Name("<-"), parens2, result2,
        new EmptyExpression(), ASSIGNMENT_OPERATOR);
    o->assignment = dynamic_cast<FuncParameter*>(o->assignment->accept(this));
    assert(o->assignment);
  }

  return o;
}

bi::Statement* bi::Resolver::modify(Import* o) {
  o->file->accept(this);
  top()->import(o->file->scope.get());
  return o;
}

bi::Statement* bi::Resolver::modify(VarDeclaration* o) {
  Modifier::modify(o);
  o->param->type->assignable = true;
  return o;
}

bi::Statement* bi::Resolver::modify(Conditional* o) {
  push();
  Modifier::modify(o);
  o->scope = pop();
  ///@todo Check that condition is of type Boolean
  return o;
}

bi::Statement* bi::Resolver::modify(Loop* o) {
  push();
  Modifier::modify(o);
  o->scope = pop();
  ///@todo Check that condition is of type Boolean
  return o;
}

bi::Type* bi::Resolver::modify(RandomType* o) {
  push();
  Modifier::modify(o);

  o->x = new VarParameter(new Name("x"), o->left->accept(&cloner));
  o->x->accept(this);
  o->m = new VarParameter(new Name("m"), o->right->accept(&cloner));
  o->m->accept(this);

  o->scope = pop();
  return o;
}

bi::Scope* bi::Resolver::takeMembershipScope() {
  Scope* scope = membershipScope;
  membershipScope = nullptr;
  return scope;
}

bi::Scope* bi::Resolver::top() {
  return scopes.back();
}

void bi::Resolver::push(Scope* scope) {
  if (scope) {
    scopes.push_back(scope);
  } else {
    scopes.push_back(new Scope());
  }
}

bi::Scope* bi::Resolver::pop() {
  /* pre-conditions */
  assert(scopes.size() > 0);

  Scope* res = scopes.back();
  scopes.pop_back();
  return res;
}

template<class ReferenceType>
void bi::Resolver::resolve(ReferenceType* ref, Scope* scope) {
  if (scope) {
    /* use provided scope, usually a membership scope */
    ref->target = scope->resolve(ref);
  } else {
    /* use current stack of scopes */
    ref->target = nullptr;
    for (auto iter = scopes.rbegin(); !ref->target && iter != scopes.rend();
        ++iter) {
      ref->target = (*iter)->resolve(ref);
    }
  }
  if (!ref->target) {
    throw UnresolvedReferenceException(ref);
  }
}

void bi::Resolver::defer(Expression* o) {
  if (files.size() == 1) {
    /* can ignore bodies in imported files */
    defers.push_back(std::make_tuple(o, top(), model()));
  }
}

void bi::Resolver::undefer() {
  if (files.size() == 1) {
    auto iter = defers.begin();
    while (iter != defers.end()) {
      auto o = std::get<0>(*iter);
      auto scope = std::get<1>(*iter);
      auto model = std::get<2>(*iter);

      push(scope);
      models.push(model);
      o->accept(this);
      models.pop();
      pop();
      ++iter;
    }
    defers.clear();
  }
}

bi::ModelParameter* bi::Resolver::model() {
  if (models.empty()) {
    return nullptr;
  } else {
    return models.top();
  }
}

template void bi::Resolver::resolve(VarReference* ref, Scope* scope);
template void bi::Resolver::resolve(FuncReference* ref, Scope* scope);
template void bi::Resolver::resolve(RandomReference* ref, Scope* scope);
template void bi::Resolver::resolve(ModelReference* ref, Scope* scope);
<|endoftext|>


<commit_before>//
// Projectname: amos-ss16-proj5
//
// Copyright (c) 2016 de.fau.cs.osr.amos2016.gruppe5
//
// This file is part of the AMOS Project 2016 @ FAU
// (Friedrich-Alexander University Erlangen-Nürnberg)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//

#include <opencv2/opencv.hpp>

using namespace cv;

void detectAndDisplay(cv::Mat *image);

const int KEY_ESC = 27;

HOGDescriptor hog;
int main (int argc, const char * argv[])
{
    if(argc < 2){
        std::cout << "Usage " << argv[0] << " video.mp4" << std::endl;
        return 0;
    }

    //set hog detector
    // TO DO: test the daimler detector again with proper settings
    hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());

    //open video
    cv::VideoCapture capture(argv[1]);
    if (!capture.isOpened()){
        std::cout << "Failed to open video" << std::endl;
        return -1;
    }

    //run video
    cv::Mat frame;
    do{
        if (!capture.read(frame))
            break;
        detectAndDisplay(&frame);
        char key = cvWaitKey(10);
        if (key == KEY_ESC)
            break;
    } while(1);

    return 0;
}

void detectAndDisplay(cv::Mat *frame){
    //resize the image to width of 400px to reduce detection time and improve detection accuracy
    //0.3125 is used because the test video is 1280 x 720, so the width resized images is 400px this has to be changed to our image size (best would be no hard coded scaling so other images sizes work too!)

    cv::Mat resizedImage;
    resize(*frame, resizedImage, Size(0, 0), 0.3125, 0.3125, CV_INTER_AREA);

    //detect people in the resizedImage
    std::vector<Rect> foundHumans;
    hog.detectMultiScale(resizedImage, foundHumans, 0.35, Size(4,4), Size(16,16), 1.04, 1);

    //add retangle to found humans
    for (int i=0; i<foundHumans.size(); i++){
        Rect r = foundHumans[i];
        rectangle(resizedImage, r.tl(), r.br(), Scalar(0,255,0), 2);
    }
    imshow("demo", resizedImage);
}
<commit_msg>you can now stop the stream by pressing space<commit_after>//
// Projectname: amos-ss16-proj5
//
// Copyright (c) 2016 de.fau.cs.osr.amos2016.gruppe5
//
// This file is part of the AMOS Project 2016 @ FAU
// (Friedrich-Alexander University Erlangen-Nürnberg)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//

#include <opencv2/opencv.hpp>

using namespace cv;

void detectAndDisplay(cv::Mat *image);

const int KEY_ESC = 27;
const int KEY_SPACE = 32;

HOGDescriptor hog;
int main (int argc, const char * argv[])
{
    if(argc < 2){
        std::cout << "Usage " << argv[0] << " video.mp4" << std::endl;
        return 0;
    }

    //set hog detector
    // TO DO: test the daimler detector again with proper settings
    hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());

    //open video
    cv::VideoCapture capture(argv[1]);
    if (!capture.isOpened()){
        std::cout << "Failed to open video" << std::endl;
        return -1;
    }

    //run video
    cv::Mat frame;
    do{
        if (!capture.read(frame))
            break;
        detectAndDisplay(&frame);
        char key = cvWaitKey(10);

        if (key == KEY_SPACE)
            key = cvWaitKey(0);

        if (key == KEY_ESC)
            break;
    } while(1);

    return 0;
}

void detectAndDisplay(cv::Mat *frame){
    //resize the image to width of 400px to reduce detection time and improve detection accuracy
    //0.3125 is used because the test video is 1280 x 720, so the width resized images is 400px this has to be changed to our image size (best would be no hard coded scaling so other images sizes work too!)

    cv::Mat resizedImage;
    resize(*frame, resizedImage, Size(0, 0), 0.3125, 0.3125, CV_INTER_AREA);

    //detect people in the resizedImage
    std::vector<Rect> foundHumans;
    hog.detectMultiScale(resizedImage, foundHumans, 0.35, Size(4,4), Size(16,16), 1.04, 1);

    //add retangle to found humans
    for (int i=0; i<foundHumans.size(); i++){
        Rect r = foundHumans[i];
        rectangle(resizedImage, r.tl(), r.br(), Scalar(0,255,0), 2);
    }
    imshow("demo", resizedImage);
}
<|endoftext|>


<commit_before>/*
 * 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.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 2011-2012 Heiko Strathmann
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/machine/Machine.h>
#include <shogun/base/Parameter.h>
#include <shogun/mathematics/Math.h>
#include <shogun/base/ParameterMap.h>

using namespace shogun;

CMachine::CMachine() : CSGObject(), m_max_train_time(0), m_labels(NULL),
		m_solver_type(ST_AUTO)
{
	m_data_locked=false;
	m_store_model_features=false;

	SG_ADD(&m_max_train_time, "max_train_time",
	       "Maximum training time.", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_solver_type, "solver_type",
	       "Type of solver.", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**) &m_labels, "labels",
	       "Labels to be used.", MS_NOT_AVAILABLE);
	SG_ADD(&m_store_model_features, "store_model_features",
	       "Should feature data of model be stored after training?", MS_NOT_AVAILABLE);
	SG_ADD(&m_data_locked, "data_locked",
			"Indicates whether data is locked", MS_NOT_AVAILABLE);

	m_parameter_map->put(
		new SGParamInfo("data_locked", CT_SCALAR, ST_NONE, PT_BOOL, 1),
		new SGParamInfo()
	);

	m_parameter_map->finalize_map();
}

CMachine::~CMachine()
{
	SG_UNREF(m_labels);
}

bool CMachine::train(CFeatures* data)
{
	/* not allowed to train on locked data */
	if (m_data_locked)
	{
		SG_ERROR("%s::train data_lock() was called, only train_locked() is"
				" possible. Call data_unlock if you want to call train()\n",
				get_name());
	}

	if (train_require_labels())
	{
		if (m_labels == NULL)
			SG_ERROR("%s@%p: No labels given", get_name(), this);

		m_labels->ensure_valid(get_name());
	}

	bool result = train_machine(data);

	if (m_store_model_features)
		store_model_features();

	return result;
}

void CMachine::set_labels(CLabels* lab)
{
    if (lab != NULL)
        if (!is_label_valid(lab))
            SG_ERROR("Invalid label for %s", get_name());

	SG_UNREF(m_labels);
	SG_REF(lab);
	m_labels = lab;
}

CLabels* CMachine::get_labels()
{
	SG_REF(m_labels);
	return m_labels;
}

void CMachine::set_max_train_time(float64_t t)
{
	m_max_train_time = t;
}

float64_t CMachine::get_max_train_time()
{
	return m_max_train_time;
}

EMachineType CMachine::get_classifier_type()
{
	return CT_NONE;
}

void CMachine::set_solver_type(ESolverType st)
{
	m_solver_type = st;
}

ESolverType CMachine::get_solver_type()
{
	return m_solver_type;
}

void CMachine::set_store_model_features(bool store_model)
{
	m_store_model_features = store_model;
}

void CMachine::data_lock(CLabels* labs, CFeatures* features)
{
	SG_DEBUG("entering %s::data_lock\n", get_name());
	if (!supports_locking())
	{
		{
			SG_ERROR("%s::data_lock(): Machine does not support data locking!\n",
					get_name());
		}
	}

	if (!labs)
	{
		SG_ERROR("%s::data_lock() is not possible will NULL labels!\n",
				get_name());
	}

	/* first set labels */
	set_labels(labs);

	if (m_data_locked)
	{
		SG_ERROR("%s::data_lock() was already called. Dont lock twice!",
				get_name());
	}

	m_data_locked=true;
	post_lock(labs,features);
	SG_DEBUG("leaving %s::data_lock\n", get_name());
}

void CMachine::data_unlock()
{
	SG_DEBUG("entering %s::data_lock\n", get_name());
	if (m_data_locked)
		m_data_locked=false;

	SG_DEBUG("leaving %s::data_lock\n", get_name());
}

CLabels* CMachine::apply(CFeatures* data)
{
	SG_DEBUG("entering %s::apply(%s at %p)\n",
			get_name(), data ? data->get_name() : "NULL", data);

	CLabels* result=NULL;

	switch (get_machine_problem_type())
	{
		case PT_BINARY:
			result=apply_binary(data);
			break;
		case PT_REGRESSION:
			result=apply_regression(data);
			break;
		case PT_MULTICLASS:
			result=apply_multiclass(data);
			break;
		case PT_STRUCTURED:
			result=apply_structured(data);
			break;
		default:
			SG_ERROR("Unknown problem type");
			break;
	}

	SG_DEBUG("leaving %s::apply(%s at %p)\n",
			get_name(), data ? data->get_name() : "NULL", data);

	return result;
}

CLabels* CMachine::apply_locked(SGVector<index_t> indices)
{
	switch (get_machine_problem_type())
	{
		case PT_BINARY:
			return apply_locked_binary(indices);
		case PT_REGRESSION:
			return apply_locked_regression(indices);
		case PT_MULTICLASS:
			return apply_locked_multiclass(indices);
		case PT_STRUCTURED:
			return apply_locked_structured(indices);
		case PT_LATENT:
			return apply_locked_latent(indices);
		default:
			SG_ERROR("Unknown problem type");
			break;
	}
	return NULL;
}

CBinaryLabels* CMachine::apply_binary(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_binary()\n");
	return NULL;
}

CRegressionLabels* CMachine::apply_regression(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_regression()\n");
	return NULL;
}

CMulticlassLabels* CMachine::apply_multiclass(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_multiclass()\n");
	return NULL;
}

CStructuredLabels* CMachine::apply_structured(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_structured()\n");
	return NULL;
}

CLatentLabels* CMachine::apply_latent(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_latent()\n");
	return NULL;
}

CBinaryLabels* CMachine::apply_locked_binary(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_binary(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CRegressionLabels* CMachine::apply_locked_regression(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_regression(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CMulticlassLabels* CMachine::apply_locked_multiclass(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_multiclass(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CStructuredLabels* CMachine::apply_locked_structured(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_structured(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CLatentLabels* CMachine::apply_locked_latent(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_latent(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

<commit_msg>Added missed latent problem handling in apply of machine<commit_after>/*
 * 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.
 *
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Written (W) 2011-2012 Heiko Strathmann
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/machine/Machine.h>
#include <shogun/base/Parameter.h>
#include <shogun/mathematics/Math.h>
#include <shogun/base/ParameterMap.h>

using namespace shogun;

CMachine::CMachine() : CSGObject(), m_max_train_time(0), m_labels(NULL),
		m_solver_type(ST_AUTO)
{
	m_data_locked=false;
	m_store_model_features=false;

	SG_ADD(&m_max_train_time, "max_train_time",
	       "Maximum training time.", MS_NOT_AVAILABLE);
	SG_ADD((machine_int_t*) &m_solver_type, "solver_type",
	       "Type of solver.", MS_NOT_AVAILABLE);
	SG_ADD((CSGObject**) &m_labels, "labels",
	       "Labels to be used.", MS_NOT_AVAILABLE);
	SG_ADD(&m_store_model_features, "store_model_features",
	       "Should feature data of model be stored after training?", MS_NOT_AVAILABLE);
	SG_ADD(&m_data_locked, "data_locked",
			"Indicates whether data is locked", MS_NOT_AVAILABLE);

	m_parameter_map->put(
		new SGParamInfo("data_locked", CT_SCALAR, ST_NONE, PT_BOOL, 1),
		new SGParamInfo()
	);

	m_parameter_map->finalize_map();
}

CMachine::~CMachine()
{
	SG_UNREF(m_labels);
}

bool CMachine::train(CFeatures* data)
{
	/* not allowed to train on locked data */
	if (m_data_locked)
	{
		SG_ERROR("%s::train data_lock() was called, only train_locked() is"
				" possible. Call data_unlock if you want to call train()\n",
				get_name());
	}

	if (train_require_labels())
	{
		if (m_labels == NULL)
			SG_ERROR("%s@%p: No labels given", get_name(), this);

		m_labels->ensure_valid(get_name());
	}

	bool result = train_machine(data);

	if (m_store_model_features)
		store_model_features();

	return result;
}

void CMachine::set_labels(CLabels* lab)
{
    if (lab != NULL)
        if (!is_label_valid(lab))
            SG_ERROR("Invalid label for %s", get_name());

	SG_UNREF(m_labels);
	SG_REF(lab);
	m_labels = lab;
}

CLabels* CMachine::get_labels()
{
	SG_REF(m_labels);
	return m_labels;
}

void CMachine::set_max_train_time(float64_t t)
{
	m_max_train_time = t;
}

float64_t CMachine::get_max_train_time()
{
	return m_max_train_time;
}

EMachineType CMachine::get_classifier_type()
{
	return CT_NONE;
}

void CMachine::set_solver_type(ESolverType st)
{
	m_solver_type = st;
}

ESolverType CMachine::get_solver_type()
{
	return m_solver_type;
}

void CMachine::set_store_model_features(bool store_model)
{
	m_store_model_features = store_model;
}

void CMachine::data_lock(CLabels* labs, CFeatures* features)
{
	SG_DEBUG("entering %s::data_lock\n", get_name());
	if (!supports_locking())
	{
		{
			SG_ERROR("%s::data_lock(): Machine does not support data locking!\n",
					get_name());
		}
	}

	if (!labs)
	{
		SG_ERROR("%s::data_lock() is not possible will NULL labels!\n",
				get_name());
	}

	/* first set labels */
	set_labels(labs);

	if (m_data_locked)
	{
		SG_ERROR("%s::data_lock() was already called. Dont lock twice!",
				get_name());
	}

	m_data_locked=true;
	post_lock(labs,features);
	SG_DEBUG("leaving %s::data_lock\n", get_name());
}

void CMachine::data_unlock()
{
	SG_DEBUG("entering %s::data_lock\n", get_name());
	if (m_data_locked)
		m_data_locked=false;

	SG_DEBUG("leaving %s::data_lock\n", get_name());
}

CLabels* CMachine::apply(CFeatures* data)
{
	SG_DEBUG("entering %s::apply(%s at %p)\n",
			get_name(), data ? data->get_name() : "NULL", data);

	CLabels* result=NULL;

	switch (get_machine_problem_type())
	{
		case PT_BINARY:
			result=apply_binary(data);
			break;
		case PT_REGRESSION:
			result=apply_regression(data);
			break;
		case PT_MULTICLASS:
			result=apply_multiclass(data);
			break;
		case PT_STRUCTURED:
			result=apply_structured(data);
			break;
		case PT_LATENT:
			result=apply_latent(data);
			break;
		default:
			SG_ERROR("Unknown problem type");
			break;
	}

	SG_DEBUG("leaving %s::apply(%s at %p)\n",
			get_name(), data ? data->get_name() : "NULL", data);

	return result;
}

CLabels* CMachine::apply_locked(SGVector<index_t> indices)
{
	switch (get_machine_problem_type())
	{
		case PT_BINARY:
			return apply_locked_binary(indices);
		case PT_REGRESSION:
			return apply_locked_regression(indices);
		case PT_MULTICLASS:
			return apply_locked_multiclass(indices);
		case PT_STRUCTURED:
			return apply_locked_structured(indices);
		case PT_LATENT:
			return apply_locked_latent(indices);
		default:
			SG_ERROR("Unknown problem type");
			break;
	}
	return NULL;
}

CBinaryLabels* CMachine::apply_binary(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_binary()\n");
	return NULL;
}

CRegressionLabels* CMachine::apply_regression(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_regression()\n");
	return NULL;
}

CMulticlassLabels* CMachine::apply_multiclass(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_multiclass()\n");
	return NULL;
}

CStructuredLabels* CMachine::apply_structured(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_structured()\n");
	return NULL;
}

CLatentLabels* CMachine::apply_latent(CFeatures* data)
{
	SG_ERROR("This machine does not support apply_latent()\n");
	return NULL;
}

CBinaryLabels* CMachine::apply_locked_binary(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_binary(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CRegressionLabels* CMachine::apply_locked_regression(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_regression(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CMulticlassLabels* CMachine::apply_locked_multiclass(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_multiclass(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CStructuredLabels* CMachine::apply_locked_structured(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_structured(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

CLatentLabels* CMachine::apply_locked_latent(SGVector<index_t> indices)
{
	SG_ERROR("apply_locked_latent(SGVector<index_t>) is not yet implemented "
			"for %s\n", get_name());
	return NULL;
}

<|endoftext|>