text:
#include "stdafx.h"
#include "game_cl_base.h"
#include "Level.h"
#include "Weapon.h"
#include "alife_space.h"
#include "hit.h"
#include "Actor.h"
#include "ExplosiveItem.h"
#include "xrServer.h"
#include "game_cl_base_weapon_usage_statistic.h"
#include "../Include/xrRender/Kinematics.h"
#include "game_cl_mp.h"
#include <boost/noncopyable.hpp>

class statistic_sync_quard : private boost::noncopyable
{
	xrCriticalSection & m_mutex;
public:
	statistic_sync_quard(xrCriticalSection & mutex) :
		m_mutex(mutex)
	{
		m_mutex.Enter();
	}
	~statistic_sync_quard()
	{
		m_mutex.Leave();
	}
};

BulletData::BulletData(shared_str FName, shared_str WName, SBullet* pBullet)
{
	FirerName = FName;
	WeaponName = WName;
	Bullet = *pBullet;
	HitRefCount = 0;
	HitResponds = 0;
	Removed = false;
};

u32 const HitData::net_packet_size = (3*2*sizeof(float) + 1 + 2 + 1 + 1);
void			HitData::net_save	(NET_Packet* P, victims_table const & vt, bone_table const & bt)
{
	P->w_vec3(Pos0);
	P->w_vec3(Pos1);
	P->w_u8(vt.get_id_by_name(TargetName)); //P->w_stringZ(TargetName);
	//P->w_stringZ(BoneName);
	P->w_s16(BoneID);
	P->w_u8(Deadly ? 1 : 0);
	P->w_u8(count);
};
void			HitData::net_load	(NET_Packet* P, victims_table const & vt, bone_table const & bt)
{
	P->r_vec3(Pos0);
	P->r_vec3(Pos1);
	TargetName = vt.get_name_by_id(P->r_u8()); //P->r_stringZ(TargetName);
	P->r_s16(BoneID);
	BoneName = bt.get_name_by_id(BoneID); //P->r_stringZ(BoneName);
	Deadly = !!P->r_u8();
	count = P->r_u8();
	Completed = true;
};

Weapon_Statistic::Weapon_Statistic(LPCSTR Name)
{
	WName = Name;
	InvName = NULL;
	NumBought = 0;

	m_dwRoundsFired = m_dwRoundsFired_d = 0;
	m_dwBulletsFired = m_dwBulletsFired_d = 0;
	m_dwHitsScored = m_dwHitsScored_d = 0;
	m_dwKillsScored = m_dwKillsScored_d = 0;
	m_explosion_kills = 0;
	m_bleed_kills = 0;

	ZeroMemory(m_Basket, sizeof(m_Basket));
};

Weapon_Statistic::~Weapon_Statistic()
{};

u32 const Weapon_Statistic::net_packet_size = 5*sizeof(u32);
void Weapon_Statistic::net_save(NET_Packet* P, victims_table const & vt, bone_table const & bt)
{
	class CompleteFilter
	{
		u32&					complete_hits_count;
		NET_Packet*				packet_to_write;
		victims_table const &	vtable;
		bone_table const &		btable;

		CompleteFilter&	operator=(CompleteFilter & copy) { return *this; };	//C4512
	public:

		CompleteFilter(u32& hits_count_result, NET_Packet* P, victims_table const & vt, bone_table const & bt) :
			complete_hits_count(hits_count_result),
			packet_to_write(P),
			vtable(vt),
			btable(bt)
		{
		};
		bool operator()(HitData & hit)
		{
			if (hit.Completed)
			{
				if (NET_PacketSizeLimit - packet_to_write->w_tell() < HitData::net_packet_size)
					return false;
				hit.net_save(packet_to_write, vtable, btable);
				++complete_hits_count;
				return true;
			}
			return false;
		}
	};
	m_dwRoundsFired_d = m_dwRoundsFired - m_dwRoundsFired_d;
	P->w_u32(m_dwRoundsFired_d);	m_dwRoundsFired_d = m_dwRoundsFired;
	P->w_u32(m_dwBulletsFired_d);	m_dwBulletsFired_d = 0;
	P->w_u32(m_dwHitsScored_d);		m_dwHitsScored_d = 0;
	P->w_u32(m_dwKillsScored_d);	m_dwKillsScored_d = 0;

	u32 hit_count_position = P->w_tell();
	u32 complete_hits = 0;
	P->w_u32(0); // <- complete_hits_count

	//P->w_u16(m_explosion_kills);
	//P->w_u16(m_bleed_kills);

	CompleteFilter	tmp_filter(complete_hits, P, vt, bt);
	m_Hits.erase(
		std::remove_if(m_Hits.begin(), m_Hits.end(),  tmp_filter),
		m_Hits.end()
	);
	P->w_seek(hit_count_position, &complete_hits, sizeof(complete_hits));
};

void Weapon_Statistic::net_load(NET_Packet* P, victims_table const & vt, bone_table const & bt)
{
	m_dwRoundsFired += P->r_u32();
	m_dwBulletsFired += P->r_u32();
	m_dwHitsScored += P->r_u32();
	m_dwKillsScored += P->r_u32();
	u32 HitsSize = P->r_u32();
	//P->r_u16(m_explosion_kills); //server sets this parameter ..
	//P->r_u16(m_bleed_kills);
	for (u32 i = 0; i<HitsSize; i++)
	{
		HitData NewHit;
		NewHit.net_load(P, vt, bt);
		m_Hits.push_back(NewHit);
	}
};

u32 const victims_table::header_count_size = sizeof(u8);
u8 victims_table::get_id_by_name	(shared_str const & player_name) const
{
	u8 index = 0;
	for (victims_table_t::const_iterator i = m_data.begin(),
		ie = m_data.end(); i != ie; ++i)
	{
		if (*i == player_name)
			return index;
		++index;
	}
	return 0;
}

shared_str	victims_table::get_name_by_id	(u8 id) const
{
	size_t name_index = static_cast<size_t>(id);
	if (name_index > m_data.size())
		return shared_str();
	return m_data[name_index];
}

bool victims_table::add_name(shared_str const & player_name)
{
	if (m_data.size() > 254)
	{
		Msg("! WARNING: victims table in statistics exceeds limit count");
		return false;
	}
	victims_table_t::const_iterator tmp_iter = std::find(
		m_data.begin(), m_data.end(), player_name);
	if (tmp_iter != m_data.end())
		return false;
	m_data.push_back(player_name);
	return true;
}

void victims_table::net_save(NET_Packet* P)
{
	P->w_u8(static_cast<u8>(m_data.size()));
	for (victims_table_t::const_iterator i = m_data.begin(),
		ie = m_data.end(); i != ie; ++i)
	{
		P->w_stringZ(*i);
	}
}

void victims_table::net_load(NET_Packet* P)
{
	m_data.clear();
	size_t table_size = static_cast<size_t>(P->r_u8());
	for (size_t i = 0; i < table_size; ++i)
	{
		shared_str tmp_string;
		P->r_stringZ(tmp_string);
		m_data.push_back(tmp_string);
	}
}

u32 const bone_table::header_count_size = sizeof(u16);

class bone_id_searcher
{
	s16 const & id;
	bone_id_searcher& operator=(bone_id_searcher& copy) { return *this; };
public:
	bone_id_searcher(s16 const & id_to_search) : id(id_to_search) {}
	bool operator()(bone_table::bone_table_t::value_type const & item)
	{
		if (item.second == id)
			return true;
		return false;
	}
};

shared_str	bone_table::get_name_by_id	(s16 id) const
{
	bone_table_t::const_iterator tmp_iter = std::find_if(
		m_data.begin(), m_data.end(), bone_id_searcher(id));
	if (tmp_iter == m_data.end())
		return shared_str();
	return tmp_iter->first;
}

bool bone_table::add_bone(shared_str const & bone_name, s16 bone_id)
{
	class bone_name_searcher
	{
		shared_str const & name;
		bone_name_searcher& operator=(bone_name_searcher& copy) { return *this; };
	public:
		bone_name_searcher(shared_str const & name_to_search) : name(name_to_search) {}
		bool operator()(bone_table::bone_table_t::value_type const & item)
		{
			if (item.first == name)
				return true;
			return false;
		}
	};
	bone_table_t::const_iterator tmp_iter = std::find_if(
		m_data.begin(), m_data.end(), bone_name_searcher(bone_name));
	if (tmp_iter != m_data.end())
		return false;
	tmp_iter = std::find_if(
		m_data.begin(), m_data.end(), bone_id_searcher(bone_id));
	if (tmp_iter != m_data.end())
		return false;
	m_data.push_back(std::make_pair(bone_name, bone_id));
	return true;
}

void bone_table::net_save(NET_Packet* P)
{
	P->w_u16(static_cast<u16>(m_data.size()));
	for (bone_table_t::const_iterator i = m_data.begin(),
		ie = m_data.end(); i != ie; ++i)
	{
		P->w_stringZ(i->first);
		P->w_s16(i->second);
	}
}

void bone_table::net_load(NET_Packet* P)
{
	m_data.clear();
	u16 bones_count = P->r_u16();
	for (u16 i = 0; i < bones_count; ++i)
	{
		shared_str tmp_string;
		s16 tmp_bone_id;
		P->r_stringZ(tmp_string);
		P->r_s16(tmp_bone_id);
		m_data.push_back(std::make_pair(tmp_string, tmp_bone_id));
	}
}

Player_Statistic::Player_Statistic(LPCSTR Name)
{
	PName					= Name;
	PID						= 0;
	m_dwTotalShots			= 0;
	m_dwTotalShots_d		= 0;
	m_dwCurrentTeam			= 0;

	ZeroMemory				(m_dwTotalAliveTime, sizeof(m_dwTotalAliveTime));
	ZeroMemory				(m_dwTotalMoneyRound, sizeof(m_dwTotalMoneyRound));
	ZeroMemory				(m_dwNumRespawned, sizeof(m_dwNumRespawned));
	ZeroMemory				(m_dwArtefacts, sizeof(m_dwArtefacts));
	ZeroMemory				(m_dwSpecialKills, sizeof(m_dwSpecialKills));
};

Player_Statistic::~Player_Statistic()
{
	aWeaponStats.clear_and_free();
};

u32 Player_Statistic::create_victims_table(victims_table & victims_table)
{
	u32 result_size = victims_table::header_count_size;
	victims_table.m_data.clear();
	for (u32 wi=0, weapons_size = aWeaponStats.size();
		wi < weapons_size; ++wi)
	{
		Weapon_Statistic& WS = aWeaponStats[wi];
		for (u32 hi = 0, hits_count = WS.m_Hits.size(); hi < hits_count; ++hi)
		{
			HitData& Hit = WS.m_Hits[hi];
			if (victims_table.add_name(Hit.TargetName))
				result_size += Hit.TargetName.size() + 1;
		}
	}
	return result_size;
}

u32 Player_Statistic::create_bone_table(bone_table & bone_table)
{
	u32 result_size = bone_table::header_count_size;
	bone_table.m_data.clear();
	for (u32 wi=0, weapons_size = aWeaponStats.size();
		wi < weapons_size; ++wi)
	{
		Weapon_Statistic& WS = aWeaponStats[wi];
		for (u32 hi = 0, hits_count = WS.m_Hits.size(); hi < hits_count; ++hi)
		{
			HitData& Hit = WS.m_Hits[hi];
			if (bone_table.add_bone(Hit.BoneName, Hit.BoneID))
				result_size += Hit.BoneName.size() + 1 + sizeof(s16);
		}
	}
	return result_size;
}

void Player_Statistic::net_save(NET_Packet* P)
{
	P->w_u32(m_dwTotalShots_d); m_dwTotalShots_d = 0;
	P->w_u32(aWeaponStats.size());

	victims_table::victims_table_t	vt_storage(
		_alloca(sizeof(victims_table::victims_table_t::value_type)*255), 255);
	bone_table::bone_table_t		bt_storage(
		_alloca(sizeof(bone_table::bone_table_t::value_type)*65), 65);

	victims_table vict_table(vt_storage);
	bone_table bone_table(bt_storage);

	u32 tables_size = create_victims_table(vict_table);
	tables_size += create_bone_table(bone_table);
	if (NET_PacketSizeLimit - P->w_tell() < tables_size + Weapon_Statistic::net_packet_size)
		return;

	vict_table.net_save(P);
	bone_table.net_save(P);

	for (u32 i=0; i<aWeaponStats.size(); i++)
	{
		Weapon_Statistic& WS = aWeaponStats[i];
		P->w_stringZ(WS.WName);
		WS.net_save(P, vict_table, bone_table);
	}
};

void Player_Statistic::net_load(NET_Packet* P)
{
	m_dwTotalShots += P->r_u32();
	u32 NumWeapons = P->r_u32();

	victims_table::victims_table_t	vt_storage(
			_alloca(sizeof(victims_table::victims_table_t::value_type)*255), 255);
	bone_table::bone_table_t		bt_storage(
		_alloca(sizeof(bone_table::bone_table_t::value_type)*65), 65);

	victims_table vict_table(vt_storage);
	bone_table bone_table(bt_storage);

	vict_table.net_load(P);
	bone_table.net_load(P);

	for (u32 i=0; i<NumWeapons; i++)
	{
		shared_str WName;
		P->r_stringZ(WName);
		WEAPON_STATS_it tmp_wst_it = FindPlayersWeapon(WName.c_str());
		R_ASSERT(tmp_wst_it != aWeaponStats.end());
		tmp_wst_it->net_load(P, vict_table, bone_table);
	}
};

WeaponUsageStatistic::WeaponUsageStatistic()
#ifdef PROFILE_CRITICAL_SECTIONS
	: m_mutex(MUTEX_PROFILE_ID(WeaponUsageStatistic)){}
#endif // PROFILE_CRITICAL_SECTIONS
{
	Clear						();
	m_dwUpdateTimeDelta			= 30000; //30 seconds
	m_bCollectStatistic			= false;
};

void WeaponUsageStatistic::Clear()
{
	statistic_sync_quard syncg(m_mutex);
	ActiveBullets.clear			();
	aPlayersStatistic.clear		();
	m_Requests.clear			();
	m_dwLastRequestSenderID		= 0;

	ZeroMemory					(m_dwTotalPlayersAliveTime, sizeof(m_dwTotalPlayersAliveTime));
	ZeroMemory					(m_dwTotalPlayersMoneyRound, sizeof(m_dwTotalPlayersMoneyRound));
	ZeroMemory					(m_dwTotalNumRespawns, sizeof(m_dwTotalNumRespawns));

	m_dwLastUpdateTime			= Level().timeServer();
	mFileName[0]				= 0;
};

WeaponUsageStatistic::~WeaponUsageStatistic()
{
	m_dwLastRequestSenderID			= 0;
};

bool WeaponUsageStatistic::GetPlayer(LPCSTR PlayerName, PLAYERS_STATS_it& pPlayerI)
{
	statistic_sync_quard syncg(m_mutex);
	pPlayerI	= std::find(aPlayersStatistic.begin(), aPlayersStatistic.end(), PlayerName);
	if (pPlayerI == aPlayersStatistic.end() || !((*pPlayerI) == PlayerName))
		return false;
	return true;
}

PLAYERS_STATS_it WeaponUsageStatistic::FindPlayer(LPCSTR PlayerName)
{
	statistic_sync_quard syncg(m_mutex);
	PLAYERS_STATS_it pPlayerI;
	if (!GetPlayer(PlayerName, pPlayerI))
	{
#ifdef DEBUG
		Msg("--- Adding new player [%s] to statistics", PlayerName);
#endif // #ifdef DEBUG
		aPlayersStatistic.push_back	(Player_Statistic(PlayerName));
		pPlayerI					= aPlayersStatistic.end()-1;
	};
	return pPlayerI;
};

void WeaponUsageStatistic::ChangePlayerName( LPCSTR from, LPCSTR to )
{
	statistic_sync_quard syncg(m_mutex);
	if ( !CollectData() ) return;
	PLAYERS_STATS_it pPlayerI = FindPlayer( from );
	pPlayerI->PName = to;
}

WEAPON_STATS_it	Player_Statistic::FindPlayersWeapon	(LPCSTR WeaponName)
{
	R_ASSERT(WeaponName);
	WEAPON_STATS_it pWeaponI = std::find(aWeaponStats.begin(), aWeaponStats.end(), WeaponName);
	if (pWeaponI == aWeaponStats.end() || !((*pWeaponI) == WeaponName))
	{
		aWeaponStats.push_back(Weapon_Statistic(WeaponName));
		pWeaponI = aWeaponStats.end()-1;
		pWeaponI->InvName = pSettings->r_string_wb(WeaponName, "inv_name");
#ifdef DEBUG
		Msg("--- Just added weapon %s to statistics", WeaponName);
#endif // #ifdef DEBUG
	}
	return pWeaponI;
};

bool WeaponUsageStatistic::FindBullet(u32 BulletID, ABULLETS_it& Bullet_It)
{
	Bullet_It = std::find(ActiveBullets.begin(), ActiveBullets.end(),BulletID);
	if (Bullet_It == ActiveBullets.end() || (*Bullet_It) != BulletID) return false;
	return true;
}

bool Weapon_Statistic::FindHit(u32 BulletID, HITS_VEC_it& Hit_it)
{
	Hit_it = std::find(m_Hits.begin(), m_Hits.end(),BulletID);
	if (Hit_it == m_Hits.end() || (*Hit_it) != BulletID) return false;
	return true;
};

void WeaponUsageStatistic::RemoveBullet(ABULLETS_it& Bullet_it)
{
	statistic_sync_quard syncg(m_mutex);
	if (!Bullet_it->Removed || Bullet_it->HitRefCount!=Bullet_it->HitResponds) return;
	//-------------------------------------------------------------
	PLAYERS_STATS_it PlayerIt = FindPlayer(*(Bullet_it->FirerName));
	WEAPON_STATS_it WeaponIt = PlayerIt->FindPlayersWeapon(*(Bullet_it->WeaponName));
	HITS_VEC_it HitIt;
	if (WeaponIt->FindHit(Bullet_it->Bullet.m_dwID, HitIt))
	{
		HitIt->Completed = true;
	};
	//-------------------------------------------------------------
	*Bullet_it = ActiveBullets.back();
	ActiveBullets.pop_back();
}

void WeaponUsageStatistic::OnWeaponBought(game_PlayerState* ps, LPCSTR WeaponName)
{
	statistic_sync_quard syncg(m_mutex);
	if (!CollectData()) return;
	if (!ps) return;
	PLAYERS_STATS_it PlayerIt = FindPlayer(ps->getName());
	WEAPON_STATS_it WeaponIt = PlayerIt->FindPlayersWeapon(WeaponName);
	WeaponIt->NumBought++;
	//-----------------------------------------------
	int BasketPos = 0;
	if (ps->money_for_round > 500)
	{
		BasketPos = (ps->money_for_round-1)/1000 + 1;
	};
	u8	team_index = ConvertToTeamIndex(ps->team);
	u8	bascet_pos = static_cast<u8>(BasketPos);
	if ((team_index >= STAT_TEAM_COUNT) ||
		(bascet_pos >= MAX_BASKET))
	{
		return;
	}
	WeaponIt->m_Basket[team_index][bascet_pos]++;
};

void WeaponUsageStatistic::OnBullet_Fire(SBullet* pBullet, const CCartridge& cartridge)
{
	statistic_sync_quard syncg(m_mutex);
	if (!CollectData()) return;

	if (!pBullet || !pBullet->flags.allow_sendhit) return;
	CObject					*object_weapon = Level().Objects.net_Find(pBullet->weapon_id);
	if (!object_weapon) return;
	CObject					*object_parent = Level().Objects.net_Find(pBullet->parent_id);
	if (!object_parent) return;
	CActor* pActor = smart_cast<CActor*>(object_parent);
	if (!pActor) return;
	//-----------------------------------------------------------------------------------
	PLAYERS_STATS_it PlayerIt = FindPlayer(*object_parent->cName());
	pBullet->m_dwID = PlayerIt->m_dwTotalShots++;
	PlayerIt->m_dwTotalShots_d++;
	WEAPON_STATS_it WeaponIt = PlayerIt->FindPlayersWeapon(*object_weapon->cNameSect());
	WeaponIt->m_dwRoundsFired = (++WeaponIt->m_dwBulletsFired)/cartridge.param_s.buckShot;
	WeaponIt->m_dwBulletsFired_d++;
	//-----------------------------------------------------------------------------------
	ActiveBullets.push_back(BulletData(object_parent->cName(), object_weapon->cNameSect(), pBullet));

//	Msg("! OnBullet Fire ID[%d]", pBullet->m_dwID);
}

void WeaponUsageStatistic::OnBullet_Hit(SBullet* pBullet, u16 TargetID, s16 element, Fvector HitLocation)
{
	statistic_sync_quard syncg(m_mutex);
	if (!pBullet || !pBullet->flags.allow_sendhit) return;
//	Msg("! OnBullet Hit ID[%d]", pBullet->m_dwID);
	ABULLETS_it BulletIt;
	if (!FindBullet(pBullet->m_dwID, BulletIt)) return;
	//-----------------------------------------------------
	PLAYERS_STATS_it PlayerIt = FindPlayer(*(BulletIt->FirerName));
	WEAPON_STATS_it WeaponIt = PlayerIt->FindPlayersWeapon(*(BulletIt->WeaponName));
	if (!BulletIt->HitRefCount++)
	{
		WeaponIt->m_dwHitsScored++;
		WeaponIt->m_dwHitsScored_d++;
		//---------------------------
		CObject					*pTarget = Level().Objects.net_Find(TargetID);
		if (!pTarget) return;
		CActor* pActor = smart_cast<CActor*>(pTarget);
		if (!pActor) return;
		//---------------------------
		BulletData& BD = *BulletIt;
		HitData NewHit;
		//---------------------------
		NewHit.Completed = false;
		NewHit.Deadly = false;
		NewHit.BoneID = element;
		NewHit.TargetID = TargetID;
		NewHit.BulletID = BD.Bullet.m_dwID;
		NewHit.Pos0 = BD.Bullet.bullet_pos;
		NewHit.Pos1 = HitLocation;
		NewHit.TargetName = pTarget->cName();
		NewHit.BoneName = smart_cast<IKinematics*>(pTarget->Visual())->LL_BoneName_dbg(element);
		NewHit.count = 1;
		//---------------------------
		WeaponIt->add_hit(NewHit);
	};

}

void WeaponUsageStatistic::OnBullet_Remove(SBullet* pBullet)
{
	if (!pBullet || !pBullet->flags.allow_sendhit)	return;
	ABULLETS_it		BulletIt;
	if (!FindBullet(pBullet->m_dwID, BulletIt))		return;
//	Msg("! Bullet Removed ID[%d]", BulletIt->Bullet.m_dwID);
	BulletIt->Removed = true;
	RemoveBullet	(BulletIt);
}

void WeaponUsageStatistic::OnBullet_Check_Request(SHit* pHDS)
{
	if (!pHDS || OnClient()) return;
	s16 BoneID = pHDS->bone();
	u32 BulletID = pHDS->BulletID;
	u32 SenderID = pHDS->SenderID;

	BChA_it pSenderI	= std::find(m_Requests.begin(), m_Requests.end(), SenderID);
	if (pSenderI == m_Requests.end() || (*pSenderI) != SenderID)
	{
		m_Requests.push_back(Bullet_Check_Array(SenderID));
		pSenderI = m_Requests.end()-1;
	};

	(*pSenderI).Requests.push_back(Bullet_Check_Request(BulletID, BoneID));
	m_dwLastRequestSenderID = SenderID;

//	HitChecksReceived++;
};

void WeaponUsageStatistic::OnBullet_Check_Result(bool Result)
{
	if (OnClient()) return;
	if (m_dwLastRequestSenderID)
	{
		BChA_it pSenderI	= std::find(m_Requests.begin(), m_Requests.end(), m_dwLastRequestSenderID);
		if (pSenderI != m_Requests.end() && (*pSenderI) == m_dwLastRequestSenderID)
		{
			(*pSenderI).Requests.back().Result = Result;
			(*pSenderI).Requests.back().Processed = true;
			if (Result) (*pSenderI).NumTrue++;
			else (*pSenderI).NumFalse++;
		}
		else
		{
			Msg ("! Warning can't Find Check!");
			R_ASSERT(0);
		}
		m_dwLastRequestSenderID = 0;
	}
};

void WeaponUsageStatistic::Send_Check_Respond()
{
	if (!OnServer()) return;
	NET_Packet P;
	string1024 STrue, SFalse;
	for (u32 i=0; i<m_Requests.size(); i++)
	{
		Bullet_Check_Array& BChA_Request = m_Requests[i];
		if (BChA_Request.Requests.empty()) continue;
		Bullet_Check_Respond_True* pSTrue = (Bullet_Check_Respond_True*) STrue;
		u32* pSFalse = (u32*) SFalse;
		//-----------------------------------------------------
		u32 NumFalse = 0;
		u32 NumTrue = 0;
		u32 j=0;
		while (j<BChA_Request.Requests.size())
		{
			Bullet_Check_Request& curBChR = BChA_Request.Requests[j];
			if (!curBChR.Processed)
			{
				j++;
				continue;
			}
			else
			{
				if (curBChR.Result)
				{
					pSTrue->BulletID = curBChR.BulletID;
					pSTrue->BoneID = curBChR.BoneID;
					pSTrue++;
//					HitChecksRespondedTrue++;
					NumTrue++;
				}
				else
				{
					*(pSFalse++) = curBChR.BulletID;
//					HitChecksRespondedFalse++;
					NumFalse++;
				};
//				HitChecksResponded++;
				//-----------------------------------------------------
				*(BChA_Request.Requests.begin()+j) = BChA_Request.Requests.back();
				BChA_Request.Requests.pop_back();
			}
		}
		//-----------------------------------------------------
		P.w_begin(M_BULLET_CHECK_RESPOND);
//		Msg("%d-%d || %d-%d", NumFalse, BChA_Request.NumFalse, NumTrue, BChA_Request.NumTrue);
		P.w_u8(BChA_Request.NumFalse);		BChA_Request.NumFalse = 0;
		P.w_u8(BChA_Request.NumTrue);		BChA_Request.NumTrue = 0;

		if ((char*)pSFalse != (char*)SFalse) P.w(SFalse, u32((char*)pSFalse-(char*)SFalse));
		if ((char*)pSTrue != (char*)STrue) P.w(STrue, u32((char*)pSTrue-(char*)STrue));
		//-----------------------------------------------------
		ClientID ClID; ClID.set(BChA_Request.SenderID);
		if(Level().Server) Level().Server->SendTo(ClID, P);
	};
}

void WeaponUsageStatistic::On_Check_Respond(NET_Packet* P)
{
	statistic_sync_quard syncg(m_mutex);
	if (!P) return;
	u8 NumFalse = P->r_u8();
	u8 NumTrue = P->r_u8();

	u8 i;
	ABULLETS_it BulletIt;
	for (i=0; i<NumFalse; i++)
	{
		u32 BulletID = P->r_u32();
		if (!FindBullet(BulletID, BulletIt))
		{
			Msg("! Warning: No bullet found! ID[%d]", BulletID);
			continue;
		};
		BulletIt->HitResponds++;
		RemoveBullet(BulletIt);
	}

	for (i=0; i<NumTrue; i++)
	{
		u32 BulletID = P->r_u32();
		s16 BoneID = P->r_s16();
		if (!FindBullet(BulletID, BulletIt))
		{
			Msg("! Warning: No bullet found! ID[%d]", BulletID);
			continue;
		};
		BulletIt->HitResponds++;

		//---------------------------------------------------------------
		PLAYERS_STATS_it PlayerIt		= FindPlayer(*(BulletIt->FirerName));
		WEAPON_STATS_it WeaponIt		= PlayerIt->FindPlayersWeapon(*(BulletIt->WeaponName));
		(*WeaponIt).m_dwKillsScored++;
		(*WeaponIt).m_dwKillsScored_d++;

		HITS_VEC_it						HitIt;
		if (WeaponIt->FindHit(BulletID, HitIt))
		{
			HitData& HData				= *HitIt;
			HData.Deadly				= true;
			HData.BoneID				= BoneID;
			CObject* pObj				= Level().Objects.net_Find(HData.TargetID);

			if (pObj)
				HData.BoneName			= smart_cast<IKinematics*>(pObj->Visual())->LL_BoneName_dbg(BoneID);
		}
		//---------------------------------------------------------------
		RemoveBullet(BulletIt);
	}
};

void WeaponUsageStatistic::OnPlayerBringArtefact(game_PlayerState* ps)
{
	if (!CollectData())					return;
	if (!ps)							return;
	Player_Statistic& PlayerStat		= *(FindPlayer(ps->getName()));

	PlayerStat.m_dwArtefacts[ConvertToTeamIndex(ps->team)]++;
}

void WeaponUsageStatistic::OnPlayerSpawned(game_PlayerState* ps)
{
	if (!CollectData()) return;
	if (!ps) return;
	Player_Statistic& PlayerStat		= *(FindPlayer(ps->getName()));
	PlayerStat.m_dwNumRespawned[ConvertToTeamIndex(ps->team)]++;
	PlayerStat.m_dwCurMoneyRoundDelta	= 0;
	m_dwTotalNumRespawns[ConvertToTeamIndex(ps->team)]++;
	PlayerStat.m_dwCurrentTeam			= ConvertToTeamIndex(ps->team);
	PlayerStat.last_alive_update_time	= Device.dwTimeGlobal;
}

void WeaponUsageStatistic::OnPlayerAddMoney(game_PlayerState* ps, s32 MoneyAmount)
{
	if (!CollectData())							return;
	if (!ps || MoneyAmount<=0)					return;
	Player_Statistic& PlayerStat				= *(FindPlayer(ps->getName()));
	PlayerStat.m_dwCurMoneyRoundDelta			+= MoneyAmount;
};

void WeaponUsageStatistic::OnPlayerKillPlayer(game_PlayerState* ps, KILL_TYPE KillType, SPECIAL_KILL_TYPE SpecialKillType)
{
	if (!CollectData()) return;
	if (!ps)			return;

	Player_Statistic& PlayerStat				= *(FindPlayer(ps->getName()));

//.	m_dwSpecialKills[0];//headshot, backstab, knifekill
	switch(SpecialKillType)
	{
	case SKT_HEADSHOT:
			PlayerStat.m_dwSpecialKills[0]++;break;
	case SKT_BACKSTAB:
			PlayerStat.m_dwSpecialKills[1]++;break;
	case SKT_KNIFEKILL:
			PlayerStat.m_dwSpecialKills[2]++;break;
	case SKT_EYESHOT:
			PlayerStat.m_dwSpecialKills[3]++;break;
	};
}

void WeaponUsageStatistic::OnExplosionKill(game_PlayerState* ps, const SHit& hit)
{

	if (!CollectData())							return;
	if (!ps)									return;
	if (!OnServer())							return;

	statistic_sync_quard syncg(m_mutex);

	CObject* killer								= hit.who;
	if(!killer)									return;

	u16 killer_id								= hit.whoID;
	game_PlayerState* killerPS					= Game().GetPlayerByGameID(killer_id);
	if (!killerPS)								return;

	Player_Statistic& PlayerStatKiller			= *(FindPlayer(killerPS->getName()));

	CObject* weapon_object						= Level().Objects.net_Find(hit.weaponID);
	WEAPON_STATS_it WeaponIt					= PlayerStatKiller.FindPlayersWeapon(weapon_object->cNameSect().c_str());
	++WeaponIt->m_dwHitsScored;
	++WeaponIt->m_dwKillsScored;
	++WeaponIt->m_explosion_kills;

	HitData NewHit;
	//---------------------------
	NewHit.Completed	= true;
	NewHit.Deadly		= true;
	NewHit.BoneID		= hit.boneID;
	NewHit.TargetID		= ps->GameID;
	NewHit.BulletID		= 0;
	NewHit.Pos0			= killer->Position();
	NewHit.Pos1			= weapon_object->Position();
	NewHit.TargetName	= ps->getName();
	NewHit.BoneName		= 0;
	NewHit.count		= 1;
	//---------------------------
	WeaponIt->add_hit(NewHit);
}

void WeaponUsageStatistic::OnBleedKill(game_PlayerState* killer_ps, game_PlayerState* victim_ps, u16 weapon_id)
{
	statistic_sync_quard syncg(m_mutex);
	if (!killer_ps || !victim_ps)
		return;
	Player_Statistic& PlayerStatKiller = *(FindPlayer(killer_ps->getName()));
	CObject* weapon_object	= Level().Objects.net_Find(weapon_id);
	if (!weapon_object)
		return;

	WEAPON_STATS_it WeaponIt = PlayerStatKiller.FindPlayersWeapon(weapon_object->cNameSect().c_str());

	++WeaponIt->m_dwHitsScored;
	++WeaponIt->m_dwKillsScored;
	++WeaponIt->m_bleed_kills;

	HitData NewHit;
	//---------------------------
	NewHit.Completed	= true;
	NewHit.Deadly		= true;
	NewHit.BoneID		= 0;
	NewHit.TargetID		= victim_ps->GameID;
	NewHit.BulletID		= 0;
	NewHit.Pos0			= Fvector3();
	NewHit.Pos1			= Fvector3();
	NewHit.TargetName	= victim_ps->getName();
	NewHit.BoneName		= 0;
	NewHit.count		= 1;
	//---------------------------
	WeaponIt->add_hit(NewHit);
}

u8 WeaponUsageStatistic::ConvertToTeamIndex(s16 team)
{
	game_cl_mp* cl_game = static_cast<game_cl_mp*>(&Game());
	s16 team_index = cl_game->ModifyTeam(team);
	if (g_pGamePersistent->GameType() == eGameIDTeamDeathmatch)
	{
		if (team_index == -1)
		{
//			Msg("! ERROR: can't process spectators in deathmatch statistics.");
			return 1;
		}
	} else
	{
		if ((team_index == etSpectatorsTeam) || (team_index == -1))
		{
			team_index = 0;
		} else
		{
			++team_index;
		}
	}
	return static_cast<u8>(team_index);
}

void WeaponUsageStatistic::OnPlayerKilled(game_PlayerState* ps)
{
	if (!CollectData())							return;
	if (!ps)									return;
	u8 team = ConvertToTeamIndex(ps->team);
	Player_Statistic& PlayerStat				= *(FindPlayer(ps->getName()));
	PlayerStat.m_dwTotalMoneyRound[team]	+= PlayerStat.m_dwCurMoneyRoundDelta;
	m_dwTotalPlayersMoneyRound[team]		+= PlayerStat.m_dwCurMoneyRoundDelta;
};

void WeaponUsageStatistic::SVUpdateAliveTimes()
{
	if (!OnServer())
		return;

	class alive_time_updator
	{
		WeaponUsageStatistic & owner;
		alive_time_updator& operator=(alive_time_updator& copy) { return *this; };
	public:
		alive_time_updator(WeaponUsageStatistic & stats_owner) :
			owner(stats_owner)
		{
		}

		void operator()(IClient* client)
		{
			xrClientData* tmp_client = static_cast<xrClientData*>(client);
			game_PlayerState* ps = tmp_client->ps;
			if (ps && !ps->testFlag(GAME_PLAYER_FLAG_VERY_VERY_DEAD))
			{
				if (xr_strlen(ps->getName()))
				{
					Player_Statistic& pstat = *(owner.FindPlayer(ps->getName()));
					u8 team = owner.ConvertToTeamIndex(ps->team);
					u32 time_dif = Device.dwTimeGlobal - pstat.last_alive_update_time;
					pstat.m_dwTotalAliveTime[team]	+= time_dif;
					pstat.last_alive_update_time = Device.dwTimeGlobal;
				}
			}
		}
	};
	alive_time_updator tmp_functor(*this);
	Level().Server->ForEachClientDo(tmp_functor);

	m_dwTotalPlayersAliveTime[0] = 0;
	m_dwTotalPlayersAliveTime[1] = 0;
	m_dwTotalPlayersAliveTime[2] = 0;
	for (u32 player_index = 0, max_players = aPlayersStatistic.size();
		player_index < max_players; ++player_index)
	{
		Player_Statistic& pstat = aPlayersStatistic[player_index];
		m_dwTotalPlayersAliveTime[0] += pstat.m_dwTotalAliveTime[0];
		m_dwTotalPlayersAliveTime[1] += pstat.m_dwTotalAliveTime[1];
		m_dwTotalPlayersAliveTime[2] += pstat.m_dwTotalAliveTime[2];
	}
}

//void WeaponUsageStatistic::Update()
//{
//	if (!CollectData())							return;
//	SVUpdateAliveTimes();		//update client alive time and servers total alive times
//	if (!OnServer())							return;
//	if (Level().timeServer() > (m_dwLastUpdateTime + m_dwUpdateTimeDelta))
//	{
//		//---------------------------------------------
//		m_dwLastUpdateTime = Level().timeServer();
//		//---------------------------------------------
//		NET_Packet P;
//		P.w_begin	(M_STATISTIC_UPDATE);
//		P.w_u32		(Level().timeServer());
//		Level().Send(P);
//	}
//};

//void WeaponUsageStatistic::OnUpdateRequest(NET_Packet*)
//{
//	if (aPlayersStatistic.empty() || !Game().local_player) return;
//
//	statistic_sync_quard syncg(m_mutex);
//
//	game_PlayerState* local_player = Game().local_player;
//	if (!xr_strlen(local_player->getName()))
//		return;
//
//	Player_Statistic& PS = *(FindPlayer(local_player->getName()));
//	//-------------------------------------------------
//	NET_Packet P;
//	P.w_begin(M_STATISTIC_UPDATE_RESPOND);
//	//-------------------------------------------------
//	P.w_stringZ(PS.PName);
//	PS.net_save(&P);
//	//-------------------------------------------------
//	Level().Send(P);
//};

//void WeaponUsageStatistic::OnUpdateRespond(NET_Packet* P, shared_str const & sender_digest, u32 sender_pid)
//{
//	if (!P) return;
//
//	statistic_sync_quard syncg(m_mutex);
//
//	shared_str PName;
//	P->r_stringZ(PName);
//	Player_Statistic& PS = *(FindPlayer(*PName));
//	PS.PDigest	= sender_digest;
//	PS.PID		= sender_pid;
//	Msg("--- CL: On Update Respond from [%s]", PName.c_str());
//	PS.net_load(P);
//};

void WeaponUsageStatistic::SetCollectData(bool Collect)
{
	if (Collect && !m_bCollectStatistic)
		Clear();
	m_bCollectStatistic = Collect;
}


text:
/*!
@file
Forward declares `boost::hana::Monad`.

@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#ifndef BOOST_HANA_MONAD_MONAD_HPP
#define BOOST_HANA_MONAD_MONAD_HPP

#include <boost/hana/applicative/applicative.hpp>
#include <boost/hana/core/typeclass.hpp>
#include <boost/hana/detail/constexpr.hpp>

namespace boost { namespace hana {
    namespace monad_detail { namespace operators { struct enable { }; }}

    //! @ingroup group-typeclasses
    //! `Monad`s are `Applicative`s with the ability to flatten values that
    //! were lifted more than once.
    //!
    //! ### Requires
    //! `Functor`, `Applicative`
    //!
    //! ### Laws
    //! Instances of `Monad` must satisfy the following laws:
    //! @code
    //!     bind(lift<M>(x), f) == f(x)
    //!     bind(m, lift<M>) == m
    //!     bind(m, [](auto x){ return bind(f(x), g); }) == bind(bind(m, f), g)
    //! @endcode
    struct Monad {
        BOOST_HANA_TYPECLASS(Monad);
        template <typename M>
        struct bind_mcd;

        template <typename M>
        struct flatten_mcd;
        struct laws;

        using operators = monad_detail::operators::enable;
    };

    //! Apply a function returning a monad to the value(s) inside a monad.
    //! @relates Monad
    //!
    //!
    //! @param monad
    //! A `Monad` to compose monadically with the given function.
    //!
    //! @param f
    //! A function taking a value inside the `monad` and returning a `Monad`.
    //! It will be called as `f(x)`, where `x` is the same argument as `f`
    //! would be called with when doing `fmap(f, monad)`.
    //!
    //!
    //! ### Example
    //! @include example/monad/bind.cpp
    BOOST_HANA_CONSTEXPR_LAMBDA auto bind = [](auto monad, auto f) {
        return Monad::instance<
            datatype_t<decltype(monad)>
        >::bind_impl(monad, f);
    };

    //! Sequentially compose two monadic actions, discarding any value
    //! produced by the first but not its effects.
    //! @relates Monad
    //!
    //! @note
    //! This is equivalent to Haskell's `>>`.
    //!
    //!
    //! @param before
    //! The first `Monad` in the monadic composition chain. The result of
    //! this monad is ignored, but its effects are combined with that of the
    //! second monad.
    //!
    //! @param monad
    //! The second `Monad` in the monadic composition chain.
    //!
    //!
    //! ### Example
    //! @snippet example/monad/then.cpp main
    BOOST_HANA_CONSTEXPR_LAMBDA auto then = [](auto before, auto monad) {
        return Monad::instance<
            datatype_t<decltype(before)>
        >::then_impl(before, monad);
    };

    //! Flatten two levels of monadic wrapping into a single level.
    //! @relates Monad
    //!
    //! @param monad
    //! A `Monad` containing a `Monad` that should be flattened to a `Monad`.
    //!
    //! ### Example
    //! @snippet example/monad/flatten.cpp main
    BOOST_HANA_CONSTEXPR_LAMBDA auto flatten = [](auto monad) {
        return Monad::instance<
            datatype_t<decltype(monad)>
        >::flatten_impl(monad);
    };

    namespace monad_detail {
        template <typename M>
        struct tap {
            template <typename F>
            constexpr auto operator()(F f) const
            { return Monad::instance<M>::tap_impl(f); }
        };
    }

    //! Tap inside a monadic chain.
    //! @relates Monad
    //!
    //! Specifically, `tap<M>(f)(x)` performs `f(x)` and returns `lift<M>(x)`.
    //! Combined with the law saying that `bind(m, lift<M>) == m`, this
    //! provides a way of executing an action inside a monadic chain without
    //! influencing its result. This is useful to e.g. insert debug statements
    //! or perform actions that are not tied to the chain but that need to be
    //! executed inside of it.
    //!
    //!
    //! @tparam M
    //! The data type (a `Monad`) of the monads in the tapped monadic chain.
    //!
    //! @param f
    //! A function to be executed inside a monadic chain. It will be called
    //! as `f(x)`, where `x` is a value inside the previous monad in the
    //! chain. The result of `f` is always discarded.
    //!
    //!
    //! ### Example
    //! @snippet example/monad/tap.cpp main
#ifdef BOOST_HANA_DOXYGEN_INVOKED
    template <typename M>
    constexpr auto tap = [](auto f) {
        return Monad::instance<M>::tap_impl(f);
    };
#else
    template <typename M>
    constexpr monad_detail::tap<M> tap{};
#endif

    namespace monad_detail { namespace operators {
        //! Equivalent to `bind`.
        //! @relates boost::hana::Monad
        //!
        //! @note
        //! This was preferred over `>>=` because `>>=` is right associative
        //! in C++, which makes it impossible to chain computations.
        template <typename M, typename F>
        constexpr auto operator|(M m, F f)
        { return bind(m, f); }
    }}

    namespace monad_detail {
        template <typename M>
        struct common {
            template <typename M1, typename M2>
            static constexpr auto then_impl(M1 m1, M2 m2)
            { return bind(m1, [=](auto) { return m2; }); }

            template <typename F>
            static constexpr auto tap_impl(F f) {
                return [=](auto x) {
                    f(x);
                    return lift<M>(x);
                };
            }
        };
    }
}} // end namespace boost::hana

#endif // !BOOST_HANA_MONAD_MONAD_HPP

ext: hpp

max_stars_repo_name: rbock/hana

max_issues_repo_name: rbock/hana

max_forks_repo_name: rbock/hana


text:
#include <boost/test/unit_test.hpp>
#include <iostream>
#include <test/setup_common.h>
#include <throttle.h>

BOOST_FIXTURE_TEST_SUITE(throttle_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(test_quota_usage)
{
    const double units_per_sec = 1000;
    const unsigned int wait_ms = 100;
    uint32_t expected_quota = (units_per_sec * wait_ms / 1000);

    Throttle throttle(units_per_sec);

    // Start with zero quota
    auto quota = throttle.GetQuota();
    BOOST_CHECK(quota == 0);

    // Accumulate quota over time
    std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));

    // Get the accumulated quota
    quota = throttle.GetQuota();
    BOOST_CHECK(quota == expected_quota);

    // Use the full quota
    BOOST_CHECK(throttle.UseQuota(quota));
    quota = throttle.GetQuota();
    BOOST_CHECK(quota == 0);

    // Accumulate quota once again
    std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
    quota = throttle.GetQuota();
    BOOST_CHECK(quota == expected_quota);

    // Use only half of the quota
    BOOST_CHECK(throttle.UseQuota(quota / 2));

    // Check that the other half remains
    expected_quota = quota / 2;
    quota = throttle.GetQuota();
    BOOST_CHECK(quota == expected_quota);
}

BOOST_AUTO_TEST_CASE(test_quota_capping)
{
    const double units_per_sec = 20000;
    const double max_quota = 100;
    const unsigned int wait_ms = 10;

    Throttle throttle(units_per_sec);
    throttle.SetMaxQuota(max_quota);

    std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));
    uint32_t uncapped_quota = (units_per_sec * wait_ms / 1000);
    BOOST_CHECK(!throttle.HasQuota(uncapped_quota));
    BOOST_CHECK(throttle.HasQuota(max_quota));
}

BOOST_AUTO_TEST_CASE(test_quota_wait_estimate)
{
    const double units_per_sec = 100;
    const uint32_t target_wait_ms = 10;
    const uint32_t expected_quota = (units_per_sec * target_wait_ms / 1000);

    Throttle throttle(units_per_sec);

    for (int i = 0; i < 10; i++) {
        // Predict the wait to accumulate the expected quota
        const uint32_t wait_ms = throttle.EstimateWait(expected_quota);
        BOOST_CHECK((wait_ms == target_wait_ms) ||
                    (wait_ms == (target_wait_ms - 1)));
        // Given that the quota accumulates continuously as a fractional number
        // and only integer quotas can be consumed, eventually the wait may be
        // one millisecond shorter.

        // Wait and accumulate
        std::this_thread::sleep_for(std::chrono::milliseconds(wait_ms));

        // Now there should be no need to wait any longer
        BOOST_CHECK(throttle.EstimateWait(expected_quota) == 0);
        BOOST_CHECK(throttle.UseQuota(expected_quota));
    }
}

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: ehsanen/bitcoinsatellite

max_issues_repo_name: ehsanen/bitcoinsatellite

max_forks_repo_name: ehsanen/bitcoinsatellite


text:
#include "gurka.h"
#include "loki/reach.h"
#include "sif/costfactory.h"
#include "sif/dynamiccost.h"
#include "test.h"

#include <boost/format.hpp>
#include <gtest/gtest.h>
#include <valhalla/proto/options.pb.h>

using namespace valhalla;
using namespace valhalla::loki;
using LiveTrafficCustomize = test::LiveTrafficCustomize;

namespace {
inline void SetLiveSpeed(baldr::TrafficSpeed* live_speed, uint64_t speed) {
  live_speed->breakpoint1 = 255;
  live_speed->overall_encoded_speed = speed >> 1;
  live_speed->encoded_speed1 = speed >> 1;
}

void close_dir_edge(baldr::GraphReader& reader,
                    baldr::TrafficTile& tile,
                    uint32_t index,
                    baldr::TrafficSpeed* current,
                    const std::string& edge_name,
                    const std::string& end_node,
                    const gurka::map& closure_map) {
  baldr::GraphId tile_id(tile.header->tile_id);
  auto edge = std::get<0>(gurka::findEdge(reader, closure_map.nodes, edge_name, end_node));
  if (edge.Tile_Base() == tile_id && edge.id() == index) {
    SetLiveSpeed(current, 0);
  }
}

void close_bidir_edge(baldr::GraphReader& reader,
                      baldr::TrafficTile& tile,
                      uint32_t index,
                      baldr::TrafficSpeed* current,
                      const std::string& edge_name,
                      const gurka::map& closure_map) {
  baldr::GraphId tile_id(tile.header->tile_id);
  std::string start_node(1, edge_name.front());
  std::string end_node(1, edge_name.back());

  close_dir_edge(reader, tile, index, current, edge_name, start_node, closure_map);
  close_dir_edge(reader, tile, index, current, edge_name, end_node, closure_map);
}
} // namespace

class TestReach : public ::testing::Test {
protected:
  static gurka::map closure_map;
  static int const default_speed;
  static std::string const tile_dir;
  static std::shared_ptr<baldr::GraphReader> reader;

  static void SetUpTestSuite() {
    const std::string ascii_map = R"(

      A---B---C
      |   |   |
      D---E---F
      |   |   |
      G---H---I

      K--L--M--N--O
     )";

    const std::string speed_str = std::to_string(default_speed);
    const gurka::ways ways = {{"AB", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"BC", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"AD", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"BE", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"CF", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"DE", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"EF", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"DG", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"EH", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"FI", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"GH", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"HI", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"KL", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"LM", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"MN", {{"highway", "primary"}, {"maxspeed", speed_str}}},
                              {"NO", {{"highway", "primary"}, {"maxspeed", speed_str}}}};

    const auto layout = gurka::detail::map_to_coordinates(ascii_map, 10, {.05f, .2f});
    closure_map = gurka::buildtiles(layout, ways, {}, {}, tile_dir);

    closure_map.config.put("mjolnir.traffic_extract", tile_dir + "/traffic.tar");
    test::build_live_traffic_data(closure_map.config);

    reader = test::make_clean_graphreader(closure_map.config.get_child("mjolnir"));
  }

  void set_default_speed_on_all_edges() {
    test::customize_live_traffic_data(closure_map.config,
                                      [](baldr::GraphReader&, baldr::TrafficTile&, int,
                                         baldr::TrafficSpeed* current) -> void {
                                        SetLiveSpeed(current, default_speed);
                                      });
  }

  virtual void SetUp() {
    set_default_speed_on_all_edges();
  }

  virtual void TearDown() {
    set_default_speed_on_all_edges();
  }
};

gurka::map TestReach::closure_map = {};
const int TestReach::default_speed = 36;
const std::string TestReach::tile_dir = "test/data/reach_with_closures";
std::shared_ptr<baldr::GraphReader> TestReach::reader;

TEST_F(TestReach, ReachWithNoClosures) {
  // Create costing
  // - type: auto
  // - flow mask: "default" (includes current) to consider live speeds
  // - filter_closures: disable filter closed edges
  sif::CostFactory factory;
  CostingOptions co;
  co.set_costing(valhalla::auto_);
  co.set_flow_mask(kDefaultFlowMask);
  co.set_filter_closures(false);

  auto costing = factory.Create(co);
  auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "A", "B");

  // check its reach
  loki::Reach reach_checker;
  auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

  // all edges should have the same in/outbound reach
  EXPECT_EQ(reach.inbound, reach.outbound);
  EXPECT_EQ(reach.inbound, 9);
  EXPECT_EQ(reach.outbound, 9);
}

TEST_F(TestReach, ReachWithClosures) {
  LiveTrafficCustomize close_edge = [](baldr::GraphReader& reader, baldr::TrafficTile& tile,
                                       uint32_t index, baldr::TrafficSpeed* current) -> void {
    close_bidir_edge(reader, tile, index, current, "AB", closure_map);
    close_bidir_edge(reader, tile, index, current, "BC", closure_map);
    close_bidir_edge(reader, tile, index, current, "AD", closure_map);
    close_bidir_edge(reader, tile, index, current, "BE", closure_map);
  };
  test::customize_live_traffic_data(closure_map.config, close_edge);

  // Create costing
  // - type: auto
  // - flow mask: "default" (includes current) to consider live speeds
  // - filter_closures: enabled, to remove closed edges
  sif::CostFactory factory;
  loki::Reach reach_checker;

  CostingOptions co;
  co.set_costing(valhalla::auto_);
  co.set_flow_mask(kDefaultFlowMask);
  co.set_filter_closures(true);
  // Check reach for AB - enclosed by closures, so reach should be 0
  {
    auto costing = factory.Create(co);
    auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "A", "B");
    auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

    EXPECT_EQ(reach.inbound, reach.outbound);
    EXPECT_EQ(reach.inbound, 0);
    EXPECT_EQ(reach.outbound, 0);
  }
  // Check reach for HI - open, but reduced reach without ignoring closures
  {
    auto costing = factory.Create(co);
    auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "H", "I");
    auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

    EXPECT_EQ(reach.inbound, 7);
    EXPECT_EQ(reach.outbound, 7);
  }

  // Check reach for AB ignoring closures
  {
    co.set_filter_closures(false);
    auto costing = factory.Create(co);
    auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "A", "B");
    auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

    EXPECT_EQ(reach.inbound, 8);
    EXPECT_EQ(reach.outbound, 8);
  }
  // Check reach for HI ignoring closures
  {
    co.set_filter_closures(false);
    auto costing = factory.Create(co);
    auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "H", "I");
    auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

    EXPECT_EQ(reach.inbound, 7);
    EXPECT_EQ(reach.outbound, 7);
  }
}

TEST_F(TestReach, DISABLED_ReachWithClosures2) {
  LiveTrafficCustomize close_edge = [](baldr::GraphReader& reader, baldr::TrafficTile& tile,
                                       uint32_t index, baldr::TrafficSpeed* current) -> void {
    close_bidir_edge(reader, tile, index, current, "LM", closure_map);
    close_bidir_edge(reader, tile, index, current, "MN", closure_map);
  };
  test::customize_live_traffic_data(closure_map.config, close_edge);

  // Create costing
  // - type: auto
  // - flow mask: "default" (includes current) to consider live speeds
  // - filter_closures: enabled, to remove closed edges
  sif::CostFactory factory;
  loki::Reach reach_checker;

  CostingOptions co;
  co.set_costing(valhalla::auto_);
  co.set_flow_mask(kDefaultFlowMask);
  co.set_filter_closures(false);
  auto costing = factory.Create(co);
  auto edge = gurka::findEdgeByNodes(*reader, closure_map.nodes, "K", "L");
  auto reach = reach_checker(std::get<1>(edge), std::get<0>(edge), 50, *reader, costing);

  EXPECT_EQ(reach.inbound, reach.outbound);
  EXPECT_EQ(reach.inbound, 3);
  EXPECT_EQ(reach.outbound, 3);
}

ext: cc

max_stars_repo_name: Akylas/valhalla

max_issues_repo_name: Akylas/valhalla

max_forks_repo_name: Akylas/valhalla


text:
//          Copyright Carl Philipp Reh 2009 - 2016.
// 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 <fcppt/math/size_type.hpp>
#include <fcppt/math/static_size.hpp>
#include <fcppt/math/vector/comparison.hpp>
#include <fcppt/math/vector/object.hpp>
#include <fcppt/math/vector/output.hpp>
#include <fcppt/math/vector/static.hpp>
#include <fcppt/preprocessor/disable_gcc_warning.hpp>
#include <fcppt/preprocessor/pop_warning.hpp>
#include <fcppt/preprocessor/push_warning.hpp>
#include <fcppt/config/external_begin.hpp>
#include <boost/test/unit_test.hpp>
#include <fcppt/config/external_end.hpp>

namespace
{

template<
	typename T,
	fcppt::math::size_type N
>
class view_storage
{
public:
	typedef T value_type;

	typedef fcppt::math::size_type size_type;

	typedef
	fcppt::math::static_size<
		N
	>
	static_size;

	typedef value_type *pointer;

	typedef value_type const *const_pointer;

	typedef value_type &reference;

	typedef value_type const &const_reference;

	typedef pointer iterator;

	typedef const_pointer const_iterator;

	explicit
	view_storage(
		pointer const _data
	)
	:
		data_(
			_data
		)
	{
	}

	iterator
	begin()
	{
		return
			data_;
	}

	const_iterator
	begin() const
	{
		return
			data_;
	}

	iterator
	end()
	{
		return
			data_
			+
			N;
	}

	const_iterator
	end() const
	{
		return
			data_
			+
			N;
	}
private:
	pointer data_;
};

}

FCPPT_PP_PUSH_WARNING
FCPPT_PP_DISABLE_GCC_WARNING(-Weffc++)

BOOST_AUTO_TEST_CASE(
	math_vector_view_storage
)
{
FCPPT_PP_POP_WARNING

	typedef
	view_storage<
		unsigned,
		2
	>
	unsigned_view_storage;

	typedef
	fcppt::math::vector::object<
		unsigned,
		2,
		unsigned_view_storage
	>
	view_vector;

	unsigned data[] = { 1, 2 };

	view_vector const view{
		unsigned_view_storage(
			data
		)
	};

	typedef
	fcppt::math::vector::static_<
		unsigned,
		2
	>
	uivector2;

	uivector2 const vec(
		view
	);

	BOOST_CHECK_EQUAL(
		vec,
		view
	);
}

max_stars_repo_name: vinzenz/fcppt

max_issues_repo_name: vinzenz/fcppt

max_forks_repo_name: vinzenz/fcppt


text:
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#include "dataset/dataset_cache_block_manager.h"

#include <boost/thread/lock_guard.hpp>
#include "common/logging.h"
#include "cache/cache_engine.h"

using namespace pegasus;

namespace pegasus {

CachedColumn::~CachedColumn() {
  if(cache_region_ != nullptr) {
    delete cache_region_;
    cache_region_ = nullptr;
  }
}

DatasetCacheBlockManager::DatasetCacheBlockManager() {
}

DatasetCacheBlockManager::~DatasetCacheBlockManager() {
  // if (cached_datasets_.size() != 0) {
  //   for(auto iter = cached_datasets_.begin(); iter != cached_datasets_.end(); iter++) {
  //     std::string dataset_path = iter->first;
  //     std::shared_ptr<CachedDataset> cached_dataset = iter->second;
  //     std::unordered_map<std::string, std::shared_ptr<CachedPartition>> cached_partitions =
  //      cached_dataset->cached_partitions_;
  //     if(cached_partitions.size() != 0) {
  //       for(auto iter = cached_partitions.begin(); iter != cached_partitions.end(); iter++) {
  //           std::string partition_path = iter->first;
  //           std::shared_ptr<CachedPartition> cached_partition = iter->second;
  //           std::unordered_map<string, std::shared_ptr<CachedColumn>> cached_columns = cached_partition->cached_columns_;
  //           if (cached_columns.size() != 0) {
  //             for(auto iter = cached_columns.begin(); iter != cached_columns.end(); iter ++) {
  //               std::string column_id = iter->first;
  //               DeleteColumn(dataset_path, partition_path, column_id);
  //             }
  //           }
  //           DeletePartition(dataset_path, partition_path);
  //       }
  //     }
  //     DeleteDataset(dataset_path);
  //   }
  // }
}

Status DatasetCacheBlockManager::Init() {
  return Status::OK();
}

Status DatasetCacheBlockManager::GetCachedDataSet(const std::string dataset_path,
  std::shared_ptr<CachedDataset>* dataset) {
  {
    boost::lock_guard<boost::mutex> l(cached_datasets_lock_);
    auto entry = cached_datasets_.find(dataset_path);

   if (entry == cached_datasets_.end()) {
    std::shared_ptr<CachedDataset> new_dataset =
     std::shared_ptr<CachedDataset>(new CachedDataset(dataset_path));
    *dataset = new_dataset;

    // Insert the dataset
    cached_datasets_.insert(std::make_pair(dataset_path, new_dataset));
    LOG(WARNING) << "The dataset does not exist and insert a new dataset";
    return Status::OK();
    }

   LOG(WARNING) << "The dataset exists and return the cached dataset";
   auto find_cache_info = entry->second;
   *dataset = std::shared_ptr<CachedDataset>(find_cache_info);
  }

  return Status::OK();
}

Status CachedDataset::GetCachedPartition(
  const std::string partition_path,
  std::shared_ptr<CachedPartition>* partition) {
    {
    boost::lock_guard<boost::mutex> l(cached_partitions_lock_);
    auto entry = cached_partitions_.find(partition_path);

    if (entry == cached_partitions_.end()) {
      std::shared_ptr<CachedPartition> new_partition =
      std::shared_ptr<CachedPartition>(new CachedPartition(
       dataset_path_, partition_path));
       if (new_partition == nullptr) {
         return Status::Invalid("The new partition is nullptr");
       }
      *partition = new_partition;

      // Insert partition
      cached_partitions_[partition_path] = new_partition;
      LOG(WARNING) << "The partition does not exist and insert a new partition";
      return Status::OK();
    }

    LOG(WARNING) << "The partition exists and return the cached partition";
    auto find_cache_info = entry->second;
    *partition = std::shared_ptr<CachedPartition>(find_cache_info);
   }
  return Status::OK();
}

 Status CachedPartition::GetCachedColumns(
   std::vector<int>  col_ids,
   std::shared_ptr<CacheEngine> cache_engine,
    unordered_map<int, std::shared_ptr<CachedColumn>>* columns) {
  {
    boost::lock_guard<boost::mutex> l(cached_columns_lock_);
    std::string dataset_path = dataset_path_;
    std::string partition_path = partition_path_;

    for (auto iter = col_ids.begin(); iter != col_ids.end(); iter++)
    {
		  auto entry = cached_columns_.find(*iter);
      if (entry != cached_columns_.end()) {
        int colId = *iter;
        auto find_column = entry->second;

        if (cache_engine != nullptr) {
          LRUCache::CacheKey* key = new LRUCache::CacheKey(dataset_path, partition_path, colId);
          // Touch value in lru cache when access the cached column.
          cache_engine->TouchValue(key);
        }

        columns->insert(pair<int, std::shared_ptr<CachedColumn>>(colId, find_column));
       }
	  }
  }
  return Status::OK();
 }

bool CachedPartition::InsertColumn(
   int column_id, std::shared_ptr<CachedColumn> new_column,
    std::shared_ptr<CachedColumn>* cached_column) {
  {
    boost::lock_guard<boost::mutex> l(cached_columns_lock_);
    auto entry = cached_columns_.find(column_id);
    if(entry == cached_columns_.end()) {
      // insert new column
      LOG(WARNING) << "The column does not exist and insert new column";
      cached_columns_[column_id] = std::move(new_column);
      *cached_column = nullptr;
      return true;
    } else {
      // the column is already existed.
      LOG(WARNING) << "The column already exists and will not insert this column";
      *cached_column = entry->second;
      return false;
    }
  }
}

Status DatasetCacheBlockManager::DeleteDataset(const std::string dataset_path) {
  {
    boost::lock_guard<boost::mutex> l(cached_datasets_lock_);
    LOG(WARNING) << "Delete the dataset and the dataset path: " << dataset_path;
    cached_datasets_.erase(dataset_path);
  }
  return Status::OK();
}

Status CachedDataset::DeletePartition(const std::string partition_path,
 std::shared_ptr<CacheEngine> cache_engine){
  {
    boost::lock_guard<boost::mutex> l(cached_partitions_lock_);

    std::shared_ptr<CachedPartition> cached_partition;
    GetCachedPartition(dataset_path_, &cached_partition);
    cached_partition->DeleteEntry(cache_engine);
    cached_partitions_.erase(partition_path);
    LOG(WARNING) << "Delete the partition and the dataset path: "
     << dataset_path_ << " and the partition path: "<< partition_path;
  }
  return Status::OK();
}

Status CachedPartition::DeleteEntry(std::shared_ptr<CacheEngine> cache_engine) {
  {
    boost::lock_guard<boost::mutex> l(cached_columns_lock_);
    for (auto iter = cached_columns_.begin(); iter != cached_columns_.end(); iter ++) {
      std::shared_ptr<CachedColumn> column = iter->second;
      int column_id = iter->first;

      LRUCache::CacheKey* key = new LRUCache::CacheKey(dataset_path_, partition_path_, column_id);
      cache_engine->EraseValue(key);
      LOG(WARNING) << "Delete the partition and the dataset path: "
      << dataset_path_ << " and the partition path: "<< partition_path_ << " and the column id: " << column_id;
    }
  }
  return Status::OK();
}

Status CachedPartition::DeleteColumn(int column_id) {
  {
    boost::lock_guard<boost::mutex> l(cached_columns_lock_);
    if (cached_columns_.find(column_id) != cached_columns_.end()) {
      // If found the column id, then delete it.
      cached_columns_.erase(column_id);
      LOG(WARNING) << "Delete the column and the dataset path: "
       << dataset_path_ <<" and the partition path: " << partition_path_ << " and the column id: " << column_id;
    }
  }
  return Status::OK();
}

} // namespace pegasus

max_stars_repo_name: jerrychenhf/pegasus

max_issues_repo_name: jerrychenhf/pegasus

max_forks_repo_name: jerrychenhf/pegasus


text:
/*
 ******************************************************************************
 Project:      OWA EPANET
 Version:      2.2
 Module:       test_toolkit.cpp
 Description:  Tests EPANET toolkit api functions
 Authors:      see AUTHORS
 Copyright:    see AUTHORS
 License:      see LICENSE
 Last Updated: 03/21/2019
 ******************************************************************************
*/

#define BOOST_TEST_MODULE toolkit

#include <math.h>

#include <boost/test/included/unit_test.hpp>

#include "test_toolkit.hpp"

// Custom test to check the minimum number of correct decimal digits between
// the test and the ref vectors.
boost::test_tools::predicate_result check_cdd_double(std::vector<double>& test,
    std::vector<double>& ref, long cdd_tol){
    double tmp, min_cdd = 10.0;

    // TODO: What if the vectors aren't the same length?

    std::vector<double>::iterator test_it;
    std::vector<double>::iterator ref_it;

    for (test_it = test.begin(), ref_it = ref.begin();
        (test_it < test.end()) && (ref_it < ref.end());
        ++test_it, ++ref_it)
    {
        if (*test_it != *ref_it) {
            // Compute log absolute error
            tmp = abs(*test_it - *ref_it);
            if (tmp < 1.0e-7)
                tmp = 1.0e-7;

            else if (tmp > 2.0)
                tmp = 1.0;

            tmp = -log10(tmp);
            if (tmp < 0.0)
                tmp = 0.0;

            if (tmp < min_cdd)
                min_cdd = tmp;
        }
    }

    return floor(min_cdd) >= cdd_tol;
}

boost::test_tools::predicate_result check_string(std::string test, std::string ref)
{
    if (ref.compare(test) == 0)
        return true;
    else
        return false;
}

max_stars_repo_name: ajholguin/EPANET

max_issues_repo_name: michaeltryby/epanet-solver

max_forks_repo_name: michaeltryby/epanet-solver