<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/task_manager.h"

#include "app/l10n_util.h"
#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/crashed_extension_infobar.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");

class ResourceChangeObserver : public TaskManagerModelObserver {
 public:
  ResourceChangeObserver(const TaskManagerModel* model,
                         int target_resource_count)
      : model_(model),
        target_resource_count_(target_resource_count) {
  }

  virtual void OnModelChanged() {
    OnResourceChange();
  }

  virtual void OnItemsChanged(int start, int length) {
    OnResourceChange();
  }

  virtual void OnItemsAdded(int start, int length) {
    OnResourceChange();
  }

  virtual void OnItemsRemoved(int start, int length) {
    OnResourceChange();
  }

 private:
  void OnResourceChange() {
    if (model_->ResourceCount() == target_resource_count_)
      MessageLoopForUI::current()->Quit();
  }

  const TaskManagerModel* model_;
  const int target_resource_count_;
};

}  // namespace

class TaskManagerBrowserTest : public ExtensionBrowserTest {
 public:
  TaskManagerModel* model() const {
    return TaskManager::GetInstance()->model();
  }

  void WaitForResourceChange(int target_count) {
    if (model()->ResourceCount() == target_count)
      return;
    ResourceChangeObserver observer(model(), target_count);
    model()->AddObserver(&observer);
    ui_test_utils::RunMessageLoop();
    model()->RemoveObserver(&observer);
  }
};

// Regression test for http://crbug.com/13361
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) {
  browser()->window()->ShowTaskManager();
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Open a new tab and make sure we notice that.
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED,
                           true, 0, false, NULL);
  WaitForResourceChange(3);

  // Close the tab and verify that we notice.
  TabContents* first_tab = browser()->GetTabContentsAt(0);
  ASSERT_TRUE(first_tab);
  browser()->CloseTabContents(first_tab);
  WaitForResourceChange(2);
}

#if defined(OS_WIN)
// http://crbug.com/31663
#define NoticeExtensionChanges DISABLED_NoticeExtensionChanges
#endif

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Loading an extension should result in a new resource being
  // created for it.
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("one_in_shelf")));
  WaitForResourceChange(3);

  // Make sure we also recognize extensions with just background pages.
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
  WaitForResourceChange(4);
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtension) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  // Kill the extension process and make sure we notice it.
  TaskManager::GetInstance()->KillProcess(2);
  WaitForResourceChange(2);
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtensionAndReload) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  // Kill the extension process and make sure we notice it.
  TaskManager::GetInstance()->KillProcess(2);
  WaitForResourceChange(2);

  // Reload the extension using the "crashed extension" infobar while the task
  // manager is still visible. Make sure we don't crash and the extension
  // gets reloaded and noticed in the task manager.
  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_EQ(1, current_tab->infobar_delegate_count());
  InfoBarDelegate* delegate = current_tab->GetInfoBarDelegateAt(0);
  CrashedExtensionInfoBarDelegate* crashed_delegate =
      delegate->AsCrashedExtensionInfoBarDelegate();
  ASSERT_TRUE(crashed_delegate);
  crashed_delegate->Accept();
  WaitForResourceChange(3);
}

// Regression test for http://crbug.com/18693.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ReloadExtension) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  const Extension* extension = model()->GetResourceExtension(2);

  // Reload the extension a few times and make sure our resource count
  // doesn't increase.
  ReloadExtension(extension->id());
  WaitForResourceChange(3);
  extension = model()->GetResourceExtension(2);

  ReloadExtension(extension->id());
  WaitForResourceChange(3);
  extension = model()->GetResourceExtension(2);

  ReloadExtension(extension->id());
  WaitForResourceChange(3);
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, PopulateWebCacheFields) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Open a new tab and make sure we notice that.
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED,
                           true, 0, false, NULL);
  WaitForResourceChange(3);

  // Check that we get some value for the cache columns.
  DCHECK_NE(model()->GetResourceWebCoreImageCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
  DCHECK_NE(model()->GetResourceWebCoreScriptsCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
  DCHECK_NE(model()->GetResourceWebCoreCSSCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
}
<commit_msg>Disable crashy TaskManagerBrowserTest.PopulateWebCacheFields<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/task_manager.h"

#include "app/l10n_util.h"
#include "base/file_path.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/crashed_extension_infobar.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/page_transition_types.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "grit/generated_resources.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

const FilePath::CharType* kTitle1File = FILE_PATH_LITERAL("title1.html");

class ResourceChangeObserver : public TaskManagerModelObserver {
 public:
  ResourceChangeObserver(const TaskManagerModel* model,
                         int target_resource_count)
      : model_(model),
        target_resource_count_(target_resource_count) {
  }

  virtual void OnModelChanged() {
    OnResourceChange();
  }

  virtual void OnItemsChanged(int start, int length) {
    OnResourceChange();
  }

  virtual void OnItemsAdded(int start, int length) {
    OnResourceChange();
  }

  virtual void OnItemsRemoved(int start, int length) {
    OnResourceChange();
  }

 private:
  void OnResourceChange() {
    if (model_->ResourceCount() == target_resource_count_)
      MessageLoopForUI::current()->Quit();
  }

  const TaskManagerModel* model_;
  const int target_resource_count_;
};

}  // namespace

class TaskManagerBrowserTest : public ExtensionBrowserTest {
 public:
  TaskManagerModel* model() const {
    return TaskManager::GetInstance()->model();
  }

  void WaitForResourceChange(int target_count) {
    if (model()->ResourceCount() == target_count)
      return;
    ResourceChangeObserver observer(model(), target_count);
    model()->AddObserver(&observer);
    ui_test_utils::RunMessageLoop();
    model()->RemoveObserver(&observer);
  }
};

// Regression test for http://crbug.com/13361
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ShutdownWhileOpen) {
  browser()->window()->ShowTaskManager();
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeTabContentsChanges) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Open a new tab and make sure we notice that.
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED,
                           true, 0, false, NULL);
  WaitForResourceChange(3);

  // Close the tab and verify that we notice.
  TabContents* first_tab = browser()->GetTabContentsAt(0);
  ASSERT_TRUE(first_tab);
  browser()->CloseTabContents(first_tab);
  WaitForResourceChange(2);
}

#if defined(OS_WIN)
// http://crbug.com/31663
#define NoticeExtensionChanges DISABLED_NoticeExtensionChanges
#endif

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeExtensionChanges) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Loading an extension should result in a new resource being
  // created for it.
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("one_in_shelf")));
  WaitForResourceChange(3);

  // Make sure we also recognize extensions with just background pages.
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));
  WaitForResourceChange(4);
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtension) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  // Kill the extension process and make sure we notice it.
  TaskManager::GetInstance()->KillProcess(2);
  WaitForResourceChange(2);
}

IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, KillExtensionAndReload) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  // Kill the extension process and make sure we notice it.
  TaskManager::GetInstance()->KillProcess(2);
  WaitForResourceChange(2);

  // Reload the extension using the "crashed extension" infobar while the task
  // manager is still visible. Make sure we don't crash and the extension
  // gets reloaded and noticed in the task manager.
  TabContents* current_tab = browser()->GetSelectedTabContents();
  ASSERT_EQ(1, current_tab->infobar_delegate_count());
  InfoBarDelegate* delegate = current_tab->GetInfoBarDelegateAt(0);
  CrashedExtensionInfoBarDelegate* crashed_delegate =
      delegate->AsCrashedExtensionInfoBarDelegate();
  ASSERT_TRUE(crashed_delegate);
  crashed_delegate->Accept();
  WaitForResourceChange(3);
}

// Regression test for http://crbug.com/18693.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, ReloadExtension) {
  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("common").AppendASCII("background_page")));

  // Wait until we see the loaded extension in the task manager (the three
  // resources are: the browser process, New Tab Page, and the extension).
  WaitForResourceChange(3);

  EXPECT_TRUE(model()->GetResourceExtension(0) == NULL);
  EXPECT_TRUE(model()->GetResourceExtension(1) == NULL);
  ASSERT_TRUE(model()->GetResourceExtension(2) != NULL);

  const Extension* extension = model()->GetResourceExtension(2);

  // Reload the extension a few times and make sure our resource count
  // doesn't increase.
  ReloadExtension(extension->id());
  WaitForResourceChange(3);
  extension = model()->GetResourceExtension(2);

  ReloadExtension(extension->id());
  WaitForResourceChange(3);
  extension = model()->GetResourceExtension(2);

  ReloadExtension(extension->id());
  WaitForResourceChange(3);
}

// Crashy, http://crbug.com/42301.
IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest,
                       DISABLED_PopulateWebCacheFields) {
  EXPECT_EQ(0, model()->ResourceCount());

  // Show the task manager. This populates the model, and helps with debugging
  // (you see the task manager).
  browser()->window()->ShowTaskManager();

  // Browser and the New Tab Page.
  EXPECT_EQ(2, model()->ResourceCount());

  // Open a new tab and make sure we notice that.
  GURL url(ui_test_utils::GetTestUrl(FilePath(FilePath::kCurrentDirectory),
                                     FilePath(kTitle1File)));
  browser()->AddTabWithURL(url, GURL(), PageTransition::TYPED,
                           true, 0, false, NULL);
  WaitForResourceChange(3);

  // Check that we get some value for the cache columns.
  DCHECK_NE(model()->GetResourceWebCoreImageCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
  DCHECK_NE(model()->GetResourceWebCoreScriptsCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
  DCHECK_NE(model()->GetResourceWebCoreCSSCacheSize(2),
            l10n_util::GetString(IDS_TASK_MANAGER_NA_CELL_TEXT));
}
<|endoftext|>


<commit_before>#include <Sound.h>
#include <Display.h>
#include <jni.h>

#include <android/log.h>

#undef LOGV
#undef LOGE

//#define LOGV(msg,args...)
#define LOGV(msg,args...) __android_log_print(ANDROID_LOG_ERROR, "NME::AndroidSound", msg, ## args)

#define LOGE(msg,args...) __android_log_print(ANDROID_LOG_ERROR, "NME::AndroidSound", msg, ## args)

extern JNIEnv *gEnv;

namespace nme
{

class AndroidSoundChannel : public SoundChannel
{
public:
   AndroidSoundChannel(Object *inSound, int inHandle,
							  double startTime, int loops, const SoundTransform &inTransform)
	{
		mStreamID = -1;
		mSound = inSound;
		inSound->IncRef();
		if (inHandle>=0)
		{
		   jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
         jmethodID mid = gEnv->GetStaticMethodID(cls, "playSound", "(IDDI)I");
         if (mid > 0)
		   {
			      mStreamID = gEnv->CallStaticIntMethod(cls, mid, inHandle, inTransform.volume, inTransform.volume, loops );
		   }
		}
    }

   ~AndroidSoundChannel()
   {
      mSound->DecRef();
	}

   bool isComplete()
	{
		return true;
	}
   double getLeft()
	{
		return 0.5;
	}
   double getRight()
	{
		return 0.5;
	}
   double getPosition()
	{
	}
   void stop()
	{
	}
   void setTransform(const SoundTransform &inTransform)
	{
	}

	Object *mSound;
	int mStreamID;
};

class AndroidMusicChannel : public SoundChannel
{
public:
   AndroidMusicChannel(Object *inSound, int inHandle,
							  double startTime, int loops, const SoundTransform &inTransform)
	{
		mState = 0;
		mSound = inSound;
		inSound->IncRef();

		if (inHandle>=0)
		{
		   jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
         jmethodID mid = gEnv->GetStaticMethodID(cls, "playMusic", "(IDDI)I");
         if (mid > 0)
		   {
			   mState = gEnv->CallStaticIntMethod(cls, mid, inHandle, inTransform.volume, inTransform.volume, loops );
		   }
		}
    }

   ~AndroidMusicChannel()
   {
      mSound->DecRef();
	}

   bool isComplete()
	{
		return true;
	}
   double getLeft()
	{
		return 0.5;
	}
   double getRight()
	{
		return 0.5;
	}
   double getPosition()
	{
	}
   void stop()
	{
	}
   void setTransform(const SoundTransform &inTransform)
	{
	}

	Object *mSound;
   int mState;
};

class AndroidSound : public Sound
{
   enum SoundMode
   {
      MODE_UNKNOWN,
      MODE_SOUND_ID,
      MODE_MUSIC_RES_ID,
      MODE_MUSIC_NAME,
   };

public:
	AndroidSound(const std::string &inSound, bool inForceMusic)
	{
		IncRef();

      mMode = MODE_UNKNOWN;
		mID = -1;
		jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
		jstring str = gEnv->NewStringUTF( inSound.c_str() );

      if (!inForceMusic)
      {
         jmethodID mid = gEnv->GetStaticMethodID(cls, "getSoundHandle", "(Ljava/lang/String;)I");
         if (mid > 0)
		   {
			   mID = gEnv->CallStaticIntMethod(cls, mid, str);
            if (mID>=0)
               mMode = MODE_SOUND_ID;
		   }
      }

      if (mID<0)
      {
         jmethodID gmh = gEnv->GetStaticMethodID(cls, "getMusicHandle", "(Ljava/lang/String;)I");
         if (gmh>0)
         {
			   mID = gEnv->CallStaticIntMethod(cls, gmh, str);
            if (mID>0)
               mMode = MODE_MUSIC_RES_ID;
         }
      }

      if (mID<0)
      {
         mMusicName = inSound;
         mMode = MODE_MUSIC_NAME;
      }
	}

   int getBytesLoaded() { return 0; }
   int getBytesTotal() { return 0; }
   bool ok() { return mID >= 0; }
   std::string getError() { return ok() ? "" : "Error"; }
   double getLength() { return 0; }
   void close()  { }

   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
	{
      if (mMode==MODE_MUSIC_RES_ID)
		   return new AndroidMusicChannel(this,mID,startTime,loops,inTransform);

		return new AndroidSoundChannel(this,mID,startTime,loops,inTransform);
	}

	int mID;
   std::string mMusicName;
   SoundMode mMode;
};

Sound *Sound::Create(const std::string &inFilename,bool inForceMusic)
{
	return new AndroidSound(inFilename,inForceMusic);
}

}
<commit_msg>respect inTransform in android sound constuctors<commit_after>#include <Sound.h>
#include <Display.h>
#include <jni.h>

#include <android/log.h>

#undef LOGV
#undef LOGE

//#define LOGV(msg,args...)
#define LOGV(msg,args...) __android_log_print(ANDROID_LOG_ERROR, "NME::AndroidSound", msg, ## args)

#define LOGE(msg,args...) __android_log_print(ANDROID_LOG_ERROR, "NME::AndroidSound", msg, ## args)

extern JNIEnv *gEnv;

namespace nme
{

class AndroidSoundChannel : public SoundChannel
{
public:
   AndroidSoundChannel(Object *inSound, int inHandle,
							  double startTime, int loops, const SoundTransform &inTransform)
	{
		mStreamID = -1;
		mSound = inSound;
		inSound->IncRef();
		if (inHandle>=0)
		{
		   jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
         jmethodID mid = gEnv->GetStaticMethodID(cls, "playSound", "(IDDI)I");
         if (mid > 0)
		   {
			      mStreamID = gEnv->CallStaticIntMethod(cls, mid, inHandle, inTransform.volume*((1-inTransform.pan)/2), inTransform.volume*((inTransform.pan+1)/2), loops );
		   }
		}
    }

   ~AndroidSoundChannel()
   {
      mSound->DecRef();
	}

   bool isComplete()
	{
		return true;
	}
   double getLeft()
	{
		return 0.5;
	}
   double getRight()
	{
		return 0.5;
	}
   double getPosition()
	{
	}
   void stop()
	{
	}
   void setTransform(const SoundTransform &inTransform)
	{
	}

	Object *mSound;
	int mStreamID;
};

class AndroidMusicChannel : public SoundChannel
{
public:
   AndroidMusicChannel(Object *inSound, int inHandle,
							  double startTime, int loops, const SoundTransform &inTransform)
	{
		mState = 0;
		mSound = inSound;
		inSound->IncRef();

		if (inHandle>=0)
		{
		   jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
         jmethodID mid = gEnv->GetStaticMethodID(cls, "playMusic", "(IDDI)I");
         if (mid > 0)
		   {
			   mState = gEnv->CallStaticIntMethod(cls, mid, inHandle, inTransform.volume*((1-inTransform.pan)/2), inTransform.volume*((inTransform.pan+1)/2), loops );
		   }
		}
    }

   ~AndroidMusicChannel()
   {
      mSound->DecRef();
	}

   bool isComplete()
	{
		return true;
	}
   double getLeft()
	{
		return 0.5;
	}
   double getRight()
	{
		return 0.5;
	}
   double getPosition()
	{
	}
   void stop()
	{
	}
   void setTransform(const SoundTransform &inTransform)
	{
	}

	Object *mSound;
   int mState;
};

class AndroidSound : public Sound
{
   enum SoundMode
   {
      MODE_UNKNOWN,
      MODE_SOUND_ID,
      MODE_MUSIC_RES_ID,
      MODE_MUSIC_NAME,
   };

public:
	AndroidSound(const std::string &inSound, bool inForceMusic)
	{
		IncRef();

      mMode = MODE_UNKNOWN;
		mID = -1;
		jclass cls = gEnv->FindClass("org/haxe/nme/GameActivity");
		jstring str = gEnv->NewStringUTF( inSound.c_str() );

      if (!inForceMusic)
      {
         jmethodID mid = gEnv->GetStaticMethodID(cls, "getSoundHandle", "(Ljava/lang/String;)I");
         if (mid > 0)
		   {
			   mID = gEnv->CallStaticIntMethod(cls, mid, str);
            if (mID>=0)
               mMode = MODE_SOUND_ID;
		   }
      }

      if (mID<0)
      {
         jmethodID gmh = gEnv->GetStaticMethodID(cls, "getMusicHandle", "(Ljava/lang/String;)I");
         if (gmh>0)
         {
			   mID = gEnv->CallStaticIntMethod(cls, gmh, str);
            if (mID>0)
               mMode = MODE_MUSIC_RES_ID;
         }
      }

      if (mID<0)
      {
         mMusicName = inSound;
         mMode = MODE_MUSIC_NAME;
      }
	}

   int getBytesLoaded() { return 0; }
   int getBytesTotal() { return 0; }
   bool ok() { return mID >= 0; }
   std::string getError() { return ok() ? "" : "Error"; }
   double getLength() { return 0; }
   void close()  { }

   SoundChannel *openChannel(double startTime, int loops, const SoundTransform &inTransform)
	{
      if (mMode==MODE_MUSIC_RES_ID)
		   return new AndroidMusicChannel(this,mID,startTime,loops,inTransform);

		return new AndroidSoundChannel(this,mID,startTime,loops,inTransform);
	}

	int mID;
   std::string mMusicName;
   SoundMode mMode;
};

Sound *Sound::Create(const std::string &inFilename,bool inForceMusic)
{
	return new AndroidSound(inFilename,inForceMusic);
}

}
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."

#include <unistd.h>
#include <sys/prctl.h>

//#include <sys/types.h>
#include <sys/wait.h>
#include <toku_race_tools.h>
#include "toku_crash.h"
#include "toku_atomic.h"

enum { MAX_GDB_ARGS = 128 };

static void
run_gdb(pid_t parent_pid, const char *gdb_path) {
    // 3 bytes per intbyte, null byte
    char pid_buf[sizeof(pid_t) * 3 + 1];
    char exe_buf[sizeof(pid_buf) + sizeof("/proc//exe")];

    // Get pid and path to executable.
    int n;
    n = snprintf(pid_buf, sizeof(pid_buf), "%d", parent_pid);
    paranoid_invariant(n >= 0 && n < (int)sizeof(pid_buf));
    n = snprintf(exe_buf, sizeof(exe_buf), "/proc/%d/exe", parent_pid);
    paranoid_invariant(n >= 0 && n < (int)sizeof(exe_buf));

    dup2(2, 1); // redirect output to stderr
    // Arguments are not dynamic due to possible security holes.
    execlp(gdb_path, gdb_path, "--batch", "-n",
           "-ex", "thread",
           "-ex", "bt",
           "-ex", "bt full",
           "-ex", "thread apply all bt",
           "-ex", "thread apply all bt full",
           exe_buf, pid_buf,
           NULL);
}

static void
intermediate_process(pid_t parent_pid, const char *gdb_path) {
    // Disable generating of core dumps
    prctl(PR_SET_DUMPABLE, 0, 0, 0);
    pid_t worker_pid = fork();
    if (worker_pid < 0) {
        perror("spawn gdb fork: ");
        goto failure;
    }
    if (worker_pid == 0) {
        // Child (debugger)
        run_gdb(parent_pid, gdb_path);
        // Normally run_gdb will not return.
        // In case it does, kill the process.
        goto failure;
    } else {
        pid_t timeout_pid = fork();
        if (timeout_pid < 0) {
            perror("spawn timeout fork: ");
            kill(worker_pid, SIGKILL);
            goto failure;
        }

        if (timeout_pid == 0) {
            sleep(5);  // Timeout of 5 seconds
            goto success;
        } else {
            pid_t exited_pid = wait(NULL);  // Wait for first child to exit
            if (exited_pid == worker_pid) {
                // Kill slower child
                kill(timeout_pid, SIGKILL);
                goto success;
            } else if (exited_pid == timeout_pid) {
                // Kill slower child
                kill(worker_pid, SIGKILL);
                goto failure;  // Timed out.
            } else {
                perror("error while waiting for gdb or timer to end: ");
                //Some failure.  Kill everything.
                kill(timeout_pid, SIGKILL);
                kill(worker_pid, SIGKILL);
                goto failure;
            }
        }
    }
success:
    _exit(EXIT_SUCCESS);
failure:
    _exit(EXIT_FAILURE);
}

static void
spawn_gdb(const char *gdb_path) {
    pid_t parent_pid = getpid();
    // Give permission for this process and (more importantly) all its children to debug this process.
    prctl(PR_SET_PTRACER, parent_pid, 0, 0, 0);
    fprintf(stderr, "Attempting to use gdb @[%s] on pid[%d]\n", gdb_path, parent_pid);
    fflush(stderr);
    int intermediate_pid = fork();
    if (intermediate_pid < 0) {
        perror("spawn_gdb intermediate process fork: ");
    } else if (intermediate_pid == 0) {
        intermediate_process(parent_pid, gdb_path);
    } else {
        waitpid(intermediate_pid, NULL, 0);
    }
}

void
toku_try_gdb_stack_trace(const char *gdb_path) {
    char default_gdb_path[] = "/usr/bin/gdb";
    static bool started = false;
    if (RUNNING_ON_VALGRIND) {
        fprintf(stderr, "gdb stack trace skipped due to running under valgrind\n");
        fflush(stderr);
    } else if (toku_sync_bool_compare_and_swap(&started, false, true)) {
        spawn_gdb(gdb_path ? gdb_path : default_gdb_path);
    }
}

<commit_msg>Refs Tokutek/ft-index#28  Fix compile failure on systems that don't support PR_SET_PTRACER<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
#ident "$Id$"
/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  02110-1301, USA.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  This program is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."

#include <unistd.h>
#include <sys/prctl.h>

//#include <sys/types.h>
#include <sys/wait.h>
#include <toku_race_tools.h>
#include "toku_crash.h"
#include "toku_atomic.h"

enum { MAX_GDB_ARGS = 128 };

static void
run_gdb(pid_t parent_pid, const char *gdb_path) {
    // 3 bytes per intbyte, null byte
    char pid_buf[sizeof(pid_t) * 3 + 1];
    char exe_buf[sizeof(pid_buf) + sizeof("/proc//exe")];

    // Get pid and path to executable.
    int n;
    n = snprintf(pid_buf, sizeof(pid_buf), "%d", parent_pid);
    paranoid_invariant(n >= 0 && n < (int)sizeof(pid_buf));
    n = snprintf(exe_buf, sizeof(exe_buf), "/proc/%d/exe", parent_pid);
    paranoid_invariant(n >= 0 && n < (int)sizeof(exe_buf));

    dup2(2, 1); // redirect output to stderr
    // Arguments are not dynamic due to possible security holes.
    execlp(gdb_path, gdb_path, "--batch", "-n",
           "-ex", "thread",
           "-ex", "bt",
           "-ex", "bt full",
           "-ex", "thread apply all bt",
           "-ex", "thread apply all bt full",
           exe_buf, pid_buf,
           NULL);
}

static void
intermediate_process(pid_t parent_pid, const char *gdb_path) {
    // Disable generating of core dumps
    prctl(PR_SET_DUMPABLE, 0, 0, 0);
    pid_t worker_pid = fork();
    if (worker_pid < 0) {
        perror("spawn gdb fork: ");
        goto failure;
    }
    if (worker_pid == 0) {
        // Child (debugger)
        run_gdb(parent_pid, gdb_path);
        // Normally run_gdb will not return.
        // In case it does, kill the process.
        goto failure;
    } else {
        pid_t timeout_pid = fork();
        if (timeout_pid < 0) {
            perror("spawn timeout fork: ");
            kill(worker_pid, SIGKILL);
            goto failure;
        }

        if (timeout_pid == 0) {
            sleep(5);  // Timeout of 5 seconds
            goto success;
        } else {
            pid_t exited_pid = wait(NULL);  // Wait for first child to exit
            if (exited_pid == worker_pid) {
                // Kill slower child
                kill(timeout_pid, SIGKILL);
                goto success;
            } else if (exited_pid == timeout_pid) {
                // Kill slower child
                kill(worker_pid, SIGKILL);
                goto failure;  // Timed out.
            } else {
                perror("error while waiting for gdb or timer to end: ");
                //Some failure.  Kill everything.
                kill(timeout_pid, SIGKILL);
                kill(worker_pid, SIGKILL);
                goto failure;
            }
        }
    }
success:
    _exit(EXIT_SUCCESS);
failure:
    _exit(EXIT_FAILURE);
}

static void
spawn_gdb(const char *gdb_path) {
    pid_t parent_pid = getpid();
#if defined(PR_SET_PTRACER)
    // On systems that require permission for the same user to ptrace,
    // give permission for this process and (more importantly) all its children to debug this process.
    prctl(PR_SET_PTRACER, parent_pid, 0, 0, 0);
#endif
    fprintf(stderr, "Attempting to use gdb @[%s] on pid[%d]\n", gdb_path, parent_pid);
    fflush(stderr);
    int intermediate_pid = fork();
    if (intermediate_pid < 0) {
        perror("spawn_gdb intermediate process fork: ");
    } else if (intermediate_pid == 0) {
        intermediate_process(parent_pid, gdb_path);
    } else {
        waitpid(intermediate_pid, NULL, 0);
    }
}

void
toku_try_gdb_stack_trace(const char *gdb_path) {
    char default_gdb_path[] = "/usr/bin/gdb";
    static bool started = false;
    if (RUNNING_ON_VALGRIND) {
        fprintf(stderr, "gdb stack trace skipped due to running under valgrind\n");
        fflush(stderr);
    } else if (toku_sync_bool_compare_and_swap(&started, false, true)) {
        spawn_gdb(gdb_path ? gdb_path : default_gdb_path);
    }
}

<|endoftext|>


<commit_before>#ifdef OS_LINUX
#define LIBLOADERSRC

#include "LinuxLibraryLoader.cpp"

#endif

#ifdef OS_WINDOWS
#define LIBLOADERSRC
#include "WindowsLibraryLoader.cpp"
//....
#endif

#ifndef LIBLOADERSRC
#error "no suited library loader found or system not recognized"
#endif

<commit_msg>fixed osx lib loader<commit_after>#ifdef OS_LINUX
#define LIBLOADERSRC
#include "LinuxLibraryLoader.cpp"
#endif

#ifdef OS_MACOSX
#define LIBLOADERSRC
#include "LinuxLibraryLoader.cpp"
#endif

#ifdef OS_WINDOWS
#define LIBLOADERSRC
#include "WindowsLibraryLoader.cpp"
#endif

#ifndef LIBLOADERSRC
#error "no suited library loader found or system not recognized"
#endif

<|endoftext|>


<commit_before>#include <Std.h>
#include <Definitions.h>
#include <MathFunctions.h>

///////////////////////////////////////////////////////////////////////////////

NumericType LaplasOperator( const CMatrix& matrix, const CUniformGrid& grid, size_t x, size_t y )
{
	const NumericType ldx = ( matrix( x, y ) - matrix( x - 1, y ) ) / grid.X.Step( x - 1 );
	const NumericType rdx = ( matrix( x + 1, y ) - matrix( x, y ) ) / grid.X.Step( x );
	const NumericType tdy = ( matrix( x, y ) - matrix( x, y - 1 ) ) / grid.Y.Step( y - 1 );
	const NumericType bdy = ( matrix( x, y + 1 ) - matrix( x, y ) ) / grid.Y.Step( y );
	const NumericType dx = ( ldx - rdx ) / grid.X.AverageStep( x );
	const NumericType dy = ( tdy - bdy ) / grid.Y.AverageStep( y );
	return ( dx + dy );
}

// Вычисление невязки rij во внутренних точках.
void CalcR( const CMatrix&p, const CUniformGrid& grid, CMatrix& r )
{
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			r( x, y ) = LaplasOperator( p, grid, x, y ) - F( grid.X[x], grid.Y[y] );
		}
	}
}

// Вычисление значений gij во внутренних точках.
void CalcG( const CMatrix&r, const NumericType alpha, CMatrix& g )
{
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for
	for( long x = 1; x < g.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < g.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < g.SizeY() - 1; y++ ) {
			g( x, y ) = r( x, y ) - alpha * g( x, y );
		}
	}
}

// Вычисление значений pij во внутренних точках, возвращается максимум норма.
NumericType CalcP( const CMatrix&g, const NumericType tau, CMatrix& p )
{
	NumericType difference = 0;
	for( size_t x = 1; x < p.SizeX() - 1; x++ ) {
		for( size_t y = 1; y < g.SizeY() - 1; y++ ) {
			const NumericType newValue = p( x, y ) - tau * g( x, y );
			difference = max( difference, abs( newValue - p( x, y ) ) );
			p( x, y ) = newValue;
		}
	}
	return difference;
}

// Вычисление alpha.
CFraction CalcAlpha( const CMatrix&r, const CMatrix&g, const CUniformGrid& grid )
{
	NumericType numerator = 0;
	NumericType denominator = 0;
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for reduction( +:numerator, denominator )
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			const NumericType common = g( x, y ) * grid.X.AverageStep( x ) * grid.Y.AverageStep( y );
			numerator += LaplasOperator( r, grid, x, y ) * common;
			denominator += LaplasOperator( g, grid, x, y ) * common;
		}
	}
	return CFraction( numerator, denominator );
}

// Вычисление tau.
CFraction CalcTau( const CMatrix&r, const CMatrix&g, const CUniformGrid& grid )
{
	NumericType numerator = 0;
	NumericType denominator = 0;
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for reduction( +:numerator, denominator )
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			const NumericType common = g( x, y ) * grid.X.AverageStep( x ) * grid.Y.AverageStep( y );
			numerator += r( x, y ) * common;
			denominator += LaplasOperator( g, grid, x, y ) * common;
		}
	}
	return CFraction( numerator, denominator );
}

///////////////////////////////////////////////////////////////////////////////
<commit_msg>small style changes<commit_after>#include <Std.h>
#include <Definitions.h>
#include <MathFunctions.h>

///////////////////////////////////////////////////////////////////////////////

NumericType LaplasOperator( const CMatrix& matrix, const CUniformGrid& grid, size_t x, size_t y )
{
	const NumericType ldx = ( matrix( x, y ) - matrix( x - 1, y ) ) / grid.X.Step( x - 1 );
	const NumericType rdx = ( matrix( x + 1, y ) - matrix( x, y ) ) / grid.X.Step( x );
	const NumericType tdy = ( matrix( x, y ) - matrix( x, y - 1 ) ) / grid.Y.Step( y - 1 );
	const NumericType bdy = ( matrix( x, y + 1 ) - matrix( x, y ) ) / grid.Y.Step( y );
	const NumericType dx = ( ldx - rdx ) / grid.X.AverageStep( x );
	const NumericType dy = ( tdy - bdy ) / grid.Y.AverageStep( y );
	return ( dx + dy );
}

// Вычисление невязки rij во внутренних точках.
void CalcR( const CMatrix& p, const CUniformGrid& grid, CMatrix& r )
{
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			r( x, y ) = LaplasOperator( p, grid, x, y ) - F( grid.X[x], grid.Y[y] );
		}
	}
}

// Вычисление значений gij во внутренних точках.
void CalcG( const CMatrix& r, const NumericType alpha, CMatrix& g )
{
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for
	for( long x = 1; x < g.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < g.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < g.SizeY() - 1; y++ ) {
			g( x, y ) = r( x, y ) - alpha * g( x, y );
		}
	}
}

// Вычисление значений pij во внутренних точках, возвращается максимум норма.
NumericType CalcP( const CMatrix& g, const NumericType tau, CMatrix& p )
{
	NumericType difference = 0;
	for( size_t x = 1; x < p.SizeX() - 1; x++ ) {
		for( size_t y = 1; y < g.SizeY() - 1; y++ ) {
			const NumericType newValue = p( x, y ) - tau * g( x, y );
			difference = max( difference, abs( newValue - p( x, y ) ) );
			p( x, y ) = newValue;
		}
	}
	return difference;
}

// Вычисление alpha.
CFraction CalcAlpha( const CMatrix& r, const CMatrix&g, const CUniformGrid& grid )
{
	NumericType numerator = 0;
	NumericType denominator = 0;
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for reduction( +:numerator, denominator )
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			const NumericType common = g( x, y ) * grid.X.AverageStep( x ) * grid.Y.AverageStep( y );
			numerator += LaplasOperator( r, grid, x, y ) * common;
			denominator += LaplasOperator( g, grid, x, y ) * common;
		}
	}
	return CFraction( numerator, denominator );
}

// Вычисление tau.
CFraction CalcTau( const CMatrix& r, const CMatrix&g, const CUniformGrid& grid )
{
	NumericType numerator = 0;
	NumericType denominator = 0;
#ifndef DIRCH_NO_OPENMP
#pragma omp parallel for reduction( +:numerator, denominator )
	for( long x = 1; x < r.SizeX() - 1; x++ ) {
#else
	for( size_t x = 1; x < r.SizeX() - 1; x++ ) {
#endif
		for( size_t y = 1; y < r.SizeY() - 1; y++ ) {
			const NumericType common = g( x, y ) * grid.X.AverageStep( x ) * grid.Y.AverageStep( y );
			numerator += r( x, y ) * common;
			denominator += LaplasOperator( g, grid, x, y ) * common;
		}
	}
	return CFraction( numerator, denominator );
}

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


<commit_before>#include "OpenGLTexture.h"

#include "TextureRef.h"

#ifdef WIN32
#include <GL/glew.h>
#endif

#define GL_GLEXT_PROTOTYPES

#ifdef __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#else
// #include <GLES3/gl3.h>
// #include <EGL/egl.h>
// #include <EGL/eglext.h>

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __WXMAC__
#include "OpenGL/gl.h"
#else
#include <GL/gl.h>
#endif

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif

#endif

#include <cassert>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
#ifdef __linux__
  case COMPRESSED_RG: return GL_RG8;
  case COMPRESSED_RGB: return GL_RGB5;
  case COMPRESSED_RGBA: return GL_RGBA8;
#else
  case COMPRESSED_RG: return GL_COMPRESSED_RG11_EAC;
  case COMPRESSED_RGB: return GL_COMPRESSED_RGB8_ETC2;
  case COMPRESSED_RGBA: return GL_COMPRESSED_RGBA8_ETC2_EAC;
#endif
  case LUMINANCE_ALPHA: return GL_LUMINANCE_ALPHA;
  }
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateData(const void * buffer) {
  updateData(buffer, 0, 0, getActualWidth(), getActualHeight());
}

void
OpenGLTexture::updateData(const void * buffer, unsigned int x, unsigned int y, unsigned int width, unsigned int height) {
  assert(buffer);

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));
  }

#ifdef __APPLE__
  glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#else
  glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
#endif
  if (has_mipmaps) {
    glGenerateMipmap(GL_TEXTURE_2D);
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::releaseTextures() {
  // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

  for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
    GLuint texid = *it;
    glDeleteTextures(1, &texid);
  }
  freed_textures.clear();
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}
<commit_msg>add conversion for LUMINANCE_ALPHA<commit_after>#include "OpenGLTexture.h"

#include "TextureRef.h"
#include "Image.h"

#ifdef WIN32
#include <GL/glew.h>
#endif

#define GL_GLEXT_PROTOTYPES

#ifdef __APPLE__
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>
#else
// #include <GLES3/gl3.h>
// #include <EGL/egl.h>
// #include <EGL/eglext.h>

#ifdef _WIN32
#include <windows.h>
#endif

#ifdef __WXMAC__
#include "OpenGL/gl.h"
#else
#include <GL/gl.h>
#endif

#ifdef _WIN32
#include "glext.h"
#else
#include <GL/glext.h>
#endif

#endif

#include <cassert>

using namespace std;
using namespace canvas;

size_t OpenGLTexture::total_textures = 0;
vector<unsigned int> OpenGLTexture::freed_textures;

static GLenum getOpenGLInternalFormat(InternalFormat internal_format) {
  switch (internal_format) {
  case RG8: return GL_RG8;
  case RGB565: return GL_RGB565;
  case RGBA4: return GL_RGBA4;
  case RGBA8: return GL_RGBA8;
#ifdef __linux__
  case COMPRESSED_RG: return GL_RG8;
  case COMPRESSED_RGB: return GL_RGB5;
  case COMPRESSED_RGBA: return GL_RGBA8;
#else
  case COMPRESSED_RG: return GL_COMPRESSED_RG11_EAC;
  case COMPRESSED_RGB: return GL_COMPRESSED_RGB8_ETC2;
  case COMPRESSED_RGBA: return GL_COMPRESSED_RGBA8_ETC2_EAC;
#endif
  case LUMINANCE_ALPHA: return GL_RG8;
  }
  return 0;
}

static GLenum getOpenGLFilterType(FilterMode mode) {
  switch (mode) {
  case NEAREST: return GL_NEAREST;
  case LINEAR: return GL_LINEAR;
  case LINEAR_MIPMAP_LINEAR: return GL_LINEAR_MIPMAP_LINEAR;
  }
  return 0;
}

void
OpenGLTexture::updateData(const void * buffer) {
  updateData(buffer, 0, 0, getActualWidth(), getActualHeight());
}

void
OpenGLTexture::updateData(const void * buffer, unsigned int x, unsigned int y, unsigned int width, unsigned int height) {
  assert(buffer);

  bool initialize = false;
  if (!texture_id) {
    initialize = true;
    glGenTextures(1, &texture_id);
    if (texture_id >= 1) total_textures++;
  }
  assert(texture_id >= 1);

  glBindTexture(GL_TEXTURE_2D, texture_id);

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

  bool has_mipmaps = getMinFilter() == LINEAR_MIPMAP_LINEAR;
  if (initialize) {
    // glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
    glTexStorage2D(GL_TEXTURE_2D, has_mipmaps ? getMipmapLevels() : 1, getOpenGLInternalFormat(getInternalFormat()), getActualWidth(), getActualHeight());

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getOpenGLFilterType(getMinFilter()));
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getOpenGLFilterType(getMagFilter()));
  }

  if (getInternalFormat() == LUMINANCE_ALPHA) {
    Image tmp_image(width, height, (const unsigned char *)buffer, ImageFormat::RGBA32);
    auto tmp_image2 = tmp_image.changeFormat(ImageFormat::LUMALPHA8);
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RG, GL_UNSIGNED_BYTE, tmp_image2->getData());
  } else {
#ifdef __APPLE__
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
#else
    glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, buffer);
#endif
  }
  if (has_mipmaps) {
    glGenerateMipmap(GL_TEXTURE_2D);
  }

  glBindTexture(GL_TEXTURE_2D, 0);
}

void
OpenGLTexture::releaseTextures() {
  // cerr << "DELETING TEXTURES: " << OpenGLTexture::getFreedTextures().size() << "/" << OpenGLTexture::getNumTextures() << endl;

  for (vector<unsigned int>::const_iterator it = freed_textures.begin(); it != freed_textures.end(); it++) {
    GLuint texid = *it;
    glDeleteTextures(1, &texid);
  }
  freed_textures.clear();
}

TextureRef
OpenGLTexture::createTexture(unsigned int _logical_width, unsigned int _logical_height, unsigned int _actual_width, unsigned int _actual_height, FilterMode min_filter, FilterMode mag_filter, InternalFormat _internal_format, unsigned int mipmap_levels) {
  return TextureRef(_logical_width, _logical_height, _actual_width, _actual_height, new OpenGLTexture(_logical_width, _logical_height, _actual_width, _actual_height, min_filter, mag_filter, _internal_format, mipmap_levels));
}
<|endoftext|>


<commit_before>/** @file edgeelement.cpp
 * 	@brief Класс, представляющий связь на диаграмме
 * */
#include <QtGui>
#include <QtGlobal>

#include "editorviewscene.h"

#include "uml_edgeelement.h"
#include "uml_nodeelement.h"

#include "realreporoles.h"
#include "realrepoinfo.h"

#include <math.h>

using namespace UML;

#ifndef M_PI
/** @brief Константа ПИ */
#define M_PI 3.14159265358979323846264338327950288419717
/** @brief Константа 1/ПИ */
#define M_1_PI 1/M_PI;
// Реквестирую ещё массу бозона Хиггса!
#endif //M_PI

/** @brief Индикатор перемещения связи */
// static bool moving = false;

EdgeElement::EdgeElement()
: beginning(0), ending(0), src(0), dst(0), portFrom(0), portTo(0), dragState(-1), longPart(0)
{
	setZValue(100);
	setFlag(ItemIsMovable, true);
	// FIXME: draws strangely...
	setFlag(ItemClipsToShape, false);

	m_penStyle = Qt::SolidLine;
	m_line << QPointF(0,0) << QPointF(200,60);

	m_endArrowStyle = NO_ARROW;
}

EdgeElement::~EdgeElement()
{
	if (src)
		src->delEdge(this);
	if (dst)
		dst->delEdge(this);
}

QRectF EdgeElement::boundingRect() const
{
	// return m_line.boundingRect().adjusted(-kvadratik,-kvadratik,kvadratik,kvadratik);
	return m_line.boundingRect().adjusted(-20,-20,20,20);
}

static double lineAngle(const QLineF &line)
{
	double angle = ::acos(line.dx() / line.length());
	if (line.dy() >= 0)
		angle = 2*M_PI - angle;

	return angle*180*M_1_PI;
}

void EdgeElement::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*)
{
	painter->save();
	QPen pen = painter->pen();
	pen.setColor(m_color);
	pen.setStyle(m_penStyle);
	pen.setWidth(1);
	painter->setPen(pen);
	painter->drawPolyline(m_line);
	painter->restore();

	painter->save();
	painter->translate(m_line[0]);
	painter->drawText(QPointF(10,20), m_fromMult);
	painter->rotate(90-lineAngle(QLineF(m_line[1],m_line[0])));
	drawStartArrow(painter);
	painter->restore();

	painter->save();
	painter->translate(m_line[m_line.size()-1]);
	painter->drawText(QPointF(10,20), m_toMult);
	painter->rotate(90-lineAngle(QLineF(m_line[m_line.size()-2],m_line[m_line.size()-1])));
	drawEndArrow(painter);
	painter->restore();

	if (option->state & QStyle::State_Selected) {
		painter->setBrush(Qt::SolidPattern);
		foreach( QPointF point, m_line)
		{
			QPen pen;
			QColor color;

			color.setNamedColor("#c3dcc4");
			pen.setWidth(11);
			pen.setColor(color);
			painter->setPen(pen);
			painter->drawPoint(point);

			color.setNamedColor("#465945");
			pen.setWidth(3);
			pen.setColor(color);
			painter->setPen(pen);
			painter->drawPoint(point);
		}
	}

	if ( ! m_text.isEmpty() ) {
		painter->save();
		QLineF longest(m_line[longPart],m_line[longPart+1]);
		painter->translate(m_line[longPart]);
		painter->rotate(-lineAngle(longest));

//		painter->drawText(0,-15,longest.length(),15,
//				Qt::TextSingleLine | Qt::AlignCenter, m_text);

		QTextDocument d;
		d.setHtml(m_text);
		d.setTextWidth(longest.length());
//		painter->drawRect(QRectF(0,0,longest.length(),20));
		d.drawContents(painter);

		painter->restore();
	}
}

bool canBeConnected( int linkID, int from, int to );
/*
void EdgeElement::checkConnection()
{
//	int type = this->type();
	int from = -1;
	int to = -1;

	if ( src != 0 )
		from = src->type();

	if ( dst != 0 )
		to = dst->type();

	m_color = Qt::black;
}
*/
QPainterPath EdgeElement::shape() const
{
	QPainterPath path;
	path.setFillRule(Qt::WindingFill);

	QPainterPathStroker ps;
	ps.setWidth(kvadratik);

	path.addPolygon(m_line);
	path = ps.createStroke(path);

	foreach( QPointF point, m_line) {
		path.addRect(QRectF(point-QPointF(kvadratik,kvadratik),QSizeF(kvadratik*2,kvadratik*2)));
	}

	return path;
}

int EdgeElement::getPoint( const QPointF &location )
{
	for ( int i = 0 ; i < m_line.size() ; i++ )
		if ( QRectF(m_line[i]-QPointF(kvadratik,kvadratik),QSizeF(kvadratik*2,kvadratik*2)).contains( location ) )
			return i;

	return -1;
}

void EdgeElement::updateLongestPart()
{
	qreal maxLen = 0.0;
	int maxIdx = 0;
	for ( int i = 0; i < m_line.size() - 1 ; i++ ) {
		qreal newLen = QLineF(m_line[i],m_line[i+1]).length();
		if ( newLen > maxLen ) {
			maxLen = newLen;
			maxIdx = i;
		}
	}
	longPart = maxIdx;
}

void EdgeElement::mousePressEvent ( QGraphicsSceneMouseEvent * event )
{
	dragState = -1;

	if ( isSelected() )
		dragState = getPoint( event->pos() );

	if ( dragState == -1 )
		Element::mousePressEvent(event);
}

void EdgeElement::connectToPort() {
	QAbstractItemModel *im = const_cast<QAbstractItemModel *>(dataIndex.model());

	setPos(pos()+m_line[0]);
	m_line.translate(-m_line[0]);

	moving = true;

	// Now we check whether start or end have been connected
	NodeElement *new_src = getNodeAt(m_line[0]);
	if ( new_src )
		portFrom = new_src->getPortId( mapToItem(new_src, m_line[0]) );
	else
		portFrom = -1.0;

	if ( src ) {
		src->delEdge(this);
		src = 0;
	}

	if ( portFrom >= 0.0 ) {
		src = new_src;
		src->addEdge(this);
	}

	if ( src )
		im->setData(dataIndex, src->uuid(), Unreal::krneRelationship::fromRole);
	else
		im->setData(dataIndex, 0, Unreal::krneRelationship::fromRole);

	im->setData(dataIndex, portFrom, Unreal::krneRelationship::fromPortRole);

	NodeElement *new_dst = getNodeAt(m_line[m_line.size()-1]);
	if ( new_dst )
		portTo = new_dst->getPortId( mapToItem(new_dst, m_line[m_line.size()-1]) );
	else
		portTo = -1.0;

	if ( dst ) {
		dst->delEdge(this);
		dst = 0;
	}

	if ( portTo >= 0.0 ) {
		dst = new_dst;
		dst->addEdge(this);
	}

	if ( dst )
		im->setData(dataIndex, dst->uuid(), Unreal::krneRelationship::toRole);
	else
		im->setData(dataIndex, 0, Unreal::krneRelationship::toRole);

	im->setData(dataIndex, portTo, Unreal::krneRelationship::toPortRole);

	setFlag(ItemIsMovable, !(dst||src) );

	im->setData(dataIndex, pos(), Unreal::PositionRole);
	im->setData(dataIndex, m_line.toPolygon(), Unreal::ConfigurationRole);

	moving = false;

	adjustLink();
}

void EdgeElement::mouseMoveEvent ( QGraphicsSceneMouseEvent * event )
{
	NodeElement *new_src = getNodeAt(m_line[0]);
	NodeElement *new_dst = getNodeAt(m_line[m_line.size()-1]);
	if (beginning) {
		if (beginning!=new_src) {
			beginning->setPortsVisible(false);
		}
	}
	if (ending) {
		if (ending!=new_dst) {
			ending->setPortsVisible(false);
		}
	}
	beginning = new_src;
	ending = new_dst;
	if (beginning) {
		beginning->setPortsVisible(true);
	}
	if (ending) {
		ending->setPortsVisible(true);
	}

	if ( dragState == -1 ) {
		Element::mouseMoveEvent(event);
	} else {
		prepareGeometryChange();
		m_line[dragState] = event->pos();
		updateLongestPart();
	}
}

void EdgeElement::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
{
	if ( dragState == -1 )
		Element::mouseReleaseEvent(event);
	else
		dragState = -1;
	connectToPort();
	if (beginning) {
		beginning->setPortsVisible(false);
	}
	if (ending) {
		ending->setPortsVisible(false);
	}
	// cleanup after moving/resizing
	beginning = ending = NULL;
}

NodeElement *EdgeElement::getNodeAt( const QPointF &position )
{
	foreach( QGraphicsItem *item, scene()->items(mapToScene(position)) ) {
		NodeElement *e = dynamic_cast<NodeElement *>(item);
		if ( e )
			return e;
	}
	return 0;
}

void EdgeElement::contextMenuEvent ( QGraphicsSceneContextMenuEvent * event )
{
	QMenu menu;

	QAction *addPointAction = menu.addAction("Add point");
	QAction *delPointAction = menu.addAction("Remove point");
	QAction *squarizeAction = menu.addAction("Squarize :)");

	if ( QAction *selectedAction = menu.exec(event->screenPos()) ) {
		if ( selectedAction == delPointAction ) {
			int i = getPoint( event->pos() );
			if ( i != -1 ) {
				prepareGeometryChange();
				m_line.remove(i);
				longPart = 0;
				update();
			}
		} else if ( selectedAction == addPointAction ) {
			for ( int i = 0; i < m_line.size()-1; i++ ) {
				QPainterPath path;
				QPainterPathStroker ps;
				ps.setWidth(kvadratik);

				path.moveTo(m_line[i]);
				path.lineTo(m_line[i+1]);
				if ( ps.createStroke(path).contains(event->pos()) ) {
					m_line.insert(i+1,event->pos());
					update();
					break;
				}
			}
		} else if ( selectedAction == squarizeAction ) {
			prepareGeometryChange();
			for ( int i = 0; i < m_line.size()-1; i++ ) {
				QLineF line(m_line[i],m_line[i+1]);
				if ( qAbs(line.dx()) < qAbs(line.dy()) ) {
					m_line[i+1].setX(m_line[i].x());
				} else {
					m_line[i+1].setY(m_line[i].y());
				}
			}
			adjustLink();
			update();
		}
	}
}

void EdgeElement::adjustLink()
{
	prepareGeometryChange();
	if ( src )
		m_line[0] = mapFromItem(src, src->getPortPos(portFrom) );
	if ( dst )
		m_line[m_line.size()-1] = mapFromItem(dst, dst->getPortPos(portTo) );
	updateLongestPart();
}

void EdgeElement::updateData()
{
	if (moving)
		return;

	Element::updateData();

	RealRepoInfo info;
	TypeIdType type = dataIndex.data(Unreal::TypeRole).toString();

	m_fromMult = dataIndex.data(info.roleByColumnName(type, "fromMultiplicity")).toString();
	m_toMult = dataIndex.data(info.roleByColumnName(type, "toMultiplicity")).toString();

	setPos(dataIndex.data(Unreal::PositionRole).toPointF());
	QPolygonF newLine = dataIndex.data(Unreal::ConfigurationRole).value<QPolygon>();
	if (!newLine.isEmpty())
		m_line = newLine;

	qDebug() << "from role: " << Unreal::krneRelationship::fromRole
		<< "to role: " << Unreal::krneRelationship::toRole;

	IdType uuidFrom = dataIndex.data(info.roleByColumnName(type, "from")).toString();
	IdType uuidTo = dataIndex.data(info.roleByColumnName(type, "to")).toString();

	qDebug() << "from: " << uuidFrom << ", to: " << uuidTo;

	if (src)
		src->delEdge(this);
	if (dst)
		dst->delEdge(this);

	src = dynamic_cast<NodeElement *>(static_cast<EditorViewScene *>(scene())->getElem(uuidFrom));
	dst = dynamic_cast<NodeElement *>(static_cast<EditorViewScene *>(scene())->getElem(uuidTo));

	if (src)
		src->addEdge(this);
	if (dst)
		dst->addEdge(this);

	setFlag(ItemIsMovable, !(dst || src));

	portFrom = dataIndex.data(info.roleByColumnName(type, "fromPort")).toDouble();
	portTo = dataIndex.data(info.roleByColumnName(type, "toPort")).toDouble();

	adjustLink();
}
<commit_msg>Request on Higgs Boson completed.<commit_after>/** @file edgeelement.cpp
 * 	@brief Класс, представляющий связь на диаграмме
 * */
#include <QtGui>
#include <QtGlobal>

#include "editorviewscene.h"

#include "uml_edgeelement.h"
#include "uml_nodeelement.h"

#include "realreporoles.h"
#include "realrepoinfo.h"

#include <math.h>

using namespace UML;

#ifndef M_PI
/** @brief Константа ПИ */
#define M_PI 3.14159265358979323846264338327950288419717
/** @brief Константа 1/ПИ */
#define M_1_PI 1/M_PI;
// Реквестирую ещё массу бозона Хиггса!
// Here you are: The God's particle energy (in GeV)
#define HIGGS_BOSON_MASS_APPROX 251
#endif //M_PI

/** @brief Индикатор перемещения связи */
// static bool moving = false;

EdgeElement::EdgeElement()
: beginning(0), ending(0), src(0), dst(0), portFrom(0), portTo(0), dragState(-1), longPart(0)
{
	setZValue(100);
	setFlag(ItemIsMovable, true);
	// FIXME: draws strangely...
	setFlag(ItemClipsToShape, false);

	m_penStyle = Qt::SolidLine;
	m_line << QPointF(0,0) << QPointF(200,60);

	m_endArrowStyle = NO_ARROW;
}

EdgeElement::~EdgeElement()
{
	if (src)
		src->delEdge(this);
	if (dst)
		dst->delEdge(this);
}

QRectF EdgeElement::boundingRect() const
{
	// return m_line.boundingRect().adjusted(-kvadratik,-kvadratik,kvadratik,kvadratik);
	return m_line.boundingRect().adjusted(-20,-20,20,20);
}

static double lineAngle(const QLineF &line)
{
	double angle = ::acos(line.dx() / line.length());
	if (line.dy() >= 0)
		angle = 2*M_PI - angle;

	return angle*180*M_1_PI;
}

void EdgeElement::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget*)
{
	painter->save();
	QPen pen = painter->pen();
	pen.setColor(m_color);
	pen.setStyle(m_penStyle);
	pen.setWidth(1);
	painter->setPen(pen);
	painter->drawPolyline(m_line);
	painter->restore();

	painter->save();
	painter->translate(m_line[0]);
	painter->drawText(QPointF(10,20), m_fromMult);
	painter->rotate(90-lineAngle(QLineF(m_line[1],m_line[0])));
	drawStartArrow(painter);
	painter->restore();

	painter->save();
	painter->translate(m_line[m_line.size()-1]);
	painter->drawText(QPointF(10,20), m_toMult);
	painter->rotate(90-lineAngle(QLineF(m_line[m_line.size()-2],m_line[m_line.size()-1])));
	drawEndArrow(painter);
	painter->restore();

	if (option->state & QStyle::State_Selected) {
		painter->setBrush(Qt::SolidPattern);
		foreach( QPointF point, m_line)
		{
			QPen pen;
			QColor color;

			color.setNamedColor("#c3dcc4");
			pen.setWidth(11);
			pen.setColor(color);
			painter->setPen(pen);
			painter->drawPoint(point);

			color.setNamedColor("#465945");
			pen.setWidth(3);
			pen.setColor(color);
			painter->setPen(pen);
			painter->drawPoint(point);
		}
	}

	if ( ! m_text.isEmpty() ) {
		painter->save();
		QLineF longest(m_line[longPart],m_line[longPart+1]);
		painter->translate(m_line[longPart]);
		painter->rotate(-lineAngle(longest));

//		painter->drawText(0,-15,longest.length(),15,
//				Qt::TextSingleLine | Qt::AlignCenter, m_text);

		QTextDocument d;
		d.setHtml(m_text);
		d.setTextWidth(longest.length());
//		painter->drawRect(QRectF(0,0,longest.length(),20));
		d.drawContents(painter);

		painter->restore();
	}
}

bool canBeConnected( int linkID, int from, int to );
/*
void EdgeElement::checkConnection()
{
//	int type = this->type();
	int from = -1;
	int to = -1;

	if ( src != 0 )
		from = src->type();

	if ( dst != 0 )
		to = dst->type();

	m_color = Qt::black;
}
*/
QPainterPath EdgeElement::shape() const
{
	QPainterPath path;
	path.setFillRule(Qt::WindingFill);

	QPainterPathStroker ps;
	ps.setWidth(kvadratik);

	path.addPolygon(m_line);
	path = ps.createStroke(path);

	foreach( QPointF point, m_line) {
		path.addRect(QRectF(point-QPointF(kvadratik,kvadratik),QSizeF(kvadratik*2,kvadratik*2)));
	}

	return path;
}

int EdgeElement::getPoint( const QPointF &location )
{
	for ( int i = 0 ; i < m_line.size() ; i++ )
		if ( QRectF(m_line[i]-QPointF(kvadratik,kvadratik),QSizeF(kvadratik*2,kvadratik*2)).contains( location ) )
			return i;

	return -1;
}

void EdgeElement::updateLongestPart()
{
	qreal maxLen = 0.0;
	int maxIdx = 0;
	for ( int i = 0; i < m_line.size() - 1 ; i++ ) {
		qreal newLen = QLineF(m_line[i],m_line[i+1]).length();
		if ( newLen > maxLen ) {
			maxLen = newLen;
			maxIdx = i;
		}
	}
	longPart = maxIdx;
}

void EdgeElement::mousePressEvent ( QGraphicsSceneMouseEvent * event )
{
	dragState = -1;

	if ( isSelected() )
		dragState = getPoint( event->pos() );

	if ( dragState == -1 )
		Element::mousePressEvent(event);
}

void EdgeElement::connectToPort() {
	QAbstractItemModel *im = const_cast<QAbstractItemModel *>(dataIndex.model());

	setPos(pos()+m_line[0]);
	m_line.translate(-m_line[0]);

	moving = true;

	// Now we check whether start or end have been connected
	NodeElement *new_src = getNodeAt(m_line[0]);
	if ( new_src )
		portFrom = new_src->getPortId( mapToItem(new_src, m_line[0]) );
	else
		portFrom = -1.0;

	if ( src ) {
		src->delEdge(this);
		src = 0;
	}

	if ( portFrom >= 0.0 ) {
		src = new_src;
		src->addEdge(this);
	}

	if ( src )
		im->setData(dataIndex, src->uuid(), Unreal::krneRelationship::fromRole);
	else
		im->setData(dataIndex, 0, Unreal::krneRelationship::fromRole);

	im->setData(dataIndex, portFrom, Unreal::krneRelationship::fromPortRole);

	NodeElement *new_dst = getNodeAt(m_line[m_line.size()-1]);
	if ( new_dst )
		portTo = new_dst->getPortId( mapToItem(new_dst, m_line[m_line.size()-1]) );
	else
		portTo = -1.0;

	if ( dst ) {
		dst->delEdge(this);
		dst = 0;
	}

	if ( portTo >= 0.0 ) {
		dst = new_dst;
		dst->addEdge(this);
	}

	if ( dst )
		im->setData(dataIndex, dst->uuid(), Unreal::krneRelationship::toRole);
	else
		im->setData(dataIndex, 0, Unreal::krneRelationship::toRole);

	im->setData(dataIndex, portTo, Unreal::krneRelationship::toPortRole);

	setFlag(ItemIsMovable, !(dst||src) );

	im->setData(dataIndex, pos(), Unreal::PositionRole);
	im->setData(dataIndex, m_line.toPolygon(), Unreal::ConfigurationRole);

	moving = false;

	adjustLink();
}

void EdgeElement::mouseMoveEvent ( QGraphicsSceneMouseEvent * event )
{
	NodeElement *new_src = getNodeAt(m_line[0]);
	NodeElement *new_dst = getNodeAt(m_line[m_line.size()-1]);
	if (beginning) {
		if (beginning!=new_src) {
			beginning->setPortsVisible(false);
		}
	}
	if (ending) {
		if (ending!=new_dst) {
			ending->setPortsVisible(false);
		}
	}
	beginning = new_src;
	ending = new_dst;
	if (beginning) {
		beginning->setPortsVisible(true);
	}
	if (ending) {
		ending->setPortsVisible(true);
	}

	if ( dragState == -1 ) {
		Element::mouseMoveEvent(event);
	} else {
		prepareGeometryChange();
		m_line[dragState] = event->pos();
		updateLongestPart();
	}
}

void EdgeElement::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )
{
	if ( dragState == -1 )
		Element::mouseReleaseEvent(event);
	else
		dragState = -1;
	connectToPort();
	if (beginning) {
		beginning->setPortsVisible(false);
	}
	if (ending) {
		ending->setPortsVisible(false);
	}
	// cleanup after moving/resizing
	beginning = ending = NULL;
}

NodeElement *EdgeElement::getNodeAt( const QPointF &position )
{
	foreach( QGraphicsItem *item, scene()->items(mapToScene(position)) ) {
		NodeElement *e = dynamic_cast<NodeElement *>(item);
		if ( e )
			return e;
	}
	return 0;
}

void EdgeElement::contextMenuEvent ( QGraphicsSceneContextMenuEvent * event )
{
	QMenu menu;

	QAction *addPointAction = menu.addAction("Add point");
	QAction *delPointAction = menu.addAction("Remove point");
	QAction *squarizeAction = menu.addAction("Squarize :)");

	if ( QAction *selectedAction = menu.exec(event->screenPos()) ) {
		if ( selectedAction == delPointAction ) {
			int i = getPoint( event->pos() );
			if ( i != -1 ) {
				prepareGeometryChange();
				m_line.remove(i);
				longPart = 0;
				update();
			}
		} else if ( selectedAction == addPointAction ) {
			for ( int i = 0; i < m_line.size()-1; i++ ) {
				QPainterPath path;
				QPainterPathStroker ps;
				ps.setWidth(kvadratik);

				path.moveTo(m_line[i]);
				path.lineTo(m_line[i+1]);
				if ( ps.createStroke(path).contains(event->pos()) ) {
					m_line.insert(i+1,event->pos());
					update();
					break;
				}
			}
		} else if ( selectedAction == squarizeAction ) {
			prepareGeometryChange();
			for ( int i = 0; i < m_line.size()-1; i++ ) {
				QLineF line(m_line[i],m_line[i+1]);
				if ( qAbs(line.dx()) < qAbs(line.dy()) ) {
					m_line[i+1].setX(m_line[i].x());
				} else {
					m_line[i+1].setY(m_line[i].y());
				}
			}
			adjustLink();
			update();
		}
	}
}

void EdgeElement::adjustLink()
{
	prepareGeometryChange();
	if ( src )
		m_line[0] = mapFromItem(src, src->getPortPos(portFrom) );
	if ( dst )
		m_line[m_line.size()-1] = mapFromItem(dst, dst->getPortPos(portTo) );
	updateLongestPart();
}

void EdgeElement::updateData()
{
	if (moving)
		return;

	Element::updateData();

	RealRepoInfo info;
	TypeIdType type = dataIndex.data(Unreal::TypeRole).toString();

	m_fromMult = dataIndex.data(info.roleByColumnName(type, "fromMultiplicity")).toString();
	m_toMult = dataIndex.data(info.roleByColumnName(type, "toMultiplicity")).toString();

	setPos(dataIndex.data(Unreal::PositionRole).toPointF());
	QPolygonF newLine = dataIndex.data(Unreal::ConfigurationRole).value<QPolygon>();
	if (!newLine.isEmpty())
		m_line = newLine;

	qDebug() << "from role: " << Unreal::krneRelationship::fromRole
		<< "to role: " << Unreal::krneRelationship::toRole;

	IdType uuidFrom = dataIndex.data(info.roleByColumnName(type, "from")).toString();
	IdType uuidTo = dataIndex.data(info.roleByColumnName(type, "to")).toString();

	qDebug() << "from: " << uuidFrom << ", to: " << uuidTo;

	if (src)
		src->delEdge(this);
	if (dst)
		dst->delEdge(this);

	src = dynamic_cast<NodeElement *>(static_cast<EditorViewScene *>(scene())->getElem(uuidFrom));
	dst = dynamic_cast<NodeElement *>(static_cast<EditorViewScene *>(scene())->getElem(uuidTo));

	if (src)
		src->addEdge(this);
	if (dst)
		dst->addEdge(this);

	setFlag(ItemIsMovable, !(dst || src));

	portFrom = dataIndex.data(info.roleByColumnName(type, "fromPort")).toDouble();
	portTo = dataIndex.data(info.roleByColumnName(type, "toPort")).toDouble();

	adjustLink();
}
<|endoftext|>


<commit_before>/*
Resembla: Word-based Japanese similar sentence search library
https://github.com/tuem/resembla

Copyright 2017 Takashi Uemura

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef RESEMBLA_ELIMINATOR_HPP
#define RESEMBLA_ELIMINATOR_HPP

#include <string>
#include <vector>
#include <map>

#include "string_util.hpp"

namespace resembla {

template<typename string_type, typename bitvector_type = uint64_t>
struct Eliminator
{
    using size_type = typename string_type::size_type;
    using symbol_type = typename string_type::value_type;
    using distance_type = int;

    Eliminator(string_type const& pattern = string_type())
    {
        init(pattern);
    }

    void init(string_type const& pattern)
    {
        this->pattern = pattern;
        if(pattern.empty()){
            return;
        }

        pattern_length = pattern.size();
        block_size = ((pattern_length - 1) >> bit_offset<bitvector_type>()) + 1;
        rest_bits = pattern_length - (block_size - 1) * bit_width<bitvector_type>();
        sink = bitvector_type{1} << (rest_bits - 1);

        constructPM();
        zeroes.resize(block_size, 0);
        work.resize(block_size);
    }

    void operator()(std::vector<string_type>& candidates, size_type k)
    {
        using string_distance = std::pair<string_type, distance_type>;
        std::vector<string_distance> work(candidates.size());
        size_type p = 0;
        for(const auto& c: candidates){
            work[p].first = c;
            work[p++].second = -distance(c);
        }
        std::nth_element(std::begin(work), std::begin(work) + k, std::end(work),
            [](const string_distance& a, const string_distance& b) -> bool{
                return a.second > b.second;
            });
#ifdef DEBUG
        std::cerr << "narrow " << work.size() << " strings" << std::endl;
        for(const auto& i: work){
            std::cerr << cast_string<std::string>(i.first) << ": " << i.second << std::endl;
        }
#endif
        for(size_type i = 0; i < k; ++i){
            candidates[i] = work.at(i).first;
        }
        candidates.erase(std::begin(candidates) + k, std::end(candidates));
    }

protected:
    string_type pattern;
    size_type pattern_length;
    size_type block_size;
    size_type rest_bits;
    bitvector_type sink;

    std::vector<std::pair<symbol_type, bitvector_type>> PM_sp;
    std::vector<std::pair<symbol_type, std::vector<bitvector_type>>> PM;
    std::vector<bitvector_type> zeroes;

    struct WorkData
    {
        bitvector_type D0;
        bitvector_type HP;
        bitvector_type HN;
        bitvector_type VP;
        bitvector_type VN;

        void reset()
        {
            D0 = HP = HN = VN = 0;
            VP = ~(bitvector_type{0});
        }
    };
    mutable std::vector<WorkData> work;

    template<typename Integer> static constexpr int bit_width()
    {
        return 8 * sizeof(Integer);
    }

    static constexpr int bit_offset(int w)
    {
        return w < 2 ? 0 : (bit_offset(w >> 1) + 1);
    }

    template<typename Integer> static constexpr int bit_offset()
    {
        return bit_offset(bit_width<Integer>());
    }

    template<typename key_type, typename value_type>
    const value_type& find_value(const std::vector<std::pair<key_type, value_type>>& data,
            const key_type c, const value_type& default_value) const
    {
        if(data.size() < 9){
            for(const auto& p: data){
                if(p.first == c){
                    return p.second;
                }
            }
        }
        else{
            size_type l = 0, r = data.size();
            while(l < r){
                auto i = (l + r) / 2;
                auto& p = data[i];
                if(p.first < c){
                    l = i + 1;
                }
                else if(p.first > c){
                    r = i;
                }
                else{
                    return p.second;
                }
            }
        }
        return default_value;
    }

    void constructPM()
    {
        std::map<symbol_type, std::vector<bitvector_type>> PM_work;
        for(size_type i = 0; i < block_size - 1; ++i){
            for(size_type j = 0; j < bit_width<bitvector_type>(); ++j){
                if(PM_work[pattern[i * bit_width<bitvector_type>() + j]].empty()){
                    PM_work[pattern[i * bit_width<bitvector_type>() + j]].resize(block_size, 0);
                }
                PM_work[pattern[i * bit_width<bitvector_type>() + j]][i] |= bitvector_type{1} << j;
            }
        }
        for(size_type i = 0; i < rest_bits; ++i){
            if(PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].empty()){
                PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].resize(block_size, 0);
            }
            PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].back() |= bitvector_type{1} << i;
        }

        PM.clear();
        for(const auto& p: PM_work){
            PM.push_back(p);
        }
    }

    distance_type distance_sp(string_type const &text) const
    {
        auto& w = work.front();
        w.reset();
        for(size_type i = 0; i < pattern_length; ++i){
            w.VP |= bitvector_type{1} << i;
        }

        distance_type D = pattern_length;
        for(auto c: text){
            auto X = find_value(PM, c, zeroes).front() | w.VN;

            w.D0 = ((w.VP + (X & w.VP)) ^ w.VP) | X;
            w.HP = w.VN | ~(w.VP | w.D0);
            w.HN = w.VP & w.D0;

            X = (w.HP << 1) | 1;
            w.VP = (w.HN << 1) | ~(X | w.D0);
            w.VN = X & w.D0;

            if(w.HP & sink){
                ++D;
            }
            else if(w.HN & sink){
                --D;
            }
        }
        return D;
    }

    distance_type distance_lp(string_type const &text) const
    {
        constexpr bitvector_type msb = bitvector_type{1} << (bit_width<bitvector_type>() - 1);
        for(size_type i = 0; i < block_size; ++i){
            work[i].reset();
        }
        for(size_type i = 0; i < rest_bits; ++i){
            work.back().VP |= bitvector_type{1} << i;
        }

        distance_type D = pattern_length;
        for(auto c: text){
            const auto& PMc = find_value(PM, c, zeroes);
            for(size_type r = 0; r < block_size; ++r){
                auto& w = work[r];
                auto X = PMc[r];
                if(r > 0 && (work[r - 1].HN & msb)){
                    X |= 1;
                }

                w.D0 = ((w.VP + (X & w.VP)) ^ w.VP) | X | w.VN;
                w.HP = w.VN | ~(w.VP | w.D0);
                w.HN = w.VP & w.D0;

                X = w.HP << 1;
                if(r == 0 || work[r - 1].HP & msb){
                    X |= 1;
                }
                w.VP = (w.HN << 1) | ~(X | w.D0);
                if(r > 0 && (work[r - 1].HN & msb)){
                    w.VP |= 1;
                }
                w.VN = X & w.D0;
            }

            if(work.back().HP & sink){
                ++D;
            }
            else if(work.back().HN & sink){
                --D;
            }
        }
        return D;
    }

    distance_type distance(string_type const &text) const
    {
        if(text.empty()){
            return pattern_length;
        }
        else if(pattern_length == 0){
            return text.size();
        }

        if(block_size == 1){
            return distance_sp(text);
        }
        else{
            return distance_lp(text);
        }
    }
};

}
#endif
<commit_msg>reduce copying<commit_after>/*
Resembla: Word-based Japanese similar sentence search library
https://github.com/tuem/resembla

Copyright 2017 Takashi Uemura

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef RESEMBLA_ELIMINATOR_HPP
#define RESEMBLA_ELIMINATOR_HPP

#include <string>
#include <vector>
#include <map>

#include "string_util.hpp"

namespace resembla {

template<typename string_type, typename bitvector_type = uint64_t>
struct Eliminator
{
    using size_type = typename string_type::size_type;
    using symbol_type = typename string_type::value_type;
    using distance_type = int;

    Eliminator(string_type const& pattern = string_type())
    {
        init(pattern);
    }

    void init(string_type const& pattern)
    {
        this->pattern = pattern;
        if(pattern.empty()){
            return;
        }

        pattern_length = pattern.size();
        block_size = ((pattern_length - 1) >> bit_offset<bitvector_type>()) + 1;
        rest_bits = pattern_length - (block_size - 1) * bit_width<bitvector_type>();
        sink = bitvector_type{1} << (rest_bits - 1);

        constructPM();
        zeroes.resize(block_size, 0);
        work.resize(block_size);
    }

    void operator()(std::vector<string_type>& candidates, size_type k)
    {
        using index_distance = std::pair<size_type, distance_type>;

        std::vector<index_distance> work(candidates.size());
        for(size_type i = 0; i < work.size(); ++i){
            work[i].first = i;
            work[i].second = -distance(candidates[i]);
        }

        // sort partially to obtain top-k elements
        std::nth_element(std::begin(work), std::begin(work) + k, std::end(work),
            [](const index_distance& a, const index_distance& b) -> bool{
                return a.second > b.second;
            });

        // ensure that work[i].first < work[j].first if i < j < k
        std::partial_sort(std::begin(work), std::begin(work) + k, std::begin(work) + k,
            [](const index_distance& a, const index_distance& b) -> bool{
                return a.first < b.first;
            });
#ifdef DEBUG
        std::cerr << "narrow " << work.size() << " strings" << std::endl;
        for(size_type i = 0; i < k; ++i){
            std::cerr << cast_string<std::string>(candidates[work[i].first]) << ": " << work[i].second << std::endl;
        }
#endif

        // sort original list
        for(size_type i = 0; i < k; ++i){
            std::swap(candidates[i], candidates[work[i].first]);
        }
        candidates.erase(std::begin(candidates) + k, std::end(candidates));
    }

protected:
    string_type pattern;
    size_type pattern_length;
    size_type block_size;
    size_type rest_bits;
    bitvector_type sink;

    std::vector<std::pair<symbol_type, bitvector_type>> PM_sp;
    std::vector<std::pair<symbol_type, std::vector<bitvector_type>>> PM;
    std::vector<bitvector_type> zeroes;

    struct WorkData
    {
        bitvector_type D0;
        bitvector_type HP;
        bitvector_type HN;
        bitvector_type VP;
        bitvector_type VN;

        void reset()
        {
            D0 = HP = HN = VN = 0;
            VP = ~(bitvector_type{0});
        }
    };
    mutable std::vector<WorkData> work;

    template<typename Integer> static constexpr int bit_width()
    {
        return 8 * sizeof(Integer);
    }

    static constexpr int bit_offset(int w)
    {
        return w < 2 ? 0 : (bit_offset(w >> 1) + 1);
    }

    template<typename Integer> static constexpr int bit_offset()
    {
        return bit_offset(bit_width<Integer>());
    }

    template<typename key_type, typename value_type>
    const value_type& find_value(const std::vector<std::pair<key_type, value_type>>& data,
            const key_type c, const value_type& default_value) const
    {
        if(data.size() < 9){
            for(const auto& p: data){
                if(p.first == c){
                    return p.second;
                }
            }
        }
        else{
            size_type l = 0, r = data.size();
            while(l < r){
                auto i = (l + r) / 2;
                auto& p = data[i];
                if(p.first < c){
                    l = i + 1;
                }
                else if(p.first > c){
                    r = i;
                }
                else{
                    return p.second;
                }
            }
        }
        return default_value;
    }

    void constructPM()
    {
        std::map<symbol_type, std::vector<bitvector_type>> PM_work;
        for(size_type i = 0; i < block_size - 1; ++i){
            for(size_type j = 0; j < bit_width<bitvector_type>(); ++j){
                if(PM_work[pattern[i * bit_width<bitvector_type>() + j]].empty()){
                    PM_work[pattern[i * bit_width<bitvector_type>() + j]].resize(block_size, 0);
                }
                PM_work[pattern[i * bit_width<bitvector_type>() + j]][i] |= bitvector_type{1} << j;
            }
        }
        for(size_type i = 0; i < rest_bits; ++i){
            if(PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].empty()){
                PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].resize(block_size, 0);
            }
            PM_work[pattern[(block_size - 1) * bit_width<bitvector_type>() + i]].back() |= bitvector_type{1} << i;
        }

        PM.clear();
        for(const auto& p: PM_work){
            PM.push_back(p);
        }
    }

    distance_type distance_sp(string_type const &text) const
    {
        auto& w = work.front();
        w.reset();
        for(size_type i = 0; i < pattern_length; ++i){
            w.VP |= bitvector_type{1} << i;
        }

        distance_type D = pattern_length;
        for(auto c: text){
            auto X = find_value(PM, c, zeroes).front() | w.VN;

            w.D0 = ((w.VP + (X & w.VP)) ^ w.VP) | X;
            w.HP = w.VN | ~(w.VP | w.D0);
            w.HN = w.VP & w.D0;

            X = (w.HP << 1) | 1;
            w.VP = (w.HN << 1) | ~(X | w.D0);
            w.VN = X & w.D0;

            if(w.HP & sink){
                ++D;
            }
            else if(w.HN & sink){
                --D;
            }
        }
        return D;
    }

    distance_type distance_lp(string_type const &text) const
    {
        constexpr bitvector_type msb = bitvector_type{1} << (bit_width<bitvector_type>() - 1);

        for(auto& w: work){
            w.reset();
        }
        for(size_type i = 0; i < rest_bits; ++i){
            work.back().VP |= bitvector_type{1} << i;
        }

        distance_type D = pattern_length;
        for(auto c: text){
            const auto& PMc = find_value(PM, c, zeroes);
            for(size_type r = 0; r < block_size; ++r){
                auto& w = work[r];
                auto X = PMc[r];
                if(r > 0 && (work[r - 1].HN & msb)){
                    X |= 1;
                }

                w.D0 = ((w.VP + (X & w.VP)) ^ w.VP) | X | w.VN;
                w.HP = w.VN | ~(w.VP | w.D0);
                w.HN = w.VP & w.D0;

                X = w.HP << 1;
                if(r == 0 || work[r - 1].HP & msb){
                    X |= 1;
                }
                w.VP = (w.HN << 1) | ~(X | w.D0);
                if(r > 0 && (work[r - 1].HN & msb)){
                    w.VP |= 1;
                }
                w.VN = X & w.D0;
            }

            if(work.back().HP & sink){
                ++D;
            }
            else if(work.back().HN & sink){
                --D;
            }
        }
        return D;
    }

    distance_type distance(string_type const &text) const
    {
        if(text.empty()){
            return pattern_length;
        }
        else if(pattern_length == 0){
            return text.size();
        }

        if(block_size == 1){
            return distance_sp(text);
        }
        else{
            return distance_lp(text);
        }
    }
};

}
#endif
<|endoftext|>


<commit_before>/*
 * pHashTest.cpp
 *
 *  Created on: 25 Jul 2013
 *      Author: nicholas
 */

#include <gtest/gtest.h>
#include <iostream>
#include "../../include/hash/ImagePHash.hpp"
#include <GraphicsMagick/Magick++.h>

using namespace Magick;

TEST(ImagePHashTest, hashImage) {
	ImagePHash iph;
	long pHash = iph.getLongHash("src/test/hash/testImage.jpg");
	ASSERT_EQ(7655956633439617023,pHash);
}

int main(int argc, char **argv) {
	 BasicConfigurator config;
	 config.configure();
::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

<commit_msg>Changed ImagePHash test for higher resolution (from 49 bit to 64 bit)<commit_after>/*
 * pHashTest.cpp
 *
 *  Created on: 25 Jul 2013
 *      Author: nicholas
 */

#include <gtest/gtest.h>
#include <iostream>
#include "../../include/hash/ImagePHash.hpp"
#include <GraphicsMagick/Magick++.h>

using namespace Magick;

TEST(ImagePHashTest, hashImage) {
	ImagePHash iph(32,9);
	long pHash = iph.getLongHash("src/test/hash/testImage.jpg");
	ASSERT_EQ(-2059292927385518081,pHash);
}

int main(int argc, char **argv) {
	 BasicConfigurator config;
	 config.configure();
::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

<|endoftext|>