<commit_before>#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <time.h>
#include <limits>
#include "UniSetTypes.h"
#include "MBTCPMultiMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <time.h>
#include <memory>
#include <limits>
#include "UniSetTypes.h"
#include "MBTCPTestServer.h"
#include "MBTCPMultiMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
static int port = 20050; // conf->getArgInt("--mbs-inet-port");
static string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static int port2 = 20052;
static string addr2("127.0.0.1");
static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static shared_ptr<MBTCPTestServer> mbs1;
static shared_ptr<MBTCPTestServer> mbs2;
static shared_ptr<UInterface> ui;
static ObjectId mbID = 6005; // MBTCPMultiMaster1
static int polltime=50; // conf->getArgInt("--mbtcp-polltime");
static ObjectId slaveNotRespond = 10; // Slave_Not_Respond_S
static ObjectId slave1NotRespond = 12; // Slave1_Not_Respond_S
static ObjectId slave2NotRespond = 13; // Slave2_Not_Respond_S
static const ObjectId exchangeMode = 11; // MBTCPMaster_Mode_AS
// -----------------------------------------------------------------------------
static void InitTest()
{
    auto conf = uniset_conf();
    CHECK( conf!=nullptr );

    if( !ui )
    {
        ui = make_shared<UInterface>();
        // UI понадобиться для проверки записанных в SM значений.
        CHECK( ui->getObjectIndex() != nullptr );
        CHECK( ui->getConf() == conf );
        CHECK( ui->waitReady(slaveNotRespond,8000) );
    }

    if( !mbs1 )
    {
        mbs1 = make_shared<MBTCPTestServer>(slaveADDR,addr,port,false);
        CHECK( mbs1!= nullptr );
        mbs1->setReply(0);
        mbs1->runThread();
        for( int i=0; !mbs1->isRunning() && i<10; i++ )
            msleep(200);
        CHECK( mbs1->isRunning() );
        msleep(7000);
        CHECK( ui->getValue(slaveNotRespond) == 0 );
    }

    if( !mbs2 )
    {
        mbs2 = make_shared<MBTCPTestServer>(slaveADDR,addr2,port2,false);
        CHECK( mbs2!= nullptr );
        mbs2->setReply(0);
        mbs2->runThread();
        for( int i=0; !mbs2->isRunning() && i<10; i++ )
            msleep(200);
        CHECK( mbs2->isRunning() );
    }

}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMultiMaster: rotate channel","[modbus][mbmaster][mbtcpmultimaster]")
{
    InitTest();
    CHECK( ui->isExist(mbID) );

    REQUIRE( ui->getValue(1003) == 0 );
    mbs1->setReply(100);
    mbs2->setReply(10);
    msleep(polltime+1000);
    REQUIRE( ui->getValue(1003) == 100 );
    mbs1->disableExchange(true);
    msleep(3200); // --mbtcp-timeout 3000 (см. run_test_mbtcmultipmaster.sh)
    REQUIRE( ui->getValue(1003) == 10 );
    mbs1->disableExchange(false);
    mbs2->disableExchange(true);
    msleep(3200); // --mbtcp-timeout 3000 (см. run_test_mbtcmultipmaster.sh)
    REQUIRE( ui->getValue(1003) == 100 );
    mbs2->disableExchange(false);
    REQUIRE( ui->getValue(1003) == 100 );
}
// -----------------------------------------------------------------------------
<commit_msg>(ModbusMaster): сделал test немного стабильнее.<commit_after>#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <time.h>
#include <limits>
#include "UniSetTypes.h"
#include "MBTCPMultiMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
#include <catch.hpp>
// -----------------------------------------------------------------------------
#include <time.h>
#include <memory>
#include <limits>
#include "UniSetTypes.h"
#include "MBTCPTestServer.h"
#include "MBTCPMultiMaster.h"
// -----------------------------------------------------------------------------
using namespace std;
using namespace UniSetTypes;
// -----------------------------------------------------------------------------
static ModbusRTU::ModbusAddr slaveaddr = 0x01; // conf->getArgInt("--mbs-my-addr");
static int port = 20050; // conf->getArgInt("--mbs-inet-port");
static string addr("127.0.0.1"); // conf->getArgParam("--mbs-inet-addr");
static int port2 = 20052;
static string addr2("127.0.0.1");
static ModbusRTU::ModbusAddr slaveADDR = 0x01;
static shared_ptr<MBTCPTestServer> mbs1;
static shared_ptr<MBTCPTestServer> mbs2;
static shared_ptr<UInterface> ui;
static ObjectId mbID = 6005; // MBTCPMultiMaster1
static int polltime=50; // conf->getArgInt("--mbtcp-polltime");
static ObjectId slaveNotRespond = 10; // Slave_Not_Respond_S
static ObjectId slave1NotRespond = 12; // Slave1_Not_Respond_S
static ObjectId slave2NotRespond = 13; // Slave2_Not_Respond_S
static const ObjectId exchangeMode = 11; // MBTCPMaster_Mode_AS
// -----------------------------------------------------------------------------
static void InitTest()
{
    auto conf = uniset_conf();
    CHECK( conf!=nullptr );

    if( !ui )
    {
        ui = make_shared<UInterface>();
        // UI понадобиться для проверки записанных в SM значений.
        CHECK( ui->getObjectIndex() != nullptr );
        CHECK( ui->getConf() == conf );
        CHECK( ui->waitReady(slaveNotRespond,8000) );
    }

    if( !mbs1 )
    {
        mbs1 = make_shared<MBTCPTestServer>(slaveADDR,addr,port,false);
        CHECK( mbs1!= nullptr );
        mbs1->setReply(0);
        mbs1->runThread();
        for( int i=0; !mbs1->isRunning() && i<10; i++ )
            msleep(200);
        CHECK( mbs1->isRunning() );
        msleep(7000);
        CHECK( ui->getValue(slaveNotRespond) == 0 );
    }

    if( !mbs2 )
    {
        mbs2 = make_shared<MBTCPTestServer>(slaveADDR,addr2,port2,false);
        CHECK( mbs2!= nullptr );
        mbs2->setReply(0);
        mbs2->runThread();
        for( int i=0; !mbs2->isRunning() && i<10; i++ )
            msleep(200);
        CHECK( mbs2->isRunning() );
    }

}
// -----------------------------------------------------------------------------
TEST_CASE("MBTCPMultiMaster: rotate channel","[modbus][mbmaster][mbtcpmultimaster]")
{
    InitTest();
    CHECK( ui->isExist(mbID) );

    REQUIRE( ui->getValue(1003) == 0 );
    mbs1->setReply(100);
    mbs2->setReply(10);
    msleep(polltime+1000);
    REQUIRE( ui->getValue(1003) == 100 );
    mbs1->disableExchange(true);
    msleep(4000); // --mbtcp-timeout 3000 (см. run_test_mbtcmultipmaster.sh)
    REQUIRE( ui->getValue(1003) == 10 );
    mbs1->disableExchange(false);
    mbs2->disableExchange(true);
    msleep(4000); // --mbtcp-timeout 3000 (см. run_test_mbtcmultipmaster.sh)
    REQUIRE( ui->getValue(1003) == 100 );
    mbs2->disableExchange(false);
    REQUIRE( ui->getValue(1003) == 100 );
}
// -----------------------------------------------------------------------------
<|endoftext|>


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

#include "StdAfx.h"

initialiseSingleton( TaxiMgr );

/************************
 *	   TaxiPath	   *
 ************************/

void TaxiPath::ComputeLen()
{
	m_length1 = m_length1 = 0;
	m_map1 = m_map2 = 0;
	float * curptr = &m_length1;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float x = itr->second->x;
	float y = itr->second->y;
	float z = itr->second->z;
	uint32 curmap = itr->second->mapid;
	m_map1 = curmap;

	itr++;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != curmap )
		{
			curptr = &m_length2;
			m_map2 = itr->second->mapid;
			curmap = itr->second->mapid;
		}

		*curptr += sqrt((itr->second->x - x)*(itr->second->x - x) +
			(itr->second->y - y)*(itr->second->y - y) +
			(itr->second->z - z)*(itr->second->z - z));

		x = itr->second->x;
		y = itr->second->y;
		z = itr->second->z;
		itr++;
	}
}

void TaxiPath::SetPosForTime(float &x, float &y, float &z, uint32 time, uint32 *last_node, uint32 mapid)
{
	if (!time)
		return;

	float length;
	if( mapid == m_map1 )
		length = m_length1;
	else
		length = m_length2;

	float traveled_len = (time/(length * TAXI_TRAVEL_SPEED))*length;
	uint32 len = 0;

	x = 0;
	y = 0;
	z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx,ny,nz = 0.0f;
	bool set = false;
	uint32 nodecounter = 0;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != mapid )
		{
			itr++;
			nodecounter++;
			continue;
		}

		if(!set)
		{
			nx = itr->second->x;
			ny = itr->second->y;
			nz = itr->second->z;
			set = true;
			continue;
		}

		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len >= traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			*last_node = nodecounter;
			return;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
		nodecounter++;
	}

	x = nx;
	y = ny;
	z = nz;
}

TaxiPathNode* TaxiPath::GetPathNode(uint32 i)
{
	if (m_pathNodes.find(i) == m_pathNodes.end())
		return NULL;
	else
		return m_pathNodes.find(i)->second;
}

void TaxiPath::SendMoveForTime(Player *riding, Player *to, uint32 time)
{
	if (!time)
		return;

	float length;
	uint32 mapid = riding->GetMapId();
	if( mapid == m_map1 )
		length = m_length1;
	else
		length = m_length2;

	float traveled_len = (time/(length * TAXI_TRAVEL_SPEED))*length;
	uint32 len = 0;
	float x = 0,y = 0,z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx,ny,nz = 0.0f;
	bool set = false;
	uint32 nodecounter = 1;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != mapid )
		{
			itr++;
			nodecounter++;
			continue;
		}

		if(!set)
		{
			nx = itr->second->x;
			ny = itr->second->y;
			nz = itr->second->z;
			set = true;
			continue;
		}

		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len >= traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			break;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
	}

	if (itr == m_pathNodes.end())
		return;

	WorldPacket * data = new WorldPacket(SMSG_MONSTER_MOVE, 2000);
	size_t pos;

	*data << riding->GetNewGUID();
	*data << riding->GetPositionX( ) << riding->GetPositionY( ) << riding->GetPositionZ( );
	*data << getMSTime();
	*data << uint8( 0 );
	*data << uint32( 0x00000300 );
	*data << uint32( uint32((length * TAXI_TRAVEL_SPEED) - time));
	*data << uint32( nodecounter );
	pos = data->wpos();
	*data << nx << ny << nz;

	while (itr != m_pathNodes.end())
	{
		TaxiPathNode *pn = itr->second;
		if( pn->mapid != mapid )
			break;

		*data << pn->x << pn->y << pn->z;
		++itr;
		++nodecounter;
	}

	*(uint32*)&(data->contents()[pos]) = nodecounter;
	to->delayedPackets.add(data);
/*	if (!time)
		return;

	float traveled_len = (time/(getLength() * TAXI_TRAVEL_SPEED))*getLength();;
	uint32 len = 0, count = 0;
	float x = 0,y = 0,z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx = itr->second->x;
	float ny = itr->second->y;
	float nz = itr->second->z;
	itr++;

	while (itr != m_pathNodes.end())
	{
		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len > traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			break;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
		count++;
	}

	if (itr == m_pathNodes.end())
		return;

	WorldPacket * data = new WorldPacket(SMSG_MONSTER_MOVE, 2000);

	*data << riding->GetNewGUID();
	*data << riding->GetPositionX( ) << riding->GetPositionY( ) << riding->GetPositionZ( );
	*data << getMSTime();
	*data << uint8( 0 );
	*data << uint32( 0x00000300 );
	*data << uint32( uint32((getLength() * TAXI_TRAVEL_SPEED) - time));
	*data << uint32( GetNodeCount() - count );
	*data << nx << ny << nz;
	while (itr != m_pathNodes.end())
	{
		TaxiPathNode *pn = itr->second;
		*data << pn->x << pn->y << pn->z;
		itr++;
	}
	//to->GetSession()->SendPacket(&data);
	to->delayedPackets.add(data);*/
}

/***********************
 *	   TaxiMgr	   *
 ***********************/

void TaxiMgr::_LoadTaxiNodes()
{
	uint32 i;

	for(i = 0; i < dbcTaxiNode.GetNumRows(); i++)
	{
		DBCTaxiNode *node = dbcTaxiNode.LookupRow(i);
		if (node)
		{
			TaxiNode *n = new TaxiNode;
			n->id = node->id;
			n->mapid = node->mapid;
			n->alliance_mount = node->alliance_mount;
			n->horde_mount = node->horde_mount;
			n->x = node->x;
			n->y = node->y;
			n->z = node->z;

			this->m_taxiNodes.insert(std::map<uint32, TaxiNode*>::value_type(n->id, n));
		}
	}

	//todo: load mounts
}

void TaxiMgr::_LoadTaxiPaths()
{
	uint32 i, j;

	for(i = 0; i < dbcTaxiPath.GetNumRows(); i++)
	{
		DBCTaxiPath *path = dbcTaxiPath.LookupRow(i);

		if (path)
		{
			TaxiPath *p = new TaxiPath;
			p->from = path->from;
			p->to = path->to;
			p->id = path->id;
			p->price = path->price;

			//Load Nodes
			for(j = 0; j < dbcTaxiPathNode.GetNumRows(); j++)
			{
				DBCTaxiPathNode *pathnode = dbcTaxiPathNode.LookupRow(j);

				if (pathnode)
				{
					if (pathnode->path == p->id)
					{
						TaxiPathNode *pn = new TaxiPathNode;
						pn->x = pathnode->x;
						pn->y = pathnode->y;
						pn->z = pathnode->z;
						pn->mapid = pathnode->mapid;
						p->AddPathNode(pathnode->seq, pn);
					}
				}
			}

			p->ComputeLen();
			this->m_taxiPaths.insert(std::map<uint32, TaxiPath*>::value_type(p->id, p));
		}
	}
}

TaxiPath* TaxiMgr::GetTaxiPath(uint32 path)
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;

	itr = this->m_taxiPaths.find(path);

	if (itr == m_taxiPaths.end())
		return NULL;
	else
		return itr->second;
}

TaxiPath* TaxiMgr::GetTaxiPath(uint32 from, uint32 to)
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;

	for (itr = m_taxiPaths.begin(); itr != m_taxiPaths.end(); itr++)
		if ((itr->second->to == to) && (itr->second->from == from))
			return itr->second;

	return NULL;
}

TaxiNode* TaxiMgr::GetTaxiNode(uint32 node)
{
	HM_NAMESPACE::hash_map<uint32, TaxiNode*>::iterator itr;

	itr = this->m_taxiNodes.find(node);

	if (itr == m_taxiNodes.end())
		return NULL;
	else
		return itr->second;
}

uint32 TaxiMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
{
	uint32 nearest = 0;
	float distance = -1;
	float nx, ny, nz, nd;

	HM_NAMESPACE::hash_map<uint32, TaxiNode*>::iterator itr;

	for (itr = m_taxiNodes.begin(); itr != m_taxiNodes.end(); itr++)
	{
		if (itr->second->mapid == mapid)
		{
			nx = itr->second->x - x;
			ny = itr->second->y - y;
			nz = itr->second->z - z;
			nd = nx * nx + ny * ny + nz * nz;
			if( nd < distance || distance < 0 )
			{
				distance = nd;
				nearest = itr->second->id;
			}
		}
	}

	return nearest;
}

bool TaxiMgr::GetGlobalTaxiNodeMask( uint32 curloc, uint32 *Mask )
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;
	uint8 field;

	for (itr = m_taxiPaths.begin(); itr != m_taxiPaths.end(); itr++)
	{
		/*if( itr->second->from == curloc )
		{*/
			field = (uint8)((itr->second->to - 1) / 32);
			Mask[field] |= 1 << ( (itr->second->to - 1 ) % 32 );
		//}
	}

	return true;
}
<commit_msg>FIXED: Potentially uninitialized variables<commit_after>/*
 * ArcEmu MMORPG Server
 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
 * Copyright (C) 2008-2009 <http://www.ArcEmu.org/>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "StdAfx.h"

initialiseSingleton( TaxiMgr );

/************************
 *	   TaxiPath	   *
 ************************/

void TaxiPath::ComputeLen()
{
	m_length1 = m_length1 = 0;
	m_map1 = m_map2 = 0;
	float * curptr = &m_length1;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float x = itr->second->x;
	float y = itr->second->y;
	float z = itr->second->z;
	uint32 curmap = itr->second->mapid;
	m_map1 = curmap;

	itr++;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != curmap )
		{
			curptr = &m_length2;
			m_map2 = itr->second->mapid;
			curmap = itr->second->mapid;
		}

		*curptr += sqrt((itr->second->x - x)*(itr->second->x - x) +
			(itr->second->y - y)*(itr->second->y - y) +
			(itr->second->z - z)*(itr->second->z - z));

		x = itr->second->x;
		y = itr->second->y;
		z = itr->second->z;
		itr++;
	}
}

void TaxiPath::SetPosForTime(float &x, float &y, float &z, uint32 time, uint32 *last_node, uint32 mapid)
{
	if (!time)
		return;

	float length;
	if( mapid == m_map1 )
		length = m_length1;
	else
		length = m_length2;

	float traveled_len = (time/(length * TAXI_TRAVEL_SPEED))*length;
	uint32 len = 0;

	x = 0;
	y = 0;
	z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx, ny, nz;
	nx = ny = nz = 0.0f;
	bool set = false;
	uint32 nodecounter = 0;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != mapid )
		{
			itr++;
			nodecounter++;
			continue;
		}

		if(!set)
		{
			nx = itr->second->x;
			ny = itr->second->y;
			nz = itr->second->z;
			set = true;
			continue;
		}

		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len >= traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			*last_node = nodecounter;
			return;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
		nodecounter++;
	}

	x = nx;
	y = ny;
	z = nz;
}

TaxiPathNode* TaxiPath::GetPathNode(uint32 i)
{
	if (m_pathNodes.find(i) == m_pathNodes.end())
		return NULL;
	else
		return m_pathNodes.find(i)->second;
}

void TaxiPath::SendMoveForTime(Player *riding, Player *to, uint32 time)
{
	if (!time)
		return;

	float length;
	uint32 mapid = riding->GetMapId();
	if( mapid == m_map1 )
		length = m_length1;
	else
		length = m_length2;

	float traveled_len = (time/(length * TAXI_TRAVEL_SPEED))*length;
	uint32 len = 0;
	float x = 0,y = 0,z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx, ny, nz;
	nx = ny = nz = 0.0f;
	bool set = false;
	uint32 nodecounter = 1;

	while (itr != m_pathNodes.end())
	{
		if( itr->second->mapid != mapid )
		{
			itr++;
			nodecounter++;
			continue;
		}

		if(!set)
		{
			nx = itr->second->x;
			ny = itr->second->y;
			nz = itr->second->z;
			set = true;
			continue;
		}

		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len >= traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			break;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
	}

	if (itr == m_pathNodes.end())
		return;

	WorldPacket * data = new WorldPacket(SMSG_MONSTER_MOVE, 2000);
	size_t pos;

	*data << riding->GetNewGUID();
	*data << riding->GetPositionX( ) << riding->GetPositionY( ) << riding->GetPositionZ( );
	*data << getMSTime();
	*data << uint8( 0 );
	*data << uint32( 0x00000300 );
	*data << uint32( uint32((length * TAXI_TRAVEL_SPEED) - time));
	*data << uint32( nodecounter );
	pos = data->wpos();
	*data << nx << ny << nz;

	while (itr != m_pathNodes.end())
	{
		TaxiPathNode *pn = itr->second;
		if( pn->mapid != mapid )
			break;

		*data << pn->x << pn->y << pn->z;
		++itr;
		++nodecounter;
	}

	*(uint32*)&(data->contents()[pos]) = nodecounter;
	to->delayedPackets.add(data);
/*	if (!time)
		return;

	float traveled_len = (time/(getLength() * TAXI_TRAVEL_SPEED))*getLength();;
	uint32 len = 0, count = 0;
	float x = 0,y = 0,z = 0;

	if (!m_pathNodes.size())
		return;

	std::map<uint32, TaxiPathNode*>::iterator itr;
	itr = m_pathNodes.begin();

	float nx = itr->second->x;
	float ny = itr->second->y;
	float nz = itr->second->z;
	itr++;

	while (itr != m_pathNodes.end())
	{
		len = (uint32)sqrt((itr->second->x - nx)*(itr->second->x - nx) +
			(itr->second->y - ny)*(itr->second->y - ny) +
			(itr->second->z - nz)*(itr->second->z - nz));

		if (len > traveled_len)
		{
			x = (itr->second->x - nx)*(traveled_len/len) + nx;
			y = (itr->second->y - ny)*(traveled_len/len) + ny;
			z = (itr->second->z - nz)*(traveled_len/len) + nz;
			break;
		}
		else
		{
			traveled_len -= len;
		}

		nx = itr->second->x;
		ny = itr->second->y;
		nz = itr->second->z;
		itr++;
		count++;
	}

	if (itr == m_pathNodes.end())
		return;

	WorldPacket * data = new WorldPacket(SMSG_MONSTER_MOVE, 2000);

	*data << riding->GetNewGUID();
	*data << riding->GetPositionX( ) << riding->GetPositionY( ) << riding->GetPositionZ( );
	*data << getMSTime();
	*data << uint8( 0 );
	*data << uint32( 0x00000300 );
	*data << uint32( uint32((getLength() * TAXI_TRAVEL_SPEED) - time));
	*data << uint32( GetNodeCount() - count );
	*data << nx << ny << nz;
	while (itr != m_pathNodes.end())
	{
		TaxiPathNode *pn = itr->second;
		*data << pn->x << pn->y << pn->z;
		itr++;
	}
	//to->GetSession()->SendPacket(&data);
	to->delayedPackets.add(data);*/
}

/***********************
 *	   TaxiMgr	   *
 ***********************/

void TaxiMgr::_LoadTaxiNodes()
{
	uint32 i;

	for(i = 0; i < dbcTaxiNode.GetNumRows(); i++)
	{
		DBCTaxiNode *node = dbcTaxiNode.LookupRow(i);
		if (node)
		{
			TaxiNode *n = new TaxiNode;
			n->id = node->id;
			n->mapid = node->mapid;
			n->alliance_mount = node->alliance_mount;
			n->horde_mount = node->horde_mount;
			n->x = node->x;
			n->y = node->y;
			n->z = node->z;

			this->m_taxiNodes.insert(std::map<uint32, TaxiNode*>::value_type(n->id, n));
		}
	}

	//todo: load mounts
}

void TaxiMgr::_LoadTaxiPaths()
{
	uint32 i, j;

	for(i = 0; i < dbcTaxiPath.GetNumRows(); i++)
	{
		DBCTaxiPath *path = dbcTaxiPath.LookupRow(i);

		if (path)
		{
			TaxiPath *p = new TaxiPath;
			p->from = path->from;
			p->to = path->to;
			p->id = path->id;
			p->price = path->price;

			//Load Nodes
			for(j = 0; j < dbcTaxiPathNode.GetNumRows(); j++)
			{
				DBCTaxiPathNode *pathnode = dbcTaxiPathNode.LookupRow(j);

				if (pathnode)
				{
					if (pathnode->path == p->id)
					{
						TaxiPathNode *pn = new TaxiPathNode;
						pn->x = pathnode->x;
						pn->y = pathnode->y;
						pn->z = pathnode->z;
						pn->mapid = pathnode->mapid;
						p->AddPathNode(pathnode->seq, pn);
					}
				}
			}

			p->ComputeLen();
			this->m_taxiPaths.insert(std::map<uint32, TaxiPath*>::value_type(p->id, p));
		}
	}
}

TaxiPath* TaxiMgr::GetTaxiPath(uint32 path)
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;

	itr = this->m_taxiPaths.find(path);

	if (itr == m_taxiPaths.end())
		return NULL;
	else
		return itr->second;
}

TaxiPath* TaxiMgr::GetTaxiPath(uint32 from, uint32 to)
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;

	for (itr = m_taxiPaths.begin(); itr != m_taxiPaths.end(); itr++)
		if ((itr->second->to == to) && (itr->second->from == from))
			return itr->second;

	return NULL;
}

TaxiNode* TaxiMgr::GetTaxiNode(uint32 node)
{
	HM_NAMESPACE::hash_map<uint32, TaxiNode*>::iterator itr;

	itr = this->m_taxiNodes.find(node);

	if (itr == m_taxiNodes.end())
		return NULL;
	else
		return itr->second;
}

uint32 TaxiMgr::GetNearestTaxiNode( float x, float y, float z, uint32 mapid )
{
	uint32 nearest = 0;
	float distance = -1;
	float nx, ny, nz, nd;

	HM_NAMESPACE::hash_map<uint32, TaxiNode*>::iterator itr;

	for (itr = m_taxiNodes.begin(); itr != m_taxiNodes.end(); itr++)
	{
		if (itr->second->mapid == mapid)
		{
			nx = itr->second->x - x;
			ny = itr->second->y - y;
			nz = itr->second->z - z;
			nd = nx * nx + ny * ny + nz * nz;
			if( nd < distance || distance < 0 )
			{
				distance = nd;
				nearest = itr->second->id;
			}
		}
	}

	return nearest;
}

bool TaxiMgr::GetGlobalTaxiNodeMask( uint32 curloc, uint32 *Mask )
{
	HM_NAMESPACE::hash_map<uint32, TaxiPath*>::iterator itr;
	uint8 field;

	for (itr = m_taxiPaths.begin(); itr != m_taxiPaths.end(); itr++)
	{
		/*if( itr->second->from == curloc )
		{*/
			field = (uint8)((itr->second->to - 1) / 32);
			Mask[field] |= 1 << ( (itr->second->to - 1 ) % 32 );
		//}
	}

	return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_SPARC_ISA_TRAITS_HH__
#define __ARCH_SPARC_ISA_TRAITS_HH__

#include "arch/sparc/types.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
#include "sim/host.hh"

class ThreadContext;
class FastCPU;
//class FullCPU;
class Checkpoint;

class StaticInst;
class StaticInstPtr;

namespace BigEndianGuest {}

#if FULL_SYSTEM
#include "arch/sparc/isa_fullsys_traits.hh"
#endif

namespace SparcISA
{
    class RegFile;

    //This makes sure the big endian versions of certain functions are used.
    using namespace BigEndianGuest;

    // Alpha Does NOT have a delay slot
    #define ISA_HAS_DELAY_SLOT 1

    //TODO this needs to be a SPARC Noop
    // Alpha UNOP (ldq_u r31,0(r0))
    const MachInst NoopMachInst = 0x2ffe0000;

    const int NumIntRegs = 32;
    const int NumFloatRegs = 64;
    const int NumMiscRegs = 40;

    // These enumerate all the registers for dependence tracking.
    enum DependenceTags {
        // 0..31 are the integer regs 0..31
        // 32..95 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag)
        FP_Base_DepTag = NumIntRegs,
        Ctrl_Base_DepTag = NumIntRegs + NumFloatRegs,
        //XXX These are here solely to get compilation and won't work
        Fpcr_DepTag = 0,
        Uniq_DepTag = 0
    };

    // MAXTL - maximum trap level
    const int MaxPTL = 2;
    const int MaxTL  = 6;
    const int MaxGL  = 3;
    const int MaxPGL = 2;

    // NWINDOWS - number of register windows, can be 3 to 32
    const int NWindows = 32;

    // semantically meaningful register indices
    const int ZeroReg = 0;	// architecturally meaningful
    // the rest of these depend on the ABI
    const int StackPointerReg = 14;
    const int ReturnAddressReg = 31; // post call, precall is 15
    const int ReturnValueReg = 8; // Post return, 24 is pre-return.
    const int FramePointerReg = 30;
    const int ArgumentReg0 = 8;
    const int ArgumentReg1 = 9;
    const int ArgumentReg2 = 10;
    const int ArgumentReg3 = 11;
    const int ArgumentReg4 = 12;
    const int ArgumentReg5 = 13;
    // Some OS syscall use a second register (o1) to return a second value
    const int SyscallPseudoReturnReg = ArgumentReg1;

    //XXX These numbers are bogus
    const int MaxInstSrcRegs = 8;
    const int MaxInstDestRegs = 9;

    //8K. This value is implmentation specific; and should probably
    //be somewhere else.
    const int LogVMPageSize = 13;
    const int VMPageSize = (1 << LogVMPageSize);

    //Why does both the previous set of constants and this one exist?
    const int PageShift = 13;
    const int PageBytes = ULL(1) << PageShift;

    const int BranchPredAddrShiftAmt = 2;

    const int MachineBytes = 8;
    const int WordBytes = 4;
    const int HalfwordBytes = 2;
    const int ByteBytes = 1;

    void serialize(std::ostream & os);

    void unserialize(Checkpoint *cp, const std::string &section);

    StaticInstPtr decodeInst(ExtMachInst);

    // return a no-op instruction... used for instruction fetch faults
    extern const MachInst NoopMachInst;
}

#endif // __ARCH_SPARC_ISA_TRAITS_HH__
<commit_msg>Replace the Alpha No op with a SPARC one.<commit_after>/*
 * Copyright (c) 2003-2005 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Gabe Black
 */

#ifndef __ARCH_SPARC_ISA_TRAITS_HH__
#define __ARCH_SPARC_ISA_TRAITS_HH__

#include "arch/sparc/types.hh"
#include "base/misc.hh"
#include "config/full_system.hh"
#include "sim/host.hh"

class ThreadContext;
class FastCPU;
//class FullCPU;
class Checkpoint;

class StaticInst;
class StaticInstPtr;

namespace BigEndianGuest {}

#if FULL_SYSTEM
#include "arch/sparc/isa_fullsys_traits.hh"
#endif

namespace SparcISA
{
    class RegFile;

    //This makes sure the big endian versions of certain functions are used.
    using namespace BigEndianGuest;

    // SPARC have a delay slot
    #define ISA_HAS_DELAY_SLOT 1

    // SPARC NOP (sethi %(hi(0), g0)
    const MachInst NoopMachInst = 0x01000000;

    const int NumIntRegs = 32;
    const int NumFloatRegs = 64;
    const int NumMiscRegs = 40;

    // These enumerate all the registers for dependence tracking.
    enum DependenceTags {
        // 0..31 are the integer regs 0..31
        // 32..95 are the FP regs 0..31, i.e. use (reg + FP_Base_DepTag)
        FP_Base_DepTag = NumIntRegs,
        Ctrl_Base_DepTag = NumIntRegs + NumFloatRegs,
        //XXX These are here solely to get compilation and won't work
        Fpcr_DepTag = 0,
        Uniq_DepTag = 0
    };

    // MAXTL - maximum trap level
    const int MaxPTL = 2;
    const int MaxTL  = 6;
    const int MaxGL  = 3;
    const int MaxPGL = 2;

    // NWINDOWS - number of register windows, can be 3 to 32
    const int NWindows = 32;

    // semantically meaningful register indices
    const int ZeroReg = 0;	// architecturally meaningful
    // the rest of these depend on the ABI
    const int StackPointerReg = 14;
    const int ReturnAddressReg = 31; // post call, precall is 15
    const int ReturnValueReg = 8; // Post return, 24 is pre-return.
    const int FramePointerReg = 30;
    const int ArgumentReg0 = 8;
    const int ArgumentReg1 = 9;
    const int ArgumentReg2 = 10;
    const int ArgumentReg3 = 11;
    const int ArgumentReg4 = 12;
    const int ArgumentReg5 = 13;
    // Some OS syscall use a second register (o1) to return a second value
    const int SyscallPseudoReturnReg = ArgumentReg1;

    //XXX These numbers are bogus
    const int MaxInstSrcRegs = 8;
    const int MaxInstDestRegs = 9;

    //8K. This value is implmentation specific; and should probably
    //be somewhere else.
    const int LogVMPageSize = 13;
    const int VMPageSize = (1 << LogVMPageSize);

    //Why does both the previous set of constants and this one exist?
    const int PageShift = 13;
    const int PageBytes = ULL(1) << PageShift;

    const int BranchPredAddrShiftAmt = 2;

    const int MachineBytes = 8;
    const int WordBytes = 4;
    const int HalfwordBytes = 2;
    const int ByteBytes = 1;

    void serialize(std::ostream & os);

    void unserialize(Checkpoint *cp, const std::string &section);

    StaticInstPtr decodeInst(ExtMachInst);

    // return a no-op instruction... used for instruction fetch faults
    extern const MachInst NoopMachInst;
}

#endif // __ARCH_SPARC_ISA_TRAITS_HH__
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <algorithm>
#include <memory>
#include <boost/variant/variant.hpp>

#include "ast/ContextAnnotator.hpp"
#include "ast/SourceFile.hpp"
#include "ast/ASTVisitor.hpp"

#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "BlockContext.hpp"
#include "VisitorUtils.hpp"

using namespace eddic;

class AnnotateVisitor : public boost::static_visitor<> {
    private:
        std::shared_ptr<GlobalContext> globalContext;
        std::shared_ptr<FunctionContext> functionContext;
        std::shared_ptr<Context> currentContext;

    public:
        AUTO_RECURSE_BINARY_CONDITION()
        AUTO_RECURSE_FUNCTION_CALLS()
        AUTO_RECURSE_BUILTIN_OPERATORS()

        void operator()(ast::SourceFile& program){
            currentContext = program.Content->context = globalContext = std::make_shared<GlobalContext>();

            visit_each(*this, program.Content->blocks);
        }

        void operator()(ast::GlobalVariableDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::GlobalArrayDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::FunctionDeclaration& function){
            currentContext = function.Content->context = functionContext = std::make_shared<FunctionContext>(currentContext);

            visit_each(*this, function.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::While& while_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, while_.Content->condition);

            visit_each(*this, while_.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::DoWhile& while_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, while_.Content->condition);

            visit_each(*this, while_.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::For& for_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_optional(*this, for_.Content->start);
            visit_optional(*this, for_.Content->condition);
            visit_optional(*this, for_.Content->repeat);

            visit_each(*this, for_.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::Foreach& foreach){
            foreach.Content->context = currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_each(*this, foreach.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::ForeachIn& foreach){
            foreach.Content->context = currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_each(*this, foreach.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::If& if_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, if_.Content->condition);

            visit_each(*this, if_.Content->instructions);

            currentContext = currentContext->parent();

            visit_each_non_variant(*this, if_.Content->elseIfs);
            visit_optional_non_variant(*this, if_.Content->else_);
        }

        void operator()(ast::ElseIf& elseIf){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, elseIf.condition);

            visit_each(*this, elseIf.instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::Else& else_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_each(*this, else_.instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::VariableDeclaration& declaration){
            declaration.Content->context = currentContext;

            visit(*this, *declaration.Content->value);
        }

        void operator()(ast::ArrayDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::Assignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->value);
        }

        void operator()(ast::CompoundAssignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->value);
        }

        void operator()(ast::ArrayAssignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->indexValue);
            visit(*this, assignment.Content->value);
        }

        void operator()(ast::Swap& swap){
            swap.Content->context = currentContext;
        }

        void operator()(ast::SuffixOperation& operation){
            operation.Content->context = currentContext;
        }

        void operator()(ast::PrefixOperation& operation){
            operation.Content->context = currentContext;
        }

        void operator()(ast::ComposedValue& value){
            value.Content->context = currentContext;

            visit(*this, value.Content->first);
            for_each(value.Content->operations.begin(), value.Content->operations.end(),
                    [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });
        }

        void operator()(ast::Plus& value){
            visit(*this, value.Content->value);
        }

        void operator()(ast::Minus& value){
            visit(*this, value.Content->value);
        }

        void operator()(ast::VariableValue& variable){
            variable.Content->context = currentContext;
        }

        void operator()(ast::ArrayValue& array){
            array.Content->context = currentContext;

            visit(*this, array.Content->indexValue);
        }

        void operator()(ast::Return& return_){
            return_.Content->context = functionContext;

            visit(*this, return_.Content->value);
        }

        void operator()(ast::Import&){
            //No context there
        }

        void operator()(ast::StandardImport&){
            //No Context there
        }

        void operator()(ast::TerminalNode&){
            //A terminal node has no context
        }
};

void ast::ContextAnnotator::annotate(ast::SourceFile& program) const {
    AnnotateVisitor visitor;
    visitor(program);
}
<commit_msg>Improve the visitor with template functions<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <algorithm>
#include <memory>
#include <boost/variant/variant.hpp>

#include "ast/ContextAnnotator.hpp"
#include "ast/SourceFile.hpp"
#include "ast/ASTVisitor.hpp"

#include "Context.hpp"
#include "GlobalContext.hpp"
#include "FunctionContext.hpp"
#include "BlockContext.hpp"
#include "VisitorUtils.hpp"

using namespace eddic;

class AnnotateVisitor : public boost::static_visitor<> {
    private:
        std::shared_ptr<GlobalContext> globalContext;
        std::shared_ptr<FunctionContext> functionContext;
        std::shared_ptr<Context> currentContext;

    public:
        AUTO_RECURSE_BINARY_CONDITION()
        AUTO_RECURSE_FUNCTION_CALLS()
        AUTO_RECURSE_BUILTIN_OPERATORS()

        void operator()(ast::SourceFile& program){
            currentContext = program.Content->context = globalContext = std::make_shared<GlobalContext>();

            visit_each(*this, program.Content->blocks);
        }

        void operator()(ast::GlobalVariableDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::GlobalArrayDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::FunctionDeclaration& function){
            currentContext = function.Content->context = functionContext = std::make_shared<FunctionContext>(currentContext);

            visit_each(*this, function.Content->instructions);

            currentContext = currentContext->parent();
        }

        template<typename Loop>
        void annotateWhileLoop(Loop& loop){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, loop.Content->condition);

            visit_each(*this, loop.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::While& while_){
            annotateWhileLoop(while_);
        }

        void operator()(ast::DoWhile& while_){
            annotateWhileLoop(while_);
        }

        void operator()(ast::For& for_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_optional(*this, for_.Content->start);
            visit_optional(*this, for_.Content->condition);
            visit_optional(*this, for_.Content->repeat);

            visit_each(*this, for_.Content->instructions);

            currentContext = currentContext->parent();
        }

        template<typename Loop>
        void annotateSimpleLoop(Loop& loop){
            loop.Content->context = currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_each(*this, loop.Content->instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::Foreach& foreach){
            annotateSimpleLoop(foreach);
        }

        void operator()(ast::ForeachIn& foreach){
            annotateSimpleLoop(foreach);
        }

        void operator()(ast::If& if_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, if_.Content->condition);

            visit_each(*this, if_.Content->instructions);

            currentContext = currentContext->parent();

            visit_each_non_variant(*this, if_.Content->elseIfs);
            visit_optional_non_variant(*this, if_.Content->else_);
        }

        void operator()(ast::ElseIf& elseIf){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit(*this, elseIf.condition);

            visit_each(*this, elseIf.instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::Else& else_){
            currentContext = std::make_shared<BlockContext>(currentContext, functionContext);

            visit_each(*this, else_.instructions);

            currentContext = currentContext->parent();
        }

        void operator()(ast::VariableDeclaration& declaration){
            declaration.Content->context = currentContext;

            visit(*this, *declaration.Content->value);
        }

        void operator()(ast::ArrayDeclaration& declaration){
            declaration.Content->context = currentContext;
        }

        void operator()(ast::Assignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->value);
        }

        void operator()(ast::CompoundAssignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->value);
        }

        void operator()(ast::ArrayAssignment& assignment){
            assignment.Content->context = currentContext;

            visit(*this, assignment.Content->indexValue);
            visit(*this, assignment.Content->value);
        }

        void operator()(ast::Swap& swap){
            swap.Content->context = currentContext;
        }

        void operator()(ast::SuffixOperation& operation){
            operation.Content->context = currentContext;
        }

        void operator()(ast::PrefixOperation& operation){
            operation.Content->context = currentContext;
        }

        void operator()(ast::ComposedValue& value){
            value.Content->context = currentContext;

            visit(*this, value.Content->first);
            for_each(value.Content->operations.begin(), value.Content->operations.end(),
                    [&](ast::Operation& operation){ visit(*this, operation.get<1>()); });
        }

        void operator()(ast::Plus& value){
            visit(*this, value.Content->value);
        }

        void operator()(ast::Minus& value){
            visit(*this, value.Content->value);
        }

        void operator()(ast::VariableValue& variable){
            variable.Content->context = currentContext;
        }

        void operator()(ast::ArrayValue& array){
            array.Content->context = currentContext;

            visit(*this, array.Content->indexValue);
        }

        void operator()(ast::Return& return_){
            return_.Content->context = functionContext;

            visit(*this, return_.Content->value);
        }

        void operator()(ast::Import&){
            //No context there
        }

        void operator()(ast::StandardImport&){
            //No Context there
        }

        void operator()(ast::TerminalNode&){
            //A terminal node has no context
        }
};

void ast::ContextAnnotator::annotate(ast::SourceFile& program) const {
    AnnotateVisitor visitor;
    visitor(program);
}
<|endoftext|>


<commit_before>// Copyright 2010-2015 RethinkDB, all rights reserved.
#ifndef BTREE_BACKFILL_DEBUG_HPP_
#define BTREE_BACKFILL_DEBUG_HPP_

#include <string>

#include "btree/keys.hpp"

/* If the `ENABLE_BACKFILL_DEBUG` symbol is defined, then backfilling-related events
will be recorded in a log and indexed by key. This can be useful for diagnosing bugs in
the backfilling logic. Obviously, this should be disabled when not in use. */
#define ENABLE_BACKFILL_DEBUG

#ifdef ENABLE_BACKFILL_DEBUG
void backfill_debug_clear_log();
void backfill_debug_key(const store_key_t &key, const std::string &msg);
void backfill_debug_range(const key_range_t &range, const std::string &msg);
void backfill_debug_all(const std::string &msg);
void backfill_debug_dump_log(const store_key_t &key);
#else
#define backfill_debug_clear_log() ((void)0)
#define backfill_debug_key(key, msg) ((void)0)
#define backfill_debug_range(range, msg) ((void)0)
#define backfill_debug_all(msg) ((void)0)
#define backfill_debug_dump_log(key) ((void)0)
#endif /* ENABLE_BACKFILL_DEBUG */

#endif /* BTREE_BACKFILL_DEBUG_HPP_ */

<commit_msg>Disable backfill debugging, because it shouldn't be on when not in use.<commit_after>// Copyright 2010-2015 RethinkDB, all rights reserved.
#ifndef BTREE_BACKFILL_DEBUG_HPP_
#define BTREE_BACKFILL_DEBUG_HPP_

#include <string>

#include "btree/keys.hpp"

/* If the `ENABLE_BACKFILL_DEBUG` symbol is defined, then backfilling-related events
will be recorded in a log and indexed by key. This can be useful for diagnosing bugs in
the backfilling logic. Obviously, this should be disabled when not in use. */
// #define ENABLE_BACKFILL_DEBUG

#ifdef ENABLE_BACKFILL_DEBUG
void backfill_debug_clear_log();
void backfill_debug_key(const store_key_t &key, const std::string &msg);
void backfill_debug_range(const key_range_t &range, const std::string &msg);
void backfill_debug_all(const std::string &msg);
void backfill_debug_dump_log(const store_key_t &key);
#else
#define backfill_debug_clear_log() ((void)0)
#define backfill_debug_key(key, msg) ((void)0)
#define backfill_debug_range(range, msg) ((void)0)
#define backfill_debug_all(msg) ((void)0)
#define backfill_debug_dump_log(key) ((void)0)
#endif /* ENABLE_BACKFILL_DEBUG */

#endif /* BTREE_BACKFILL_DEBUG_HPP_ */

<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_GRAMMAR_X3_DEF_HPP
#define MAPNIK_TRANSFORM_GRAMMAR_X3_DEF_HPP

#include <mapnik/transform_expression.hpp>
#include <mapnik/transform_expression_grammar_x3.hpp>
#include <mapnik/expression_grammar_x3.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#pragma GCC diagnostic pop

// skewX
BOOST_FUSION_ADAPT_STRUCT(mapnik::skewX_node,
                          (mapnik::expr_node, angle_))

// skewY
BOOST_FUSION_ADAPT_STRUCT(mapnik::skewY_node,
                          (mapnik::expr_node, angle_))

// Following specializations are required to avoid trasferring mapnik::skewX/Y nodes as underlying expressions
//
// template <typename Source, typename Dest>
// inline void
// move_to_plain(Source&& src, Dest& dest, mpl::true_) // src is a single-element tuple
// {
//     dest = std::move(fusion::front(src));
// }
// which will fail to compile with latest (more strict) `mapbox::variant` (boost_1_61)

namespace boost { namespace spirit { namespace x3 { namespace traits {
template <>
inline void move_to<mapnik::skewX_node, mapnik::detail::transform_node>(mapnik::skewX_node && src, mapnik::detail::transform_node& dst)
{
    dst = std::move(src);
}

template <>
inline void move_to<mapnik::skewY_node, mapnik::detail::transform_node>(mapnik::skewY_node && src, mapnik::detail::transform_node& dst)
{
    dst = std::move(src);
}

}}}}

namespace mapnik { namespace grammar {

namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;

// [http://www.w3.org/TR/SVG/coords.html#TransformAttribute]

// The value of the ‘transform’ attribute is a <transform-list>, which
// is defined as a list of transform definitions, which are applied in
// the order provided.  The individual transform definitions are
// separated by whitespace and/or a comma.

using x3::double_;
using x3::no_skip;
using x3::no_case;
using x3::lit;

auto const create_expr_node = [](auto const& ctx)
{
    _val(ctx) = _attr(ctx);
};

auto const construct_matrix = [] (auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& a = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& b = boost::fusion::at<boost::mpl::int_<1>>(attr);
    auto const& c = boost::fusion::at<boost::mpl::int_<2>>(attr);
    auto const& d = boost::fusion::at<boost::mpl::int_<3>>(attr);
    auto const& e = boost::fusion::at<boost::mpl::int_<4>>(attr);
    auto const& f = boost::fusion::at<boost::mpl::int_<5>>(attr);
    _val(ctx) = mapnik::matrix_node(a, b, c, d, e, f);
};

auto const construct_translate = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& dx = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& dy = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    _val(ctx) = mapnik::translate_node(dx, dy);
};

auto const construct_scale = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& sx = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& sy = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    _val(ctx) = mapnik::scale_node(sx, sy);
};

auto const construct_rotate = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& a = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& sx = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    auto const& sy = boost::fusion::at<boost::mpl::int_<2>>(attr); //optional
    _val(ctx) = mapnik::rotate_node(a, sx, sy);
};

// starting rule
transform_expression_grammar_type const transform("transform");
// rules
x3::rule<class transform_list_class, mapnik::transform_list> transform_list_rule("transform list");
x3::rule<class transform_node_class, mapnik::transform_node> transform_node_rule("transform node");
x3::rule<class matrix_node_class, mapnik::matrix_node> matrix("matrix node");
x3::rule<class translate_node_class, mapnik::translate_node> translate("translate node");
x3::rule<class scale_node_class, mapnik::scale_node> scale("scale node");
x3::rule<class rotate_node_class, mapnik::rotate_node> rotate("rotate node");
x3::rule<class skewX_node_class, mapnik::skewX_node> skewX("skew X node");
x3::rule<class skewY_node_class, mapnik::skewY_node> skewY("skew Y node");
x3::rule<class expr_tag, mapnik::expr_node> expr("Expression");
x3::rule<class sep_expr_tag, mapnik::expr_node> sep_expr("Separated Expression");

// start
auto const transform_def = transform_list_rule;

auto const transform_list_rule_def = transform_node_rule % *lit(',');

auto const transform_node_rule_def = matrix | translate  | scale | rotate | skewX | skewY ;

// number or attribute
auto const atom = x3::rule<class atom_tag, expr_node> {} = double_[create_expr_node]
    ;
// FIXME - ^ add feature attribute support e.g attr [ _val = construct<mapnik::attribute>(_1) ];

auto const sep_atom = x3::rule<class sep_atom_tag, expr_node> {} = -lit(',') >> double_[create_expr_node]
    ;

auto const expr_def = expression_grammar();
// Individual arguments in lists containing one or more compound
// expressions are separated by a comma.
auto const sep_expr_def = lit(',') > expr
    ;

// matrix(<a> <b> <c> <d> <e> <f>)
auto const matrix_def = no_case[lit("matrix")] > '('
    > ((atom >> sep_atom >> sep_atom >> sep_atom >> sep_atom >> sep_atom >> lit(')'))[construct_matrix]
       |
       (expr > sep_expr > sep_expr > sep_expr > sep_expr > sep_expr > lit(')'))[construct_matrix])
    ;

// translate(<tx> [<ty>])
auto const translate_def = no_case[lit("translate")] > lit('(')
    > (( atom >> -sep_atom  >> lit(')'))[construct_translate]
       |
       ( expr > -sep_expr > lit(')'))[construct_translate]
        );

// scale(<sx> [<sy>])
auto const scale_def = no_case[lit("scale")] > lit('(')
    > (( atom >> -sep_atom  >> lit(')'))[construct_scale]
       |
       ( expr > -sep_expr > lit(')'))[construct_scale]
        );

// rotate(<rotate-angle> [<cx> <cy>])
auto const rotate_def = no_case[lit("rotate")] > lit('(')
    > ((atom >> -sep_atom >> -sep_atom >>  lit(')'))[construct_rotate]
       |
       (expr > -sep_expr > -sep_expr > lit(')'))[construct_rotate]
        );

// skewX(<skew-angle>)
auto const skewX_def = no_case[lit("skewX")]
    > '(' > expr > ')';

// skewY(<skew-angle>)
auto const skewY_def = no_case[lit("skewY")]
    > '(' >  expr  > ')';

BOOST_SPIRIT_DEFINE (
    expr,
    sep_expr,
    transform,
    transform_list_rule,
    transform_node_rule,
    matrix,
    translate,
    scale,
    rotate,
    skewX,
    skewY);

}} // ns

namespace mapnik
{
grammar::transform_expression_grammar_type const& transform_expression_grammar()
{
    return grammar::transform;
}
}

#endif
<commit_msg>cleanup<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#ifndef MAPNIK_TRANSFORM_GRAMMAR_X3_DEF_HPP
#define MAPNIK_TRANSFORM_GRAMMAR_X3_DEF_HPP

#include <mapnik/transform_expression.hpp>
#include <mapnik/transform_expression_grammar_x3.hpp>
#include <mapnik/expression_grammar_x3.hpp>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#pragma GCC diagnostic pop

// skewX
BOOST_FUSION_ADAPT_STRUCT(mapnik::skewX_node,
                          (mapnik::expr_node, angle_))

// skewY
BOOST_FUSION_ADAPT_STRUCT(mapnik::skewY_node,
                          (mapnik::expr_node, angle_))

// Following specializations are required to avoid trasferring mapnik::skewX/Y nodes as underlying expressions
//
// template <typename Source, typename Dest>
// inline void
// move_to_plain(Source&& src, Dest& dest, mpl::true_) // src is a single-element tuple
// {
//     dest = std::move(fusion::front(src));
// }
// which will fail to compile with latest (more strict) `mapbox::variant` (boost_1_61)

namespace boost { namespace spirit { namespace x3 { namespace traits {
template <>
inline void move_to<mapnik::skewX_node, mapnik::detail::transform_node>(mapnik::skewX_node && src, mapnik::detail::transform_node& dst)
{
    dst = std::move(src);
}

template <>
inline void move_to<mapnik::skewY_node, mapnik::detail::transform_node>(mapnik::skewY_node && src, mapnik::detail::transform_node& dst)
{
    dst = std::move(src);
}

}}}}

namespace mapnik { namespace grammar {

namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;

// [http://www.w3.org/TR/SVG/coords.html#TransformAttribute]

// The value of the ‘transform’ attribute is a <transform-list>, which
// is defined as a list of transform definitions, which are applied in
// the order provided.  The individual transform definitions are
// separated by whitespace and/or a comma.

using x3::double_;
using x3::no_skip;
using x3::no_case;
using x3::lit;

auto const create_expr_node = [](auto const& ctx)
{
    _val(ctx) = _attr(ctx);
};

auto const construct_matrix = [] (auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& a = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& b = boost::fusion::at<boost::mpl::int_<1>>(attr);
    auto const& c = boost::fusion::at<boost::mpl::int_<2>>(attr);
    auto const& d = boost::fusion::at<boost::mpl::int_<3>>(attr);
    auto const& e = boost::fusion::at<boost::mpl::int_<4>>(attr);
    auto const& f = boost::fusion::at<boost::mpl::int_<5>>(attr);
    _val(ctx) = mapnik::matrix_node(a, b, c, d, e, f);
};

auto const construct_translate = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& dx = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& dy = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    _val(ctx) = mapnik::translate_node(dx, dy);
};

auto const construct_scale = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& sx = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& sy = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    _val(ctx) = mapnik::scale_node(sx, sy);
};

auto const construct_rotate = [](auto const& ctx)
{
    auto const& attr = _attr(ctx);
    auto const& a = boost::fusion::at<boost::mpl::int_<0>>(attr);
    auto const& sx = boost::fusion::at<boost::mpl::int_<1>>(attr); //optional
    auto const& sy = boost::fusion::at<boost::mpl::int_<2>>(attr); //optional
    _val(ctx) = mapnik::rotate_node(a, sx, sy);
};

// starting rule
transform_expression_grammar_type const transform("transform");
// rules
x3::rule<class transform_list_class, mapnik::transform_list> transform_list_rule("transform list");
x3::rule<class transform_node_class, mapnik::transform_node> transform_node_rule("transform node");
x3::rule<class matrix_node_class, mapnik::matrix_node> matrix("matrix node");
x3::rule<class translate_node_class, mapnik::translate_node> translate("translate node");
x3::rule<class scale_node_class, mapnik::scale_node> scale("scale node");
x3::rule<class rotate_node_class, mapnik::rotate_node> rotate("rotate node");
x3::rule<class skewX_node_class, mapnik::skewX_node> skewX("skew X node");
x3::rule<class skewY_node_class, mapnik::skewY_node> skewY("skew Y node");
x3::rule<class expr_tag, mapnik::expr_node> expr("Expression");
x3::rule<class sep_expr_tag, mapnik::expr_node> sep_expr("Separated Expression");

// start
auto const transform_def = transform_list_rule;

auto const transform_list_rule_def = transform_node_rule % *lit(',');

auto const transform_node_rule_def = matrix | translate  | scale | rotate | skewX | skewY ;

// number or attribute
auto const atom = x3::rule<class atom_tag, expr_node> {} = double_[create_expr_node]
    ;

auto const sep_atom = x3::rule<class sep_atom_tag, expr_node> {} = -lit(',') >> double_[create_expr_node]
    ;

auto const expr_def = expression_grammar();
// Individual arguments in lists containing one or more compound
// expressions are separated by a comma.
auto const sep_expr_def = lit(',') > expr
    ;

// matrix(<a> <b> <c> <d> <e> <f>)
auto const matrix_def = no_case[lit("matrix")] > '('
    > ((atom >> sep_atom >> sep_atom >> sep_atom >> sep_atom >> sep_atom >> lit(')'))[construct_matrix]
       |
       (expr > sep_expr > sep_expr > sep_expr > sep_expr > sep_expr > lit(')'))[construct_matrix])
    ;

// translate(<tx> [<ty>])
auto const translate_def = no_case[lit("translate")] > lit('(')
    > (( atom >> -sep_atom  >> lit(')'))[construct_translate]
       |
       ( expr > -sep_expr > lit(')'))[construct_translate]
        );

// scale(<sx> [<sy>])
auto const scale_def = no_case[lit("scale")] > lit('(')
    > (( atom >> -sep_atom  >> lit(')'))[construct_scale]
       |
       ( expr > -sep_expr > lit(')'))[construct_scale]
        );

// rotate(<rotate-angle> [<cx> <cy>])
auto const rotate_def = no_case[lit("rotate")] > lit('(')
    > ((atom >> -sep_atom >> -sep_atom >>  lit(')'))[construct_rotate]
       |
       (expr > -sep_expr > -sep_expr > lit(')'))[construct_rotate]
        );

// skewX(<skew-angle>)
auto const skewX_def = no_case[lit("skewX")]
    > '(' > expr > ')';

// skewY(<skew-angle>)
auto const skewY_def = no_case[lit("skewY")]
    > '(' >  expr  > ')';

BOOST_SPIRIT_DEFINE (
    expr,
    sep_expr,
    transform,
    transform_list_rule,
    transform_node_rule,
    matrix,
    translate,
    scale,
    rotate,
    skewX,
    skewY);

}} // ns

namespace mapnik
{
grammar::transform_expression_grammar_type const& transform_expression_grammar()
{
    return grammar::transform;
}
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <tudocomp/compressors/lz78/LZ78Trie.hpp>
#include <tudocomp/Algorithm.hpp>

namespace tdc {
namespace lz78 {

class BinarySortedTrie : public Algorithm, public LZ78Trie<factorid_t> {
    /*
     * The trie is not stored in standard form. Each node stores the pointer to its first child and a pointer to its next sibling (first as first come first served)
     */
    std::vector<factorid_t> m_first_child;
    std::vector<factorid_t> m_next_sibling;
    std::vector<literal_t> m_literal;

    IF_STATS(
        size_t m_resizes = 0;
        size_t m_specialresizes = 0;
    )
public:
    inline static Meta meta() {
        Meta m("lz78trie", "binarysorted", "Lempel-Ziv 78 Sorted Binary Trie");
        return m;
    }
    inline BinarySortedTrie(Env&& env, size_t n, const size_t& remaining_characters, factorid_t reserve = 0)
        : Algorithm(std::move(env))
          , LZ78Trie(n,remaining_characters)
    {
        if(reserve > 0) {
            m_first_child.reserve(reserve);
            m_next_sibling.reserve(reserve);
            m_literal.reserve(reserve);
        }
    }

    node_t add_rootnode(uliteral_t c) override {
        m_first_child.push_back(undef_id);
        m_next_sibling.push_back(undef_id);
        m_literal.push_back(c);
        return size() - 1;
    }

    node_t get_rootnode(uliteral_t c) override {
        return c;
    }

    void clear() override {
        m_first_child.clear();
        m_next_sibling.clear();
        m_literal.clear();

    }

    inline factorid_t new_node(uliteral_t c, const factorid_t m_first_child_id, const factorid_t m_next_sibling_id) {
        m_first_child.push_back(m_first_child_id);
        m_next_sibling.push_back(m_next_sibling_id);
        m_literal.push_back(c);
        return undef_id;
    }

    node_t find_or_insert(const node_t& parent_w, uliteral_t c) override {
        auto parent = parent_w.id();
        const factorid_t newleaf_id = size(); //! if we add a new node, its index will be equal to the current size of the dictionary

        DCHECK_LT(parent, size());

        if(m_first_child[parent] == undef_id) {
            m_first_child[parent] = newleaf_id;
            return new_node(c, undef_id, undef_id);
        } else {
            factorid_t node = m_first_child[parent];
            if(m_literal[node] > c) {
                m_first_child[parent] = newleaf_id;
                return new_node(c, undef_id, node);
            }
            while(true) { // search the binary tree stored in parent (following left/right siblings)
                if(c == m_literal[node]) return node;
                if(m_next_sibling[node] == undef_id) {
                    m_next_sibling[node] = newleaf_id;
                    return new_node(c, undef_id, undef_id);
                }
                const factorid_t nextnode = m_next_sibling[node];
                if(m_literal[nextnode] > c) {
                    m_next_sibling[node] = newleaf_id;
                    return new_node(c, undef_id, nextnode);
                }
                node = m_next_sibling[node];
        if(m_first_child.capacity() == m_first_child.size()) {
            const size_t newbound =    m_first_child.size()+lz78_expected_number_of_remaining_elements(size(),m_n,m_remaining_characters);
            if(newbound < m_first_child.size()*2 ) {
                m_first_child.reserve   (newbound);
                m_next_sibling.reserve  (newbound);
                m_literal.reserve       (newbound);
                IF_STATS(++m_specialresizes);
            }
            IF_STATS(++m_resizes);
        }
            }
        }
        DCHECK(false);
        return undef_id;
    }

    factorid_t size() const override {
        return m_first_child.size();
    }

};

}} //ns

<commit_msg>fix bug in sorted binary trie<commit_after>#pragma once

#include <vector>
#include <tudocomp/compressors/lz78/LZ78Trie.hpp>
#include <tudocomp/Algorithm.hpp>

namespace tdc {
namespace lz78 {

class BinarySortedTrie : public Algorithm, public LZ78Trie<factorid_t> {
    /*
     * The trie is not stored in standard form. Each node stores the pointer to its first child and a pointer to its next sibling (first as first come first served)
     */
    std::vector<factorid_t> m_first_child;
    std::vector<factorid_t> m_next_sibling;
    std::vector<uliteral_t> m_literal;

    IF_STATS(
        size_t m_resizes = 0;
        size_t m_specialresizes = 0;
    )
public:
    inline static Meta meta() {
        Meta m("lz78trie", "binarysorted", "Lempel-Ziv 78 Sorted Binary Trie");
        return m;
    }
    inline BinarySortedTrie(Env&& env, size_t n, const size_t& remaining_characters, factorid_t reserve = 0)
        : Algorithm(std::move(env))
          , LZ78Trie(n,remaining_characters)
    {
        if(reserve > 0) {
            m_first_child.reserve(reserve);
            m_next_sibling.reserve(reserve);
            m_literal.reserve(reserve);
        }
    }

    node_t add_rootnode(uliteral_t c) override {
        m_first_child.push_back(undef_id);
        m_next_sibling.push_back(undef_id);
        m_literal.push_back(c);
        return size() - 1;
    }

    node_t get_rootnode(uliteral_t c) override {
        return c;
    }

    void clear() override {
        m_first_child.clear();
        m_next_sibling.clear();
        m_literal.clear();

    }

    inline factorid_t new_node(uliteral_t c, const factorid_t m_first_child_id, const factorid_t m_next_sibling_id) {
        m_first_child.push_back(m_first_child_id);
        m_next_sibling.push_back(m_next_sibling_id);
        m_literal.push_back(c);
        return undef_id;
    }

    node_t find_or_insert(const node_t& parent_w, uliteral_t c) override {
        auto parent = parent_w.id();
        const factorid_t newleaf_id = size(); //! if we add a new node, its index will be equal to the current size of the dictionary

        DCHECK_LT(parent, size());

        if(m_first_child[parent] == undef_id) {
            m_first_child[parent] = newleaf_id;
            return new_node(c, undef_id, undef_id);
        } else {
            factorid_t node = m_first_child[parent];
            if(m_literal[node] > c) {
                m_first_child[parent] = newleaf_id;
                return new_node(c, undef_id, node);
            }
            while(true) { // search the binary tree stored in parent (following left/right siblings)
                if(c == m_literal[node]) return node;
                if(m_next_sibling[node] == undef_id) {
                    m_next_sibling[node] = newleaf_id;
                    return new_node(c, undef_id, undef_id);
                }
                const factorid_t nextnode = m_next_sibling[node];
                if(m_literal[nextnode] > c) {
                    m_next_sibling[node] = newleaf_id;
                    return new_node(c, undef_id, nextnode);
                }
                node = m_next_sibling[node];
        if(m_first_child.capacity() == m_first_child.size()) {
            const size_t newbound =    m_first_child.size()+lz78_expected_number_of_remaining_elements(size(),m_n,m_remaining_characters);
            if(newbound < m_first_child.size()*2 ) {
                m_first_child.reserve   (newbound);
                m_next_sibling.reserve  (newbound);
                m_literal.reserve       (newbound);
                IF_STATS(++m_specialresizes);
            }
            IF_STATS(++m_resizes);
        }
            }
        }
        DCHECK(false);
        return undef_id;
    }

    factorid_t size() const override {
        return m_first_child.size();
    }

};

}} //ns

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

 #pragma once

namespace choreograph
{

// A motion describes a one-dimensional change through time.
// These can be ease equations, always return the same value, or sample some data. Whatever you want.
// For classic motion, EaseFn( 0 ) = 0, EaseFn( 1 ) = 1.
// set( 0.0f ).move( )
// then again, might just make a curve struct that is callable and have a way to set its initial and final derivatives.
typedef std::function<float (float)> EaseFn;

struct Hold
{
  float operator() ( float t ) const { return 0.0f; }
};

struct LinearRamp
{
  float operator() ( float t ) const { return t; }
};

inline float easeNone( float t ) { return t; }

//! A Position describes a point in time.
template<typename T>
struct Position
{
  Position() = default;

  Position( const T &value, float time = 0.0f ):
    time( time ),
    value( value )
  {}

  float time = 0.0f;
  T     value;
};

//! The default templated lerp function.
template<typename T>
T lerpT( const T &a, const T &b, float t )
{
  return a + (b - a) * t;
}

/**
 A Phrase is a part of a Sequence.
 It describes the motion between two positions.
 This is the essence of a Tween, with all values held internally.
 */
template<typename T>
class Phrase
{
public:
  using LerpFn = std::function<T (const T&, const T&, float)>;

  Phrase( const T &end, float duration, const EaseFn &easeFn = &easeNone ):
    end( end, duration ),
    motion( easeFn )
  {}

  Phrase( const Position<T> &start, const Position<T> &end, const EaseFn &easeFn = &easeNone ):
    start( start ),
    end( end ),
    motion( easeFn )
  {}

  virtual ~Phrase() = default;

  //! Set start time to \a time. End time is adjusted to preserve duration.
  void shiftStartTimeTo( float time ) {
    float delta = time - start.time;
    start.time = time;
    end.time += delta;
  }

  //! Change start value to \a value.
  void setStartValue( const T &value )
  {
    start.value = value;
  }

  //! Returns the value at the beginning of this phrase.
  inline const T& getStartValue() const { return start.value; }
  //! Returns the value at the end of this phrase.
  inline const T& getEndValue() const { return end.value; }

  //! Returns the time at the beginning of this phrase.
  inline float getStartTime() const { return start.time; }
  //! Returns the time at the end of this phrase.
  inline float getEndTime() const { return end.time; }

  //! Returns normalized time if t is in range [start.time, end.time].
  inline float normalizeTime( float t ) const { return (t - start.time) / (end.time - start.time); }
  //! Returns the duration of this phrase.
  inline float getDuration() const { return end.time - start.time; }

  //! Returns the interpolated value at the given time.
  virtual T getValue( float atTime ) const
  {
    return lerpFn( start.value, end.value, motion( normalizeTime( atTime ) ) );
  }
private:
  Position<T> start;
  Position<T> end;
  EaseFn      motion;
  LerpFn      lerpFn = &lerpT<T>;
};

template<typename T>
using PhraseRef = std::shared_ptr<Phrase<T>>;

/**
 Phrase with separately-interpolated components.
 Allows for the use of separate ease functions per component.
 All components must be of the same type.
 */
template<typename T>
class Phrase2 : public Phrase<T>
{
public:
  Phrase2( const T &end, float duration, const EaseFn &ease_x, const EaseFn &ease_y ):
    Phrase<T>( end, duration ),
    motion_x( ease_x ),
    motion_y( ease_y )
  {}

  Phrase2( const Position<T> &start, const Position<T> &end, const EaseFn &ease_x, const EaseFn &ease_y ):
    Phrase<T>( start, end ),
    motion_x( ease_x ),
    motion_y( ease_y )
  {}

  //! Returns the interpolated value at the given time.
  T getValue( float atTime ) const override
  {
    float t = Phrase<T>::normalizeTime( atTime );
    return T( componentLerpFn( Phrase<T>::getStartValue().x, Phrase<T>::getEndValue().x, motion_x( t ) ),
             componentLerpFn( Phrase<T>::getStartValue().y, Phrase<T>::getEndValue().y, motion_y( t ) ) );
  }

  //! Set ease functions for first and second components.
  void setEase( const EaseFn &component_0, const EaseFn &component_1 ) {
    motion_x = component_0;
    motion_y = component_1;
  }

private:
  using ComponentT = decltype( T().x ); // get the type of the x component;
  using ComponentLerpFn = std::function<ComponentT (const ComponentT&, const ComponentT&, float)>;

  ComponentLerpFn componentLerpFn = &lerpT<ComponentT>;
  EaseFn          motion_x;
  EaseFn          motion_y;
};

/**
 A Sequence of motions.
 Our essential compositional tool, describing all the transformations to one element.
 A kind of platonic idea of an animation sequence; this describes a motion without giving it an output.
*/
template<typename T>
class Sequence
{
public:
  // Sequences always need to have some valid value.
  Sequence() = delete;

  //! Construct a Sequence with an initial \a value.
  explicit Sequence( const T &value ):
    _initial_value( value )
  {}

  T getValue( float atTime );

  //! Set current value. An instantaneous hold.
  Sequence<T>& set( const T &value )
  {
    if( _segments.empty() ) {
      _initial_value = value;
    }
    else {
      hold( value, 0.0f );
    }
    return *this;
  }

  //! Returns a copy of this sequence. Useful if you want to make a base animation and modify that.
  std::shared_ptr<Sequence<T>> copy() const { return std::make_shared<Sequence<T>>( *this ); }

  //! Hold on current end value for \a duration seconds.
  Sequence<T>& wait( float duration ) { return hold( duration ); }

  //! Hold on current end value for \a duration seconds.
  Sequence<T>& hold( float duration )
  {
    return hold( endValue(), duration );
  }

  //! Hold on \a value for \a duration seconds.
  Sequence<T>& hold( const T &value, float duration )
  {
    Position<T> start{ value, _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<Phrase<T>>( start, end, Hold() );

    _segments.push_back( phrase );
    _duration = phrase->getEndTime();

    return *this;
  }

  //! Animate to \a value over \a duration seconds using \a ease easing.
  Sequence<T>& rampTo( const T &value, float duration, const EaseFn &ease = LinearRamp() )
  {
    Position<T> start{ endValue(), _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<Phrase<T>>( start, end, ease );

    _segments.push_back( phrase );

    _duration = phrase->getEndTime();

    return *this;
  }

  template<typename PhraseT, typename... Args>
  Sequence<T>& then( const T& value, float duration, Args... args )
  {
    Position<T> start{ endValue(), _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<PhraseT>( start, end, args... );
    // Would expect the following to make my dream user syntax work.
//    auto phrase = std::make_shared<PhraseT<T>>( start, end, args... );

    _segments.push_back( phrase );
    _duration = phrase->getEndTime();

    return *this;
  }

  Sequence<T>& then( const PhraseRef<T>& phrase )
  {
    phrase->setStartValue( endValue() );
    phrase->shiftStartTimeTo( _duration );
    _duration = phrase->getEndTime();

    _segments.push_back( phrase );

    return *this;
  }

  //! Sets the ease function of the last Phrase in the Sequence.
  Sequence<T>& ease( const EaseFn &easeFn ) {
    if( ! _segments.empty() ) {
      _segments.back().motion = easeFn;
    }
    return *this;
  }

  //! Returns the number of seconds required to move through all Phrases.
  float getDuration() const { return _duration; }

  //! Returns the value at the end of the Sequence.
  T endValue() const { return _segments.empty() ? _initial_value : _segments.back()->getEndValue(); }

  //! Returns the value at the beginning of the Sequence.
  T initialValue() const { return _initial_value; }

private:
  std::vector<PhraseRef<T>>  _segments;
  T                       _initial_value;
  float                   _duration = 0.0f;

  friend class Timeline;
};

//! Returns the value of this sequence for a given point in time.
// Would be nice to have a constant-time check (without a while loop).
template<typename T>
T Sequence<T>::getValue( float atTime )
{
  if( atTime < 0.0f )
  {
    return _initial_value;
  }
  else if ( atTime >= _duration )
  {
    return endValue();
  }

  auto iter = _segments.begin();
  while( iter < _segments.end() ) {
    if( (*iter)->getEndTime() > atTime )
    {
      return (*iter)->getValue( atTime );
    }
    ++iter;
  }
  // past the end, get the final value
  // this should be unreachable, given that we return early if time >= duration
  return endValue();
}

template<typename T>
using SequenceRef = std::shared_ptr<Sequence<T>>;

} // namespace choreograph
<commit_msg>Typedef for Phrase2v.<commit_after>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

 #pragma once

namespace choreograph
{

// A motion describes a one-dimensional change through time.
// These can be ease equations, always return the same value, or sample some data. Whatever you want.
// For classic motion, EaseFn( 0 ) = 0, EaseFn( 1 ) = 1.
// set( 0.0f ).move( )
// then again, might just make a curve struct that is callable and have a way to set its initial and final derivatives.
typedef std::function<float (float)> EaseFn;

struct Hold
{
  float operator() ( float t ) const { return 0.0f; }
};

struct LinearRamp
{
  float operator() ( float t ) const { return t; }
};

inline float easeNone( float t ) { return t; }

//! A Position describes a point in time.
template<typename T>
struct Position
{
  Position() = default;

  Position( const T &value, float time = 0.0f ):
    time( time ),
    value( value )
  {}

  float time = 0.0f;
  T     value;
};

//! The default templated lerp function.
template<typename T>
T lerpT( const T &a, const T &b, float t )
{
  return a + (b - a) * t;
}

/**
 A Phrase is a part of a Sequence.
 It describes the motion between two positions.
 This is the essence of a Tween, with all values held internally.
 */
template<typename T>
class Phrase
{
public:
  using LerpFn = std::function<T (const T&, const T&, float)>;

  Phrase( const T &end, float duration, const EaseFn &easeFn = &easeNone ):
    end( end, duration ),
    motion( easeFn )
  {}

  Phrase( const Position<T> &start, const Position<T> &end, const EaseFn &easeFn = &easeNone ):
    start( start ),
    end( end ),
    motion( easeFn )
  {}

  virtual ~Phrase() = default;

  //! Set start time to \a time. End time is adjusted to preserve duration.
  void shiftStartTimeTo( float time ) {
    float delta = time - start.time;
    start.time = time;
    end.time += delta;
  }

  //! Change start value to \a value.
  void setStartValue( const T &value )
  {
    start.value = value;
  }

  //! Returns the value at the beginning of this phrase.
  inline const T& getStartValue() const { return start.value; }
  //! Returns the value at the end of this phrase.
  inline const T& getEndValue() const { return end.value; }

  //! Returns the time at the beginning of this phrase.
  inline float getStartTime() const { return start.time; }
  //! Returns the time at the end of this phrase.
  inline float getEndTime() const { return end.time; }

  //! Returns normalized time if t is in range [start.time, end.time].
  inline float normalizeTime( float t ) const { return (t - start.time) / (end.time - start.time); }
  //! Returns the duration of this phrase.
  inline float getDuration() const { return end.time - start.time; }

  //! Returns the interpolated value at the given time.
  virtual T getValue( float atTime ) const
  {
    return lerpFn( start.value, end.value, motion( normalizeTime( atTime ) ) );
  }
private:
  Position<T> start;
  Position<T> end;
  EaseFn      motion;
  LerpFn      lerpFn = &lerpT<T>;
};

template<typename T>
using PhraseRef = std::shared_ptr<Phrase<T>>;

/**
 Phrase with separately-interpolated components.
 Allows for the use of separate ease functions per component.
 All components must be of the same type.
 */
template<typename T>
class Phrase2 : public Phrase<T>
{
public:
  Phrase2( const T &end, float duration, const EaseFn &ease_x, const EaseFn &ease_y ):
    Phrase<T>( end, duration ),
    motion_x( ease_x ),
    motion_y( ease_y )
  {}

  Phrase2( const Position<T> &start, const Position<T> &end, const EaseFn &ease_x, const EaseFn &ease_y ):
    Phrase<T>( start, end ),
    motion_x( ease_x ),
    motion_y( ease_y )
  {}

  //! Returns the interpolated value at the given time.
  T getValue( float atTime ) const override
  {
    float t = Phrase<T>::normalizeTime( atTime );
    return T( componentLerpFn( Phrase<T>::getStartValue().x, Phrase<T>::getEndValue().x, motion_x( t ) ),
             componentLerpFn( Phrase<T>::getStartValue().y, Phrase<T>::getEndValue().y, motion_y( t ) ) );
  }

  //! Set ease functions for first and second components.
  void setEase( const EaseFn &component_0, const EaseFn &component_1 ) {
    motion_x = component_0;
    motion_y = component_1;
  }

private:
  using ComponentT = decltype( T().x ); // get the type of the x component;
  using ComponentLerpFn = std::function<ComponentT (const ComponentT&, const ComponentT&, float)>;

  ComponentLerpFn componentLerpFn = &lerpT<ComponentT>;
  EaseFn          motion_x;
  EaseFn          motion_y;
};

using Phrase2v = Phrase2<ci::vec2>;

/**
 A Sequence of motions.
 Our essential compositional tool, describing all the transformations to one element.
 A kind of platonic idea of an animation sequence; this describes a motion without giving it an output.
*/
template<typename T>
class Sequence
{
public:
  // Sequences always need to have some valid value.
  Sequence() = delete;

  //! Construct a Sequence with an initial \a value.
  explicit Sequence( const T &value ):
    _initial_value( value )
  {}

  T getValue( float atTime );

  //! Set current value. An instantaneous hold.
  Sequence<T>& set( const T &value )
  {
    if( _segments.empty() ) {
      _initial_value = value;
    }
    else {
      hold( value, 0.0f );
    }
    return *this;
  }

  //! Returns a copy of this sequence. Useful if you want to make a base animation and modify that.
  std::shared_ptr<Sequence<T>> copy() const { return std::make_shared<Sequence<T>>( *this ); }

  //! Hold on current end value for \a duration seconds.
  Sequence<T>& wait( float duration ) { return hold( duration ); }

  //! Hold on current end value for \a duration seconds.
  Sequence<T>& hold( float duration )
  {
    return hold( endValue(), duration );
  }

  //! Hold on \a value for \a duration seconds.
  Sequence<T>& hold( const T &value, float duration )
  {
    Position<T> start{ value, _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<Phrase<T>>( start, end, Hold() );

    _segments.push_back( phrase );
    _duration = phrase->getEndTime();

    return *this;
  }

  //! Animate to \a value over \a duration seconds using \a ease easing.
  Sequence<T>& rampTo( const T &value, float duration, const EaseFn &ease = LinearRamp() )
  {
    Position<T> start{ endValue(), _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<Phrase<T>>( start, end, ease );

    _segments.push_back( phrase );

    _duration = phrase->getEndTime();

    return *this;
  }

  template<typename PhraseT, typename... Args>
  Sequence<T>& then( const T& value, float duration, Args... args )
  {
    Position<T> start{ endValue(), _duration };
    Position<T> end{ value, _duration + duration };
    auto phrase = std::make_shared<PhraseT>( start, end, args... );
    // Would expect the following to make my dream user syntax work.
//    auto phrase = std::make_shared<PhraseT<T>>( start, end, args... );

    _segments.push_back( phrase );
    _duration = phrase->getEndTime();

    return *this;
  }

  Sequence<T>& then( const PhraseRef<T>& phrase )
  {
    phrase->setStartValue( endValue() );
    phrase->shiftStartTimeTo( _duration );
    _duration = phrase->getEndTime();

    _segments.push_back( phrase );

    return *this;
  }

  //! Sets the ease function of the last Phrase in the Sequence.
  Sequence<T>& ease( const EaseFn &easeFn ) {
    if( ! _segments.empty() ) {
      _segments.back().motion = easeFn;
    }
    return *this;
  }

  //! Returns the number of seconds required to move through all Phrases.
  float getDuration() const { return _duration; }

  //! Returns the value at the end of the Sequence.
  T endValue() const { return _segments.empty() ? _initial_value : _segments.back()->getEndValue(); }

  //! Returns the value at the beginning of the Sequence.
  T initialValue() const { return _initial_value; }

private:
  std::vector<PhraseRef<T>>  _segments;
  T                       _initial_value;
  float                   _duration = 0.0f;

  friend class Timeline;
};

//! Returns the value of this sequence for a given point in time.
// Would be nice to have a constant-time check (without a while loop).
template<typename T>
T Sequence<T>::getValue( float atTime )
{
  if( atTime < 0.0f )
  {
    return _initial_value;
  }
  else if ( atTime >= _duration )
  {
    return endValue();
  }

  auto iter = _segments.begin();
  while( iter < _segments.end() ) {
    if( (*iter)->getEndTime() > atTime )
    {
      return (*iter)->getValue( atTime );
    }
    ++iter;
  }
  // past the end, get the final value
  // this should be unreachable, given that we return early if time >= duration
  return endValue();
}

template<typename T>
using SequenceRef = std::shared_ptr<Sequence<T>>;

} // namespace choreograph
<|endoftext|>