<commit_before>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/Autowired.h>
#include <autowiring/Bolt.h>
#include <autowiring/ContextCreator.h>
#include "TestFixtures/SimpleObject.hpp"
#include <string>
#include <iostream>

class BoltTest:
  public testing::Test
{};

struct Pipeline {};
struct OtherContext {};

class Listener:
  public Bolt<Pipeline>
{
public:
  Listener(void):
    hit(false)
  {}

  bool hit;

  std::shared_ptr<CoreContext> createdContext;

  void ContextCreated(void) override {
    hit = true;

    createdContext = CoreContext::CurrentContext();
  }
};

class Creator:
  public ContextCreator<Pipeline, std::string>
{
};

class InjectsIntoPipeline:
  public Bolt<Pipeline>
{
public:
  void ContextCreated(void) override {
    AutoRequired<SimpleObject>();
  }
};

class InjectsIntoBoth:
  public Bolt<Pipeline,OtherContext>
{
public:
  void ContextCreated(void) override {
    AutoRequired<SimpleObject>();
  }
};

struct CountObject:
  ContextMember
{
  CountObject():
    count(0)
  {}

  int count;
};

class InjectsIntoEverything:
  public Bolt<>
{
public:
  InjectsIntoEverything():
    count(0)
  {}

  void ContextCreated(void) override {
    AutoRequired<CountObject> derp;
    (derp->count)++;
  }

  int count;
};

TEST_F(BoltTest, VerifySimpleInjection) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoPipeline>();

  auto created = ctxt->Create<Pipeline>();

  // Verify that the SimpleObject didn't accidentally get injected out here:
  {
    Autowired<SimpleObject> so;
    EXPECT_FALSE(so.IsAutowired()) << "Object was injected into an outer scope by a bolt";
  }

  // Verify that the objecT DID get autowired where we expected it to be autowired
  CurrentContextPusher pshr(created);
  Autowired<SimpleObject> so;
  ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
}

TEST_F(BoltTest, VerifyMapping) {
  ContextCreator<Pipeline, std::wstring> simpleCreator;

  // Trivial context creation check:
  {
    auto ctxt = simpleCreator.CreateContext(L"Simple");
    ASSERT_TRUE(ctxt.second && ctxt.first.get()) << "Initial context creation did not succeed as expected";
  }

  // Now try to autowire a listener:
  AutoRequired<Listener> myListener;

  // Create a second context, verify that the listener got the message:
  std::shared_ptr<CoreContext> createdContext = simpleCreator.CreateContext(L"Simple2").first;

  // Verify we have a hit our bolt:
  EXPECT_TRUE(myListener->hit) << "The listener callback was not hit as expected";

  // Verify that the correct context was created:
  EXPECT_EQ(createdContext, myListener->createdContext) << "The context set to current for the listener callback was not the context that got created";
}

TEST_F(BoltTest, VerifyCreationBubbling) {
  // Leakage check:
  {
    Autowired<Listener> validation;
    ASSERT_FALSE(validation.IsAutowired());
  }

  // Put the listener in the parent context:
  AutoRequired<Listener> listener;

  // Create a child context of the current one, and put the creator in there:
  AutoCreateContext childContext;
  std::shared_ptr<ContextCreator<Pipeline, std::wstring>> simpleCreator = (
    CurrentContextPusher(childContext),
    AutoRequired<ContextCreator<Pipeline, std::wstring>>()
  );

  // Dependent context broadcast check:
  simpleCreator->CreateContext(L"Simple");

  // Check the listener to verify we had a hit:
  EXPECT_TRUE(listener->hit) << "The listener callback was not hit as expected";
}

TEST_F(BoltTest, VerifyMultipleInjection) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoBoth>();

  auto created = ctxt->Create<Pipeline>();
  auto created2 = ctxt->Create<OtherContext>();

  // Verify that the SimpleObject didn't accidentally get injected out here:
  {
    Autowired<SimpleObject> so;
    EXPECT_FALSE(so.IsAutowired()) << "Object was injected into an outer scope by a bolt";
  }

  // Verify that the objecT DID get autowired where we expected it to be autowired
  {
    CurrentContextPusher pshr(created);
    Autowired<SimpleObject> so;
    ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
  }
  {
    CurrentContextPusher pshr(created2);
    Autowired<SimpleObject> so;
    ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
  }
}

TEST_F(BoltTest, EmptyBolt) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoEverything>();
  Autowired<CountObject> so;
  EXPECT_FALSE(so.IsAutowired()) << "CountObject injected into outer context";

  AutoCreateContext created;
  {
    CurrentContextPusher pshr(created);
    Autowired<CountObject> innerSo;
    ASSERT_TRUE(innerSo.IsAutowired()) << "CountObject not injected into anonymous context";
    ASSERT_EQ(1, innerSo->count) << "ContextCreated() called incorrect number of times";
  }

  auto created2 = ctxt->Create<Pipeline>();
  {
    CurrentContextPusher pshr(created2);
    Autowired<CountObject> innerSo;
    ASSERT_TRUE(innerSo.IsAutowired()) << "CountObject not injected into named context";
    ASSERT_EQ(1, innerSo->count) << "ContextCreated() called incorrect number of times";
  }
}

class PipelineBoltable: public Boltable<Pipeline> {
  static int numCons;
  static int numDest;

public:
  static int ConstructedNum() {return numCons;}
  static int DestructedNum() {return numDest;}

  PipelineBoltable() {++numCons;}
  ~PipelineBoltable() {++numDest;}
};
int PipelineBoltable::numCons = 0;
int PipelineBoltable::numDest = 0;

TEST_F(BoltTest, BoltBeforeContext) {
  AutoCurrentContext ctxt;
  AutoEnable<PipelineBoltable>();
  ASSERT_EQ(0, PipelineBoltable::ConstructedNum()) << "Instantiated Boltable without context";
  auto otherCtx = ctxt->Create<OtherContext>();
  ASSERT_EQ(0, PipelineBoltable::ConstructedNum()) << "Instantiated on creation of unmatched context";

  {
    auto created = ctxt->Create<Pipeline>();
    ASSERT_EQ(1, PipelineBoltable::ConstructedNum()) << "Failed to instantiate on creation of matching context";
  }
  ASSERT_EQ(1, PipelineBoltable::DestructedNum()) << "Failed to be destroyed with matching context";
}

<commit_msg>Added failing unit test - requested feature would enable bootable if declared after the creation of a context.<commit_after>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include <autowiring/Autowired.h>
#include <autowiring/Bolt.h>
#include <autowiring/ContextCreator.h>
#include "TestFixtures/SimpleObject.hpp"
#include <string>
#include <iostream>

class BoltTest:
  public testing::Test
{};

struct Pipeline {};
struct OtherContext {};

class Listener:
  public Bolt<Pipeline>
{
public:
  Listener(void):
    hit(false)
  {}

  bool hit;

  std::shared_ptr<CoreContext> createdContext;

  void ContextCreated(void) override {
    hit = true;

    createdContext = CoreContext::CurrentContext();
  }
};

class Creator:
  public ContextCreator<Pipeline, std::string>
{
};

class InjectsIntoPipeline:
  public Bolt<Pipeline>
{
public:
  void ContextCreated(void) override {
    AutoRequired<SimpleObject>();
  }
};

class InjectsIntoBoth:
  public Bolt<Pipeline,OtherContext>
{
public:
  void ContextCreated(void) override {
    AutoRequired<SimpleObject>();
  }
};

struct CountObject:
  ContextMember
{
  CountObject():
    count(0)
  {}

  int count;
};

class InjectsIntoEverything:
  public Bolt<>
{
public:
  InjectsIntoEverything():
    count(0)
  {}

  void ContextCreated(void) override {
    AutoRequired<CountObject> derp;
    (derp->count)++;
  }

  int count;
};

TEST_F(BoltTest, VerifySimpleInjection) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoPipeline>();

  auto created = ctxt->Create<Pipeline>();

  // Verify that the SimpleObject didn't accidentally get injected out here:
  {
    Autowired<SimpleObject> so;
    EXPECT_FALSE(so.IsAutowired()) << "Object was injected into an outer scope by a bolt";
  }

  // Verify that the objecT DID get autowired where we expected it to be autowired
  CurrentContextPusher pshr(created);
  Autowired<SimpleObject> so;
  ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
}

TEST_F(BoltTest, VerifyMapping) {
  ContextCreator<Pipeline, std::wstring> simpleCreator;

  // Trivial context creation check:
  {
    auto ctxt = simpleCreator.CreateContext(L"Simple");
    ASSERT_TRUE(ctxt.second && ctxt.first.get()) << "Initial context creation did not succeed as expected";
  }

  // Now try to autowire a listener:
  AutoRequired<Listener> myListener;

  // Create a second context, verify that the listener got the message:
  std::shared_ptr<CoreContext> createdContext = simpleCreator.CreateContext(L"Simple2").first;

  // Verify we have a hit our bolt:
  EXPECT_TRUE(myListener->hit) << "The listener callback was not hit as expected";

  // Verify that the correct context was created:
  EXPECT_EQ(createdContext, myListener->createdContext) << "The context set to current for the listener callback was not the context that got created";
}

TEST_F(BoltTest, VerifyCreationBubbling) {
  // Leakage check:
  {
    Autowired<Listener> validation;
    ASSERT_FALSE(validation.IsAutowired());
  }

  // Put the listener in the parent context:
  AutoRequired<Listener> listener;

  // Create a child context of the current one, and put the creator in there:
  AutoCreateContext childContext;
  std::shared_ptr<ContextCreator<Pipeline, std::wstring>> simpleCreator = (
    CurrentContextPusher(childContext),
    AutoRequired<ContextCreator<Pipeline, std::wstring>>()
  );

  // Dependent context broadcast check:
  simpleCreator->CreateContext(L"Simple");

  // Check the listener to verify we had a hit:
  EXPECT_TRUE(listener->hit) << "The listener callback was not hit as expected";
}

TEST_F(BoltTest, VerifyMultipleInjection) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoBoth>();

  auto created = ctxt->Create<Pipeline>();
  auto created2 = ctxt->Create<OtherContext>();

  // Verify that the SimpleObject didn't accidentally get injected out here:
  {
    Autowired<SimpleObject> so;
    EXPECT_FALSE(so.IsAutowired()) << "Object was injected into an outer scope by a bolt";
  }

  // Verify that the objecT DID get autowired where we expected it to be autowired
  {
    CurrentContextPusher pshr(created);
    Autowired<SimpleObject> so;
    ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
  }
  {
    CurrentContextPusher pshr(created2);
    Autowired<SimpleObject> so;
    ASSERT_TRUE(so.IsAutowired()) << "Simple object was not injected as expected into a dependent context";
  }
}

TEST_F(BoltTest, EmptyBolt) {
  AutoCurrentContext ctxt;
  AutoEnable<InjectsIntoEverything>();
  Autowired<CountObject> so;
  EXPECT_FALSE(so.IsAutowired()) << "CountObject injected into outer context";

  AutoCreateContext created;
  {
    CurrentContextPusher pshr(created);
    Autowired<CountObject> innerSo;
    ASSERT_TRUE(innerSo.IsAutowired()) << "CountObject not injected into anonymous context";
    ASSERT_EQ(1, innerSo->count) << "ContextCreated() called incorrect number of times";
  }

  auto created2 = ctxt->Create<Pipeline>();
  {
    CurrentContextPusher pshr(created2);
    Autowired<CountObject> innerSo;
    ASSERT_TRUE(innerSo.IsAutowired()) << "CountObject not injected into named context";
    ASSERT_EQ(1, innerSo->count) << "ContextCreated() called incorrect number of times";
  }
}

template<class target>
class TargetBoltable: public Boltable<target> {
  static int numCons;
  static int numDest;

public:
  static void InitializeNum() {
    numCons = 0;
    numDest = 0;
  }
  static int ConstructedNum() {return numCons;}
  static int DestructedNum() {return numDest;}

  TargetBoltable() {++numCons;}
  ~TargetBoltable() {++numDest;}
};
template<class target>
int TargetBoltable<target>::numCons = 0;
template<class target>
int TargetBoltable<target>::numDest = 0;

TEST_F(BoltTest, BoltBeforeContext) {
  AutoCurrentContext ctxt;
  TargetBoltable<Pipeline>::InitializeNum();
  AutoEnable<TargetBoltable<Pipeline>>();
  ASSERT_EQ(0, TargetBoltable<Pipeline>::ConstructedNum()) << "Instantiated Boltable without context";
  auto otherCtx = ctxt->Create<OtherContext>();
  ASSERT_EQ(0, TargetBoltable<Pipeline>::ConstructedNum()) << "Instantiated on creation of unmatched context";

  {
    auto created = ctxt->Create<Pipeline>();
    ASSERT_EQ(1, TargetBoltable<Pipeline>::ConstructedNum()) << "Failed to instantiate on creation of matching context";
  }
  ASSERT_EQ(1, TargetBoltable<Pipeline>::DestructedNum()) << "Failed to be destroyed with matching context";
}

TEST_F(BoltTest, BoltAfterContext) {
  AutoCurrentContext ctxt;
  TargetBoltable<OtherContext>::InitializeNum();
  TargetBoltable<Pipeline>::InitializeNum();

  {
    auto created = ctxt->Create<Pipeline>();
    AutoEnable<TargetBoltable<OtherContext>>();
    ASSERT_EQ(0, TargetBoltable<OtherContext>::ConstructedNum()) << "Instantiated Boltable without context";
    AutoEnable<TargetBoltable<Pipeline>>();
    ASSERT_EQ(1, TargetBoltable<Pipeline>::ConstructedNum()) << "Failed to instantiate on creation of matching context";
  }
  ASSERT_EQ(1, TargetBoltable<Pipeline>::DestructedNum()) << "Failed to be destroyed with matching context";
}
<|endoftext|>


<commit_before>#include "Application.h"
#include "QuadTree.h"
#include ".\mmgr\mmgr.h"
#include "ModuleRenderer3D.h"
#include "ModuleScene.h"
#include "GameObject.h"
#include <vector>

//Node functions--------------------------------

QuadTreeNodeObj::~QuadTreeNodeObj()
{
	for (std::vector<QuadTreeNodeObj*>::iterator it = children.begin(); it != children.end(); ++it)
	{
		RELEASE(*it);
	}
	Clear();
}

void QuadTreeNodeObj::Insert(GameObject* game_object)
{
	game_objects.push_back(game_object);
}

void QuadTreeNodeObj::Remove()
{
	game_objects.clear();
}

void QuadTreeNodeObj::SetAABBToDraw()
{
	App->renderer3D->SetBoxToDraw(box);
	for (int i = 0; i < children.size(); ++i)
	{
		children[i]->SetAABBToDraw();
	}

}
void QuadTreeNodeObj::Partition()
{
	float3 center_point = { (box.minPoint.x + box.maxPoint.x) / 2,0,(box.minPoint.z + box.maxPoint.z) / 2 };
	float3 min_point1 = box.minPoint;
	float3 max_point1 = { center_point.x,box.maxPoint.y,center_point.z };
	float3 min_point2 = { center_point.x,box.minPoint.y,center_point.z };
	float3 max_point2 = box.maxPoint;
	float3 min_point3 = { center_point.x,box.minPoint.y,box.minPoint.z };
	float3 max_point3 = { box.maxPoint.x,box.maxPoint.y,center_point.z };
	float3 min_point4 = { box.minPoint.x,box.minPoint.y,center_point.z };
	float3 max_point4 = { center_point.x,box.maxPoint.y,box.maxPoint.z };
	QuadTreeNodeObj* child1 = new QuadTreeNodeObj(min_point1,max_point1);
	QuadTreeNodeObj* child2 = new QuadTreeNodeObj(min_point2, max_point2);
	QuadTreeNodeObj* child3 = new QuadTreeNodeObj(min_point3, max_point3);
	QuadTreeNodeObj* child4 = new QuadTreeNodeObj(min_point4, max_point4);
	if (child1->box.Size().x > minimum_aabb.Size().x)
	{
		children.push_back(child1);
		child1->Fill();
	}
	if (child2->box.Size().x > minimum_aabb.Size().x)
	{
		children.push_back(child2);
		child2->Fill();
	}
	if (child3->box.Size().x > minimum_aabb.Size().x)
	{
		children.push_back(child3);
		child3->Fill();
	}
	if (child4->box.Size().x > minimum_aabb.Size().x)
	{
		children.push_back(child4);
		child4->Fill();
	}
}

void QuadTreeNodeObj::Fill()
{
	std::vector<GameObject*> root_children = App->scene->root->GetChildrens();
	for (std::vector<GameObject*>::iterator it = root_children.begin(); it != root_children.end(); ++it)
	{
		if ((*it)->PutInQuadTree(this) == false)
		{
			if (this->box.Size().x > minimum_aabb.Size().x)
			{
				game_objects.clear();
				Partition();
				break;
			}
			else
				break;
		}
	}

}

void QuadTreeNodeObj::Clear()
{
	children.clear();
	game_objects.clear();
}

//QuadTree functions---------------------------------------
QuadTreeObj::QuadTreeObj()
{
	root.box.minPoint = float3(MIN_SCENE_POINT_X, MIN_SCENE_POINT_Y, MIN_SCENE_POINT_Z);
	root.box.maxPoint = float3(MAX_SCENE_POINT_X, MAX_SCENE_POINT_X, MAX_SCENE_POINT_X);
}
QuadTreeObj::~QuadTreeObj()
{
	for (std::vector<QuadTreeNodeObj*>::iterator it = root.children.begin(); it != root.children.end(); ++it)
	{
		RELEASE(*it);
	}
	root.Clear();
}

void QuadTreeObj::Calcutale()
{
	root.Fill();
}

void QuadTreeObj::DeleteAll()
{
	root.Clear();
}

<commit_msg>No more memory leaks at quadtree<commit_after>#include "Application.h"
#include "QuadTree.h"
#include ".\mmgr\mmgr.h"
#include "ModuleRenderer3D.h"
#include "ModuleScene.h"
#include "GameObject.h"
#include <vector>

//Node functions--------------------------------

QuadTreeNodeObj::~QuadTreeNodeObj()
{
	for (std::vector<QuadTreeNodeObj*>::iterator it = children.begin(); it != children.end(); ++it)
	{
		RELEASE(*it);
	}
	Clear();
}

void QuadTreeNodeObj::Insert(GameObject* game_object)
{
	game_objects.push_back(game_object);
}

void QuadTreeNodeObj::Remove()
{
	game_objects.clear();
}

void QuadTreeNodeObj::SetAABBToDraw()
{
	App->renderer3D->SetBoxToDraw(box);
	for (int i = 0; i < children.size(); ++i)
	{
		children[i]->SetAABBToDraw();
	}

}
void QuadTreeNodeObj::Partition()
{
	float3 center_point = { (box.minPoint.x + box.maxPoint.x) / 2,0,(box.minPoint.z + box.maxPoint.z) / 2 };
	float3 min_point1 = box.minPoint;
	float3 max_point1 = { center_point.x,box.maxPoint.y,center_point.z };
	float3 min_point2 = { center_point.x,box.minPoint.y,center_point.z };
	float3 max_point2 = box.maxPoint;
	float3 min_point3 = { center_point.x,box.minPoint.y,box.minPoint.z };
	float3 max_point3 = { box.maxPoint.x,box.maxPoint.y,center_point.z };
	float3 min_point4 = { box.minPoint.x,box.minPoint.y,center_point.z };
	float3 max_point4 = { center_point.x,box.maxPoint.y,box.maxPoint.z };
	QuadTreeNodeObj* child1 = new QuadTreeNodeObj(min_point1, max_point1);
	QuadTreeNodeObj* child2 = new QuadTreeNodeObj(min_point2, max_point2);
	QuadTreeNodeObj* child3 = new QuadTreeNodeObj(min_point3, max_point3);
	QuadTreeNodeObj* child4 = new QuadTreeNodeObj(min_point4, max_point4);

	children.push_back(child1);
	child1->Fill();
	children.push_back(child2);
	child2->Fill();
	children.push_back(child3);
	child3->Fill();
	children.push_back(child4);
	child4->Fill();
}

void QuadTreeNodeObj::Fill()
{
	std::vector<GameObject*> root_children = App->scene->root->GetChildrens();
	for (std::vector<GameObject*>::iterator it = root_children.begin(); it != root_children.end(); ++it)
	{
		if ((*it)->PutInQuadTree(this) == false)
		{
			if (this->box.Size().x > minimum_aabb.Size().x)
			{
				game_objects.clear();
				Partition();
				break;
			}
			else
				break;
		}
	}

}

void QuadTreeNodeObj::Clear()
{
	children.clear();
	game_objects.clear();
}

//QuadTree functions---------------------------------------
QuadTreeObj::QuadTreeObj()
{
	root.box.minPoint = float3(MIN_SCENE_POINT_X, MIN_SCENE_POINT_Y, MIN_SCENE_POINT_Z);
	root.box.maxPoint = float3(MAX_SCENE_POINT_X, MAX_SCENE_POINT_X, MAX_SCENE_POINT_X);
}
QuadTreeObj::~QuadTreeObj()
{
	for (std::vector<QuadTreeNodeObj*>::iterator it = root.children.begin(); it != root.children.end(); ++it)
	{
		RELEASE(*it);
	}
	root.Clear();
}

void QuadTreeObj::Calcutale()
{
	root.Fill();
}

void QuadTreeObj::DeleteAll()
{
	root.Clear();
}

<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_ROWS_DOT_SELF_HPP
#define STAN_MATH_PRIM_FUN_ROWS_DOT_SELF_HPP

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

namespace stan {
namespace math {

/**
 * Returns the dot product of each row of a matrix with itself.
 *
 * @tparam T type of the matrix (must be derived from \c
 * Eigen::MatrixBase)
 *
 * @param x matrix
 */
template <typename T, require_eigen_t<T>* = nullptr>
inline Eigen::Matrix<value_type_t<T>, T::RowsAtCompileTime, 1> rows_dot_self(
    const T& x) {
  return x.rowwise().squaredNorm();
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>fix template ambiguity<commit_after>#ifndef STAN_MATH_PRIM_FUN_ROWS_DOT_SELF_HPP
#define STAN_MATH_PRIM_FUN_ROWS_DOT_SELF_HPP

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

namespace stan {
namespace math {

/**
 * Returns the dot product of each row of a matrix with itself.
 *
 * @tparam T type of the matrix (must be derived from \c
 * Eigen::MatrixBase)
 *
 * @param x matrix
 */
template <typename T, require_eigen_t<T>* = nullptr,
          require_not_st_var<T>* = nullptr>
inline Eigen::Matrix<value_type_t<T>, T::RowsAtCompileTime, 1> rows_dot_self(
    const T& x) {
  return x.rowwise().squaredNorm();
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>/*
    Yojimbo Client/Server Network Library.

    Copyright © 2016, The Network Protocol Company, Inc.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

        1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

        2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
           in the documentation and/or other materials provided with the distribution.

        3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
           from this software without specific prior written permission.

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

#include "yojimbo_network.h"

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    #define NOMINMAX
    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <ws2ipdef.h>
    #pragma comment( lib, "WS2_32.lib" )

    #ifdef SetPort
    #undef SetPort
    #endif // #ifdef SetPort

    #if YOJIMBO_SOCKETS
    #include <iphlpapi.h>
    #pragma comment( lib, "IPHLPAPI.lib" )
    #endif // #if YOJIMBO_SOCKETS

#elif YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_MAC || YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_UNIX

    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <ifaddrs.h>
    #include <net/if.h>
    #include <fcntl.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <errno.h>

#endif

#include <memory.h>
#include <string.h>

namespace yojimbo
{
    static bool s_networkInitialized = false;

    bool InitializeNetwork()
    {
        assert( !s_networkInitialized );

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        WSADATA WsaData;
        const bool result = WSAStartup( MAKEWORD(2,2), &WsaData ) == NO_ERROR;
#else // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        const bool result = true;
#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

        if ( result )
            s_networkInitialized = result;

        return result;
    }

    void ShutdownNetwork()
    {
        assert( s_networkInitialized );

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        WSACleanup();
#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

        s_networkInitialized = false;
    }

    bool IsNetworkInitialized()
    {
        return s_networkInitialized;
    }

    bool FilterAddress( const Address & address, AddressFilter filter )
    {
        if ( !address.IsValid() )
            return false;

        if ( address.IsLoopback() )
            return false;

        if ( filter == ADDRESS_FILTER_IPV4_ONLY && address.GetType() != ADDRESS_IPV4 )
            return false;

        if ( filter == ADDRESS_FILTER_IPV6_ONLY && address.GetType() != ADDRESS_IPV6 )
            return false;

        if ( address.GetType() == ADDRESS_IPV6 && !address.IsGlobalUnicast() )
            return false;

        return true;
    }

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    #define WORKING_BUFFER_SIZE 15000
    #define MAX_TRIES 3

    void GetNetworkAddresses( Address * addresses, int & numAddresses, int maxAddresses, AddressFilter filter )
    {
        assert( addresses );
        assert( maxAddresses >= 0 );

        numAddresses = 0;

        DWORD dwRetVal = 0;

        ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;

        ULONG family = AF_UNSPEC;

        PIP_ADAPTER_ADDRESSES pAddresses = NULL;
        ULONG outBufLen = 0;
        ULONG iterations = 0;

        PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
        PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;

        outBufLen = WORKING_BUFFER_SIZE;

        do
        {
            pAddresses = (IP_ADAPTER_ADDRESSES*) malloc( outBufLen );
            if ( pAddresses == NULL )
                return;

            dwRetVal = GetAdaptersAddresses( family, flags, NULL, pAddresses, &outBufLen );

            if ( dwRetVal == ERROR_BUFFER_OVERFLOW )
            {
                free( pAddresses );
                pAddresses = NULL;
            }
            else
            {
                break;
            }

            iterations++;

        } while ( ( dwRetVal == ERROR_BUFFER_OVERFLOW ) && ( iterations < MAX_TRIES ) );

        if ( dwRetVal == NO_ERROR )
        {
            pCurrAddresses = pAddresses;

            for ( ; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next )
            {
                if ( pCurrAddresses->OperStatus != IfOperStatusUp )
                    continue;

                pUnicast = pCurrAddresses->FirstUnicastAddress;
                if ( pUnicast == NULL )
					continue;

                for ( ; pUnicast != NULL; pUnicast = pUnicast->Next )
                {
					if ( numAddresses >= maxAddresses )
						break;

                    Address address( (sockaddr_storage*) pUnicast->Address.lpSockaddr );

					if ( !FilterAddress( address, filter ) )
						continue;

                    addresses[numAddresses++] = address;
                }
            }
        }

        if ( pAddresses)
        {
            free( pAddresses );
        }
    }

#elif YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_MAC || YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_UNIX // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    void GetNetworkAddresses( Address * addresses, int & numAddresses, int maxAddresses, AddressFilter filter )
    {
        assert( addresses );
        assert( maxAddresses >= 0 );

        struct ifaddrs *ifaddr, *ifa;

        numAddresses = 0;

        if ( getifaddrs( &ifaddr ) == -1 )
            return;

        for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next )
        {
            if ( numAddresses >= maxAddresses )
                break;

            if ( ( ifa->ifa_flags & IFF_RUNNING ) == 0 )
                continue;

            if ( ifa->ifa_addr == NULL || ( ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6 ) )
                continue;

            Address address( (sockaddr_storage*) ifa->ifa_addr );

            if ( !FilterAddress( address, filter ) )
                continue;

            addresses[numAddresses++] = address;
        }

        freeifaddrs( ifaddr );
    }

#else // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    void GetNetworkAddresses( Address * /*addresses*/, int & numAddresses, int /*maxAddresses*/ )
    {
        numAddresses = 0;
    }

#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
}
<commit_msg>fucking tabs go away<commit_after>/*
    Yojimbo Client/Server Network Library.

    Copyright © 2016, The Network Protocol Company, Inc.

    Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

        1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

        2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
           in the documentation and/or other materials provided with the distribution.

        3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived
           from this software without specific prior written permission.

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

#include "yojimbo_network.h"

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    #define NOMINMAX
    #define _WINSOCK_DEPRECATED_NO_WARNINGS
    #include <winsock2.h>
    #include <ws2tcpip.h>
    #include <ws2ipdef.h>
    #pragma comment( lib, "WS2_32.lib" )

    #ifdef SetPort
    #undef SetPort
    #endif // #ifdef SetPort

    #if YOJIMBO_SOCKETS
    #include <iphlpapi.h>
    #pragma comment( lib, "IPHLPAPI.lib" )
    #endif // #if YOJIMBO_SOCKETS

#elif YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_MAC || YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_UNIX

    #include <netdb.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <ifaddrs.h>
    #include <net/if.h>
    #include <fcntl.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    #include <errno.h>

#endif

#include <memory.h>
#include <string.h>

namespace yojimbo
{
    static bool s_networkInitialized = false;

    bool InitializeNetwork()
    {
        assert( !s_networkInitialized );

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        WSADATA WsaData;
        const bool result = WSAStartup( MAKEWORD(2,2), &WsaData ) == NO_ERROR;
#else // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        const bool result = true;
#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

        if ( result )
            s_networkInitialized = result;

        return result;
    }

    void ShutdownNetwork()
    {
        assert( s_networkInitialized );

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
        WSACleanup();
#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

        s_networkInitialized = false;
    }

    bool IsNetworkInitialized()
    {
        return s_networkInitialized;
    }

    bool FilterAddress( const Address & address, AddressFilter filter )
    {
        if ( !address.IsValid() )
            return false;

        if ( address.IsLoopback() )
            return false;

        if ( filter == ADDRESS_FILTER_IPV4_ONLY && address.GetType() != ADDRESS_IPV4 )
            return false;

        if ( filter == ADDRESS_FILTER_IPV6_ONLY && address.GetType() != ADDRESS_IPV6 )
            return false;

        if ( address.GetType() == ADDRESS_IPV6 && !address.IsGlobalUnicast() )
            return false;

        return true;
    }

#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    #define WORKING_BUFFER_SIZE 15000
    #define MAX_TRIES 3

    void GetNetworkAddresses( Address * addresses, int & numAddresses, int maxAddresses, AddressFilter filter )
    {
        assert( addresses );
        assert( maxAddresses >= 0 );

        numAddresses = 0;

        DWORD dwRetVal = 0;

        ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;

        ULONG family = AF_UNSPEC;

        PIP_ADAPTER_ADDRESSES pAddresses = NULL;
        ULONG outBufLen = 0;
        ULONG iterations = 0;

        PIP_ADAPTER_ADDRESSES pCurrAddresses = NULL;
        PIP_ADAPTER_UNICAST_ADDRESS pUnicast = NULL;

        outBufLen = WORKING_BUFFER_SIZE;

        do
        {
            pAddresses = (IP_ADAPTER_ADDRESSES*) malloc( outBufLen );
            if ( pAddresses == NULL )
                return;

            dwRetVal = GetAdaptersAddresses( family, flags, NULL, pAddresses, &outBufLen );

            if ( dwRetVal == ERROR_BUFFER_OVERFLOW )
            {
                free( pAddresses );
                pAddresses = NULL;
            }
            else
            {
                break;
            }

            iterations++;

        } while ( ( dwRetVal == ERROR_BUFFER_OVERFLOW ) && ( iterations < MAX_TRIES ) );

        if ( dwRetVal == NO_ERROR )
        {
            pCurrAddresses = pAddresses;

            for ( ; pCurrAddresses; pCurrAddresses = pCurrAddresses->Next )
            {
                if ( pCurrAddresses->OperStatus != IfOperStatusUp )
                    continue;

                pUnicast = pCurrAddresses->FirstUnicastAddress;
                if ( pUnicast == NULL )
                    continue;

                for ( ; pUnicast != NULL; pUnicast = pUnicast->Next )
                {
                    if ( numAddresses >= maxAddresses )
                        break;

                    Address address( (sockaddr_storage*) pUnicast->Address.lpSockaddr );

                    if ( !FilterAddress( address, filter ) )
                        continue;

                    addresses[numAddresses++] = address;
                }
            }
        }

        if ( pAddresses)
        {
            free( pAddresses );
        }
    }

#elif YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_MAC || YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_UNIX // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    void GetNetworkAddresses( Address * addresses, int & numAddresses, int maxAddresses, AddressFilter filter )
    {
        assert( addresses );
        assert( maxAddresses >= 0 );

        struct ifaddrs *ifaddr, *ifa;

        numAddresses = 0;

        if ( getifaddrs( &ifaddr ) == -1 )
            return;

        for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next )
        {
            if ( numAddresses >= maxAddresses )
                break;

            if ( ( ifa->ifa_flags & IFF_RUNNING ) == 0 )
                continue;

            if ( ifa->ifa_addr == NULL || ( ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6 ) )
                continue;

            Address address( (sockaddr_storage*) ifa->ifa_addr );

            if ( !FilterAddress( address, filter ) )
                continue;

            addresses[numAddresses++] = address;
        }

        freeifaddrs( ifaddr );
    }

#else // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS

    void GetNetworkAddresses( Address * /*addresses*/, int & numAddresses, int /*maxAddresses*/ )
    {
        numAddresses = 0;
    }

#endif // #if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QElapsedTimer>
#include <QtNetwork/QTcpSocket>

#include "minihttpserver.h"
#include "../network-settings.h"

class tst_QTcpSocket_stresstest : public QObject
{
    Q_OBJECT
public:
    enum { AttemptCount = 100 };
    tst_QTcpSocket_stresstest();
    MiniHttpServer server;

public slots:
    void initTestCase_data();

private Q_SLOTS:
    void blockingConnectDisconnect();
    void blockingPipelined();
    void blockingMultipleRequests();
    void connectDisconnect();
    void parallelConnectDisconnect_data();
    void parallelConnectDisconnect();
};

tst_QTcpSocket_stresstest::tst_QTcpSocket_stresstest()
{
}

void tst_QTcpSocket_stresstest::initTestCase_data()
{
    QTest::addColumn<bool>("isLocalhost");
    QTest::addColumn<QString>("hostname");
    QTest::addColumn<int>("port");

    QTest::newRow("localhost") << false << "localhost" << server.port();
    QTest::newRow("remote") << true << QtNetworkSettings::serverName() << 80;
}

void tst_QTcpSocket_stresstest::blockingConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        while (socket.bytesToWrite())
            QVERIFY2(socket.waitForBytesWritten(), "Timeout");

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingPipelined()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 2; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 3; ++j) {
            qDebug("Attempt %d%c", i, 'a' + j);
            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: " + QByteArray(j == 2 ? "close" : "keep-alive") + "\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");
        }

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingMultipleRequests()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 5; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 5; ++j) {
            qDebug("Attempt %d", i * 5 + j);

            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: keep-alive\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");

            QElapsedTimer timeout;
            timeout.start();

            qint64 bytesRead = 0;
            qint64 bytesExpected = -1;
            QByteArray buffer;
            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
                socket.waitForReadyRead();
                buffer += socket.readAll();
                int pos = buffer.indexOf("\r\n\r\n");
                if (pos == -1)
                    continue;

                bytesRead = buffer.length() - pos - 1;

                buffer.truncate(pos);
                buffer = buffer.toLower();
                pos = buffer.indexOf("\r\ncontent-length: ");
                if (pos == -1)
                    break;
                pos += strlen("\r\ncontent-length: ");

                int eol = buffer.indexOf("\r\n", pos + 2);
                if (eol == -1)
                    break;

                bytesExpected = buffer.mid(pos, eol - pos).toLongLong();
                break;
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");

            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000) && bytesExpected > bytesRead) {
                socket.waitForReadyRead();
                bytesRead += socket.read(bytesExpected - bytesRead).length(); // discard
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");
        }

        socket.disconnectFromHost();
        QVERIFY(socket.state() == QAbstractSocket::UnconnectedState);
    }
}

void tst_QTcpSocket_stresstest::connectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");

        QTestEventLoop::instance().connect(&socket, SIGNAL(disconnected()), SLOT(exitLoop()));
        QTestEventLoop::instance().enterLoop(30);
        QVERIFY2(!QTestEventLoop::instance().timeout(), "Timeout");
    }
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect_data()
{
    QTest::addColumn<int>("parallelAttempts");
    QTest::newRow("1") << 1;
    QTest::newRow("2") << 2;
    QTest::newRow("4") << 4;
    QTest::newRow("5") << 5;
    QTest::newRow("10") << 10;
    QTest::newRow("25") << 25;
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);
    QFETCH(int, parallelAttempts);

    for (int i = 0; i < AttemptCount/qMax(2, parallelAttempts/4); ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket *socket = new QTcpSocket[parallelAttempts];
        for (int j = 0; j < parallelAttempts; ++j) {
            socket[j].connectToHost(hostname, port);

            socket[j].write("GET /qtest/bigfile HTTP/1.1\r\n"
                            "Connection: close\r\n"
                            "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                            "Host: " + hostname.toLatin1() + "\r\n"
                            "\r\n");

            QTestEventLoop::instance().connect(&socket[j], SIGNAL(disconnected()), SLOT(exitLoop()));
        }

        QElapsedTimer timeout;
        timeout.start();
        while (!timeout.hasExpired(10000)) {
            QTestEventLoop::instance().enterLoop(10);
            int done = 0;
            for (int j = 0; j < parallelAttempts; ++j)
                done += socket[j].state() == QAbstractSocket::UnconnectedState ? 1 : 0;
            if (done == parallelAttempts)
                break;
        }
        delete[] socket;
        QVERIFY2(!timeout.hasExpired(10000), "Timeout");
    }
}

QTEST_MAIN(tst_QTcpSocket_stresstest);

#include "tst_qtcpsocket_stresstest.moc"
<commit_msg>Make sure we read the data, to avoid keeping it all on RAM<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
#include <QtCore/QElapsedTimer>
#include <QtNetwork/QTcpSocket>

#include "minihttpserver.h"
#include "../network-settings.h"

class tst_QTcpSocket_stresstest : public QObject
{
    Q_OBJECT
public:
    enum { AttemptCount = 100 };
    tst_QTcpSocket_stresstest();
    MiniHttpServer server;

public slots:
    void initTestCase_data();

    void slotReadAll() { static_cast<QTcpSocket *>(sender())->readAll(); }

private Q_SLOTS:
    void blockingConnectDisconnect();
    void blockingPipelined();
    void blockingMultipleRequests();
    void connectDisconnect();
    void parallelConnectDisconnect_data();
    void parallelConnectDisconnect();
};

tst_QTcpSocket_stresstest::tst_QTcpSocket_stresstest()
{
}

void tst_QTcpSocket_stresstest::initTestCase_data()
{
    QTest::addColumn<bool>("isLocalhost");
    QTest::addColumn<QString>("hostname");
    QTest::addColumn<int>("port");

    QTest::newRow("localhost") << false << "localhost" << server.port();
    QTest::newRow("remote") << true << QtNetworkSettings::serverName() << 80;
}

void tst_QTcpSocket_stresstest::blockingConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        while (socket.bytesToWrite())
            QVERIFY2(socket.waitForBytesWritten(), "Timeout");

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingPipelined()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 2; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 3; ++j) {
            qDebug("Attempt %d%c", i, 'a' + j);
            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: " + QByteArray(j == 2 ? "close" : "keep-alive") + "\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");
        }

        QElapsedTimer timeout;
        timeout.start();
        while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
            socket.waitForReadyRead();
            socket.readAll(); // discard
        }
    }
}

void tst_QTcpSocket_stresstest::blockingMultipleRequests()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount / 5; ++i) {
        QTcpSocket socket;
        socket.connectToHost(hostname, port);
        QVERIFY2(socket.waitForConnected(), "Timeout");

        for (int j = 0 ; j < 5; ++j) {
            qDebug("Attempt %d", i * 5 + j);

            socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                         "Connection: keep-alive\r\n"
                         "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                         "Host: " + hostname.toLatin1() + "\r\n"
                         "\r\n");
            while (socket.bytesToWrite())
                QVERIFY2(socket.waitForBytesWritten(), "Timeout");

            QElapsedTimer timeout;
            timeout.start();

            qint64 bytesRead = 0;
            qint64 bytesExpected = -1;
            QByteArray buffer;
            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000)) {
                socket.waitForReadyRead();
                buffer += socket.readAll();
                int pos = buffer.indexOf("\r\n\r\n");
                if (pos == -1)
                    continue;

                bytesRead = buffer.length() - pos - 1;

                buffer.truncate(pos);
                buffer = buffer.toLower();
                pos = buffer.indexOf("\r\ncontent-length: ");
                if (pos == -1)
                    break;
                pos += strlen("\r\ncontent-length: ");

                int eol = buffer.indexOf("\r\n", pos + 2);
                if (eol == -1)
                    break;

                bytesExpected = buffer.mid(pos, eol - pos).toLongLong();
                break;
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");

            while (socket.state() == QAbstractSocket::ConnectedState && !timeout.hasExpired(10000) && bytesExpected > bytesRead) {
                socket.waitForReadyRead();
                bytesRead += socket.read(bytesExpected - bytesRead).length(); // discard
            }
            QVERIFY2(!timeout.hasExpired(10000), "Timeout");
        }

        socket.disconnectFromHost();
        QVERIFY(socket.state() == QAbstractSocket::UnconnectedState);
    }
}

void tst_QTcpSocket_stresstest::connectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);

    for (int i = 0; i < AttemptCount; ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket socket;
        socket.connectToHost(hostname, port);

        socket.write("GET /qtest/bigfile HTTP/1.1\r\n"
                     "Connection: close\r\n"
                     "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                     "Host: " + hostname.toLatin1() + "\r\n"
                     "\r\n");
        connect(&socket, SIGNAL(readyRead()), SLOT(slotReadAll()));

        QTestEventLoop::instance().connect(&socket, SIGNAL(disconnected()), SLOT(exitLoop()));
        QTestEventLoop::instance().enterLoop(30);
        QVERIFY2(!QTestEventLoop::instance().timeout(), "Timeout");
    }
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect_data()
{
    QTest::addColumn<int>("parallelAttempts");
    QTest::newRow("1") << 1;
    QTest::newRow("2") << 2;
    QTest::newRow("4") << 4;
    QTest::newRow("5") << 5;
    QTest::newRow("10") << 10;
    QTest::newRow("25") << 25;
    QTest::newRow("100") << 100;
}

void tst_QTcpSocket_stresstest::parallelConnectDisconnect()
{
    QFETCH_GLOBAL(QString, hostname);
    QFETCH_GLOBAL(int, port);
    QFETCH(int, parallelAttempts);

    for (int i = 0; i < AttemptCount/qMax(2, parallelAttempts/4); ++i) {
        qDebug("Attempt %d", i);
        QTcpSocket *socket = new QTcpSocket[parallelAttempts];
        for (int j = 0; j < parallelAttempts; ++j) {
            socket[j].connectToHost(hostname, port);

            socket[j].write("GET /qtest/bigfile HTTP/1.1\r\n"
                            "Connection: close\r\n"
                            "User-Agent: tst_QTcpSocket_stresstest/1.0\r\n"
                            "Host: " + hostname.toLatin1() + "\r\n"
                            "\r\n");
            connect(&socket[j], SIGNAL(readyRead()), SLOT(slotReadAll()));

            QTestEventLoop::instance().connect(&socket[j], SIGNAL(disconnected()), SLOT(exitLoop()));
        }

        QElapsedTimer timeout;
        timeout.start();
        while (!timeout.hasExpired(30000)) {
            QTestEventLoop::instance().enterLoop(10);
            int done = 0;
            for (int j = 0; j < parallelAttempts; ++j)
                done += socket[j].state() == QAbstractSocket::UnconnectedState ? 1 : 0;
            if (done == parallelAttempts)
                break;
        }
        delete[] socket;
        QVERIFY2(!timeout.hasExpired(30000), "Timeout");
        //qDebug() << "Run-time was" << timeout.elapsed();
    }
}

QTEST_MAIN(tst_QTcpSocket_stresstest);

#include "tst_qtcpsocket_stresstest.moc"
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkGraphTransferDataToTree.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/
#include "vtkGraphTransferDataToTree.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkEdgeListIterator.h"
#include "vtkFloatArray.h"
#include "vtkGraph.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSmartPointer.h"
#include "vtkStdString.h"
#include "vtkTree.h"
#include "vtkVariantArray.h"
#include "vtkIntArray.h"

#include <vtksys/stl/map>
using vtksys_stl::map;

//---------------------------------------------------------------------------
template <typename T>
vtkVariant vtkGetValue(T* arr, vtkIdType index)
{
  return vtkVariant(arr[index]);
}

//---------------------------------------------------------------------------
static vtkVariant vtkGetVariantValue(vtkAbstractArray* arr, vtkIdType i)
{
  vtkVariant val;
  switch(arr->GetDataType())
    {
    vtkExtraExtendedTemplateMacro(val = vtkGetValue(
      static_cast<VTK_TT*>(arr->GetVoidPointer(0)), i));
    }
  return val;
}

vtkCxxRevisionMacro(vtkGraphTransferDataToTree, "1.2");
vtkStandardNewMacro(vtkGraphTransferDataToTree);

vtkGraphTransferDataToTree::vtkGraphTransferDataToTree()
{
  this->SetNumberOfInputPorts(2);
  this->DirectMapping = false;
  this->DefaultValue = 1;
  this->SourceArrayName = 0;
  this->TargetArrayName = 0;
}

vtkGraphTransferDataToTree::~vtkGraphTransferDataToTree()
{
  this->SetSourceArrayName(0);
  this->SetTargetArrayName(0);
}

int vtkGraphTransferDataToTree::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    return 1;
    }
  return 0;
}

int vtkGraphTransferDataToTree::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *graphInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *treeInfo = inputVector[1]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkGraph *graph = vtkGraph::SafeDownCast(
    graphInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkTree *tree = vtkTree::SafeDownCast(
    treeInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkTree *output = vtkTree::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

    // Copy the input into the output
  output->ShallowCopy(tree);

  // If graph or tree is empty, we're done.
  if (graph->GetNumberOfVertices() == 0 ||
      tree->GetNumberOfVertices() == 0)
    {
    return 1;
    }

  if( this->SourceArrayName == 0 || this->TargetArrayName == 0 )
  {
    vtkErrorMacro( "Must specify source and target array names for the transfer." );
    return 0;
  }

  // Create a map from graph indices to tree indices
  // If we are using DirectMapping this is trivial
  // we just create an identity map
  map<vtkIdType, vtkIdType> graphIndexToTreeIndex;
  if (this->DirectMapping)
    {
    if (graph->GetNumberOfVertices() > tree->GetNumberOfVertices())
      {
      vtkErrorMacro("Cannot have more graph vertices than tree vertices using direct mapping.");
      return 0;
      }
    // Create identity map.
    for (vtkIdType gv = 0; gv < graph->GetNumberOfVertices(); gv++)
      {
      graphIndexToTreeIndex[gv] = gv;
      }
    }

  // Okay if we do not have direct mapping then we need
  // to do some templated madness to go from an arbitrary
  // type to a nice vtkIdType to vtkIdType mapping
  if (!this->DirectMapping)
    {
    // Check for valid pedigree id arrays.
    vtkAbstractArray* graphIdArray =
      graph->GetVertexData()->GetPedigreeIds();
    if (!graphIdArray)
      {
      vtkErrorMacro("Graph pedigree id array not found.");
      return 0;
      }
    vtkAbstractArray* treeIdArray =
      tree->GetVertexData()->GetPedigreeIds();
    if (!treeIdArray)
      {
      vtkErrorMacro("Tree pedigree id array not found.");
      return 0;
      }

    map<vtkVariant,vtkIdType,vtkVariantLessThan> graphIdMap;

    // Create a map from graph id to graph index
    for (int i=0; i<graph->GetNumberOfVertices(); ++i)
      {
      graphIdMap[vtkGetVariantValue(graphIdArray,i)] = i;
      }

    // Now create the map from graph index to tree index
    for (int i=0; i<tree->GetNumberOfVertices(); ++i)
      {
      vtkVariant id = vtkGetVariantValue(treeIdArray,i);
      if (graphIdMap.count(id))
        {
        graphIndexToTreeIndex[graphIdMap[id]] = i;
        }
      }
    }

  int i;
  vtkAbstractArray *sourceArray = graph->GetVertexData()->GetAbstractArray( this->SourceArrayName );
  vtkAbstractArray *targetArray = vtkAbstractArray::CreateArray(sourceArray->GetDataType());
  targetArray->SetName( this->TargetArrayName );

  targetArray->SetNumberOfComponents(sourceArray->GetNumberOfComponents());
  targetArray->SetNumberOfTuples(output->GetNumberOfVertices());

  for( i = 0; i < output->GetNumberOfVertices(); i++)
  {
    targetArray->InsertVariantValue(i, this->DefaultValue);
  }

  for( i = 0; i < graph->GetNumberOfVertices(); i++)
  {
    targetArray->SetTuple(graphIndexToTreeIndex[i], i, sourceArray);
  }

  output->GetVertexData()->AddArray(targetArray);
  targetArray->Delete();

  return 1;
}

vtkVariant vtkGraphTransferDataToTree::GetDefaultValue()
{
  return this->DefaultValue;
}

void vtkGraphTransferDataToTree::SetDefaultValue(vtkVariant value)
{
  this->DefaultValue = value;
}

void vtkGraphTransferDataToTree::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "DirectMapping: " << this->DirectMapping << endl;
//  os << indent << "DefaultValue: " << this->DefaultValue.ToString() << endl;
  os << indent << "SourceArrayName: " << this->SourceArrayName << endl;
  os << indent << "TargetArrayName: " << this->TargetArrayName << endl;
}

<commit_msg>BUG: One more try on fixing the otherPrint test for win32-vs60<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkGraphTransferDataToTree.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/
#include "vtkGraphTransferDataToTree.h"

#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkEdgeListIterator.h"
#include "vtkFloatArray.h"
#include "vtkGraph.h"
#include "vtkIdTypeArray.h"
#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkSmartPointer.h"
#include "vtkStdString.h"
#include "vtkTree.h"
#include "vtkVariantArray.h"
#include "vtkIntArray.h"

#include <vtksys/stl/map>
using vtksys_stl::map;

//---------------------------------------------------------------------------
template <typename T>
vtkVariant vtkGetValue(T* arr, vtkIdType index)
{
  return vtkVariant(arr[index]);
}

//---------------------------------------------------------------------------
static vtkVariant vtkGetVariantValue(vtkAbstractArray* arr, vtkIdType i)
{
  vtkVariant val;
  switch(arr->GetDataType())
    {
    vtkExtraExtendedTemplateMacro(val = vtkGetValue(
      static_cast<VTK_TT*>(arr->GetVoidPointer(0)), i));
    }
  return val;
}

vtkCxxRevisionMacro(vtkGraphTransferDataToTree, "1.3");
vtkStandardNewMacro(vtkGraphTransferDataToTree);

vtkGraphTransferDataToTree::vtkGraphTransferDataToTree()
{
  this->SetNumberOfInputPorts(2);
  this->DirectMapping = false;
  this->DefaultValue = 1;
  this->SourceArrayName = 0;
  this->TargetArrayName = 0;
}

vtkGraphTransferDataToTree::~vtkGraphTransferDataToTree()
{
  this->SetSourceArrayName(0);
  this->SetTargetArrayName(0);
}

int vtkGraphTransferDataToTree::FillInputPortInformation(int port, vtkInformation* info)
{
  if (port == 0)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph");
    return 1;
    }
  else if (port == 1)
    {
    info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTree");
    return 1;
    }
  return 0;
}

int vtkGraphTransferDataToTree::RequestData(
  vtkInformation *vtkNotUsed(request),
  vtkInformationVector **inputVector,
  vtkInformationVector *outputVector)
{
  // get the info objects
  vtkInformation *graphInfo = inputVector[0]->GetInformationObject(0);
  vtkInformation *treeInfo = inputVector[1]->GetInformationObject(0);
  vtkInformation *outInfo = outputVector->GetInformationObject(0);

  // get the input and ouptut
  vtkGraph *graph = vtkGraph::SafeDownCast(
    graphInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkTree *tree = vtkTree::SafeDownCast(
    treeInfo->Get(vtkDataObject::DATA_OBJECT()));
  vtkTree *output = vtkTree::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

    // Copy the input into the output
  output->ShallowCopy(tree);

  // If graph or tree is empty, we're done.
  if (graph->GetNumberOfVertices() == 0 ||
      tree->GetNumberOfVertices() == 0)
    {
    return 1;
    }

  if( this->SourceArrayName == 0 || this->TargetArrayName == 0 )
  {
    vtkErrorMacro( "Must specify source and target array names for the transfer." );
    return 0;
  }

  // Create a map from graph indices to tree indices
  // If we are using DirectMapping this is trivial
  // we just create an identity map
  map<vtkIdType, vtkIdType> graphIndexToTreeIndex;
  if (this->DirectMapping)
    {
    if (graph->GetNumberOfVertices() > tree->GetNumberOfVertices())
      {
      vtkErrorMacro("Cannot have more graph vertices than tree vertices using direct mapping.");
      return 0;
      }
    // Create identity map.
    for (vtkIdType gv = 0; gv < graph->GetNumberOfVertices(); gv++)
      {
      graphIndexToTreeIndex[gv] = gv;
      }
    }

  // Okay if we do not have direct mapping then we need
  // to do some templated madness to go from an arbitrary
  // type to a nice vtkIdType to vtkIdType mapping
  if (!this->DirectMapping)
    {
    // Check for valid pedigree id arrays.
    vtkAbstractArray* graphIdArray =
      graph->GetVertexData()->GetPedigreeIds();
    if (!graphIdArray)
      {
      vtkErrorMacro("Graph pedigree id array not found.");
      return 0;
      }
    vtkAbstractArray* treeIdArray =
      tree->GetVertexData()->GetPedigreeIds();
    if (!treeIdArray)
      {
      vtkErrorMacro("Tree pedigree id array not found.");
      return 0;
      }

    map<vtkVariant,vtkIdType,vtkVariantLessThan> graphIdMap;

    // Create a map from graph id to graph index
    for (int i=0; i<graph->GetNumberOfVertices(); ++i)
      {
      graphIdMap[vtkGetVariantValue(graphIdArray,i)] = i;
      }

    // Now create the map from graph index to tree index
    for (int i=0; i<tree->GetNumberOfVertices(); ++i)
      {
      vtkVariant id = vtkGetVariantValue(treeIdArray,i);
      if (graphIdMap.count(id))
        {
        graphIndexToTreeIndex[graphIdMap[id]] = i;
        }
      }
    }

  int i;
  vtkAbstractArray *sourceArray = graph->GetVertexData()->GetAbstractArray( this->SourceArrayName );
  vtkAbstractArray *targetArray = vtkAbstractArray::CreateArray(sourceArray->GetDataType());
  targetArray->SetName( this->TargetArrayName );

  targetArray->SetNumberOfComponents(sourceArray->GetNumberOfComponents());
  targetArray->SetNumberOfTuples(output->GetNumberOfVertices());

  for( i = 0; i < output->GetNumberOfVertices(); i++)
  {
    targetArray->InsertVariantValue(i, this->DefaultValue);
  }

  for( i = 0; i < graph->GetNumberOfVertices(); i++)
  {
    targetArray->SetTuple(graphIndexToTreeIndex[i], i, sourceArray);
  }

  output->GetVertexData()->AddArray(targetArray);
  targetArray->Delete();

  return 1;
}

vtkVariant vtkGraphTransferDataToTree::GetDefaultValue()
{
  return this->DefaultValue;
}

void vtkGraphTransferDataToTree::SetDefaultValue(vtkVariant value)
{
  this->DefaultValue = value;
}

void vtkGraphTransferDataToTree::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "DirectMapping: " << this->DirectMapping << endl;
  os << indent << "DefaultValue: " << this->DefaultValue.ToString() << endl;
  os << indent << "SourceArrayName: " << (this->SourceArrayName ? this->SourceArrayName : "(none)") << endl;
  os << indent << "TargetArrayName: " << (this->TargetArrayName ? this->TargetArrayName : "(none)") << endl;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2008 Stephen Liu
 * For license terms, see the file COPYING along with this library.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>

#include "spporting.hpp"
#include "spthread.hpp"

#include "spiocpdispatcher.hpp"

#include "spwin32iocp.hpp"
#include "sphandler.hpp"
#include "spsession.hpp"
#include "spexecutor.hpp"
#include "sputils.hpp"
#include "spioutils.hpp"
#include "spiochannel.hpp"

#include "spiocpevent.hpp"

SP_IocpDispatcher :: SP_IocpDispatcher( SP_CompletionHandler * completionHandler, int maxThreads )
{
#ifdef SIGPIPE
	/* Don't die with SIGPIPE on remote read shutdown. That's dumb. */
	signal( SIGPIPE, SIG_IGN );
#endif

	mIsShutdown = 0;
	mIsRunning = 0;

	mEventArg = new SP_IocpEventArg( 600 );
	SP_IocpMsgQueue * msgQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(),
			SP_IocpEventCallback::eKeyMsgQueue, SP_IocpEventCallback::onResponse, mEventArg );
	mEventArg->setResponseQueue( msgQueue );
	// load DisconnectEx
	{
		int fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED );
		mEventArg->loadDisconnectEx( fd );
		closesocket( fd );
	}

	mMaxThreads = maxThreads > 0 ? maxThreads : 4;

	mCompletionHandler = completionHandler;

	mPushQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(),
			SP_IocpEventCallback::eKeyMsgQueue, onPush, mEventArg );
}

SP_IocpDispatcher :: ~SP_IocpDispatcher()
{
	if( 0 == mIsRunning ) sleep( 1 );

	shutdown();

	for( ; mIsRunning; ) sleep( 1 );

	delete mPushQueue;
	mPushQueue = NULL;

	delete mEventArg;
	mEventArg = NULL;
}

void SP_IocpDispatcher :: setTimeout( int timeout )
{
	mEventArg->setTimeout( timeout );
}

void SP_IocpDispatcher :: shutdown()
{
	mIsShutdown = 1;
}

int SP_IocpDispatcher :: isRunning()
{
	return mIsRunning;
}

int SP_IocpDispatcher :: getSessionCount()
{
	return mEventArg->getSessionManager()->getCount();
}

int SP_IocpDispatcher :: getReqQueueLength()
{
	return mEventArg->getInputResultQueue()->getLength();
}

int SP_IocpDispatcher :: dispatch()
{
	int ret = -1;

	sp_thread_attr_t attr;
	sp_thread_attr_init( &attr );
	assert( sp_thread_attr_setstacksize( &attr, 1024 * 1024 ) == 0 );
	sp_thread_attr_setdetachstate( &attr, SP_THREAD_CREATE_DETACHED );

	sp_thread_t thread;
	ret = sp_thread_create( &thread, &attr, eventLoop, this );
	sp_thread_attr_destroy( &attr );
	if( 0 == ret ) {
		sp_syslog( LOG_NOTICE, "Thread #%ld has been created for dispatcher", thread );
	} else {
		mIsRunning = 0;
		sp_syslog( LOG_WARNING, "Unable to create a thread for dispatcher, %s",
			strerror( errno ) ) ;
	}

	return ret;
}

sp_thread_result_t SP_THREAD_CALL SP_IocpDispatcher :: eventLoop( void * arg )
{
	SP_IocpDispatcher * dispatcher = (SP_IocpDispatcher*)arg;

	dispatcher->mIsRunning = 1;

	dispatcher->start();

	dispatcher->mIsRunning = 0;

	return 0;
}

void SP_IocpDispatcher :: outputCompleted( void * arg )
{
	SP_CompletionHandler * handler = ( SP_CompletionHandler * ) ((void**)arg)[0];
	SP_Message * msg = ( SP_Message * ) ((void**)arg)[ 1 ];

	handler->completionMessage( msg );

	free( arg );
}

int SP_IocpDispatcher :: start()
{
	SP_Executor workerExecutor( mMaxThreads, "work" );
	SP_Executor actExecutor( 1, "act" );

	/* Start the event loop. */
	while( 0 == mIsShutdown ) {
		SP_IocpEventCallback::eventLoop( mEventArg, NULL );

		for( ; NULL != mEventArg->getInputResultQueue()->top(); ) {
			SP_Task * task = (SP_Task*)mEventArg->getInputResultQueue()->pop();
			workerExecutor.execute( task );
		}

		for( ; NULL != mEventArg->getOutputResultQueue()->top(); ) {
			SP_Message * msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop();

			void ** arg = ( void** )malloc( sizeof( void * ) * 2 );
			arg[ 0 ] = (void*)mCompletionHandler;
			arg[ 1 ] = (void*)msg;

			actExecutor.execute( outputCompleted, arg );
		}
	}

	sp_syslog( LOG_NOTICE, "Dispatcher is shutdown." );

	return 0;
}

typedef struct tagSP_IocpPushArg {
	int mType;      // 0 : fd, 1 : timer

	// for push fd
	int mFd;
	SP_Handler * mHandler;
	SP_IOChannel * mIOChannel;
	int mNeedStart;

	// for push timer
	struct timeval mTimeout;
	SP_IocpEvent_t mTimerEvent;
	SP_TimerHandler * mTimerHandler;
	SP_IocpEventArg * mEventArg;
	SP_IocpMsgQueue * mPushQueue;
} SP_IocpPushArg_t;

void SP_IocpDispatcher :: onPush( void * queueData, void * arg )
{
	SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)queueData;
	SP_IocpEventArg * eventArg = (SP_IocpEventArg*)arg;

	if( 0 == pushArg->mType ) {
		SP_Sid_t sid;
		sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq );
		assert( sid.mKey > 0 );

		SP_Session * session = new SP_Session( sid );

		session->setHandler( pushArg->mHandler );
		session->setArg( eventArg );
		session->setIOChannel( pushArg->mIOChannel );

		if( SP_IocpEventCallback::addSession( eventArg, (HANDLE)pushArg->mFd, session ) ) {
			eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session );

			if( pushArg->mNeedStart ) {
				SP_IocpEventHelper::doStart( session );
			} else {
				SP_IocpEventCallback::addRecv( session );
			}
		} else {
			delete session;
		}

		free( pushArg );
	} else {
		memset( &( pushArg->mTimerEvent ), 0, sizeof( SP_IocpEvent_t ) );
		pushArg->mTimerEvent.mType = SP_IocpEvent_t::eEventTimer;

		struct timeval curr;
		sp_gettimeofday( &curr, NULL );
		struct timeval * dest = &( pushArg->mTimerEvent.mTimeout );
		struct timeval * src = &( pushArg->mTimeout );

		dest->tv_sec = curr.tv_sec + src->tv_sec;
		dest->tv_usec = curr.tv_usec + src->tv_usec;
		if( dest->tv_usec >= 1000000 ) {
			dest->tv_sec++;
			dest->tv_usec -= 1000000;
		}

		pushArg->mTimerEvent.mHeapIndex = -1;
		pushArg->mTimerEvent.mOnTimer = onTimer;

		eventArg->getEventHeap()->push( &( pushArg->mTimerEvent ) );
	}
}

int SP_IocpDispatcher :: push( int fd, SP_Handler * handler, int needStart )
{
	SP_IOChannel * ioChannel = new SP_DefaultIOChannel();
	return push( fd, handler, ioChannel, needStart );
}

int SP_IocpDispatcher :: push( int fd, SP_Handler * handler,
		SP_IOChannel * ioChannel, int needStart )
{
	SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) );
	arg->mType = 0;
	arg->mFd = fd;
	arg->mHandler = handler;
	arg->mNeedStart = needStart;
	arg->mIOChannel = ioChannel;

	SP_IOUtils::setNonblock( fd );

	return mPushQueue->push( arg );
}

void SP_IocpDispatcher :: onTimer( void * arg )
{
	SP_IocpEvent_t * event = (SP_IocpEvent_t*)arg;
	SP_IocpPushArg_t * pushArg = CONTAINING_RECORD( event, SP_IocpPushArg_t, mTimerEvent );

	pushArg->mEventArg->getInputResultQueue()->push(
		new SP_SimpleTask( timer, pushArg, 1 ) );
}

void SP_IocpDispatcher :: timer( void * arg )
{
	SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)arg;
	SP_TimerHandler * handler = pushArg->mTimerHandler;
	SP_IocpEventArg * eventArg = pushArg->mEventArg;

	SP_Sid_t sid;
	sid.mKey = SP_Sid_t::eTimerKey;
	sid.mSeq = SP_Sid_t::eTimerSeq;
	SP_Response * response = new SP_Response( sid );
	if( 0 == handler->handle( response, &( pushArg->mTimeout ) ) ) {
		pushArg->mPushQueue->push( arg );
	} else {
		delete pushArg->mTimerHandler;
		free( pushArg );
	}

	eventArg->getResponseQueue()->push( response );
}

int SP_IocpDispatcher :: push( const struct timeval * timeout, SP_TimerHandler * handler )
{
	SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) );

	arg->mType = 1;
	arg->mTimeout = *timeout;
	arg->mTimerHandler = handler;
	arg->mEventArg = mEventArg;
	arg->mPushQueue = mPushQueue;

	return mPushQueue->push( arg );
}

int SP_IocpDispatcher :: push( SP_Response * response )
{
	return mEventArg->getResponseQueue()->push( response );
}
<commit_msg>add client ip for request in iocpdispatcher<commit_after>/*
 * Copyright 2008 Stephen Liu
 * For license terms, see the file COPYING along with this library.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <signal.h>

#include "spporting.hpp"
#include "spthread.hpp"

#include "spiocpdispatcher.hpp"

#include "spwin32iocp.hpp"
#include "sphandler.hpp"
#include "spsession.hpp"
#include "spexecutor.hpp"
#include "sputils.hpp"
#include "spioutils.hpp"
#include "spiochannel.hpp"
#include "sprequest.hpp"

#include "spiocpevent.hpp"

SP_IocpDispatcher :: SP_IocpDispatcher( SP_CompletionHandler * completionHandler, int maxThreads )
{
#ifdef SIGPIPE
	/* Don't die with SIGPIPE on remote read shutdown. That's dumb. */
	signal( SIGPIPE, SIG_IGN );
#endif

	mIsShutdown = 0;
	mIsRunning = 0;

	mEventArg = new SP_IocpEventArg( 600 );
	SP_IocpMsgQueue * msgQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(),
			SP_IocpEventCallback::eKeyMsgQueue, SP_IocpEventCallback::onResponse, mEventArg );
	mEventArg->setResponseQueue( msgQueue );
	// load DisconnectEx
	{
		int fd = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED );
		mEventArg->loadDisconnectEx( fd );
		closesocket( fd );
	}

	mMaxThreads = maxThreads > 0 ? maxThreads : 4;

	mCompletionHandler = completionHandler;

	mPushQueue = new SP_IocpMsgQueue( mEventArg->getCompletionPort(),
			SP_IocpEventCallback::eKeyMsgQueue, onPush, mEventArg );
}

SP_IocpDispatcher :: ~SP_IocpDispatcher()
{
	if( 0 == mIsRunning ) sleep( 1 );

	shutdown();

	for( ; mIsRunning; ) sleep( 1 );

	delete mPushQueue;
	mPushQueue = NULL;

	delete mEventArg;
	mEventArg = NULL;
}

void SP_IocpDispatcher :: setTimeout( int timeout )
{
	mEventArg->setTimeout( timeout );
}

void SP_IocpDispatcher :: shutdown()
{
	mIsShutdown = 1;
}

int SP_IocpDispatcher :: isRunning()
{
	return mIsRunning;
}

int SP_IocpDispatcher :: getSessionCount()
{
	return mEventArg->getSessionManager()->getCount();
}

int SP_IocpDispatcher :: getReqQueueLength()
{
	return mEventArg->getInputResultQueue()->getLength();
}

int SP_IocpDispatcher :: dispatch()
{
	int ret = -1;

	sp_thread_attr_t attr;
	sp_thread_attr_init( &attr );
	assert( sp_thread_attr_setstacksize( &attr, 1024 * 1024 ) == 0 );
	sp_thread_attr_setdetachstate( &attr, SP_THREAD_CREATE_DETACHED );

	sp_thread_t thread;
	ret = sp_thread_create( &thread, &attr, eventLoop, this );
	sp_thread_attr_destroy( &attr );
	if( 0 == ret ) {
		sp_syslog( LOG_NOTICE, "Thread #%ld has been created for dispatcher", thread );
	} else {
		mIsRunning = 0;
		sp_syslog( LOG_WARNING, "Unable to create a thread for dispatcher, %s",
			strerror( errno ) ) ;
	}

	return ret;
}

sp_thread_result_t SP_THREAD_CALL SP_IocpDispatcher :: eventLoop( void * arg )
{
	SP_IocpDispatcher * dispatcher = (SP_IocpDispatcher*)arg;

	dispatcher->mIsRunning = 1;

	dispatcher->start();

	dispatcher->mIsRunning = 0;

	return 0;
}

void SP_IocpDispatcher :: outputCompleted( void * arg )
{
	SP_CompletionHandler * handler = ( SP_CompletionHandler * ) ((void**)arg)[0];
	SP_Message * msg = ( SP_Message * ) ((void**)arg)[ 1 ];

	handler->completionMessage( msg );

	free( arg );
}

int SP_IocpDispatcher :: start()
{
	SP_Executor workerExecutor( mMaxThreads, "work" );
	SP_Executor actExecutor( 1, "act" );

	/* Start the event loop. */
	while( 0 == mIsShutdown ) {
		SP_IocpEventCallback::eventLoop( mEventArg, NULL );

		for( ; NULL != mEventArg->getInputResultQueue()->top(); ) {
			SP_Task * task = (SP_Task*)mEventArg->getInputResultQueue()->pop();
			workerExecutor.execute( task );
		}

		for( ; NULL != mEventArg->getOutputResultQueue()->top(); ) {
			SP_Message * msg = (SP_Message*)mEventArg->getOutputResultQueue()->pop();

			void ** arg = ( void** )malloc( sizeof( void * ) * 2 );
			arg[ 0 ] = (void*)mCompletionHandler;
			arg[ 1 ] = (void*)msg;

			actExecutor.execute( outputCompleted, arg );
		}
	}

	sp_syslog( LOG_NOTICE, "Dispatcher is shutdown." );

	return 0;
}

typedef struct tagSP_IocpPushArg {
	int mType;      // 0 : fd, 1 : timer

	// for push fd
	int mFd;
	SP_Handler * mHandler;
	SP_IOChannel * mIOChannel;
	int mNeedStart;

	// for push timer
	struct timeval mTimeout;
	SP_IocpEvent_t mTimerEvent;
	SP_TimerHandler * mTimerHandler;
	SP_IocpEventArg * mEventArg;
	SP_IocpMsgQueue * mPushQueue;
} SP_IocpPushArg_t;

void SP_IocpDispatcher :: onPush( void * queueData, void * arg )
{
	SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)queueData;
	SP_IocpEventArg * eventArg = (SP_IocpEventArg*)arg;

	if( 0 == pushArg->mType ) {
		SP_Sid_t sid;
		sid.mKey = eventArg->getSessionManager()->allocKey( &sid.mSeq );
		assert( sid.mKey > 0 );

		SP_Session * session = new SP_Session( sid );

		char clientIP[ 32 ] = { 0 };
		{
			struct sockaddr_in clientAddr;
			socklen_t clientLen = sizeof( clientAddr );
			getpeername( pushArg->mFd, (struct sockaddr *)&clientAddr, &clientLen );
			SP_IOUtils::inetNtoa( &( clientAddr.sin_addr ), clientIP, sizeof( clientIP ) );
		}
		session->getRequest()->setClientIP( clientIP );

		session->setHandler( pushArg->mHandler );
		session->setArg( eventArg );
		session->setIOChannel( pushArg->mIOChannel );

		if( SP_IocpEventCallback::addSession( eventArg, (HANDLE)pushArg->mFd, session ) ) {
			eventArg->getSessionManager()->put( sid.mKey, sid.mSeq, session );

			if( pushArg->mNeedStart ) {
				SP_IocpEventHelper::doStart( session );
			} else {
				SP_IocpEventCallback::addRecv( session );
			}
		} else {
			delete session;
		}

		free( pushArg );
	} else {
		memset( &( pushArg->mTimerEvent ), 0, sizeof( SP_IocpEvent_t ) );
		pushArg->mTimerEvent.mType = SP_IocpEvent_t::eEventTimer;

		struct timeval curr;
		sp_gettimeofday( &curr, NULL );
		struct timeval * dest = &( pushArg->mTimerEvent.mTimeout );
		struct timeval * src = &( pushArg->mTimeout );

		dest->tv_sec = curr.tv_sec + src->tv_sec;
		dest->tv_usec = curr.tv_usec + src->tv_usec;
		if( dest->tv_usec >= 1000000 ) {
			dest->tv_sec++;
			dest->tv_usec -= 1000000;
		}

		pushArg->mTimerEvent.mHeapIndex = -1;
		pushArg->mTimerEvent.mOnTimer = onTimer;

		eventArg->getEventHeap()->push( &( pushArg->mTimerEvent ) );
	}
}

int SP_IocpDispatcher :: push( int fd, SP_Handler * handler, int needStart )
{
	SP_IOChannel * ioChannel = new SP_DefaultIOChannel();
	return push( fd, handler, ioChannel, needStart );
}

int SP_IocpDispatcher :: push( int fd, SP_Handler * handler,
		SP_IOChannel * ioChannel, int needStart )
{
	SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) );
	arg->mType = 0;
	arg->mFd = fd;
	arg->mHandler = handler;
	arg->mNeedStart = needStart;
	arg->mIOChannel = ioChannel;

	SP_IOUtils::setNonblock( fd );

	return mPushQueue->push( arg );
}

void SP_IocpDispatcher :: onTimer( void * arg )
{
	SP_IocpEvent_t * event = (SP_IocpEvent_t*)arg;
	SP_IocpPushArg_t * pushArg = CONTAINING_RECORD( event, SP_IocpPushArg_t, mTimerEvent );

	pushArg->mEventArg->getInputResultQueue()->push(
		new SP_SimpleTask( timer, pushArg, 1 ) );
}

void SP_IocpDispatcher :: timer( void * arg )
{
	SP_IocpPushArg_t * pushArg = (SP_IocpPushArg_t*)arg;
	SP_TimerHandler * handler = pushArg->mTimerHandler;
	SP_IocpEventArg * eventArg = pushArg->mEventArg;

	SP_Sid_t sid;
	sid.mKey = SP_Sid_t::eTimerKey;
	sid.mSeq = SP_Sid_t::eTimerSeq;
	SP_Response * response = new SP_Response( sid );
	if( 0 == handler->handle( response, &( pushArg->mTimeout ) ) ) {
		pushArg->mPushQueue->push( arg );
	} else {
		delete pushArg->mTimerHandler;
		free( pushArg );
	}

	eventArg->getResponseQueue()->push( response );
}

int SP_IocpDispatcher :: push( const struct timeval * timeout, SP_TimerHandler * handler )
{
	SP_IocpPushArg_t * arg = (SP_IocpPushArg_t*)malloc( sizeof( SP_IocpPushArg_t ) );

	arg->mType = 1;
	arg->mTimeout = *timeout;
	arg->mTimerHandler = handler;
	arg->mEventArg = mEventArg;
	arg->mPushQueue = mPushQueue;

	return mPushQueue->push( arg );
}

int SP_IocpDispatcher :: push( SP_Response * response )
{
	return mEventArg->getResponseQueue()->push( response );
}
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "CDiff.h"

#include "ModelBase/src/model/TreeManager.h"

#include "VisualizationBase/src/items/RootItem.h"
#include "VisualizationBase/src/items/Item.h"
#include "VisualizationBase/src/VisualizationManager.h"
#include "VisualizationBase/src/CustomSceneEvent.h"

#include "FilePersistence/src/simple/SimpleTextFileStore.h"

using namespace Visualization;

namespace Interaction {

CDiff::CDiff() : CommandWithNameAndFlags{"diff", {{"project"}}, false}
{}

CommandResult* CDiff::executeNamed(Visualization::Item*, Visualization::Item* target,
											  const std::unique_ptr<Visualization::Cursor>&,
											  const QString& name, const QStringList& attributes)
{
	// TODO only display affected subtree
	(void) attributes;

	Model::TreeManager* manager = target->node()->manager();
	QString managerName = manager->name();

	// get GitRepository
	QString path("projects/");
	path.append(managerName);
	repository = new FilePersistence::GitRepository(path);

	// load HEAD into tree
	auto headManager = new Model::TreeManager();
	headManager->load(new FilePersistence::SimpleTextFileStore("projects/"), managerName, false);
	headManager->setName("HEAD");

	// load name into tree
	const FilePersistence::Commit* commit = repository->getCommit(name);

	auto fileStore = new FilePersistence::SimpleTextFileStore(
				[this, &commit](QString filename, const char*& data, int& size)
				{ return commit->getFileContent(filename, data, size); }
			);

	auto revisionManager = new Model::TreeManager();
	revisionManager->load(fileStore, managerName, false);
	revisionManager->setName(name);

	// build visualization
	Item* headRoot = new RootItem(headManager->root());

	Item* revisionRoot = new RootItem(revisionManager->root());
	revisionRoot->setPos(-400.f, 0.f);

	VisualizationManager::instance().mainScene()->addTopLevelItem(headRoot);
	VisualizationManager::instance().mainScene()->listenToTreeManager(headManager);

	VisualizationManager::instance().mainScene()->addTopLevelItem(revisionRoot);
	VisualizationManager::instance().mainScene()->listenToTreeManager(revisionManager);

	QApplication::postEvent(Visualization::VisualizationManager::instance().mainScene(),
		new Visualization::CustomSceneEvent([headRoot, headManager, revisionRoot, revisionManager,
														name, this]()
	{
			FilePersistence::Diff diff = repository->diff(name, FilePersistence::GitRepository::WORKDIR);
			FilePersistence::IdToChangeDescriptionHash changes = diff.changes();

			auto insertHighlight = VisualizationManager::instance().mainScene()->addHighlight("Insert", "green");
			auto deleteHighlight = VisualizationManager::instance().mainScene()->addHighlight("Delete", "red");

			Model::Node* node = nullptr;
			for (FilePersistence::ChangeDescription* change : changes.values())
			{
				switch (change->type())
				{
					case FilePersistence::ChangeType::Added:
						node = const_cast<Model::Node*>(headManager->nodeIdMap().node(change->id()));
						if (auto item = headRoot->findVisualizationOf(node))
							insertHighlight->addHighlightedItem(item);
						break;

					case FilePersistence::ChangeType::Deleted:
						node = const_cast<Model::Node*>(revisionManager->nodeIdMap().node(change->id()));
						if (auto item = revisionRoot->findVisualizationOf(node))
							deleteHighlight->addHighlightedItem(item);
						break;

					default:
						break;
				}
			}

	} ) );

	delete commit;

	return new CommandResult();
}

QStringList CDiff::possibleNames()
{
	return QStringList();
}

} /* namespace Interaction */
<commit_msg>Improve CDiff to visualize only the selected item<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
** following conditions are met:
**
** * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
** disclaimer.
** * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
** following disclaimer in the documentation and/or other materials provided with the distribution.
** * Neither the name of the ETH Zurich nor the names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
** INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "CDiff.h"

#include "ModelBase/src/model/TreeManager.h"

#include "VisualizationBase/src/items/RootItem.h"
#include "VisualizationBase/src/items/Item.h"
#include "VisualizationBase/src/VisualizationManager.h"
#include "VisualizationBase/src/CustomSceneEvent.h"

#include "FilePersistence/src/simple/SimpleTextFileStore.h"

using namespace Visualization;
using namespace FilePersistence;

namespace Interaction {

CDiff::CDiff() : CommandWithNameAndFlags{"diff", {{"project"}}, false}
{}

CommandResult* CDiff::executeNamed(Visualization::Item*, Visualization::Item* target,
											  const std::unique_ptr<Visualization::Cursor>&,
											  const QString& name, const QStringList&)
{
	Model::TreeManager* headManager = target->node()->manager();
	QString managerName = headManager->name();

	// get GitRepository
	QString path("projects/");
	path.append(managerName);
	repository = new GitRepository(path);

	headManager->setName("HEAD");

	// load name into tree
	const Commit* commit = repository->getCommit(name);

	auto fileStore = new SimpleTextFileStore(
				[this, &commit](QString filename, const char*& data, int& size)
				{ return commit->getFileContent(filename, data, size); }
			);

	auto revisionManager = new Model::TreeManager();
	revisionManager->load(fileStore, managerName, false);
	revisionManager->setName(name);

	// build visualization
	Item* headRoot = target;
	while (headRoot->parent()) headRoot = headRoot->parent();

	Item* revisionRoot = new RootItem(revisionManager->root());
	revisionRoot->setPos(-400.f, 0.f);

	VisualizationManager::instance().mainScene()->addTopLevelItem(revisionRoot);
	VisualizationManager::instance().mainScene()->listenToTreeManager(revisionManager);

	QApplication::postEvent(Visualization::VisualizationManager::instance().mainScene(),
		new Visualization::CustomSceneEvent([headRoot, headManager, revisionRoot, revisionManager,
														name, target, this]()
	{
			Diff diff = repository->diff(name, GitRepository::WORKDIR);
			IdToChangeDescriptionHash changes = diff.changes();

			auto insertHighlight = VisualizationManager::instance().mainScene()->addHighlight("Insert", "green");
			auto deleteHighlight = VisualizationManager::instance().mainScene()->addHighlight("Delete", "red");

			IdToChangeDescriptionHash::iterator iter;

			QSet<Model::NodeIdType> relevantIDs;

			QSet<Model::NodeIdType> completed;
			QList<Model::Node*> stack;
			stack.append(target->node());
			while (!stack.isEmpty())
			{
				// HEAD version
				Model::Node* current = stack.takeLast();

				stack.append(current->children());

				// check if relevant
				Model::NodeIdType currentID = headManager->nodeIdMap().id(current);
				//qDebug() << currentID.toString();
				iter = changes.find(currentID);
				if (iter != changes.end())
					relevantIDs.insert(currentID);

				// REVISION version
				if (!completed.contains(currentID))
				{
					QList<Model::Node*> revisionStack;
					Model::Node* revisionNode = const_cast<Model::Node*>(revisionManager->nodeIdMap().node(currentID));
					if (revisionNode != nullptr)
					{
						revisionStack.append(revisionNode);
						while (!revisionStack.isEmpty())
						{
							revisionNode = revisionStack.takeLast();
							Model::NodeIdType revisionNodeID = revisionManager->nodeIdMap().id(revisionNode);
							completed.insert(revisionNodeID);

							revisionStack.append(revisionNode->children());

							// check if relevant
							iter = changes.find(revisionNodeID);
							if (iter != changes.end())
								relevantIDs.insert(revisionNodeID);
						}
					}
				}
			}

			Model::Node* node = nullptr;
			for (auto id : relevantIDs)
			{
				iter = changes.find(id);
				if (iter != changes.end())
				{
					ChangeDescription* change = iter.value();
					switch (change->type())
					{
						case ChangeType::Added:
							node = const_cast<Model::Node*>(headManager->nodeIdMap().node(id));
							if (auto item = headRoot->findVisualizationOf(node))
								insertHighlight->addHighlightedItem(item);
							break;

						case ChangeType::Deleted:
							node = const_cast<Model::Node*>(revisionManager->nodeIdMap().node(id));
							if (auto item = revisionRoot->findVisualizationOf(node))
								deleteHighlight->addHighlightedItem(item);
							break;

						default:
							break;
					}
				}
				else
					Q_ASSERT(false);
			}

	} ) );

	SAFE_DELETE(commit);

	return new CommandResult();
}

QStringList CDiff::possibleNames()
{
	return QStringList();
}

} /* namespace Interaction */
<|endoftext|>