<commit_before>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// 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 Rice University (RICE) 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 RICE 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 RICE 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.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************
//
// File:
//    DerivedProfile.C
//
// Purpose:
//    [The purpose of this file]
//
// Description:
//    [The set of functions, macros, etc. defined in the file]
//
//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>

//*************************** User Include Files ****************************

#include "DerivedProfile.h"

//*************************** Forward Declarations ***************************

using std::endl;
using std::hex;
using std::dec;

static bool
VerifyPeriod(const PCProfileMetricSet* s);
static ulong
GetPeriod(const PCProfileMetricSet* s);
String
GetNativeName(const PCProfileMetricSet* s);

//****************************************************************************
// DerivedProfile
//****************************************************************************

DerivedProfile::DerivedProfile()
  : metricVec(0)
{
}

DerivedProfile::DerivedProfile(const PCProfile* pcprof_,
			       const PCProfileFilterList* filtlist)
  : metricVec(0)
{
  Create(pcprof_, filtlist);
}

DerivedProfile::~DerivedProfile()
{
  for (DerivedProfile_MetricIterator it(*this); it.IsValid(); ++it) {
    DerivedProfileMetric* dm = it.Current();
    delete dm;
  }
  metricVec.clear();
}

void
DerivedProfile::Create(const PCProfile* pcprof_,
		       const PCProfileFilterList* filtlist)
{
  pcprof = pcprof_;

  // -------------------------------------------------------
  // 1. Create metrics.  As a special case, if filtlist is null we
  // have a one to one mapping between the raw and derived profile
  // metrics (identity filter).
  // -------------------------------------------------------
  if (filtlist == NULL) {
    SetNumMetrics(pcprof->GetNumMetrics());
    for (suint i = 0; i < pcprof->GetNumMetrics(); ++i) {
      const PCProfileMetric* m = pcprof->GetMetric(i);
      DerivedProfileMetric* dm = new DerivedProfileMetric(m);
      SetMetric(i, dm);
    }
  } else {
    // For each metric filter, create a derived metric
    SetNumMetrics(filtlist->size());
    PCProfileFilterListCIt it = filtlist->begin();
    for (suint i = 0; it != filtlist->end(); ++it, ++i) {
      PCProfileFilter* filt = *it;
      MetricFilter* mfilt = filt->GetMetricFilter();
      const PCProfileMetricSet* s = pcprof->Filter(mfilt);
      BriefAssertion(VerifyPeriod(s)); // we should all have the same period

      DerivedProfileMetric* dm = new DerivedProfileMetric(s);
      dm->SetName(filt->GetName());
      dm->SetNativeName(GetNativeName(s));
      dm->SetDescription(filt->GetDescription());
      dm->SetPeriod(GetPeriod(s));
      SetMetric(i, dm);
    }
  }

  // -------------------------------------------------------
  // 2. Determine set of interesting PCs.  As a special case, if
  // filtlist is null, we have a one to one mapping between raw PCs
  // and derived PCs.
  // -------------------------------------------------------

  if (filtlist == NULL) {
    for (DerivedProfile_MetricIterator dmIt(*this); dmIt.IsValid(); ++dmIt) {
      DerivedProfileMetric* dm = dmIt.Current();
      dm->MakeDerivedPCSetCoterminousWithPCSet();
    }
  } else {
    // FIXME: Save memory by using MakeDerivedPCSetCoterminousWithPCSet()
    // when the insn filter is the identity filter.

    // Iterate over PC values in the profile
    for (PCProfile_PCIterator it(*pcprof); it.IsValid(); ++it) {

      Addr oppc = it.Current(); // an 'operation pc'
      ushort opIndex;
      Addr pc = isa->ConvertOpPCToPC(oppc, opIndex);

      // For each derived metric and its insn filter
      PCProfileFilterListCIt fIt = filtlist->begin();
      for (suint i = 0; fIt != filtlist->end(); ++fIt, ++i) {
	PCProfileFilter* filt = *fIt;
	PCFilter* pcfilt = filt->GetPCFilter();

	DerivedProfileMetric* dm
	  = const_cast<DerivedProfileMetric*>(GetMetric(i));
	const PCProfileMetricSet* rawMSet = dm->GetMetricSet();

	// if pc has data && insn filter is satisfied for pc, record pc
	if (rawMSet->DataExists(pc, opIndex) >= 0 && (*pcfilt)(pc, opIndex)) {
	  dm->InsertPC(pc, opIndex);
	}
      }
    }
  }

}

void
DerivedProfile::Dump(std::ostream& o)
{
}

void
DerivedProfile::DDump()
{
  Dump(std::cerr);
}

//****************************************************************************
// DerivedProfileMetric
//****************************************************************************

DerivedProfileMetric::DerivedProfileMetric(const PCProfileMetricSet* s)
{
  Ctor(s);
}

DerivedProfileMetric::DerivedProfileMetric(const PCProfileMetric* m)
{
  PCProfileMetricSet* s = new PCProfileMetricSet(m->GetISA(), 1);
  s->Add(m);

  Ctor(s);
  SetName(m->GetName());
  SetNativeName(m->GetName());
  SetDescription(m->GetDescription());
  SetPeriod(m->GetPeriod());
}

void
DerivedProfileMetric::Ctor(const PCProfileMetricSet* s)
{
  SetMetricSet(s);
  pcset = new PCSet;
}

DerivedProfileMetric::~DerivedProfileMetric()
{
  mset->Clear(); // we own the set container, but not the contents!
  delete mset;
  delete pcset;
}

void
DerivedProfileMetric::Dump(std::ostream& o)
{
  o << "'DerivedProfileMetric' --\n";
  o << "  name: " << name << "\n";
  o << "  description: " << description << "\n";
  o << "  period: " << period << "\n";
}

void
DerivedProfileMetric::DDump()
{
  Dump(std::cerr);
}

//****************************************************************************

// Verify that all metrics within the set 's' have the same period.
// Otherwise, things get complicated...
static bool
VerifyPeriod(const PCProfileMetricSet* s)
{
  if (s->GetSz() == 0) { return true; }

  ulong period = (*s)[0]->GetPeriod();
  for (PCProfileMetricSetIterator it(*s); it.IsValid(); ++it) {
    PCProfileMetric* m = it.Current();
    if (period != m->GetPeriod()) {
      return false;
    }
  }
  return true;
}

static ulong
GetPeriod(const PCProfileMetricSet* s)
{
  // We assume that if s is non-empty, all the metrics periods are the same!
  if (s->GetSz() == 0) {
    return 0;
  } else {
    return (*s)[0]->GetPeriod();
  }
}

String
GetNativeName(const PCProfileMetricSet* s)
{
  String nm;
  PCProfileMetricSetIterator it(*s);
  for (suint i = 0; it.IsValid(); ++it, ++i) {
    PCProfileMetric* m = it.Current();
    if (i != 0) { nm += "+"; }
    nm += String("[") + m->GetName() + "]";
  }

  if (nm.Empty()) { nm = "<no-metrics>"; }
  return nm;
}
<commit_msg>Use sqaure brackets [] instead of pointed brackets <> to identify the empty metric set (consistent with nonempty sets).<commit_after>// $Id$
// -*-C++-*-
// * BeginRiceCopyright *****************************************************
//
// Copyright ((c)) 2002, Rice University
// 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 Rice University (RICE) 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 RICE 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 RICE 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.
//
// ******************************************************* EndRiceCopyright *

//***************************************************************************
//
// File:
//    DerivedProfile.C
//
// Purpose:
//    [The purpose of this file]
//
// Description:
//    [The set of functions, macros, etc. defined in the file]
//
//***************************************************************************

//************************* System Include Files ****************************

#include <iostream>

//*************************** User Include Files ****************************

#include "DerivedProfile.h"

//*************************** Forward Declarations ***************************

using std::endl;
using std::hex;
using std::dec;

static bool
VerifyPeriod(const PCProfileMetricSet* s);
static ulong
GetPeriod(const PCProfileMetricSet* s);
String
GetNativeName(const PCProfileMetricSet* s);

//****************************************************************************
// DerivedProfile
//****************************************************************************

DerivedProfile::DerivedProfile()
  : metricVec(0)
{
}

DerivedProfile::DerivedProfile(const PCProfile* pcprof_,
			       const PCProfileFilterList* filtlist)
  : metricVec(0)
{
  Create(pcprof_, filtlist);
}

DerivedProfile::~DerivedProfile()
{
  for (DerivedProfile_MetricIterator it(*this); it.IsValid(); ++it) {
    DerivedProfileMetric* dm = it.Current();
    delete dm;
  }
  metricVec.clear();
}

void
DerivedProfile::Create(const PCProfile* pcprof_,
		       const PCProfileFilterList* filtlist)
{
  pcprof = pcprof_;

  // -------------------------------------------------------
  // 1. Create metrics.  As a special case, if filtlist is null we
  // have a one to one mapping between the raw and derived profile
  // metrics (identity filter).
  // -------------------------------------------------------
  if (filtlist == NULL) {
    SetNumMetrics(pcprof->GetNumMetrics());
    for (suint i = 0; i < pcprof->GetNumMetrics(); ++i) {
      const PCProfileMetric* m = pcprof->GetMetric(i);
      DerivedProfileMetric* dm = new DerivedProfileMetric(m);
      SetMetric(i, dm);
    }
  } else {
    // For each metric filter, create a derived metric
    SetNumMetrics(filtlist->size());
    PCProfileFilterListCIt it = filtlist->begin();
    for (suint i = 0; it != filtlist->end(); ++it, ++i) {
      PCProfileFilter* filt = *it;
      MetricFilter* mfilt = filt->GetMetricFilter();
      const PCProfileMetricSet* s = pcprof->Filter(mfilt);
      BriefAssertion(VerifyPeriod(s)); // we should all have the same period

      DerivedProfileMetric* dm = new DerivedProfileMetric(s);
      dm->SetName(filt->GetName());
      dm->SetNativeName(GetNativeName(s));
      dm->SetDescription(filt->GetDescription());
      dm->SetPeriod(GetPeriod(s));
      SetMetric(i, dm);
    }
  }

  // -------------------------------------------------------
  // 2. Determine set of interesting PCs.  As a special case, if
  // filtlist is null, we have a one to one mapping between raw PCs
  // and derived PCs.
  // -------------------------------------------------------

  if (filtlist == NULL) {
    for (DerivedProfile_MetricIterator dmIt(*this); dmIt.IsValid(); ++dmIt) {
      DerivedProfileMetric* dm = dmIt.Current();
      dm->MakeDerivedPCSetCoterminousWithPCSet();
    }
  } else {
    // FIXME: Save memory by using MakeDerivedPCSetCoterminousWithPCSet()
    // when the insn filter is the identity filter.

    // Iterate over PC values in the profile
    for (PCProfile_PCIterator it(*pcprof); it.IsValid(); ++it) {

      Addr oppc = it.Current(); // an 'operation pc'
      ushort opIndex;
      Addr pc = isa->ConvertOpPCToPC(oppc, opIndex);

      // For each derived metric and its insn filter
      PCProfileFilterListCIt fIt = filtlist->begin();
      for (suint i = 0; fIt != filtlist->end(); ++fIt, ++i) {
	PCProfileFilter* filt = *fIt;
	PCFilter* pcfilt = filt->GetPCFilter();

	DerivedProfileMetric* dm
	  = const_cast<DerivedProfileMetric*>(GetMetric(i));
	const PCProfileMetricSet* rawMSet = dm->GetMetricSet();

	// if pc has data && insn filter is satisfied for pc, record pc
	if (rawMSet->DataExists(pc, opIndex) >= 0 && (*pcfilt)(pc, opIndex)) {
	  dm->InsertPC(pc, opIndex);
	}
      }
    }
  }

}

void
DerivedProfile::Dump(std::ostream& o)
{
}

void
DerivedProfile::DDump()
{
  Dump(std::cerr);
}

//****************************************************************************
// DerivedProfileMetric
//****************************************************************************

DerivedProfileMetric::DerivedProfileMetric(const PCProfileMetricSet* s)
{
  Ctor(s);
}

DerivedProfileMetric::DerivedProfileMetric(const PCProfileMetric* m)
{
  PCProfileMetricSet* s = new PCProfileMetricSet(m->GetISA(), 1);
  s->Add(m);

  Ctor(s);
  SetName(m->GetName());
  SetNativeName(m->GetName());
  SetDescription(m->GetDescription());
  SetPeriod(m->GetPeriod());
}

void
DerivedProfileMetric::Ctor(const PCProfileMetricSet* s)
{
  SetMetricSet(s);
  pcset = new PCSet;
}

DerivedProfileMetric::~DerivedProfileMetric()
{
  mset->Clear(); // we own the set container, but not the contents!
  delete mset;
  delete pcset;
}

void
DerivedProfileMetric::Dump(std::ostream& o)
{
  o << "'DerivedProfileMetric' --\n";
  o << "  name: " << name << "\n";
  o << "  description: " << description << "\n";
  o << "  period: " << period << "\n";
}

void
DerivedProfileMetric::DDump()
{
  Dump(std::cerr);
}

//****************************************************************************

// Verify that all metrics within the set 's' have the same period.
// Otherwise, things get complicated...
static bool
VerifyPeriod(const PCProfileMetricSet* s)
{
  if (s->GetSz() == 0) { return true; }

  ulong period = (*s)[0]->GetPeriod();
  for (PCProfileMetricSetIterator it(*s); it.IsValid(); ++it) {
    PCProfileMetric* m = it.Current();
    if (period != m->GetPeriod()) {
      return false;
    }
  }
  return true;
}

static ulong
GetPeriod(const PCProfileMetricSet* s)
{
  // We assume that if s is non-empty, all the metrics periods are the same!
  if (s->GetSz() == 0) {
    return 0;
  } else {
    return (*s)[0]->GetPeriod();
  }
}

String
GetNativeName(const PCProfileMetricSet* s)
{
  String nm;
  PCProfileMetricSetIterator it(*s);
  for (suint i = 0; it.IsValid(); ++it, ++i) {
    PCProfileMetric* m = it.Current();
    if (i != 0) { nm += "+"; }
    nm += String("[") + m->GetName() + "]";
  }

  if (nm.Empty()) { nm = "[no-matching-metrics]"; }
  return nm;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/browser.h"

#include <atlbase.h>
#include <propkey.h>
#include <windows.h>
#include <shlobj.h>
#include <shobjidl.h>

#include "base/base_paths.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "atom/common/atom_version.h"

namespace atom {

namespace {

const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";

BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
  DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
  DWORD process_id = 0;

  GetWindowThreadProcessId(hwnd, &process_id);
  if (process_id == target_process_id) {
    SetFocus(hwnd);
    return FALSE;
  }

  return TRUE;
}

}  // namespace

void Browser::Focus() {
  // On Windows we just focus on the first window found for this process.
  DWORD pid = GetCurrentProcessId();
  EnumWindows(&WindowsEnumerationHandler, reinterpret_cast<LPARAM>(&pid));
}

void Browser::AddRecentDocument(const base::FilePath& path) {
  if (base::win::GetVersion() < base::win::VERSION_WIN7)
    return;

  CComPtr<IShellItem> item;
  HRESULT hr = SHCreateItemFromParsingName(
      path.value().c_str(), NULL, IID_PPV_ARGS(&item));
  if (SUCCEEDED(hr)) {
    SHARDAPPIDINFO info;
    info.psi = item;
    info.pszAppID = GetAppUserModelID();
    SHAddToRecentDocs(SHARD_APPIDINFO, &info);
  }
}

void Browser::ClearRecentDocuments() {
  CComPtr<IApplicationDestinations> destinations;
  if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations,
                                           NULL, CLSCTX_INPROC_SERVER)))
    return;
  if (FAILED(destinations->SetAppID(GetAppUserModelID())))
    return;
  destinations->RemoveAllDestinations();
}

void Browser::SetAppUserModelID(const base::string16& name) {
  app_user_model_id_ = name;
  SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}

bool Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
  CComPtr<ICustomDestinationList> destinations;
  if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList)))
    return false;
  if (FAILED(destinations->SetAppID(GetAppUserModelID())))
    return false;

  // Start a transaction that updates the JumpList of this application.
  UINT max_slots;
  CComPtr<IObjectArray> removed;
  if (FAILED(destinations->BeginList(&max_slots, IID_PPV_ARGS(&removed))))
    return false;

  CComPtr<IObjectCollection> collection;
  if (FAILED(collection.CoCreateInstance(CLSID_EnumerableObjectCollection)))
    return false;

  for (auto& task : tasks) {
    CComPtr<IShellLink> link;
    if (FAILED(link.CoCreateInstance(CLSID_ShellLink)) ||
        FAILED(link->SetPath(task.program.value().c_str())) ||
        FAILED(link->SetArguments(task.arguments.c_str())) ||
        FAILED(link->SetDescription(task.description.c_str())))
      return false;

    if (!task.icon_path.empty() &&
        FAILED(link->SetIconLocation(task.icon_path.value().c_str(),
                                     task.icon_index)))
      return false;

    CComQIPtr<IPropertyStore> property_store = link;
    if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title,
                                                   task.title.c_str()))
      return false;

    if (FAILED(collection->AddObject(link)))
      return false;
  }

  // When the list is empty "AddUserTasks" could fail, so we don't check return
  // value for it.
  CComQIPtr<IObjectArray> task_array = collection;
  destinations->AddUserTasks(task_array);
  return SUCCEEDED(destinations->CommitList());
}

bool GetProtocolLaunchPath(std::string protocol, mate::Arguments* args, std::wstring* exe) {
  // Read in optional exe path arg
  std::wstring exePath;
  std::string rawExePath;

  base::FilePath path;

  if (!args->GetNext(&rawExePath)) {
    if (!PathService::Get(base::FILE_EXE, &path)) {
      LOG(ERROR) << "Error getting app exe path";
      return false;
    }
    // Executable Path
    exePath = path.value();
  } else {
    exePath.assign(rawExePath.begin(), rawExePath.end());
  }

  // Read in optional args arg
  std::vector<std::string> launchArgs;
  args->GetNext(&launchArgs);

  *exe = L"\"" + exePath + L"\" ";

  // Parse launch args into a string of space spearated args
  if (launchArgs.size() != 0) {
    std::string launchArgString = base::JoinString(launchArgs, " ");
    std::wstring wLaunchArgString;
    wLaunchArgString.assign(launchArgString.begin(), launchArgString.end());
    *exe = *exe + L"\"" + wLaunchArgString + L"\"";
  }
  *exe = *exe + L"\"%1\"";
  return true;
}

bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
                                            mate::Arguments* args) {
  if (protocol.empty())
    return false;

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  base::win::RegKey key;
  base::win::RegKey commandKey;
  if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't even exist, we can confirm that it is not set
    return true;

  if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't even exist, we can confirm that it is not set
    return true;

  std::wstring keyVal;
  if (FAILED(commandKey.ReadValue(L"", &keyVal)))
    // Default value not set, we can confirm that it is not set
    return true;

  std::wstring exe;
  if (!GetProtocolLaunchPath(protocol, args, &exe)) {
    return false;
  }
  if (exe == L"")
    return false;
  if (keyVal == exe) {
    // Let's kill the key
    if (FAILED(key.DeleteKey(L"shell")))
      return false;

    return true;
  } else {
    return true;
  }
}

bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
                                        mate::Arguments* args) {
  // HKEY_CLASSES_ROOT
  //    $PROTOCOL
  //       (Default) = "URL:$NAME"
  //       URL Protocol = ""
  //       shell
  //          open
  //             command
  //                (Default) = "$COMMAND" "%1"
  //
  // However, the "HKEY_CLASSES_ROOT" key can only be written by the
  // Administrator user. So, we instead write to "HKEY_CURRENT_USER\
  // Software\Classes", which is inherited by "HKEY_CLASSES_ROOT"
  // anyway, and can be written by unprivileged users.

  if (protocol.empty())
    return false;

  std::wstring exe;
  if (!GetProtocolLaunchPath(protocol, args, &exe)) {
    return false;
  }

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());
  std::string urlDeclStr = "URL:" + protocol;
  std::wstring urlDecl = std::wstring(urlDeclStr.begin(), urlDeclStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  // Write information to registry
  base::win::RegKey key(root, keyPath.c_str(), KEY_ALL_ACCESS);
  if (FAILED(key.WriteValue(L"URL Protocol", L"")) ||
      FAILED(key.WriteValue(L"", urlDecl.c_str())))
    return false;

  base::win::RegKey commandKey(root, cmdPath.c_str(), KEY_ALL_ACCESS);
  if (FAILED(commandKey.WriteValue(L"", exe.c_str())))
    return false;

  return true;
}

bool Browser::IsDefaultProtocolClient(const std::string& protocol,
                                      mate::Arguments* args) {
  if (protocol.empty())
    return false;

  std::wstring exe;
  if (!GetProtocolLaunchPath(protocol, args, &exe)) {
    return false;
  }

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  base::win::RegKey key;
  base::win::RegKey commandKey;
  if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't exist, we can confirm that it is not set
    return false;

  if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't exist, we can confirm that it is not set
    return false;

  std::wstring keyVal;
  if (FAILED(commandKey.ReadValue(L"", &keyVal)))
    // Default value not set, we can confirm that it is not set
    return false;

  if (keyVal == exe) {
    // Default value is the same as current file path
    return true;
  } else {
    return false;
  }
}

bool Browser::SetBadgeCount(int count) {
  return false;
}

void Browser::SetLoginItemSettings(LoginItemSettings settings) {
  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);

  if (settings.open_at_login) {
    base::FilePath path;
    if (PathService::Get(base::FILE_EXE, &path)) {
      std::wstring exePath(path.value());
      key.WriteValue(GetAppUserModelID(), exePath.c_str());
    }
  } else {
    key.DeleteValue(GetAppUserModelID());
  }
}

Browser::LoginItemSettings Browser::GetLoginItemSettings() {
  LoginItemSettings settings;
  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
  std::wstring keyVal;

  if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) {
    base::FilePath path;
    if (PathService::Get(base::FILE_EXE, &path)) {
      std::wstring exePath(path.value());
      settings.open_at_login = keyVal == exePath;
    }
  }

  return settings;
}

PCWSTR Browser::GetAppUserModelID() {
  if (app_user_model_id_.empty()) {
    SetAppUserModelID(base::ReplaceStringPlaceholders(
        kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr));
  }

  return app_user_model_id_.c_str();
}

std::string Browser::GetExecutableFileVersion() const {
  base::FilePath path;
  if (PathService::Get(base::FILE_EXE, &path)) {
    std::unique_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(path));
    return base::UTF16ToUTF8(version_info->product_version());
  }

  return ATOM_VERSION_STRING;
}

std::string Browser::GetExecutableFileProductName() const {
  base::FilePath path;
  if (PathService::Get(base::FILE_EXE, &path)) {
    std::unique_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(path));
    return base::UTF16ToUTF8(version_info->product_name());
  }

  return ATOM_PRODUCT_NAME;
}

}  // namespace atom
<commit_msg>Use base::string16 and base::JoinString instead of custom methods<commit_after>// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "atom/browser/browser.h"

#include <atlbase.h>
#include <propkey.h>
#include <windows.h>
#include <shlobj.h>
#include <shobjidl.h>

#include "base/base_paths.h"
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/win/win_util.h"
#include "base/win/registry.h"
#include "base/win/windows_version.h"
#include "atom/common/atom_version.h"
#include "atom/common/native_mate_converters/string16_converter.h"

namespace atom {

namespace {

const wchar_t kAppUserModelIDFormat[] = L"electron.app.$1";

BOOL CALLBACK WindowsEnumerationHandler(HWND hwnd, LPARAM param) {
  DWORD target_process_id = *reinterpret_cast<DWORD*>(param);
  DWORD process_id = 0;

  GetWindowThreadProcessId(hwnd, &process_id);
  if (process_id == target_process_id) {
    SetFocus(hwnd);
    return FALSE;
  }

  return TRUE;
}

}  // namespace

void Browser::Focus() {
  // On Windows we just focus on the first window found for this process.
  DWORD pid = GetCurrentProcessId();
  EnumWindows(&WindowsEnumerationHandler, reinterpret_cast<LPARAM>(&pid));
}

void Browser::AddRecentDocument(const base::FilePath& path) {
  if (base::win::GetVersion() < base::win::VERSION_WIN7)
    return;

  CComPtr<IShellItem> item;
  HRESULT hr = SHCreateItemFromParsingName(
      path.value().c_str(), NULL, IID_PPV_ARGS(&item));
  if (SUCCEEDED(hr)) {
    SHARDAPPIDINFO info;
    info.psi = item;
    info.pszAppID = GetAppUserModelID();
    SHAddToRecentDocs(SHARD_APPIDINFO, &info);
  }
}

void Browser::ClearRecentDocuments() {
  CComPtr<IApplicationDestinations> destinations;
  if (FAILED(destinations.CoCreateInstance(CLSID_ApplicationDestinations,
                                           NULL, CLSCTX_INPROC_SERVER)))
    return;
  if (FAILED(destinations->SetAppID(GetAppUserModelID())))
    return;
  destinations->RemoveAllDestinations();
}

void Browser::SetAppUserModelID(const base::string16& name) {
  app_user_model_id_ = name;
  SetCurrentProcessExplicitAppUserModelID(app_user_model_id_.c_str());
}

bool Browser::SetUserTasks(const std::vector<UserTask>& tasks) {
  CComPtr<ICustomDestinationList> destinations;
  if (FAILED(destinations.CoCreateInstance(CLSID_DestinationList)))
    return false;
  if (FAILED(destinations->SetAppID(GetAppUserModelID())))
    return false;

  // Start a transaction that updates the JumpList of this application.
  UINT max_slots;
  CComPtr<IObjectArray> removed;
  if (FAILED(destinations->BeginList(&max_slots, IID_PPV_ARGS(&removed))))
    return false;

  CComPtr<IObjectCollection> collection;
  if (FAILED(collection.CoCreateInstance(CLSID_EnumerableObjectCollection)))
    return false;

  for (auto& task : tasks) {
    CComPtr<IShellLink> link;
    if (FAILED(link.CoCreateInstance(CLSID_ShellLink)) ||
        FAILED(link->SetPath(task.program.value().c_str())) ||
        FAILED(link->SetArguments(task.arguments.c_str())) ||
        FAILED(link->SetDescription(task.description.c_str())))
      return false;

    if (!task.icon_path.empty() &&
        FAILED(link->SetIconLocation(task.icon_path.value().c_str(),
                                     task.icon_index)))
      return false;

    CComQIPtr<IPropertyStore> property_store = link;
    if (!base::win::SetStringValueForPropertyStore(property_store, PKEY_Title,
                                                   task.title.c_str()))
      return false;

    if (FAILED(collection->AddObject(link)))
      return false;
  }

  // When the list is empty "AddUserTasks" could fail, so we don't check return
  // value for it.
  CComQIPtr<IObjectArray> task_array = collection;
  destinations->AddUserTasks(task_array);
  return SUCCEEDED(destinations->CommitList());
}

bool GetProtocolLaunchPath(mate::Arguments* args, base::string16* exe) {
  // Read in optional exe path arg
  base::string16 exePath;

  base::FilePath path;

  if (!args->GetNext(&exePath)) {
    if (!PathService::Get(base::FILE_EXE, &path)) {
      LOG(ERROR) << "Error getting app exe path";
      return false;
    }
    // Executable Path
    exePath = path.value();
  }

  // Read in optional args arg
  std::vector<base::string16> launchArgs;
  args->GetNext(&launchArgs);

  // Parse launch args into a string of space spearated args
  base::string16 launchArgString;
  if (launchArgs.size() != 0) {
    launchArgString = base::JoinString(launchArgs, L" ");
  }
  *exe = base::StringPrintf(L"\"%s\" %s \"%%1\"", exePath.c_str(), launchArgString.c_str());
  return true;
}

bool Browser::RemoveAsDefaultProtocolClient(const std::string& protocol,
                                            mate::Arguments* args) {
  if (protocol.empty())
    return false;

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  base::win::RegKey key;
  base::win::RegKey commandKey;
  if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't even exist, we can confirm that it is not set
    return true;

  if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't even exist, we can confirm that it is not set
    return true;

  std::wstring keyVal;
  if (FAILED(commandKey.ReadValue(L"", &keyVal)))
    // Default value not set, we can confirm that it is not set
    return true;

  std::wstring exe;
  if (!GetProtocolLaunchPath(args, &exe)) {
    return false;
  }
  if (exe == L"")
    return false;
  if (keyVal == exe) {
    // Let's kill the key
    if (FAILED(key.DeleteKey(L"shell")))
      return false;

    return true;
  } else {
    return true;
  }
}

bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
                                        mate::Arguments* args) {
  // HKEY_CLASSES_ROOT
  //    $PROTOCOL
  //       (Default) = "URL:$NAME"
  //       URL Protocol = ""
  //       shell
  //          open
  //             command
  //                (Default) = "$COMMAND" "%1"
  //
  // However, the "HKEY_CLASSES_ROOT" key can only be written by the
  // Administrator user. So, we instead write to "HKEY_CURRENT_USER\
  // Software\Classes", which is inherited by "HKEY_CLASSES_ROOT"
  // anyway, and can be written by unprivileged users.

  if (protocol.empty())
    return false;

  std::wstring exe;
  if (!GetProtocolLaunchPath(args, &exe)) {
    return false;
  }

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());
  std::string urlDeclStr = "URL:" + protocol;
  std::wstring urlDecl = std::wstring(urlDeclStr.begin(), urlDeclStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  // Write information to registry
  base::win::RegKey key(root, keyPath.c_str(), KEY_ALL_ACCESS);
  if (FAILED(key.WriteValue(L"URL Protocol", L"")) ||
      FAILED(key.WriteValue(L"", urlDecl.c_str())))
    return false;

  base::win::RegKey commandKey(root, cmdPath.c_str(), KEY_ALL_ACCESS);
  if (FAILED(commandKey.WriteValue(L"", exe.c_str())))
    return false;

  return true;
}

bool Browser::IsDefaultProtocolClient(const std::string& protocol,
                                      mate::Arguments* args) {
  if (protocol.empty())
    return false;

  std::wstring exe;
  if (!GetProtocolLaunchPath(args, &exe)) {
    return false;
  }

  // Main Registry Key
  HKEY root = HKEY_CURRENT_USER;
  std::string keyPathStr = "Software\\Classes\\" + protocol;
  std::wstring keyPath = std::wstring(keyPathStr.begin(), keyPathStr.end());

  // Command Key
  std::string cmdPathStr = keyPathStr + "\\shell\\open\\command";
  std::wstring cmdPath = std::wstring(cmdPathStr.begin(), cmdPathStr.end());

  base::win::RegKey key;
  base::win::RegKey commandKey;
  if (FAILED(key.Open(root, keyPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't exist, we can confirm that it is not set
    return false;

  if (FAILED(commandKey.Open(root, cmdPath.c_str(), KEY_ALL_ACCESS)))
    // Key doesn't exist, we can confirm that it is not set
    return false;

  std::wstring keyVal;
  if (FAILED(commandKey.ReadValue(L"", &keyVal)))
    // Default value not set, we can confirm that it is not set
    return false;

  if (keyVal == exe) {
    // Default value is the same as current file path
    return true;
  } else {
    return false;
  }
}

bool Browser::SetBadgeCount(int count) {
  return false;
}

void Browser::SetLoginItemSettings(LoginItemSettings settings) {
  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);

  if (settings.open_at_login) {
    base::FilePath path;
    if (PathService::Get(base::FILE_EXE, &path)) {
      std::wstring exePath(path.value());
      key.WriteValue(GetAppUserModelID(), exePath.c_str());
    }
  } else {
    key.DeleteValue(GetAppUserModelID());
  }
}

Browser::LoginItemSettings Browser::GetLoginItemSettings() {
  LoginItemSettings settings;
  std::wstring keyPath = L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
  base::win::RegKey key(HKEY_CURRENT_USER, keyPath.c_str(), KEY_ALL_ACCESS);
  std::wstring keyVal;

  if (!FAILED(key.ReadValue(GetAppUserModelID(), &keyVal))) {
    base::FilePath path;
    if (PathService::Get(base::FILE_EXE, &path)) {
      std::wstring exePath(path.value());
      settings.open_at_login = keyVal == exePath;
    }
  }

  return settings;
}

PCWSTR Browser::GetAppUserModelID() {
  if (app_user_model_id_.empty()) {
    SetAppUserModelID(base::ReplaceStringPlaceholders(
        kAppUserModelIDFormat, base::UTF8ToUTF16(GetName()), nullptr));
  }

  return app_user_model_id_.c_str();
}

std::string Browser::GetExecutableFileVersion() const {
  base::FilePath path;
  if (PathService::Get(base::FILE_EXE, &path)) {
    std::unique_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(path));
    return base::UTF16ToUTF8(version_info->product_version());
  }

  return ATOM_VERSION_STRING;
}

std::string Browser::GetExecutableFileProductName() const {
  base::FilePath path;
  if (PathService::Get(base::FILE_EXE, &path)) {
    std::unique_ptr<FileVersionInfo> version_info(
        FileVersionInfo::CreateFileVersionInfo(path));
    return base::UTF16ToUTF8(version_info->product_name());
  }

  return ATOM_PRODUCT_NAME;
}

}  // namespace atom
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Crossbar.io Technologies GmbH and contributors
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef AUTOBAHN_WAMP_ARGUMENTS_HPP
#define AUTOBAHN_WAMP_ARGUMENTS_HPP

#include <array>
#include <msgpack.hpp>
#include <string>
#include <unordered_map>
#include <vector>

namespace autobahn {

using wamp_arguments = std::vector<msgpack::object>;
using wamp_kw_arguments = std::unordered_map<std::string, msgpack::object>;

static const msgpack::object EMPTY_ARGUMENTS(std::array<msgpack::object, 0>(), nullptr);
static const msgpack::object EMPTY_KW_ARGUMENTS(wamp_kw_arguments(), nullptr);

//msgpack map utilities.
//TODO: refactor event & invocation to used these
template <typename T>
inline T value_for_key(const msgpack::object& object, const std::string& key)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " keyword argument doesn't exist");
}

template <typename T>
inline T value_for_key(const msgpack::object& object, const char* key)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " keyword argument doesn't exist");
}

template <typename T>
inline T value_for_key_or(const msgpack::object& object, const std::string& key, const T& fallback)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}

template <typename T>
inline T value_for_key_or(const msgpack::object& object, const char* key, const T& fallback)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}
} // namespace autobahn

#endif // AUTOBAHN_WAMP_ARGUMENTS_HPP
<commit_msg>Fix undefined behaviour reported by gcc-7.3 sanitize=undefined<commit_after>///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) Crossbar.io Technologies GmbH and contributors
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////

#ifndef AUTOBAHN_WAMP_ARGUMENTS_HPP
#define AUTOBAHN_WAMP_ARGUMENTS_HPP

#include <array>
#include <msgpack.hpp>
#include <string>
#include <unordered_map>
#include <vector>

namespace autobahn {

using wamp_arguments = std::vector<msgpack::object>;
using wamp_kw_arguments = std::unordered_map<std::string, msgpack::object>;

static msgpack::zone EMPTY_ARGUMENTS_ZONE;
static msgpack::zone EMPTY_KW_ARGUMENTS_ZONE;
static const msgpack::object EMPTY_ARGUMENTS(std::array<msgpack::object, 0>(), &EMPTY_ARGUMENTS_ZONE);
static const msgpack::object EMPTY_KW_ARGUMENTS(wamp_kw_arguments(), &EMPTY_KW_ARGUMENTS_ZONE);

//msgpack map utilities.
//TODO: refactor event & invocation to used these
template <typename T>
inline T value_for_key(const msgpack::object& object, const std::string& key)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(key + " keyword argument doesn't exist");
}

template <typename T>
inline T value_for_key(const msgpack::object& object, const char* key)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    throw std::out_of_range(std::string(key) + " keyword argument doesn't exist");
}

template <typename T>
inline T value_for_key_or(const msgpack::object& object, const std::string& key, const T& fallback)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key.size() == kv.key.via.str.size
            && key.compare(0, key.size(), kv.key.via.str.ptr, kv.key.via.str.size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}

template <typename T>
inline T value_for_key_or(const msgpack::object& object, const char* key, const T& fallback)
{
    if (object.type != msgpack::type::MAP) {
        throw msgpack::type_error();
    }
    std::size_t key_size = strlen(key);
    for (std::size_t i = 0; i < object.via.map.size; ++i) {
        const msgpack::object_kv& kv = object.via.map.ptr[i];
        if (kv.key.type == msgpack::type::STR && key_size == kv.key.via.str.size
            && memcmp(key, kv.key.via.str.ptr, key_size) == 0)
        {
            return kv.val.as<T>();
        }
    }
    return fallback;
}
} // namespace autobahn

#endif // AUTOBAHN_WAMP_ARGUMENTS_HPP
<|endoftext|>


<commit_before>#include <v8.h>
#include <vector>
#using <System.dll>

using namespace v8;
using namespace System::Net::Sockets;
using namespace System::Net;
using namespace System::Threading;
using namespace System::IO;

ref class NetStream {
private:
	Stream^ stream;
	static const int bufferSize = 1024;
	std::vector<Handle<Function>>* dataCallbacks;
	std::vector<Handle<Function>>* endCallbacks;

	Handle<v8::Object>* callbackReceiver;

public:
	NetStream( Stream^ in_stream, Handle<v8::Object>* in_receiver ) {
		dataCallbacks = new std::vector<Handle<Function>>();
		endCallbacks = new std::vector<Handle<Function>>();
		stream = in_stream;

		// TODO: we are temporarily passing receiver object here
		callbackReceiver = in_receiver;

	}
	void read() {
		array<unsigned char>^ buffer = gcnew array<unsigned char>( bufferSize );
		System::AsyncCallback^ ReadCallbackDelegate = gcnew System::AsyncCallback( this, &NetStream::ReadCallback );
		this->stream->BeginRead( buffer, 0, bufferSize, ReadCallbackDelegate, buffer );
	}

	void ReadCallback( System::IAsyncResult^ result ) {
		array<unsigned char>^ buffer = ( array<unsigned char>^ )result->AsyncState;
		int bytesRead = this->stream->EndRead( result );
		printf( "ReadCallback(): read %i bytes from stream\n", bytesRead );
		System::String^ chunk = System::Text::Encoding::UTF8->GetString( buffer, 0, bytesRead );

		if( bytesRead > 0 ) {

			System::Console::WriteLine( chunk );

			// queueWorkItem( { callback: raiseDataEvent, args: [ chunk ] } );
			array<unsigned char>^ nextBuffer = gcnew array<unsigned char>( bufferSize );
			System::AsyncCallback^ ReadCallbackDelegate = gcnew System::AsyncCallback( this, &NetStream::ReadCallback );
			this->stream->BeginRead( nextBuffer, 0, bufferSize, ReadCallbackDelegate, nextBuffer );
		}
		else {
			// queueWorkItem( { callback: raiseEndEvent, args: [] } );
		}

	}

	void write( System::String^ chunk /*, TODO: encoding */ ) {
		array<unsigned char>^ buffer = System::Text::Encoding::UTF8->GetBytes( chunk );
		this->stream->Write( buffer, 0, buffer->Length );
	}

	void addListener( System::String^ eventname, Handle<Function> callback ) {
		if( eventname == "data" ) {
			dataCallbacks->push_back( callback );
		}
		else if( eventname == "end" ) {
			endCallbacks->push_back( callback );
		}
	}

	void raiseDataEvent( System::String^ chunk ) {
		printf( "net.stream.raiseDataEvent()\n" );
		for( int i=0; i < dataCallbacks->size(); i++ ) {
			Handle<Function> fn = dataCallbacks->at(i);
			// fn->Call( chunk );
		}
	}

	void raiseEndEvent() {
		printf( "net.stream.raiseEndEvent()\n" );
		for( int i=0; i < endCallbacks->size(); i++ ) {
			Handle<Function> fn = endCallbacks->at(i);
			// fn->Call();
		}
	}

};

ref class NetServer {
private:
	TcpListener^ tcpListener;
	std::vector<Handle<Function>>* listeningCallbacks;
	std::vector<Handle<Function>>* connectionCallbacks;
	std::vector<Handle<Function>>* closeCallbacks;

	Handle<v8::Object>* callbackReceiver;

public:
	// constructor takes a v8 handle for callback
	NetServer( Handle<Function> in_callback, Handle<v8::Object>* in_receiver ) {
		listeningCallbacks = new std::vector<Handle<Function>>();
		connectionCallbacks = new std::vector<Handle<Function>>();
		closeCallbacks = new std::vector<Handle<Function>>();

		// TODO: we are temporarily passing receiver object here
		callbackReceiver = in_receiver;

		AddListener( "listening", in_callback );
	}

	NetServer() {
		listeningCallbacks = new std::vector<Handle<Function>>();
		connectionCallbacks = new std::vector<Handle<Function>>();
		closeCallbacks = new std::vector<Handle<Function>>();
	}

	void Listen( System::Int32 port, System::String^ host ) {

		IPHostEntry^ hostInfo = Dns::Resolve( host );
		IPAddress^ ipAddress = hostInfo->AddressList[0];

		this->tcpListener = gcnew TcpListener( ipAddress, port );
		// print( 'net.Server.listen(): starting tcp server' );
		this->tcpListener->Start();

		// queueWorkItem( { callback: raiseListeningEvent, args: [] } );
		RaiseListeningEvent();

		System::AsyncCallback^ ListenerCallbackDelegate = gcnew System::AsyncCallback( this, &NetServer::ListenerCallback );
		this->tcpListener->BeginAcceptTcpClient( ListenerCallbackDelegate, NULL );
	}

	void ListenerCallback( System::IAsyncResult^ result ) {
		printf("%s\n", "listener called" );
		System::AsyncCallback^ ListenerCallbackDelegate = gcnew System::AsyncCallback( this, &NetServer::ListenerCallback );
		this->tcpListener->BeginAcceptTcpClient( ListenerCallbackDelegate, NULL );

		TcpClient^ client = this->tcpListener->EndAcceptTcpClient( result );
		NetStream^ stream = gcnew NetStream( client->GetStream(), callbackReceiver );

		//queueWorkItem( { callback: raiseConnectionEvent, args: [ stream ] } );

		// TODO: we need wrapper object around NetStream to pass here
		RaiseConnectionEvent( v8::Undefined() );

		// kick off async read
		stream->read();
	}

	void RaiseListeningEvent() {
		printf( "%s\n", "http.server.raiseListeningEvent()" );
		printf( "http.server.raiseListeningEvent(): calling %i callbacks\n", (int)this->listeningCallbacks->size() );
		for( int i=0; i < listeningCallbacks->size(); i++ ) {
			Handle<Function> fn = listeningCallbacks->at(i);
			fn->Call( *callbackReceiver, NULL, NULL );
		}
	}
	void RaiseConnectionEvent( Handle<Value> stream ) {
		printf( "%s\n", "http.server.RaiseConnectionEvent()" );
		for( int i=0; i < connectionCallbacks->size(); i++ ) {
			Handle<Function> fn = connectionCallbacks->at(i);
			Handle<Value> args[] = { stream };
			fn->Call( *callbackReceiver, 1, args );
		}
	}

	void AddListener( System::String^ eventname, Handle<Function> callback ) {
		if( eventname == "listening" ) {
			listeningCallbacks->push_back( callback );
		}
		else if( eventname == "connection" ) {
			connectionCallbacks->push_back( callback );
		}
		else if( eventname == "close" ) {
			closeCallbacks->push_back( callback );
		}
		else {
			throw "addListener called for unsupported event";
		}
	}
};

// This callback is the native code associated with a v8 function.
// Eventually all of the v8 functions that we call will come from compiled
// scripts
v8::Handle<v8::Value> listeningCallback( const v8::Arguments& args ) {
	HandleScope handle_scope;
	printf( "called v8 listening callback\n" );
	return v8::Undefined();
}

int main(int argc, char* argv[]) {
	printf("%s\n", "entered main()" );
	HandleScope handle_scope;

	// create global and context
	v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
	v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
	v8::Context::Scope context_scope(context);

	// note: GetFunction() fails if there is no context
	Local<FunctionTemplate> cbTemplate = FunctionTemplate::New( listeningCallback );
	Local<Function> cbFunction = cbTemplate->GetFunction();

	NetServer^ netServer = gcnew NetServer( cbFunction, &context->Global() );
	netServer->Listen( 9980, "localhost" );

	Thread::Sleep( Timeout::Infinite );
}<commit_msg>making progress on tcpserver - still unsolved is storing native pointer for referencing managed object later<commit_after>#include <v8.h>
#include <vector>
// needed for gcroot
#include <vcclr.h>
#using <System.dll>

using namespace v8;
using namespace System::Net::Sockets;
using namespace System::Net;
using namespace System::Threading;
using namespace System::IO;

ref class NetStream {
private:
	Stream^ stream;
	static const int bufferSize = 1024;
	std::vector<Handle<Function>>* dataCallbacks;
	std::vector<Handle<Function>>* endCallbacks;

	Handle<v8::Object>* callbackReceiver;

public:
	NetStream( Stream^ in_stream, Handle<v8::Object>* in_receiver ) {
		dataCallbacks = new std::vector<Handle<Function>>();
		endCallbacks = new std::vector<Handle<Function>>();
		stream = in_stream;

		// TODO: we are temporarily passing receiver object here
		callbackReceiver = in_receiver;

	}
	void read() {
		array<unsigned char>^ buffer = gcnew array<unsigned char>( bufferSize );
		System::AsyncCallback^ ReadCallbackDelegate = gcnew System::AsyncCallback( this, &NetStream::ReadCallback );
		this->stream->BeginRead( buffer, 0, bufferSize, ReadCallbackDelegate, buffer );
	}

	void ReadCallback( System::IAsyncResult^ result ) {
		array<unsigned char>^ buffer = ( array<unsigned char>^ )result->AsyncState;
		int bytesRead = this->stream->EndRead( result );
		printf( "ReadCallback(): read %i bytes from stream\n", bytesRead );
		System::String^ chunk = System::Text::Encoding::UTF8->GetString( buffer, 0, bytesRead );

		if( bytesRead > 0 ) {

			System::Console::WriteLine( chunk );

			// queueWorkItem( { callback: raiseDataEvent, args: [ chunk ] } );
			array<unsigned char>^ nextBuffer = gcnew array<unsigned char>( bufferSize );
			System::AsyncCallback^ ReadCallbackDelegate = gcnew System::AsyncCallback( this, &NetStream::ReadCallback );
			this->stream->BeginRead( nextBuffer, 0, bufferSize, ReadCallbackDelegate, nextBuffer );
		}
		else {
			// queueWorkItem( { callback: raiseEndEvent, args: [] } );
		}

	}

	void write( System::String^ chunk /*, TODO: encoding */ ) {
		array<unsigned char>^ buffer = System::Text::Encoding::UTF8->GetBytes( chunk );
		this->stream->Write( buffer, 0, buffer->Length );
	}

	void addListener( System::String^ eventname, Handle<Function> callback ) {
		if( eventname == "data" ) {
			dataCallbacks->push_back( callback );
		}
		else if( eventname == "end" ) {
			endCallbacks->push_back( callback );
		}
	}

	void raiseDataEvent( System::String^ chunk ) {
		printf( "net.stream.raiseDataEvent()\n" );
		for( int i=0; i < dataCallbacks->size(); i++ ) {
			Handle<Function> fn = dataCallbacks->at(i);
			// fn->Call( chunk );
		}
	}

	void raiseEndEvent() {
		printf( "net.stream.raiseEndEvent()\n" );
		for( int i=0; i < endCallbacks->size(); i++ ) {
			Handle<Function> fn = endCallbacks->at(i);
			// fn->Call();
		}
	}

};

ref class NetServer {
private:
	TcpListener^ tcpListener;
	std::vector<Handle<Function>>* listeningCallbacks;
	std::vector<Handle<Function>>* connectionCallbacks;
	std::vector<Handle<Function>>* closeCallbacks;

	Handle<v8::Object>* callbackReceiver;

public:
	// constructor takes a v8 handle for callback
	NetServer( Handle<Function> in_callback, Handle<v8::Object>* in_receiver ) {
		listeningCallbacks = new std::vector<Handle<Function>>();
		connectionCallbacks = new std::vector<Handle<Function>>();
		closeCallbacks = new std::vector<Handle<Function>>();

		// TODO: we are temporarily passing receiver object here
		callbackReceiver = in_receiver;

		AddListener( "listening", in_callback );
	}

	NetServer() {
		listeningCallbacks = new std::vector<Handle<Function>>();
		connectionCallbacks = new std::vector<Handle<Function>>();
		closeCallbacks = new std::vector<Handle<Function>>();
	}

	void Listen( System::Int32 port, System::String^ host ) {

		IPHostEntry^ hostInfo = Dns::Resolve( host );
		IPAddress^ ipAddress = hostInfo->AddressList[0];

		this->tcpListener = gcnew TcpListener( ipAddress, port );
		// print( 'net.Server.listen(): starting tcp server' );
		this->tcpListener->Start();

		// queueWorkItem( { callback: raiseListeningEvent, args: [] } );
		RaiseListeningEvent();

		System::AsyncCallback^ ListenerCallbackDelegate = gcnew System::AsyncCallback( this, &NetServer::ListenerCallback );
		this->tcpListener->BeginAcceptTcpClient( ListenerCallbackDelegate, NULL );
	}

	void ListenerCallback( System::IAsyncResult^ result ) {
		printf("%s\n", "listener called" );
		System::AsyncCallback^ ListenerCallbackDelegate = gcnew System::AsyncCallback( this, &NetServer::ListenerCallback );
		this->tcpListener->BeginAcceptTcpClient( ListenerCallbackDelegate, NULL );

		TcpClient^ client = this->tcpListener->EndAcceptTcpClient( result );
		NetStream^ stream = gcnew NetStream( client->GetStream(), callbackReceiver );

		//queueWorkItem( { callback: raiseConnectionEvent, args: [ stream ] } );

		// TODO: we need wrapper object around NetStream to pass here
		RaiseConnectionEvent( v8::Undefined() );

		// kick off async read
		stream->read();
	}

	void RaiseListeningEvent() {
		printf( "%s\n", "http.server.raiseListeningEvent()" );
		printf( "http.server.raiseListeningEvent(): calling %i callbacks\n", (int)this->listeningCallbacks->size() );
		for( int i=0; i < listeningCallbacks->size(); i++ ) {
			Handle<Function> fn = listeningCallbacks->at(i);
			fn->Call( *callbackReceiver, NULL, NULL );
		}
	}
	void RaiseConnectionEvent( Handle<Value> stream ) {
		printf( "%s\n", "http.server.RaiseConnectionEvent()" );
		for( int i=0; i < connectionCallbacks->size(); i++ ) {
			Handle<Function> fn = connectionCallbacks->at(i);
			Handle<Value> args[] = { stream };
			fn->Call( *callbackReceiver, 1, args );
		}
	}

	void AddListener( System::String^ eventname, Handle<Function> callback ) {
		if( eventname == "listening" ) {
			listeningCallbacks->push_back( callback );
		}
		else if( eventname == "connection" ) {
			connectionCallbacks->push_back( callback );
		}
		else if( eventname == "close" ) {
			closeCallbacks->push_back( callback );
		}
		else {
			throw "addListener called for unsupported event";
		}
	}
};

// This callback is the native code associated with a v8 function.
// Eventually all of the v8 functions that we call will come from compiled
// scripts
v8::Handle<v8::Value> listenCallback( const v8::Arguments& args ) {
	HandleScope handle_scope;
	printf( "called v8 listen callback\n" );

	Local<Object> self = args.This();
	Local<Value> p = self->GetInternalField(0);
	Local<External> wrap = Local<External>::Cast( p );
    void* ptr = wrap->Value();
    // NetServer value = static_cast<NetServer*>(ptr);

	return v8::Undefined();
}

v8::Handle<v8::Value> addListenerCallback( const v8::Arguments& args ) {
	HandleScope handle_scope;
	printf( "called v8 addListenerCallback\n" );
	return v8::Undefined();
}

v8::Handle<v8::Value> createServerCallback( const v8::Arguments& args ) {
	HandleScope handle_scope;
	printf( "called v8 createServer callback\n" );

	Handle<Function> fn = Handle<Function>::Cast( args[0] );
	NetServer^ netServer = gcnew NetServer( fn, &args.This() );
	// TODO: create js wrapper around netServer and return it
	Handle<ObjectTemplate> serverObjTempl = ObjectTemplate::New();
	serverObjTempl->SetInternalFieldCount(1);
	serverObjTempl->Set( String::New( "listen" ), FunctionTemplate::New( listenCallback ) );

	Local<Object> obj = serverObjTempl->NewInstance();
	// pin_ptr<NetServer^> p = &netServer;
	gcroot<NetServer^>* p = netServer;
	obj->SetInternalField( 0, External::New( p ) );

	return obj;
	// return v8::Undefined();
}

int main(int argc, char* argv[]) {
	printf("%s\n", "entered main()" );
	HandleScope handle_scope;

	// create global and context
	v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
	Local<FunctionTemplate> createServerCallbackTemplate = FunctionTemplate::New( createServerCallback );
	global->Set( String::New( "createServer" ), createServerCallbackTemplate );
	v8::Handle<v8::Context> context = v8::Context::New(NULL, global);
	v8::Context::Scope context_scope(context);

	// note: GetFunction() fails if there is no context
	Local<FunctionTemplate> cbTemplate = FunctionTemplate::New( listenCallback );
	Local<Function> cbFunction = cbTemplate->GetFunction();

	Handle<Script> script = Script::Compile( String::New( "createServer( function( stream ){ }, this ).listen( 9980, 'localhost' );") );
	Handle<Value> scriptresult = script->Run();

	// NetServer^ netServer = gcnew NetServer( cbFunction, &context->Global() );
	// netServer->Listen( 9980, "localhost" );

	Thread::Sleep( Timeout::Infinite );
}<|endoftext|>


<commit_before>#include "boost_defs.hpp"

#include "dispatcher_utility.hpp"
#include "hid_observer.hpp"
#include "iokit_utility.hpp"
#include <boost/optional/optional_io.hpp>
#include <pqrs/osx/iokit_hid_manager.hpp>

namespace {
class dump_hid_value final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  dump_hid_value(const dump_hid_value&) = delete;

  dump_hid_value(void) : dispatcher_client() {
    std::vector<pqrs::cf_ptr<CFDictionaryRef>> matching_dictionaries;

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_keyboard));

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_mouse));

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_pointer));

    hid_manager_ = std::make_unique<pqrs::osx::iokit_hid_manager>(weak_dispatcher_,
                                                                  matching_dictionaries);

    hid_manager_->device_detected.connect([this](auto&& registry_entry_id, auto&& device_ptr) {
      auto hid = std::make_shared<krbn::human_interface_device>(*device_ptr,
                                                                registry_entry_id);
      auto weak_hid = std::weak_ptr<krbn::human_interface_device>(hid);

      hids_[registry_entry_id] = hid;

      hid->values_arrived.connect([this, weak_hid](auto&& shared_event_queue) {
        if (auto hid = weak_hid.lock()) {
          values_arrived(hid, shared_event_queue);
        }
      });

      // Observe

      auto hid_observer = std::make_shared<krbn::hid_observer>(hid);

      hid_observer->device_observed.connect([weak_hid] {
        if (auto hid = weak_hid.lock()) {
          krbn::logger::get_logger().info("{0} is observed.", hid->get_name_for_log());
        }
      });

      hid_observer->device_unobserved.connect([weak_hid] {
        if (auto hid = weak_hid.lock()) {
          krbn::logger::get_logger().info("{0} is unobserved.", hid->get_name_for_log());
        }
      });

      hid_observer->async_observe();

      hid_observers_[hid->get_registry_entry_id()] = hid_observer;
    });

    hid_manager_->device_removed.connect([this](auto&& registry_entry_id) {
      krbn::logger::get_logger().info("registry_entry_id:{0} is removed.", type_safe::get(registry_entry_id));

      hids_.erase(registry_entry_id);
      hid_observers_.erase(registry_entry_id);
    });

    hid_manager_->async_start();
  }

  virtual ~dump_hid_value(void) {
    detach_from_dispatcher([this] {
      hid_manager_ = nullptr;
      hid_observers_.clear();
    });
  }

private:
  void values_arrived(std::shared_ptr<krbn::human_interface_device> hid,
                      std::shared_ptr<krbn::event_queue::queue> event_queue) const {
    for (const auto& entry : event_queue->get_entries()) {
      std::cout << entry.get_event_time_stamp().get_time_stamp() << " ";

      switch (entry.get_event().get_type()) {
        case krbn::event_queue::event::type::none:
          std::cout << "none" << std::endl;
          break;

        case krbn::event_queue::event::type::key_code:
          if (auto key_code = entry.get_event().get_key_code()) {
            std::cout << "Key: " << std::dec << static_cast<uint32_t>(*key_code) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::consumer_key_code:
          if (auto consumer_key_code = entry.get_event().get_consumer_key_code()) {
            std::cout << "ConsumerKey: " << std::dec << static_cast<uint32_t>(*consumer_key_code) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_button:
          if (auto pointing_button = entry.get_event().get_pointing_button()) {
            std::cout << "Button: " << std::dec << static_cast<uint32_t>(*pointing_button) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_motion:
          if (auto pointing_motion = entry.get_event().get_pointing_motion()) {
            std::cout << "pointing_motion: " << pointing_motion->to_json() << std::endl;
          }
          break;

        case krbn::event_queue::event::type::shell_command:
          std::cout << "shell_command" << std::endl;
          break;

        case krbn::event_queue::event::type::select_input_source:
          std::cout << "select_input_source" << std::endl;
          break;

        case krbn::event_queue::event::type::set_variable:
          std::cout << "set_variable" << std::endl;
          break;

        case krbn::event_queue::event::type::mouse_key:
          std::cout << "mouse_key" << std::endl;
          break;

        case krbn::event_queue::event::type::stop_keyboard_repeat:
          std::cout << "stop_keyboard_repeat" << std::endl;
          break;

        case krbn::event_queue::event::type::device_keys_and_pointing_buttons_are_released:
          std::cout << "device_keys_and_pointing_buttons_are_released for " << hid->get_name_for_log() << " (" << hid->get_device_id() << ")" << std::endl;
          break;

        case krbn::event_queue::event::type::device_ungrabbed:
          std::cout << "device_ungrabbed for " << hid->get_name_for_log() << " (" << hid->get_device_id() << ")" << std::endl;
          break;

        case krbn::event_queue::event::type::caps_lock_state_changed:
          if (auto integer_value = entry.get_event().get_integer_value()) {
            std::cout << "caps_lock_state_changed " << *integer_value << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_device_event_from_event_tap:
          std::cout << "pointing_device_event_from_event_tap from " << hid->get_name_for_log() << " (" << hid->get_device_id() << ")" << std::endl;
          break;

        case krbn::event_queue::event::type::frontmost_application_changed:
          if (auto frontmost_application = entry.get_event().get_frontmost_application()) {
            std::cout << "frontmost_application_changed "
                      << frontmost_application->get_bundle_identifier() << " "
                      << frontmost_application->get_file_path() << std::endl;
          }
          break;

        case krbn::event_queue::event::type::input_source_changed:
          if (auto input_source_identifiers = entry.get_event().get_input_source_identifiers()) {
            std::cout << "input_source_changed " << input_source_identifiers << std::endl;
          }
          break;

        case krbn::event_queue::event::type::keyboard_type_changed:
          if (auto keyboard_type = entry.get_event().get_keyboard_type()) {
            std::cout << "keyboard_type_changed " << keyboard_type << std::endl;
          }
          break;

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

  std::unique_ptr<pqrs::osx::iokit_hid_manager> hid_manager_;
  std::unordered_map<pqrs::osx::iokit_registry_entry_id, std::shared_ptr<krbn::human_interface_device>> hids_;
  std::unordered_map<pqrs::osx::iokit_registry_entry_id, std::shared_ptr<krbn::hid_observer>> hid_observers_;
};
} // namespace

int main(int argc, const char* argv[]) {
  krbn::dispatcher_utility::initialize_dispatchers();

  signal(SIGINT, [](int) {
    CFRunLoopStop(CFRunLoopGetMain());
  });

  auto d = std::make_unique<dump_hid_value>();

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

  CFRunLoopRun();

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

  d = nullptr;

  krbn::dispatcher_utility::terminate_dispatchers();

  return 0;
}
<commit_msg>update appendix/dump_hid_value<commit_after>#include "boost_defs.hpp"

#include "dispatcher_utility.hpp"
#include "hid_observer.hpp"
#include "iokit_utility.hpp"
#include <boost/optional/optional_io.hpp>
#include <pqrs/osx/iokit_hid_manager.hpp>

namespace {
class dump_hid_value final : public pqrs::dispatcher::extra::dispatcher_client {
public:
  dump_hid_value(const dump_hid_value&) = delete;

  dump_hid_value(void) : dispatcher_client() {
    std::vector<pqrs::cf_ptr<CFDictionaryRef>> matching_dictionaries;

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_keyboard));

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_mouse));

    matching_dictionaries.push_back(
        pqrs::osx::iokit_hid_manager::make_matching_dictionary(
            pqrs::osx::iokit_hid_usage_page_generic_desktop,
            pqrs::osx::iokit_hid_usage_generic_desktop_pointer));

    hid_manager_ = std::make_unique<pqrs::osx::iokit_hid_manager>(weak_dispatcher_,
                                                                  matching_dictionaries);

    hid_manager_->device_detected.connect([this](auto&& registry_entry_id, auto&& device_ptr) {
      auto hid = std::make_shared<krbn::human_interface_device>(*device_ptr,
                                                                registry_entry_id);
      hids_[registry_entry_id] = hid;
      auto device_name = hid->get_name_for_log();

      hid->values_arrived.connect([this, registry_entry_id](auto&& shared_event_queue) {
        values_arrived(shared_event_queue, registry_entry_id);
      });

      // Observe

      auto hid_observer = std::make_shared<krbn::hid_observer>(hid);

      hid_observer->device_observed.connect([device_name, registry_entry_id] {
        krbn::logger::get_logger().info("{0}:{1} is observed.",
                                        device_name,
                                        type_safe::get(registry_entry_id));
      });

      hid_observer->device_unobserved.connect([device_name, registry_entry_id] {
        krbn::logger::get_logger().info("{0}:{1} is unobserved.",
                                        device_name,
                                        type_safe::get(registry_entry_id));
      });

      hid_observer->async_observe();

      hid_observers_[hid->get_registry_entry_id()] = hid_observer;
    });

    hid_manager_->device_removed.connect([this](auto&& registry_entry_id) {
      krbn::logger::get_logger().info("registry_entry_id:{0} is removed.", type_safe::get(registry_entry_id));

      hids_.erase(registry_entry_id);
      hid_observers_.erase(registry_entry_id);
    });

    hid_manager_->async_start();
  }

  virtual ~dump_hid_value(void) {
    detach_from_dispatcher([this] {
      hid_manager_ = nullptr;
      hid_observers_.clear();
    });
  }

private:
  void values_arrived(std::shared_ptr<krbn::event_queue::queue> event_queue,
                      pqrs::osx::iokit_registry_entry_id registry_entry_id) const {
    for (const auto& entry : event_queue->get_entries()) {
      std::cout << entry.get_event_time_stamp().get_time_stamp() << " ";

      switch (entry.get_event().get_type()) {
        case krbn::event_queue::event::type::none:
          std::cout << "none" << std::endl;
          break;

        case krbn::event_queue::event::type::key_code:
          if (auto key_code = entry.get_event().get_key_code()) {
            std::cout << "Key: " << std::dec << static_cast<uint32_t>(*key_code) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::consumer_key_code:
          if (auto consumer_key_code = entry.get_event().get_consumer_key_code()) {
            std::cout << "ConsumerKey: " << std::dec << static_cast<uint32_t>(*consumer_key_code) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_button:
          if (auto pointing_button = entry.get_event().get_pointing_button()) {
            std::cout << "Button: " << std::dec << static_cast<uint32_t>(*pointing_button) << " "
                      << entry.get_event_type()
                      << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_motion:
          if (auto pointing_motion = entry.get_event().get_pointing_motion()) {
            std::cout << "pointing_motion: " << pointing_motion->to_json() << std::endl;
          }
          break;

        case krbn::event_queue::event::type::shell_command:
          std::cout << "shell_command" << std::endl;
          break;

        case krbn::event_queue::event::type::select_input_source:
          std::cout << "select_input_source" << std::endl;
          break;

        case krbn::event_queue::event::type::set_variable:
          std::cout << "set_variable" << std::endl;
          break;

        case krbn::event_queue::event::type::mouse_key:
          std::cout << "mouse_key" << std::endl;
          break;

        case krbn::event_queue::event::type::stop_keyboard_repeat:
          std::cout << "stop_keyboard_repeat" << std::endl;
          break;

        case krbn::event_queue::event::type::device_keys_and_pointing_buttons_are_released:
          std::cout << "device_keys_and_pointing_buttons_are_released: " << registry_entry_id << std::endl;
          break;

        case krbn::event_queue::event::type::device_ungrabbed:
          std::cout << "device_ungrabbed: " << registry_entry_id << std::endl;
          break;

        case krbn::event_queue::event::type::caps_lock_state_changed:
          if (auto integer_value = entry.get_event().get_integer_value()) {
            std::cout << "caps_lock_state_changed " << *integer_value << std::endl;
          }
          break;

        case krbn::event_queue::event::type::pointing_device_event_from_event_tap:
          std::cout << "pointing_device_event_from_event_tap: " << registry_entry_id << std::endl;
          break;

        case krbn::event_queue::event::type::frontmost_application_changed:
          if (auto frontmost_application = entry.get_event().get_frontmost_application()) {
            std::cout << "frontmost_application_changed "
                      << frontmost_application->get_bundle_identifier() << " "
                      << frontmost_application->get_file_path() << std::endl;
          }
          break;

        case krbn::event_queue::event::type::input_source_changed:
          if (auto input_source_identifiers = entry.get_event().get_input_source_identifiers()) {
            std::cout << "input_source_changed " << input_source_identifiers << std::endl;
          }
          break;

        case krbn::event_queue::event::type::keyboard_type_changed:
          if (auto keyboard_type = entry.get_event().get_keyboard_type()) {
            std::cout << "keyboard_type_changed " << keyboard_type << std::endl;
          }
          break;

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

  std::unique_ptr<pqrs::osx::iokit_hid_manager> hid_manager_;
  std::unordered_map<pqrs::osx::iokit_registry_entry_id, std::shared_ptr<krbn::human_interface_device>> hids_;
  std::unordered_map<pqrs::osx::iokit_registry_entry_id, std::shared_ptr<krbn::hid_observer>> hid_observers_;
};
} // namespace

int main(int argc, const char* argv[]) {
  krbn::dispatcher_utility::initialize_dispatchers();

  signal(SIGINT, [](int) {
    CFRunLoopStop(CFRunLoopGetMain());
  });

  auto d = std::make_unique<dump_hid_value>();

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

  CFRunLoopRun();

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

  d = nullptr;

  krbn::dispatcher_utility::terminate_dispatchers();

  return 0;
}
<|endoftext|>


<commit_before>#ifndef MATCHES_DHT_HPP
#define MATCHES_DHT_HPP

#include <Grappa.hpp>
#include <GlobalAllocator.hpp>
#include <ParallelLoop.hpp>
#include <BufferVector.hpp>
#include <Metrics.hpp>

#include <list>

// for all hash tables
//GRAPPA_DEFINE_METRIC(MaxMetric<uint64_t>, max_cell_length, 0);

// for naming the types scoped in MatchesDHT
#define MDHT_TYPE(type) typename MatchesDHT<K,V,HF>::type

// Hash table for joins
// * allows multiple copies of a Key
// * lookups return all Key matches
template <typename K, typename V, uint64_t (*HF)(K)>
class MatchesDHT {

  private:
    struct Entry {
      K key;
      BufferVector<V> * vs;
      Entry( K key ) : key(key), vs(new BufferVector<V>( 16 )) {}
      Entry ( ) {}
    };

    struct Cell {
      std::list<Entry> * entries;

      Cell() : entries( NULL ) {}
    };

    struct lookup_result {
      GlobalAddress<V> matches;
      size_t num;
    };

    // private members
    GlobalAddress< Cell > base;
    size_t capacity;

    uint64_t computeIndex( K key ) {
      return HF(key) % capacity;
    }

    // for creating local MatchesDHT
    MatchesDHT( GlobalAddress<Cell> base, size_t capacity ) {
      this->base = base;
      this->capacity = capacity;
    }

    static bool lookup_local( K key, Cell * target, Entry * result ) {
        std::list<MDHT_TYPE(Entry)> * entries = target->entries;

        // first check if the cell has any entries;
        // if not then the lookup returns nothing
        if ( entries == NULL ) return false;

        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          const Entry e = *i;
          if ( e.key == key ) {  // typename K must implement operator==
            *result = e;
            return true;
          }
        }

        return false;
    }

  public:
    // for static construction
    MatchesDHT( ) {}

    static void init_global_DHT( MatchesDHT<K,V,HF> * globally_valid_local_pointer, size_t capacity ) {
      GlobalAddress<Cell> base = Grappa::global_alloc<Cell>( capacity );

      Grappa::on_all_cores( [globally_valid_local_pointer,base,capacity] {
        *globally_valid_local_pointer = MatchesDHT<K,V,HF>( base, capacity );
      });

      Grappa::forall( base, capacity, []( int64_t i, Cell& c ) {
        Cell empty;
        c = empty;
      });
    }

    static void set_RO_global( MatchesDHT<K,V,HF> * globally_valid_local_pointer ) {
      Grappa::forall( globally_valid_local_pointer->base, globally_valid_local_pointer->capacity, []( int64_t i, Cell& c ) {
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = c.entries;

        // if cell is not hit then no action
        if ( entries == NULL ) {
          return;
        }

        uint64_t sum_size = 0;
        // for all keys, set match vector to RO
        typename std::list<MDHT_TYPE(Entry)>::iterator it;
        for (it = entries->begin(); it!=entries->end(); ++it) {
          Entry e = *it;
          e.vs->setReadMode();
          sum_size+=e.vs->getLength();
        }
        //max_cell_length.add(sum_size);
      });
    }

    uint64_t lookup ( K key, GlobalAddress<V> * vals ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      lookup_result result = Grappa::delegate::call( target.core(), [key,target,this]() {

        MDHT_TYPE(lookup_result) lr;
        lr.num = 0;

        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          lr.matches = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer());
          lr.num = e.vs->getLength();
        }

        return lr;
      });

      *vals = result.matches;
      return result.num;
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup_iter ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      //TODO optimization where only need to do remotePrivateTask instead of call_async
      //if you are going to do more suspending ops (comms) inside the loop
      spawnRemote<GCE>( target.node(), [key, target, f, this]() {
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          V * results = e.vs->getReadBuffer().pointer(); // global address to local array
          forall_here<async,GCE>(0, e.vs->getLength(), [f,results](int64_t start, int64_t iters) {
            for  (int64_t i=start; i<start+iters; i++) {
              // call the continuation with the lookup result
              f(results[i]);
            }
          });
        }
      });
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call<async>( target.node(), [key, target, f]() {
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          V * results = e.vs->getReadBuffer().pointer(); // global address to local array
          uint64_t len = e.vs->getLength();
          f(results, len);
        }
      });
    }

    // Inserts the key if not already in the set
    // Shouldn't be used with `insert`.
    //
    // returns true if the set already contains the key
    bool insert_unique( K key ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;
//FIXME: remove index capture
      bool result = Grappa::delegate::call( target.core(), [index,key, target]() {   // TODO: have an additional version that returns void
                                                                 // to upgrade to call_async
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so no insert
            return true;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );        // TODO: cleanup since sharing insert* code here, we are just going to store an empty vector
                                  // perhaps a different module
        entries->push_back( newe );

        return false;
     });

      return result;
    }

    void insert( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call( target.core(), [key, val, target]() {   // TODO: upgrade to call_async
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so add to matches
            e.vs->insert( val );
            return 0;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );
        newe.vs->insert( val );
        entries->push_back( newe );

        return 0;
      });
    }

};

#endif // MATCHES_DHT_HPP
<commit_msg>make hash multi table compile with new changes<commit_after>#ifndef MATCHES_DHT_HPP
#define MATCHES_DHT_HPP

#include <Grappa.hpp>
#include <GlobalAllocator.hpp>
#include <ParallelLoop.hpp>
#include <BufferVector.hpp>
#include <Metrics.hpp>

#include <list>

// for all hash tables
//GRAPPA_DEFINE_METRIC(MaxMetric<uint64_t>, max_cell_length, 0);

// for naming the types scoped in MatchesDHT
#define MDHT_TYPE(type) typename MatchesDHT<K,V,HF>::type

// Hash table for joins
// * allows multiple copies of a Key
// * lookups return all Key matches
template <typename K, typename V, uint64_t (*HF)(K)>
class MatchesDHT {

  private:
    struct Entry {
      K key;
      BufferVector<V> * vs;
      Entry( K key ) : key(key), vs(new BufferVector<V>( 16 )) {}
      Entry ( ) {}
    };

    struct Cell {
      std::list<Entry> * entries;

      Cell() : entries( NULL ) {}
    };

    struct lookup_result {
      GlobalAddress<V> matches;
      size_t num;
    };

    // private members
    GlobalAddress< Cell > base;
    size_t capacity;

    uint64_t computeIndex( K key ) {
      return HF(key) % capacity;
    }

    // for creating local MatchesDHT
    MatchesDHT( GlobalAddress<Cell> base, size_t capacity ) {
      this->base = base;
      this->capacity = capacity;
    }

    static bool lookup_local( K key, Cell * target, Entry * result ) {
        std::list<MDHT_TYPE(Entry)> * entries = target->entries;

        // first check if the cell has any entries;
        // if not then the lookup returns nothing
        if ( entries == NULL ) return false;

        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          const Entry e = *i;
          if ( e.key == key ) {  // typename K must implement operator==
            *result = e;
            return true;
          }
        }

        return false;
    }

  public:
    // for static construction
    MatchesDHT( ) {}

    static void init_global_DHT( MatchesDHT<K,V,HF> * globally_valid_local_pointer, size_t capacity ) {
      GlobalAddress<Cell> base = Grappa::global_alloc<Cell>( capacity );

      Grappa::on_all_cores( [globally_valid_local_pointer,base,capacity] {
        *globally_valid_local_pointer = MatchesDHT<K,V,HF>( base, capacity );
      });

      Grappa::forall( base, capacity, []( int64_t i, Cell& c ) {
        Cell empty;
        c = empty;
      });
    }

    static void set_RO_global( MatchesDHT<K,V,HF> * globally_valid_local_pointer ) {
      Grappa::forall( globally_valid_local_pointer->base, globally_valid_local_pointer->capacity, []( int64_t i, Cell& c ) {
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = c.entries;

        // if cell is not hit then no action
        if ( entries == NULL ) {
          return;
        }

        uint64_t sum_size = 0;
        // for all keys, set match vector to RO
        typename std::list<MDHT_TYPE(Entry)>::iterator it;
        for (it = entries->begin(); it!=entries->end(); ++it) {
          Entry e = *it;
          e.vs->setReadMode();
          sum_size+=e.vs->getLength();
        }
        //max_cell_length.add(sum_size);
      });
    }

    uint64_t lookup ( K key, GlobalAddress<V> * vals ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      lookup_result result = Grappa::delegate::call( target.core(), [key,target,this]() {

        MDHT_TYPE(lookup_result) lr;
        lr.num = 0;

        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          lr.matches = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer());
          lr.num = e.vs->getLength();
        }

        return lr;
      });

      *vals = result.matches;
      return result.num;
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup_iter ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      // FIXME: remove 'this' capture when using gcc4.8, this is just a bug in 4.7
      //TODO optimization where only need to do remotePrivateTask instead of call_async
      //if you are going to do more suspending ops (comms) inside the loop
      spawnRemote<GCE>( target.core(), [key, target, f, this]() {
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          V * results = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer()).pointer(); // global address to local array
          forall_here<async,GCE>(0, e.vs->getLength(), [f,results](int64_t start, int64_t iters) {
            for  (int64_t i=start; i<start+iters; i++) {
              // call the continuation with the lookup result
              f(results[i]);
            }
          });
        }
      });
    }

    // version of lookup that takes a continuation instead of returning results back
    template< typename CF, GlobalCompletionEvent * GCE = &Grappa::impl::local_gce >
    void lookup ( K key, CF f ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call<async>( target.core(), [key, target, f]() {
        Entry e;
        if (lookup_local( key, target.pointer(), &e)) {
          V * results = static_cast<GlobalAddress<V>>(e.vs->getReadBuffer()).pointer(); // global address to local array
          uint64_t len = e.vs->getLength();
          f(results, len);
        }
      });
    }

    // Inserts the key if not already in the set
    // Shouldn't be used with `insert`.
    //
    // returns true if the set already contains the key
    bool insert_unique( K key ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;
//FIXME: remove index capture
      bool result = Grappa::delegate::call( target.core(), [index,key, target]() {   // TODO: have an additional version that returns void
                                                                 // to upgrade to call_async
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so no insert
            return true;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );        // TODO: cleanup since sharing insert* code here, we are just going to store an empty vector
                                  // perhaps a different module
        entries->push_back( newe );

        return false;
     });

      return result;
    }

    void insert( K key, V val ) {
      uint64_t index = computeIndex( key );
      GlobalAddress< Cell > target = base + index;

      Grappa::delegate::call( target.core(), [key, val, target]() {   // TODO: upgrade to call_async
        // list of entries in this cell
        std::list<MDHT_TYPE(Entry)> * entries = target.pointer()->entries;

        // if first time the cell is hit then initialize
        if ( entries == NULL ) {
          entries = new std::list<Entry>();
          target.pointer()->entries = entries;
        }

        // find matching key in the list
        typename std::list<MDHT_TYPE(Entry)>::iterator i;
        for (i = entries->begin(); i!=entries->end(); ++i) {
          Entry e = *i;
          if ( e.key == key ) {
            // key found so add to matches
            e.vs->insert( val );
            return 0;
          }
        }

        // this is the first time the key has been seen
        // so add it to the list
        Entry newe( key );
        newe.vs->insert( val );
        entries->push_back( newe );

        return 0;
      });
    }

};

#endif // MATCHES_DHT_HPP
<|endoftext|>