<commit_before>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 2012 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code 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.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

extern "C"
{
#include "q_shared.h"
#include "qcommon.h"
#include "../../libs/findlocale/findlocale.h"
}

#include "../../libs/tinygettext/tinygettext.hpp"
#include <sstream>

using namespace tinygettext;

DictionaryManager trans_manager;
DictionaryManager trans_managergame;
Dictionary        trans_dict;
Dictionary        trans_dictgame;

cvar_t            *language;
bool              enabled = false;

#define _(x) Trans_Gettext(x)

extern "C" void Trans_Init( void )
{
	char      **poFiles;
	int       numPoFiles, i;
	FL_Locale *locale;

	language = Cvar_Get( "language", "", CVAR_ARCHIVE );

	FL_FindLocale( &locale, FL_MESSAGES );

	// Invalid or not found. Just use builtin language.
	if( !locale->lang || !locale->lang[0] || !locale->country || !locale->country[0] )
	{
		Cvar_Set( "language", "en_US" );
	}

	poFiles = FS_ListFiles( "translation/client", ".po", &numPoFiles );

	// This assumes that the names in both folders are the same
	for( i = 0; i < numPoFiles; i++ )
	{
		int ret;
		Dictionary *dict1;
		Dictionary *dict2;
		char *buffer, language[ 6 ];

		if( FS_ReadFile( va( "translation/client/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			dict1 = new Dictionary();
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_manager.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf( "^1ERROR: Could not open client translation: %s\n", poFiles[ i ] );
		}

		if( FS_ReadFile( va( "translation/game/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			dict2 = new Dictionary();
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_managergame.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf( "^1ERROR: Could not open game translation: %s\n", poFiles[ i ] );
		}
	}
	FS_FreeFileList( poFiles );
	trans_dict = trans_manager.get_dictionary( Language::from_env( std::string( language->string ) ) );
	trans_dictgame = trans_managergame.get_dictionary( Language::from_env( std::string( language->string ) ) );
	enabled = true;
	Com_Printf( "Loaded %lu language(s)\n", trans_manager.get_languages().size() );
}

extern "C" const char* Trans_Gettext( const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dict.translate( std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextGame( const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dictgame.translate( std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextPlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	return trans_dict.translate_plural( std::string( msgid ), std::string( msgid_plural ), num ).c_str();
}

extern "C" const char* Trans_GettextGamePlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	return trans_dictgame.translate_plural( std::string( msgid ), std::string( msgid_plural ), num ).c_str();
}
<commit_msg>Force language changing through a menu<commit_after>/*
===========================================================================

Daemon GPL Source Code
Copyright (C) 2012 Unvanquished Developers

This file is part of the Daemon GPL Source Code (Daemon Source Code).

Daemon Source Code 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.

Daemon Source Code 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 Daemon Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Daemon Source Code is also subject to certain additional terms.
You should have received a copy of these additional terms immediately following the
terms and conditions of the GNU General Public License which accompanied the Daemon
Source Code.  If not, please request a copy in writing from id Software at the address
below.

If you have questions concerning this license or the applicable additional terms, you
may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville,
Maryland 20850 USA.

===========================================================================
*/

extern "C"
{
#include "q_shared.h"
#include "qcommon.h"
#include "../../libs/findlocale/findlocale.h"
}

#include "../../libs/tinygettext/tinygettext.hpp"
#include <sstream>

using namespace tinygettext;

DictionaryManager trans_manager;
DictionaryManager trans_managergame;
Dictionary        trans_dict;
Dictionary        trans_dictgame;

cvar_t            *language;
bool              enabled = false;
int               modificationCount=0;

#define _(x) Trans_Gettext(x)

extern "C" void Trans_UpdateLanguage_f( void )
{
	trans_dict = trans_manager.get_dictionary( Language::from_env( std::string( language->string ) ) );
	trans_dictgame = trans_managergame.get_dictionary( Language::from_env( std::string( language->string ) ) );
	Com_Printf( "Switched language to %s\n", Language::from_env( std::string( language->string ) ).get_name().c_str() );
}

extern "C" void Trans_Init( void )
{
	char                **poFiles, langList[ MAX_TOKEN_CHARS ], encList[ MAX_TOKEN_CHARS ];
	int                 numPoFiles, i;
	FL_Locale           *locale;
	std::set<Language>  lang;

	language = Cvar_Get( "language", "", CVAR_ROM );

	FL_FindLocale( &locale, FL_MESSAGES );

	// Invalid or not found. Just use builtin language.
	if( !locale->lang || !locale->lang[0] || !locale->country || !locale->country[0] )
	{
		Cvar_Set( "language", "en_US" );
	}
	else
	{
		Cvar_Set( "language", va( "%s_%s", locale->lang, locale->country ) );
	}

	poFiles = FS_ListFiles( "translation/client", ".po", &numPoFiles );

	// This assumes that the names in both folders are the same
	for( i = 0; i < numPoFiles; i++ )
	{
		int ret;
		Dictionary *dict1;
		Dictionary *dict2;
		char *buffer, language[ 6 ];

		if( FS_ReadFile( va( "translation/client/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			dict1 = new Dictionary();
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_manager.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf( "^1ERROR: Could not open client translation: %s\n", poFiles[ i ] );
		}

		if( FS_ReadFile( va( "translation/game/%s", poFiles[ i ] ), ( void ** ) &buffer ) > 0 )
		{
			dict2 = new Dictionary();
			COM_StripExtension2( poFiles[ i ], language, sizeof( language ) );
			std::stringstream ss( buffer );
			trans_managergame.add_po( poFiles[ i ], ss, Language::from_env( std::string( language ) ) );
			FS_FreeFile( buffer );
		}
		else
		{
			Com_Printf( "^1ERROR: Could not open game translation: %s\n", poFiles[ i ] );
		}
	}
	FS_FreeFileList( poFiles );
	trans_dict = trans_manager.get_dictionary( Language::from_env( std::string( language->string ) ) );
	trans_dictgame = trans_managergame.get_dictionary( Language::from_env( std::string( language->string ) ) );
	lang = trans_manager.get_languages();
	for( std::set<Language>::iterator p = lang.begin(); p != lang.end(); p++ )
	{
		Q_strcat( langList, sizeof( langList ), va( "\"%s\" ", p->get_name().c_str() ) );
		Q_strcat( encList, sizeof( encList ), va( "\"%s_%s\" ", p->get_language().c_str(), p->get_country().c_str() ) );
	}
	Cvar_Set( "trans_languages", langList );
	Cvar_Set( "trans_encodings", encList );
	Com_Printf( "Loaded %lu language(s)\n", lang.size() );
	Cmd_AddCommand( "updatelanguage", Trans_UpdateLanguage_f );
	enabled = true;
}

extern "C" const char* Trans_Gettext( const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dict.translate( std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextGame( const char *msgid )
{
	if( !enabled ) { return msgid; }
	return trans_dictgame.translate( std::string( msgid ) ).c_str();
}

extern "C" const char* Trans_GettextPlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	return trans_dict.translate_plural( std::string( msgid ), std::string( msgid_plural ), num ).c_str();
}

extern "C" const char* Trans_GettextGamePlural( const char *msgid, const char *msgid_plural, int num )
{
	if( !enabled ) { return num == 1 ? msgid : msgid_plural; }
	return trans_dictgame.translate_plural( std::string( msgid ), std::string( msgid_plural ), num ).c_str();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Noriyuki OHKAWA a.k.a. notogawa.
// 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 of conditions 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 materials provided
//   with the distribution.
//
// * Neither the name of Noriyuki OHKAWA and notogawa nor the names of other
//   contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
//
// 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
// OWNER 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 "scoped_global_lock.hpp"

namespace ift {

scoped_global_lock::scoped_global_lock()
{
    while (!__sync_bool_compare_and_swap (&mutex, recurse, recurse+1));
    ++recurse;
}

scoped_global_lock::~scoped_global_lock() throw ()
{
    --recurse;
    __sync_bool_compare_and_swap (&mutex, recurse+1, recurse);
}

bool scoped_global_lock::locked()
{
    return 0 < mutex && recurse == mutex;
}

int scoped_global_lock::mutex = 0;

__thread int scoped_global_lock::recurse = 0;

}
<commit_msg>suggested to add explicit braces around empty body in 'while' statement.<commit_after>// Copyright (c) 2012, Noriyuki OHKAWA a.k.a. notogawa.
// 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 of conditions 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 materials provided
//   with the distribution.
//
// * Neither the name of Noriyuki OHKAWA and notogawa nor the names of other
//   contributors may be used to endorse or promote products derived
//   from this software without specific prior written permission.
//
// 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
// OWNER 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 "scoped_global_lock.hpp"

namespace ift {

scoped_global_lock::scoped_global_lock()
{
    while (!__sync_bool_compare_and_swap (&mutex, recurse, recurse+1)) {}
    ++recurse;
}

scoped_global_lock::~scoped_global_lock() throw ()
{
    --recurse;
    __sync_bool_compare_and_swap (&mutex, recurse+1, recurse);
}

bool scoped_global_lock::locked()
{
    return 0 < mutex && recurse == mutex;
}

int scoped_global_lock::mutex = 0;

__thread int scoped_global_lock::recurse = 0;

}
<|endoftext|>


<commit_before>#include "Genes/Look_Ahead_Gene.h"

#include <cmath>
#include <algorithm>

#include "Utility.h"
#include "Game/Board.h"
#include "Game/Clock.h"

Look_Ahead_Gene::Look_Ahead_Gene() :
    Gene(0.0),
    mean_game_length(100),
    positions_per_second(0)
{
}

void Look_Ahead_Gene::reset_properties() const
{
    properties["Mean Game Length"] = mean_game_length;
    properties["Positions Per Second"] = positions_per_second;
}

void Look_Ahead_Gene::load_properties()
{
    mean_game_length = properties["Mean Game Length"];
    positions_per_second = properties["Positions Per Second"];
}

Look_Ahead_Gene::~Look_Ahead_Gene()
{
}

double Look_Ahead_Gene::positions_to_examine(const Board& board, const Clock& clock) const
{
    auto time_left = clock.time_left(board.whose_turn());
    auto moves_so_far = board.get_game_record().size()/2; // only count moves by this player
    auto moves_left = Math::average_moves_left(mean_game_length, moves_so_far);
    auto time_per_move = time_left/moves_left;
    return positions_per_second*time_per_move; // positions to examine for one move
}

void Look_Ahead_Gene::mutate()
{
    mean_game_length = std::max(1.0, mean_game_length + Random::random_normal(1.0));
    positions_per_second = std::max(0.0, positions_per_second + Random::random_normal(10.0));
}

Look_Ahead_Gene* Look_Ahead_Gene::duplicate() const
{
    return new Look_Ahead_Gene(*this);
}

std::string Look_Ahead_Gene::name() const
{
    return "Look Ahead Gene";
}

double Look_Ahead_Gene::score_board(const Board&, Color) const
{
    return 0.0;
}
<commit_msg>Lower initial estimate of mean game length<commit_after>#include "Genes/Look_Ahead_Gene.h"

#include <cmath>
#include <algorithm>

#include "Utility.h"
#include "Game/Board.h"
#include "Game/Clock.h"

Look_Ahead_Gene::Look_Ahead_Gene() :
    Gene(0.0),
    mean_game_length(50),
    positions_per_second(0)
{
}

void Look_Ahead_Gene::reset_properties() const
{
    properties["Mean Game Length"] = mean_game_length;
    properties["Positions Per Second"] = positions_per_second;
}

void Look_Ahead_Gene::load_properties()
{
    mean_game_length = properties["Mean Game Length"];
    positions_per_second = properties["Positions Per Second"];
}

Look_Ahead_Gene::~Look_Ahead_Gene()
{
}

double Look_Ahead_Gene::positions_to_examine(const Board& board, const Clock& clock) const
{
    auto time_left = clock.time_left(board.whose_turn());
    auto moves_so_far = board.get_game_record().size()/2; // only count moves by this player
    auto moves_left = Math::average_moves_left(mean_game_length, moves_so_far);
    auto time_per_move = time_left/moves_left;
    return positions_per_second*time_per_move; // positions to examine for one move
}

void Look_Ahead_Gene::mutate()
{
    mean_game_length = std::max(1.0, mean_game_length + Random::random_normal(1.0));
    positions_per_second = std::max(0.0, positions_per_second + Random::random_normal(10.0));
}

Look_Ahead_Gene* Look_Ahead_Gene::duplicate() const
{
    return new Look_Ahead_Gene(*this);
}

std::string Look_Ahead_Gene::name() const
{
    return "Look Ahead Gene";
}

double Look_Ahead_Gene::score_board(const Board&, Color) const
{
    return 0.0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012, Cornell University
// 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 of conditions 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 materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// 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 OWNER 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.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

// Google Log
#include <glog/logging.h>

// HyperDex
#include "daemon/communication.h"
#include "daemon/daemon.h"

using hyperdex::communication;
using hyperdex::reconfigure_returncode;

//////////////////////////////// Early Messages ////////////////////////////////

class communication::early_message
{
    public:
        early_message();
        early_message(uint64_t version, uint64_t id,
                      std::auto_ptr<e::buffer> m);
        ~early_message() throw ();

    public:
        uint64_t config_version;
        uint64_t id;
        std::auto_ptr<e::buffer> msg;
};

communication :: early_message :: early_message()
    : config_version(0)
    , id()
    , msg()
{
}

communication :: early_message :: early_message(uint64_t v,
                                                uint64_t i,
                                                std::auto_ptr<e::buffer> m)
    : config_version(v)
    , id(i)
    , msg(m)
{
}

communication :: early_message :: ~early_message() throw ()
{
}

///////////////////////////////// Public Class /////////////////////////////////

communication :: communication(daemon* d)
    : m_daemon(d)
    , m_busybee_mapper(&m_daemon->m_config)
    , m_busybee()
    , m_early_messages()
{
}

communication :: ~communication() throw ()
{
}

bool
communication :: setup(const po6::net::location& bind_to,
                       unsigned threads)
{
    m_busybee.reset(new busybee_mta(&m_busybee_mapper, bind_to, m_daemon->m_us.get(), threads));
    return true;
}

void
communication :: teardown()
{
}

reconfigure_returncode
communication :: prepare(const configuration&,
                         const configuration&,
                         const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

reconfigure_returncode
communication :: reconfigure(const configuration&,
                             const configuration&,
                             const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

reconfigure_returncode
communication :: cleanup(const configuration&,
                         const configuration&,
                         const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

bool
communication :: send(const virtual_server_id& from,
                      const server_id& to,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_VS);

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND " << from << "->" << to << " " << msg_type << " " << msg->hex();
#endif

    if (m_daemon->m_us != m_daemon->m_config.get_server_id(from))
    {
        return false;
    }

    uint8_t mt = static_cast<uint8_t>(msg_type);
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << from.get();

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: send(const virtual_server_id& from,
                      const virtual_server_id& vto,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_VV);

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND " << from << "->" << vto << " " << msg_type << " " << msg->hex();
#endif

    if (m_daemon->m_us != m_daemon->m_config.get_server_id(from))
    {
        return false;
    }

    uint8_t mt = static_cast<uint8_t>(msg_type);
    uint8_t flags = 1;
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << flags << m_daemon->m_config.version() << vto.get() << from.get();
    server_id to = m_daemon->m_config.get_server_id(vto);

    if (to == server_id())
    {
        return false;
    }

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: send(const virtual_server_id& vto,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_SV);

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND ->" << vto << " " << msg_type << " " << msg->hex();
#endif

    uint8_t mt = static_cast<uint8_t>(msg_type);
    uint8_t flags = 0;
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << flags << m_daemon->m_config.version() << vto.get();
    server_id to = m_daemon->m_config.get_server_id(vto);

    if (to == server_id())
    {
        return false;
    }

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: recv(server_id* from,
                      virtual_server_id* vfrom,
                      virtual_server_id* vto,
                      network_msgtype* msg_type,
                      std::auto_ptr<e::buffer>* msg,
                      e::unpacker* up)
{
    // Read messages from the network until we get one that meets the following
    // constraints:
    //  - It is addressed to a virtual_server_id
    //  - The virtual_server_id destination maps to us
    //  - If it comes from a virtual_server_id, that id maps to the sender
    //  - The message version is less than or equal to our current config
    while (true)
    {
        uint64_t id;
        busybee_returncode rc = m_busybee->recv(&id, msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_SHUTDOWN:
                return false;
            case BUSYBEE_DISRUPTED:
                handle_disruption(id);
                continue;
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "busybee unexpectedly returned " << rc;
                continue;
        }

        uint8_t mt;
        uint8_t flags;
        uint64_t version;
        uint64_t vidf;
        uint64_t vidt;
        *up = (*msg)->unpack_from(BUSYBEE_HEADER_SIZE);
        *up = *up >> mt >> flags >> version >> vidt;
        *msg_type = static_cast<network_msgtype>(mt);
        *from = server_id(id);
        *vto = virtual_server_id(vidt);

        if ((flags & 0x1))
        {
            *up = *up >> vidf;
            *vfrom = virtual_server_id(vidf);
        }
        else
        {
            *vfrom = virtual_server_id();
        }

        if (up->error())
        {
            LOG(WARNING) << "dropping message that has a malformed header; here's some hex: " << (*msg)->hex();
            continue;
        }

        bool from_valid = true;
        bool to_valid = m_daemon->m_us == m_daemon->m_config.get_server_id(virtual_server_id(vidt));

        // If this is a virtual-virtual message
        if ((flags & 0x1))
        {
            from_valid = *from == m_daemon->m_config.get_server_id(virtual_server_id(vidf));
        }

        if (from_valid && to_valid)
        {
#ifdef HD_LOG_ALL_MESSAGES
            LOG(INFO) << "RECV " << *from << "->" << *vto << " " << *msg_type << " " << (*msg)->hex();
#endif
            return true;
        }

        // Shove the message back at the client so it fails with a reconfigure.
        if (!(flags & 0x1))
        {
            mt = static_cast<uint8_t>(CONFIGMISMATCH);
            (*msg)->pack_at(BUSYBEE_HEADER_SIZE) << mt;
            m_busybee->send(id, *msg);
        }
        else if (version > m_daemon->m_config.version())
        {
            early_message em(version, id, *msg);
            m_early_messages.push(em);
            continue;
        }
    }
}

void
communication :: handle_disruption(uint64_t)
{
    // XXX
}
<commit_msg>Log messages after filling in the header<commit_after>// Copyright (c) 2012, Cornell University
// 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 of conditions 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 materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// 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 OWNER 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.

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

// Google Log
#include <glog/logging.h>

// HyperDex
#include "daemon/communication.h"
#include "daemon/daemon.h"

using hyperdex::communication;
using hyperdex::reconfigure_returncode;

//////////////////////////////// Early Messages ////////////////////////////////

class communication::early_message
{
    public:
        early_message();
        early_message(uint64_t version, uint64_t id,
                      std::auto_ptr<e::buffer> m);
        ~early_message() throw ();

    public:
        uint64_t config_version;
        uint64_t id;
        std::auto_ptr<e::buffer> msg;
};

communication :: early_message :: early_message()
    : config_version(0)
    , id()
    , msg()
{
}

communication :: early_message :: early_message(uint64_t v,
                                                uint64_t i,
                                                std::auto_ptr<e::buffer> m)
    : config_version(v)
    , id(i)
    , msg(m)
{
}

communication :: early_message :: ~early_message() throw ()
{
}

///////////////////////////////// Public Class /////////////////////////////////

communication :: communication(daemon* d)
    : m_daemon(d)
    , m_busybee_mapper(&m_daemon->m_config)
    , m_busybee()
    , m_early_messages()
{
}

communication :: ~communication() throw ()
{
}

bool
communication :: setup(const po6::net::location& bind_to,
                       unsigned threads)
{
    m_busybee.reset(new busybee_mta(&m_busybee_mapper, bind_to, m_daemon->m_us.get(), threads));
    return true;
}

void
communication :: teardown()
{
}

reconfigure_returncode
communication :: prepare(const configuration&,
                         const configuration&,
                         const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

reconfigure_returncode
communication :: reconfigure(const configuration&,
                             const configuration&,
                             const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

reconfigure_returncode
communication :: cleanup(const configuration&,
                         const configuration&,
                         const server_id&)
{
    // XXX
    return RECONFIGURE_SUCCESS;
}

bool
communication :: send(const virtual_server_id& from,
                      const server_id& to,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_VS);

    if (m_daemon->m_us != m_daemon->m_config.get_server_id(from))
    {
        return false;
    }

    uint8_t mt = static_cast<uint8_t>(msg_type);
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << from.get();

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND " << from << "->" << to << " " << msg_type << " " << msg->hex();
#endif

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: send(const virtual_server_id& from,
                      const virtual_server_id& vto,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_VV);

    if (m_daemon->m_us != m_daemon->m_config.get_server_id(from))
    {
        return false;
    }

    uint8_t mt = static_cast<uint8_t>(msg_type);
    uint8_t flags = 1;
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << flags << m_daemon->m_config.version() << vto.get() << from.get();
    server_id to = m_daemon->m_config.get_server_id(vto);

    if (to == server_id())
    {
        return false;
    }

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND " << from << "->" << vto << " " << msg_type << " " << msg->hex();
#endif

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: send(const virtual_server_id& vto,
                      network_msgtype msg_type,
                      std::auto_ptr<e::buffer> msg)
{
    assert(msg->size() >= HYPERDEX_HEADER_SIZE_SV);

    uint8_t mt = static_cast<uint8_t>(msg_type);
    uint8_t flags = 0;
    msg->pack_at(BUSYBEE_HEADER_SIZE) << mt << flags << m_daemon->m_config.version() << vto.get();
    server_id to = m_daemon->m_config.get_server_id(vto);

    if (to == server_id())
    {
        return false;
    }

#ifdef HD_LOG_ALL_MESSAGES
    LOG(INFO) << "SEND ->" << vto << " " << msg_type << " " << msg->hex();
#endif

    if (to == m_daemon->m_us)
    {
        m_busybee->deliver(to.get(), msg);
    }
    else
    {
        busybee_returncode rc = m_busybee->send(to.get(), msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_DISRUPTED:
                handle_disruption(to.get());
                return false;
            case BUSYBEE_SHUTDOWN:
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "BusyBee unexpectedly returned " << rc;
                return false;
        }
    }

    return true;
}

bool
communication :: recv(server_id* from,
                      virtual_server_id* vfrom,
                      virtual_server_id* vto,
                      network_msgtype* msg_type,
                      std::auto_ptr<e::buffer>* msg,
                      e::unpacker* up)
{
    // Read messages from the network until we get one that meets the following
    // constraints:
    //  - It is addressed to a virtual_server_id
    //  - The virtual_server_id destination maps to us
    //  - If it comes from a virtual_server_id, that id maps to the sender
    //  - The message version is less than or equal to our current config
    while (true)
    {
        uint64_t id;
        busybee_returncode rc = m_busybee->recv(&id, msg);

        switch (rc)
        {
            case BUSYBEE_SUCCESS:
                break;
            case BUSYBEE_SHUTDOWN:
                return false;
            case BUSYBEE_DISRUPTED:
                handle_disruption(id);
                continue;
            case BUSYBEE_POLLFAILED:
            case BUSYBEE_ADDFDFAIL:
            case BUSYBEE_TIMEOUT:
            case BUSYBEE_EXTERNAL:
            default:
                LOG(ERROR) << "busybee unexpectedly returned " << rc;
                continue;
        }

        uint8_t mt;
        uint8_t flags;
        uint64_t version;
        uint64_t vidf;
        uint64_t vidt;
        *up = (*msg)->unpack_from(BUSYBEE_HEADER_SIZE);
        *up = *up >> mt >> flags >> version >> vidt;
        *msg_type = static_cast<network_msgtype>(mt);
        *from = server_id(id);
        *vto = virtual_server_id(vidt);

        if ((flags & 0x1))
        {
            *up = *up >> vidf;
            *vfrom = virtual_server_id(vidf);
        }
        else
        {
            *vfrom = virtual_server_id();
        }

        if (up->error())
        {
            LOG(WARNING) << "dropping message that has a malformed header; here's some hex: " << (*msg)->hex();
            continue;
        }

        bool from_valid = true;
        bool to_valid = m_daemon->m_us == m_daemon->m_config.get_server_id(virtual_server_id(vidt));

        // If this is a virtual-virtual message
        if ((flags & 0x1))
        {
            from_valid = *from == m_daemon->m_config.get_server_id(virtual_server_id(vidf));
        }

        if (from_valid && to_valid)
        {
#ifdef HD_LOG_ALL_MESSAGES
            LOG(INFO) << "RECV " << *from << "->" << *vto << " " << *msg_type << " " << (*msg)->hex();
#endif
            return true;
        }

        // Shove the message back at the client so it fails with a reconfigure.
        if (!(flags & 0x1))
        {
            mt = static_cast<uint8_t>(CONFIGMISMATCH);
            (*msg)->pack_at(BUSYBEE_HEADER_SIZE) << mt;
            m_busybee->send(id, *msg);
        }
        else if (version > m_daemon->m_config.version())
        {
            early_message em(version, id, *msg);
            m_early_messages.push(em);
            continue;
        }
    }
}

void
communication :: handle_disruption(uint64_t)
{
    // XXX
}
<|endoftext|>


<commit_before>#include "extractor/graph_compressor.hpp"

#include "extractor/compressed_edge_container.hpp"
#include "extractor/restriction_map.hpp"
#include "util/dynamic_graph.hpp"
#include "util/node_based_graph.hpp"
#include "util/percent.hpp"

#include "util/simple_logger.hpp"

namespace osrm
{
namespace extractor
{

GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
    : speed_profile(std::move(speed_profile))
{
}

void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
                               const std::unordered_set<NodeID> &traffic_lights,
                               RestrictionMap &restriction_map,
                               util::NodeBasedDynamicGraph &graph,
                               CompressedEdgeContainer &geometry_compressor)
{
    const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
    const unsigned original_number_of_edges = graph.GetNumberOfEdges();

    util::Percent progress(original_number_of_nodes);

    for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
    {
        progress.printStatus(node_v);

        // only contract degree 2 vertices
        if (2 != graph.GetOutDegree(node_v))
        {
            continue;
        }

        // don't contract barrier node
        if (barrier_nodes.end() != barrier_nodes.find(node_v))
        {
            continue;
        }

        // check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
        if (restriction_map.IsViaNode(node_v))
        {
            continue;
        }

        //    reverse_e2   forward_e2
        // u <---------- v -----------> w
        //    ----------> <-----------
        //    forward_e1   reverse_e1
        //
        // Will be compressed to:
        //
        //    reverse_e1
        // u <---------- w
        //    ---------->
        //    forward_e1
        //
        // If the edges are compatible.

        const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
        const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
        BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
        BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v));
        const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
        BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
        BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v));

        const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
        const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);

        const NodeID node_w = graph.GetTarget(forward_e2);
        BOOST_ASSERT(SPECIAL_NODEID != node_w);
        BOOST_ASSERT(node_v != node_w);
        const NodeID node_u = graph.GetTarget(reverse_e2);
        BOOST_ASSERT(SPECIAL_NODEID != node_u);
        BOOST_ASSERT(node_u != node_v);

        const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
        BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
        BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
        const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
        BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
        BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));

        const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
        const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);

        if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
        {
            continue;
        }

        // this case can happen if two ways with different names overlap
        if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
            fwd_edge_data2.name_id != rev_edge_data2.name_id)
        {
            continue;
        }

        if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) &&
            rev_edge_data1.IsCompatibleTo(rev_edge_data2))
        {
            BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
                         graph.GetEdgeData(reverse_e1).name_id);
            BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
                         graph.GetEdgeData(reverse_e2).name_id);

            // Get distances before graph is modified
            const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
            const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;

            BOOST_ASSERT(0 != forward_weight1);
            BOOST_ASSERT(0 != forward_weight2);

            const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
            const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;

            BOOST_ASSERT(0 != reverse_weight1);
            BOOST_ASSERT(0 != reverse_weight2);

            const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();

            // add weight of e2's to e1
            graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
            graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;
            if (has_node_penalty)
            {
                graph.GetEdgeData(forward_e1).distance += speed_profile.traffic_signal_penalty;
                graph.GetEdgeData(reverse_e1).distance += speed_profile.traffic_signal_penalty;
            }

            // extend e1's to targets of e2's
            graph.SetTarget(forward_e1, node_w);
            graph.SetTarget(reverse_e1, node_u);

            // remove e2's (if bidir, otherwise only one)
            graph.DeleteEdge(node_v, forward_e2);
            graph.DeleteEdge(node_v, reverse_e2);

            // update any involved turn restrictions
            restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
            restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);

            restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
            restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);

            // store compressed geometry in container
            geometry_compressor.CompressEdge(
                forward_e1, forward_e2, node_v, node_w,
                forward_weight1 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0),
                forward_weight2);
            geometry_compressor.CompressEdge(
                reverse_e1, reverse_e2, node_v, node_u, reverse_weight1,
                reverse_weight2 + (has_node_penalty ? speed_profile.traffic_signal_penalty : 0));
        }
    }

    PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
}

void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
                                      unsigned original_number_of_edges,
                                      const util::NodeBasedDynamicGraph &graph) const
{

    unsigned new_node_count = 0;
    unsigned new_edge_count = 0;

    for (const auto i : util::irange(0u, graph.GetNumberOfNodes()))
    {
        if (graph.GetOutDegree(i) > 0)
        {
            ++new_node_count;
            new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
        }
    }
    util::SimpleLogger().Write() << "Node compression ratio: "
                                 << new_node_count / (double)original_number_of_nodes;
    util::SimpleLogger().Write() << "Edge compression ratio: "
                                 << new_edge_count / (double)original_number_of_edges;
}
}
}
<commit_msg>Disable compression across traffic lights.  Previously, we merged the traffic light penalty into the edge weight.  When later considering traffic data, we need to be able to update just the edge weight, and it was impossible to extricate the traffic penalty.  This increases the number of edge-based-nodes a little bit, but some quick tests show it should only be about 0.1% overall (only affects traffic signals on edges with no intersections (i.e. degree=2))<commit_after>#include "extractor/graph_compressor.hpp"

#include "extractor/compressed_edge_container.hpp"
#include "extractor/restriction_map.hpp"
#include "util/dynamic_graph.hpp"
#include "util/node_based_graph.hpp"
#include "util/percent.hpp"

#include "util/simple_logger.hpp"

namespace osrm
{
namespace extractor
{

GraphCompressor::GraphCompressor(SpeedProfileProperties speed_profile)
    : speed_profile(std::move(speed_profile))
{
}

void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
                               const std::unordered_set<NodeID> &traffic_lights,
                               RestrictionMap &restriction_map,
                               util::NodeBasedDynamicGraph &graph,
                               CompressedEdgeContainer &geometry_compressor)
{
    const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
    const unsigned original_number_of_edges = graph.GetNumberOfEdges();

    util::Percent progress(original_number_of_nodes);

    for (const NodeID node_v : util::irange(0u, original_number_of_nodes))
    {
        progress.printStatus(node_v);

        // only contract degree 2 vertices
        if (2 != graph.GetOutDegree(node_v))
        {
            continue;
        }

        // don't contract barrier node
        if (barrier_nodes.end() != barrier_nodes.find(node_v))
        {
            continue;
        }

        // check if v is a via node for a turn restriction, i.e. a 'directed' barrier node
        if (restriction_map.IsViaNode(node_v))
        {
            continue;
        }

        //    reverse_e2   forward_e2
        // u <---------- v -----------> w
        //    ----------> <-----------
        //    forward_e1   reverse_e1
        //
        // Will be compressed to:
        //
        //    reverse_e1
        // u <---------- w
        //    ---------->
        //    forward_e1
        //
        // If the edges are compatible.

        const bool reverse_edge_order = graph.GetEdgeData(graph.BeginEdges(node_v)).reversed;
        const EdgeID forward_e2 = graph.BeginEdges(node_v) + reverse_edge_order;
        BOOST_ASSERT(SPECIAL_EDGEID != forward_e2);
        BOOST_ASSERT(forward_e2 >= graph.BeginEdges(node_v) && forward_e2 < graph.EndEdges(node_v));
        const EdgeID reverse_e2 = graph.BeginEdges(node_v) + 1 - reverse_edge_order;
        BOOST_ASSERT(SPECIAL_EDGEID != reverse_e2);
        BOOST_ASSERT(reverse_e2 >= graph.BeginEdges(node_v) && reverse_e2 < graph.EndEdges(node_v));

        const EdgeData &fwd_edge_data2 = graph.GetEdgeData(forward_e2);
        const EdgeData &rev_edge_data2 = graph.GetEdgeData(reverse_e2);

        const NodeID node_w = graph.GetTarget(forward_e2);
        BOOST_ASSERT(SPECIAL_NODEID != node_w);
        BOOST_ASSERT(node_v != node_w);
        const NodeID node_u = graph.GetTarget(reverse_e2);
        BOOST_ASSERT(SPECIAL_NODEID != node_u);
        BOOST_ASSERT(node_u != node_v);

        const EdgeID forward_e1 = graph.FindEdge(node_u, node_v);
        BOOST_ASSERT(SPECIAL_EDGEID != forward_e1);
        BOOST_ASSERT(node_v == graph.GetTarget(forward_e1));
        const EdgeID reverse_e1 = graph.FindEdge(node_w, node_v);
        BOOST_ASSERT(SPECIAL_EDGEID != reverse_e1);
        BOOST_ASSERT(node_v == graph.GetTarget(reverse_e1));

        const EdgeData &fwd_edge_data1 = graph.GetEdgeData(forward_e1);
        const EdgeData &rev_edge_data1 = graph.GetEdgeData(reverse_e1);

        if (graph.FindEdgeInEitherDirection(node_u, node_w) != SPECIAL_EDGEID)
        {
            continue;
        }

        // this case can happen if two ways with different names overlap
        if (fwd_edge_data1.name_id != rev_edge_data1.name_id ||
            fwd_edge_data2.name_id != rev_edge_data2.name_id)
        {
            continue;
        }

        if (fwd_edge_data1.IsCompatibleTo(fwd_edge_data2) &&
            rev_edge_data1.IsCompatibleTo(rev_edge_data2))
        {
            BOOST_ASSERT(graph.GetEdgeData(forward_e1).name_id ==
                         graph.GetEdgeData(reverse_e1).name_id);
            BOOST_ASSERT(graph.GetEdgeData(forward_e2).name_id ==
                         graph.GetEdgeData(reverse_e2).name_id);

            // Do not compress edge if it crosses a traffic signal.
            // This can't be done in IsCompatibleTo, becase we only store the
            // traffic signals in the `traffic_lights` list, which EdgeData
            // doesn't have access to.
            const bool has_node_penalty = traffic_lights.find(node_v) != traffic_lights.end();
            if (has_node_penalty)
            {
                continue;
            }

            // Get distances before graph is modified
            const int forward_weight1 = graph.GetEdgeData(forward_e1).distance;
            const int forward_weight2 = graph.GetEdgeData(forward_e2).distance;

            BOOST_ASSERT(0 != forward_weight1);
            BOOST_ASSERT(0 != forward_weight2);

            const int reverse_weight1 = graph.GetEdgeData(reverse_e1).distance;
            const int reverse_weight2 = graph.GetEdgeData(reverse_e2).distance;

            BOOST_ASSERT(0 != reverse_weight1);
            BOOST_ASSERT(0 != reverse_weight2);

            // add weight of e2's to e1
            graph.GetEdgeData(forward_e1).distance += fwd_edge_data2.distance;
            graph.GetEdgeData(reverse_e1).distance += rev_edge_data2.distance;

            // extend e1's to targets of e2's
            graph.SetTarget(forward_e1, node_w);
            graph.SetTarget(reverse_e1, node_u);

            // remove e2's (if bidir, otherwise only one)
            graph.DeleteEdge(node_v, forward_e2);
            graph.DeleteEdge(node_v, reverse_e2);

            // update any involved turn restrictions
            restriction_map.FixupStartingTurnRestriction(node_u, node_v, node_w);
            restriction_map.FixupArrivingTurnRestriction(node_u, node_v, node_w, graph);

            restriction_map.FixupStartingTurnRestriction(node_w, node_v, node_u);
            restriction_map.FixupArrivingTurnRestriction(node_w, node_v, node_u, graph);

            // store compressed geometry in container
            geometry_compressor.CompressEdge(
                forward_e1, forward_e2, node_v, node_w,
                forward_weight1, forward_weight2);
            geometry_compressor.CompressEdge(
                reverse_e1, reverse_e2, node_v, node_u,
                reverse_weight1, reverse_weight2);
        }
    }

    PrintStatistics(original_number_of_nodes, original_number_of_edges, graph);
}

void GraphCompressor::PrintStatistics(unsigned original_number_of_nodes,
                                      unsigned original_number_of_edges,
                                      const util::NodeBasedDynamicGraph &graph) const
{

    unsigned new_node_count = 0;
    unsigned new_edge_count = 0;

    for (const auto i : util::irange(0u, graph.GetNumberOfNodes()))
    {
        if (graph.GetOutDegree(i) > 0)
        {
            ++new_node_count;
            new_edge_count += (graph.EndEdges(i) - graph.BeginEdges(i));
        }
    }
    util::SimpleLogger().Write() << "Node compression ratio: "
                                 << new_node_count / (double)original_number_of_nodes;
    util::SimpleLogger().Write() << "Edge compression ratio: "
                                 << new_edge_count / (double)original_number_of_edges;
}
}
}
<|endoftext|>


<commit_before>#include <stdint.h>

#include "types.h"

#include "GetProofOfStakeReward.h"

money_t GetProofOfStakeReward(timestamp_t coinAge, blockheight_t height)
{
    // The actual formula is shaped as (A + exp(B * nHeight) + C)
    // Since we can't use float, and that using fixed-point numbers would be both complex and error-prone, we chose to use a step-by-step solution
    // Each array cell is the reward given starting from a specific bloc height. Each cells will be applied for the next 43,836 blocks (about a month)
    // Note that these values have to be divided by 10,000 later (ie 9278 is actually 0.9278).

    static uint16_t const rewardSteps[] = { 10000, 9754, 9593, 9435, 9278, 9124, 8972, 8823, 8675, 8530, 8386, 8245, 8106, 7969, 7834, 7701, 7569, 7440, 7312, 7187, 7063, 6941, 6821, 6702, 6585, 6470, 6356, 6245, 6134, 6026, 5919, 5813, 5709, 5607, 5505, 5406, 5308, 5211, 5116, 5022, 4929, 4838, 4748, 4659, 4572, 4486, 4401, 4318, 4235, 4154, 4074, 3995, 3917, 3841, 3765, 3691, 3617, 3545, 3474, 3404, 3334, 3266, 3199, 3133, 3067, 3003, 2940, 2877, 2816, 2755, 2695, 2636, 2578, 2521, 2464, 2409, 2354, 2300, 2247, 2194, 2142, 2091, 2041, 1992, 1943, 1895, 1847, 1801, 1755, 1709, 1664, 1620, 1577, 1534, 1492, 1450, 1409, 1369, 1329, 1290, 1251, 1213, 1176, 1139, 1102, 1066, 1031, 996, 961, 928, 894, 861, 829, 797, 765, 734, 703, 673, 643, 600 };

    uint32_t stepIndex = height / 43836;
    uint32_t stepCount = sizeof( rewardSteps ) / sizeof( rewardSteps[ 0 ] );

    if ( stepIndex >= stepCount )
        stepIndex = stepCount;

    money_t rewardCoinYear = COIN * rewardSteps[ stepIndex ] / 10000;

    // So basically, we're getting the number of coin per year (above), divided by the number of days in a year, multiplied by the coin age (in days) of the stake (prorata).
    // If the end of the formula looks weird to you, it's because there isn't exactly 365 days in a year - that would be forgetting the leap years ... So there's actually 365.2421 days.
    // "( 365 * 33 + 8 ) / 33" is approximatively 0.2424. "* 33 / ( 365 * 33 + 8 )" is a way to take this in account without risking losing precision (ie. without using floats).

    return coinAge * rewardCoinYear * 33 / ( 365 * 33 + 8 );
}
<commit_msg>Fixes buffer overflow<commit_after>#include <stdint.h>

#include "types.h"

#include "GetProofOfStakeReward.h"

money_t GetProofOfStakeReward(timestamp_t coinAge, blockheight_t height)
{
    // The actual formula is shaped as (A + exp(B * nHeight) + C)
    // Since we can't use float, and that using fixed-point numbers would be both complex and error-prone, we chose to use a step-by-step solution
    // Each array cell is the reward given starting from a specific bloc height. Each cells will be applied for the next 43,836 blocks (about a month)
    // Note that these values have to be divided by 10,000 later (ie 9278 is actually 0.9278).

    static uint16_t const rewardSteps[] = { 10000, 9754, 9593, 9435, 9278, 9124, 8972, 8823, 8675, 8530, 8386, 8245, 8106, 7969, 7834, 7701, 7569, 7440, 7312, 7187, 7063, 6941, 6821, 6702, 6585, 6470, 6356, 6245, 6134, 6026, 5919, 5813, 5709, 5607, 5505, 5406, 5308, 5211, 5116, 5022, 4929, 4838, 4748, 4659, 4572, 4486, 4401, 4318, 4235, 4154, 4074, 3995, 3917, 3841, 3765, 3691, 3617, 3545, 3474, 3404, 3334, 3266, 3199, 3133, 3067, 3003, 2940, 2877, 2816, 2755, 2695, 2636, 2578, 2521, 2464, 2409, 2354, 2300, 2247, 2194, 2142, 2091, 2041, 1992, 1943, 1895, 1847, 1801, 1755, 1709, 1664, 1620, 1577, 1534, 1492, 1450, 1409, 1369, 1329, 1290, 1251, 1213, 1176, 1139, 1102, 1066, 1031, 996, 961, 928, 894, 861, 829, 797, 765, 734, 703, 673, 643, 600 };

    uint32_t stepIndex = height / 43836;
    uint32_t stepCount = sizeof( rewardSteps ) / sizeof( rewardSteps[ 0 ] );

    if ( stepIndex >= stepCount )
        stepIndex = stepCount - 1;

    money_t rewardCoinYear = COIN * rewardSteps[ stepIndex ] / 10000;

    // So basically, we're getting the number of coin per year (above), divided by the number of days in a year, multiplied by the coin age (in days) of the stake (prorata).
    // If the end of the formula looks weird to you, it's because there isn't exactly 365 days in a year - that would be forgetting the leap years ... So there's actually 365.2421 days.
    // "( 365 * 33 + 8 ) / 33" is approximatively 0.2424. "* 33 / ( 365 * 33 + 8 )" is a way to take this in account without risking losing precision (ie. without using floats).

    return coinAge * rewardCoinYear * 33 / ( 365 * 33 + 8 );
}
<|endoftext|>


<commit_before><commit_msg>No cloud collisions<commit_after><|endoftext|>


<commit_before>/*************************************************************************
> File Name: TaskSerializer.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Serializer for TaskMeta and MetaData
> Created Time: 2018/05/20
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Cards/Character.h>
#include <Cards/Weapon.h>
#include <Tasks/MetaData.h>
#include <Tasks/TaskSerializer.h>

#include <algorithm>

namespace Hearthstonepp::Serializer
{
flatbuffers::Offset<FlatData::Entity> CreateEntity(
    flatbuffers::FlatBufferBuilder& builder, const Entity* entity)
{
	if (entity == nullptr)
	{
		return FlatData::CreateEntity(builder);
	}

    return FlatData::CreateEntity(builder, CreateCard(builder, entity->card),
                                  0);
}

flatbuffers::Offset<FlatData::Card> CreateCard(
    flatbuffers::FlatBufferBuilder& builder, const Card* card)
{
    std::vector<int> mechanics;
    mechanics.reserve(card->mechanics.size());
    for (const auto& mechanic : card->mechanics)
    {
        mechanics.emplace_back(static_cast<int>(mechanic));
    }

    size_t attack = card->attack ? *card->attack : 0;
    size_t health = card->health ? *card->health : 0;
    size_t durability = card->durability ? *card->durability : 0;

    return FlatData::CreateCard(
        builder, builder.CreateString(card->id), static_cast<int>(card->rarity),
        static_cast<int>(card->faction), static_cast<int>(card->cardSet),
        static_cast<int>(card->cardClass), static_cast<int>(card->cardType),
        static_cast<int>(card->race), builder.CreateString(card->name),
        builder.CreateString(card->text), card->isCollectible,
        static_cast<int>(card->cost), static_cast<uint32_t>(attack),
        static_cast<uint32_t>(health), static_cast<uint32_t>(durability),
        builder.CreateVector(mechanics), 0, 0, card->GetMaxAllowedInDeck());
}

TaskMeta CreateEntityVector(const TaskMetaTrait& trait,
                            const std::vector<Entity*>& vector)
{
    flatbuffers::FlatBufferBuilder builder(1024);
    std::vector<flatbuffers::Offset<FlatData::Entity>> flatten;

    for (const auto entity : vector)
    {
        flatten.emplace_back(CreateEntity(builder, entity));
    }

    auto entities =
        FlatData::CreateEntityVector(builder, builder.CreateVector(flatten));
    builder.Finish(entities);

    return TaskMeta(trait, builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateTaskMetaVector(const std::vector<TaskMeta>& vector,
                              MetaData status, BYTE userID)
{
    flatbuffers::FlatBufferBuilder builder(1024);
    std::vector<flatbuffers::Offset<FlatData::TaskMeta>> flatten;

    // Convert TaskMeta to FlatData::TaskMeta
    for (const auto& task : vector)
    {
        auto trait = FlatData::TaskMetaTrait(static_cast<int>(task.id),
                                             static_cast<status_t>(task.status),
                                             task.userID);
        const auto& unique = task.GetConstBuffer();
        auto buffer = builder.CreateVector(unique.get(), task.GetBufferSize());

        auto temporal = FlatData::CreateTaskMeta(builder, &trait, buffer);
        flatten.emplace_back(std::move(temporal));
    }

    // Convert std::vector to FlatData::TaskMetaVector
    auto integrated =
        FlatData::CreateTaskMetaVector(builder, builder.CreateVector(flatten));
    builder.Finish(integrated);

    return TaskMeta(TaskMetaTrait(TaskID::TASK_VECTOR, status, userID),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateRequire(TaskID request, BYTE userID)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat =
        FlatData::CreateRequireTaskMeta(builder, static_cast<int>(request));

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::REQUIRE, MetaData::INVALID, userID),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponseMulligan(const BYTE* index, size_t size)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto vector = builder.CreateVector(index, size);
    auto flat = FlatData::CreateResponseMulligan(builder, vector);

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::MULLIGAN), builder.GetSize(),
                    builder.GetBufferPointer());
}

TaskMeta CreateResponsePlayCard(size_t cardIndex)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat =
        FlatData::CreateResponsePlayCard(builder, static_cast<BYTE>(cardIndex));

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::SELECT_CARD, MetaData::SELECT_CARD),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponsePlayMinion(size_t position)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat = FlatData::CreateResponsePlayMinion(builder,
                                                   static_cast<BYTE>(position));

    builder.Finish(flat);
    return TaskMeta(
        TaskMetaTrait(TaskID::SELECT_POSITION, MetaData::SELECT_POSITION),
        builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponseTarget(size_t src, size_t dst)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat = FlatData::CreateResponseTarget(builder, static_cast<BYTE>(src),
                                               static_cast<BYTE>(dst));

    builder.Finish(flat);
    return TaskMeta(
        TaskMetaTrait(TaskID::SELECT_TARGET, MetaData::SELECT_TARGET),
        builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreatePlayerSetting(const std::string& player1,
                             const std::string& player2)
{
    flatbuffers::FlatBufferBuilder builder(256);

    auto setting = FlatData::CreatePlayerSetting(
        builder, builder.CreateString(player1), builder.CreateString(player2));

    builder.Finish(setting);
    return TaskMeta(TaskMetaTrait(TaskID::PLAYER_SETTING), builder.GetSize(),
                    builder.GetBufferPointer());
}

TaskMeta CreateGameStatus(TaskID taskID, MetaData status, const Player& player1,
                          const Player& player2)
{
    using EntityOffset = flatbuffers::Offset<FlatData::Entity>;
    using VectorOffset = flatbuffers::Offset<flatbuffers::Vector<EntityOffset>>;

    flatbuffers::FlatBufferBuilder builder(256);

    // Tie multi card vector
    auto target = {player1.field, player2.field, player1.attacked,
                   player2.attacked};
    std::vector<VectorOffset> result(target.size());

    // Convert Card vector to FlatData::Card vector
    std::transform(target.begin(), target.end(), result.begin(),
                   [&builder](auto&& vec) -> VectorOffset {
                       std::vector<EntityOffset> dest(vec.size());
                       std::transform(vec.begin(), vec.end(), dest.begin(),
                                      [&builder](Entity* entity) {
                                          return CreateEntity(builder, entity);
                                      });

                       return builder.CreateVector(dest);
                   });

    auto gameStatus = FlatData::CreateGameStatus(
        builder, player1.id, player2.id, player1.existMana, player2.existMana,
        CreateEntity(builder, player1.hero),
        CreateEntity(builder, player2.hero), result[0], result[1], result[2],
        static_cast<BYTE>(player2.hand.size()),
        static_cast<BYTE>(player1.cards.size()),
        static_cast<BYTE>(player2.cards.size()), result[3], result[4]);

    builder.Finish(gameStatus);
    return TaskMeta(TaskMetaTrait(taskID, status, player1.id),
                    builder.GetSize(), builder.GetBufferPointer());
}
}  // namespace Hearthstonepp::Serializer
<commit_msg>[ci skip] Update TaskSerializer - Fix invalid Argument of player1.hand<commit_after>/*************************************************************************
> File Name: TaskSerializer.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Serializer for TaskMeta and MetaData
> Created Time: 2018/05/20
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Cards/Character.h>
#include <Cards/Weapon.h>
#include <Tasks/MetaData.h>
#include <Tasks/TaskSerializer.h>

#include <algorithm>

namespace Hearthstonepp::Serializer
{
flatbuffers::Offset<FlatData::Entity> CreateEntity(
    flatbuffers::FlatBufferBuilder& builder, const Entity* entity)
{
    if (entity == nullptr)
    {
        return FlatData::CreateEntity(builder);
    }

    return FlatData::CreateEntity(builder, CreateCard(builder, entity->card),
                                  0);
}

flatbuffers::Offset<FlatData::Card> CreateCard(
    flatbuffers::FlatBufferBuilder& builder, const Card* card)
{
    std::vector<int> mechanics;
    mechanics.reserve(card->mechanics.size());
    for (const auto& mechanic : card->mechanics)
    {
        mechanics.emplace_back(static_cast<int>(mechanic));
    }

    size_t attack = card->attack ? *card->attack : 0;
    size_t health = card->health ? *card->health : 0;
    size_t durability = card->durability ? *card->durability : 0;

    return FlatData::CreateCard(
        builder, builder.CreateString(card->id), static_cast<int>(card->rarity),
        static_cast<int>(card->faction), static_cast<int>(card->cardSet),
        static_cast<int>(card->cardClass), static_cast<int>(card->cardType),
        static_cast<int>(card->race), builder.CreateString(card->name),
        builder.CreateString(card->text), card->isCollectible,
        static_cast<int>(card->cost), static_cast<uint32_t>(attack),
        static_cast<uint32_t>(health), static_cast<uint32_t>(durability),
        builder.CreateVector(mechanics), 0, 0, card->GetMaxAllowedInDeck());
}

TaskMeta CreateEntityVector(const TaskMetaTrait& trait,
                            const std::vector<Entity*>& vector)
{
    flatbuffers::FlatBufferBuilder builder(1024);
    std::vector<flatbuffers::Offset<FlatData::Entity>> flatten;

    for (const auto entity : vector)
    {
        flatten.emplace_back(CreateEntity(builder, entity));
    }

    auto entities =
        FlatData::CreateEntityVector(builder, builder.CreateVector(flatten));
    builder.Finish(entities);

    return TaskMeta(trait, builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateTaskMetaVector(const std::vector<TaskMeta>& vector,
                              MetaData status, BYTE userID)
{
    flatbuffers::FlatBufferBuilder builder(1024);
    std::vector<flatbuffers::Offset<FlatData::TaskMeta>> flatten;

    // Convert TaskMeta to FlatData::TaskMeta
    for (const auto& task : vector)
    {
        auto trait = FlatData::TaskMetaTrait(static_cast<int>(task.id),
                                             static_cast<status_t>(task.status),
                                             task.userID);
        const auto& unique = task.GetConstBuffer();
        auto buffer = builder.CreateVector(unique.get(), task.GetBufferSize());

        auto temporal = FlatData::CreateTaskMeta(builder, &trait, buffer);
        flatten.emplace_back(std::move(temporal));
    }

    // Convert std::vector to FlatData::TaskMetaVector
    auto integrated =
        FlatData::CreateTaskMetaVector(builder, builder.CreateVector(flatten));
    builder.Finish(integrated);

    return TaskMeta(TaskMetaTrait(TaskID::TASK_VECTOR, status, userID),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateRequire(TaskID request, BYTE userID)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat =
        FlatData::CreateRequireTaskMeta(builder, static_cast<int>(request));

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::REQUIRE, MetaData::INVALID, userID),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponseMulligan(const BYTE* index, size_t size)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto vector = builder.CreateVector(index, size);
    auto flat = FlatData::CreateResponseMulligan(builder, vector);

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::MULLIGAN), builder.GetSize(),
                    builder.GetBufferPointer());
}

TaskMeta CreateResponsePlayCard(size_t cardIndex)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat =
        FlatData::CreateResponsePlayCard(builder, static_cast<BYTE>(cardIndex));

    builder.Finish(flat);
    return TaskMeta(TaskMetaTrait(TaskID::SELECT_CARD, MetaData::SELECT_CARD),
                    builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponsePlayMinion(size_t position)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat = FlatData::CreateResponsePlayMinion(builder,
                                                   static_cast<BYTE>(position));

    builder.Finish(flat);
    return TaskMeta(
        TaskMetaTrait(TaskID::SELECT_POSITION, MetaData::SELECT_POSITION),
        builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreateResponseTarget(size_t src, size_t dst)
{
    flatbuffers::FlatBufferBuilder builder(32);
    auto flat = FlatData::CreateResponseTarget(builder, static_cast<BYTE>(src),
                                               static_cast<BYTE>(dst));

    builder.Finish(flat);
    return TaskMeta(
        TaskMetaTrait(TaskID::SELECT_TARGET, MetaData::SELECT_TARGET),
        builder.GetSize(), builder.GetBufferPointer());
}

TaskMeta CreatePlayerSetting(const std::string& player1,
                             const std::string& player2)
{
    flatbuffers::FlatBufferBuilder builder(256);

    auto setting = FlatData::CreatePlayerSetting(
        builder, builder.CreateString(player1), builder.CreateString(player2));

    builder.Finish(setting);
    return TaskMeta(TaskMetaTrait(TaskID::PLAYER_SETTING), builder.GetSize(),
                    builder.GetBufferPointer());
}

TaskMeta CreateGameStatus(TaskID taskID, MetaData status, const Player& player1,
                          const Player& player2)
{
    using EntityOffset = flatbuffers::Offset<FlatData::Entity>;
    using VectorOffset = flatbuffers::Offset<flatbuffers::Vector<EntityOffset>>;

    flatbuffers::FlatBufferBuilder builder(256);

    auto makeOffset = [&builder](auto&& vec) -> VectorOffset {
        std::vector<EntityOffset> dest(vec.size());
        std::transform(vec.begin(), vec.end(), dest.begin(),
                       [&builder](Entity* entity) {
                           return CreateEntity(builder, entity);
                       });
        return builder.CreateVector(dest);
    };

    // Tie multi card vector
    auto target = {player1.field, player2.field, player1.attacked,
                   player2.attacked};
    std::vector<VectorOffset> result(target.size());

    // Convert Card vector to FlatData::Card vector
    std::transform(target.begin(), target.end(), result.begin(), makeOffset);

    auto gameStatus = FlatData::CreateGameStatus(
        builder, player1.id, player2.id, player1.existMana, player2.existMana,
        CreateEntity(builder, player1.hero),
        CreateEntity(builder, player2.hero), result[0],
        makeOffset(player1.hand), result[1],
        static_cast<BYTE>(player2.hand.size()),
        static_cast<BYTE>(player1.cards.size()),
        static_cast<BYTE>(player2.cards.size()), result[2], result[3]);

    builder.Finish(gameStatus);
    return TaskMeta(TaskMetaTrait(taskID, status, player1.id),
                    builder.GetSize(), builder.GetBufferPointer());
}
}  // namespace Hearthstonepp::Serializer
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012, J3P LLC. 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 of conditions 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 materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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 "DDImage/Knobs.h"
#include "DDImage/Row.h"

#include "boost/signal.hpp"
#include "boost/bind.hpp"
#include "boost/lexical_cast.hpp"

#include "IECore/LRUCache.h"
#include "IECore/ImageDisplayDriver.h"

#include "IECoreNuke/DisplayIop.h"
#include "IECoreNuke/TypeIds.h"

using namespace IECore;
using namespace IECoreNuke;
using namespace DD::Image;
using namespace Imath;

//////////////////////////////////////////////////////////////////////////
// DisplayDriverServer cache. Many nodes may all want to use a server on
// the same port. We therefore use an LRUCache to manage the lifetime of
// the servers and provide them to the nodes.
//////////////////////////////////////////////////////////////////////////

typedef LRUCache<int, DisplayDriverServerPtr> ServerCache;

// key is the port number for the server.
static DisplayDriverServerPtr serverCacheGetter( int key, size_t cost )
{
	cost = 1;
	return new DisplayDriverServer( key );
}

// max cost of 4 means we will never have more than 4 unused servers at any one time.
static ServerCache g_servers( serverCacheGetter, 4 );

//////////////////////////////////////////////////////////////////////////
// NukeDisplayDriver implementation
//////////////////////////////////////////////////////////////////////////

namespace IECoreNuke
{

class NukeDisplayDriver : public IECore::ImageDisplayDriver
{

	public :

		IE_CORE_DECLARERUNTIMETYPEDEXTENSION( NukeDisplayDriver, NukeDisplayDriverTypeId, ImageDisplayDriver );

		NukeDisplayDriver( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, const std::vector<std::string> &channelNames, ConstCompoundDataPtr parameters )
			:	ImageDisplayDriver( displayWindow, dataWindow, channelNames, parameters )
		{
			if( parameters )
			{
				m_parameters = parameters->copy();
			}
			else
			{
				m_parameters = new CompoundData;
			}

			instanceCreatedSignal( this );
		}

		virtual ~NukeDisplayDriver()
		{
		}

		/// Returns a copy of the parameters used in creating this instance. This
		/// is useful in recognising relevant instances in the instanceCreatedSignal.
		ConstCompoundDataPtr parameters() const
		{
			return m_parameters;
		}

		/// Updates the current image, and then emits the dataReceivedSignal.
		virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize )
		{
			ImageDisplayDriver::imageData( box, data, dataSize );
			dataReceivedSignal( this, box );
		}

		/// This signal is emitted when a new NukeDisplayDriver has been created.
		/// This allows nuke nodes to pick up the new DisplayDrivers even when they're
		/// created in some other code, such as a DisplayDriverServer.
		typedef boost::signal<void( NukeDisplayDriver * )> InstanceCreatedSignal;
		static InstanceCreatedSignal instanceCreatedSignal;

		/// This signal is emitted when this NukeDisplayDriver instance receives new data.
		typedef boost::signal<void( NukeDisplayDriver *, const Imath::Box2i &box )> DataReceivedSignal;
		DataReceivedSignal dataReceivedSignal;

	private :

		static const DisplayDriverDescription<NukeDisplayDriver> g_description;

		ConstCompoundDataPtr m_parameters;

};

NukeDisplayDriver::InstanceCreatedSignal NukeDisplayDriver::instanceCreatedSignal;
const DisplayDriver::DisplayDriverDescription<NukeDisplayDriver> NukeDisplayDriver::g_description;

} // namespace IECoreNuke

//////////////////////////////////////////////////////////////////////////
// DisplayIop implementation
//////////////////////////////////////////////////////////////////////////

const DD::Image::Iop::Description DisplayIop::g_description( "ieDisplay", DisplayIop::build );

DisplayIop::DisplayIop( Node *node )
	:	Iop( node ), m_portNumber( 1559 ), m_updateCount( 0 ), m_server( g_servers.get( m_portNumber ) ), m_driver( 0 )
{
	inputs( 0 );
	slowness( 0 ); // disable caching as we're buffering everything internally ourselves
	NukeDisplayDriver::instanceCreatedSignal.connect( boost::bind( &DisplayIop::driverCreated, this, _1 ) );
}

DisplayIop::~DisplayIop()
{
	NukeDisplayDriver::instanceCreatedSignal.disconnect( boost::bind( &DisplayIop::driverCreated, this, _1 ) );
	connectToDriver( 0 );
}

const char *DisplayIop::Class() const
{
	return "ieDisplay";
}

const char *DisplayIop::node_help() const
{
	return "Acts as a framebuffer for external renderers.";
}

void DisplayIop::knobs( DD::Image::Knob_Callback f )
{
	Iop::knobs( f );

	Int_knob( f, &m_portNumber, "portNumber", "Port Number" );
	SetFlags( f, Knob::KNOB_CHANGED_ALWAYS | Knob::NO_ANIMATION );
	Tooltip(
		f,
		"The port on which to receive images. This must match "
		"the port being used by the renderer to send images."
	);

}

int DisplayIop::knob_changed( DD::Image::Knob *knob )
{
	if( knob->is( "portNumber" ) )
	{
	 	int portNumber = this->knob( "portNumber" )->get_value();
		m_server = g_servers.get( portNumber );
		return 1;
	}

	return Iop::knob_changed( knob );
}

void DisplayIop::append( DD::Image::Hash &hash )
{
	Iop::append( hash );

	hash.append( __DATE__ );
	hash.append( __TIME__ );
	hash.append( firstDisplayIop()->m_updateCount );
}

void DisplayIop::_validate( bool forReal )
{
	Box2i displayWindow( V2i( 0, 0 ), V2i( 255, 255 ) );

	if( firstDisplayIop()->m_driver )
	{
		displayWindow = firstDisplayIop()->m_driver->image()->getDisplayWindow();
	}

	m_format = m_fullSizeFormat = Format( displayWindow.size().x + 1, displayWindow.size().y + 1 );
	// these set function don't copy the format, but instead reference its address.
	// we therefore have to store the format as member data.
	info_.format( m_format );
	info_.full_size_format( m_fullSizeFormat );
	info_.set( m_format );

	info_.channels( Mask_RGBA );
}

void DisplayIop::engine( int y, int x, int r, const DD::Image::ChannelSet &channels, DD::Image::Row &row )
{
	Channel outputChannels[4] = { Chan_Red, Chan_Green, Chan_Blue, Chan_Alpha };
	const char *inputChannels[] = { "R", "G", "B", "A", 0 };

	const ImagePrimitive *image = 0;
	Box2i inputDataWindow;
	Box2i inputDisplayWindow;
	if( firstDisplayIop()->m_driver )
	{
		image = firstDisplayIop()->m_driver->image().get();
		inputDataWindow = image->getDataWindow();
		inputDisplayWindow = image->getDisplayWindow();
	}

	int i = 0;
	while( inputChannels[i] )
	{
		const FloatVectorData *inputData = image ? image->variableData<FloatVectorData>( inputChannels[i] ) : 0;
		if( inputData )
		{
			float *output = row.writable( outputChannels[i] ) + x;
			// remap coordinate relative to our data window. nuke images have pixel origin at bottom,
			// cortex images have pixel origin at top.
			V2i pDataWindow = V2i( x, inputDisplayWindow.max.y - y ) - inputDataWindow.min;
			const float *input = &((inputData->readable())[pDataWindow.y*(inputDataWindow.size().x+1) + pDataWindow.x]);
			memcpy( output, input, (r-x) * sizeof( float ) );
		}
		else
		{
			row.erase( outputChannels[i] );
		}
		i++;
	}
}

DD::Image::Op *DisplayIop::build( Node *node )
{
	return new DisplayIop( node );
}

DisplayIop *DisplayIop::firstDisplayIop()
{
	return static_cast<DisplayIop *>( firstOp() );
}

void DisplayIop::driverCreated( NukeDisplayDriver *driver )
{
	ConstStringDataPtr portNumber = driver->parameters()->member<StringData>( "displayPort" );
	if( portNumber && boost::lexical_cast<int>( portNumber->readable() ) == m_portNumber )
	{
		firstDisplayIop()->connectToDriver( driver );
	}
}

void DisplayIop::connectToDriver( NukeDisplayDriver *driver )
{
	assert( this == firstDisplayIop() );

	if( m_driver )
	{
		m_driver->dataReceivedSignal.disconnect( boost::bind( &DisplayIop::driverDataReceived, this, _1, _2 ) );
	}

	m_driver = driver;
	if( m_driver )
	{
		m_driver->dataReceivedSignal.connect( boost::bind( &DisplayIop::driverDataReceived, this, _1, _2 ) );
	}

	m_updateCount++;
	asapUpdate();
}

void DisplayIop::driverDataReceived( NukeDisplayDriver *driver, const Imath::Box2i &box )
{
	assert( this == firstDisplayIop() );
	m_updateCount++;
	asapUpdate();
}
<commit_msg>Setting KNOB_CHANGED_RECURSIVE on port number knob to work around nuke not calling DisplayIop::knob_changed() when the knob is changed from a PythonPanel.knobChanged() method.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2012, J3P LLC. 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 of conditions 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 materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  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 OWNER 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 "DDImage/Knobs.h"
#include "DDImage/Row.h"

#include "boost/signal.hpp"
#include "boost/bind.hpp"
#include "boost/lexical_cast.hpp"

#include "IECore/LRUCache.h"
#include "IECore/ImageDisplayDriver.h"

#include "IECoreNuke/DisplayIop.h"
#include "IECoreNuke/TypeIds.h"

using namespace IECore;
using namespace IECoreNuke;
using namespace DD::Image;
using namespace Imath;

//////////////////////////////////////////////////////////////////////////
// DisplayDriverServer cache. Many nodes may all want to use a server on
// the same port. We therefore use an LRUCache to manage the lifetime of
// the servers and provide them to the nodes.
//////////////////////////////////////////////////////////////////////////

typedef LRUCache<int, DisplayDriverServerPtr> ServerCache;

// key is the port number for the server.
static DisplayDriverServerPtr serverCacheGetter( int key, size_t cost )
{
	cost = 1;
	return new DisplayDriverServer( key );
}

// max cost of 4 means we will never have more than 4 unused servers at any one time.
static ServerCache g_servers( serverCacheGetter, 4 );

//////////////////////////////////////////////////////////////////////////
// NukeDisplayDriver implementation
//////////////////////////////////////////////////////////////////////////

namespace IECoreNuke
{

class NukeDisplayDriver : public IECore::ImageDisplayDriver
{

	public :

		IE_CORE_DECLARERUNTIMETYPEDEXTENSION( NukeDisplayDriver, NukeDisplayDriverTypeId, ImageDisplayDriver );

		NukeDisplayDriver( const Imath::Box2i &displayWindow, const Imath::Box2i &dataWindow, const std::vector<std::string> &channelNames, ConstCompoundDataPtr parameters )
			:	ImageDisplayDriver( displayWindow, dataWindow, channelNames, parameters )
		{
			if( parameters )
			{
				m_parameters = parameters->copy();
			}
			else
			{
				m_parameters = new CompoundData;
			}

			instanceCreatedSignal( this );
		}

		virtual ~NukeDisplayDriver()
		{
		}

		/// Returns a copy of the parameters used in creating this instance. This
		/// is useful in recognising relevant instances in the instanceCreatedSignal.
		ConstCompoundDataPtr parameters() const
		{
			return m_parameters;
		}

		/// Updates the current image, and then emits the dataReceivedSignal.
		virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize )
		{
			ImageDisplayDriver::imageData( box, data, dataSize );
			dataReceivedSignal( this, box );
		}

		/// This signal is emitted when a new NukeDisplayDriver has been created.
		/// This allows nuke nodes to pick up the new DisplayDrivers even when they're
		/// created in some other code, such as a DisplayDriverServer.
		typedef boost::signal<void( NukeDisplayDriver * )> InstanceCreatedSignal;
		static InstanceCreatedSignal instanceCreatedSignal;

		/// This signal is emitted when this NukeDisplayDriver instance receives new data.
		typedef boost::signal<void( NukeDisplayDriver *, const Imath::Box2i &box )> DataReceivedSignal;
		DataReceivedSignal dataReceivedSignal;

	private :

		static const DisplayDriverDescription<NukeDisplayDriver> g_description;

		ConstCompoundDataPtr m_parameters;

};

NukeDisplayDriver::InstanceCreatedSignal NukeDisplayDriver::instanceCreatedSignal;
const DisplayDriver::DisplayDriverDescription<NukeDisplayDriver> NukeDisplayDriver::g_description;

} // namespace IECoreNuke

//////////////////////////////////////////////////////////////////////////
// DisplayIop implementation
//////////////////////////////////////////////////////////////////////////

const DD::Image::Iop::Description DisplayIop::g_description( "ieDisplay", DisplayIop::build );

DisplayIop::DisplayIop( Node *node )
	:	Iop( node ), m_portNumber( 1559 ), m_server( g_servers.get( m_portNumber ) ), m_updateCount( 0 ), m_driver( 0 )
{
	inputs( 0 );
	slowness( 0 ); // disable caching as we're buffering everything internally ourselves
	NukeDisplayDriver::instanceCreatedSignal.connect( boost::bind( &DisplayIop::driverCreated, this, _1 ) );
}

DisplayIop::~DisplayIop()
{
	NukeDisplayDriver::instanceCreatedSignal.disconnect( boost::bind( &DisplayIop::driverCreated, this, _1 ) );
	connectToDriver( 0 );
}

const char *DisplayIop::Class() const
{
	return "ieDisplay";
}

const char *DisplayIop::node_help() const
{
	return "Acts as a framebuffer for external renderers.";
}

void DisplayIop::knobs( DD::Image::Knob_Callback f )
{
	Iop::knobs( f );

	Int_knob( f, &m_portNumber, "portNumber", "Port Number" );
	// we must have KNOB_CHANGED_RECURSIVE set otherwise nuke doesn't give us knob_changed()
	// calls when the knob value is changed from a knobChanged method of a PythonPanel.
	SetFlags( f, Knob::KNOB_CHANGED_ALWAYS | Knob::KNOB_CHANGED_RECURSIVE | Knob::NO_ANIMATION );
	Tooltip(
		f,
		"The port on which to receive images. This must match "
		"the port being used by the renderer to send images."
	);

}

int DisplayIop::knob_changed( DD::Image::Knob *knob )
{
	if( knob->is( "portNumber" ) )
	{
	 	int portNumber = this->knob( "portNumber" )->get_value();
		m_server = g_servers.get( portNumber );
		return 1;
	}

	return Iop::knob_changed( knob );
}

void DisplayIop::append( DD::Image::Hash &hash )
{
	Iop::append( hash );

	hash.append( __DATE__ );
	hash.append( __TIME__ );
	hash.append( firstDisplayIop()->m_updateCount );
}

void DisplayIop::_validate( bool forReal )
{
	Box2i displayWindow( V2i( 0, 0 ), V2i( 255, 255 ) );

	if( firstDisplayIop()->m_driver )
	{
		displayWindow = firstDisplayIop()->m_driver->image()->getDisplayWindow();
	}

	m_format = m_fullSizeFormat = Format( displayWindow.size().x + 1, displayWindow.size().y + 1 );
	// these set function don't copy the format, but instead reference its address.
	// we therefore have to store the format as member data.
	info_.format( m_format );
	info_.full_size_format( m_fullSizeFormat );
	info_.set( m_format );

	info_.channels( Mask_RGBA );
}

void DisplayIop::engine( int y, int x, int r, const DD::Image::ChannelSet &channels, DD::Image::Row &row )
{
	Channel outputChannels[4] = { Chan_Red, Chan_Green, Chan_Blue, Chan_Alpha };
	const char *inputChannels[] = { "R", "G", "B", "A", 0 };

	const ImagePrimitive *image = 0;
	Box2i inputDataWindow;
	Box2i inputDisplayWindow;
	if( firstDisplayIop()->m_driver )
	{
		image = firstDisplayIop()->m_driver->image().get();
		inputDataWindow = image->getDataWindow();
		inputDisplayWindow = image->getDisplayWindow();
	}

	int i = 0;
	while( inputChannels[i] )
	{
		const FloatVectorData *inputData = image ? image->variableData<FloatVectorData>( inputChannels[i] ) : 0;
		if( inputData )
		{
			float *output = row.writable( outputChannels[i] ) + x;
			// remap coordinate relative to our data window. nuke images have pixel origin at bottom,
			// cortex images have pixel origin at top.
			V2i pDataWindow = V2i( x, inputDisplayWindow.max.y - y ) - inputDataWindow.min;
			const float *input = &((inputData->readable())[pDataWindow.y*(inputDataWindow.size().x+1) + pDataWindow.x]);
			memcpy( output, input, (r-x) * sizeof( float ) );
		}
		else
		{
			row.erase( outputChannels[i] );
		}
		i++;
	}
}

DD::Image::Op *DisplayIop::build( Node *node )
{
	return new DisplayIop( node );
}

DisplayIop *DisplayIop::firstDisplayIop()
{
	return static_cast<DisplayIop *>( firstOp() );
}

void DisplayIop::driverCreated( NukeDisplayDriver *driver )
{
	ConstStringDataPtr portNumber = driver->parameters()->member<StringData>( "displayPort" );
	if( portNumber && boost::lexical_cast<int>( portNumber->readable() ) == m_portNumber )
	{
		firstDisplayIop()->connectToDriver( driver );
	}
}

void DisplayIop::connectToDriver( NukeDisplayDriver *driver )
{
	assert( this == firstDisplayIop() );

	if( m_driver )
	{
		m_driver->dataReceivedSignal.disconnect( boost::bind( &DisplayIop::driverDataReceived, this, _1, _2 ) );
	}

	m_driver = driver;
	if( m_driver )
	{
		m_driver->dataReceivedSignal.connect( boost::bind( &DisplayIop::driverDataReceived, this, _1, _2 ) );
	}

	m_updateCount++;
	asapUpdate();
}

void DisplayIop::driverDataReceived( NukeDisplayDriver *driver, const Imath::Box2i &box )
{
	assert( this == firstDisplayIop() );
	m_updateCount++;
	asapUpdate();
}
<|endoftext|>