<commit_before>//
// file : spinlock.hpp
// in : file:///home/tim/projects/yaggler/yaggler/threads/spinlock.hpp
//
// created by : Timothée Feuillet on linux-coincoin.tim
// date: 19/10/2013 05:02:34
//

#pragma once

#include <atomic>
#include <thread>
#include <new>

// Add a ton of checks on the locks, at the cost of performance
// Checks for:
//  - deadlocks
//  - invalid unlocks (both wrong ownership and already unlocked)
//  - invalid spinlock (mostly use-after-destruction)
#ifndef N_ENABLE_LOCK_DEBUG
  #define N_ENABLE_LOCK_DEBUG false
#endif

namespace neam
{
  namespace spinlock_internal
  {
#ifdef __cpp_lib_hardware_interference_size
    using std::hardware_constructive_interference_size;
    using std::hardware_destructive_interference_size;
#else
    // 64 bytes on x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ...
    constexpr std::size_t hardware_constructive_interference_size = 64;
    constexpr std::size_t hardware_destructive_interference_size = 64;
#endif
  }

  /// \brief a simple spinlock class
  class /*alignas(spinlock_internal::hardware_destructive_interference_size)*/ spinlock
  {
    public:
      spinlock() = default;
#if N_ENABLE_LOCK_DEBUG
      ~spinlock()
      {
        // poison the lock
        lock();
        owner_id = std::thread::id();
        key = k_destructed_key_value;
      }
#else
      ~spinlock() = default;
#endif
      spinlock(spinlock&) = delete;
      spinlock& operator = (spinlock&) = delete;

      /// \brief Lock the lock. Only return when the lock was acquired.
      void lock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (owner_id == std::this_thread::get_id())
        {
          printf("[spinlock: deadlock detected in lock()]\n");
          abort();
        }
#endif
        while (true)
        {
          if (try_lock())
            return;
          while (_relaxed_test());
        }
      }

      /// \brief Try to lock the lock, return whether the lock was acquired
      bool try_lock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (!lock_flag.test_and_set(std::memory_order_acquire))
        {
          owner_id = std::this_thread::get_id();
          return true;
        }
        return false;
#else
        return !lock_flag.test_and_set(std::memory_order_acquire);
#endif
      }

      /// \brief Unlock the lock
      void unlock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (!lock_flag.test())
        {
          printf("[spinlock: invalid unlock detected in unlock() (unlocking an unlocked mutex)]\n");
          abort();
        }
        if (owner_id != std::this_thread::get_id())
        {
          printf("[spinlock: invalid unlock detected in unlock() (unlocking a lock that the current thread did not lock)]\n");
          abort();
        }

        owner_id = std::thread::id();
#endif
        lock_flag.clear(std::memory_order_release);
      }

      /// \brief Does not lock the lock, simply wait for the lock to be unlocked
      /// \note marked as advaced: the lock _was_ unlocked at some point,
      ///       but this operation does not prevent any other thread to lock the lock and modify the protected data
      void _wait_for_lock() const
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (owner_id == std::this_thread::get_id())
        {
          printf("[spinlock: deadlock detected in _wait_for_lock()]\n");
          abort();
        }
#endif
        while (lock_flag.test(std::memory_order_acquire));
      }

      bool _get_state() const
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
#endif
        return lock_flag.test(std::memory_order_acquire);
      }

      bool _relaxed_test() const
      {
        return lock_flag.test(std::memory_order_relaxed);
      }

    private:
      std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;
#if N_ENABLE_LOCK_DEBUG
      std::atomic<std::thread::id> owner_id;
      static constexpr uint64_t k_key_value = 0xCACA00CACA;
      static constexpr uint64_t k_destructed_key_value = ~k_key_value;
      std::atomic<uint64_t> key = k_key_value;
      void check_for_key() const
      {
        if (key == k_destructed_key_value)
        {
          printf("[spinlock: invalid lock: trying to do operations after lock destruction]\n");
          abort();
        }
        if (key != k_key_value)
        {
          printf("[spinlock: invalid lock: memory area is not a lock]\n");
          abort();
        }

      }
#endif
  };
} // namespace neam
<commit_msg>add rw-spinlock (shared/exclusive)<commit_after>//
// file : spinlock.hpp
// in : file:///home/tim/projects/yaggler/yaggler/threads/spinlock.hpp
//
// created by : Timothée Feuillet on linux-coincoin.tim
// date: 19/10/2013 05:02:34
//

#pragma once

#include <atomic>
#include <thread>
#include <new>

// Add a ton of checks on the locks, at the cost of performance
// Checks for:
//  - deadlocks
//  - invalid unlocks (both wrong ownership and already unlocked)
//  - invalid spinlock (mostly use-after-destruction)
#ifndef N_ENABLE_LOCK_DEBUG
  #define N_ENABLE_LOCK_DEBUG false
#endif

namespace neam
{
  namespace spinlock_internal
  {
#ifdef __cpp_lib_hardware_interference_size
    using std::hardware_constructive_interference_size;
    using std::hardware_destructive_interference_size;
#else
    // 64 bytes on x86-64 │ L1_CACHE_BYTES │ L1_CACHE_SHIFT │ __cacheline_aligned │ ...
    constexpr std::size_t hardware_constructive_interference_size = 64;
    constexpr std::size_t hardware_destructive_interference_size = 64;
#endif
  }

  /// \brief a simple spinlock class
  class /*alignas(spinlock_internal::hardware_destructive_interference_size)*/ spinlock
  {
    public:
      spinlock() = default;
#if N_ENABLE_LOCK_DEBUG
      ~spinlock()
      {
        // poison the lock
        lock();
        owner_id = std::thread::id();
        key = k_destructed_key_value;
      }
#else
      ~spinlock() = default;
#endif
      spinlock(spinlock&) = delete;
      spinlock& operator = (spinlock&) = delete;

      /// \brief Lock the lock. Only return when the lock was acquired.
      void lock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (owner_id == std::this_thread::get_id())
        {
          printf("[spinlock: deadlock detected in lock()]\n");
          abort();
        }
#endif
        while (true)
        {
          if (try_lock())
            return;
          while (_relaxed_test());
        }
      }

      /// \brief Try to lock the lock, return whether the lock was acquired
      bool try_lock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (!lock_flag.test_and_set(std::memory_order_acquire))
        {
          owner_id = std::this_thread::get_id();
          return true;
        }
        return false;
#else
        return !lock_flag.test_and_set(std::memory_order_acquire);
#endif
      }

      /// \brief Unlock the lock
      void unlock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (!lock_flag.test())
        {
          printf("[spinlock: invalid unlock detected in unlock() (unlocking an unlocked mutex)]\n");
          abort();
        }
        if (owner_id != std::this_thread::get_id())
        {
          printf("[spinlock: invalid unlock detected in unlock() (unlocking a lock that the current thread did not lock)]\n");
          abort();
        }

        owner_id = std::thread::id();
#endif
        lock_flag.clear(std::memory_order_release);
      }

      /// \brief unlock the lock, but don't check if the thread has lock ownership
      void _unlock()
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (!lock_flag.test())
        {
          printf("[spinlock: invalid unlock detected in unlock() (unlocking an unlocked mutex)]\n");
          abort();
        }

        owner_id = std::thread::id();
#endif
        lock_flag.clear(std::memory_order_release);
      }

      /// \brief Does not lock the lock, simply wait for the lock to be unlocked
      /// \note marked as advaced: the lock _was_ unlocked at some point,
      ///       but this operation does not prevent any other thread to lock the lock and modify the protected data
      void _wait_for_lock() const
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
        if (owner_id == std::this_thread::get_id())
        {
          printf("[spinlock: deadlock detected in _wait_for_lock()]\n");
          abort();
        }
#endif
        while (lock_flag.test(std::memory_order_acquire))
        {
          while (_relaxed_test());
        }
      }

      bool _get_state() const
      {
#if N_ENABLE_LOCK_DEBUG
        check_for_key();
#endif
        return lock_flag.test(std::memory_order_acquire);
      }

      bool _relaxed_test() const
      {
        return lock_flag.test(std::memory_order_relaxed);
      }

    private:
      std::atomic_flag lock_flag = ATOMIC_FLAG_INIT;
#if N_ENABLE_LOCK_DEBUG
      std::atomic<std::thread::id> owner_id;
      static constexpr uint64_t k_key_value = 0xCACA00CACA;
      static constexpr uint64_t k_destructed_key_value = ~k_key_value;
      std::atomic<uint64_t> key = k_key_value;
      void check_for_key() const
      {
        if (key == k_destructed_key_value)
        {
          printf("[spinlock: invalid lock: trying to do operations after lock destruction]\n");
          abort();
        }
        if (key != k_key_value)
        {
          printf("[spinlock: invalid lock: memory area is not a lock]\n");
          abort();
        }

      }
#endif
  };

  /// \brief A simple shared spinlock that favor writers
  class shared_spinlock
  {
    public:
      bool try_lock_exclusive(bool wait_shared = true)
      {
        if (!exclusive_lock.try_lock())
        {
          return false;
        }

        if (shared_count.load(std::memory_order_seq_cst) != 0)
        {
          if (wait_shared)
          {
            do
            {
              while (shared_count.load(std::memory_order_relaxed) != 0);
            }
            while (shared_count.load(std::memory_order_acquire) != 0);
          }
          else
          {
            exclusive_lock.unlock();
            return false;
          }
        }
        return true;
      }

      void lock_exclusive()
      {
        exclusive_lock.lock();

        // wait for the shared lock to be released:
        if (shared_count.load(std::memory_order_seq_cst) != 0)
        {
          do
          {
            while (shared_count.load(std::memory_order_relaxed) != 0);
          }
          while (shared_count.load(std::memory_order_acquire) != 0);
        }
      }

      void unlock_exclusive()
      {
        exclusive_lock.unlock();
      }

      void lock_shared()
      {
        // wait for the exclusive lock to be release:
        exclusive_lock._wait_for_lock();

        // try to increment the shared lock:
        shared_count.fetch_add(1, std::memory_order_acquire);
        if (exclusive_lock._get_state())
        {
          shared_count.fetch_sub(1, std::memory_order_release);

          // we got a race condition on the lock, so we release the shared lock and try again:
          // this is not recursion.
          return lock_shared();
        }
      }

      void unlock_shared()
      {
        [[maybe_unused]] const int32_t ret = shared_count.fetch_sub(1, std::memory_order_release);
#if N_ENABLE_LOCK_DEBUG
        if (ret < 0)
        {
          printf("[shared_spinlock: invalid unlock: double/invalid shared unlock detected]\n");
          abort();
        }
#endif
      }

    private:
      spinlock exclusive_lock;
      std::atomic<int32_t> shared_count = 0;
  };

  /// \brief adapter for lock_guard (exclusive version)
  class spinlock_exclusive_adapter
  {
    public:
      static spinlock_exclusive_adapter& adapt(shared_spinlock& sl) { return reinterpret_cast<spinlock_exclusive_adapter&>(sl); }

      void lock() { reinterpret_cast<shared_spinlock*>(this)->lock_exclusive(); }
      void unlock() { reinterpret_cast<shared_spinlock*>(this)->unlock_exclusive(); }
  };

  /// \brief adapter for lock_guard (shared version)
  class spinlock_shared_adapter
  {
    public:
      static spinlock_shared_adapter& adapt(shared_spinlock& sl) { return reinterpret_cast<spinlock_shared_adapter&>(sl); }

      void lock() { reinterpret_cast<shared_spinlock*>(this)->lock_shared(); }
      void unlock() { reinterpret_cast<shared_spinlock*>(this)->unlock_shared(); }
  };
} // namespace neam
<|endoftext|>


<commit_before>/******************************************************************************\
* File:          stc.cpp
* Purpose:       Implementation of class 'ftSTC'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2008 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/filetool/filetool.h>

BEGIN_EVENT_TABLE(ftSTC, exSTC)
  EVT_MENU_RANGE(ID_STC_LOWEST, ID_STC_HIGHEST, ftSTC::OnCommand)
  EVT_MENU_RANGE(ID_TOOL_LOWEST, ID_TOOL_HIGHEST, ftSTC::OnCommand)
END_EVENT_TABLE()

#if wxUSE_DRAG_AND_DROP
class ftSTCDropTarget : public wxFileDropTarget
{
public:
  ftSTCDropTarget(ftFrame* owner) {m_Owner = owner;}
private:
  virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
  {
    ftOpenFiles(m_Owner, filenames);
    return true;
  }

  ftFrame* m_Owner;
};
#endif

ftSTC::ftSTC(wxWindow* parent,
  long type,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size,
  long style,
  const wxString& name)
  : exSTC(parent, type, wxEmptyString, id, pos, size, style, name)
{
  Initialize();
}

ftSTC::ftSTC(wxWindow* parent,
  const exFileName& filename,
  int line_number,
  const wxString& match,
  long flags,
  long type,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size,
  long style,
  const wxString& name)
  : exSTC(parent, filename, line_number, match, flags, type, id, pos, size, style, name)
{
  if (Initialize())
  {
    m_Frame->SetRecentFile(GetFileName().GetFullPath());
  }
}

ftSTC::ftSTC(const ftSTC& stc)
  : exSTC(stc)
{
  m_Frame = stc.m_Frame;
}

void ftSTC::BuildPopupMenu(exMenu& menu)
{
  exSTC::BuildPopupMenu(menu);

  // Add tools if we have at least some text, the tool flag,
  // and a lexer.
  if (GetSelectedText().empty() && GetTextLength() > 0 &&
     (GetMenuFlags() & STC_MENU_TOOL) &&
      !GetFileName().GetLexer().GetScintillaLexer().empty())
  {
    menu.AppendSeparator();
    menu.AppendTools(ID_STC_TOOL_MENU);
  }

  if (GetMenuFlags() & (STC_MENU_REPORT_FIND | STC_MENU_REPORT_REPLACE))
  {
    menu.AppendSeparator();

    if (GetMenuFlags() & STC_MENU_REPORT_FIND)
    {
      menu.Append(ID_STC_FIND_FILES, exEllipsed(_("Find &In Files")));
    }

    if (GetMenuFlags() & STC_MENU_REPORT_REPLACE)
    {
      menu.Append(ID_STC_REPLACE_FILES, exEllipsed(_("&Replace In Files")));
    }
  }

  if (m_FileName.FileExists() && GetSelectedText().empty())
  {
    if (GetMenuFlags() & STC_MENU_COMPARE)
    {
      menu.AppendSeparator();

      if (exApp::GetConfigBool("RCS/Local"))
      {
        menu.Append(ID_STC_COMPARE, exEllipsed(_("&Compare Recent Version")));
      }
      else
      {
        menu.Append(ID_STC_SVN_DIFF, exEllipsed(_("&diff")));
        menu.Append(ID_STC_SVN_LOG, exEllipsed(_("&log")));
        menu.Append(ID_STC_SVN_CAT, exEllipsed(_("&cat")));
      }
    }
  }
}

bool ftSTC::Initialize()
{
  wxWindow* window = wxTheApp->GetTopWindow();
  m_Frame = wxDynamicCast(window, ftFrame);

  if (m_Frame == NULL)
  {
    wxLogError("Cannot initialize ftSTC without ftFrame");
    return false;
  }

#if wxUSE_DRAG_AND_DROP
  // Now DnD normal text inside the editor does not work.
  // Adding a wxTextDropTarget works a little, but does not move text.
  SetDropTarget(new ftSTCDropTarget(m_Frame));
#endif

  return true;
}

void ftSTC::OnCommand(wxCommandEvent& command)
{
  if (!Continue())
  {
    return;
  }

  if (command.GetId() > ID_TOOL_LOWEST && command.GetId() < ID_TOOL_HIGHEST)
  {
    const exTool tool(command.GetId());

    if (ftTextFile::SetupTool(tool))
    {
      ftTextFile report(m_FileName);
      report.RunTool();
      report.GetStatistics().Log();
    }

    return;
  }

  switch (command.GetId())
  {
  case ID_STC_COMPARE:
    {
      wxFileName lastfile;
      if (ftFindOtherFileName(m_FileName, NULL, &lastfile))
        ftCompareFile(m_FileName, lastfile);
    }
    break;

  case ID_STC_SVN_DIFF: exSvnDialog(SVN_DIFF, m_FileName.GetFullPath()); break;
  case ID_STC_SVN_LOG: exSvnDialog(SVN_LOG, m_FileName.GetFullPath()); break;

  case ID_STC_FIND_FILES:
    GetSearchText();
    ftFindInFiles(m_Frame);
    break;

  case ID_STC_REPLACE_FILES:
    GetSearchText();
    ftFindInFiles(m_Frame, true);
    break;

  default: wxLogError(FILE_INFO("Unhandled"));
    break;
  }
}

bool ftSTC::Open(
  const exFileName& filename,
  int line_number,
  const wxString& match,
  long flags)
{
  bool retValue;

  if (flags & (STC_OPEN_FROM_LINK | STC_OPEN_FROM_STATISTICS))
  {
    retValue = m_Frame->OpenFile(filename, line_number, match, flags);
  }
  else
  {
    retValue = exSTC::Open(filename, line_number, match, flags);

    if (retValue)
    {
      m_Frame->SetRecentFile(filename.GetFullPath());
    }
  }

  return retValue;
}

void ftSTC::PropertiesMessage()
{
  exSTC::PropertiesMessage();

  const wxString ro = (m_FileName.GetStat().IsReadOnly() ?
    " [" + _("Readonly") + "]":
    wxString(wxEmptyString));

  m_Frame->SetTitle(m_FileName.GetFullPath() + ro, wxEmptyString);
}
<commit_msg>fixed error<commit_after>/******************************************************************************\
* File:          stc.cpp
* Purpose:       Implementation of class 'ftSTC'
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id$
*
* Copyright (c) 1998-2008 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/filetool/filetool.h>

BEGIN_EVENT_TABLE(ftSTC, exSTC)
  EVT_MENU_RANGE(ID_STC_LOWEST, ID_STC_HIGHEST, ftSTC::OnCommand)
  EVT_MENU_RANGE(ID_TOOL_LOWEST, ID_TOOL_HIGHEST, ftSTC::OnCommand)
END_EVENT_TABLE()

#if wxUSE_DRAG_AND_DROP
class ftSTCDropTarget : public wxFileDropTarget
{
public:
  ftSTCDropTarget(ftFrame* owner) {m_Owner = owner;}
private:
  virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames)
  {
    ftOpenFiles(m_Owner, filenames);
    return true;
  }

  ftFrame* m_Owner;
};
#endif

ftSTC::ftSTC(wxWindow* parent,
  long type,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size,
  long style,
  const wxString& name)
  : exSTC(parent, type, wxEmptyString, id, pos, size, style, name)
{
  Initialize();
}

ftSTC::ftSTC(wxWindow* parent,
  const exFileName& filename,
  int line_number,
  const wxString& match,
  long flags,
  long type,
  wxWindowID id,
  const wxPoint& pos,
  const wxSize& size,
  long style,
  const wxString& name)
  : exSTC(parent, filename, line_number, match, flags, type, id, pos, size, style, name)
{
  if (Initialize())
  {
    m_Frame->SetRecentFile(GetFileName().GetFullPath());
  }
}

ftSTC::ftSTC(const ftSTC& stc)
  : exSTC(stc)
{
  m_Frame = stc.m_Frame;
}

void ftSTC::BuildPopupMenu(exMenu& menu)
{
  exSTC::BuildPopupMenu(menu);

  // Add tools if we have at least some text, the tool flag,
  // and a lexer.
  if (GetSelectedText().empty() && GetTextLength() > 0 &&
     (GetMenuFlags() & STC_MENU_TOOL) &&
      !GetFileName().GetLexer().GetScintillaLexer().empty())
  {
    menu.AppendSeparator();
    menu.AppendTools(ID_STC_TOOL_MENU);
  }

  if (GetMenuFlags() & (STC_MENU_REPORT_FIND | STC_MENU_REPORT_REPLACE))
  {
    menu.AppendSeparator();

    if (GetMenuFlags() & STC_MENU_REPORT_FIND)
    {
      menu.Append(ID_STC_FIND_FILES, exEllipsed(_("Find &In Files")));
    }

    if (GetMenuFlags() & STC_MENU_REPORT_REPLACE)
    {
      menu.Append(ID_STC_REPLACE_FILES, exEllipsed(_("&Replace In Files")));
    }
  }

  if (m_FileName.FileExists() && GetSelectedText().empty())
  {
    if (GetMenuFlags() & STC_MENU_COMPARE)
    {
      menu.AppendSeparator();

      if (exApp::GetConfigBool("RCS/Local"))
      {
        menu.Append(ID_STC_COMPARE, exEllipsed(_("&Compare Recent Version")));
      }
      else
      {
        menu.Append(ID_STC_SVN_DIFF, exEllipsed(_("&diff")));
        menu.Append(ID_STC_SVN_LOG, exEllipsed(_("&log")));
        menu.Append(ID_STC_SVN_CAT, exEllipsed(_("&cat")));
      }
    }
  }
}

bool ftSTC::Initialize()
{
  wxWindow* window = wxTheApp->GetTopWindow();
  m_Frame = wxDynamicCast(window, ftFrame);

  if (m_Frame == NULL)
  {
    wxLogError("Cannot initialize ftSTC without ftFrame");
    return false;
  }

#if wxUSE_DRAG_AND_DROP
  // Now DnD normal text inside the editor does not work.
  // Adding a wxTextDropTarget works a little, but does not move text.
  SetDropTarget(new ftSTCDropTarget(m_Frame));
#endif

  return true;
}

void ftSTC::OnCommand(wxCommandEvent& command)
{
  if (!Continue())
  {
    return;
  }

  if (command.GetId() > ID_TOOL_LOWEST && command.GetId() < ID_TOOL_HIGHEST)
  {
    const exTool tool(command.GetId());

    if (ftTextFile::SetupTool(tool))
    {
      ftTextFile report(m_FileName);
      report.RunTool();
      report.GetStatistics().Log();
    }

    return;
  }

  switch (command.GetId())
  {
  case ID_STC_COMPARE:
    {
      wxFileName lastfile;
      if (ftFindOtherFileName(m_FileName, NULL, &lastfile))
        ftCompareFile(m_FileName, lastfile);
    }
    break;

  case ID_STC_SVN_CAT: exSvnDialog(SVN_CAT, m_FileName.GetFullPath()); break;
  case ID_STC_SVN_DIFF: exSvnDialog(SVN_DIFF, m_FileName.GetFullPath()); break;
  case ID_STC_SVN_LOG: exSvnDialog(SVN_LOG, m_FileName.GetFullPath()); break;

  case ID_STC_FIND_FILES:
    GetSearchText();
    ftFindInFiles(m_Frame);
    break;

  case ID_STC_REPLACE_FILES:
    GetSearchText();
    ftFindInFiles(m_Frame, true);
    break;

  default: wxLogError(FILE_INFO("Unhandled"));
    break;
  }
}

bool ftSTC::Open(
  const exFileName& filename,
  int line_number,
  const wxString& match,
  long flags)
{
  bool retValue;

  if (flags & (STC_OPEN_FROM_LINK | STC_OPEN_FROM_STATISTICS))
  {
    retValue = m_Frame->OpenFile(filename, line_number, match, flags);
  }
  else
  {
    retValue = exSTC::Open(filename, line_number, match, flags);

    if (retValue)
    {
      m_Frame->SetRecentFile(filename.GetFullPath());
    }
  }

  return retValue;
}

void ftSTC::PropertiesMessage()
{
  exSTC::PropertiesMessage();

  const wxString ro = (m_FileName.GetStat().IsReadOnly() ?
    " [" + _("Readonly") + "]":
    wxString(wxEmptyString));

  m_Frame->SetTitle(m_FileName.GetFullPath() + ro, wxEmptyString);
}
<|endoftext|>


<commit_before>#include <UnitTest++/UnitTest++.h>

#include <memory>
#include <sstream>
#include <utility>

#include "Article.h"
#include "JsonSerializer.h"

SUITE(ArticleJsonSerializerTests)
{
  using namespace WikiWalker;

  TEST(WriteUnanalyzedArticleWithoutLinks_LinksIsNull)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;
    ac.add(std::make_shared<Article>("Farm"));

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Farm":{"forward_links":null}})", oss.str());
  }

  TEST(WriteAnalyzedArticleWithoutLinks_LinksIsEmptyArray)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    auto a = std::make_shared<Article>("Farm");
    ac.add(a);
    a->analyzed(true);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Farm":{"forward_links":[]}})", oss.str());
  }

  TEST(WriteArticleWithOneLink)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    // yes, only a is inserted, since we want to emulate article-only
    auto a = std::make_shared<Article>("Farm");
    ac.add(a);

    auto linked = std::make_shared<Article>("Animal");
    a->addLink(linked);

    atj.serialize(ac, oss);
    CHECK_EQUAL(R"({"Farm":{"forward_links":["Animal"]}})", oss.str());
  }

  TEST(WriteArticleWithMultipleLinks)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    // yes, only a is inserted, since we want to emulate article-only
    auto a = std::make_shared<Article>("Farm");
    ac.add(a);

    auto al1 = std::make_shared<Article>("Animal"),
         al2 = std::make_shared<Article>("Pig"),
         al3 = std::make_shared<Article>("Equality");

    a->addLink(al1);
    a->addLink(al2);
    a->addLink(al3);

    atj.serialize(ac, oss);

    CHECK_EQUAL(
        R"({"Farm":{"forward_links":["Animal","Pig","Equality"]}})", oss.str());
  }

  TEST(WriteEmptyArticleCollection)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    atj.serialize(ac, oss);

    CHECK_EQUAL("{}", oss.str());
  }

  TEST(WriteArticleCollection_OneUnanalyzedArticleWithoutLinks_LinksIsNull)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto linked = std::make_shared<Article>("Foo");
    ac.add(linked);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Foo":{"forward_links":null}})", oss.str());
  }

  TEST(WriteArticleCollection_OneAnalyzedArticleWithoutLinks_LinksIsEmptyArray)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto a = std::make_shared<Article>("Foo");
    a->analyzed(true);
    ac.add(a);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Foo":{"forward_links":[]}})", oss.str());
  }

  TEST(
      WriteArticleCollection_MultipleArticles_WithMultipleLinks_MatchesExpected)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto a = std::make_shared<Article>("Foo");
    auto b = std::make_shared<Article>("Bar");
    auto c = std::make_shared<Article>("Baz");
    a->addLink(b);
    b->addLink(a);
    b->addLink(c);
    ac.add(a);
    ac.add(b);
    ac.add(c);

    atj.serialize(ac, oss);

    CHECK_EQUAL(
        R"({"Bar":{"forward_links":["Foo","Baz"]})"
        R"(,"Baz":{"forward_links":null},"Foo":{"forward_links":["Bar"]}})",
        oss.str());
  }
}
<commit_msg>Add serialization test with weak_ptr out of scope<commit_after>#include <UnitTest++/UnitTest++.h>

#include <memory>
#include <sstream>
#include <utility>

#include "Article.h"
#include "JsonSerializer.h"

SUITE(ArticleJsonSerializerTests)
{
  using namespace WikiWalker;

  TEST(WriteUnanalyzedArticleWithoutLinks_LinksIsNull)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;
    ac.add(std::make_shared<Article>("Farm"));

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Farm":{"forward_links":null}})", oss.str());
  }

  TEST(WriteAnalyzedArticleWithoutLinks_LinksIsEmptyArray)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    auto a = std::make_shared<Article>("Farm");
    ac.add(a);
    a->analyzed(true);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Farm":{"forward_links":[]}})", oss.str());
  }

  TEST(WriteArticleWithOneLink)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    // yes, only a is inserted, since we want to emulate article-only
    auto a = std::make_shared<Article>("Farm");
    ac.add(a);

    auto linked = std::make_shared<Article>("Animal");
    a->addLink(linked);

    atj.serialize(ac, oss);
    CHECK_EQUAL(R"({"Farm":{"forward_links":["Animal"]}})", oss.str());
  }

  TEST(WriteArticleWithMultipleLinks)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    // yes, only a is inserted, since we want to emulate article-only
    auto a = std::make_shared<Article>("Farm");
    ac.add(a);

    auto al1 = std::make_shared<Article>("Animal"),
         al2 = std::make_shared<Article>("Pig"),
         al3 = std::make_shared<Article>("Equality");

    a->addLink(al1);
    a->addLink(al2);
    a->addLink(al3);

    atj.serialize(ac, oss);

    CHECK_EQUAL(
        R"({"Farm":{"forward_links":["Animal","Pig","Equality"]}})", oss.str());
  }

  TEST(WriteEmptyArticleCollection)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    atj.serialize(ac, oss);

    CHECK_EQUAL("{}", oss.str());
  }

  TEST(WriteArticleCollection_OneUnanalyzedArticleWithoutLinks_LinksIsNull)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto linked = std::make_shared<Article>("Foo");
    ac.add(linked);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Foo":{"forward_links":null}})", oss.str());
  }

  TEST(WriteArticleCollection_OneAnalyzedArticleWithoutLinks_LinksIsEmptyArray)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto a = std::make_shared<Article>("Foo");
    a->analyzed(true);
    ac.add(a);

    atj.serialize(ac, oss);

    CHECK_EQUAL(R"({"Foo":{"forward_links":[]}})", oss.str());
  }

  TEST(
      WriteArticleCollection_MultipleArticles_WithMultipleLinks_MatchesExpected)
  {
    JsonSerializer atj;
    ArticleCollection ac;
    std::ostringstream oss;

    auto a = std::make_shared<Article>("Foo");
    auto b = std::make_shared<Article>("Bar");
    auto c = std::make_shared<Article>("Baz");
    a->addLink(b);
    b->addLink(a);
    b->addLink(c);
    ac.add(a);
    ac.add(b);
    ac.add(c);

    atj.serialize(ac, oss);

    CHECK_EQUAL(
        R"({"Bar":{"forward_links":["Foo","Baz"]})"
        R"(,"Baz":{"forward_links":null},"Foo":{"forward_links":["Bar"]}})",
        oss.str());
  }

  TEST(SerializeArticleWithNullptr_NotSureHowToHandleYet)
  {
    JsonSerializer atj;
    std::ostringstream oss;
    ArticleCollection ac;

    // yes, only a is inserted, since we want to emulate article-only
    auto a = std::make_shared<Article>("Farm");
    ac.add(a);

    {
      // what will happen when this goes out of scope?
      auto linked = std::make_shared<Article>("Animal");
      a->addLink(linked);
    }

    atj.serialize(ac, oss);

    // deliberately fail the test
    CHECK_EQUAL(R"({"Farm":{"forward_links":[ /* ???? */ ]}})", oss.str());
  }
}
<|endoftext|>


<commit_before>///
/// @file   LogarithmicIntegral.cpp
/// @brief  Test the offset logarithmic integral function
///         Li(x) = li(x) - li(2)
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>

#include <stdint.h>
#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;
using namespace primecount;

vector<int64_t> offset_Li =
{
                     5, // Li(10^1)
                    29, // Li(10^2)
                   176, // Li(10^3)
                  1245, // Li(10^4)
                  9628, // Li(10^5)
                 78626, // Li(10^6)
                664917, // Li(10^7)
               5762208, // Li(10^8)
              50849233, // Li(10^9)
             455055613, // Li(10^10)
          4118066399ll, // Li(10^11)
         37607950279ll, // Li(10^12)
        346065645809ll, // Li(10^13)
       3204942065690ll, // Li(10^14)
      29844571475286ll, // Li(10^15)
     279238344248555ll, // Li(10^16)
    2623557165610820ll  // Li(10^17)
};

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  for (size_t i = 0; i < offset_Li.size(); i++)
  {
    int64_t x = ipow(10ll, i + 1);
    cout << "Li(" << x << ") = " << Li(x);
    check(Li(x) == offset_Li[i]);
  }

  for (size_t i = 0; i < offset_Li.size(); i++)
  {
    int64_t x = ipow(10ll, i + 1);
    cout << "Li_inverse(" << offset_Li[i] << ") = " << Li_inverse(offset_Li[i]);
    check(Li_inverse(offset_Li[i]) <= x &&
          Li_inverse(offset_Li[i] + 1) > x);
  }

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<commit_msg>Fix MSVC issue<commit_after>///
/// @file   LogarithmicIntegral.cpp
/// @brief  Test the offset logarithmic integral function
///         Li(x) = li(x) - li(2)
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount-internal.hpp>

#include <stdint.h>
#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;
using namespace primecount;

vector<int64_t> Li_table =
{
                     5, // Li(10^1)
                    29, // Li(10^2)
                   176, // Li(10^3)
                  1245, // Li(10^4)
                  9628, // Li(10^5)
                 78626, // Li(10^6)
                664917, // Li(10^7)
               5762208, // Li(10^8)
              50849233, // Li(10^9)
             455055613, // Li(10^10)
          4118066399ll, // Li(10^11)
         37607950279ll, // Li(10^12)
        346065645809ll, // Li(10^13)
       3204942065690ll, // Li(10^14)
      29844571475286ll, // Li(10^15)
     279238344248555ll, // Li(10^16)
    2623557165610820ll  // Li(10^17)
};

void check(bool OK)
{
  cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    exit(1);
}

int main()
{
  size_t size = 15;

  if (sizeof(long double) > 8)
    size = Li_table.size();

  for (size_t i = 0; i < size; i++)
  {
    int64_t x = ipow(10ll, i + 1);
    cout << "Li(" << x << ") = " << Li(x);
    check(Li(x) == Li_table[i]);
  }

  for (size_t i = 0; i < size; i++)
  {
    int64_t x = ipow(10ll, i + 1);
    cout << "Li_inverse(" << Li_table[i] << ") = " << Li_inverse(Li_table[i]);
    check(Li_inverse(Li_table[i]) <= x &&
          Li_inverse(Li_table[i] + 1) > x);
  }

  cout << endl;
  cout << "All tests passed successfully!" << endl;

  return 0;
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -std=c++11 -ast-dump %s 2>&1 | FileCheck %s

char c8[] = u8"test\0\\\"\t\a\b\234";
// CHECK: char c8[12] = (StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234")

char16_t c16[] = u"test\0\\\"\t\a\b\234\u1234";
// CHECK: char16_t c16[13] = (StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234")

char32_t c32[] = U"test\0\\\"\t\a\b\234\u1234\U0010ffff"; // \
// CHECK: char32_t c32[14] = (StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF")

wchar_t wc[] = L"test\0\\\"\t\a\b\234\u1234\xffffffff"; // \
// CHECK: wchar_t wc[14] = (StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF")
<commit_msg>Remove unnecessary output redirection in a test.<commit_after>// RUN: %clang_cc1 -std=c++11 -ast-dump %s | FileCheck %s

char c8[] = u8"test\0\\\"\t\a\b\234";
// CHECK: char c8[12] = (StringLiteral {{.*}} lvalue u8"test\000\\\"\t\a\b\234")

char16_t c16[] = u"test\0\\\"\t\a\b\234\u1234";
// CHECK: char16_t c16[13] = (StringLiteral {{.*}} lvalue u"test\000\\\"\t\a\b\234\u1234")

char32_t c32[] = U"test\0\\\"\t\a\b\234\u1234\U0010ffff"; // \
// CHECK: char32_t c32[14] = (StringLiteral {{.*}} lvalue U"test\000\\\"\t\a\b\234\u1234\U0010FFFF")

wchar_t wc[] = L"test\0\\\"\t\a\b\234\u1234\xffffffff"; // \
// CHECK: wchar_t wc[14] = (StringLiteral {{.*}} lvalue L"test\000\\\"\t\a\b\234\x1234\xFFFFFFFF")
<|endoftext|>


<commit_before>#include <cybozu/test.hpp>
#include <cybozu/sucvector.hpp>
#include <cybozu/xorshift.hpp>
#include <time.h>

uint64_t select64n(uint64_t v, size_t n)
{
	n++;
	size_t count = 0;
	for (int i = 0; i < 64; i++) {
		if (v & (uint64_t(1) << i))
			count++;
		if (count == n)
			return i;
	}
	return 64;
}

uint64_t rank(const cybozu::SucVector& v, bool b, size_t n)
{
	uint64_t ret = 0;
	for (size_t i = 0; i < n; i++) {
		if (v.get(i) == b) {
			ret++;
		}
	}
	return ret;
}

uint64_t select(const cybozu::SucVector& v, bool b, size_t n)
{
	n++;
	for (size_t i = 0; i < v.size(); i++) {
		if (v.get(i) == b) n--;
		if (n == 0) return i;
	}
	return cybozu::NotFound;
}

CYBOZU_TEST_AUTO(testall)
{
	cybozu::XorShift rg;
	const size_t N = 30;
	std::vector<uint64_t> v;
	v.resize(N);
	for (size_t i = 0; i < N; i++) {
		v[i] = rg.get64();
	}
	cybozu::SucVector sv;
	sv.init(&v[0], v.size() * 64);
	for (size_t i = 0; i < sv.size(); i++) {
		CYBOZU_TEST_EQUAL(sv.rank(true, i), rank(sv, true, i));
		CYBOZU_TEST_EQUAL(sv.rank(false, i), rank(sv, false, i));
		CYBOZU_TEST_EQUAL(sv.select(true, i), select(sv, true, i));
		CYBOZU_TEST_EQUAL(sv.select(false, i), select(sv, false, i));
	}
}

CYBOZU_TEST_AUTO(test0)
{
	cybozu::SucVector sv;
	uint64_t blk = 722;
	sv.init(&blk, 64); // 0100101101
	CYBOZU_TEST_EQUAL(sv.rank(1, 6), 2u);
	CYBOZU_TEST_EQUAL(sv.select(0, 4), 8u);
}

CYBOZU_TEST_AUTO(select)
{
	const uint64_t v[] = {
		0xdca345ea1b5116e6ULL,
		0x951049aad88d00b0ULL,
		0x1ec7825e8db24146ULL,
		0x9af814432ac00f2cULL,
		0xffffffffffffffffULL,
		0x242342afecbfe4aaULL,
		0xffffffffffffffffULL,
		0xf324987abcef3242ULL
	};
	const size_t bitLen = sizeof(v) * 8;
	cybozu::SucVector sv;
	sv.init(v, bitLen);
	for (int s = 0; s < 2; s++) {
		const bool b = s == 0;
		const size_t max = sv.rank(b, bitLen);
		for (size_t r = 0; r < max; r++) {
			CYBOZU_TEST_EQUAL(sv.select(b, r), select(sv, b, r));
			CYBOZU_TEST_EQUAL(sv.rank(b, sv.select(b, r) + 1), r + 1);
		}
	}
}

CYBOZU_TEST_AUTO(relation)
{
	const uint64_t v = 0x242342afecbfe4aaULL;
	const size_t max = cybozu::popcnt<uint64_t>(v);
	for (size_t r = 0; r < max; r++) {
		CYBOZU_TEST_EQUAL(cybozu::sucvector_util::rank64(v, cybozu::sucvector_util::select64(v, r) + 1), r);
		CYBOZU_TEST_EQUAL(cybozu::sucvector_util::rank64(v, cybozu::sucvector_util::select64(v, r + 1) + 1), r + 1);
	}
}

CYBOZU_TEST_AUTO(rank)
{
	cybozu::SucVector sv;
	uint64_t blk = 6;
	sv.init(&blk, 64); // 0b0110
	const struct {
		bool val;
		uint32_t rank0;
		uint32_t rank1;
	} tbl [] = {
		{ 0, 1, 0 },
		{ 1, 1, 1 },
		{ 1, 1, 2 },
		{ 0, 2, 2 },
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		CYBOZU_TEST_EQUAL(sv.rank0(i + 1), tbl[i].rank0);
		CYBOZU_TEST_EQUAL(sv.rank1(i + 1), tbl[i].rank1);
		CYBOZU_TEST_EQUAL(sv.get(i), tbl[i].val);
	}
}

bool get(const uint64_t *blk, size_t pos)
{
	size_t q = pos / 64;
	size_t r = pos & 63;
	return ((blk[q] >> r) & 1) != 0;
}

uint32_t count(const uint64_t *blk, size_t pos)
{
	uint32_t ret = 0;
	for (size_t i = 0; i < pos; i++) {
		if (get(blk, i)) ret++;
	}
	return ret;
}

CYBOZU_TEST_AUTO(get)
{
	uint64_t tbl[] = {
		0x1234567812345678ULL, 0xffffffffffffffffULL, 0x1020304050607080ULL,
		0x3172039874192874ULL, 0x0000000000000000ULL, 0xfeabcbfeacbefaaeULL,
		0xfefefefefefefeefULL, 0x1864192836419823ULL, 0xaaaaaaaaaaaaaaaaULL,
	};
	const size_t tblNum = CYBOZU_NUM_OF_ARRAY(tbl);
	cybozu::SucVector sv;
	sv.init(tbl, tblNum * 64);
	for (size_t i = 0; i < tblNum * 64; i++) {
		CYBOZU_TEST_EQUAL(sv.get(i), get(tbl, i));
		CYBOZU_TEST_EQUAL(sv.rank1(i), count(tbl, i));
	}
	CYBOZU_TEST_EQUAL(sv.rank0(tblNum * 64), sv.getNum(0));
	CYBOZU_TEST_EQUAL(sv.rank1(tblNum * 64), sv.getNum(1));
}

/*
	compare speed
	from https://code.google.com/p/shellinford/source/browse/trunk/src/shellinford_bit_vector.cc
*/
inline uint64_t select64C(uint64_t x, uint64_t i)
{
	uint64_t x1 = ((x  & 0xaaaaaaaaaaaaaaaaULL) >>  1) + (x  & 0x5555555555555555ULL);
	uint64_t x2 = ((x1 & 0xccccccccccccccccULL) >>  2) + (x1 & 0x3333333333333333ULL);
	uint64_t x3 = ((x2 & 0xf0f0f0f0f0f0f0f0ULL) >>  4) + (x2 & 0x0f0f0f0f0f0f0f0fULL);
	uint64_t x4 = ((x3 & 0xff00ff00ff00ff00ULL) >>  8) + (x3 & 0x00ff00ff00ff00ffULL);
	uint64_t x5 = ((x4 & 0xffff0000ffff0000ULL) >> 16) + (x4 & 0x0000ffff0000ffffULL);
	i++;
	uint64_t pos = 0;
	uint64_t v5 = x5 & 0xffffffffULL;
	if (i > v5) { i -= v5; pos += 32; }
	uint64_t v4 = (x4 >> pos) & 0x0000ffffULL;
	if (i > v4) { i -= v4; pos += 16; }
	uint64_t v3 = (x3 >> pos) & 0x000000ffULL;
	if (i > v3) { i -= v3; pos +=  8; }
	uint64_t v2 = (x2 >> pos) & 0x0000000fULL;
	if (i > v2) { i -= v2; pos +=  4; }
	uint64_t v1 = (x1 >> pos) & 0x00000003ULL;
	if (i > v1) { i -= v1; pos +=  2; }
	uint64_t v0 = (x  >> pos) & 0x00000001ULL;
	if (i > v0) { i -= v0; pos +=  1; }
	return pos;
}

CYBOZU_TEST_AUTO(select8)
{
	const uint32_t s = 18;
	for (uint32_t v = 0; v < (1 << s); v++) {
		for (uint32_t x = 0; x < s; x++) {
			uint64_t a = cybozu::sucvector_util::select64(v, x + 1);
//			uint64_t a = select64n(v, x);
			uint64_t b = select64C(v, x);
			if (a < 64) {
				CYBOZU_TEST_EQUAL(a, b);
			}
		}
	}
}

CYBOZU_TEST_AUTO(select64)
{
	uint64_t tbl[] = {
		0xf0f0f0f0f0f030eeULL,
		0x0000000000000006ULL,
		0x0000000000000000ULL,
		0x0000000000000001ULL,
		0x9190751837459273ULL,
		0xffffffffffffffffULL,
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		uint64_t v = tbl[i];
		for (size_t x = 0; x < 64; x++) {
//			uint64_t a = select64C(v, x);
			uint64_t a = cybozu::sucvector_util::select64(v, x + 1);
			uint64_t b = select64n(v, x);
			if (a < 64) {
				CYBOZU_TEST_EQUAL(a, b);
			}
		}
	}
}

#ifdef NDEBUG
template<class F>
void benchSelect64(F& f)
{
	cybozu::XorShift rg;
	const int N = 1000000;
	uint64_t ret = 0;
	clock_t begin = clock();
	for (int i = 0; i < N; i++) {
		uint64_t v = rg.get64();
		int x = rg.get32() % 64;
		ret += f(v, x);
	}
	double t = (clock() - begin) / double(CLOCKS_PER_SEC) / N * 1e9;
	printf("ret=%x, %.2fnsec\n", (int)ret, t);
}

template<class T, class F>
void bench(const T& sv, const F& f, size_t N)
{
	const size_t M = sv.size();
	cybozu::XorShift rg;
	uint64_t ret = 0;
	clock_t begin = clock();
	for (size_t i = 0; i < N; i++) {
		uint32_t x = rg() % M;
		ret += (sv.*f)((x & 0x80000000) != 0, x);
	}
	double t = (clock() - begin) / double(CLOCKS_PER_SEC) / N * 1e9;
	printf("ret=%x, %.2fnsec\n", (int)ret, t);
}

CYBOZU_TEST_AUTO(select64Bench)
{
	puts("select64C");
	benchSelect64(select64C);
	puts("cybozu::sucvector_util::select64");
	benchSelect64(cybozu::sucvector_util::select64);
	puts("select64n");
	benchSelect64(select64n);

	cybozu::XorShift rg;
	const size_t N = 100000;
	std::vector<uint64_t> v;
	v.resize(N);
	for (size_t i = 0; i < N; i++) {
		v[i] = rg.get64();
	}
	cybozu::SucVector sv;
	sv.init(&v[0], v.size() * 64);
	puts("bench");
	puts("rank");
	bench(sv, &cybozu::SucVector::rank, 100000000);
	puts("select");
	bench(sv, &cybozu::SucVector::select, 10000000);
}
#endif
<commit_msg>same origin for select<commit_after>#include <cybozu/test.hpp>
#include <cybozu/sucvector.hpp>
#include <cybozu/xorshift.hpp>
#include <time.h>

uint64_t select64n(uint64_t v, size_t n)
{
	size_t count = 0;
	for (int i = 0; i < 64; i++) {
		if (v & (uint64_t(1) << i))
			count++;
		if (count == n)
			return i;
	}
	return 64;
}

uint64_t rank(const cybozu::SucVector& v, bool b, size_t n)
{
	uint64_t ret = 0;
	for (size_t i = 0; i < n; i++) {
		if (v.get(i) == b) {
			ret++;
		}
	}
	return ret;
}

uint64_t select(const cybozu::SucVector& v, bool b, size_t n)
{
	n++;
	for (size_t i = 0; i < v.size(); i++) {
		if (v.get(i) == b) n--;
		if (n == 0) return i;
	}
	return cybozu::NotFound;
}

CYBOZU_TEST_AUTO(testall)
{
	cybozu::XorShift rg;
	const size_t N = 30;
	std::vector<uint64_t> v;
	v.resize(N);
	for (size_t i = 0; i < N; i++) {
		v[i] = rg.get64();
	}
	cybozu::SucVector sv;
	sv.init(&v[0], v.size() * 64);
	for (size_t i = 0; i < sv.size(); i++) {
		CYBOZU_TEST_EQUAL(sv.rank(true, i), rank(sv, true, i));
		CYBOZU_TEST_EQUAL(sv.rank(false, i), rank(sv, false, i));
		CYBOZU_TEST_EQUAL(sv.select(true, i), select(sv, true, i));
		CYBOZU_TEST_EQUAL(sv.select(false, i), select(sv, false, i));
	}
}

CYBOZU_TEST_AUTO(test0)
{
	cybozu::SucVector sv;
	uint64_t blk = 722;
	sv.init(&blk, 64); // 0100101101
	CYBOZU_TEST_EQUAL(sv.rank(1, 6), 2u);
	CYBOZU_TEST_EQUAL(sv.select(0, 4), 8u);
}

CYBOZU_TEST_AUTO(select)
{
	const uint64_t v[] = {
		0xdca345ea1b5116e6ULL,
		0x951049aad88d00b0ULL,
		0x1ec7825e8db24146ULL,
		0x9af814432ac00f2cULL,
		0xffffffffffffffffULL,
		0x242342afecbfe4aaULL,
		0xffffffffffffffffULL,
		0xf324987abcef3242ULL
	};
	const size_t bitLen = sizeof(v) * 8;
	cybozu::SucVector sv;
	sv.init(v, bitLen);
	for (int s = 0; s < 2; s++) {
		const bool b = s == 0;
		const size_t max = sv.rank(b, bitLen);
		for (size_t r = 0; r < max; r++) {
			CYBOZU_TEST_EQUAL(sv.select(b, r), select(sv, b, r));
			CYBOZU_TEST_EQUAL(sv.rank(b, sv.select(b, r) + 1), r + 1);
		}
	}
}

CYBOZU_TEST_AUTO(relation)
{
	const uint64_t v = 0x242342afecbfe4aaULL;
	const size_t max = cybozu::popcnt<uint64_t>(v);
	for (size_t r = 0; r < max; r++) {
		CYBOZU_TEST_EQUAL(cybozu::sucvector_util::rank64(v, cybozu::sucvector_util::select64(v, r) + 1), r);
		CYBOZU_TEST_EQUAL(cybozu::sucvector_util::rank64(v, cybozu::sucvector_util::select64(v, r + 1) + 1), r + 1);
	}
}

CYBOZU_TEST_AUTO(rank)
{
	cybozu::SucVector sv;
	uint64_t blk = 6;
	sv.init(&blk, 64); // 0b0110
	const struct {
		bool val;
		uint32_t rank0;
		uint32_t rank1;
	} tbl [] = {
		{ 0, 1, 0 },
		{ 1, 1, 1 },
		{ 1, 1, 2 },
		{ 0, 2, 2 },
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		CYBOZU_TEST_EQUAL(sv.rank0(i + 1), tbl[i].rank0);
		CYBOZU_TEST_EQUAL(sv.rank1(i + 1), tbl[i].rank1);
		CYBOZU_TEST_EQUAL(sv.get(i), tbl[i].val);
	}
}

bool get(const uint64_t *blk, size_t pos)
{
	size_t q = pos / 64;
	size_t r = pos & 63;
	return ((blk[q] >> r) & 1) != 0;
}

uint32_t count(const uint64_t *blk, size_t pos)
{
	uint32_t ret = 0;
	for (size_t i = 0; i < pos; i++) {
		if (get(blk, i)) ret++;
	}
	return ret;
}

CYBOZU_TEST_AUTO(get)
{
	uint64_t tbl[] = {
		0x1234567812345678ULL, 0xffffffffffffffffULL, 0x1020304050607080ULL,
		0x3172039874192874ULL, 0x0000000000000000ULL, 0xfeabcbfeacbefaaeULL,
		0xfefefefefefefeefULL, 0x1864192836419823ULL, 0xaaaaaaaaaaaaaaaaULL,
	};
	const size_t tblNum = CYBOZU_NUM_OF_ARRAY(tbl);
	cybozu::SucVector sv;
	sv.init(tbl, tblNum * 64);
	for (size_t i = 0; i < tblNum * 64; i++) {
		CYBOZU_TEST_EQUAL(sv.get(i), get(tbl, i));
		CYBOZU_TEST_EQUAL(sv.rank1(i), count(tbl, i));
	}
	CYBOZU_TEST_EQUAL(sv.rank0(tblNum * 64), sv.getNum(0));
	CYBOZU_TEST_EQUAL(sv.rank1(tblNum * 64), sv.getNum(1));
}

/*
	compare speed
	from https://code.google.com/p/shellinford/source/browse/trunk/src/shellinford_bit_vector.cc
*/
inline uint64_t select64C(uint64_t x, uint64_t i)
{
	uint64_t x1 = ((x  & 0xaaaaaaaaaaaaaaaaULL) >>  1) + (x  & 0x5555555555555555ULL);
	uint64_t x2 = ((x1 & 0xccccccccccccccccULL) >>  2) + (x1 & 0x3333333333333333ULL);
	uint64_t x3 = ((x2 & 0xf0f0f0f0f0f0f0f0ULL) >>  4) + (x2 & 0x0f0f0f0f0f0f0f0fULL);
	uint64_t x4 = ((x3 & 0xff00ff00ff00ff00ULL) >>  8) + (x3 & 0x00ff00ff00ff00ffULL);
	uint64_t x5 = ((x4 & 0xffff0000ffff0000ULL) >> 16) + (x4 & 0x0000ffff0000ffffULL);
//	i++;
	uint64_t pos = 0;
	uint64_t v5 = x5 & 0xffffffffULL;
	if (i > v5) { i -= v5; pos += 32; }
	uint64_t v4 = (x4 >> pos) & 0x0000ffffULL;
	if (i > v4) { i -= v4; pos += 16; }
	uint64_t v3 = (x3 >> pos) & 0x000000ffULL;
	if (i > v3) { i -= v3; pos +=  8; }
	uint64_t v2 = (x2 >> pos) & 0x0000000fULL;
	if (i > v2) { i -= v2; pos +=  4; }
	uint64_t v1 = (x1 >> pos) & 0x00000003ULL;
	if (i > v1) { i -= v1; pos +=  2; }
	uint64_t v0 = (x  >> pos) & 0x00000001ULL;
	if (i > v0) { i -= v0; pos +=  1; }
	return pos;
}

CYBOZU_TEST_AUTO(select8)
{
	const uint32_t s = 18;
	for (uint32_t v = 0; v < (1 << s); v++) {
		for (uint32_t x = 0; x < s; x++) {
			uint64_t a = cybozu::sucvector_util::select64(v, x);
//			uint64_t a = select64n(v, x);
			uint64_t b = select64C(v, x);
			if (a < 64) {
				CYBOZU_TEST_EQUAL(a, b);
			}
		}
	}
}

CYBOZU_TEST_AUTO(select64)
{
	uint64_t tbl[] = {
		0xf0f0f0f0f0f030eeULL,
		0x0000000000000006ULL,
		0x0000000000000000ULL,
		0x0000000000000001ULL,
		0x9190751837459273ULL,
		0xffffffffffffffffULL,
	};
	for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
		uint64_t v = tbl[i];
		for (size_t x = 0; x < 64; x++) {
//			uint64_t a = select64C(v, x);
			uint64_t a = cybozu::sucvector_util::select64(v, x);
			uint64_t b = select64n(v, x);
			if (a < 64) {
				CYBOZU_TEST_EQUAL(a, b);
			}
		}
	}
}

#ifdef NDEBUG
template<class F>
void benchSelect64(F& f)
{
	cybozu::XorShift rg;
	const int N = 1000000;
	uint64_t ret = 0;
	clock_t begin = clock();
	for (int i = 0; i < N; i++) {
		uint64_t v = rg.get64();
		int x = rg.get32() % 64;
		ret += f(v, x);
	}
	double t = (clock() - begin) / double(CLOCKS_PER_SEC) / N * 1e9;
	printf("ret=%x, %.2fnsec\n", (int)ret, t);
}

template<class T, class F>
void bench(const T& sv, const F& f, size_t N)
{
	const size_t M = sv.size();
	cybozu::XorShift rg;
	uint64_t ret = 0;
	clock_t begin = clock();
	for (size_t i = 0; i < N; i++) {
		uint32_t x = rg() % M;
		ret += (sv.*f)((x & 0x80000000) != 0, x);
	}
	double t = (clock() - begin) / double(CLOCKS_PER_SEC) / N * 1e9;
	printf("ret=%x, %.2fnsec\n", (int)ret, t);
}

CYBOZU_TEST_AUTO(select64Bench)
{
	puts("select64C");
	benchSelect64(select64C);
	puts("cybozu::sucvector_util::select64");
	benchSelect64(cybozu::sucvector_util::select64);
	puts("select64n");
	benchSelect64(select64n);

	cybozu::XorShift rg;
	const size_t N = 100000;
	std::vector<uint64_t> v;
	v.resize(N);
	for (size_t i = 0; i < N; i++) {
		v[i] = rg.get64();
	}
	cybozu::SucVector sv;
	sv.init(&v[0], v.size() * 64);
	puts("bench");
	puts("rank");
	bench(sv, &cybozu::SucVector::rank, 100000000);
	puts("select");
	bench(sv, &cybozu::SucVector::select, 10000000);
}
#endif
<|endoftext|>


<commit_before>#include <stdio.h>
#include "Halide.h"

using namespace Halide;

Expr u8(Expr a) {
    return cast<uint8_t>(a);
}

Expr u16(Expr a) {
    return cast<uint16_t>(a);
}

int main(int argc, char **argv) {

    Image<uint8_t> input(128, 64);

    for (int y = 0; y < input.height(); y++) {
        for (int x = 0; x < input.width(); x++) {
            input(x, y) = y*input.width() + x;
        }
    }

    Var x, y;
    {
        Func f;
        f(x, y) = select(((input(x, y) > 10) && (input(x, y) < 20)) ||
                         ((input(x, y) > 40) && (!(input(x, y) > 50))),
                         u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool cond = ((input(x, y) > 10) && (input(x, y) < 20)) ||
                    ((input(x, y) > 40) && (!(input(x, y) > 50)));
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a condition that uses a let resulting from common
    // subexpression elimination.
    {
        Func f;
        Expr common_cond = input(x, y) > 10;
        f(x, y) = select((common_cond && (input(x, y) < 20)) ||
                         ((input(x, y) > 40) && (!common_cond)),
                         u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool common_cond = input(x, y) > 10;
                bool cond = (common_cond && (input(x, y) < 20)) ||
                    ((input(x, y) > 40) && (!common_cond));
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a condition that uses differently sized types.
    {
        Func f;
        Expr ten = 10;
        f(x, y) = select(input(x, y) > ten, u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool cond = input(x, y) > 10;
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a select where the condition has a different width than
    // the true/false values.
    {
        Func f;
        f(x, y) = select(input(x, y) > 10, u16(255), u16(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint16_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool cond = input(x, y) > 10;
                uint16_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    printf("Success!\n");
    return 0;

}
<commit_msg>Expand test_logical to demonstrate hvx bug<commit_after>#include <stdio.h>
#include "Halide.h"

using namespace Halide;

Expr u8(Expr a) {
    return cast<uint8_t>(a);
}

Expr u16(Expr a) {
    return cast<uint16_t>(a);
}

int main(int argc, char **argv) {

    Image<uint8_t> input(128, 64);

    for (int y = 0; y < input.height(); y++) {
        for (int x = 0; x < input.width(); x++) {
            input(x, y) = y*input.width() + x;
        }
    }

    Var x, y;
    {
        Func f;
        f(x, y) = select(((input(x, y) > 10) && (input(x, y) < 20)) ||
                         ((input(x, y) > 40) && (!(input(x, y) > 50))),
                         u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool cond = ((input(x, y) > 10) && (input(x, y) < 20)) ||
                    ((input(x, y) > 40) && (!(input(x, y) > 50)));
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a condition that uses a let resulting from common
    // subexpression elimination.
    {
        Func f;
        Expr common_cond = input(x, y) > 10;
        f(x, y) = select((common_cond && (input(x, y) < 20)) ||
                         ((input(x, y) > 40) && (!common_cond)),
                         u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool common_cond = input(x, y) > 10;
                bool cond = (common_cond && (input(x, y) < 20)) ||
                    ((input(x, y) > 40) && (!common_cond));
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a condition that uses differently sized types.
    {
        Func f;
        Expr ten = 10;
        f(x, y) = select(input(x, y) > ten, u8(255), u8(0));

        Target target = get_jit_target_from_environment();
        if (target.has_gpu_feature()) {
            f.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
        } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon().vectorize(x, 128);
        } else {
            f.vectorize(x, 8);
        }

        Image<uint8_t> output = f.realize(input.width(), input.height(), target);

        for (int y = 0; y < input.height(); y++) {
            for (int x = 0; x < input.width(); x++) {
                bool cond = input(x, y) > 10;
                uint8_t correct = cond ? 255 : 0;
                if (correct != output(x, y)) {
                    printf("output(%d, %d) = %d instead of %d\n", x, y, output(x, y), correct);
                    return -1;
                }
            }
        }
    }

    // Test a select where the condition has a different width than
    // the true/false values.
    for (int w = 8; w <= 32; w *= 2) {
        for (int n = 8; n < w; n *= 2) {
            Type narrow = UInt(n), wide = UInt(w);

            Func in_wide;
            in_wide(x, y) = cast(wide, y + x*3);
            in_wide.compute_root();

            Func in_narrow;
            in_narrow(x, y) = cast(narrow, x*y + x - 17);
            in_narrow.compute_root();

            Func f;
            f(x, y) = select(in_narrow(x, y) > 10, in_wide(x, y*2), in_wide(x, y*2+1));

            Func cpu;
            cpu(x, y) = f(x, y);

            Func gpu;
            gpu(x, y) = f(x, y);

            Func out;
            out(x, y) = {cast<uint32_t>(cpu(x, y)), cast<uint32_t>(gpu(x, y))};

            cpu.compute_root();
            gpu.compute_root();

            Target target = get_jit_target_from_environment();
            if (target.has_gpu_feature()) {
                gpu.gpu_tile(x, y, 16, 16).vectorize(Var::gpu_threads(), 4);
            } else if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
                gpu.hexagon().vectorize(x, 128);
            } else {
                // Just test vectorization
                gpu.vectorize(x, 8);
            }

            Realization r = out.realize(input.width(), input.height(), target);
            Image<uint32_t> cpu_output = r[0];
            Image<uint32_t> gpu_output = r[1];

            for (int y = 0; y < input.height(); y++) {
                for (int x = 0; x < input.width(); x++) {
                    if (cpu_output(x, y) != gpu_output(x, y)) {
                        printf("gpu_output(%d, %d) = %d instead of %d\n",
                               x, y, gpu_output(x, y), cpu_output(x, y));
                        return -1;
                    }
                }
            }
        }
    }

    printf("Success!\n");
    return 0;

}
<|endoftext|>


<commit_before>#include <iostream>
#include "../include/baralho.h"
#include "../include/carta.h"
#include "../include/eventmanager.h"

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

using namespace std;

int main(int argv, char** args){
	// Janela principal
	SDL_Window* gWindow = NULL;

	// Renderizador principal
	SDL_Renderer* gRenderer = NULL;

	// Responsavel pelo loop principal
	bool quit = false;

	// Eventos
	EventManager event = EventManager(&quit);

	// Cria a janela
	gWindow = SDL_CreateWindow("Freecell", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
	if(gWindow == NULL){
		cout << "Window could not be created. SDL Error: " << SDL_GetError() << endl;
	} else {
		// Cria o renderizador
		gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
		if(gRenderer == NULL) {
			cout << "Renderer could not be created. SDL Error: " << SDL_GetError() << endl;
		} else {
			// Inicializa a cor do renderizador
			SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);

			// Inicializa o carregamento de PNG
			int imgFlags = IMG_INIT_PNG;
			if(!(IMG_Init(imgFlags) & imgFlags)){
				cout << "SDL could not initialize image. SDL Error: " << IMG_GetError() << endl;
			}
		}
	}

	Baralho b = Baralho(gRenderer);
	Carta c;
	b.getCard(c);

	// Loop  principal
	while(!quit){
		// Responsavel pelos eventos em espera
		event.update();

		// Limpa a tela
		SDL_RenderClear(gRenderer);

		// Renderiza a carta
		c.renderCard();

		// Atualiza a tela
		SDL_RenderPresent(gRenderer);
	}

	// Destroi a janela
	SDL_DestroyRenderer(gRenderer);
	SDL_DestroyWindow(gWindow);
	gRenderer = NULL;
	gWindow = NULL;

	// Sai dos subsistemas
	IMG_Quit();
	SDL_Quit();

	return 0;
}
<commit_msg>Testes para organizar e renderizar o baralho<commit_after>#include <iostream>
#include "../include/baralho.h"
#include "../include/carta.h"
#include "../include/eventmanager.h"

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

using namespace std;

int main(int argv, char** args){
	// Janela principal
	SDL_Window* gWindow = NULL;

	// Renderizador principal
	SDL_Renderer* gRenderer = NULL;

	// Responsavel pelo loop principal
	bool quit = false;

	// Eventos
	EventManager event = EventManager(&quit);

	// Cria a janela
	gWindow = SDL_CreateWindow("Freecell", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
	if(gWindow == NULL){
		cout << "Window could not be created. SDL Error: " << SDL_GetError() << endl;
	} else {
		// Cria o renderizador
		gRenderer = SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED);
		if(gRenderer == NULL) {
			cout << "Renderer could not be created. SDL Error: " << SDL_GetError() << endl;
		} else {
			// Inicializa a cor do renderizador
			SDL_SetRenderDrawColor(gRenderer, 0xFF, 0xFF, 0xFF, 0xFF);

			// Inicializa o carregamento de PNG
			int imgFlags = IMG_INIT_PNG;
			if(!(IMG_Init(imgFlags) & imgFlags)){
				cout << "SDL could not initialize image. SDL Error: " << IMG_GetError() << endl;
			}
		}
	}

	Baralho b = Baralho(gRenderer);
	b.organize();
	Carta c;
	b.getCard(c);

	// Loop  principal
	while(!quit){
		// Responsavel pelos eventos em espera
		event.update();

		// Limpa a tela
		SDL_RenderClear(gRenderer);

		// Renderiza o baralho
		b.render();

		// Renderiza a carta
//		c.renderCard();

		// Atualiza a tela
		SDL_RenderPresent(gRenderer);
	}

	// Destroi a janela
	SDL_DestroyRenderer(gRenderer);
	SDL_DestroyWindow(gWindow);
	gRenderer = NULL;
	gWindow = NULL;

	// Sai dos subsistemas
	IMG_Quit();
	SDL_Quit();

	return 0;
}
<|endoftext|>


<commit_before>
#include <libclientserver.h>

int Caps::HasCap(int cap)
{
	cap_t caps;
	cap_flag_value_t value = CAP_CLEAR;

	caps = cap_get_proc();

	if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &value) < 0)
	{
		int err = errno;
		cap_free(caps);
		return -err;
	}

	cap_free(caps);
	return value;
}

int Caps::SetCap(int cap)
{
	cap_t caps;
	cap_value_t cap_list[1] { cap };

	caps = cap_get_proc();
	if (caps == NULL)
		return -errno;

	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1)
	{
		int err = errno;
		cap_free(caps);
		return -err;
	}
	cap_free(caps);
	return 0;
}

<commit_msg>Fixed bug in Caps::SetCap<commit_after>
#include <libclientserver.h>

int Caps::HasCap(int cap)
{
	cap_t caps;
	cap_flag_value_t value = CAP_CLEAR;

	caps = cap_get_proc();

	if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &value) < 0)
	{
		int err = errno;
		cap_free(caps);
		return -err;
	}

	cap_free(caps);
	return value;
}

int Caps::SetCap(int cap)
{
	cap_t caps;
	cap_value_t cap_list[1] { cap };

	caps = cap_get_proc();
	if (caps == NULL)
		return -errno;

	if (cap_set_flag(caps, CAP_EFFECTIVE, 1, cap_list, CAP_SET) == -1)
	{
		int err = errno;
		cap_free(caps);
		return -err;
	}

	if (cap_set_proc(caps) < 0)
	{
		int err = errno;
		cap_free(caps);
		return -err;
	}

	cap_free(caps);
	return 0;
}

<|endoftext|>


<commit_before>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.1.2
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.

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

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

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

#include "catch.hpp"

#include <nlohmann/json.hpp>
#include <string>
#include <utility>

/*
 * This is virtually a string class.
 * It covers std::string under the hood.
 */
class alt_string
{
  public:
    using value_type = std::string::value_type;

    alt_string(const char* str): str_impl(str) {}
    alt_string(const char* str, std::size_t count): str_impl(str, count) {}
    alt_string(size_t count, char chr): str_impl(count, chr) {}
    alt_string() = default;

    template <typename...TParams>
    alt_string& append(TParams&& ...params)
    {
        str_impl.append(std::forward<TParams>(params)...);
        return *this;
    }

    void push_back(char c)
    {
        str_impl.push_back(c);
    }

    template <typename op_type>
    typename std::enable_if< // disable for alt_string
                !std::is_same<  alt_string,
                                typename std::remove_reference<op_type>::type
                             >::value,
                bool>::type
    operator==(op_type&& op) const
    {
        return str_impl == op;
    }

    bool operator==(const alt_string& op) const
    {
        return str_impl == op.str_impl;
    }

    template <typename op_type>
    typename std::enable_if< // disable for alt_string
                !std::is_same<  alt_string,
                                typename std::remove_reference<op_type>::type
                             >::value,
                bool>::type
    operator!=(op_type&& op) const
    {
        return str_impl != op;
    }

    bool operator!=(const alt_string& op) const {
        return str_impl != op.str_impl;
    }

    std::size_t size() const noexcept
    {
        return str_impl.size();
    }

    void resize (std::size_t n)
    {
        str_impl.resize(n);
    }

    void resize (std::size_t n, char c)
    {
        str_impl.resize(n, c);
    }

    template <typename op_type>
    bool operator<(op_type&& op) const
    {
        return str_impl < op;
    }

    bool operator<(const alt_string& op) const
    {
        return str_impl < op.str_impl;
    }

    const char* c_str() const
    {
        return str_impl.c_str();
    }

    char& operator[](std::size_t index)
    {
        return str_impl[index];
    }

    const char& operator[](std::size_t index) const
    {
        return str_impl[index];
    }

    char& back()
    {
        return str_impl.back();
    }

    const char& back() const
    {
        return str_impl.back();
    }

    void clear()
    {
        str_impl.clear();
    }

    const value_type* data()
    {
        return str_impl.data();
    }

  private:
    std::string str_impl;
};

using alt_json = nlohmann::basic_json <
                 std::map,
                 std::vector,
                 alt_string,
                 bool,
                 std::int64_t,
                 std::uint64_t,
                 double,
                 std::allocator,
                 nlohmann::adl_serializer >;

TEST_CASE("alternative string type")
{
    SECTION("dump")
    {
        {
            alt_json doc;
            doc["pi"] = 3.141;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"pi":3.141})");
        }

        {
            alt_json doc;
            doc["happy"] = true;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"happy":true})");
        }

        {
            alt_json doc;
            doc["name"] = "I'm Batman";
            alt_string dump = doc.dump();
            CHECK(dump == R"({"name":"I'm Batman"})");
        }

        {
            alt_json doc;
            doc["nothing"] = nullptr;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"nothing":null})");
        }

        {
            alt_json doc;
            doc["answer"]["everything"] = 42;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"answer":{"everything":42}})");
        }

        {
            alt_json doc;
            doc["list"] = { 1, 0, 2 };
            alt_string dump = doc.dump();
            CHECK(dump == R"({"list":[1,0,2]})");
        }

        {
            alt_json doc;
            doc["list"] = { 1, 0, 2 };
            alt_string dump = doc.dump();
            CHECK(dump == R"({"list":[1,0,2]})");
        }
    }

    SECTION("parse")
    {
        auto doc = alt_json::parse("{\"foo\": \"bar\"}");
        alt_string dump = doc.dump();
        CHECK(dump == R"({"foo":"bar"})");
    }

    SECTION("equality")
    {
        alt_json doc;
        doc["Who are you?"] = "I'm Batman";

        CHECK("I'm Batman" == doc["Who are you?"]);
        CHECK(doc["Who are you?"]  == "I'm Batman");

        CHECK("I'm Bruce Wayne" != doc["Who are you?"]);
        CHECK(doc["Who are you?"]  != "I'm Bruce Wayne");

        {
            const alt_json& const_doc = doc;

            CHECK("I'm Batman" == const_doc["Who are you?"]);
            CHECK(const_doc["Who are you?"] == "I'm Batman");

            CHECK("I'm Bruce Wayne" != const_doc["Who are you?"]);
            CHECK(const_doc["Who are you?"] != "I'm Bruce Wayne");
        }
    }
}
<commit_msg>define global operator< for const char* and alt_string<commit_after>/*
    __ _____ _____ _____
 __|  |   __|     |   | |  JSON for Modern C++ (test suite)
|  |  |__   |  |  | | | |  version 3.1.2
|_____|_____|_____|_|___|  https://github.com/nlohmann/json

Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2018 Vitaliy Manushkin <agri@akamo.info>.

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

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

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

#include "catch.hpp"

#include <nlohmann/json.hpp>
#include <string>
#include <utility>

/*
 * This is virtually a string class.
 * It covers std::string under the hood.
 */
class alt_string
{
  public:
    using value_type = std::string::value_type;

    alt_string(const char* str): str_impl(str) {}
    alt_string(const char* str, std::size_t count): str_impl(str, count) {}
    alt_string(size_t count, char chr): str_impl(count, chr) {}
    alt_string() = default;

    template <typename...TParams>
    alt_string& append(TParams&& ...params)
    {
        str_impl.append(std::forward<TParams>(params)...);
        return *this;
    }

    void push_back(char c)
    {
        str_impl.push_back(c);
    }

    template <typename op_type>
    typename std::enable_if< // disable for alt_string
                !std::is_same<  alt_string,
                                typename std::remove_reference<op_type>::type
                             >::value,
                bool>::type
    operator==(op_type&& op) const
    {
        return str_impl == op;
    }

    bool operator==(const alt_string& op) const
    {
        return str_impl == op.str_impl;
    }

    template <typename op_type>
    typename std::enable_if< // disable for alt_string
                !std::is_same<  alt_string,
                                typename std::remove_reference<op_type>::type
                             >::value,
                bool>::type
    operator!=(op_type&& op) const
    {
        return str_impl != op;
    }

    bool operator!=(const alt_string& op) const {
        return str_impl != op.str_impl;
    }

    std::size_t size() const noexcept
    {
        return str_impl.size();
    }

    void resize (std::size_t n)
    {
        str_impl.resize(n);
    }

    void resize (std::size_t n, char c)
    {
        str_impl.resize(n, c);
    }

    template <typename op_type>
    typename std::enable_if< // disable for alt_string
                !std::is_same<  alt_string,
                                typename std::remove_reference<op_type>::type
                             >::value,
                bool>::type
    operator<(op_type&& op) const
    {
        return str_impl < op;
    }

    bool operator<(const alt_string& op) const
    {
        return str_impl < op.str_impl;
    }

    const char* c_str() const
    {
        return str_impl.c_str();
    }

    char& operator[](std::size_t index)
    {
        return str_impl[index];
    }

    const char& operator[](std::size_t index) const
    {
        return str_impl[index];
    }

    char& back()
    {
        return str_impl.back();
    }

    const char& back() const
    {
        return str_impl.back();
    }

    void clear()
    {
        str_impl.clear();
    }

    const value_type* data()
    {
        return str_impl.data();
    }

  private:
    std::string str_impl;

    friend bool ::operator<(const char*, const alt_string&);
};

using alt_json = nlohmann::basic_json <
                 std::map,
                 std::vector,
                 alt_string,
                 bool,
                 std::int64_t,
                 std::uint64_t,
                 double,
                 std::allocator,
                 nlohmann::adl_serializer >;

bool operator<(const char* op1, const alt_string& op2) {
    return op1 < op2.str_impl;
}

TEST_CASE("alternative string type")
{
    SECTION("dump")
    {
        {
            alt_json doc;
            doc["pi"] = 3.141;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"pi":3.141})");
        }

        {
            alt_json doc;
            doc["happy"] = true;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"happy":true})");
        }

        {
            alt_json doc;
            doc["name"] = "I'm Batman";
            alt_string dump = doc.dump();
            CHECK(dump == R"({"name":"I'm Batman"})");
        }

        {
            alt_json doc;
            doc["nothing"] = nullptr;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"nothing":null})");
        }

        {
            alt_json doc;
            doc["answer"]["everything"] = 42;
            alt_string dump = doc.dump();
            CHECK(dump == R"({"answer":{"everything":42}})");
        }

        {
            alt_json doc;
            doc["list"] = { 1, 0, 2 };
            alt_string dump = doc.dump();
            CHECK(dump == R"({"list":[1,0,2]})");
        }

        {
            alt_json doc;
            doc["list"] = { 1, 0, 2 };
            alt_string dump = doc.dump();
            CHECK(dump == R"({"list":[1,0,2]})");
        }
    }

    SECTION("parse")
    {
        auto doc = alt_json::parse("{\"foo\": \"bar\"}");
        alt_string dump = doc.dump();
        CHECK(dump == R"({"foo":"bar"})");
    }

    SECTION("equality")
    {
        alt_json doc;
        doc["Who are you?"] = "I'm Batman";

        CHECK("I'm Batman" == doc["Who are you?"]);
        CHECK(doc["Who are you?"]  == "I'm Batman");

        CHECK("I'm Bruce Wayne" != doc["Who are you?"]);
        CHECK(doc["Who are you?"]  != "I'm Bruce Wayne");

        {
            const alt_json& const_doc = doc;

            CHECK("I'm Batman" == const_doc["Who are you?"]);
            CHECK(const_doc["Who are you?"] == "I'm Batman");

            CHECK("I'm Bruce Wayne" != const_doc["Who are you?"]);
            CHECK(const_doc["Who are you?"] != "I'm Bruce Wayne");
        }
    }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <boost/bind.hpp>
#include <iostream>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	error_code ec;
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 4)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	char* ptr = buffer;
	int length = read_int32(ptr);

	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, length)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	return length;
}

char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
	, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
	, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

void send_allow_fast(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> allow fast: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_suggest_piece(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> suggest piece: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_keepalive(stream_socket& s)
{
	std::cout << time_now_string() << " ==> keepalive" << std::endl;
	char msg[] = "\0\0\0\0";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 4)
		, libtorrent::asio::transfer_all(), ec);
}

void send_unchoke(stream_socket& s)
{
	std::cout << time_now_string() << " ==> unchoke" << std::endl;
	char msg[] = "\0\0\0\x01\x01";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 5)
		, libtorrent::asio::transfer_all(), ec);
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	std::cout << time_now_string() << " ==> handshake" << std::endl;
	std::cout << time_now_string() << " ==> have_all" << std::endl;
	error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	libtorrent::asio::write(s, libtorrent::asio::buffer(handshake, sizeof(handshake) - 1)
		, libtorrent::asio::transfer_all(), ec);

	// read handshake
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 68)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	std::cout << time_now_string() << " <== handshake" << std::endl;

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	std::cerr << " === test reject ===" << std::endl;

	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);
	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, boost::bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		read_message(s, recv_buffer);
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << time_now_string() << " <== " << message_name[msg] << std::endl;
		else
			std::cerr << time_now_string() << " <== " << msg << std::endl;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
}

void test_respect_suggest()
{
	std::cerr << " === test suggest ===" << std::endl;
	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);

	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, boost::bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	send_keepalive(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		read_message(s, recv_buffer);
		std::cerr << time_now_string() << " <== ";
		int msg = recv_buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			std::cerr << message_name[msg] << std::endl;
		else
			std::cerr << msg << std::endl;
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<commit_msg>improve print-out of fast extension test<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/io.hpp"
#include <cstring>
#include <boost/bind.hpp>
#include <iostream>

using namespace libtorrent;

int read_message(stream_socket& s, char* buffer)
{
	using namespace libtorrent::detail;
	error_code ec;
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 4)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	char* ptr = buffer;
	int length = read_int32(ptr);

	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, length)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	return length;
}

void print_message(char const* buffer, int len)
{
	char const* message_name[] = {"choke", "unchoke", "interested", "not_interested"
		, "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
		, "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};

	char message[50];
	char extra[300];
	extra[0] = 0;
	if (len == 0)
	{
		strcpy(message, "keepalive");
	}
	else
	{
		int msg = buffer[0];
		if (msg >= 0 && msg < int(sizeof(message_name)/sizeof(message_name[0])))
			strcpy(message, message_name[msg]);
		else
			snprintf(message, sizeof(message), "unknown[%d]", msg);

		if (msg == 0x6 && len == 13)
		{
			peer_request r;
			const char* ptr = buffer + 1;
			r.piece = detail::read_int32(ptr);
			r.start = detail::read_int32(ptr);
			r.length = detail::read_int32(ptr);
			snprintf(extra, sizeof(extra), "p: %d s: %d l: %d", r.piece, r.start, r.length);
		}
		else if (msg == 0x11 && len == 5)
		{
			const char* ptr = buffer + 1;
			int index = detail::read_int32(ptr);
			snprintf(extra, sizeof(extra), "p: %d", index);
		}
	}

	fprintf(stderr, "%s <== %s %s\n", time_now_string(), message, extra);
}

void send_allow_fast(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> allow fast: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x11\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_suggest_piece(stream_socket& s, int piece)
{
	std::cout << time_now_string() << " ==> suggest piece: " << piece << std::endl;
	using namespace libtorrent::detail;
	char msg[] = "\0\0\0\x05\x0d\0\0\0\0";
	char* ptr = msg + 5;
	write_int32(piece, ptr);
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 9)
		, libtorrent::asio::transfer_all(), ec);
}

void send_keepalive(stream_socket& s)
{
	std::cout << time_now_string() << " ==> keepalive" << std::endl;
	char msg[] = "\0\0\0\0";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 4)
		, libtorrent::asio::transfer_all(), ec);
}

void send_unchoke(stream_socket& s)
{
	std::cout << time_now_string() << " ==> unchoke" << std::endl;
	char msg[] = "\0\0\0\x01\x01";
	error_code ec;
	libtorrent::asio::write(s, libtorrent::asio::buffer(msg, 5)
		, libtorrent::asio::transfer_all(), ec);
}

void do_handshake(stream_socket& s, sha1_hash const& ih, char* buffer)
{
	char handshake[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
		"                    " // space for info-hash
		"aaaaaaaaaaaaaaaaaaaa" // peer-id
		"\0\0\0\x01\x0e"; // have_all
	std::cout << time_now_string() << " ==> handshake" << std::endl;
	std::cout << time_now_string() << " ==> have_all" << std::endl;
	error_code ec;
	std::memcpy(handshake + 28, ih.begin(), 20);
	libtorrent::asio::write(s, libtorrent::asio::buffer(handshake, sizeof(handshake) - 1)
		, libtorrent::asio::transfer_all(), ec);

	// read handshake
	libtorrent::asio::read(s, libtorrent::asio::buffer(buffer, 68)
		, libtorrent::asio::transfer_all(), ec);
	if (ec)
	{
		std::cout << time_now_string() << ": " << ec.message() << std::endl;
		exit(1);
	}
	std::cout << time_now_string() << " <== handshake" << std::endl;

	TEST_CHECK(buffer[0] == 19);
	TEST_CHECK(std::memcmp(buffer + 1, "BitTorrent protocol", 19) == 0);

	char* extensions = buffer + 20;
	// check for fast extension support
	TEST_CHECK(extensions[7] & 0x4);

#ifndef TORRENT_DISABLE_EXTENSIONS
	// check for extension protocol support
	TEST_CHECK(extensions[5] & 0x10);
#endif

#ifndef TORRENT_DISABLE_DHT
	// check for DHT support
	TEST_CHECK(extensions[7] & 0x1);
#endif

	TEST_CHECK(std::memcmp(buffer + 28, ih.begin(), 20) == 0);
}

// makes sure that pieces that are allowed and then
// rejected aren't requested again
void test_reject_fast()
{
	std::cerr << " === test reject ===" << std::endl;

	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);
	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> allowed_fast;
	allowed_fast.push_back(0);
	allowed_fast.push_back(1);
	allowed_fast.push_back(2);
	allowed_fast.push_back(3);

	std::for_each(allowed_fast.begin(), allowed_fast.end()
		, boost::bind(&send_allow_fast, boost::ref(s), _1));

	while (!allowed_fast.empty())
	{
		int len = read_message(s, recv_buffer);
		print_message(recv_buffer, len);
		int msg = recv_buffer[0];
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(allowed_fast.begin()
			, allowed_fast.end(), piece);
		TEST_CHECK(i != allowed_fast.end());
		if (i != allowed_fast.end())
			allowed_fast.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
}

void test_respect_suggest()
{
	std::cerr << " === test suggest ===" << std::endl;
	boost::intrusive_ptr<torrent_info> t = ::create_torrent();
	sha1_hash ih = t->info_hash();
	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000), "0.0.0.0", 0);

	error_code ec;
	add_torrent_params p;
	p.ti = t;
	p.save_path = "./tmp1_fast";
	ses1.add_torrent(p, ec);

	test_sleep(2000);

	io_service ios;
	stream_socket s(ios);
	s.connect(tcp::endpoint(address::from_string("127.0.0.1", ec), ses1.listen_port()), ec);

	char recv_buffer[1000];
	do_handshake(s, ih, recv_buffer);

	std::vector<int> suggested;
	suggested.push_back(0);
	suggested.push_back(1);
	suggested.push_back(2);
	suggested.push_back(3);

	std::for_each(suggested.begin(), suggested.end()
		, boost::bind(&send_suggest_piece, boost::ref(s), _1));

	send_unchoke(s);

	send_keepalive(s);

	int fail_counter = 100;
	while (!suggested.empty() && fail_counter > 0)
	{
		int len = read_message(s, recv_buffer);
		print_message(recv_buffer, len);
		int msg = recv_buffer[0];
		fail_counter--;
		if (recv_buffer[0] != 0x6) continue;

		using namespace libtorrent::detail;
		char* ptr = recv_buffer + 1;
		int piece = read_int32(ptr);

		std::vector<int>::iterator i = std::find(suggested.begin()
			, suggested.end(), piece);
		TEST_CHECK(i != suggested.end());
		if (i != suggested.end())
			suggested.erase(i);
		// send reject request
		recv_buffer[0] = 0x10;
		error_code ec;
		std::cerr << time_now_string() << " ==> reject" << std::endl;
		libtorrent::asio::write(s, libtorrent::asio::buffer("\0\0\0\x0d", 4)
			, libtorrent::asio::transfer_all(), ec);
		libtorrent::asio::write(s, libtorrent::asio::buffer(recv_buffer, 13)
			, libtorrent::asio::transfer_all(), ec);
	}
	TEST_CHECK(fail_counter > 0);
}

int test_main()
{
	test_reject_fast();
	test_respect_suggest();
	return 0;
}

<|endoftext|>