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

//------------------------------------------------------------------------------
// Description of the life cycle of a instance of MetricsService.
//
//  OVERVIEW
//
// A MetricsService instance is created at ChromeFrame startup in
// the IE process. It is the central controller for the UMA log data.
// Its major job is to manage logs, prepare them for transmission.
// Currently only histogram data is tracked in log.  When MetricsService
// prepares log for submission it snapshots the current stats of histograms,
// translates log to XML.  Transmission includes submitting a compressed log
// as data in a URL-get, and is performed using functionality provided by
// Urlmon
// The actual transmission is performed using a windows timer procedure which
// basically means that the thread on which the MetricsService object is
// instantiated needs a message pump. Also on IE7 where every tab is created
// on its own thread we would have a case where the timer procedures can
// compete for sending histograms.
//
// When preparing log for submission we acquire a list of all local histograms
// that have been flagged for upload to the UMA server.
//
// When ChromeFrame shuts down, there will typically be a fragment of an ongoing
// log that has not yet been transmitted.  Currently this data is ignored.
//
// With the above overview, we can now describe the state machine's various
// stats, based on the State enum specified in the state_ member.  Those states
// are:
//
//    INITIALIZED,      // Constructor was called.
//    ACTIVE,           // Accumalating log data.
//    STOPPED,          // Service has stopped.
//
//-----------------------------------------------------------------------------

#include "chrome_frame/metrics_service.h"

#include <windows.h>
#include <objbase.h>

#if defined(USE_SYSTEM_LIBBZ2)
#include <bzlib.h>
#else
#include "third_party/bzip2/bzlib.h"
#endif

#include "base/file_version_info.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/chrome_frame_distribution.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome_frame/bind_status_callback_impl.h"
#include "chrome_frame/crash_reporting/crash_metrics.h"
#include "chrome_frame/utils.h"
#include "net/base/upload_data.h"
#include "chrome_frame/urlmon_bind_status_callback.h"

using base::Time;
using base::TimeDelta;

static const char kMetricsType[] =
    "Content-Type: application/vnd.mozilla.metrics.bz2\r\n";

// The first UMA upload occurs after this interval.
static const int kInitialUMAUploadTimeoutMilliSeconds = 30000;

// Default to one UMA upload per 10 mins.
static const int kMinMilliSecondsPerUMAUpload = 600000;

base::LazyInstance<base::ThreadLocalPointer<MetricsService> >
    MetricsService::g_metrics_instance_(base::LINKER_INITIALIZED);

extern base::LazyInstance<StatisticsRecorder> g_statistics_recorder_;

// This class provides functionality to upload the ChromeFrame UMA data to the
// server. An instance of this class is created whenever we have data to be
// uploaded to the server.
class ChromeFrameMetricsDataUploader : public BSCBImpl {
 public:
  ChromeFrameMetricsDataUploader()
      : cache_stream_(NULL),
        upload_data_size_(0) {
    DLOG(INFO) << __FUNCTION__;
  }

  ~ChromeFrameMetricsDataUploader() {
    DLOG(INFO) << __FUNCTION__;
  }

  static HRESULT ChromeFrameMetricsDataUploader::UploadDataHelper(
      const std::string& upload_data) {
    CComObject<ChromeFrameMetricsDataUploader>* data_uploader = NULL;
    CComObject<ChromeFrameMetricsDataUploader>::CreateInstance(&data_uploader);
    DCHECK(data_uploader != NULL);

    data_uploader->AddRef();
    HRESULT hr = data_uploader->UploadData(upload_data);
    if (FAILED(hr)) {
      DLOG(ERROR) << "Failed to initialize ChromeFrame UMA data uploader: Err"
                  << hr;
    }
    data_uploader->Release();
    return hr;
  }

  HRESULT UploadData(const std::string& upload_data) {
    if (upload_data.empty()) {
      NOTREACHED() << "Invalid upload data";
      return E_INVALIDARG;
    }

    DCHECK(cache_stream_.get() == NULL);

    upload_data_size_ = upload_data.size() + 1;

    HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, cache_stream_.Receive());
    if (FAILED(hr)) {
      NOTREACHED() << "Failed to create stream. Error:"
                   << hr;
      return hr;
    }

    DCHECK(cache_stream_.get());

    unsigned long written = 0;
    cache_stream_->Write(upload_data.c_str(), upload_data_size_, &written);
    DCHECK(written == upload_data_size_);

    RewindStream(cache_stream_);

    BrowserDistribution* dist = ChromeFrameDistribution::GetDistribution();
    server_url_ = dist->GetStatsServerURL();
    DCHECK(!server_url_.empty());

    hr = CreateURLMoniker(NULL, server_url_.c_str(),
                          upload_moniker_.Receive());
    if (FAILED(hr)) {
      DLOG(ERROR) << "Failed to create url moniker for url:"
                  << server_url_.c_str()
                  << " Error:"
                  << hr;
    } else {
      ScopedComPtr<IBindCtx> context;
      hr = CreateAsyncBindCtx(0, this, NULL, context.Receive());
      DCHECK(SUCCEEDED(hr));
      DCHECK(context);

      ScopedComPtr<IStream> stream;
      hr = upload_moniker_->BindToStorage(
          context, NULL, IID_IStream,
          reinterpret_cast<void**>(stream.Receive()));
      if (FAILED(hr)) {
        NOTREACHED();
        DLOG(ERROR) << "Failed to bind to upload data moniker. Error:"
                    << hr;
      }
    }
    return hr;
  }

  STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
                                  LPWSTR* additional_headers) {
    std::string new_headers;
    new_headers = StringPrintf("Content-Length: %s\r\n",
                               base::Int64ToString(upload_data_size_).c_str());
    new_headers += kMetricsType;

    *additional_headers = reinterpret_cast<wchar_t*>(
        CoTaskMemAlloc((new_headers.size() + 1) * sizeof(wchar_t)));

    lstrcpynW(*additional_headers, ASCIIToWide(new_headers).c_str(),
              new_headers.size());
    return BSCBImpl::BeginningTransaction(url, headers, reserved,
                                          additional_headers);
  }

  STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info) {
    if ((bind_info == NULL) || (bind_info->cbSize == 0) ||
        (bind_flags == NULL))
      return E_INVALIDARG;

    *bind_flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
    // Bypass caching proxies on POSTs and PUTs and avoid writing responses to
    // these requests to the browser's cache
    *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_PRAGMA_NO_CACHE;

    DCHECK(cache_stream_.get());

    // Initialize the STGMEDIUM.
    memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
    bind_info->grfBindInfoF = 0;
    bind_info->szCustomVerb = NULL;
    bind_info->dwBindVerb = BINDVERB_POST;
    bind_info->stgmedData.tymed = TYMED_ISTREAM;
    bind_info->stgmedData.pstm = cache_stream_.get();
    bind_info->stgmedData.pstm->AddRef();
    return BSCBImpl::GetBindInfo(bind_flags, bind_info);
  }

  STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers,
                        LPCWSTR request_headers, LPWSTR* additional_headers) {
    DLOG(INFO) << __FUNCTION__ << " headers: \n" << response_headers;
    return BSCBImpl::OnResponse(response_code, response_headers,
                                request_headers, additional_headers);
  }

 private:
  std::wstring server_url_;
  size_t upload_data_size_;
  ScopedComPtr<IStream> cache_stream_;
  ScopedComPtr<IMoniker> upload_moniker_;
};

MetricsService* MetricsService::GetInstance() {
  if (g_metrics_instance_.Pointer()->Get())
    return g_metrics_instance_.Pointer()->Get();

  g_metrics_instance_.Pointer()->Set(new MetricsService);
  return g_metrics_instance_.Pointer()->Get();
}

MetricsService::MetricsService()
    : recording_active_(false),
      reporting_active_(false),
      user_permits_upload_(false),
      state_(INITIALIZED),
      thread_(NULL),
      initial_uma_upload_(true),
      transmission_timer_id_(0) {
}

MetricsService::~MetricsService() {
  SetRecording(false);
  if (pending_log_) {
    delete pending_log_;
    pending_log_ = NULL;
  }
  if (current_log_) {
    delete current_log_;
    current_log_ = NULL;
  }
}

void MetricsService::InitializeMetricsState() {
  DCHECK(state_ == INITIALIZED);

  thread_ = PlatformThread::CurrentId();

  user_permits_upload_ = GoogleUpdateSettings::GetCollectStatsConsent();
  // Update session ID
  session_id_ = CrashMetricsReporter::GetInstance()->IncrementMetric(
      CrashMetricsReporter::SESSION_ID);

  // Ensure that an instance of the StatisticsRecorder object is created.
  g_statistics_recorder_.Get();

  CrashMetricsReporter::GetInstance()->set_active(true);
}

// static
void MetricsService::Start() {
  if (GetInstance()->state_ == ACTIVE)
    return;

  GetInstance()->InitializeMetricsState();
  GetInstance()->SetRecording(true);
  GetInstance()->SetReporting(true);
}

// static
void MetricsService::Stop() {
  GetInstance()->SetReporting(false);
  GetInstance()->SetRecording(false);
}

void MetricsService::SetRecording(bool enabled) {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (enabled == recording_active_)
    return;

  if (enabled) {
    if (client_id_.empty()) {
      client_id_ = GenerateClientID();
      // Save client id somewhere.
    }
    StartRecording();

  } else {
    state_ = STOPPED;
  }
  recording_active_ = enabled;
}

// static
std::string MetricsService::GenerateClientID() {
  const int kGUIDSize = 39;

  GUID guid;
  HRESULT guid_result = CoCreateGuid(&guid);
  DCHECK(SUCCEEDED(guid_result));

  std::wstring guid_string;
  int result = StringFromGUID2(guid,
                               WriteInto(&guid_string, kGUIDSize), kGUIDSize);
  DCHECK(result == kGUIDSize);
  return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
}

// static
void CALLBACK MetricsService::TransmissionTimerProc(HWND window,
                                                    unsigned int message,
                                                    unsigned int event_id,
                                                    unsigned int time) {
  DLOG(INFO) << "Transmission timer notified";
  DCHECK(GetInstance() != NULL);
  GetInstance()->UploadData();
  if (GetInstance()->initial_uma_upload_) {
    // If this is the first uma upload by this process then subsequent uma
    // uploads should occur once every 10 minutes(default).
    GetInstance()->initial_uma_upload_ = false;
    DCHECK(GetInstance()->transmission_timer_id_ != 0);
    SetTimer(NULL, GetInstance()->transmission_timer_id_,
             kMinMilliSecondsPerUMAUpload,
             reinterpret_cast<TIMERPROC>(TransmissionTimerProc));
  }
}

void MetricsService::SetReporting(bool enable) {
  static const int kChromeFrameMetricsTimerId = 0xFFFFFFFF;

  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (reporting_active_ != enable) {
    reporting_active_ = enable;
    if (reporting_active_) {
      transmission_timer_id_ =
          SetTimer(NULL, kChromeFrameMetricsTimerId,
                   kInitialUMAUploadTimeoutMilliSeconds,
                   reinterpret_cast<TIMERPROC>(TransmissionTimerProc));
    }
  }
}

//------------------------------------------------------------------------------
// Recording control methods

void MetricsService::StartRecording() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (current_log_)
    return;

  current_log_ = new MetricsLogBase(client_id_, session_id_,
                                    GetVersionString());
  if (state_ == INITIALIZED)
    state_ = ACTIVE;
}

void MetricsService::StopRecording(bool save_log) {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (!current_log_)
    return;

  // Put incremental histogram deltas at the end of all log transmissions.
  // Don't bother if we're going to discard current_log_.
  if (save_log) {
    CrashMetricsReporter::GetInstance()->RecordCrashMetrics();
    RecordCurrentHistograms();
  }

  if (save_log) {
    pending_log_ = current_log_;
  }
  current_log_ = NULL;
}

void MetricsService::MakePendingLog() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (pending_log())
    return;

  switch (state_) {
    case INITIALIZED:  // We should be further along by now.
      DCHECK(false);
      return;

    case ACTIVE:
      StopRecording(true);
      StartRecording();
      break;

    default:
      DCHECK(false);
      return;
  }

  DCHECK(pending_log());
}

bool MetricsService::TransmissionPermitted() const {
  // If the user forbids uploading that's their business, and we don't upload
  // anything.
  return user_permits_upload_;
}

std::string MetricsService::PrepareLogSubmissionString() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());

  MakePendingLog();
  DCHECK(pending_log());
  if (pending_log_== NULL) {
    return std::string();
  }

  pending_log_->CloseLog();
  std::string pending_log_text = pending_log_->GetEncodedLogString();
  DCHECK(!pending_log_text.empty());
  DiscardPendingLog();
  return pending_log_text;
}

bool MetricsService::UploadData() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());

  if (!GetInstance()->TransmissionPermitted())
    return false;

  static long currently_uploading = 0;
  if (InterlockedCompareExchange(&currently_uploading, 1, 0)) {
    DLOG(INFO) << "Contention for uploading metrics data. Backing off";
    return false;
  }

  std::string pending_log_text = PrepareLogSubmissionString();
  DCHECK(!pending_log_text.empty());

  // Allow security conscious users to see all metrics logs that we send.
  LOG(INFO) << "METRICS LOG: " << pending_log_text;

  bool ret = true;

  if (!Bzip2Compress(pending_log_text, &compressed_log_)) {
    NOTREACHED() << "Failed to compress log for transmission.";
    ret = false;
  } else {
    HRESULT hr = ChromeFrameMetricsDataUploader::UploadDataHelper(
        compressed_log_);
    DCHECK(SUCCEEDED(hr));
  }
  DiscardPendingLog();

  currently_uploading = 0;
  return ret;
}

// static
std::string MetricsService::GetVersionString() {
  chrome::VersionInfo version_info;
  if (version_info.is_valid()) {
    std::string version = version_info.Version();
    // Add the -F extensions to ensure that UMA data uploaded by ChromeFrame
    // lands in the ChromeFrame bucket.
    version += "-F";
    if (!version_info.IsOfficialBuild())
      version.append("-devel");
    return version;
  } else {
    NOTREACHED() << "Unable to retrieve version string.";
  }

  return std::string();
}
<commit_msg>Add ChromeFrame to the useragent string in outgoing UMA requests from ChromeFrame.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//------------------------------------------------------------------------------
// Description of the life cycle of a instance of MetricsService.
//
//  OVERVIEW
//
// A MetricsService instance is created at ChromeFrame startup in
// the IE process. It is the central controller for the UMA log data.
// Its major job is to manage logs, prepare them for transmission.
// Currently only histogram data is tracked in log.  When MetricsService
// prepares log for submission it snapshots the current stats of histograms,
// translates log to XML.  Transmission includes submitting a compressed log
// as data in a URL-get, and is performed using functionality provided by
// Urlmon
// The actual transmission is performed using a windows timer procedure which
// basically means that the thread on which the MetricsService object is
// instantiated needs a message pump. Also on IE7 where every tab is created
// on its own thread we would have a case where the timer procedures can
// compete for sending histograms.
//
// When preparing log for submission we acquire a list of all local histograms
// that have been flagged for upload to the UMA server.
//
// When ChromeFrame shuts down, there will typically be a fragment of an ongoing
// log that has not yet been transmitted.  Currently this data is ignored.
//
// With the above overview, we can now describe the state machine's various
// stats, based on the State enum specified in the state_ member.  Those states
// are:
//
//    INITIALIZED,      // Constructor was called.
//    ACTIVE,           // Accumalating log data.
//    STOPPED,          // Service has stopped.
//
//-----------------------------------------------------------------------------

#include "chrome_frame/metrics_service.h"

#include <windows.h>
#include <objbase.h>

#if defined(USE_SYSTEM_LIBBZ2)
#include <bzlib.h>
#else
#include "third_party/bzip2/bzlib.h"
#endif

#include "base/file_version_info.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/chrome_frame_distribution.h"
#include "chrome/installer/util/google_update_settings.h"
#include "chrome_frame/bind_status_callback_impl.h"
#include "chrome_frame/crash_reporting/crash_metrics.h"
#include "chrome_frame/html_utils.h"
#include "chrome_frame/http_negotiate.h"
#include "chrome_frame/utils.h"
#include "net/base/upload_data.h"
#include "chrome_frame/urlmon_bind_status_callback.h"

using base::Time;
using base::TimeDelta;

static const char kMetricsType[] =
    "Content-Type: application/vnd.mozilla.metrics.bz2\r\n";

// The first UMA upload occurs after this interval.
static const int kInitialUMAUploadTimeoutMilliSeconds = 30000;

// Default to one UMA upload per 10 mins.
static const int kMinMilliSecondsPerUMAUpload = 600000;

base::LazyInstance<base::ThreadLocalPointer<MetricsService> >
    MetricsService::g_metrics_instance_(base::LINKER_INITIALIZED);

extern base::LazyInstance<StatisticsRecorder> g_statistics_recorder_;

// This class provides functionality to upload the ChromeFrame UMA data to the
// server. An instance of this class is created whenever we have data to be
// uploaded to the server.
class ChromeFrameMetricsDataUploader : public BSCBImpl {
 public:
  ChromeFrameMetricsDataUploader()
      : cache_stream_(NULL),
        upload_data_size_(0) {
    DLOG(INFO) << __FUNCTION__;
  }

  ~ChromeFrameMetricsDataUploader() {
    DLOG(INFO) << __FUNCTION__;
  }

  static HRESULT ChromeFrameMetricsDataUploader::UploadDataHelper(
      const std::string& upload_data) {
    CComObject<ChromeFrameMetricsDataUploader>* data_uploader = NULL;
    CComObject<ChromeFrameMetricsDataUploader>::CreateInstance(&data_uploader);
    DCHECK(data_uploader != NULL);

    data_uploader->AddRef();
    HRESULT hr = data_uploader->UploadData(upload_data);
    if (FAILED(hr)) {
      DLOG(ERROR) << "Failed to initialize ChromeFrame UMA data uploader: Err"
                  << hr;
    }
    data_uploader->Release();
    return hr;
  }

  HRESULT UploadData(const std::string& upload_data) {
    if (upload_data.empty()) {
      NOTREACHED() << "Invalid upload data";
      return E_INVALIDARG;
    }

    DCHECK(cache_stream_.get() == NULL);

    upload_data_size_ = upload_data.size() + 1;

    HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, cache_stream_.Receive());
    if (FAILED(hr)) {
      NOTREACHED() << "Failed to create stream. Error:"
                   << hr;
      return hr;
    }

    DCHECK(cache_stream_.get());

    unsigned long written = 0;
    cache_stream_->Write(upload_data.c_str(), upload_data_size_, &written);
    DCHECK(written == upload_data_size_);

    RewindStream(cache_stream_);

    BrowserDistribution* dist = ChromeFrameDistribution::GetDistribution();
    server_url_ = dist->GetStatsServerURL();
    DCHECK(!server_url_.empty());

    hr = CreateURLMoniker(NULL, server_url_.c_str(),
                          upload_moniker_.Receive());
    if (FAILED(hr)) {
      DLOG(ERROR) << "Failed to create url moniker for url:"
                  << server_url_.c_str()
                  << " Error:"
                  << hr;
    } else {
      ScopedComPtr<IBindCtx> context;
      hr = CreateAsyncBindCtx(0, this, NULL, context.Receive());
      DCHECK(SUCCEEDED(hr));
      DCHECK(context);

      ScopedComPtr<IStream> stream;
      hr = upload_moniker_->BindToStorage(
          context, NULL, IID_IStream,
          reinterpret_cast<void**>(stream.Receive()));
      if (FAILED(hr)) {
        NOTREACHED();
        DLOG(ERROR) << "Failed to bind to upload data moniker. Error:"
                    << hr;
      }
    }
    return hr;
  }

  STDMETHOD(BeginningTransaction)(LPCWSTR url, LPCWSTR headers, DWORD reserved,
                                  LPWSTR* additional_headers) {
    std::string new_headers;
    new_headers = StringPrintf("Content-Length: %s\r\n",
                               base::Int64ToString(upload_data_size_).c_str());
    new_headers += kMetricsType;

    std::string user_agent_value = http_utils::GetDefaultUserAgent();
    user_agent_value = http_utils::AddChromeFrameToUserAgentValue(
        user_agent_value);

    new_headers += "User-Agent: " + user_agent_value;
    new_headers += "\r\n";

    *additional_headers = reinterpret_cast<wchar_t*>(
        CoTaskMemAlloc((new_headers.size() + 1) * sizeof(wchar_t)));

    lstrcpynW(*additional_headers, ASCIIToWide(new_headers).c_str(),
              new_headers.size());

    return BSCBImpl::BeginningTransaction(url, headers, reserved,
                                          additional_headers);
  }

  STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info) {
    if ((bind_info == NULL) || (bind_info->cbSize == 0) ||
        (bind_flags == NULL))
      return E_INVALIDARG;

    *bind_flags = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE | BINDF_PULLDATA;
    // Bypass caching proxies on POSTs and PUTs and avoid writing responses to
    // these requests to the browser's cache
    *bind_flags |= BINDF_GETNEWESTVERSION | BINDF_PRAGMA_NO_CACHE;

    DCHECK(cache_stream_.get());

    // Initialize the STGMEDIUM.
    memset(&bind_info->stgmedData, 0, sizeof(STGMEDIUM));
    bind_info->grfBindInfoF = 0;
    bind_info->szCustomVerb = NULL;
    bind_info->dwBindVerb = BINDVERB_POST;
    bind_info->stgmedData.tymed = TYMED_ISTREAM;
    bind_info->stgmedData.pstm = cache_stream_.get();
    bind_info->stgmedData.pstm->AddRef();
    return BSCBImpl::GetBindInfo(bind_flags, bind_info);
  }

  STDMETHOD(OnResponse)(DWORD response_code, LPCWSTR response_headers,
                        LPCWSTR request_headers, LPWSTR* additional_headers) {
    DLOG(INFO) << __FUNCTION__ << " headers: \n" << response_headers;
    return BSCBImpl::OnResponse(response_code, response_headers,
                                request_headers, additional_headers);
  }

 private:
  std::wstring server_url_;
  size_t upload_data_size_;
  ScopedComPtr<IStream> cache_stream_;
  ScopedComPtr<IMoniker> upload_moniker_;
};

MetricsService* MetricsService::GetInstance() {
  if (g_metrics_instance_.Pointer()->Get())
    return g_metrics_instance_.Pointer()->Get();

  g_metrics_instance_.Pointer()->Set(new MetricsService);
  return g_metrics_instance_.Pointer()->Get();
}

MetricsService::MetricsService()
    : recording_active_(false),
      reporting_active_(false),
      user_permits_upload_(false),
      state_(INITIALIZED),
      thread_(NULL),
      initial_uma_upload_(true),
      transmission_timer_id_(0) {
}

MetricsService::~MetricsService() {
  SetRecording(false);
  if (pending_log_) {
    delete pending_log_;
    pending_log_ = NULL;
  }
  if (current_log_) {
    delete current_log_;
    current_log_ = NULL;
  }
}

void MetricsService::InitializeMetricsState() {
  DCHECK(state_ == INITIALIZED);

  thread_ = PlatformThread::CurrentId();

  user_permits_upload_ = GoogleUpdateSettings::GetCollectStatsConsent();
  // Update session ID
  session_id_ = CrashMetricsReporter::GetInstance()->IncrementMetric(
      CrashMetricsReporter::SESSION_ID);

  // Ensure that an instance of the StatisticsRecorder object is created.
  g_statistics_recorder_.Get();

  CrashMetricsReporter::GetInstance()->set_active(true);
}

// static
void MetricsService::Start() {
  if (GetInstance()->state_ == ACTIVE)
    return;

  GetInstance()->InitializeMetricsState();
  GetInstance()->SetRecording(true);
  GetInstance()->SetReporting(true);
}

// static
void MetricsService::Stop() {
  GetInstance()->SetReporting(false);
  GetInstance()->SetRecording(false);
}

void MetricsService::SetRecording(bool enabled) {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (enabled == recording_active_)
    return;

  if (enabled) {
    if (client_id_.empty()) {
      client_id_ = GenerateClientID();
      // Save client id somewhere.
    }
    StartRecording();

  } else {
    state_ = STOPPED;
  }
  recording_active_ = enabled;
}

// static
std::string MetricsService::GenerateClientID() {
  const int kGUIDSize = 39;

  GUID guid;
  HRESULT guid_result = CoCreateGuid(&guid);
  DCHECK(SUCCEEDED(guid_result));

  std::wstring guid_string;
  int result = StringFromGUID2(guid,
                               WriteInto(&guid_string, kGUIDSize), kGUIDSize);
  DCHECK(result == kGUIDSize);
  return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
}

// static
void CALLBACK MetricsService::TransmissionTimerProc(HWND window,
                                                    unsigned int message,
                                                    unsigned int event_id,
                                                    unsigned int time) {
  DLOG(INFO) << "Transmission timer notified";
  DCHECK(GetInstance() != NULL);
  GetInstance()->UploadData();
  if (GetInstance()->initial_uma_upload_) {
    // If this is the first uma upload by this process then subsequent uma
    // uploads should occur once every 10 minutes(default).
    GetInstance()->initial_uma_upload_ = false;
    DCHECK(GetInstance()->transmission_timer_id_ != 0);
    SetTimer(NULL, GetInstance()->transmission_timer_id_,
             kMinMilliSecondsPerUMAUpload,
             reinterpret_cast<TIMERPROC>(TransmissionTimerProc));
  }
}

void MetricsService::SetReporting(bool enable) {
  static const int kChromeFrameMetricsTimerId = 0xFFFFFFFF;

  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (reporting_active_ != enable) {
    reporting_active_ = enable;
    if (reporting_active_) {
      transmission_timer_id_ =
          SetTimer(NULL, kChromeFrameMetricsTimerId,
                   kInitialUMAUploadTimeoutMilliSeconds,
                   reinterpret_cast<TIMERPROC>(TransmissionTimerProc));
    }
  }
}

//------------------------------------------------------------------------------
// Recording control methods

void MetricsService::StartRecording() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (current_log_)
    return;

  current_log_ = new MetricsLogBase(client_id_, session_id_,
                                    GetVersionString());
  if (state_ == INITIALIZED)
    state_ = ACTIVE;
}

void MetricsService::StopRecording(bool save_log) {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (!current_log_)
    return;

  // Put incremental histogram deltas at the end of all log transmissions.
  // Don't bother if we're going to discard current_log_.
  if (save_log) {
    CrashMetricsReporter::GetInstance()->RecordCrashMetrics();
    RecordCurrentHistograms();
  }

  if (save_log) {
    pending_log_ = current_log_;
  }
  current_log_ = NULL;
}

void MetricsService::MakePendingLog() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());
  if (pending_log())
    return;

  switch (state_) {
    case INITIALIZED:  // We should be further along by now.
      DCHECK(false);
      return;

    case ACTIVE:
      StopRecording(true);
      StartRecording();
      break;

    default:
      DCHECK(false);
      return;
  }

  DCHECK(pending_log());
}

bool MetricsService::TransmissionPermitted() const {
  // If the user forbids uploading that's their business, and we don't upload
  // anything.
  return user_permits_upload_;
}

std::string MetricsService::PrepareLogSubmissionString() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());

  MakePendingLog();
  DCHECK(pending_log());
  if (pending_log_== NULL) {
    return std::string();
  }

  pending_log_->CloseLog();
  std::string pending_log_text = pending_log_->GetEncodedLogString();
  DCHECK(!pending_log_text.empty());
  DiscardPendingLog();
  return pending_log_text;
}

bool MetricsService::UploadData() {
  DCHECK_EQ(thread_, PlatformThread::CurrentId());

  if (!GetInstance()->TransmissionPermitted())
    return false;

  static long currently_uploading = 0;
  if (InterlockedCompareExchange(&currently_uploading, 1, 0)) {
    DLOG(INFO) << "Contention for uploading metrics data. Backing off";
    return false;
  }

  std::string pending_log_text = PrepareLogSubmissionString();
  DCHECK(!pending_log_text.empty());

  // Allow security conscious users to see all metrics logs that we send.
  LOG(INFO) << "METRICS LOG: " << pending_log_text;

  bool ret = true;

  if (!Bzip2Compress(pending_log_text, &compressed_log_)) {
    NOTREACHED() << "Failed to compress log for transmission.";
    ret = false;
  } else {
    HRESULT hr = ChromeFrameMetricsDataUploader::UploadDataHelper(
        compressed_log_);
    DCHECK(SUCCEEDED(hr));
  }
  DiscardPendingLog();

  currently_uploading = 0;
  return ret;
}

// static
std::string MetricsService::GetVersionString() {
  chrome::VersionInfo version_info;
  if (version_info.is_valid()) {
    std::string version = version_info.Version();
    // Add the -F extensions to ensure that UMA data uploaded by ChromeFrame
    // lands in the ChromeFrame bucket.
    version += "-F";
    if (!version_info.IsOfficialBuild())
      version.append("-devel");
    return version;
  } else {
    NOTREACHED() << "Unable to retrieve version string.";
  }

  return std::string();
}
<|endoftext|>


<commit_before>#include <boost/python.hpp>
#include <vector>

typedef int player_id;

class TBT_game_core;

struct TBT_game_player
{
        TBT_game_player(player_id p_id,TBT_game_core * core)
        {
            this->p_id = p_id;
            this->game_core = core;
        }

        void do_turn(int hand);

        player_id p_id;
        TBT_game_core * game_core;
};

class TBT_game_core
{
    public:
        TBT_game_core()
        {
            initial_stage = true;
            last_player_id = -1;
        }

        TBT_game_player& generate_new_player()
        {
            players.push_back(new TBT_game_player(++last_player_id,this));
            return &(players[last_player_id]);
        }

        void end_initial_stage()
        {
            initial_stage = false;
            current_turn_no = 0;
            score = std::vector<int> (last_player_id,0);
            current_turn = new std::vector<int>(last_player_id,0);
            current_turn_done = std::vector<bool>(last_player_id,false);
        }

        void inform_turn_done(player_id id,int hand)
        {
            current_turn->at(id) = hand;
            current_turn_done[id] = true;
            check_next_turn();
        }

        player_id get_winner()
        {
            if (current_turn_no < 10)
                return -1;
            player_id maxi = 0;
            for (int i = 0; i < last_player_id; i++)
                if (score[i] > score[maxi])
                    maxi = i;
            return maxi;
        }
    private:
        void check_next_turn()
        {
            player_id i;
            for (i=0;i<last_player_id;i++)
                if (!current_turn_done[i])
                    return;

            do_next_turn();

            current_turn_done = std::vector<bool>(last_player_id,false);
            old_turns.push_back(*current_turn);
            current_turn = new std::vector<int> (last_player_id,0);
        }

        /*
        All the logic is in here.
        *
        */
        void do_next_turn()
        {
            for (player_id i = 0;i<last_player_id;i++)
                for (player_id j=0;i<last_player_id;j++)
                    if (current_turn->at(i) == (current_turn->at(j)+1)%3)
                        score[i]++;
        }

        bool initial_stage;
        player_id last_player_id;
        int current_turn_no;
        std::vector<TBT_game_player> players;
        std::vector<int> score;
        std::vector<int> * current_turn;
        std::vector<bool> current_turn_done;
        std::vector< std::vector<int> > old_turns;
};

void TBT_game_player::do_turn(int hand)
        {
            this->game_core->inform_turn_done(this->p_id,hand);
        }

using namespace boost::python;

BOOST_PYTHON_MODULE(libtbtg)
{
    class_<TBT_game_core>("TBT_game_core")
        .def("end_initial_stage", &TBT_game_core::end_initial_stage)
        .def("inform_turn_done", &TBT_game_core::inform_turn_done)
        .def("get_winner", &TBT_game_core::get_winner)
        .def("generate_new_player", &TBT_game_core::generate_new_player)
    ;

    class_<TBT_game_player>("TBT_game_player", init<player_id,TBT_game_core*>())
        .def("do_turn", &TBT_game_player::do_turn)
    ;

}
<commit_msg>fixing shivs bugs<commit_after>#include <boost/python.hpp>
#include <vector>

using namespace boost::python;

typedef int player_id;

class TBT_game_core;

struct TBT_game_player
{
        TBT_game_player(player_id p_id,TBT_game_core * core)
        {
            this->p_id = p_id;
            this->game_core = core;
        }

        void do_turn(int hand);

        player_id p_id;
        TBT_game_core * game_core;
};

struct TBT_game_player_python
{
	static PyObject* convert(TBT_game_player const& p)
	{
		return boost::python::incref(boost::python::object(p).ptr());
    }
};

class TBT_game_core
{
    public:
        TBT_game_core()
        {
            initial_stage = true;
            last_player_id = -1;
        }

        PyObject * generate_new_player()
        {
            players.push_back(*(new TBT_game_player(++last_player_id, this)));
            return TBT_game_player_python::convert(players[last_player_id]);
        }

        void end_initial_stage()
        {
            initial_stage = false;
            current_turn_no = 0;
            score = std::vector<int> (last_player_id + 1, 0);
            current_turn = new std::vector<int>(last_player_id + 1, 0);
            current_turn_done = std::vector<bool>(last_player_id + 1,false);
        }

        void inform_turn_done(player_id id,int hand)
        {
            current_turn->at(id) = hand;
            current_turn_done[id] = true;
            check_next_turn();
        }

        player_id get_winner()
        {
            if (current_turn_no < 10)
                return -1;
            player_id maxi = 0;
            for (int i = 0; i < last_player_id; i++)
                if (score[i] > score[maxi])
                    maxi = i;
            return maxi;
        }
    private:

        void check_next_turn()
        {
            player_id i;
            for (i=0;i<last_player_id;i++)
                if (!current_turn_done[i])
                    return;

            do_next_turn();

            current_turn_done = std::vector<bool>(last_player_id,false);
            old_turns.push_back(*current_turn);
            current_turn = new std::vector<int> (last_player_id,0);
        }

        /*
        All the logic is in here.
        *
        */
        void do_next_turn()
        {
            for (player_id i = 0;i<last_player_id;i++)
                for (player_id j=0;i<last_player_id;j++)
                    if (current_turn->at(i) == (current_turn->at(j)+1)%3)
                        score[i]++;
        }

        bool initial_stage;
        player_id last_player_id;
        int current_turn_no;
        std::vector<TBT_game_player> players;
        std::vector<int> score;
        std::vector<int> * current_turn;
        std::vector<bool> current_turn_done;
        std::vector< std::vector<int> > old_turns;
};

void TBT_game_player::do_turn(int hand)
{
            this->game_core->inform_turn_done(this->p_id, hand);
}

BOOST_PYTHON_MODULE(libtbtg)
{

	boost::python::to_python_converter<
	  TBT_game_player,
	  TBT_game_player_python>();

    class_<TBT_game_core>("TBT_game_core")
        .def("end_initial_stage", &TBT_game_core::end_initial_stage)
        .def("inform_turn_done", &TBT_game_core::inform_turn_done)
        .def("get_winner", &TBT_game_core::get_winner)
        .def("generate_new_player", &TBT_game_core::generate_new_player)
    ;

    class_<TBT_game_player>("TBT_game_player", init<player_id,TBT_game_core*>())
        .def("do_turn", &TBT_game_player::do_turn)
    ;

}
<|endoftext|>


<commit_before>// Copyright 2013 Sean McKenna
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//

// light sub-classes (e.g. generic, ambient, direct, point)
// originally adapted from code provided by Cem Yuksel

// namespace
using namespace scene;
namespace scene{

// generic light definition (from main light class)
class GenericLight: public Light{
  public:

    // calculate a shadow for any light (never call from ambient!)
    float shadow(Cone ray, float z = FLOAT_MAX){

      // set initial hit info
      HitInfo h = HitInfo();
      h.z = z;

      // check ray from point to light, is it occluded?
      bool occlude = traceRay(ray, h);

      // return 0 if in shadow, 1 if lit directly
      if(occlude)
        return 0.0;
      else
        return 1.0;
    }
};

// ambient light definition
class AmbientLight: public GenericLight{
  public:

    // constructor
    AmbientLight(){
      intensity.Set(0, 0, 0);
    }

    // get color of ambient light
    Color illuminate(Point p){
      return intensity;
    }

    // get direction of ambient light (non-sensical)
    Point direction(Point p){
      return Point(0, 0, 0);
    }

    // return true, since light is ambient
    bool isAmbient(){
      return true;
    }

    // set color of ambient light
    void setIntensity(Color c){
      intensity = c;
    }

  private:

    // intensity (or color) of light
    Color intensity;
};

// direct light definition
class DirectLight: public GenericLight{
  public:

    // constructor
    DirectLight(){
      intensity.Set(0, 0, 0);
      dir.Set(0, 0, 1);
    }

    // get color of direct light (check for shadows)
    Color illuminate(Point p){
      Cone r = Cone();
      r.pos = p;
      r.dir = -dir;
      return shadow(r) * intensity;
    }

    // get direction of direct light (constant)
    Point direction(Point p){
      return dir;
    }

    // set color of direct light
    void setIntensity(Color c){
      intensity = c;
    }

    // set direction of direct light
    void setDirection(Point d){
      dir = d.GetNormalized();
    }

  private:

    // intensity (or color) of light
    Color intensity;

    // direction of light
    Point dir;
};

// point light definition
class PointLight: public GenericLight{
  public:

    // constructor
    PointLight(){
      intensity.Set(0, 0, 0);
      position.Set(0, 0, 0);
      size = 0.0;
    }

    // get color of point light (check for shadows)
    Color illuminate(Point p){
      if(size == 0.0){
        Cone r = Cone();
        r.pos = p;
        r.dir = position - p;
        return shadow(r, 1.0) * intensity;

      // otherwise, we have a spherical light, cast multiple shadow rays
      }else{

        // to detect if we are in the penumbra
        bool penumbra = false;

        // keep track of running shadow variables
        int count;
        float mean = 0.0;

        // calculate random rotation for Halton sequence on our sphere of confusion
        float rotate = dist(rnd) * 2.0 * M_PI;

        // cast our minmum number of shadow rays
        for(count = 0; count < shadowMin; count++){

          // calculate (partially) randomized shadow ray
          Cone r = getShadowRay(p, count, rotate);

          // cast shadow ray
          int val = shadow(r, 1.0);

          // update our mean shadow value
          mean = ((float) (mean * count + val)) / ((float) (count + 1));

          // check if we are in penumbra
          if(mean != 0.0 && mean != 1.0)
            penumbra = true;
        }

        // continue casting more shadow rays, if in penumbra
        if(penumbra){

          // continue casting shadow rays
          for(count = shadowMin; count < shadowMax; count++){

            // calculate (partially) randomized shadow ray
            Cone r = getShadowRay(p, count, rotate);

            // cast shadow ray
            int val = shadow(r, 1.0);

            // update our mean shadow value
            mean = ((float) (mean * count + val)) / ((float) (count + 1));
          }
        }

        // return our final shaded intensity
        return mean * intensity;
      }
    }

    // get direction of point light (calculated)
    Point direction(Point p){
      return (p - position).GetNormalized();
    }

    // set color of point light
    void setIntensity(Color c){
      intensity = c;
    }

    // set the location of the point light
    void setPosition(Point pos){
      position = pos;
    }

    // set the size of the point light (now a sphere)
    void setSize(float s){
      size = s;
    }

    // set shadow ray samples (min & max)
    void setShadowRays(int min, int max){
      shadowMin = min;
      shadowMax = max;
    }

  private:

    // intensity (or color) of light
    Color intensity;

    // location of light
    Point position;

    // size of point light (sphere if not zero)
    float size;

    // how many shadow rays to cast
    int shadowMin;
    int shadowMax;

    // random number generation for light disk rotation
    mt19937 rnd;
    uniform_real_distribution<float> dist{0.0, 1.0};

    // calculate a randomized light position on a spherical light
    Cone getShadowRay(Point p, int c, float r){

      // get original direction
      Point dir = (position - p).GetNormalized();

      // get two vectors for spanning our light disk
      Point v0 = Point(0.0, 1.0, 0.0);
      if(v0 % dir < 0.1 && v0 % dir > -0.1)
        v0 = Point(0.0, 0.0, 1.0);
      Point v1 = (v0 ^ dir).GetNormalized();

      // grab Halton sequence to shift point along light disk
      // first four points on the perimeter of the disk
      float diskRad;
      if(c < 4)
        diskRad = 1.0 * size;
      else
        diskRad = sqrt(Halton(c - 4, 2)) * size;

      // grab Halton sequence to shift point around light disk
      // first four points will be distributed about the perimeter
      float diskRot;
      if(c == 0)
        diskRot = 0.0;
      else if(c == 1)
        diskRot = 1.0 * M_PI;
      else if(c == 2)
        diskRot = 0.5 * M_PI;
      else if(c == 3)
        diskRot = 1.5 * M_PI;
      else
        diskRot = Halton(c - 4, 3) * 2.0 * M_PI;

      // compute our semi-random position inside the disk
      Point pos = position + (v0 * diskRad * cos(diskRot + r)) + (v1 * diskRad * sin(diskRot + r));

      // shadow ray to return
      Cone ray = Cone();
      ray.pos = p;
      ray.dir = pos - p;
      return ray;
    }
};
}
<commit_msg>update shadow ray calculation, better vectors to span light disk<commit_after>// Copyright 2013 Sean McKenna
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//

// light sub-classes (e.g. generic, ambient, direct, point)
// originally adapted from code provided by Cem Yuksel

// namespace
using namespace scene;
namespace scene{

// generic light definition (from main light class)
class GenericLight: public Light{
  public:

    // calculate a shadow for any light (never call from ambient!)
    float shadow(Cone ray, float z = FLOAT_MAX){

      // set initial hit info
      HitInfo h = HitInfo();
      h.z = z;

      // check ray from point to light, is it occluded?
      bool occlude = traceRay(ray, h);

      // return 0 if in shadow, 1 if lit directly
      if(occlude)
        return 0.0;
      else
        return 1.0;
    }
};

// ambient light definition
class AmbientLight: public GenericLight{
  public:

    // constructor
    AmbientLight(){
      intensity.Set(0, 0, 0);
    }

    // get color of ambient light
    Color illuminate(Point p){
      return intensity;
    }

    // get direction of ambient light (non-sensical)
    Point direction(Point p){
      return Point(0, 0, 0);
    }

    // return true, since light is ambient
    bool isAmbient(){
      return true;
    }

    // set color of ambient light
    void setIntensity(Color c){
      intensity = c;
    }

  private:

    // intensity (or color) of light
    Color intensity;
};

// direct light definition
class DirectLight: public GenericLight{
  public:

    // constructor
    DirectLight(){
      intensity.Set(0, 0, 0);
      dir.Set(0, 0, 1);
    }

    // get color of direct light (check for shadows)
    Color illuminate(Point p){
      Cone r = Cone();
      r.pos = p;
      r.dir = -dir;
      return shadow(r) * intensity;
    }

    // get direction of direct light (constant)
    Point direction(Point p){
      return dir;
    }

    // set color of direct light
    void setIntensity(Color c){
      intensity = c;
    }

    // set direction of direct light
    void setDirection(Point d){
      dir = d.GetNormalized();
    }

  private:

    // intensity (or color) of light
    Color intensity;

    // direction of light
    Point dir;
};

// point light definition
class PointLight: public GenericLight{
  public:

    // constructor
    PointLight(){
      intensity.Set(0, 0, 0);
      position.Set(0, 0, 0);
      size = 0.0;
    }

    // get color of point light (check for shadows)
    Color illuminate(Point p){
      if(size == 0.0){
        Cone r = Cone();
        r.pos = p;
        r.dir = position - p;
        return shadow(r, 1.0) * intensity;

      // otherwise, we have a spherical light, cast multiple shadow rays
      }else{

        // to detect if we are in the penumbra
        bool penumbra = false;

        // keep track of running shadow variables
        int count;
        float mean = 0.0;

        // calculate random rotation for Halton sequence on our sphere of confusion
        float rotate = dist(rnd) * 2.0 * M_PI;

        // cast our minmum number of shadow rays
        for(count = 0; count < shadowMin; count++){

          // calculate (partially) randomized shadow ray
          Cone r = getShadowRay(p, count, rotate);

          // cast shadow ray
          int val = shadow(r, 1.0);

          // update our mean shadow value
          mean = ((float) (mean * count + val)) / ((float) (count + 1));

          // check if we are in penumbra
          if(mean != 0.0 && mean != 1.0)
            penumbra = true;
        }

        // continue casting more shadow rays, if in penumbra
        if(penumbra){

          // continue casting shadow rays
          for(count = shadowMin; count < shadowMax; count++){

            // calculate (partially) randomized shadow ray
            Cone r = getShadowRay(p, count, rotate);

            // cast shadow ray
            int val = shadow(r, 1.0);

            // update our mean shadow value
            mean = ((float) (mean * count + val)) / ((float) (count + 1));
          }
        }

        // return our final shaded intensity
        return mean * intensity;
      }
    }

    // get direction of point light (calculated)
    Point direction(Point p){
      return (p - position).GetNormalized();
    }

    // set color of point light
    void setIntensity(Color c){
      intensity = c;
    }

    // set the location of the point light
    void setPosition(Point pos){
      position = pos;
    }

    // set the size of the point light (now a sphere)
    void setSize(float s){
      size = s;
    }

    // set shadow ray samples (min & max)
    void setShadowRays(int min, int max){
      shadowMin = min;
      shadowMax = max;
    }

  private:

    // intensity (or color) of light
    Color intensity;

    // location of light
    Point position;

    // size of point light (sphere if not zero)
    float size;

    // how many shadow rays to cast
    int shadowMin;
    int shadowMax;

    // random number generation for light disk rotation
    mt19937 rnd;
    uniform_real_distribution<float> dist{0.0, 1.0};

    // calculate a randomized light position on a spherical light
    Cone getShadowRay(Point p, int c, float r){

      // get original direction
      Point dir = (position - p).GetNormalized();

      // get two vectors for spanning our light disk
      Point v0 = Point(0.0, 1.0, 0.0);
      if(v0 % dir < 0.5 && v0 % dir > -0.5)
        v0 = Point(0.0, 0.0, 1.0);
      Point v1 = (v0 ^ dir).GetNormalized();

      // grab Halton sequence to shift point along light disk
      // first four points on the perimeter of the disk
      float diskRad;
      if(c < 4)
        diskRad = 1.0 * size;
      else
        diskRad = sqrt(Halton(c - 4, 2)) * size;

      // grab Halton sequence to shift point around light disk
      // first four points will be distributed about the perimeter
      float diskRot;
      if(c == 0)
        diskRot = 0.0;
      else if(c == 1)
        diskRot = 1.0 * M_PI;
      else if(c == 2)
        diskRot = 0.5 * M_PI;
      else if(c == 3)
        diskRot = 1.5 * M_PI;
      else
        diskRot = Halton(c - 4, 3) * 2.0 * M_PI;

      // compute our semi-random position inside the disk
      Point pos = position + (v0 * diskRad * cos(diskRot + r)) + (v1 * diskRad * sin(diskRot + r));

      // shadow ray to return
      Cone ray = Cone();
      ray.pos = p;
      ray.dir = pos - p;
      return ray;
    }
};
}
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib> // exit()
#include <cstdio> // printf()
#include <cstring> // strcmp()
#include <string>
#include <stack>
#include <openssl/sha.h>
#include <byteswap.h>
#include "alphabet.h"

using namespace std;

string pwd;

char pwdHash[SHA256_DIGEST_LENGTH];
char bruteHash[SHA256_DIGEST_LENGTH];

static const unsigned char MaxChars = 3;

void printSHAHash(unsigned int* pbuf)
{
    // byteswap the integer pointed to, to display hex dump in correct order
    // TODO: how to deal with big endian machines
    printf("%X%X%X%X%X%X%X%X\n",
           bswap_32(*(pbuf)),
           bswap_32(*(pbuf+1)),
           bswap_32(*(pbuf+2)),
           bswap_32(*(pbuf+3)),
           bswap_32(*(pbuf+4)),
           bswap_32(*(pbuf+5)),
           bswap_32(*(pbuf+6)),
           bswap_32(*(pbuf+7))
          );
}

bool generateSHA256(const void *const inputStr, const size_t &length, char *const hashStr)
{
    SHA256_CTX hash;
    if(!SHA256_Init(&hash))
    {
        return false;
    }

    if(!SHA256_Update(&hash, inputStr, length))
    {
        return false;
    }

    if(!SHA256_Final(reinterpret_cast<unsigned char*>(hashStr), &hash))
    {
        return false;
    }

    return true;
}

void checkPassword(const string &password)
{
//#ifdef VERBOSE
    cout << "checking " << password << endl;
//#endif // VERBOSE

    // generate sha hash from entered string and write it to pwdHash
    if(!generateSHA256(password.c_str(), password.length(), bruteHash))
    {
        cerr << "Error when generating SHA256 from \"" << password << "\"" << endl;
        //return;
    }

    if (!memcmp(bruteHash, pwdHash, SHA256_DIGEST_LENGTH))
    {
        cout << "match [" << password << "]" << endl << "hash: " << endl;
        printSHAHash((unsigned int*)bruteHash);
        exit(0);
    }
}

void bruteRecursive(const string baseString, const unsigned int width)
{
    for(int i=0; i<SizeAlphabet; i++)
    {
        if (baseString.length()+1 < width)
        {
            bruteRecursive(baseString+alphabet[i], width);
        }

        checkPassword(baseString+alphabet[i]);
    }
}

void bruteIterative(const unsigned int width)
{
    stack<string> myStack;

    // myStack must contain at least one element when entering loop
    // else: SIGSEGV
    // hence, start checking with an empty string
    myStack.push("");

    do
    {
        string baseString = myStack.top();
        myStack.pop();
        cout << "checking passwords with " << baseString.length()+1 << " characters..." << endl;
        for(int i=0; i<SizeAlphabet; i++)
        {
            if (baseString.length()+1 < width)
            {
                myStack.push(baseString+alphabet[i]);
            }

            checkPassword(baseString+alphabet[i]);
        }
    }
    while(!myStack.empty());
}

int main()
{
    cout << "Enter a string: " << endl;
    cin >> pwd;

    // generate sha hash from entered string and write it to pwdHash
    if(!generateSHA256(pwd.c_str(), pwd.length(), pwdHash))
    {
        cerr << "Error when generating SHA256 from \"" << pwd << "\"" << endl;
        return -2;
    }
    else
    {
        printf("SHA256 Hash for your string is:\n");
        printSHAHash((unsigned int*)pwdHash);

    }

    cout << "checking using Recusive Method" << endl;
    for(int i=1; i<=MaxChars; i++)
    {
        cout << "checking passwords with " << i << " characters..." << endl;
        bruteRecursive(string(""),i);
    }

    cout << "checking using Iterative Method" << endl;
    bruteIterative(MaxChars);

    return -1;
}
<commit_msg>added lots of comments<commit_after>#include <iostream>
#include <cstdlib> // exit()
#include <cstdio> // printf()
#include <cstring> // memcmp()
#include <string>
#include <stack>
#include <openssl/sha.h>
#include <byteswap.h>
#include "alphabet.h"

using namespace std;

// clear text password entered by user
string pwd;

// contains the hash of the unknown password
char pwdHash[SHA256_DIGEST_LENGTH];

// contains the hash of a bruteforced string
char bruteHash[SHA256_DIGEST_LENGTH];

// the maximum number of characters bruteforce shall check
static const unsigned char MaxChars = 3;

/**
 * @brief prints 32 bytes of memory
 *
 * prints a hex dump of 32 bytes of memory pointed to
 *
 * @param[in]   pbuf: pointer to some memory, usually containing an SHA256 hash
 */
void printSHAHash(const unsigned int *const pbuf)
{
    // byteswap the integer pointed to, to display hex dump in correct order
    // TODO: how to deal with big endian machines
    printf("%X%X%X%X%X%X%X%X\n",
           bswap_32(*(pbuf)),
           bswap_32(*(pbuf+1)),
           bswap_32(*(pbuf+2)),
           bswap_32(*(pbuf+3)),
           bswap_32(*(pbuf+4)),
           bswap_32(*(pbuf+5)),
           bswap_32(*(pbuf+6)),
           bswap_32(*(pbuf+7))
          );
}

/**
 * @brief generates an SHA256 hash
 *
 * generates an SHA256 hash using openSSL
 *
 * @param[in]      input:   a const pointer to const block of data, usually a char array of which the hash is being generated
 * @param[in]      length:  the number of bytes the that input points to holds
 * @param[in,out]  hashStr: const pointer to an array of SHA256_DIGEST_LENGTH bytes that will receive the hash
 *
 * @return returns true if the hash has been generated successfully; returns false if input or hashStr is NULL or length==0; else: false
 */
bool generateSHA256(const void *const input, const size_t &length, char *const hashStr)
{
    if(!hashStr || !input || length==0)
    {
        return false;
    }

    SHA256_CTX hash;
    if(!SHA256_Init(&hash))
    {
        return false;
    }

    if(!SHA256_Update(&hash, input, length))
    {
        return false;
    }

    if(!SHA256_Final(reinterpret_cast<unsigned char*>(hashStr), &hash))
    {
        return false;
    }

    return true;
}

/**
 * @brief checks equality of two hashes
 *
 * calculates the SHA256 hash of 'password' and compares it
 * with the initial password hash
 *
 * @param[in]   password: a const string containing a guessed password
 */
void checkPassword(const string &password)
{
//#ifdef VERBOSE
    cout << "checking " << password << endl;
//#endif // VERBOSE

    // generate sha hash from entered string and write it to pwdHash
    if(!generateSHA256(password.c_str(), password.length(), bruteHash))
    {
        cerr << "Error when generating SHA256 from \"" << password << "\"" << endl;
        //return;
    }

    if (!memcmp(bruteHash, pwdHash, SHA256_DIGEST_LENGTH))
    {
        cout << "match [" << password << "]" << endl << "hash: " << endl;
        printSHAHash((unsigned int*)bruteHash);
        exit(0);
    }
}

/**
 * @brief recursive implementation of bruteforce
 *
 * recursive implementation of bruteforce attack
 * call it as follows: bruteRecursive(string(""), width);
 *
 * @param[in]   baseString: a const string indicates the prefix of a string to be checked
 * @param[in]   width:      the maximum number of characters you wish to be checked
 */
void bruteRecursive(const string baseString, const unsigned int width)
{
    for(int i=0; i<SizeAlphabet; i++)
    {
        if (baseString.length()+1 < width)
        {
            bruteRecursive(baseString+alphabet[i], width);
        }

        checkPassword(baseString+alphabet[i]);
    }
}

/**
 * @brief iterative implementation of bruteforce
 *
 * iterative implementation of bruteforce attack
 * call it as follows: bruteIterative(width);
 *
 * @param[in]   width:      the maximum number of characters you wish to be checked
 */
void bruteIterative(const unsigned int width)
{
    stack<string> myStack;

    // myStack must contain at least one element when entering loop
    // else: SIGSEGV
    // hence, start checking with an empty string
    myStack.push("");

    do
    {
        string baseString = myStack.top();
        myStack.pop();
        cout << "checking passwords with " << baseString.length()+1 << " characters..." << endl;
        for(int i=0; i<SizeAlphabet; i++)
        {
            if (baseString.length()+1 < width)
            {
                myStack.push(baseString+alphabet[i]);
            }

            checkPassword(baseString+alphabet[i]);
        }
    }
    while(!myStack.empty());
}

int main()
{
    cout << "Enter a string: " << endl;
    cin >> pwd;

    // generate sha hash from entered string and write it to pwdHash
    if(!generateSHA256(pwd.c_str(), pwd.length(), pwdHash))
    {
        cerr << "Error when generating SHA256 from \"" << pwd << "\"" << endl;
        return -2;
    }
    else
    {
        printf("SHA256 Hash for your string is:\n");
        printSHAHash((unsigned int*)pwdHash);

    }

    cout << "checking using Recusive Method" << endl;
    for(int i=1; i<=MaxChars; i++)
    {
        cout << "checking passwords with " << i << " characters..." << endl;
        bruteRecursive(string(""),i);
    }

    cout << "checking using Iterative Method" << endl;
    bruteIterative(MaxChars);

    return -1;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <immintrin.h>
#include <new>
#include <cassert>
#include <sstream>
#include "simd_util.h"
#include "pauli_string.h"
#include <cstring>
#include <cstdlib>
#include <bit>

PauliStringPtr::PauliStringPtr(
            size_t init_size,
            BitPtr init_sign,
            uint64_t *init_x,
            uint64_t *init_z,
            size_t init_stride256) :
        size(init_size),
        bit_ptr_sign(init_sign),
        _x(init_x),
        _z(init_z),
        stride256(init_stride256) {
}

PauliStringVal::PauliStringVal(size_t init_size) :
        val_sign(false),
        x_data(init_size),
        z_data(init_size) {
}

PauliStringVal::PauliStringVal(const PauliStringPtr &other) :
        val_sign(other.bit_ptr_sign.get()),
        x_data(other.size, other._x),
        z_data(other.size, other._z) {
}

PauliStringPtr PauliStringVal::ptr() const {
    return PauliStringPtr(*this);
}

std::string PauliStringVal::str() const {
    return ptr().str();
}

void PauliStringPtr::swap_with(PauliStringPtr &other) {
    assert(size == other.size);
    bit_ptr_sign.swap(other.bit_ptr_sign);
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        std::swap(*x256, *ox256);
        std::swap(*z256, *oz256);
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }
}

void PauliStringPtr::overwrite_with(const PauliStringPtr &other) {
    assert(size == other.size);
    bit_ptr_sign.set(other.bit_ptr_sign.get());
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        *x256 = *ox256;
        *z256 = *oz256;
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }
}

PauliStringVal& PauliStringVal::operator=(const PauliStringPtr &other) noexcept {
    (*this).~PauliStringVal();
    new(this) PauliStringVal(other);
    return *this;
}

PauliStringPtr::PauliStringPtr(const PauliStringVal &other) :
        size(other.x_data.num_bits),
        bit_ptr_sign(BitPtr((void *)&other.val_sign, 0)),
        _x(other.x_data.u64),
        _z(other.z_data.u64),
        stride256(1) {
}

uint8_t PauliStringPtr::log_i_scalar_byproduct(const PauliStringPtr &other) const {
    assert(size == other.size);
    union {__m256i u256; uint64_t u64[4]; } cnt1 {};
    union {__m256i u256; uint64_t u64[4]; } cnt2 {};
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        auto x1 = *x256;
        auto z2 = *oz256;
        auto z1 = *z256;
        auto x2 = *ox256;
        auto t1 = x1 & z2;
        auto t2 = x2 & z1;
        auto f = t1 ^ t2;
        auto b = ((x1 ^ z2) & t2) ^ _mm256_andnot_si256(z1, _mm256_andnot_si256(x2, t1));
        cnt1.u256 ^= b;
        cnt2.u256 ^= cnt1.u256 & f;
        cnt1.u256 ^= f ^ b;
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }
    size_t s = 0;
    for (size_t k = 0; k < 4; k++) {
        s += (uint8_t) std::popcount(cnt1.u64[k]);
        s ^= (uint8_t) std::popcount(cnt2.u64[k]) << 1;
    }
    return s & 3;
}

std::string PauliStringPtr::str() const {
    std::stringstream ss;
    ss << *this;
    return ss.str();
}

bool PauliStringPtr::operator==(const PauliStringPtr &other) const {
    if (size != other.size || bit_ptr_sign.get() != other.bit_ptr_sign.get()) {
        return false;
    }
    __m256i acc {};
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        acc |= *x256 ^ *ox256;
        acc |= *z256 ^ *oz256;
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }

    auto acc64 = (uint64_t *)&acc;
    for (size_t k = 0; k < 4; k++) {
        if (acc64[k]) {
            return false;
        }
    }

    return true;
}

bool PauliStringPtr::operator!=(const PauliStringPtr &other) const {
    return !(*this == other);
}

std::ostream &operator<<(std::ostream &out, const PauliStringVal &ps) {
    return out << ps.ptr();
}

size_t PauliStringPtr::num_words256() const {
    return ceil256(size) >> 8;
}

std::ostream &operator<<(std::ostream &out, const PauliStringPtr &ps) {
    out << (ps.bit_ptr_sign.get() ? '-' : '+');
    auto x256 = (__m256i *)ps._x;
    auto z256 = (__m256i *)ps._z;
    auto end = &x256[ps.num_words256() * ps.stride256];
    size_t remaining = ps.size;
    while (x256 != end) {
        auto xs = m256i_to_bits(*x256);
        auto zs = m256i_to_bits(*z256);
        for (int j = 0; j < 256 && remaining; j++) {
            out << "_XZY"[xs[j] + 2 * zs[j]];
            remaining--;
        }
        x256 += ps.stride256;
        z256 += ps.stride256;
    }
    return out;
}

PauliStringVal PauliStringVal::from_pattern(bool sign, size_t size, const std::function<char(size_t)> &func) {
    PauliStringVal result(size);
    result.val_sign = sign;
    for (size_t i = 0; i < size; i++) {
        char c = func(i);
        bool x;
        bool z;
        if (c == 'X') {
            x = true;
            z = false;
        } else if (c == 'Y') {
            x = true;
            z = true;
        } else if (c == 'Z') {
            x = false;
            z = true;
        } else if (c == '_' || c == 'I') {
            x = false;
            z = false;
        } else {
            throw std::runtime_error("Unrecognized pauli character. " + std::to_string(c));
        }
        result.x_data.u64[i / 64] ^= (uint64_t)x << (i & 63);
        result.z_data.u64[i / 64] ^= (uint64_t)z << (i & 63);
    }
    return result;
}

PauliStringVal PauliStringVal::from_str(const char *text) {
    auto sign = text[0] == '-';
    if (text[0] == '+' || text[0] == '-') {
        text++;
    }
    return PauliStringVal::from_pattern(sign, strlen(text), [&](size_t i){ return text[i]; });
}

PauliStringVal PauliStringVal::identity(size_t size) {
    return PauliStringVal(size);
}

PauliStringPtr& PauliStringPtr::operator*=(const PauliStringPtr& rhs) {
    uint8_t log_i = inplace_right_mul_with_scalar_output(rhs);
    assert((log_i & 1) == 0);
    bit_ptr_sign.toggle_if(log_i & 2);
    return *this;
}

uint8_t PauliStringPtr::inplace_right_mul_with_scalar_output(const PauliStringPtr& rhs) {
    uint8_t result = log_i_scalar_byproduct(rhs);
    result ^= (uint8_t)rhs.bit_ptr_sign.get() << 1;
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)rhs._x;
    auto oz256 = (__m256i *)rhs._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        *x256 ^= *ox256;
        x256 += stride256;
        ox256 += rhs.stride256;
    }
    end = &z256[num_words256() * stride256];
    while (z256 != end) {
        *z256 ^= *oz256;
        z256 += stride256;
        oz256 += rhs.stride256;
    }
    return result;
}

bool PauliStringPtr::get_x_bit(size_t k) const {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    return ((_x[i0] >> i1) & 1) != 0;
}

bool PauliStringPtr::get_z_bit(size_t k) const {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    return ((_z[i0] >> i1) & 1) != 0;
}

void PauliStringPtr::toggle_x_bit(size_t k) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _x[i0] ^= 1ull << i1;
}

void PauliStringPtr::toggle_z_bit(size_t k) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _z[i0] ^= 1ull << i1;
}

void PauliStringPtr::set_x_bit(size_t k, bool val) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _x[i0] &= ~(1ull << i1);
    _x[i0] ^= (uint64_t)val << i1;
}

void PauliStringPtr::set_z_bit(size_t k, bool val) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _z[i0] &= ~(1ull << i1);
    _z[i0] ^= (uint64_t)val << i1;
}

void PauliStringPtr::gather_into(PauliStringPtr &out, const std::vector<size_t> &in_indices) const {
    assert(in_indices.size() == out.size);
    for (size_t k_out = 0; k_out < out.size; k_out++) {
        size_t k_in = in_indices[k_out];
        out.set_x_bit(k_out, get_x_bit(k_in));
        out.set_z_bit(k_out, get_z_bit(k_in));
    }
}

void PauliStringPtr::scatter_into(PauliStringPtr &out, const std::vector<size_t> &out_indices) const {
    assert(size == out_indices.size());
    for (size_t k_in = 0; k_in < size; k_in++) {
        size_t k_out = out_indices[k_in];
        out.set_x_bit(k_out, get_x_bit(k_in));
        out.set_z_bit(k_out, get_z_bit(k_in));
    }
    out.bit_ptr_sign.toggle_if(bit_ptr_sign.get());
}

bool PauliStringVal::operator==(const PauliStringPtr &other) const {
    return ptr() == other;
}
bool PauliStringVal::operator!=(const PauliStringPtr &other) const {
    return ptr() != other;
}
<commit_msg>Commenting<commit_after>#include <iostream>
#include <immintrin.h>
#include <new>
#include <cassert>
#include <sstream>
#include "simd_util.h"
#include "pauli_string.h"
#include <cstring>
#include <cstdlib>
#include <bit>

PauliStringPtr::PauliStringPtr(
            size_t init_size,
            BitPtr init_sign,
            uint64_t *init_x,
            uint64_t *init_z,
            size_t init_stride256) :
        size(init_size),
        bit_ptr_sign(init_sign),
        _x(init_x),
        _z(init_z),
        stride256(init_stride256) {
}

PauliStringVal::PauliStringVal(size_t init_size) :
        val_sign(false),
        x_data(init_size),
        z_data(init_size) {
}

PauliStringVal::PauliStringVal(const PauliStringPtr &other) :
        val_sign(other.bit_ptr_sign.get()),
        x_data(other.size, other._x),
        z_data(other.size, other._z) {
}

PauliStringPtr PauliStringVal::ptr() const {
    return PauliStringPtr(*this);
}

std::string PauliStringVal::str() const {
    return ptr().str();
}

void PauliStringPtr::swap_with(PauliStringPtr &other) {
    assert(size == other.size);
    bit_ptr_sign.swap(other.bit_ptr_sign);
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        std::swap(*x256, *ox256);
        std::swap(*z256, *oz256);
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }
}

void PauliStringPtr::overwrite_with(const PauliStringPtr &other) {
    assert(size == other.size);
    bit_ptr_sign.set(other.bit_ptr_sign.get());
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        *x256 = *ox256;
        *z256 = *oz256;
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }
}

PauliStringVal& PauliStringVal::operator=(const PauliStringPtr &other) noexcept {
    (*this).~PauliStringVal();
    new(this) PauliStringVal(other);
    return *this;
}

PauliStringPtr::PauliStringPtr(const PauliStringVal &other) :
        size(other.x_data.num_bits),
        bit_ptr_sign(BitPtr((void *)&other.val_sign, 0)),
        _x(other.x_data.u64),
        _z(other.z_data.u64),
        stride256(1) {
}

uint8_t PauliStringPtr::log_i_scalar_byproduct(const PauliStringPtr &other) const {
    assert(size == other.size);
    union {__m256i u256; uint64_t u64[4]; } cnt1 {};
    union {__m256i u256; uint64_t u64[4]; } cnt2 {};
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        // Load into registers.
        auto x1 = *x256;
        auto z2 = *oz256;
        auto z1 = *z256;
        auto x2 = *ox256;

        auto t1 = x1 & z2;
        auto t2 = x2 & z1;
        // At each bit position: do the Paulis anti-commute?
        auto a = t1 ^ t2;
        // At each bit position: do the Paulis anti-commute and produce a -i instead of a +i?
        auto b = ((x1 ^ z2) & t2) ^ _mm256_andnot_si256(z1, _mm256_andnot_si256(x2, t1));
        // At each bit position: `count += forward - backward` where `backward=b`, `forward=a^b`, `count=cnt1 + 2*cnt2`.
        cnt1.u256 ^= b;
        cnt2.u256 ^= cnt1.u256 & a;
        cnt1.u256 ^= a ^ b;

        // Move along.
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }

    // Combine final anti-commutation phase tally (mod 4).
    size_t s = 0;
    for (size_t k = 0; k < 4; k++) {
        s += (uint8_t) std::popcount(cnt1.u64[k]);
        s ^= (uint8_t) std::popcount(cnt2.u64[k]) << 1;
    }
    return s & 3;
}

std::string PauliStringPtr::str() const {
    std::stringstream ss;
    ss << *this;
    return ss.str();
}

bool PauliStringPtr::operator==(const PauliStringPtr &other) const {
    if (size != other.size || bit_ptr_sign.get() != other.bit_ptr_sign.get()) {
        return false;
    }
    __m256i acc {};
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)other._x;
    auto oz256 = (__m256i *)other._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        acc |= *x256 ^ *ox256;
        acc |= *z256 ^ *oz256;
        x256 += stride256;
        z256 += stride256;
        ox256 += other.stride256;
        oz256 += other.stride256;
    }

    auto acc64 = (uint64_t *)&acc;
    for (size_t k = 0; k < 4; k++) {
        if (acc64[k]) {
            return false;
        }
    }

    return true;
}

bool PauliStringPtr::operator!=(const PauliStringPtr &other) const {
    return !(*this == other);
}

std::ostream &operator<<(std::ostream &out, const PauliStringVal &ps) {
    return out << ps.ptr();
}

size_t PauliStringPtr::num_words256() const {
    return ceil256(size) >> 8;
}

std::ostream &operator<<(std::ostream &out, const PauliStringPtr &ps) {
    out << (ps.bit_ptr_sign.get() ? '-' : '+');
    auto x256 = (__m256i *)ps._x;
    auto z256 = (__m256i *)ps._z;
    auto end = &x256[ps.num_words256() * ps.stride256];
    size_t remaining = ps.size;
    while (x256 != end) {
        auto xs = m256i_to_bits(*x256);
        auto zs = m256i_to_bits(*z256);
        for (int j = 0; j < 256 && remaining; j++) {
            out << "_XZY"[xs[j] + 2 * zs[j]];
            remaining--;
        }
        x256 += ps.stride256;
        z256 += ps.stride256;
    }
    return out;
}

PauliStringVal PauliStringVal::from_pattern(bool sign, size_t size, const std::function<char(size_t)> &func) {
    PauliStringVal result(size);
    result.val_sign = sign;
    for (size_t i = 0; i < size; i++) {
        char c = func(i);
        bool x;
        bool z;
        if (c == 'X') {
            x = true;
            z = false;
        } else if (c == 'Y') {
            x = true;
            z = true;
        } else if (c == 'Z') {
            x = false;
            z = true;
        } else if (c == '_' || c == 'I') {
            x = false;
            z = false;
        } else {
            throw std::runtime_error("Unrecognized pauli character. " + std::to_string(c));
        }
        result.x_data.u64[i / 64] ^= (uint64_t)x << (i & 63);
        result.z_data.u64[i / 64] ^= (uint64_t)z << (i & 63);
    }
    return result;
}

PauliStringVal PauliStringVal::from_str(const char *text) {
    auto sign = text[0] == '-';
    if (text[0] == '+' || text[0] == '-') {
        text++;
    }
    return PauliStringVal::from_pattern(sign, strlen(text), [&](size_t i){ return text[i]; });
}

PauliStringVal PauliStringVal::identity(size_t size) {
    return PauliStringVal(size);
}

PauliStringPtr& PauliStringPtr::operator*=(const PauliStringPtr& rhs) {
    uint8_t log_i = inplace_right_mul_with_scalar_output(rhs);
    assert((log_i & 1) == 0);
    bit_ptr_sign.toggle_if(log_i & 2);
    return *this;
}

uint8_t PauliStringPtr::inplace_right_mul_with_scalar_output(const PauliStringPtr& rhs) {
    uint8_t result = log_i_scalar_byproduct(rhs);
    result ^= (uint8_t)rhs.bit_ptr_sign.get() << 1;
    auto x256 = (__m256i *)_x;
    auto z256 = (__m256i *)_z;
    auto ox256 = (__m256i *)rhs._x;
    auto oz256 = (__m256i *)rhs._z;
    auto end = &x256[num_words256() * stride256];
    while (x256 != end) {
        *x256 ^= *ox256;
        x256 += stride256;
        ox256 += rhs.stride256;
    }
    end = &z256[num_words256() * stride256];
    while (z256 != end) {
        *z256 ^= *oz256;
        z256 += stride256;
        oz256 += rhs.stride256;
    }
    return result;
}

bool PauliStringPtr::get_x_bit(size_t k) const {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    return ((_x[i0] >> i1) & 1) != 0;
}

bool PauliStringPtr::get_z_bit(size_t k) const {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    return ((_z[i0] >> i1) & 1) != 0;
}

void PauliStringPtr::toggle_x_bit(size_t k) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _x[i0] ^= 1ull << i1;
}

void PauliStringPtr::toggle_z_bit(size_t k) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _z[i0] ^= 1ull << i1;
}

void PauliStringPtr::set_x_bit(size_t k, bool val) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _x[i0] &= ~(1ull << i1);
    _x[i0] ^= (uint64_t)val << i1;
}

void PauliStringPtr::set_z_bit(size_t k, bool val) {
    k = (k & ~0xFF)*stride256 | (k & 0xFF);
    size_t i0 = k >> 6;
    size_t i1 = k & 63;
    _z[i0] &= ~(1ull << i1);
    _z[i0] ^= (uint64_t)val << i1;
}

void PauliStringPtr::gather_into(PauliStringPtr &out, const std::vector<size_t> &in_indices) const {
    assert(in_indices.size() == out.size);
    for (size_t k_out = 0; k_out < out.size; k_out++) {
        size_t k_in = in_indices[k_out];
        out.set_x_bit(k_out, get_x_bit(k_in));
        out.set_z_bit(k_out, get_z_bit(k_in));
    }
}

void PauliStringPtr::scatter_into(PauliStringPtr &out, const std::vector<size_t> &out_indices) const {
    assert(size == out_indices.size());
    for (size_t k_in = 0; k_in < size; k_in++) {
        size_t k_out = out_indices[k_in];
        out.set_x_bit(k_out, get_x_bit(k_in));
        out.set_z_bit(k_out, get_z_bit(k_in));
    }
    out.bit_ptr_sign.toggle_if(bit_ptr_sign.get());
}

bool PauliStringVal::operator==(const PauliStringPtr &other) const {
    return ptr() == other;
}
bool PauliStringVal::operator!=(const PauliStringPtr &other) const {
    return ptr() != other;
}
<|endoftext|>


<commit_before>/*
 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
 * Copyright (C) 1999, 2000, 2001 Simon Peter, <dn.tlp@gmx.net>, et al.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * sa2.cpp - SAdT2 Loader by Simon Peter (dn.tlp@gmx.net)
 *
 * NOTES:
 * SAdT2 version 7 files are unimplemented (i don't have any).
 */

#include <stdio.h>

#include "sa2.h"

bool Csa2Loader::load(istream &f)
{
	struct {
		unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt;
	} insts[31];
	unsigned char buf;
	int i,j;
	const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15};

	// file validation section
	f.read((char *)&header,sizeof(sa2header));
	if(strncmp(header.sadt,"SAdT",4) || (header.version != 9 && header.version != 8))
		return false;

	// load section
	f.read((char *)insts,31*15);				// instruments
	f.read((char *)instname,29*17);				// instrument names
	f.ignore(3);								// dummy bytes
	f.read(order,sizeof(order));				// pattern orders
	f.read((char *)&nop,2); f.read(&length,1); f.read(&restartpos,1); f.read((char *)&bpm,2);	// infos
	f.read(arplist,sizeof(arplist));			// arpeggio list
	f.read(arpcmd,sizeof(arpcmd));				// arpeggio commands
	for(i=0;i<64*9;i++)							// track orders
		f.read((char *)&trackord[i/9][i%9],1);
	if(header.version == 9)
		f.read((char *)&activechan,2);			// active channels
	else
		activechan = 0xffff;	// v8 files have always all channels active

	// track data
	i = 0;
	while(f.peek() != EOF) {
		for(j=0;j<64;j++) {
			buf = f.get();
			tracks[i][j].note = buf >> 1;
			tracks[i][j].inst = (buf & 1) << 4;
			buf = f.get();
			tracks[i][j].inst += buf >> 4;
			tracks[i][j].command = convfx[buf & 0x0f];
			buf = f.get();
			tracks[i][j].param1 = buf >> 4;
			tracks[i][j].param2 = buf & 0x0f;
		}
		i++;
	}

	// convert instruments
	for(i=0;i<31;i++) {
		for(j=0;j<11;j++)
			inst[i].data[j] = insts[i].data[j];
		inst[i].arpstart = insts[i].arpstart;
		inst[i].arpspeed = insts[i].arpspeed;
		inst[i].arppos = insts[i].arppos;
		inst[i].arpspdcnt = insts[i].arpspdcnt;
		inst[i].misc = 0;
		inst[i].slide = 0;
	}

	// fix instrument names
	for(i=0;i<29;i++)
		for(j=0;j<17;j++)
			if(!instname[i][j])
				instname[i][j] = ' ';

	rewind(0);		// rewind module
	return true;
}

std::string Csa2Loader::gettype()
{
	char tmpstr[40];

	sprintf(tmpstr,"Surprise! Adlib Tracker 2 (version %d)",header.version);
	return std::string(tmpstr);
}

std::string Csa2Loader::gettitle()
{
	char bufinst[29*17],buf[18];
	int i,ptr;

	// parse instrument names for song name
	memset(bufinst,'\0',29*17);
	for(i=0;i<29;i++) {
		buf[16] = ' '; buf[17] = '\0';
		memcpy(buf,instname[i]+1,16);
		for(ptr=16;ptr>0;ptr--)
			if(buf[ptr] == ' ')
				buf[ptr] = '\0';
			else {
				if(ptr<16)
					buf[ptr+1] = ' ';
				break;
			}
		strcat(bufinst,buf);
	}

	if(strchr(bufinst,'"'))
		return std::string(bufinst,strchr(bufinst,'"')-bufinst+1,strrchr(bufinst,'"')-strchr(bufinst,'"')-1);
	else
		return std::string();
}
<commit_msg>.SAT support added to sa2.cpp - thanks mamiya<commit_after>/*
 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
 * Copyright (C) 1999, 2000, 2001 Simon Peter, <dn.tlp@gmx.net>, et al.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 * sa2.cpp - SAdT2 Loader by Simon Peter (dn.tlp@gmx.net)
 *           SAdT Loader by Mamiya(mamiya@users.sourceforge.net)
 *
 */

#include <stdio.h>

#include "sa2.h"

bool Csa2Loader::load(istream &f)
{
	struct {
		unsigned char data[11],arpstart,arpspeed,arppos,arpspdcnt;
	} insts;
	unsigned char buf;
	int i,j, k, notedis = 0;
	const unsigned char convfx[16] = {0,1,2,3,4,5,6,255,8,255,10,11,12,13,255,15};
	unsigned sat_type;
	enum SAT_TYPE {
		HAS_ARPEGIOLIST = (1 << 7),
		HAS_V7PATTERNS = (1 << 6),
		HAS_ACTIVECHANNELS = (1 << 5),
		HAS_TRACKORDER = (1 << 4),
		HAS_ARPEGIO = (1 << 3),
		HAS_OLDBPM = (1 << 2),
		HAS_OLDPATTERNS = (1 << 1),
		HAS_UNKNOWN127 = (1 << 0)
	};

	// file validation section
	f.read((char *)&header,sizeof(sa2header));
	if(strncmp(header.sadt,"SAdT",4))
		return false;
	switch(header.version) {
	case 1:
		notedis = +0x18;
		sat_type = HAS_UNKNOWN127 | HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 2:
		notedis = +0x18;
		sat_type = HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 3:
		notedis = +0x0c;
		sat_type = HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 4:
		notedis = +0x0c;
		sat_type = HAS_ARPEGIO | HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 5:
		notedis = +0x0c;
		sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 6:
		sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_OLDPATTERNS | HAS_OLDBPM;
		break;
	case 7:
		sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_V7PATTERNS;
		break;
	case 8:
		sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER;
		break;
	case 9:
		sat_type = HAS_ARPEGIO | HAS_ARPEGIOLIST | HAS_TRACKORDER | HAS_ACTIVECHANNELS;
		break;
	default:	/* unknown */
		return false;
	}

	// load section
	for(i = 0; i < 31; i++) {
		if(sat_type & HAS_ARPEGIO) {
			f.read((char *)&insts,15);			// instruments
			inst[i].arpstart = insts.arpstart;
			inst[i].arpspeed = insts.arpspeed;
			inst[i].arppos = insts.arppos;
			inst[i].arpspdcnt = insts.arpspdcnt;
		} else {
			f.read((char *)&insts,11);			// instruments
			inst[i].arpstart = 0;
			inst[i].arpspeed = 0;
			inst[i].arppos = 0;
			inst[i].arpspdcnt = 0;
		}
		for(j=0;j<11;j++)
			inst[i].data[j] = insts.data[j];
		inst[i].misc = 0;
		inst[i].slide = 0;
	}
	f.read((char *)instname,29*17);				// instrument names
	f.ignore(3);								// dummy bytes
	f.read(order,128);							// pattern orders
	if (sat_type & HAS_UNKNOWN127) f.ignore(127);

	// infos
	f.read((char *)&nop,2); f.read(&length,1); f.read(&restartpos,1);

	// bpm
	f.read((char *)&bpm,2);
	if(sat_type & HAS_OLDBPM) {
		bpm = bpm * 125 / 50;					// cps -> bpm
	}

	if(sat_type & HAS_ARPEGIOLIST) {
		f.read(arplist,sizeof(arplist));		// arpeggio list
		f.read(arpcmd,sizeof(arpcmd));			// arpeggio commands
	}

	for(i=0;i<64;i++) {							// track orders
		for(j=0;j<9;j++) {
			if(sat_type & HAS_TRACKORDER)
				f.read((char *)&trackord[i][j],1);
			else
			{
				trackord[i][j] = i * 9 + j;
			}
		}
	}

	if(sat_type & HAS_ACTIVECHANNELS)
		f.read((char *)&activechan,2);			// active channels
	else
		activechan = 0xffff;

	// track data
	if(sat_type & HAS_OLDPATTERNS) {
		i = 0;
		while(f.peek() != EOF) {
			for(j=0;j<64;j++) {
				for(k=0;k<9;k++) {
					buf = f.get();
					tracks[i+k][j].note = buf ? (buf + notedis) : 0;
					tracks[i+k][j].inst = f.get();
					tracks[i+k][j].command = convfx[f.get() & 0xf];
					tracks[i+k][j].param1 = f.get();
					tracks[i+k][j].param2 = f.get();
				}
			}
			i+=9;
		}
	} else if(sat_type & HAS_V7PATTERNS) {
		i = 0;
		while(f.peek() != EOF) {
			for(j=0;j<64;j++) {
				for(k=0;k<9;k++) {
					buf = f.get();
					tracks[i+k][j].note = buf >> 1;
					tracks[i+k][j].inst = (buf & 1) << 4;
					buf = f.get();
					tracks[i+k][j].inst += buf >> 4;
					tracks[i+k][j].command = convfx[buf & 0x0f];
					buf = f.get();
					tracks[i+k][j].param1 = buf >> 4;
					tracks[i+k][j].param2 = buf & 0x0f;
				}
			}
			i+=9;
		}
	} else {
		i = 0;
		while(f.peek() != EOF) {
			for(j=0;j<64;j++) {
				buf = f.get();
				tracks[i][j].note = buf >> 1;
				tracks[i][j].inst = (buf & 1) << 4;
				buf = f.get();
				tracks[i][j].inst += buf >> 4;
				tracks[i][j].command = convfx[buf & 0x0f];
				buf = f.get();
				tracks[i][j].param1 = buf >> 4;
				tracks[i][j].param2 = buf & 0x0f;
			}
			i++;
		}
	}

	// fix instrument names
	for(i=0;i<29;i++)
		for(j=0;j<17;j++)
			if(!instname[i][j])
				instname[i][j] = ' ';

	rewind(0);		// rewind module
	return true;
}

std::string Csa2Loader::gettype()
{
	char tmpstr[40];

	sprintf(tmpstr,"Surprise! Adlib Tracker 2 (version %d)",header.version);
	return std::string(tmpstr);
}

std::string Csa2Loader::gettitle()
{
	char bufinst[29*17],buf[18];
	int i,ptr;

	// parse instrument names for song name
	memset(bufinst,'\0',29*17);
	for(i=0;i<29;i++) {
		buf[16] = ' '; buf[17] = '\0';
		memcpy(buf,instname[i]+1,16);
		for(ptr=16;ptr>0;ptr--)
			if(buf[ptr] == ' ')
				buf[ptr] = '\0';
			else {
				if(ptr<16)
					buf[ptr+1] = ' ';
				break;
			}
		strcat(bufinst,buf);
	}

	if(strchr(bufinst,'"'))
		return std::string(bufinst,strchr(bufinst,'"')-bufinst+1,strrchr(bufinst,'"')-strchr(bufinst,'"')-1);
	else
		return std::string();
}
<|endoftext|>