<commit_before>
#include "../Flare.h"
#include "FlareTurret.h"
#include "FlareSpacecraft.h"
#include "FlareShell.h"
#include "FlareSpacecraftSubComponent.h"

/*----------------------------------------------------
	Constructor
----------------------------------------------------*/

UFlareTurret::UFlareTurret(const class FObjectInitializer& PCIP)
	: Super(PCIP)
	, TurretComponent(NULL)
	, BarrelComponent(NULL)
{
	HasFlickeringLights = false;
}

/*----------------------------------------------------
	Gameplay
----------------------------------------------------*/

void UFlareTurret::Initialize(const FFlareSpacecraftComponentSave* Data, UFlareCompany* Company, AFlareSpacecraftPawn* OwnerShip, bool IsInMenu)
{
	Super::Initialize(Data, Company, OwnerShip, IsInMenu);
	AimDirection = FVector::ZeroVector;

	// Initialize pilot
	Pilot = NewObject<UFlareTurretPilot>(this, UFlareTurretPilot::StaticClass());
	Pilot->Initialize(&(Data->Pilot), Company, this);
}

void UFlareTurret::SetupFiringEffects()
{
	if (FiringEffect == NULL && FiringEffectTemplate)
	{
		FiringEffects.Empty();

		for (int32 i = 0; i < ComponentDescription->WeaponCharacteristics.GunCharacteristics.GunCount; i++)
		{
			// Create the effect
			UParticleSystemComponent* TempFiringEffect = UGameplayStatics::SpawnEmitterAttached(
				FiringEffectTemplate,
				BarrelComponent,
				NAME_None,
				GetMuzzleLocation(i),
				GetComponentRotation(),
				EAttachLocation::KeepWorldPosition,
				false);

			// Additional setup
			TempFiringEffect->DeactivateSystem();
			TempFiringEffect->SetTickGroup(ETickingGroup::TG_PostPhysics);
			FiringEffects.Add(TempFiringEffect);
		}
	}
}

void UFlareTurret::SetupComponentMesh()
{
	Super::SetupComponentMesh();

	if (TurretComponent)
	{
		TurretComponent->DestroyComponent();
		TurretComponent = NULL;
	}

	if (BarrelComponent)
	{
		BarrelComponent->DestroyComponent();
		BarrelComponent = NULL;
	}

	// Turret Mesh
	if (Spacecraft && ComponentDescription && ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh)
	{

		TurretComponent = NewObject<UFlareSpacecraftSubComponent>(this, UFlareSpacecraftSubComponent::StaticClass(), TEXT("TurretMesh"));
		 if (TurretComponent)
		 {
			TurretComponent->SetParentSpacecraftComponent(this);
			TurretComponent->RegisterComponent();
			TurretComponent->AttachTo(this);
			TurretComponent->SetStaticMesh(ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh);
			TurretComponent->SetMaterial(0, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh->GetMaterial(0));
			TurretComponent->Initialize(NULL, PlayerCompany, Spacecraft, false);
			Spacecraft->AddOwnedComponent(TurretComponent);
		}
	}

	// Barrel Mesh
	if (Spacecraft && ComponentDescription && ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh)
	{

		BarrelComponent = NewObject<UFlareSpacecraftSubComponent>(this, UFlareSpacecraftSubComponent::StaticClass() , TEXT("BarrelMesh"));
		 if (BarrelComponent)
		 {
			 BarrelComponent->SetParentSpacecraftComponent(this);
			BarrelComponent->RegisterComponent();
			if (TurretComponent)
			{
				BarrelComponent->AttachTo(TurretComponent, FName("Axis"));
			}
			else
			{
				BarrelComponent->AttachTo(this);
			}
			BarrelComponent->SetStaticMesh(ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh);
			BarrelComponent->SetMaterial(0, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh->GetMaterial(0));
			Spacecraft->AddOwnedComponent(BarrelComponent);
		}
	}
}

void UFlareTurret::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
	if (Spacecraft->IsPresentationMode())
	{
		TurretComponent->SetRelativeRotation(FRotator(0, 0, 0));
		BarrelComponent->SetRelativeRotation(FRotator(15, 0, 0));

		Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
		return;
	}

	if (Spacecraft->GetDamageSystem()->IsAlive() && Pilot)
	{

		Pilot->TickPilot(DeltaTime);
		//FLOGV("Pilot exist WantFire %d", Pilot->IsWantFire());
		if (Pilot->IsWantFire())
		{
			StartFire();
		}
		else
		{
			StopFire();
		}
		AimDirection = Pilot->GetTargetAimAxis();
		//FLOGV("Pilot AimDirection %s", *AimDirection.ToString());
	}

	if (Spacecraft->GetDamageSystem()->IsAlive() && GetUsableRatio() > 0)
	{

		if (TurretComponent && ComponentDescription)
		{

			float TargetTurretAngle = 0;
			if (AimDirection != FVector::ZeroVector)
			{
				FVector LocalTurretAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				TargetTurretAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalTurretAimDirection.Y, LocalTurretAimDirection.X)));
			}

			// Clamp movements
			TargetTurretAngle = FMath::Clamp(TargetTurretAngle, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMinAngle, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMaxAngle);

			float UsableTurretVelocity = GetUsableRatio() * ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretAngularVelocity;

			float TurretAngleDiff = FMath::UnwindDegrees(TargetTurretAngle - ShipComponentData.Turret.TurretAngle);

			if (FMath::Abs(TurretAngleDiff) <= UsableTurretVelocity * DeltaTime)
			{
				ShipComponentData.Turret.TurretAngle = TargetTurretAngle;
			}
			else if (TurretAngleDiff < 0)
			{
				ShipComponentData.Turret.TurretAngle -= UsableTurretVelocity * DeltaTime;
			}
			else
			{
				ShipComponentData.Turret.TurretAngle += UsableTurretVelocity * DeltaTime;
			}

			TurretComponent->SetRelativeRotation(FRotator(0, ShipComponentData.Turret.TurretAngle, 0));
		}

		if (BarrelComponent)
		{

			float TargetBarrelAngle = 15;

			if (AimDirection != FVector::ZeroVector)
			{
				FVector LocalBarrelAimDirection;
				if (TurretComponent)
				{
					LocalBarrelAimDirection = TurretComponent->GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				}
				else
				{
					LocalBarrelAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				}

				TargetBarrelAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalBarrelAimDirection.Z, LocalBarrelAimDirection.X)));
			}

			// Clamp movements
			TargetBarrelAngle = FMath::Clamp(TargetBarrelAngle, GetMinLimitAtAngle(ShipComponentData.Turret.TurretAngle), ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMaxAngle);

			// TODO Add ship specific bound

			float UsableBarrelsVelocity = GetUsableRatio() * ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretAngularVelocity;
			float BarrelAngleDiff = FMath::UnwindDegrees(TargetBarrelAngle - ShipComponentData.Turret.BarrelsAngle);

			if (FMath::Abs(BarrelAngleDiff) <= UsableBarrelsVelocity * DeltaTime) {
				ShipComponentData.Turret.BarrelsAngle = TargetBarrelAngle;
			} else if (BarrelAngleDiff < 0) {
				ShipComponentData.Turret.BarrelsAngle -= UsableBarrelsVelocity * DeltaTime;
			} else {
				ShipComponentData.Turret.BarrelsAngle += UsableBarrelsVelocity * DeltaTime;
			}
			BarrelComponent->SetRelativeRotation(FRotator(ShipComponentData.Turret.BarrelsAngle, 0, 0));

		}
	}

	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

FVector UFlareTurret::GetFireAxis() const
{
	if (BarrelComponent)
	{
		return BarrelComponent->GetComponentRotation().RotateVector(FVector(1, 0, 0));
	}
	else if (TurretComponent)
	{
		return TurretComponent->GetComponentRotation().RotateVector(FVector(1, 0, 0));
	}
	else
	{
		return Super::GetFireAxis();
	}
}

FVector UFlareTurret::GetIdleAxis() const
{
	// Ship front
	return Spacecraft->Airframe->GetComponentRotation().RotateVector(FVector(1, 0, 0));
}

FVector UFlareTurret::GetMuzzleLocation(int GunIndex) const
{
	const UStaticMeshComponent* GunComponent = this;
	if (BarrelComponent)
	{
		GunComponent = BarrelComponent;
	}
	else if (TurretComponent)
	{
		GunComponent = TurretComponent;
	}

	if (ComponentDescription->WeaponCharacteristics.GunCharacteristics.GunCount <= 1)
	{
		return GunComponent->GetSocketLocation(FName("Muzzle"));
	}
	else
	{
		return GunComponent->GetSocketLocation(FName(*(FString("Muzzle") + FString::FromInt(GunIndex))));
	}
}

FVector UFlareTurret::GetTurretBaseLocation() const
{
	if (BarrelComponent)
	{
		return BarrelComponent->GetComponentLocation();
	}
	else if (TurretComponent)
	{
		return TurretComponent->GetComponentLocation();
	}
	return GetComponentLocation();
}

bool UFlareTurret::IsSafeToFire(int GunIndex) const
{
	FVector FiringLocation = GetMuzzleLocation(GunIndex);
	FVector FiringDirection = GetFireAxis();
	FVector TargetLocation = FiringLocation + FiringDirection * 100000;

	FHitResult HitResult(ForceInit);
	if (Trace(FiringLocation, TargetLocation, HitResult))
	{
		if (HitResult.Actor.IsValid() && HitResult.Actor == Spacecraft)
		{
			//FLOG("!!!!!!!!!Not safe to fire !");
			return false;
		}
	}
	return true;
}

bool UFlareTurret::Trace(const FVector& Start, const FVector& End, FHitResult& HitOut) const
{
	FCollisionQueryParams TraceParams(FName(TEXT("Shell Trace")), true, NULL);
	TraceParams.bTraceComplex = true;
	// TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = false;

	// Re-initialize hit info
	HitOut = FHitResult(ForceInit);

	ECollisionChannel CollisionChannel = (ECollisionChannel) (ECC_WorldStatic | ECC_WorldDynamic | ECC_Pawn);

	// Trace!
	GetWorld()->LineTraceSingleByChannel(
		HitOut,		// result
		Start,	// start
		End , // end
		CollisionChannel, // collision channel
		TraceParams
	);

	// Hit any Actor?
	return (HitOut.GetActor() != NULL) ;
}

bool UFlareTurret::IsReacheableAxis(FVector TargetAxis) const
{
	float TargetTurretAngle = 0;
	if (TurretComponent && ComponentDescription)
	{

		FVector LocalTurretAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		TargetTurretAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalTurretAimDirection.Y, LocalTurretAimDirection.X)));

		if (TargetTurretAngle > ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMaxAngle
				|| TargetTurretAngle < ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMinAngle)
		{
			return false;
		}
	}

	if (BarrelComponent && ComponentDescription)
	{

		FVector LocalBarrelAimDirection;
		if (TurretComponent)
		{
			LocalBarrelAimDirection = TurretComponent->GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		}
		else
		{
			LocalBarrelAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		}

		float TargetBarrelAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalBarrelAimDirection.Z, LocalBarrelAimDirection.X)));
		if (TargetBarrelAngle > ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMaxAngle
				|| TargetBarrelAngle < GetMinLimitAtAngle(TargetTurretAngle))
		{
			return false;
		}

	}
	return true;
}

static inline int PositiveModulo(int i, int n)
{
	return (i % n + n) % n;
}

float UFlareTurret::GetMinLimitAtAngle(float Angle) const
{
	float BarrelsMinAngle = ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMinAngle;

	// Fine Local slot check
	for (int32 i = 0; i < Spacecraft->GetDescription()->TurretSlots.Num(); i++)
	{
		// TODO optimize and store that in cache
		if (Spacecraft->GetDescription()->TurretSlots[i].SlotIdentifier == ShipComponentData.ShipSlotIdentifier)
		{
			int LimitStepCount = Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit.Num();

			if (LimitStepCount > 0)
			{
				float StepAngle = 360.f / (float) LimitStepCount;

				float AngleInStep = Angle / StepAngle;
				int NearestStep = FMath::FloorToInt(AngleInStep + 0.5f);
				int SecondNearestStep;
				if (AngleInStep > NearestStep)
				{
					SecondNearestStep = NearestStep+1;
				}
				else
				{
					SecondNearestStep = NearestStep-1;
				}

				float Ratio = FMath::Abs(Angle - NearestStep * StepAngle) /  StepAngle;

				float LocalMin = Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit[PositiveModulo(NearestStep, LimitStepCount)] * (1.f - Ratio)
									+ Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit[PositiveModulo(SecondNearestStep,LimitStepCount)] * Ratio;

				BarrelsMinAngle = FMath::Max(BarrelsMinAngle, LocalMin);
			}
		}

	}
	return BarrelsMinAngle;
}

void UFlareTurret::GetBoundingSphere(FVector& Location, float& SphereRadius)
{
	Super::GetBoundingSphere(Location, SphereRadius);
	if (TurretComponent || BarrelComponent)
	{
		SphereRadius = 0;
	}
}

void UFlareTurret::ShowFiringEffects(int GunIndex)
{
	if (FiringEffects[GunIndex])
	{
		FiringEffects[GunIndex]->ActivateSystem();
	}
}
<commit_msg>#309 Fix crash on ugrading ship with turret du to component wrong recyling<commit_after>
#include "../Flare.h"
#include "FlareTurret.h"
#include "FlareSpacecraft.h"
#include "FlareShell.h"
#include "FlareSpacecraftSubComponent.h"

/*----------------------------------------------------
	Constructor
----------------------------------------------------*/

UFlareTurret::UFlareTurret(const class FObjectInitializer& PCIP)
	: Super(PCIP)
	, TurretComponent(NULL)
	, BarrelComponent(NULL)
{
	HasFlickeringLights = false;
}

/*----------------------------------------------------
	Gameplay
----------------------------------------------------*/

void UFlareTurret::Initialize(const FFlareSpacecraftComponentSave* Data, UFlareCompany* Company, AFlareSpacecraftPawn* OwnerShip, bool IsInMenu)
{
	Super::Initialize(Data, Company, OwnerShip, IsInMenu);
	AimDirection = FVector::ZeroVector;

	// Initialize pilot
	Pilot = NewObject<UFlareTurretPilot>(this, UFlareTurretPilot::StaticClass());
	Pilot->Initialize(&(Data->Pilot), Company, this);
}

void UFlareTurret::SetupFiringEffects()
{
	if (FiringEffect == NULL && FiringEffectTemplate)
	{
		FiringEffects.Empty();

		for (int32 i = 0; i < ComponentDescription->WeaponCharacteristics.GunCharacteristics.GunCount; i++)
		{
			// Create the effect
			UParticleSystemComponent* TempFiringEffect = UGameplayStatics::SpawnEmitterAttached(
				FiringEffectTemplate,
				BarrelComponent,
				NAME_None,
				GetMuzzleLocation(i),
				GetComponentRotation(),
				EAttachLocation::KeepWorldPosition,
				false);

			// Additional setup
			TempFiringEffect->DeactivateSystem();
			TempFiringEffect->SetTickGroup(ETickingGroup::TG_PostPhysics);
			FiringEffects.Add(TempFiringEffect);
		}
	}
}

void UFlareTurret::SetupComponentMesh()
{
	Super::SetupComponentMesh();

	if (TurretComponent)
	{
		TurretComponent->DestroyComponent();
		TurretComponent = NULL;
	}

	if (BarrelComponent)
	{
		BarrelComponent->DestroyComponent();
		BarrelComponent = NULL;
	}

	// Turret Mesh
	if (Spacecraft && ComponentDescription && ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh)
	{

		TurretComponent = NewObject<UFlareSpacecraftSubComponent>(this, UFlareSpacecraftSubComponent::StaticClass());
		 if (TurretComponent)
		 {
			TurretComponent->SetParentSpacecraftComponent(this);
			TurretComponent->RegisterComponent();
			TurretComponent->AttachTo(this);
			TurretComponent->SetStaticMesh(ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh);
			TurretComponent->SetMaterial(0, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMesh->GetMaterial(0));
			TurretComponent->Initialize(NULL, PlayerCompany, Spacecraft, false);
			Spacecraft->AddOwnedComponent(TurretComponent);
		}
	}

	// Barrel Mesh
	if (Spacecraft && ComponentDescription && ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh)
	{

		BarrelComponent = NewObject<UFlareSpacecraftSubComponent>(this, UFlareSpacecraftSubComponent::StaticClass());
		 if (BarrelComponent)
		 {
			 BarrelComponent->SetParentSpacecraftComponent(this);
			BarrelComponent->RegisterComponent();
			if (TurretComponent)
			{
				BarrelComponent->AttachTo(TurretComponent, FName("Axis"));
			}
			else
			{
				BarrelComponent->AttachTo(this);
			}
			BarrelComponent->SetStaticMesh(ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh);
			BarrelComponent->SetMaterial(0, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMesh->GetMaterial(0));
			Spacecraft->AddOwnedComponent(BarrelComponent);
		}
	}
}

void UFlareTurret::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction)
{
	if (Spacecraft->IsPresentationMode())
	{
		TurretComponent->SetRelativeRotation(FRotator(0, 0, 0));
		BarrelComponent->SetRelativeRotation(FRotator(15, 0, 0));

		Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
		return;
	}

	if (Spacecraft->GetDamageSystem()->IsAlive() && Pilot)
	{

		Pilot->TickPilot(DeltaTime);
		//FLOGV("Pilot exist WantFire %d", Pilot->IsWantFire());
		if (Pilot->IsWantFire())
		{
			StartFire();
		}
		else
		{
			StopFire();
		}
		AimDirection = Pilot->GetTargetAimAxis();
		//FLOGV("Pilot AimDirection %s", *AimDirection.ToString());
	}

	if (Spacecraft->GetDamageSystem()->IsAlive() && GetUsableRatio() > 0)
	{

		if (TurretComponent && ComponentDescription)
		{

			float TargetTurretAngle = 0;
			if (AimDirection != FVector::ZeroVector)
			{
				FVector LocalTurretAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				TargetTurretAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalTurretAimDirection.Y, LocalTurretAimDirection.X)));
			}

			// Clamp movements
			TargetTurretAngle = FMath::Clamp(TargetTurretAngle, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMinAngle, ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMaxAngle);

			float UsableTurretVelocity = GetUsableRatio() * ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretAngularVelocity;

			float TurretAngleDiff = FMath::UnwindDegrees(TargetTurretAngle - ShipComponentData.Turret.TurretAngle);

			if (FMath::Abs(TurretAngleDiff) <= UsableTurretVelocity * DeltaTime)
			{
				ShipComponentData.Turret.TurretAngle = TargetTurretAngle;
			}
			else if (TurretAngleDiff < 0)
			{
				ShipComponentData.Turret.TurretAngle -= UsableTurretVelocity * DeltaTime;
			}
			else
			{
				ShipComponentData.Turret.TurretAngle += UsableTurretVelocity * DeltaTime;
			}

			TurretComponent->SetRelativeRotation(FRotator(0, ShipComponentData.Turret.TurretAngle, 0));
		}

		if (BarrelComponent)
		{

			float TargetBarrelAngle = 15;

			if (AimDirection != FVector::ZeroVector)
			{
				FVector LocalBarrelAimDirection;
				if (TurretComponent)
				{
					LocalBarrelAimDirection = TurretComponent->GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				}
				else
				{
					LocalBarrelAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(AimDirection);
				}

				TargetBarrelAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalBarrelAimDirection.Z, LocalBarrelAimDirection.X)));
			}

			// Clamp movements
			TargetBarrelAngle = FMath::Clamp(TargetBarrelAngle, GetMinLimitAtAngle(ShipComponentData.Turret.TurretAngle), ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMaxAngle);

			// TODO Add ship specific bound

			float UsableBarrelsVelocity = GetUsableRatio() * ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretAngularVelocity;
			float BarrelAngleDiff = FMath::UnwindDegrees(TargetBarrelAngle - ShipComponentData.Turret.BarrelsAngle);

			if (FMath::Abs(BarrelAngleDiff) <= UsableBarrelsVelocity * DeltaTime) {
				ShipComponentData.Turret.BarrelsAngle = TargetBarrelAngle;
			} else if (BarrelAngleDiff < 0) {
				ShipComponentData.Turret.BarrelsAngle -= UsableBarrelsVelocity * DeltaTime;
			} else {
				ShipComponentData.Turret.BarrelsAngle += UsableBarrelsVelocity * DeltaTime;
			}
			BarrelComponent->SetRelativeRotation(FRotator(ShipComponentData.Turret.BarrelsAngle, 0, 0));

		}
	}

	Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}

FVector UFlareTurret::GetFireAxis() const
{
	if (BarrelComponent)
	{
		return BarrelComponent->GetComponentRotation().RotateVector(FVector(1, 0, 0));
	}
	else if (TurretComponent)
	{
		return TurretComponent->GetComponentRotation().RotateVector(FVector(1, 0, 0));
	}
	else
	{
		return Super::GetFireAxis();
	}
}

FVector UFlareTurret::GetIdleAxis() const
{
	// Ship front
	return Spacecraft->Airframe->GetComponentRotation().RotateVector(FVector(1, 0, 0));
}

FVector UFlareTurret::GetMuzzleLocation(int GunIndex) const
{
	const UStaticMeshComponent* GunComponent = this;
	if (BarrelComponent)
	{
		GunComponent = BarrelComponent;
	}
	else if (TurretComponent)
	{
		GunComponent = TurretComponent;
	}

	if (ComponentDescription->WeaponCharacteristics.GunCharacteristics.GunCount <= 1)
	{
		return GunComponent->GetSocketLocation(FName("Muzzle"));
	}
	else
	{
		return GunComponent->GetSocketLocation(FName(*(FString("Muzzle") + FString::FromInt(GunIndex))));
	}
}

FVector UFlareTurret::GetTurretBaseLocation() const
{
	if (BarrelComponent)
	{
		return BarrelComponent->GetComponentLocation();
	}
	else if (TurretComponent)
	{
		return TurretComponent->GetComponentLocation();
	}
	return GetComponentLocation();
}

bool UFlareTurret::IsSafeToFire(int GunIndex) const
{
	FVector FiringLocation = GetMuzzleLocation(GunIndex);
	FVector FiringDirection = GetFireAxis();
	FVector TargetLocation = FiringLocation + FiringDirection * 100000;

	FHitResult HitResult(ForceInit);
	if (Trace(FiringLocation, TargetLocation, HitResult))
	{
		if (HitResult.Actor.IsValid() && HitResult.Actor == Spacecraft)
		{
			//FLOG("!!!!!!!!!Not safe to fire !");
			return false;
		}
	}
	return true;
}

bool UFlareTurret::Trace(const FVector& Start, const FVector& End, FHitResult& HitOut) const
{
	FCollisionQueryParams TraceParams(FName(TEXT("Shell Trace")), true, NULL);
	TraceParams.bTraceComplex = true;
	// TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = false;

	// Re-initialize hit info
	HitOut = FHitResult(ForceInit);

	ECollisionChannel CollisionChannel = (ECollisionChannel) (ECC_WorldStatic | ECC_WorldDynamic | ECC_Pawn);

	// Trace!
	GetWorld()->LineTraceSingleByChannel(
		HitOut,		// result
		Start,	// start
		End , // end
		CollisionChannel, // collision channel
		TraceParams
	);

	// Hit any Actor?
	return (HitOut.GetActor() != NULL) ;
}

bool UFlareTurret::IsReacheableAxis(FVector TargetAxis) const
{
	float TargetTurretAngle = 0;
	if (TurretComponent && ComponentDescription)
	{

		FVector LocalTurretAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		TargetTurretAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalTurretAimDirection.Y, LocalTurretAimDirection.X)));

		if (TargetTurretAngle > ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMaxAngle
				|| TargetTurretAngle < ComponentDescription->WeaponCharacteristics.TurretCharacteristics.TurretMinAngle)
		{
			return false;
		}
	}

	if (BarrelComponent && ComponentDescription)
	{

		FVector LocalBarrelAimDirection;
		if (TurretComponent)
		{
			LocalBarrelAimDirection = TurretComponent->GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		}
		else
		{
			LocalBarrelAimDirection = GetComponentToWorld().GetRotation().Inverse().RotateVector(TargetAxis);
		}

		float TargetBarrelAngle = FMath::UnwindDegrees(FMath::RadiansToDegrees(FMath::Atan2(LocalBarrelAimDirection.Z, LocalBarrelAimDirection.X)));
		if (TargetBarrelAngle > ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMaxAngle
				|| TargetBarrelAngle < GetMinLimitAtAngle(TargetTurretAngle))
		{
			return false;
		}

	}
	return true;
}

static inline int PositiveModulo(int i, int n)
{
	return (i % n + n) % n;
}

float UFlareTurret::GetMinLimitAtAngle(float Angle) const
{
	float BarrelsMinAngle = ComponentDescription->WeaponCharacteristics.TurretCharacteristics.BarrelsMinAngle;

	// Fine Local slot check
	for (int32 i = 0; i < Spacecraft->GetDescription()->TurretSlots.Num(); i++)
	{
		// TODO optimize and store that in cache
		if (Spacecraft->GetDescription()->TurretSlots[i].SlotIdentifier == ShipComponentData.ShipSlotIdentifier)
		{
			int LimitStepCount = Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit.Num();

			if (LimitStepCount > 0)
			{
				float StepAngle = 360.f / (float) LimitStepCount;

				float AngleInStep = Angle / StepAngle;
				int NearestStep = FMath::FloorToInt(AngleInStep + 0.5f);
				int SecondNearestStep;
				if (AngleInStep > NearestStep)
				{
					SecondNearestStep = NearestStep+1;
				}
				else
				{
					SecondNearestStep = NearestStep-1;
				}

				float Ratio = FMath::Abs(Angle - NearestStep * StepAngle) /  StepAngle;

				float LocalMin = Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit[PositiveModulo(NearestStep, LimitStepCount)] * (1.f - Ratio)
									+ Spacecraft->GetDescription()->TurretSlots[i].TurretBarrelsAngleLimit[PositiveModulo(SecondNearestStep,LimitStepCount)] * Ratio;

				BarrelsMinAngle = FMath::Max(BarrelsMinAngle, LocalMin);
			}
		}

	}
	return BarrelsMinAngle;
}

void UFlareTurret::GetBoundingSphere(FVector& Location, float& SphereRadius)
{
	Super::GetBoundingSphere(Location, SphereRadius);
	if (TurretComponent || BarrelComponent)
	{
		SphereRadius = 0;
	}
}

void UFlareTurret::ShowFiringEffects(int GunIndex)
{
	if (FiringEffects[GunIndex])
	{
		FiringEffects[GunIndex]->ActivateSystem();
	}
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "PageCoreTests.h"
#include "OgrePaging.h"

CPPUNIT_TEST_SUITE_REGISTRATION( PageCoreTests );

void PageCoreTests::setUp()
{
	mRoot = OGRE_NEW Root();
	mPageManager = OGRE_NEW PageManager();

	mRoot->addResourceLocation("./", "FileSystem");

	mSceneMgr = mRoot->createSceneManager(ST_GENERIC);

}

void PageCoreTests::tearDown()
{
	OGRE_DELETE mPageManager;
	OGRE_DELETE mRoot;
}

void PageCoreTests::testSimpleCreateSaveLoadWorld()
{
	String worldName = "MyWorld";
	String filename = "myworld.world";
	String sectionName1 = "Section1";
	String sectionName2 = "Section2";
	PagedWorld* world = mPageManager->createWorld(worldName);
	PagedWorldSection* section = world->createSection("Grid2D", mSceneMgr, sectionName1);
	section = world->createSection("Grid2D", mSceneMgr, sectionName2);

	// Create a page
	Page* p = section->loadOrCreatePage(Vector3::ZERO);

	SimplePageContentCollection* coll = static_cast<SimplePageContentCollection*>(
		p->createContentCollection("Simple"));

	world->save(filename);

	mPageManager->destroyWorld(world);
	world = 0;

	world = mPageManager->loadWorld(filename);

	CPPUNIT_ASSERT_EQUAL(worldName, world->getName());
	CPPUNIT_ASSERT_EQUAL((size_t)2, world->getSectionCount());

	section = world->getSection(sectionName1);
	CPPUNIT_ASSERT(section != 0);
	section = world->getSection(sectionName2);
	CPPUNIT_ASSERT(section != 0);

}

<commit_msg>PageCoreTests was throwing an exception, so the unit tests would not complete. The problem was that the added resource location needed to be read/write.<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2012 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "PageCoreTests.h"
#include "OgrePaging.h"

CPPUNIT_TEST_SUITE_REGISTRATION( PageCoreTests );

void PageCoreTests::setUp()
{
	mRoot = OGRE_NEW Root();
	mPageManager = OGRE_NEW PageManager();

	// make certain the resource location is NOT read-only
	ResourceGroupManager::getSingleton().addResourceLocation("./", "FileSystem",
	    ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, false, false);

	mSceneMgr = mRoot->createSceneManager(ST_GENERIC);

}

void PageCoreTests::tearDown()
{
	OGRE_DELETE mPageManager;
	OGRE_DELETE mRoot;
}

void PageCoreTests::testSimpleCreateSaveLoadWorld()
{
	String worldName = "MyWorld";
	String filename = "myworld.world";
	String sectionName1 = "Section1";
	String sectionName2 = "Section2";
	PagedWorld* world = mPageManager->createWorld(worldName);
	PagedWorldSection* section = world->createSection("Grid2D", mSceneMgr, sectionName1);
	section = world->createSection("Grid2D", mSceneMgr, sectionName2);

	// Create a page
	Page* p = section->loadOrCreatePage(Vector3::ZERO);

	SimplePageContentCollection* coll = static_cast<SimplePageContentCollection*>(
		p->createContentCollection("Simple"));

	world->save(filename);

	mPageManager->destroyWorld(world);
	world = 0;
	world = mPageManager->loadWorld(filename);

	CPPUNIT_ASSERT_EQUAL(worldName, world->getName());
	CPPUNIT_ASSERT_EQUAL((size_t)2, world->getSectionCount());

	section = world->getSection(sectionName1);
	CPPUNIT_ASSERT(section != 0);
	section = world->getSection(sectionName2);
	CPPUNIT_ASSERT(section != 0);

}

<|endoftext|>


<commit_before>#ifndef STAN_MATH_FWD_FUN_HPP
#define STAN_MATH_FWD_FUN_HPP

#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/fwd/fun/Eigen_NumTraits.hpp>

#include <stan/math/fwd/prob/std_normal_log_qf.hpp>

#endif<commit_msg>whitespace<commit_after>#ifndef STAN_MATH_FWD_FUN_HPP
#define STAN_MATH_FWD_FUN_HPP

#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/fwd/fun/Eigen_NumTraits.hpp>

#include <stan/math/fwd/prob/std_normal_log_qf.hpp>

#endif
<|endoftext|>


<commit_before>#include "audiobase.h"

namespace openalpp {

AudioBase::AudioBase(int frequency,int refresh,int synchronous)
  throw (InitError)
{
  if(!instances_) {
    device_=alcOpenDevice(NULL);
    if(!device_)
      throw InitError("Couldn't open device.");
    int attributes[7],i=0;
    attributes[0]=0;
    if(frequency>0) {
      attributes[i++]=ALC_FREQUENCY;
      attributes[i++]=frequency;
      attributes[i]=0;
    }
    if(refresh>0) {
      attributes[i++]=ALC_REFRESH;
      attributes[i++]=refresh;
      attributes[i]=0;
    }
    if(synchronous>0) {
      attributes[i++]=ALC_SYNC;
      attributes[i++]=synchronous;
      attributes[i]=0;
    }
    context_=alcCreateContext(device_,attributes);
    if(!context_ || alcGetError(device_)!=AL_FALSE) {
      if(context_)
	alcDestroyContext(context_);
      else
	alcCloseDevice(device_);
      throw InitError("Couldn't create context.");
    }
    alcMakeContextCurrent(context_);
    reverbinitiated_=false;
  }
  instances_++;
}

AudioBase::~AudioBase() {
  instances_--;
  if(!instances_) {
    alcDestroyContext(context_);
  }
}

// Static member
int AudioBase::instances_=0;

}
<commit_msg>Changed device to open in write-only<commit_after>#include "audiobase.h"

namespace openalpp {

AudioBase::AudioBase(int frequency,int refresh,int synchronous)
  throw (InitError)
{
  if(!instances_) {
    // Open a write (output) device. This should (in theory) make it possible
    // to open a read (input) device later..
    device_=alcOpenDevice((const ALubyte *)"'((direction \"write\"))");
    if(!device_)
      throw InitError("Couldn't open device.");
    int attributes[7],i=0;
    attributes[0]=0;
    if(frequency>0) {
      attributes[i++]=ALC_FREQUENCY;
      attributes[i++]=frequency;
      attributes[i]=0;
    }
    if(refresh>0) {
      attributes[i++]=ALC_REFRESH;
      attributes[i++]=refresh;
      attributes[i]=0;
    }
    if(synchronous>0) {
      attributes[i++]=ALC_SYNC;
      attributes[i++]=synchronous;
      attributes[i]=0;
    }
    context_=alcCreateContext(device_,attributes);
    if(!context_ || alcGetError(device_)!=AL_FALSE) {
      if(context_)
	alcDestroyContext(context_);
      else
	alcCloseDevice(device_);
      throw InitError("Couldn't create context.");
    }
    alcMakeContextCurrent(context_);
    reverbinitiated_=false;
  }
  instances_++;
}

AudioBase::~AudioBase() {
  instances_--;
  if(!instances_) {
    alcDestroyContext(context_);
  }
}

// Static member
int AudioBase::instances_=0;

}
<|endoftext|>


<commit_before>#include <mapbox/geojsonvt.hpp>
#include "util.hpp"

using namespace mapbox::geojsonvt;

int main() {

    unsigned iterations = 1000;

    std::string filename("data/countries.geojson");
    std::string data = loadFile(filename);
    // load once before benchmarking to warm up
    const auto features = GeoJSONVT::convertFeatures(data);
    std::unique_ptr<GeoJSONVT> vt = std::make_unique<GeoJSONVT>(features);

    Timer timer;

    for (unsigned i=0;i<iterations;++i) {
        GeoJSONVT::convertFeatures(data);
    }
    timer.report("convertFeatures");

    for (unsigned i=0;i<iterations;++i) {
        std::make_unique<GeoJSONVT>(features);
    }
    timer.report("parse");

    for (unsigned z=0;z<255;++z) {
        for (unsigned x=0;x<255;++x) {
            for (unsigned y=0;y<255;++y) {
                vt->getTile(z, x, y);
            }
        }
    }
    timer.report("getTile");
}<commit_msg>include missing header<commit_after>#include <mapbox/geojsonvt.hpp>
#include <memory>
#include "util.hpp"

using namespace mapbox::geojsonvt;

int main() {

    unsigned iterations = 1000;

    std::string filename("data/countries.geojson");
    std::string data = loadFile(filename);
    // load once before benchmarking to warm up
    const auto features = GeoJSONVT::convertFeatures(data);
    std::unique_ptr<GeoJSONVT> vt = std::make_unique<GeoJSONVT>(features);

    Timer timer;

    for (unsigned i=0;i<iterations;++i) {
        GeoJSONVT::convertFeatures(data);
    }
    timer.report("convertFeatures");

    for (unsigned i=0;i<iterations;++i) {
        std::make_unique<GeoJSONVT>(features);
    }
    timer.report("parse");

    for (unsigned z=0;z<255;++z) {
        for (unsigned x=0;x<255;++x) {
            for (unsigned y=0;y<255;++y) {
                vt->getTile(z, x, y);
            }
        }
    }
    timer.report("getTile");
}<|endoftext|>


<commit_before>/*
  Copyright (c) 2017, 2018 Jouni Siren

  Author: Jouni Siren <jouni.siren@iki.fi>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

#include <random>
#include <unistd.h>

#include <gbwt/dynamic_gbwt.h>

using namespace gbwt;

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

const std::string tool_name = "GBWT benchmark";

const size_type RANDOM_SEED  = 0xDEADBEEF;

void printUsage(int exit_code = EXIT_SUCCESS);

std::vector<SearchState> findBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type find_queries, size_type pattern_length, std::vector<vector_type>& queries);

void bidirectionalBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, const std::vector<vector_type>& queries);

template<class GBWTType>
void locateBenchmark(const GBWTType& index, const std::vector<SearchState>& queries);

void extractBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type extract_queries);

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

int
main(int argc, char** argv)
{
  if(argc < 2) { printUsage(); }

  int c = 0;
  bool find = false, locate = false, extract = false;
  size_type find_queries = 0, pattern_length = 0, extract_queries = 0;
  while((c = getopt(argc, argv, "f:p:le:")) != -1)
  {
    switch(c)
    {
    case 'f':
      find = true;
      find_queries = std::stoul(optarg); break;
    case 'p':
      pattern_length = std::stoul(optarg); break;
    case 'l':
      locate = true; break;
    case 'e':
      extract = true;
      extract_queries = std::stoul(optarg); break;
    case '?':
      std::exit(EXIT_FAILURE);
    default:
      std::exit(EXIT_FAILURE);
    }
  }

  if(optind >= argc) { printUsage(EXIT_FAILURE); }
  std::string index_base = argv[optind];
  if(find)
  {
    if(find_queries == 0 || pattern_length == 0)
    {
      std::cerr << "benchmark: Number of queries and pattern length must be non-zero" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  if(locate)
  {
    if(!find)
    {
      std::cerr << "benchmark: Cannot benchmark locate() queries without find() queries" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  if(extract)
  {
    if(extract_queries == 0)
    {
      std::cerr << "benchmark: Number of queries must be non-zero" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }

  Version::print(std::cout, tool_name);
  printHeader("Index name"); std::cout << index_base << std::endl;
  if(find || locate || extract)
  {
    printHeader("Queries");
    if(find) { std::cout << "find(" << find_queries << ", " << pattern_length << ") "; }
    if(locate) { std::cout << "locate() "; }
    if(extract) { std::cout << "extract(" << extract_queries << ") "; }
    std::cout << std::endl;
  }
  std::cout << std::endl;

  GBWT compressed_index;
  sdsl::load_from_file(compressed_index, index_base + GBWT::EXTENSION);
  printStatistics(compressed_index, index_base);
  if(!(find || locate || extract)) { return 0; }

  DynamicGBWT dynamic_index;
  sdsl::load_from_file(dynamic_index, index_base + DynamicGBWT::EXTENSION);
  printStatistics(dynamic_index, index_base);

  if(find)
  {
    std::vector<vector_type> queries;
    std::vector<SearchState> results = findBenchmark(compressed_index, dynamic_index, find_queries, pattern_length, queries);
    if(compressed_index.bidirectional())
    {
      bidirectionalBenchmark(compressed_index, dynamic_index, queries);
    }
    queries.clear();
    if(locate)
    {
      locateBenchmark(compressed_index, results);
      locateBenchmark(dynamic_index, results);
    }
  }
  if(extract)
  {
    extractBenchmark(compressed_index, dynamic_index, extract_queries);
  }

  return 0;
}

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

void
printUsage(int exit_code)
{
  Version::print(std::cerr, tool_name);

  std::cerr << "Usage: benchmark [options] index_base" << std::endl;
  std::cerr << "  -f N  Benchmark N find() queries (requires -p)" << std::endl;
  std::cerr << "  -p N  Use patterns of length N" << std::endl;
  std::cerr << "  -l    Benchmark locate() queries (requires -f)" << std::endl;
  std::cerr << "  -e N  Benchmark N extract() queries" << std::endl;
  std::cerr << std::endl;

  std::exit(exit_code);
}

std::vector<vector_type>
generateQueries(const DynamicGBWT& index, size_type find_queries, size_type pattern_length)
{
  std::mt19937_64 rng(RANDOM_SEED);
  std::vector<vector_type> result;

  size_type attempts = 0;
  while(result.size() < find_queries && attempts < 2 * find_queries)
  {
    vector_type sequence = index.extract(rng() % index.sequences());
    if(sequence.size() >= pattern_length)
    {
      size_type start_offset = rng() % (sequence.size() + 1 - pattern_length);
      result.push_back(vector_type(sequence.begin() + start_offset, sequence.begin() + start_offset + pattern_length));
    }
    attempts++;
  }

  std::cout << "Generated " << result.size() << " queries of total length " << (result.size() * pattern_length) << std::endl;
  return result;
}

std::string indexType(const GBWT&) { return "Compressed GBWT"; }
std::string indexType(const DynamicGBWT&) { return "Dynamic GBWT"; }

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

template<class GBWTType>
size_type
findBenchmark(const GBWTType& index, const std::vector<vector_type>& queries, std::vector<SearchState>& results)
{
  double start = readTimer();
  size_type total_length = 0, total_size = 0;
  for(size_type i = 0; i < queries.size(); i++)
  {
    results[i] = index.find(queries[i].begin(), queries[i].end());
    total_length += queries[i].size();
    total_size += results[i].size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), queries.size(), total_length, seconds);
  return total_size;
}

std::vector<SearchState>
findBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type find_queries, size_type pattern_length, std::vector<vector_type>& queries)
{
  std::cout << "find() benchmarks:" << std::endl;

  queries = generateQueries(dynamic_index, find_queries, pattern_length);
  std::vector<SearchState> results(queries.size());

  size_type compressed_length = findBenchmark(compressed_index, queries, results);
  size_type dynamic_length = findBenchmark(dynamic_index, queries, results);

  if(compressed_length != dynamic_length)
  {
    std::cerr << "findBenchmark(): Total length mismatch: "
              << compressed_length << " (" << indexType(compressed_index) << "), "
              << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }

  std::cout << "Found " << results.size() << " ranges of total length " << compressed_length << std::endl;
  std::cout << std::endl;

  return results;
}

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

template<class GBWTType>
BidirectionalState
bidirectionalSearch(const GBWTType& index, const vector_type& query)
{
  if(query.empty()) { return BidirectionalState(); }

  size_type midpoint = query.size() / 2;
  BidirectionalState state = index.bdFind(query[midpoint]);
  for(size_type i = midpoint + 1; !(state.empty()) && i < query.size(); i++)
  {
    state = index.bdExtendForward(state, query[i]);
  }
  for(size_type i = midpoint; !(state.empty()) && i > 0; i--)
  {
    state = index.bdExtendBackward(state, query[i - 1]);
  }

  return state;
}

template<class GBWTType>
size_type
bidirectionalBenchmark(const GBWTType& index, const std::vector<vector_type>& queries)
{
  double start = readTimer();
  size_type total_length = 0, total_size = 0;
  for(size_type i = 0; i < queries.size(); i++)
  {
    BidirectionalState result = bidirectionalSearch(index, queries[i]);
    total_length += queries[i].size();
    total_size += result.size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), queries.size(), total_length, seconds);
  return total_size;
}

void
bidirectionalBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, const std::vector<vector_type>& queries)
{
  std::cout << "Bidirectional benchmarks:" << std::endl;

  size_type compressed_length = bidirectionalBenchmark(compressed_index, queries);
  size_type dynamic_length = bidirectionalBenchmark(dynamic_index, queries);

  if(compressed_length != dynamic_length)
  {
    std::cerr << "bidirectionalBenchmark(): Total length mismatch: "
              << compressed_length << " (" << indexType(compressed_index) << "), "
              << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }

  std::cout << "Found " << queries.size() << " ranges of total length " << compressed_length << std::endl;
  std::cout << std::endl;
}

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

template<class GBWTType>
void
locateBenchmark(const GBWTType& index, const std::vector<SearchState>& queries)
{
  std::cout << "locate() benchmarks (" << indexType(index) << "):" << std::endl;

  {
    double start = readTimer();
    size_type found = 0;
    for(SearchState query : queries)
    {
      if(query.empty()) { continue; }
      std::vector<size_type> result;
      for(size_type i = query.range.first; i <= query.range.second; i++)
      {
        result.push_back(index.locate(query.node, i));
      }
      removeDuplicates(result, false);
      found += result.size();
    }
    double seconds = readTimer() - start;
    printTime("Direct", found, seconds);
  }

  {
    double start = readTimer();
    size_type found = 0;
    for(SearchState query : queries)
    {
      std::vector<size_type> result = index.locate(query);
      found += result.size();
    }
    double seconds = readTimer() - start;
    printTime("Fast", found, seconds);
  }

  std::cout << std::endl;
}

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

template<class GBWTType>
size_type
extractBenchmark(const GBWTType& index, size_type extract_queries)
{
  double start = readTimer();
  std::mt19937_64 rng(RANDOM_SEED);
  size_type total_length = 0;
  for(size_type i = 0; i < extract_queries; i++)
  {
    vector_type sequence = index.extract(rng() % index.sequences());
    total_length += sequence.size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), extract_queries, total_length, seconds);
  return total_length;
}

void
extractBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type extract_queries)
{
  std::cout << "extract() benchmarks:" << std::endl;
  size_type compressed_length = extractBenchmark(compressed_index, extract_queries);
  size_type dynamic_length = extractBenchmark(dynamic_index, extract_queries);
  if(compressed_length != dynamic_length)
  {
    std::cerr << "extractBenchmark(): Total length " << compressed_length << " (" << indexType(compressed_index) << "), "
      << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }
  std::cout << std::endl;
}

//------------------------------------------------------------------------------
<commit_msg>Run/outdegree statistics<commit_after>/*
  Copyright (c) 2017, 2018 Jouni Siren

  Author: Jouni Siren <jouni.siren@iki.fi>

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

#include <random>
#include <map>
#include <string>
#include <unistd.h>

#include <gbwt/dynamic_gbwt.h>

using namespace gbwt;

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

const std::string tool_name = "GBWT benchmark";

const size_type RANDOM_SEED  = 0xDEADBEEF;

void printUsage(int exit_code = EXIT_SUCCESS);

void extendedStatistics(const DynamicGBWT& index);

std::vector<SearchState> findBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type find_queries, size_type pattern_length, std::vector<vector_type>& queries);

void bidirectionalBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, const std::vector<vector_type>& queries);

template<class GBWTType>
void locateBenchmark(const GBWTType& index, const std::vector<SearchState>& queries);

void extractBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type extract_queries);

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

int
main(int argc, char** argv)
{
  if(argc < 2) { printUsage(); }

  int c = 0;
  bool find = false, locate = false, extract = false, statistics = false;
  size_type find_queries = 0, pattern_length = 0, extract_queries = 0;
  while((c = getopt(argc, argv, "f:p:le:s")) != -1)
  {
    switch(c)
    {
    case 'f':
      find = true;
      find_queries = std::stoul(optarg); break;
    case 'p':
      pattern_length = std::stoul(optarg); break;
    case 'l':
      locate = true; break;
    case 'e':
      extract = true;
      extract_queries = std::stoul(optarg); break;
    case 's':
      statistics = true;
      break;
    case '?':
      std::exit(EXIT_FAILURE);
    default:
      std::exit(EXIT_FAILURE);
    }
  }

  if(optind >= argc) { printUsage(EXIT_FAILURE); }
  std::string index_base = argv[optind];
  if(find)
  {
    if(find_queries == 0 || pattern_length == 0)
    {
      std::cerr << "benchmark: Number of queries and pattern length must be non-zero" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  if(locate)
  {
    if(!find)
    {
      std::cerr << "benchmark: Cannot benchmark locate() queries without find() queries" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }
  if(extract)
  {
    if(extract_queries == 0)
    {
      std::cerr << "benchmark: Number of queries must be non-zero" << std::endl;
      std::exit(EXIT_FAILURE);
    }
  }

  Version::print(std::cout, tool_name);
  printHeader("Index name"); std::cout << index_base << std::endl;
  if(find || locate || extract)
  {
    printHeader("Queries");
    if(find) { std::cout << "find(" << find_queries << ", " << pattern_length << ") "; }
    if(locate) { std::cout << "locate() "; }
    if(extract) { std::cout << "extract(" << extract_queries << ") "; }
    std::cout << std::endl;
  }
  std::cout << std::endl;

  GBWT compressed_index;
  sdsl::load_from_file(compressed_index, index_base + GBWT::EXTENSION);
  printStatistics(compressed_index, index_base);
  if(!(find || locate || extract || statistics)) { return 0; }

  DynamicGBWT dynamic_index;
  sdsl::load_from_file(dynamic_index, index_base + DynamicGBWT::EXTENSION);
  printStatistics(dynamic_index, index_base);

  if(statistics) { extendedStatistics(dynamic_index); }
  if(!(find || locate || extract)) { return 0; }

  if(find)
  {
    std::vector<vector_type> queries;
    std::vector<SearchState> results = findBenchmark(compressed_index, dynamic_index, find_queries, pattern_length, queries);
    if(compressed_index.bidirectional())
    {
      bidirectionalBenchmark(compressed_index, dynamic_index, queries);
    }
    queries.clear();
    if(locate)
    {
      locateBenchmark(compressed_index, results);
      locateBenchmark(dynamic_index, results);
    }
  }
  if(extract)
  {
    extractBenchmark(compressed_index, dynamic_index, extract_queries);
  }

  return 0;
}

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

void
printUsage(int exit_code)
{
  Version::print(std::cerr, tool_name);

  std::cerr << "Usage: benchmark [options] index_base" << std::endl;
  std::cerr << "  -f N  Benchmark N find() queries (requires -p)" << std::endl;
  std::cerr << "  -p N  Use patterns of length N" << std::endl;
  std::cerr << "  -l    Benchmark locate() queries (requires -f)" << std::endl;
  std::cerr << "  -e N  Benchmark N extract() queries" << std::endl;
  std::cerr << "  -s    Print extended statistics" << std::endl;
  std::cerr << std::endl;

  std::exit(exit_code);
}

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

void
printStatistics(const std::string& header, const std::map<size_type, size_type>& distribution,
                size_type endmarker, size_type total, size_type n)
{
  std::cout << header << std::endl;
  printHeader("Total"); std::cout << total << std::endl;
  printHeader("Average"); std::cout << (total / static_cast<double>(n)) << std::endl;
  printHeader("Endmarker"); std::cout << endmarker << std::endl;

  double multiplier = 0.0;
  auto iter = distribution.begin();
  size_type records_seen = 0, value = 0;
  for(size_type nines = 1; nines <= 6; nines++)
  {
    multiplier = multiplier / 10.0 + 0.9;
    double limit = multiplier * n;
    while(iter != distribution.end() && static_cast<double>(records_seen) < limit)
    {
      value = iter->first;
      records_seen += iter->second;
      ++iter;
    }
    printHeader(std::to_string(multiplier)); std::cout << "at most " << value << std::endl;
  }

  std::cout << std::endl;
}

void
extendedStatistics(const DynamicGBWT& index)
{
  if(index.effective() < 2) { return; }

  std::map<size_type, size_type> run_distribution, outdegree_distribution;
  size_type endmarker_runs = 0, endmarker_outdegree = 0;
  size_type total_runs = 0, total_outdegree = 0;

  {
    const DynamicRecord& endmarker = index.record(ENDMARKER);
    endmarker_runs = endmarker.runs();
    endmarker_outdegree = endmarker.outdegree();
  }
  for(comp_type comp = 1; comp < index.effective(); comp++)
  {
    const DynamicRecord& record = index.record(index.toNode(comp));
    run_distribution[record.runs()]++;
    outdegree_distribution[record.outdegree()]++;
    total_runs += record.runs();
    total_outdegree += record.outdegree();
  }

  printStatistics("Runs", run_distribution, endmarker_runs, total_runs, index.effective() - 1);
  printStatistics("Outdegrees", outdegree_distribution, endmarker_outdegree, total_outdegree, index.effective() - 1);
}

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

std::vector<vector_type>
generateQueries(const DynamicGBWT& index, size_type find_queries, size_type pattern_length)
{
  std::mt19937_64 rng(RANDOM_SEED);
  std::vector<vector_type> result;

  size_type attempts = 0;
  while(result.size() < find_queries && attempts < 2 * find_queries)
  {
    vector_type sequence = index.extract(rng() % index.sequences());
    if(sequence.size() >= pattern_length)
    {
      size_type start_offset = rng() % (sequence.size() + 1 - pattern_length);
      result.push_back(vector_type(sequence.begin() + start_offset, sequence.begin() + start_offset + pattern_length));
    }
    attempts++;
  }

  std::cout << "Generated " << result.size() << " queries of total length " << (result.size() * pattern_length) << std::endl;
  return result;
}

std::string indexType(const GBWT&) { return "Compressed GBWT"; }
std::string indexType(const DynamicGBWT&) { return "Dynamic GBWT"; }

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

template<class GBWTType>
size_type
findBenchmark(const GBWTType& index, const std::vector<vector_type>& queries, std::vector<SearchState>& results)
{
  double start = readTimer();
  size_type total_length = 0, total_size = 0;
  for(size_type i = 0; i < queries.size(); i++)
  {
    results[i] = index.find(queries[i].begin(), queries[i].end());
    total_length += queries[i].size();
    total_size += results[i].size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), queries.size(), total_length, seconds);
  return total_size;
}

std::vector<SearchState>
findBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type find_queries, size_type pattern_length, std::vector<vector_type>& queries)
{
  std::cout << "find() benchmarks:" << std::endl;

  queries = generateQueries(dynamic_index, find_queries, pattern_length);
  std::vector<SearchState> results(queries.size());

  size_type compressed_length = findBenchmark(compressed_index, queries, results);
  size_type dynamic_length = findBenchmark(dynamic_index, queries, results);

  if(compressed_length != dynamic_length)
  {
    std::cerr << "findBenchmark(): Total length mismatch: "
              << compressed_length << " (" << indexType(compressed_index) << "), "
              << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }

  std::cout << "Found " << results.size() << " ranges of total length " << compressed_length << std::endl;
  std::cout << std::endl;

  return results;
}

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

template<class GBWTType>
BidirectionalState
bidirectionalSearch(const GBWTType& index, const vector_type& query)
{
  if(query.empty()) { return BidirectionalState(); }

  size_type midpoint = query.size() / 2;
  BidirectionalState state = index.bdFind(query[midpoint]);
  for(size_type i = midpoint + 1; !(state.empty()) && i < query.size(); i++)
  {
    state = index.bdExtendForward(state, query[i]);
  }
  for(size_type i = midpoint; !(state.empty()) && i > 0; i--)
  {
    state = index.bdExtendBackward(state, query[i - 1]);
  }

  return state;
}

template<class GBWTType>
size_type
bidirectionalBenchmark(const GBWTType& index, const std::vector<vector_type>& queries)
{
  double start = readTimer();
  size_type total_length = 0, total_size = 0;
  for(size_type i = 0; i < queries.size(); i++)
  {
    BidirectionalState result = bidirectionalSearch(index, queries[i]);
    total_length += queries[i].size();
    total_size += result.size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), queries.size(), total_length, seconds);
  return total_size;
}

void
bidirectionalBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, const std::vector<vector_type>& queries)
{
  std::cout << "Bidirectional benchmarks:" << std::endl;

  size_type compressed_length = bidirectionalBenchmark(compressed_index, queries);
  size_type dynamic_length = bidirectionalBenchmark(dynamic_index, queries);

  if(compressed_length != dynamic_length)
  {
    std::cerr << "bidirectionalBenchmark(): Total length mismatch: "
              << compressed_length << " (" << indexType(compressed_index) << "), "
              << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }

  std::cout << "Found " << queries.size() << " ranges of total length " << compressed_length << std::endl;
  std::cout << std::endl;
}

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

template<class GBWTType>
void
locateBenchmark(const GBWTType& index, const std::vector<SearchState>& queries)
{
  std::cout << "locate() benchmarks (" << indexType(index) << "):" << std::endl;

  {
    double start = readTimer();
    size_type found = 0;
    for(SearchState query : queries)
    {
      if(query.empty()) { continue; }
      std::vector<size_type> result;
      for(size_type i = query.range.first; i <= query.range.second; i++)
      {
        result.push_back(index.locate(query.node, i));
      }
      removeDuplicates(result, false);
      found += result.size();
    }
    double seconds = readTimer() - start;
    printTime("Direct", found, seconds);
  }

  {
    double start = readTimer();
    size_type found = 0;
    for(SearchState query : queries)
    {
      std::vector<size_type> result = index.locate(query);
      found += result.size();
    }
    double seconds = readTimer() - start;
    printTime("Fast", found, seconds);
  }

  std::cout << std::endl;
}

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

template<class GBWTType>
size_type
extractBenchmark(const GBWTType& index, size_type extract_queries)
{
  double start = readTimer();
  std::mt19937_64 rng(RANDOM_SEED);
  size_type total_length = 0;
  for(size_type i = 0; i < extract_queries; i++)
  {
    vector_type sequence = index.extract(rng() % index.sequences());
    total_length += sequence.size();
  }
  double seconds = readTimer() - start;
  printTimeLength(indexType(index), extract_queries, total_length, seconds);
  return total_length;
}

void
extractBenchmark(const GBWT& compressed_index, const DynamicGBWT& dynamic_index, size_type extract_queries)
{
  std::cout << "extract() benchmarks:" << std::endl;
  size_type compressed_length = extractBenchmark(compressed_index, extract_queries);
  size_type dynamic_length = extractBenchmark(dynamic_index, extract_queries);
  if(compressed_length != dynamic_length)
  {
    std::cerr << "extractBenchmark(): Total length " << compressed_length << " (" << indexType(compressed_index) << "), "
      << dynamic_length << " (" << indexType(dynamic_index) << ")" << std::endl;
  }
  std::cout << std::endl;
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*
 * test.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  test.cpp
 * @brief Contains various test routines to check if PrimeSieve
 *        produces correct results (single-threaded).
 */

#include "../soe/PrimeSieve.h"
#include "../soe/pmath.h"

#include <stdint.h>
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <exception>
#include <ctime>

namespace {
  uint64_t primeCounts[] = {
    4,         // pi(101)
    25,        // pi(10^2)
    168,       // pi(10^3)
    1229,      // pi(10^4)
    9592,      // pi(10^5)
    78498,     // pi(10^6)
    664579,    // pi(10^7)
    5761455,   // pi(10^8)
    50847534,  // pi(10^9)
    203280221, // pi(2^32)
    455052511, // pi(10^10)
    155428406, // prime count 2^32 interval starting at 10^12
    143482916, // prime count 2^32 interval starting at 10^13
    133235063, // prime count 2^32 interval starting at 10^14
    124350420, // prime count 2^32 interval starting at 10^15
    116578809, // prime count 2^32 interval starting at 10^16
    109726486, // prime count 2^32 interval starting at 10^17
    103626726, // prime count 2^32 interval starting at 10^18
    98169972}; // prime count 2^32 interval starting at 10^19

  /// Set to true if one or more tests failed
  bool isError = false;
}

/**
 * Evaluate a sieving test, sets isError to true if one or more tests
 * fail.
 */
void evaluateTest(bool isSuccess) {
  if (isSuccess)
    std::cout << "OK" << std::endl;
  else {
    std::cerr << "ERROR" << std::endl;
    isError  = true;
  }
}

/**
 * Sieve about 1000 small random intervals starting at 10^14 until an
 * overall interval of 2^32 has been completed and compare the
 * accumulated prime count result with the correct value from the
 * lookup table.
 */
void testRandomIntervals() {
  std::cout << "Sieve random intervals starting at 10^14" << std::endl;

  uint64_t lowerBound = ipow(10, 14);
  uint64_t upperBound = lowerBound + ipow(2, 32);
  uint64_t maxInterval = ipow(10, 7);
  uint64_t primeCount = 0;

  try {
    std::srand(static_cast<unsigned int> (std::time(0)));
    PrimeSieve primeSieve;
    primeSieve.setStartNumber(lowerBound - 1);
    primeSieve.setStopNumber(lowerBound - 1);
    primeSieve.setFlags(COUNT_PRIMES);

    while (primeSieve.getStopNumber() < upperBound) {
      // generate a rondom 64 bit integer
      uint64_t rand64 = 2 + std::rand();
      while (rand64 < UINT32_MAX)
        rand64 *= rand64;

      // generate a random interval >= 0 and < 10^7
      uint64_t interval = rand64 % maxInterval;
      // generate a random sieve size >= 1 and <= 128
      uint32_t sieveSize = 1 << static_cast<uint32_t> (rand64 % 8);

      // set up primeSieve for the next random interval
      primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
      primeSieve.setStopNumber(primeSieve.getStartNumber() + interval);
      primeSieve.setSieveSize(sieveSize);
      if (primeSieve.getStopNumber() > upperBound)
        primeSieve.setStopNumber(upperBound);

      // start sieving primes
      primeSieve.sieve();
      // sum the prime count results
      primeCount += primeSieve.getPrimeCount();
      std::cout << "\rRemaining chunk:           "
                << "\rRemaining chunk: " << upperBound - primeSieve.getStopNumber()
                << std::flush;
    }
    std::cout << std::endl;
    std::cout << "Prime count: " << std::setw(11) << primeCount;
    evaluateTest(primeCount == primeCounts[13]);
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Calculate the prime-counting function pi(x) for some popular values
 * of x and compare the results with the correct values from the
 * lookup table.
 */
void testPix() {
  std::cout << "Calculate the prime-counting function pi(x)" << std::endl;
  try {
    PrimeSieve primeSieve;
    primeSieve.setStartNumber(0);
    primeSieve.setStopNumber(0);
    primeSieve.setSieveSize(32);
    primeSieve.setFlags(COUNT_PRIMES);

    uint64_t primeCount = 0;

    // calculate pi(x) for 10^x with x := 1 to 9
    for (int i = 0; i < 9; i++) {
      primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
      primeSieve.setStopNumber(ipow(10, i + 1));
      primeSieve.sieve();
      primeCount += primeSieve.getPrimeCount();
      std::cout << "pi(10^" << i + 1 << ")  = " << std::setw(12) << primeCount;
      evaluateTest(primeCount == primeCounts[i]);
    }

    // calculate pi(2^32)
    primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
    primeSieve.setStopNumber(ipow(2, 32));
    primeSieve.sieve();
    primeCount += primeSieve.getPrimeCount();
    std::cout << "pi(2^32)  = " << std::setw(12) << primeCount;
    evaluateTest(primeCount == primeCounts[9]);

    // calculate pi(10^10)
    primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
    primeSieve.setStopNumber(ipow(10, 10));
    primeSieve.sieve();
    primeCount += primeSieve.getPrimeCount();
    std::cout << "pi(10^10) = " << std::setw(12) << primeCount;
    evaluateTest(primeCount == primeCounts[10]);
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Count the prime numbers within the 2^32 interval starting at 10^x
 * with x := 12 to 19 and compare the results with the correct values
 * from the lookup table.
 */
void testBigPrimes() {
  try {
    int flags = COUNT_PRIMES | PRINT_STATUS;
    PrimeSieve primeSieve;
    primeSieve.setSieveSize(512);
    primeSieve.setFlags(flags);

    for (int i = 0; i <= 7; i++) {
      primeSieve.setStartNumber(ipow(10, 12 + i));
      primeSieve.setStopNumber(primeSieve.getStartNumber() + ipow(2, 32));
      std::cout << "Sieve an interval of 2^32 starting at 10^" << 12 + i << std::endl;
      primeSieve.sieve();
      std::cout << "\rPrime count: " << std::setw(11) << primeSieve.getPrimeCount();
      evaluateTest(primeSieve.getPrimeCount() == primeCounts[11 + i]);
    }
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Run various sieving tests to check if PrimeSieve produces correct
 * results.
 *
 * The test may fail for one of the following reasons:
 *
 * 1. The source code has been modified and a new bug has been
 *    introduced somewhere.
 * 2. The compiler has produced an erroneous executable.
 * 3. The user's system is not stable, i.e. overclocked PC.
 */
void test() {
  std::cout.setf(std::ios::left);

  std::clock_t begin = std::clock();
  // perform random sieving test
  testRandomIntervals();
  std::cout << std::endl;
  // calculate some popular values of pi(x)
  testPix();
  std::cout << std::endl;
  // allocates up to 1 GB of memory
  testBigPrimes();
  std::clock_t stop = std::clock();
  std::cout << std::endl;

  std::cout << "Time elapsed: "
            << ((stop - begin) / static_cast<double> (CLOCKS_PER_SEC))
            << " sec" << std::endl;
  std::cout << ((!isError ) ?"All tests passed SUCCESSFULLY!"
                            :"One or more tests FAILED!")
            << std::endl;
}
<commit_msg>defined __STDC_LIMIT_MACROS before <stdint.h> to enable UINT32_MAX<commit_after>/*
 * test.cpp -- This file is part of primesieve
 *
 * Copyright (C) 2011 Kim Walisch, <kim.walisch@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 */

/**
 * @file  test.cpp
 * @brief Contains various test routines to check if PrimeSieve
 *        produces correct results (single-threaded).
 */

#include "../soe/PrimeSieve.h"
#include "../soe/pmath.h"

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <exception>
#include <ctime>

/**
 * @def __STDC_LIMIT_MACROS
 * Enable the UINT32_MAX macro from <stdint.h>.
 */
#if !defined(__STDC_LIMIT_MACROS)
#  define __STDC_LIMIT_MACROS 1
#endif
#include <stdint.h>

namespace {
  uint64_t primeCounts[] = {
    4,         // pi(101)
    25,        // pi(10^2)
    168,       // pi(10^3)
    1229,      // pi(10^4)
    9592,      // pi(10^5)
    78498,     // pi(10^6)
    664579,    // pi(10^7)
    5761455,   // pi(10^8)
    50847534,  // pi(10^9)
    203280221, // pi(2^32)
    455052511, // pi(10^10)
    155428406, // prime count 2^32 interval starting at 10^12
    143482916, // prime count 2^32 interval starting at 10^13
    133235063, // prime count 2^32 interval starting at 10^14
    124350420, // prime count 2^32 interval starting at 10^15
    116578809, // prime count 2^32 interval starting at 10^16
    109726486, // prime count 2^32 interval starting at 10^17
    103626726, // prime count 2^32 interval starting at 10^18
    98169972}; // prime count 2^32 interval starting at 10^19

  /// Set to true if one or more tests failed
  bool isError = false;
}

/**
 * Evaluate a sieving test, sets isError to true if one or more tests
 * fail.
 */
void evaluateTest(bool isSuccess) {
  if (isSuccess)
    std::cout << "OK" << std::endl;
  else {
    std::cerr << "ERROR" << std::endl;
    isError  = true;
  }
}

/**
 * Sieve about 1000 small random intervals starting at 10^14 until an
 * overall interval of 2^32 has been completed and compare the
 * accumulated prime count result with the correct value from the
 * lookup table.
 */
void testRandomIntervals() {
  std::cout << "Sieve random intervals starting at 10^14" << std::endl;

  uint64_t lowerBound = ipow(10, 14);
  uint64_t upperBound = lowerBound + ipow(2, 32);
  uint64_t maxInterval = ipow(10, 7);
  uint64_t primeCount = 0;

  try {
    std::srand(static_cast<unsigned int> (std::time(0)));
    PrimeSieve primeSieve;
    primeSieve.setStartNumber(lowerBound - 1);
    primeSieve.setStopNumber(lowerBound - 1);
    primeSieve.setFlags(COUNT_PRIMES);

    while (primeSieve.getStopNumber() < upperBound) {
      // generate a rondom 64 bit integer
      uint64_t rand64 = 2 + std::rand();
      while (rand64 < UINT32_MAX)
        rand64 *= rand64;

      // generate a random interval >= 0 and < 10^7
      uint64_t interval = rand64 % maxInterval;
      // generate a random sieve size >= 1 and <= 128
      uint32_t sieveSize = 1 << static_cast<uint32_t> (rand64 % 8);

      // set up primeSieve for the next random interval
      primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
      primeSieve.setStopNumber(primeSieve.getStartNumber() + interval);
      primeSieve.setSieveSize(sieveSize);
      if (primeSieve.getStopNumber() > upperBound)
        primeSieve.setStopNumber(upperBound);

      // start sieving primes
      primeSieve.sieve();
      // sum the prime count results
      primeCount += primeSieve.getPrimeCount();
      std::cout << "\rRemaining chunk:           "
                << "\rRemaining chunk: " << upperBound - primeSieve.getStopNumber()
                << std::flush;
    }
    std::cout << std::endl;
    std::cout << "Prime count: " << std::setw(11) << primeCount;
    evaluateTest(primeCount == primeCounts[13]);
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Calculate the prime-counting function pi(x) for some popular values
 * of x and compare the results with the correct values from the
 * lookup table.
 */
void testPix() {
  std::cout << "Calculate the prime-counting function pi(x)" << std::endl;
  try {
    PrimeSieve primeSieve;
    primeSieve.setStartNumber(0);
    primeSieve.setStopNumber(0);
    primeSieve.setSieveSize(32);
    primeSieve.setFlags(COUNT_PRIMES);

    uint64_t primeCount = 0;

    // calculate pi(x) for 10^x with x := 1 to 9
    for (int i = 0; i < 9; i++) {
      primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
      primeSieve.setStopNumber(ipow(10, i + 1));
      primeSieve.sieve();
      primeCount += primeSieve.getPrimeCount();
      std::cout << "pi(10^" << i + 1 << ")  = " << std::setw(12) << primeCount;
      evaluateTest(primeCount == primeCounts[i]);
    }

    // calculate pi(2^32)
    primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
    primeSieve.setStopNumber(ipow(2, 32));
    primeSieve.sieve();
    primeCount += primeSieve.getPrimeCount();
    std::cout << "pi(2^32)  = " << std::setw(12) << primeCount;
    evaluateTest(primeCount == primeCounts[9]);

    // calculate pi(10^10)
    primeSieve.setStartNumber(primeSieve.getStopNumber() + 1);
    primeSieve.setStopNumber(ipow(10, 10));
    primeSieve.sieve();
    primeCount += primeSieve.getPrimeCount();
    std::cout << "pi(10^10) = " << std::setw(12) << primeCount;
    evaluateTest(primeCount == primeCounts[10]);
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Count the prime numbers within the 2^32 interval starting at 10^x
 * with x := 12 to 19 and compare the results with the correct values
 * from the lookup table.
 */
void testBigPrimes() {
  try {
    int flags = COUNT_PRIMES | PRINT_STATUS;
    PrimeSieve primeSieve;
    primeSieve.setSieveSize(512);
    primeSieve.setFlags(flags);

    for (int i = 0; i <= 7; i++) {
      primeSieve.setStartNumber(ipow(10, 12 + i));
      primeSieve.setStopNumber(primeSieve.getStartNumber() + ipow(2, 32));
      std::cout << "Sieve an interval of 2^32 starting at 10^" << 12 + i << std::endl;
      primeSieve.sieve();
      std::cout << "\rPrime count: " << std::setw(11) << primeSieve.getPrimeCount();
      evaluateTest(primeSieve.getPrimeCount() == primeCounts[11 + i]);
    }
  }
  catch (std::exception& ex) {
    std::cerr << "Exception " << ex.what() << std::endl;
    std::exit(EXIT_FAILURE);
  }
}

/**
 * Run various sieving tests to check if PrimeSieve produces correct
 * results.
 *
 * The test may fail for one of the following reasons:
 *
 * 1. The source code has been modified and a new bug has been
 *    introduced somewhere.
 * 2. The compiler has produced an erroneous executable.
 * 3. The user's system is not stable, i.e. overclocked PC.
 */
void test() {
  std::cout.setf(std::ios::left);

  std::clock_t begin = std::clock();
  // perform random sieving test
  testRandomIntervals();
  std::cout << std::endl;
  // calculate some popular values of pi(x)
  testPix();
  std::cout << std::endl;
  // allocates up to 1 GB of memory
  testBigPrimes();
  std::clock_t stop = std::clock();
  std::cout << std::endl;

  std::cout << "Time elapsed: "
            << ((stop - begin) / static_cast<double> (CLOCKS_PER_SEC))
            << " sec" << std::endl;
  std::cout << ((!isError ) ?"All tests passed SUCCESSFULLY!"
                            :"One or more tests FAILED!")
            << std::endl;
}
<|endoftext|>


<commit_before>#include "video.h"

using func_p = void(*)();

//Labels to the arrays of constructors and destructors placed by the linker
extern "C" func_p start_ctors, end_ctors, start_dtors, end_dtors;

//Constructs all static objects
void static_construct()
{
    for(auto fp = &start_ctors; fp < &end_ctors; ++fp)
        (*fp)();
}

//Destructs all static objects
void static_destruct()
{
    for(auto fp = &start_dtors; fp < &end_dtors; ++fp)
        (*fp)();
}
<commit_msg>Remove unused include<commit_after>using func_p = void(*)();

//Labels to the arrays of constructors and destructors placed by the linker
extern "C" func_p start_ctors, end_ctors, start_dtors, end_dtors;

//Constructs all static objects
void static_construct()
{
    for(auto fp = &start_ctors; fp < &end_ctors; ++fp)
        (*fp)();
}

//Destructs all static objects
void static_destruct()
{
    for(auto fp = &start_dtors; fp < &end_dtors; ++fp)
        (*fp)();
}
<|endoftext|>