<commit_before>#include <other/core/value/Prop.h>
#include <other/core/value/Listen.h>
#include <other/core/array/NdArray.h>
#include <other/core/array/view.h>
#include <other/core/python/Class.h>
#include <other/core/python/numpy.h>
#include <other/core/python/Ptr.h>
#include <other/core/structure/Tuple.h>
#include <other/core/utility/const_cast.h>
#include <other/core/utility/curry.h>
#include <other/core/utility/format.h>
#include <other/core/vector/Frame.h>
#include <other/core/vector/Rotation.h>
#include <iostream>
#include <stdio.h>
namespace other{

using std::cout;
using std::endl;
using std::exception;
using std::numeric_limits;
typedef real T;
typedef Vector<T,2> TV2;
typedef Vector<T,3> TV3;
typedef Vector<T,4> TV4;

PropBase::PropBase()
  : hidden(false)
  , required(false)
  , abbrev(0)
{}

PropBase::~PropBase() {}

void PropBase::dump(int indent) const {
  printf("%*sProp('%s',%s)\n",2*indent,"",name_().c_str(),value_str().c_str());
}

// Since PropBase doesn't by itself inherit from Object due to multiple inheritance woes,
// we need a special wrapper class to expose Prop<T> to python.

#ifdef OTHER_PYTHON
Ref<PropBase> make_prop_shape(const string& n, NdArray<const T> a, RawArray<const int> shape) {
  const int rank = a.rank();
  OTHER_ASSERT(rank==shape.size());
  const int fixed = shape.count_matches(-1);
  if (shape.slice(0,fixed).count_matches(-1)!=fixed)
    throw ValueError(format("Prop: -1's in shape must occur at the beginning, got %s",str(shape)));
  for (int i=fixed;i<rank;i++)
    if (a.shape[i]!=shape[i])
      throw ValueError(format("Prop: default shape %s does not match shape specification %s",str(a.shape),str(shape)));
  if (rank==1 && fixed==0) {
    if (shape[0]==2) return new_<Prop<TV2>>(n,vec(a[0],a[1]));
    if (shape[0]==3) return new_<Prop<TV3>>(n,vec(a[0],a[1],a[2]));
    if (shape[0]==4) return new_<Prop<TV4>>(n,vec(a[0],a[1],a[2],a[3]));
  } else if (rank==1 && fixed==1)
    return new_<Prop<Array<const T>>>(n,a.flat);
  else if (rank==2 && fixed==1) {
    if (shape[1]==2) return new_<Prop<Array<const TV2>>>(n,vector_view_own<2>(a.flat));
    if (shape[1]==3) return new_<Prop<Array<const TV3>>>(n,vector_view_own<3>(a.flat));
    if (shape[1]==4) return new_<Prop<Array<const TV4>>>(n,vector_view_own<4>(a.flat));
  }
  throw NotImplementedError(format("Prop: shape specification %s is not implemented",str(shape)));
}

Ref<PropBase> make_prop(const string& n, PyObject* value) {
  // If the value has known simple type, make the corresponding property
  if (PyBool_Check(value))
    return new_<Prop<bool>>(n,from_python<bool>(value));
  if (PyInt_Check(value))
    return new_<Prop<int>>(n,from_python<int>(value));
  if (PyFloat_Check(value))
    return new_<Prop<double>>(n,from_python<double>(value));
  if (PyString_Check(value))
    return new_<Prop<string>>(n,from_python<string>(value));
  if (PySequence_Check(value)) {
    if (PyArray_Check(value)) {
      if (rotations_check<TV2>(value))
        return new_<Prop<Rotation<TV2>>>(n,from_python<Rotation<TV2>>(value));
      if (rotations_check<TV3>(value))
        return new_<Prop<Rotation<TV3>>>(n,from_python<Rotation<TV3>>(value));
      if (frames_check<TV2>(value))
        return new_<Prop<Frame<TV2>>>(n,from_python<Frame<TV2>>(value));
      if (frames_check<TV3>(value))
        return new_<Prop<Frame<TV3>>>(n,from_python<Frame<TV3>>(value));
    }
    NdArray<const T> a;
    try {
      a = from_python<NdArray<const T>>(value);
    } catch (const exception&) {
      // If the NdArray conversion fails, squelch the error and fall back to our default
      PyErr_Clear();
    }
    return make_prop_shape(n,a,a.shape);
  }

  // Default to a property containing an arbitrary python object
  return new_<Prop<Ref<>>>(n,ref(*value));
}
#endif

template<class T> PropClamp<T,true>::PropClamp()
  : min(-numeric_limits<T>::max())
  , max( numeric_limits<T>::max())
  , step(max) {}

template<class T> PropClamp<T,true>::~PropClamp() {}

template<class T> Prop<T>& PropClamp<T,true>::set_min(const PropRef<T> p, real alpha) {
  Prop<T>& self = this->self();
  OTHER_ASSERT(p->name != self.name && !(p->prop_min && p->prop_min->x->name == self.name));
  prop_min.reset(new Tuple<PropRef<T>,Ref<Listen>,real>(p,listen(p,curry(&Self::minimize,this)),alpha));
  minimize();
  return self;
}

template<class T> Prop<T>& PropClamp<T,true>::set_max(const PropRef<T> p, real alpha) {
  auto& self = this->self();
  OTHER_ASSERT(p->name != self.name && !(p->prop_max && p->prop_max->x->name == self.name));
  prop_max.reset(new Tuple<PropRef<T>,Ref<Listen>,real>(p,listen(p,curry(&Self::maximize,this)),alpha));
  maximize();
  return self;
}

template<class T> void PropClamp<T,true>::minimize() {
  const auto& self = this->self();
  min = T(prop_min->x()*prop_min->z);
  T v = self();
  self.set_value(v < min ? min : v); //a bit dirty, but we want to trigger update to toolbar
}

template<class T> void PropClamp<T,true>::maximize() {
  const auto& self = this->self();
  max = T(prop_max->x()*prop_max->z);
  T v = self();
  self.set_value(v > max ? max : v); //a bit dirty, but we want to trigger update to toolbar
}

template struct PropClamp<int,true>;
template struct PropClamp<double,true>;

#ifdef OTHER_PYTHON

PyObject* to_python(const PropBase& prop) {
  return to_python(prop.base());
}

PyObject* ptr_to_python(const PropBase* prop) {
  return (PyObject*)&prop->base()-1;
}

PropBase& FromPython<PropBase&>::convert(PyObject* object) {
  ValueBase& value = from_python<ValueBase&>(object);
  if (PropBase* prop = dynamic_cast<PropBase*>(&value))
    return *prop;
  throw TypeError("expected Prop, got Value");
}

PropBase& prop_from_python(PyObject* object, const type_info& goal) {
  PropBase& self = from_python<PropBase&>(object);
  const type_info& type = self.type();
  if (type==goal || !strcmp(type.name(),goal.name()))
    return self;
  throw TypeError(format("expected Prop<%s>, got Prop<%s>",goal.name(),self.type().name()));
}

namespace {
struct Unusable {
  bool operator==(Unusable) const { return true; }
  friend ostream& operator<<(ostream& output, Unusable) { return output; }
};
}

// A Prop with a non-python convertible type
static Ref<PropBase> unusable_prop_test() {
  BOOST_MPL_ASSERT((has_to_python<int>));
  return new_<Prop<Unusable>>("unusable",Unusable());
}

#endif

}
using namespace other;

void wrap_prop() {
#ifdef OTHER_PYTHON
  OTHER_FUNCTION(make_prop)
  OTHER_FUNCTION(make_prop_shape)
  OTHER_FUNCTION(unusable_prop_test)
#endif
}
<commit_msg>Prop: Make make_prop fall back to default in more cases<commit_after>#include <other/core/value/Prop.h>
#include <other/core/value/Listen.h>
#include <other/core/array/NdArray.h>
#include <other/core/array/view.h>
#include <other/core/python/Class.h>
#include <other/core/python/numpy.h>
#include <other/core/python/Ptr.h>
#include <other/core/structure/Tuple.h>
#include <other/core/utility/const_cast.h>
#include <other/core/utility/curry.h>
#include <other/core/utility/format.h>
#include <other/core/vector/Frame.h>
#include <other/core/vector/Rotation.h>
#include <iostream>
#include <stdio.h>
namespace other{

using std::cout;
using std::endl;
using std::exception;
using std::numeric_limits;
typedef real T;
typedef Vector<T,2> TV2;
typedef Vector<T,3> TV3;
typedef Vector<T,4> TV4;

PropBase::PropBase()
  : hidden(false)
  , required(false)
  , abbrev(0)
{}

PropBase::~PropBase() {}

void PropBase::dump(int indent) const {
  printf("%*sProp('%s',%s)\n",2*indent,"",name_().c_str(),value_str().c_str());
}

// Since PropBase doesn't by itself inherit from Object due to multiple inheritance woes,
// we need a special wrapper class to expose Prop<T> to python.

#ifdef OTHER_PYTHON
Ref<PropBase> make_prop_shape(const string& n, NdArray<const T> a, RawArray<const int> shape) {
  const int rank = a.rank();
  OTHER_ASSERT(rank==shape.size());
  const int fixed = shape.count_matches(-1);
  if (shape.slice(0,fixed).count_matches(-1)!=fixed)
    throw ValueError(format("Prop: -1's in shape must occur at the beginning, got %s",str(shape)));
  for (int i=fixed;i<rank;i++)
    if (a.shape[i]!=shape[i])
      throw ValueError(format("Prop: default shape %s does not match shape specification %s",str(a.shape),str(shape)));
  if (rank==1 && fixed==0) {
    if (shape[0]==2) return new_<Prop<TV2>>(n,vec(a[0],a[1]));
    if (shape[0]==3) return new_<Prop<TV3>>(n,vec(a[0],a[1],a[2]));
    if (shape[0]==4) return new_<Prop<TV4>>(n,vec(a[0],a[1],a[2],a[3]));
  } else if (rank==1 && fixed==1)
    return new_<Prop<Array<const T>>>(n,a.flat);
  else if (rank==2 && fixed==1) {
    if (shape[1]==2) return new_<Prop<Array<const TV2>>>(n,vector_view_own<2>(a.flat));
    if (shape[1]==3) return new_<Prop<Array<const TV3>>>(n,vector_view_own<3>(a.flat));
    if (shape[1]==4) return new_<Prop<Array<const TV4>>>(n,vector_view_own<4>(a.flat));
  }
  throw NotImplementedError(format("Prop: shape specification %s is not implemented",str(shape)));
}

Ref<PropBase> make_prop(const string& n, PyObject* value) {
  // If the value has known simple type, make the corresponding property
  if (PyBool_Check(value))
    return new_<Prop<bool>>(n,from_python<bool>(value));
  if (PyInt_Check(value))
    return new_<Prop<int>>(n,from_python<int>(value));
  if (PyFloat_Check(value))
    return new_<Prop<double>>(n,from_python<double>(value));
  if (PyString_Check(value))
    return new_<Prop<string>>(n,from_python<string>(value));
  if (PySequence_Check(value)) {
    if (PyArray_Check(value)) {
      if (rotations_check<TV2>(value))
        return new_<Prop<Rotation<TV2>>>(n,from_python<Rotation<TV2>>(value));
      if (rotations_check<TV3>(value))
        return new_<Prop<Rotation<TV3>>>(n,from_python<Rotation<TV3>>(value));
      if (frames_check<TV2>(value))
        return new_<Prop<Frame<TV2>>>(n,from_python<Frame<TV2>>(value));
      if (frames_check<TV3>(value))
        return new_<Prop<Frame<TV3>>>(n,from_python<Frame<TV3>>(value));
    }
    NdArray<const T> a;
    try {
      a = from_python<NdArray<const T>>(value);
      return make_prop_shape(n,a,a.shape);
    } catch (const exception&) {
      // If the conversion fails, squelch the error and fall back to our default
      PyErr_Clear();
    }
  }

  // Default to a property containing an arbitrary python object
  return new_<Prop<Ref<>>>(n,ref(*value));
}
#endif

template<class T> PropClamp<T,true>::PropClamp()
  : min(-numeric_limits<T>::max())
  , max( numeric_limits<T>::max())
  , step(max) {}

template<class T> PropClamp<T,true>::~PropClamp() {}

template<class T> Prop<T>& PropClamp<T,true>::set_min(const PropRef<T> p, real alpha) {
  Prop<T>& self = this->self();
  OTHER_ASSERT(p->name != self.name && !(p->prop_min && p->prop_min->x->name == self.name));
  prop_min.reset(new Tuple<PropRef<T>,Ref<Listen>,real>(p,listen(p,curry(&Self::minimize,this)),alpha));
  minimize();
  return self;
}

template<class T> Prop<T>& PropClamp<T,true>::set_max(const PropRef<T> p, real alpha) {
  auto& self = this->self();
  OTHER_ASSERT(p->name != self.name && !(p->prop_max && p->prop_max->x->name == self.name));
  prop_max.reset(new Tuple<PropRef<T>,Ref<Listen>,real>(p,listen(p,curry(&Self::maximize,this)),alpha));
  maximize();
  return self;
}

template<class T> void PropClamp<T,true>::minimize() {
  const auto& self = this->self();
  min = T(prop_min->x()*prop_min->z);
  T v = self();
  self.set_value(v < min ? min : v); //a bit dirty, but we want to trigger update to toolbar
}

template<class T> void PropClamp<T,true>::maximize() {
  const auto& self = this->self();
  max = T(prop_max->x()*prop_max->z);
  T v = self();
  self.set_value(v > max ? max : v); //a bit dirty, but we want to trigger update to toolbar
}

template struct PropClamp<int,true>;
template struct PropClamp<double,true>;

#ifdef OTHER_PYTHON

PyObject* to_python(const PropBase& prop) {
  return to_python(prop.base());
}

PyObject* ptr_to_python(const PropBase* prop) {
  return (PyObject*)&prop->base()-1;
}

PropBase& FromPython<PropBase&>::convert(PyObject* object) {
  ValueBase& value = from_python<ValueBase&>(object);
  if (PropBase* prop = dynamic_cast<PropBase*>(&value))
    return *prop;
  throw TypeError("expected Prop, got Value");
}

PropBase& prop_from_python(PyObject* object, const type_info& goal) {
  PropBase& self = from_python<PropBase&>(object);
  const type_info& type = self.type();
  if (type==goal || !strcmp(type.name(),goal.name()))
    return self;
  throw TypeError(format("expected Prop<%s>, got Prop<%s>",goal.name(),self.type().name()));
}

namespace {
struct Unusable {
  bool operator==(Unusable) const { return true; }
  friend ostream& operator<<(ostream& output, Unusable) { return output; }
};
}

// A Prop with a non-python convertible type
static Ref<PropBase> unusable_prop_test() {
  BOOST_MPL_ASSERT((has_to_python<int>));
  return new_<Prop<Unusable>>("unusable",Unusable());
}

#endif

}
using namespace other;

void wrap_prop() {
#ifdef OTHER_PYTHON
  OTHER_FUNCTION(make_prop)
  OTHER_FUNCTION(make_prop_shape)
  OTHER_FUNCTION(unusable_prop_test)
#endif
}
<|endoftext|>


<commit_before>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#define _WINSOCK2API_
#endif

// bzflag common header
#include "common.h"

// class interface header
#include "URLManager.h"

// system headers
#ifdef _WIN32
#include <winsock.h>
#endif
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif
#include <iostream>

// common implementation headers
#include "bzfio.h"
#include "StateDatabase.h"

template <>
URLManager* Singleton<URLManager>::_instance = (URLManager*)0;

#ifdef HAVE_CURL
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, void *stream);
#endif // HAVE_CURL

bool URLManager::getURL(const std::string URL, std::string &data)
{
  clearInternal();

  if (!beginGet(URL))
    return false;

  char* newData = (char*)malloc(theLen + 1);
  memcpy(newData, theData, theLen);
  newData[theLen] = 0;

  data = newData;
  free(newData);

  return true;
}

bool URLManager::getURL(const std::string URL, void **data, unsigned int& size)
{
  clearInternal();

  if (!beginGet(URL))
    return false;

  *data = malloc(theLen);
  memcpy(*data, theData, theLen);
  size = theLen;
  return true;
}

void URLManager::freeURLData(void *data)
{
  free(data);
}

URLManager::URLManager()
{
  easyHandle = NULL;
  theData = NULL;
  theLen = 0;

#ifdef HAVE_CURL
  CURLcode curlResult;

#if LIBCURL_VERSION_NUM >= 0x070a00
  if ((curlResult = curl_global_init(CURL_GLOBAL_NOTHING)))
    DEBUG1("Unexpected error from libcurl; Error: %d\n", curlResult);
#endif

  easyHandle = curl_easy_init();
  if (!easyHandle) {
    DEBUG1("Something wrong with CURL\n");
    return;
  }

  CURLcode result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_WRITEFUNCTION, writeFunction);
  if (result)
    DEBUG1("Something wrong with CURL; Error: %d\n", result);

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_FILE, this);
  if (result)
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
#endif
}

URLManager::~URLManager()
{
  clearInternal();

#ifdef HAVE_CURL
  if (easyHandle)
    curl_easy_cleanup((CURL*)easyHandle);

#if LIBCURL_VERSION_NUM >= 0x070a00
  curl_global_cleanup();
#endif

#endif
}

void URLManager::collectData(char* ptr, int len)
{
  unsigned char	*newData = (unsigned char*)malloc(theLen + len);
  if (theData)
    memcpy(newData, theData, theLen);

  memcpy(&(newData[theLen]), ptr, len);
  theLen += len;

  free(theData);
  theData = newData;
}

void URLManager::clearInternal()
{
  if (theData)
    free (theData);

  theData = NULL;
  theLen = 0;
}

#ifdef HAVE_CURL
bool URLManager::beginGet(const std::string URL)
#else
bool URLManager::beginGet(const std::string)
#endif
{
#ifdef HAVE_CURL
  CURLcode result = CURLE_OK;
  if (!easyHandle) {
    return false;
  }

  float timeout = 15;
  if (BZDB.isSet("httpTimeout"))
    timeout = BZDB.eval("httpTimeout");

#if LIBCURL_VERSION_NUM >= 0x070a00
  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_NOSIGNAL, true);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }
#endif

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_TIMEOUT, timeout);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_URL, URL.c_str());
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }

  // FIXME: This could block for a _long_ time.
  result = curl_easy_perform((CURL*)easyHandle);
  if (result == (CURLcode)CURLOPT_ERRORBUFFER) {
    DEBUG1("Error: server reported: %d\n", result);
    return false;
  } else if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
    return false;
  }

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_URL, NULL);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
    return false;
  }

  if (!theData)
    return false;

  return true;
#else
  return false;
#endif // HAVE_CURL
}

#ifdef HAVE_CURL
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, void *stream)
{
  int len = size * nmemb;
  ((URLManager*)stream)->collectData((char*)ptr, len);
  return len;
}
#endif // HAVE_CURL

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>better not declare if your not going to use it<commit_after>/* bzflag
* Copyright (c) 1993 - 2005 Tim Riker
*
* This package is free software;  you can redistribute it and/or
* modify it under the terms of the license found in the file
* named COPYING that should have accompanied this file.
*
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

#ifdef _MSC_VER
#pragma warning( 4: 4786)
#define _WINSOCK2API_
#endif

// bzflag common header
#include "common.h"

// class interface header
#include "URLManager.h"

// system headers
#ifdef _WIN32
#include <winsock.h>
#endif
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif
#include <iostream>

// common implementation headers
#include "bzfio.h"
#include "StateDatabase.h"

template <>
URLManager* Singleton<URLManager>::_instance = (URLManager*)0;

#ifdef HAVE_CURL
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, void *stream);
#endif // HAVE_CURL

bool URLManager::getURL(const std::string URL, std::string &data)
{
  clearInternal();

  if (!beginGet(URL))
    return false;

  char* newData = (char*)malloc(theLen + 1);
  memcpy(newData, theData, theLen);
  newData[theLen] = 0;

  data = newData;
  free(newData);

  return true;
}

bool URLManager::getURL(const std::string URL, void **data, unsigned int& size)
{
  clearInternal();

  if (!beginGet(URL))
    return false;

  *data = malloc(theLen);
  memcpy(*data, theData, theLen);
  size = theLen;
  return true;
}

void URLManager::freeURLData(void *data)
{
  free(data);
}

URLManager::URLManager()
{
  easyHandle = NULL;
  theData = NULL;
  theLen = 0;

#ifdef HAVE_CURL

#if LIBCURL_VERSION_NUM >= 0x070a00
  CURLcode curlResult;
  if ((curlResult = curl_global_init(CURL_GLOBAL_NOTHING)))
    DEBUG1("Unexpected error from libcurl; Error: %d\n", curlResult);
#endif

  easyHandle = curl_easy_init();
  if (!easyHandle) {
    DEBUG1("Something wrong with CURL\n");
    return;
  }

  CURLcode result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_WRITEFUNCTION, writeFunction);
  if (result)
    DEBUG1("Something wrong with CURL; Error: %d\n", result);

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_FILE, this);
  if (result)
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
#endif
}

URLManager::~URLManager()
{
  clearInternal();

#ifdef HAVE_CURL
  if (easyHandle)
    curl_easy_cleanup((CURL*)easyHandle);

#if LIBCURL_VERSION_NUM >= 0x070a00
  curl_global_cleanup();
#endif

#endif
}

void URLManager::collectData(char* ptr, int len)
{
  unsigned char	*newData = (unsigned char*)malloc(theLen + len);
  if (theData)
    memcpy(newData, theData, theLen);

  memcpy(&(newData[theLen]), ptr, len);
  theLen += len;

  free(theData);
  theData = newData;
}

void URLManager::clearInternal()
{
  if (theData)
    free (theData);

  theData = NULL;
  theLen = 0;
}

#ifdef HAVE_CURL
bool URLManager::beginGet(const std::string URL)
#else
bool URLManager::beginGet(const std::string)
#endif
{
#ifdef HAVE_CURL
  CURLcode result = CURLE_OK;
  if (!easyHandle) {
    return false;
  }

  float timeout = 15;
  if (BZDB.isSet("httpTimeout"))
    timeout = BZDB.eval("httpTimeout");

#if LIBCURL_VERSION_NUM >= 0x070a00
  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_NOSIGNAL, true);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }
#endif

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_TIMEOUT, timeout);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_URL, URL.c_str());
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
  }

  // FIXME: This could block for a _long_ time.
  result = curl_easy_perform((CURL*)easyHandle);
  if (result == (CURLcode)CURLOPT_ERRORBUFFER) {
    DEBUG1("Error: server reported: %d\n", result);
    return false;
  } else if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
    return false;
  }

  result = curl_easy_setopt((CURL*)easyHandle, CURLOPT_URL, NULL);
  if (result) {
    DEBUG1("Something wrong with CURL; Error: %d\n", result);
    return false;
  }

  if (!theData)
    return false;

  return true;
#else
  return false;
#endif // HAVE_CURL
}

#ifdef HAVE_CURL
static size_t writeFunction(void *ptr, size_t size, size_t nmemb, void *stream)
{
  int len = size * nmemb;
  ((URLManager*)stream)->collectData((char*)ptr, len);
  return len;
}
#endif // HAVE_CURL

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include "HOTP.h"

/**
* Converts a 64bit int to char
*/
const unsigned char * HOTP::toChar(int64_t number) const
{
	unsigned char *temp=new unsigned char[8];//8bytes (64bit)

	for(int i=8-1;i>=0;--i)//loop through number and copy to char
	{
		temp[i]=(number&0xff);
		number>>=8;
	}
	return temp;
}

/**
* convert a 8byte char to int
*/
int64_t HOTP::toInt(const char*& number)
{
	return
		(((int64_t)number[0]<<56) & 0xff00000000000000U) |
		(((int64_t)number[1]<<48) & 0x00ff000000000000U) |
		(((int64_t)number[2]<<40) & 0x0000ff0000000000U) |
		(((int64_t)number[3]<<32) & 0x000000ff00000000U) |
		(((int64_t)number[4]<<24) & 0x00000000ff000000U) |
		(((int64_t)number[5]<<16) & 0x0000000000ff0000U) |
		(((int64_t)number[6]<<8)  & 0x000000000000ff00U) |
		(((int64_t)number[7])	  & 0x00000000000000ffU);
}

unsigned char * HOTP::generateHmac(const EVP_MD* algo)
{
	return HMAC(algo,
				this->secret,//shared secret
				this->secretLength,//length of secret
				this->toChar(this->counter),//counter to char
				8,//length of counter (8bytes)
				0,0);//don't copy to any vars
}

/**
* Set length of one time password, and generates a HMAC-SHA-1
* from input secret and counter
*/
void HOTP::initOTP(int codeLength)
{
	this->setLength(codeLength);
	this->setHmac(this->generateHmac());
}

HOTP::HOTP(unsigned char * secret,int secretLength,int codeLength,int64_t c) : OTP()
{
	this->counter=c;
	this->secretLength=secretLength;

	this->secret=new unsigned char[this->secretLength];

	for(int i=0;i<this->secretLength;++i)
		this->secret[i]=secret[i];
	this->secret[this->secretLength]='\0';
	this->initOTP(codeLength);
}

int64_t HOTP::getCounter()
{
	return this->counter;
}

void HOTP::setCounter(int64_t c)
{
	this->counter=c;
}<commit_msg>added length to setHmac<commit_after>#include "HOTP.h"
#include <iostream>
#include <iomanip>
/**
* Converts a 64bit int to char
*/
const unsigned char * HOTP::toChar(int64_t number) const
{
	unsigned char *temp=new unsigned char[8];//8bytes (64bit)

	for(int i=8-1;i>=0;--i)//loop through number and copy to char
	{
		temp[i]=(number&0xff);
		number>>=8;
	}
	return temp;
}

/**
* convert a 8byte char to int
*/
int64_t HOTP::toInt(const char*& number)
{
	return
		(((int64_t)number[0]<<56) & 0xff00000000000000U) |
		(((int64_t)number[1]<<48) & 0x00ff000000000000U) |
		(((int64_t)number[2]<<40) & 0x0000ff0000000000U) |
		(((int64_t)number[3]<<32) & 0x000000ff00000000U) |
		(((int64_t)number[4]<<24) & 0x00000000ff000000U) |
		(((int64_t)number[5]<<16) & 0x0000000000ff0000U) |
		(((int64_t)number[6]<<8)  & 0x000000000000ff00U) |
		(((int64_t)number[7])	  & 0x00000000000000ffU);
}

unsigned char * HOTP::generateHmac(const EVP_MD* algo)
{
	return HMAC(algo,
				this->secret,//shared secret
				this->secretLength,//length of secret
				this->toChar(this->counter),//counter to char
				8,//length of counter (8bytes)
				0,0);//don't copy to any vars
}

/**
* Set length of one time password, and generates a HMAC-SHA-1
* from input secret and counter
*/
void HOTP::initOTP(int codeLength)
{
	this->setLength(codeLength);
	this->setHmac(this->generateHmac(),20);
}

HOTP::HOTP(unsigned char * secret,int secretLength,int codeLength,int64_t c) : OTP()
{
	this->counter=c;
	this->secretLength=secretLength;

	this->secret=new unsigned char[this->secretLength];

	for(int i=0;i<this->secretLength;++i)
		this->secret[i]=secret[i];
	this->secret[this->secretLength]='\0';
	this->initOTP(codeLength);
}

int64_t HOTP::getCounter()
{
	return this->counter;
}

void HOTP::setCounter(int64_t c)
{
	this->counter=c;
}<|endoftext|>


<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <vector>
#include "GamepadDeviceIOKit.hpp"
#include "InputSystemMacOS.hpp"
#include "../GamepadConfig.hpp"
#include "../../utils/Utils.hpp"

namespace ouzel::input::macos
{
    namespace
    {
        constexpr float thumbDeadzone = 0.2F;

        void deviceInput(void* ctx, IOReturn, void*, IOHIDValueRef value)
        {
            auto gamepadDevice = static_cast<GamepadDeviceIOKit*>(ctx);
            gamepadDevice->handleInput(value);
        }
    }

    GamepadDeviceIOKit::GamepadDeviceIOKit(InputSystem& initInputSystem,
                                           DeviceId initId,
                                           IOHIDDeviceRef initDevice):
        GamepadDevice(initInputSystem, initId),
        device(initDevice)
    {
        if (const auto result = IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); result != kIOReturnSuccess)
            throw std::system_error(result, getErrorCategory(), "Failed to open HID device");

        const auto productName = static_cast<CFStringRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)));
        if (productName)
        {
            if (const char* deviceName = CFStringGetCStringPtr(productName, kCFStringEncodingUTF8))
                name = deviceName;
            else
            {
                const auto stringLength = CFStringGetLength(productName);
                std::vector<char> temp(static_cast<std::size_t>(CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8)) + 1);
                if (CFStringGetCString(productName, temp.data(), static_cast<CFIndex>(temp.size()), kCFStringEncodingUTF8))
                    name = temp.data();
            }
        }

        const auto vendor = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)));
        if (!vendor)
            throw std::runtime_error("Failed to get vendor ID");

        std::int32_t vendorId;
        if (!CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId))
            throw std::runtime_error("Failed to get vendor ID");

        const auto product = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)));
        if (!product)
            throw std::runtime_error("Failed to get product ID");

        std::int32_t productId;
        if (!CFNumberGetValue(product, kCFNumberSInt32Type, &productId))
            throw std::runtime_error("Failed to get product ID");

        const auto& gamepadConfig = getGamepadConfig(vendorId, productId);

        static const std::unordered_map<std::uint32_t, std::size_t> axisUsageMap = {
            {kHIDUsage_GD_X, 0},
            {kHIDUsage_GD_Y, 1},
            {kHIDUsage_GD_Z, 2},
            {kHIDUsage_GD_Rx, 3},
            {kHIDUsage_GD_Ry, 4},
            {kHIDUsage_GD_Rz, 5}
        };

        const auto elementArray = IOHIDDeviceCopyMatchingElements(device, nullptr, kIOHIDOptionsTypeNone);
        const auto count = CFArrayGetCount(elementArray);

        for (CFIndex i = 0; i < count; ++i)
        {
            auto getElement = [](CFArrayRef elementArray, CFIndex i) noexcept {
                auto arrayValue = CFArrayGetValueAtIndex(elementArray, i);
                return bitCast<IOHIDElementRef>(arrayValue);
            };

            const auto element = getElement(elementArray, i);
            const auto type = IOHIDElementGetType(element);
            const auto usagePage = IOHIDElementGetUsagePage(element);
            const auto usage = IOHIDElementGetUsage(element);

            if (usage == kHIDUsage_GD_Hatswitch)
                hatElement = element;

            if (usage >= kHIDUsage_Button_1 && usage < kHIDUsage_Button_1 + 24)
            {
                Button button;
                button.button = gamepadConfig.buttonMap[usage - kHIDUsage_Button_1];
                buttons.insert(std::pair(element, button));
            }

            if ((type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis) &&
                usagePage == kHIDPage_GenericDesktop)
            {
                auto usageIterator = axisUsageMap.find(usage);

                if (usageIterator != axisUsageMap.end())
                {
                    const std::size_t index = usageIterator->second;

                    Axis axis;
                    axis.axis = gamepadConfig.axisMap[index];
                    axis.min = IOHIDElementGetLogicalMin(element);
                    axis.max = IOHIDElementGetLogicalMax(element);
                    axis.range = axis.max - axis.min;

                    switch (gamepadConfig.axisMap[index])
                    {
                        case Gamepad::Axis::none:
                            break;
                        case Gamepad::Axis::leftThumbX:
                            axis.negativeButton = Gamepad::Button::leftThumbLeft;
                            axis.positiveButton = Gamepad::Button::leftThumbRight;
                            break;
                        case Gamepad::Axis::leftThumbY:
                            axis.negativeButton = Gamepad::Button::leftThumbUp;
                            axis.positiveButton = Gamepad::Button::leftThumbDown;
                            break;
                        case Gamepad::Axis::rightThumbX:
                            axis.negativeButton = Gamepad::Button::rightThumbLeft;
                            axis.positiveButton = Gamepad::Button::rightThumbRight;
                            break;
                        case Gamepad::Axis::rightThumbY:
                            axis.negativeButton = Gamepad::Button::rightThumbUp;
                            axis.positiveButton = Gamepad::Button::rightThumbDown;
                            break;
                        case Gamepad::Axis::leftTrigger:
                            axis.negativeButton = Gamepad::Button::leftTrigger;
                            axis.positiveButton = Gamepad::Button::leftTrigger;
                            hasLeftTrigger = true;
                            break;
                        case Gamepad::Axis::rightTrigger:
                            axis.negativeButton = Gamepad::Button::rightTrigger;
                            axis.positiveButton = Gamepad::Button::rightTrigger;
                            hasRightTrigger = true;
                            break;
                    }

                    axes.insert(std::pair(element, axis));
                }
            }
        }

        CFRelease(elementArray);

        IOHIDDeviceRegisterInputValueCallback(device, deviceInput, this);
    }

    void GamepadDeviceIOKit::handleInput(IOHIDValueRef value)
    {
        const auto element = IOHIDValueGetElement(value);
        const auto newValue = IOHIDValueGetIntegerValue(value);

        if (element == hatElement)
        {
            const auto oldHatValue = static_cast<std::uint32_t>(hatValue);
            const std::uint32_t oldBitmask = (oldHatValue >= 8) ? 0 : (1 << (oldHatValue / 2)) | // first bit
                (1 << (oldHatValue / 2 + oldHatValue % 2)) % 4; // second bit

            const std::uint32_t newBitmask = (newValue >= 8) ? 0 : (1 << (newValue / 2)) | // first bit
            (1 << (newValue / 2 + newValue % 2)) % 4; // second bit

            if ((oldBitmask & 0x01) != (newBitmask & 0x01))
                handleButtonValueChange(Gamepad::Button::dPadUp,
                                        (newBitmask & 0x01) > 0,
                                        (newBitmask & 0x01) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x02) != (newBitmask & 0x02))
                handleButtonValueChange(Gamepad::Button::dPadRight,
                                        (newBitmask & 0x02) > 0,
                                        (newBitmask & 0x02) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x04) != (newBitmask & 0x04))
                handleButtonValueChange(Gamepad::Button::dPadDown,
                                        (newBitmask & 0x04) > 0,
                                        (newBitmask & 0x04) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x08) != (newBitmask & 0x08))
                handleButtonValueChange(Gamepad::Button::dPadLeft,
                                        (newBitmask & 0x08) > 0,
                                        (newBitmask & 0x08) > 0 ? 1.0F : 0.0F);

            hatValue = newValue;
        }

        auto buttonIterator = buttons.find(element);

        if (buttonIterator != buttons.end())
        {
            Button& button = buttonIterator->second;

            if ((button.button != Gamepad::Button::leftTrigger || !hasLeftTrigger) &&
                (button.button != Gamepad::Button::rightTrigger || !hasRightTrigger))
                handleButtonValueChange(button.button, newValue > 0, (newValue > 0) ? 1.0F : 0.0F);

            button.value = newValue;
        }

        auto axisIterator = axes.find(element);

        if (axisIterator != axes.end())
        {
            Axis& axis = axisIterator->second;

            handleAxisChange(axis.value,
                                newValue,
                                axis.min, axis.range,
                                axis.negativeButton, axis.positiveButton);

            axis.value = newValue;
        }
    }

    void GamepadDeviceIOKit::handleAxisChange(CFIndex oldValue, CFIndex newValue,
                                                CFIndex min, CFIndex range,
                                                Gamepad::Button negativeButton,
                                                Gamepad::Button positiveButton)
    {
        if (negativeButton == positiveButton)
        {
            const auto floatValue = static_cast<float>(newValue - min) / range;

            handleButtonValueChange(negativeButton,
                                    floatValue > 0.0F,
                                    floatValue);
        }
        else
        {
            const auto floatValue = 2.0F * static_cast<float>(newValue - min) / range - 1.0F;

            if (floatValue > 0.0F)
                handleButtonValueChange(positiveButton,
                                        floatValue > thumbDeadzone,
                                        floatValue);
            else if (floatValue < 0.0F)
                handleButtonValueChange(negativeButton,
                                        -floatValue > thumbDeadzone,
                                        -floatValue);
            else // thumbstick is 0
            {
                if (oldValue > newValue)
                    handleButtonValueChange(positiveButton, false, 0.0F);
                else
                    handleButtonValueChange(negativeButton, false, 0.0F);
            }
        }
    }
}
<commit_msg>Use const<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <vector>
#include "GamepadDeviceIOKit.hpp"
#include "InputSystemMacOS.hpp"
#include "../GamepadConfig.hpp"
#include "../../utils/Utils.hpp"

namespace ouzel::input::macos
{
    namespace
    {
        constexpr float thumbDeadzone = 0.2F;

        void deviceInput(void* ctx, IOReturn, void*, IOHIDValueRef value)
        {
            auto gamepadDevice = static_cast<GamepadDeviceIOKit*>(ctx);
            gamepadDevice->handleInput(value);
        }
    }

    GamepadDeviceIOKit::GamepadDeviceIOKit(InputSystem& initInputSystem,
                                           DeviceId initId,
                                           IOHIDDeviceRef initDevice):
        GamepadDevice(initInputSystem, initId),
        device(initDevice)
    {
        if (const auto result = IOHIDDeviceOpen(device, kIOHIDOptionsTypeNone); result != kIOReturnSuccess)
            throw std::system_error(result, getErrorCategory(), "Failed to open HID device");

        const auto productName = static_cast<CFStringRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey)));
        if (productName)
        {
            if (const char* deviceName = CFStringGetCStringPtr(productName, kCFStringEncodingUTF8))
                name = deviceName;
            else
            {
                const auto stringLength = CFStringGetLength(productName);
                std::vector<char> temp(static_cast<std::size_t>(CFStringGetMaximumSizeForEncoding(stringLength, kCFStringEncodingUTF8)) + 1);
                if (CFStringGetCString(productName, temp.data(), static_cast<CFIndex>(temp.size()), kCFStringEncodingUTF8))
                    name = temp.data();
            }
        }

        const auto vendor = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey)));
        if (!vendor)
            throw std::runtime_error("Failed to get vendor ID");

        std::int32_t vendorId;
        if (!CFNumberGetValue(vendor, kCFNumberSInt32Type, &vendorId))
            throw std::runtime_error("Failed to get vendor ID");

        const auto product = static_cast<CFNumberRef>(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey)));
        if (!product)
            throw std::runtime_error("Failed to get product ID");

        std::int32_t productId;
        if (!CFNumberGetValue(product, kCFNumberSInt32Type, &productId))
            throw std::runtime_error("Failed to get product ID");

        const auto& gamepadConfig = getGamepadConfig(vendorId, productId);

        static const std::unordered_map<std::uint32_t, std::size_t> axisUsageMap = {
            {kHIDUsage_GD_X, 0},
            {kHIDUsage_GD_Y, 1},
            {kHIDUsage_GD_Z, 2},
            {kHIDUsage_GD_Rx, 3},
            {kHIDUsage_GD_Ry, 4},
            {kHIDUsage_GD_Rz, 5}
        };

        const auto elementArray = IOHIDDeviceCopyMatchingElements(device, nullptr, kIOHIDOptionsTypeNone);
        const auto count = CFArrayGetCount(elementArray);

        for (CFIndex i = 0; i < count; ++i)
        {
            auto getElement = [](CFArrayRef elementArray, CFIndex i) noexcept {
                auto arrayValue = CFArrayGetValueAtIndex(elementArray, i);
                return bitCast<IOHIDElementRef>(arrayValue);
            };

            const auto element = getElement(elementArray, i);
            const auto type = IOHIDElementGetType(element);
            const auto usagePage = IOHIDElementGetUsagePage(element);
            const auto usage = IOHIDElementGetUsage(element);

            if (usage == kHIDUsage_GD_Hatswitch)
                hatElement = element;

            if (usage >= kHIDUsage_Button_1 && usage < kHIDUsage_Button_1 + 24)
            {
                Button button;
                button.button = gamepadConfig.buttonMap[usage - kHIDUsage_Button_1];
                buttons.insert(std::pair(element, button));
            }

            if ((type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis) &&
                usagePage == kHIDPage_GenericDesktop)
            {
                auto usageIterator = axisUsageMap.find(usage);

                if (usageIterator != axisUsageMap.end())
                {
                    const std::size_t index = usageIterator->second;

                    Axis axis;
                    axis.axis = gamepadConfig.axisMap[index];
                    axis.min = IOHIDElementGetLogicalMin(element);
                    axis.max = IOHIDElementGetLogicalMax(element);
                    axis.range = axis.max - axis.min;

                    switch (gamepadConfig.axisMap[index])
                    {
                        case Gamepad::Axis::none:
                            break;
                        case Gamepad::Axis::leftThumbX:
                            axis.negativeButton = Gamepad::Button::leftThumbLeft;
                            axis.positiveButton = Gamepad::Button::leftThumbRight;
                            break;
                        case Gamepad::Axis::leftThumbY:
                            axis.negativeButton = Gamepad::Button::leftThumbUp;
                            axis.positiveButton = Gamepad::Button::leftThumbDown;
                            break;
                        case Gamepad::Axis::rightThumbX:
                            axis.negativeButton = Gamepad::Button::rightThumbLeft;
                            axis.positiveButton = Gamepad::Button::rightThumbRight;
                            break;
                        case Gamepad::Axis::rightThumbY:
                            axis.negativeButton = Gamepad::Button::rightThumbUp;
                            axis.positiveButton = Gamepad::Button::rightThumbDown;
                            break;
                        case Gamepad::Axis::leftTrigger:
                            axis.negativeButton = Gamepad::Button::leftTrigger;
                            axis.positiveButton = Gamepad::Button::leftTrigger;
                            hasLeftTrigger = true;
                            break;
                        case Gamepad::Axis::rightTrigger:
                            axis.negativeButton = Gamepad::Button::rightTrigger;
                            axis.positiveButton = Gamepad::Button::rightTrigger;
                            hasRightTrigger = true;
                            break;
                    }

                    axes.insert(std::pair(element, axis));
                }
            }
        }

        CFRelease(elementArray);

        IOHIDDeviceRegisterInputValueCallback(device, deviceInput, this);
    }

    void GamepadDeviceIOKit::handleInput(IOHIDValueRef value)
    {
        const auto element = IOHIDValueGetElement(value);
        const auto newValue = IOHIDValueGetIntegerValue(value);

        if (element == hatElement)
        {
            const auto oldHatValue = static_cast<std::uint32_t>(hatValue);
            const std::uint32_t oldBitmask = (oldHatValue >= 8) ? 0 : (1 << (oldHatValue / 2)) | // first bit
                (1 << (oldHatValue / 2 + oldHatValue % 2)) % 4; // second bit

            const std::uint32_t newBitmask = (newValue >= 8) ? 0 : (1 << (newValue / 2)) | // first bit
            (1 << (newValue / 2 + newValue % 2)) % 4; // second bit

            if ((oldBitmask & 0x01) != (newBitmask & 0x01))
                handleButtonValueChange(Gamepad::Button::dPadUp,
                                        (newBitmask & 0x01) > 0,
                                        (newBitmask & 0x01) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x02) != (newBitmask & 0x02))
                handleButtonValueChange(Gamepad::Button::dPadRight,
                                        (newBitmask & 0x02) > 0,
                                        (newBitmask & 0x02) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x04) != (newBitmask & 0x04))
                handleButtonValueChange(Gamepad::Button::dPadDown,
                                        (newBitmask & 0x04) > 0,
                                        (newBitmask & 0x04) > 0 ? 1.0F : 0.0F);
            if ((oldBitmask & 0x08) != (newBitmask & 0x08))
                handleButtonValueChange(Gamepad::Button::dPadLeft,
                                        (newBitmask & 0x08) > 0,
                                        (newBitmask & 0x08) > 0 ? 1.0F : 0.0F);

            hatValue = newValue;
        }

        const auto buttonIterator = buttons.find(element);

        if (buttonIterator != buttons.end())
        {
            Button& button = buttonIterator->second;

            if ((button.button != Gamepad::Button::leftTrigger || !hasLeftTrigger) &&
                (button.button != Gamepad::Button::rightTrigger || !hasRightTrigger))
                handleButtonValueChange(button.button, newValue > 0, (newValue > 0) ? 1.0F : 0.0F);

            button.value = newValue;
        }

        const auto axisIterator = axes.find(element);

        if (axisIterator != axes.end())
        {
            Axis& axis = axisIterator->second;

            handleAxisChange(axis.value,
                             newValue,
                             axis.min, axis.range,
                             axis.negativeButton, axis.positiveButton);

            axis.value = newValue;
        }
    }

    void GamepadDeviceIOKit::handleAxisChange(CFIndex oldValue, CFIndex newValue,
                                              CFIndex min, CFIndex range,
                                              Gamepad::Button negativeButton,
                                              Gamepad::Button positiveButton)
    {
        if (negativeButton == positiveButton)
        {
            const auto floatValue = static_cast<float>(newValue - min) / range;

            handleButtonValueChange(negativeButton,
                                    floatValue > 0.0F,
                                    floatValue);
        }
        else
        {
            const auto floatValue = 2.0F * static_cast<float>(newValue - min) / range - 1.0F;

            if (floatValue > 0.0F)
                handleButtonValueChange(positiveButton,
                                        floatValue > thumbDeadzone,
                                        floatValue);
            else if (floatValue < 0.0F)
                handleButtonValueChange(negativeButton,
                                        -floatValue > thumbDeadzone,
                                        -floatValue);
            else // thumbstick is 0
            {
                if (oldValue > newValue)
                    handleButtonValueChange(positiveButton, false, 0.0F);
                else
                    handleButtonValueChange(negativeButton, false, 0.0F);
            }
        }
    }
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "console/console.h"
#include "graphics/dgl.h"
#include "gui/guiCanvas.h"
#include "gui/buttons/guiRadioCtrl.h"
#include "console/consoleTypes.h"
#include "gui/guiDefaultControlRender.h"

//---------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiRadioCtrl);

GuiRadioCtrl::GuiRadioCtrl()
{
}

void GuiRadioCtrl::initPersistFields()
{
	Parent::initPersistFields();
	addField("groupNum", TypeS32, Offset(mRadioGroup, GuiRadioCtrl));
}

void GuiRadioCtrl::renderInnerControl(RectI &boxRect, const GuiControlState currentState)
{
	U8 stateIndex = currentState;

	if ((mProfile->mImageAsset->isAssetValid() && mProfile->mImageAsset->getFrameCount() > stateIndex)
		|| (mProfile->mBitmapName != NULL && mProfile->constructBitmapArray() > stateIndex))
	{
		renderUniversalRect(boxRect, mProfile, currentState);
	}
	else
	{
		S32 radius = boxRect.extent.x;
		if (boxRect.extent.y < radius)
		{
			radius = boxRect.extent.y;
		}
		radius = (S32)round(radius / 2);
		Point2I center = Point2I(boxRect.point.x + (boxRect.extent.x / 2), boxRect.point.y + (boxRect.extent.y / 2));
		renderBorderedCircle(center, radius, mProfile, currentState);
	}
}

void GuiRadioCtrl::onAction()
{
	if (!mActive)
		return;

	mStateOn = false;

	Parent::onAction();

	messageSiblings(mRadioGroup);
}

void GuiRadioCtrl::setStateOn(bool bStateOn)
{
	if (!mActive)
		return;

	mStateOn = true;
	messageSiblings(mRadioGroup);

	setUpdate();
}

void GuiRadioCtrl::onMessage(GuiControl *sender, S32 msg)
{
	Parent::onMessage(sender, msg);
	if (mRadioGroup == msg)
	{
		mStateOn = (sender == this);
		setUpdate();
	}
}<commit_msg>Fixed a Crash with GuiRadioCtrl<commit_after>//-----------------------------------------------------------------------------
// Copyright (c) 2013 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------

#include "console/console.h"
#include "graphics/dgl.h"
#include "gui/guiCanvas.h"
#include "gui/buttons/guiRadioCtrl.h"
#include "console/consoleTypes.h"
#include "gui/guiDefaultControlRender.h"

//---------------------------------------------------------------------------
IMPLEMENT_CONOBJECT(GuiRadioCtrl);

GuiRadioCtrl::GuiRadioCtrl()
{
}

void GuiRadioCtrl::initPersistFields()
{
	Parent::initPersistFields();
	addField("groupNum", TypeS32, Offset(mRadioGroup, GuiRadioCtrl));
}

void GuiRadioCtrl::renderInnerControl(RectI &boxRect, const GuiControlState currentState)
{
	U8 stateIndex = currentState;

	if ((mProfile->mImageAsset != NULL && mProfile->mImageAsset->isAssetValid() && mProfile->mImageAsset->getFrameCount() > stateIndex)
		|| (mProfile->mBitmapName != NULL && mProfile->constructBitmapArray() > stateIndex))
	{
		renderUniversalRect(boxRect, mProfile, currentState);
	}
	else
	{
		S32 radius = boxRect.extent.x;
		if (boxRect.extent.y < radius)
		{
			radius = boxRect.extent.y;
		}
		radius = (S32)round(radius / 2);
		Point2I center = Point2I(boxRect.point.x + (boxRect.extent.x / 2), boxRect.point.y + (boxRect.extent.y / 2));
		renderBorderedCircle(center, radius, mProfile, currentState);
	}
}

void GuiRadioCtrl::onAction()
{
	if (!mActive)
		return;

	mStateOn = false;

	Parent::onAction();

	messageSiblings(mRadioGroup);
}

void GuiRadioCtrl::setStateOn(bool bStateOn)
{
	if (!mActive)
		return;

	mStateOn = true;
	messageSiblings(mRadioGroup);

	setUpdate();
}

void GuiRadioCtrl::onMessage(GuiControl *sender, S32 msg)
{
	Parent::onMessage(sender, msg);
	if (mRadioGroup == msg)
	{
		mStateOn = (sender == this);
		setUpdate();
	}
}<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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

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

// This transformation forms clusters from instructions in same island and
// assigned to save devices. Clusters are represented as regions.
// Note that side-effecting ops are not correctly handled yet.

#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "mlir/IR/Attributes.h"  // TF:llvm-project
#include "mlir/IR/Block.h"  // TF:llvm-project
#include "mlir/IR/BlockAndValueMapping.h"  // TF:llvm-project
#include "mlir/IR/Builders.h"  // TF:llvm-project
#include "mlir/IR/Operation.h"  // TF:llvm-project
#include "mlir/Pass/Pass.h"  // TF:llvm-project
#include "mlir/Pass/PassRegistry.h"  // TF:llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_executor.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/core/platform/logging.h"

namespace mlir {
namespace TFDevice {

namespace {

struct ClusterFormationPass : public FunctionPass<ClusterFormationPass> {
  void runOnFunction() override;
};

// Cluster structure captures all the operations that are assigned to same
// device and can form a legal strict cluster.
// Ops must follow same ordering in their parent block. We rely on this
// assumption to perform analysis.
struct Cluster {
  llvm::SmallVector<Operation*, 4> ops;
  StringRef device;
};

StringRef GetDevice(Operation* op) {
  auto device_attr = op->getAttrOfType<StringAttr>("device");
  return device_attr ? device_attr.getValue() : "";
}

// An op can be merged into cluster if all of its operands are one of the
// following:
//  1) A block argument
//  2) A value produced by other islands
//  1) Defined before the cluster
//  2) Defined by an operation in the cluster
// TODO(ycao): This is not optimal as it doesn't consider the situation of
// defining_op's operands all meet the requirements above. In that case, the
// defining_op can be moved and to_merge op would be legal to absorb.
// TODO(ycao): Take op side-effects into consideration since they can not be
// re-ordered but forming clusters of non-continuous ops is effectively
// re-ordering them..
bool CanMergeIntoCluster(const Cluster& c, Operation* to_merge) {
  return llvm::all_of(to_merge->getOperands(), [&](Value operand) {
    // Block arguments.
    if (operand.isa<BlockArgument>()) return true;

    Operation* defining_op = operand.getDefiningOp();

    // Operand produced by other islands.
    if (defining_op->getBlock() != c.ops.front()->getBlock()) return true;

    // Defining op is before the cluster.
    if (defining_op->isBeforeInBlock(c.ops.front())) return true;

    // Defining op is between first and last operation in cluster. Note that
    // cluster may contain operations that are non-continuous in their original
    // block, thus we also need to check defining_op is also assigned to
    // cluster's device to be sure. This is a faster check than linearly
    // searching through all ops in cluster.
    if (defining_op->isBeforeInBlock(c.ops.back()->getNextNode()) &&
        GetDevice(defining_op) == c.device)
      return true;

    // Other cases, operand is generated after or outside the cluster, this
    // means it is illegal to merge operation.
    return false;
  });
}

void ReplaceLiveOutExternalUses(llvm::ArrayRef<Value> live_outs,
                                tf_device::LaunchOp launch_op) {
  Region* launch_op_region = &launch_op.body();
  for (const auto& p : llvm::zip(live_outs, launch_op.getResults())) {
    Value from = std::get<0>(p);
    for (auto& use : from.getUses()) {
      if (launch_op_region->isAncestor(use.getOwner()->getParentRegion()))
        continue;
      use.set(std::get<1>(p));
    }
  }
}

// Get all escaped live-out values of a region.
void GetLiveOuts(Region* region, llvm::SmallVectorImpl<Value>* live_outs) {
  live_outs->clear();

  for (Operation& op : region->front()) {
    for (Value v : op.getResults()) {
      // A value is live-out if any of its users are not inside value producer's
      // region.
      bool is_live_out = llvm::any_of(v.getUsers(), [&](Operation* user) {
        return !region->isAncestor(user->getParentRegion());
      });

      if (is_live_out) live_outs->emplace_back(v);
    }
  }
}

// Build a `tf_device.launch` op with a region that contains all the operations
// in given cluster. Then all ops in cluster are replaced by `tf_device.launch`.
void BuildLaunchForCluster(const Cluster& c, OpBuilder* builder) {
  // Set insertion point to right after all operations in cluster.
  builder->setInsertionPoint(c.ops.back()->getNextNode());

  // Create a stand-alone region to hold all instructions in the cluster.
  Region region;
  region.push_back(new Block);

  // Move all operations in cluster to newly created region, stripping their
  // "device" attribute since launch op already carries device information.
  Block* block = &region.front();
  for (Operation* op : c.ops) {
    op->moveBefore(block, block->end());
    op->removeAttr(builder->getIdentifier("device"));
  }

  // Get all escaped live-out values of region, they are used later to determine
  // return values and types of launch op.
  llvm::SmallVector<Value, 4> live_outs;
  GetLiveOuts(&region, &live_outs);

  // Build a `tf_device.return` op at end of region, with all live-out values
  // as operand.
  OpBuilder return_builder(builder->getContext());
  return_builder.setInsertionPointToEnd(block);
  return_builder.create<tf_device::ReturnOp>(return_builder.getUnknownLoc(),
                                             live_outs);

  llvm::SmallVector<Type, 4> live_out_types;
  live_out_types.reserve(live_outs.size());
  for (Value v : live_outs) {
    live_out_types.emplace_back(v.getType());
  }

  tf_device::LaunchOp launch_op = builder->create<tf_device::LaunchOp>(
      builder->getUnknownLoc(), builder->getStringAttr(c.device),
      live_out_types);

  // Attach the region to launch_op.
  launch_op.body().takeBody(region);

  // Replace any external uses of live-out values with return values of launch
  // op. So live-out values no longer escape the region.
  ReplaceLiveOutExternalUses(live_outs, launch_op);
}

void BuildClusters(Block* block, OpBuilder builder) {
  // Iteratively find clusters of different devices within an island.
  // Whenever we see an operation that is assigned to an accelerator device
  // (ie. device != ""), we try to merge it into the last cluster of same
  // device. If that is infeasible (say because of violating def-before-use),
  // create a new cluster with that operation and move on.
  llvm::MapVector<StringRef, Cluster> nearest_clusters;
  for (Operation& op : llvm::make_early_inc_range(*block)) {
    auto device = GetDevice(&op);
    if (device == "") continue;

    // If no cluster of same device has been formed yet, create a new cluster
    // with op alone.
    auto it = nearest_clusters.find(device);
    if (it == nearest_clusters.end()) {
      nearest_clusters[device] = Cluster{{&op}, device};
      continue;
    }

    // Check if it is legal to merge op into nearest cluster of same device.
    // If positive, update cluster and move on to next operation.
    Cluster& nearest_cluster = it->second;
    if (CanMergeIntoCluster(nearest_cluster, &op)) {
      nearest_cluster.ops.emplace_back(&op);
      continue;
    }

    // If nearest cluster of same device can not absorb `op`, then that
    // cluster needs to be finalized by building a `tf_device.launch` op with
    // a region that contains all operations in clusters.
    BuildLaunchForCluster(nearest_cluster, &builder);

    // Create a new cluster to hold op alone and update nearest_clusters.
    nearest_clusters[device] = Cluster{{&op}, device};
  }

  // At the end, there might be left-over found clusters that need to be
  // built.
  for (auto& device_cluster : nearest_clusters)
    BuildLaunchForCluster(device_cluster.second, &builder);
}

void ClusterFormationPass::runOnFunction() {
  OpBuilder builder(getFunction().getContext());

  // Operates on individual blocks independently of if they are directly in the
  // function body or if they are nested in individual `tf_executor.island`.
  for (Block& block : getFunction().getBody()) BuildClusters(&block, builder);
  getFunction().walk([&](tf_executor::IslandOp island) {
    BuildClusters(&island.GetBody(), builder);
  });
}

}  // namespace

std::unique_ptr<OpPassBase<FuncOp>> CreateClusterFormationPass() {
  return std::make_unique<ClusterFormationPass>();
}

static PassRegistration<ClusterFormationPass> pass(
    "tf-device-cluster-formation",
    "Form clusters from instructions assigned to same device");

}  // namespace TFDevice
}  // namespace mlir
<commit_msg>Fix a subtle bug where we unsafely modify the list while iterating it.<commit_after>/* Copyright 2019 The TensorFlow Authors. All Rights Reserved.

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

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

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

// This transformation forms clusters from instructions in same island and
// assigned to save devices. Clusters are represented as regions.
// Note that side-effecting ops are not correctly handled yet.

#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "mlir/IR/Attributes.h"  // TF:llvm-project
#include "mlir/IR/Block.h"  // TF:llvm-project
#include "mlir/IR/BlockAndValueMapping.h"  // TF:llvm-project
#include "mlir/IR/Builders.h"  // TF:llvm-project
#include "mlir/IR/Operation.h"  // TF:llvm-project
#include "mlir/Pass/Pass.h"  // TF:llvm-project
#include "mlir/Pass/PassRegistry.h"  // TF:llvm-project
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_device.h"
#include "tensorflow/compiler/mlir/tensorflow/ir/tf_executor.h"
#include "tensorflow/compiler/mlir/tensorflow/transforms/passes.h"
#include "tensorflow/core/platform/logging.h"

namespace mlir {
namespace TFDevice {

namespace {

struct ClusterFormationPass : public FunctionPass<ClusterFormationPass> {
  void runOnFunction() override;
};

// Cluster structure captures all the operations that are assigned to same
// device and can form a legal strict cluster.
// Ops must follow same ordering in their parent block. We rely on this
// assumption to perform analysis.
struct Cluster {
  llvm::SmallVector<Operation*, 4> ops;
  StringRef device;
};

StringRef GetDevice(Operation* op) {
  auto device_attr = op->getAttrOfType<StringAttr>("device");
  return device_attr ? device_attr.getValue() : "";
}

// An op can be merged into cluster if all of its operands are one of the
// following:
//  1) A block argument
//  2) A value produced by other islands
//  1) Defined before the cluster
//  2) Defined by an operation in the cluster
// TODO(ycao): This is not optimal as it doesn't consider the situation of
// defining_op's operands all meet the requirements above. In that case, the
// defining_op can be moved and to_merge op would be legal to absorb.
// TODO(ycao): Take op side-effects into consideration since they can not be
// re-ordered but forming clusters of non-continuous ops is effectively
// re-ordering them..
bool CanMergeIntoCluster(const Cluster& c, Operation* to_merge) {
  return llvm::all_of(to_merge->getOperands(), [&](Value operand) {
    // Block arguments.
    if (operand.isa<BlockArgument>()) return true;

    Operation* defining_op = operand.getDefiningOp();

    // Operand produced by other islands.
    if (defining_op->getBlock() != c.ops.front()->getBlock()) return true;

    // Defining op is before the cluster.
    if (defining_op->isBeforeInBlock(c.ops.front())) return true;

    // Defining op is between first and last operation in cluster. Note that
    // cluster may contain operations that are non-continuous in their original
    // block, thus we also need to check defining_op is also assigned to
    // cluster's device to be sure. This is a faster check than linearly
    // searching through all ops in cluster.
    if (defining_op->isBeforeInBlock(c.ops.back()->getNextNode()) &&
        GetDevice(defining_op) == c.device)
      return true;

    // Other cases, operand is generated after or outside the cluster, this
    // means it is illegal to merge operation.
    return false;
  });
}

void ReplaceLiveOutExternalUses(llvm::ArrayRef<Value> live_outs,
                                tf_device::LaunchOp launch_op) {
  Region* launch_op_region = &launch_op.body();
  for (const auto& p : llvm::zip(live_outs, launch_op.getResults())) {
    Value from = std::get<0>(p);
    // TODO(jingpu): move this to RegionUtils.h in MLIR core.
    for (auto& use : llvm::make_early_inc_range(from.getUses())) {
      if (launch_op_region->isAncestor(use.getOwner()->getParentRegion()))
        continue;
      use.set(std::get<1>(p));
    }
  }
}

// Get all escaped live-out values of a region.
void GetLiveOuts(Region* region, llvm::SmallVectorImpl<Value>* live_outs) {
  live_outs->clear();

  for (Operation& op : region->front()) {
    for (Value v : op.getResults()) {
      // A value is live-out if any of its users are not inside value producer's
      // region.
      bool is_live_out = llvm::any_of(v.getUsers(), [&](Operation* user) {
        return !region->isAncestor(user->getParentRegion());
      });

      if (is_live_out) live_outs->emplace_back(v);
    }
  }
}

// Build a `tf_device.launch` op with a region that contains all the operations
// in given cluster. Then all ops in cluster are replaced by `tf_device.launch`.
void BuildLaunchForCluster(const Cluster& c, OpBuilder* builder) {
  // Set insertion point to right after all operations in cluster.
  builder->setInsertionPoint(c.ops.back()->getNextNode());

  // Create a stand-alone region to hold all instructions in the cluster.
  Region region;
  region.push_back(new Block);

  // Move all operations in cluster to newly created region, stripping their
  // "device" attribute since launch op already carries device information.
  Block* block = &region.front();
  for (Operation* op : c.ops) {
    op->moveBefore(block, block->end());
    op->removeAttr(builder->getIdentifier("device"));
  }

  // Get all escaped live-out values of region, they are used later to determine
  // return values and types of launch op.
  llvm::SmallVector<Value, 4> live_outs;
  GetLiveOuts(&region, &live_outs);

  // Build a `tf_device.return` op at end of region, with all live-out values
  // as operand.
  OpBuilder return_builder(builder->getContext());
  return_builder.setInsertionPointToEnd(block);
  return_builder.create<tf_device::ReturnOp>(return_builder.getUnknownLoc(),
                                             live_outs);

  llvm::SmallVector<Type, 4> live_out_types;
  live_out_types.reserve(live_outs.size());
  for (Value v : live_outs) {
    live_out_types.emplace_back(v.getType());
  }

  tf_device::LaunchOp launch_op = builder->create<tf_device::LaunchOp>(
      builder->getUnknownLoc(), builder->getStringAttr(c.device),
      live_out_types);

  // Attach the region to launch_op.
  launch_op.body().takeBody(region);

  // Replace any external uses of live-out values with return values of launch
  // op. So live-out values no longer escape the region.
  ReplaceLiveOutExternalUses(live_outs, launch_op);
}

void BuildClusters(Block* block, OpBuilder builder) {
  // Iteratively find clusters of different devices within an island.
  // Whenever we see an operation that is assigned to an accelerator device
  // (ie. device != ""), we try to merge it into the last cluster of same
  // device. If that is infeasible (say because of violating def-before-use),
  // create a new cluster with that operation and move on.
  llvm::MapVector<StringRef, Cluster> nearest_clusters;
  for (Operation& op : llvm::make_early_inc_range(*block)) {
    auto device = GetDevice(&op);
    if (device == "") continue;

    // If no cluster of same device has been formed yet, create a new cluster
    // with op alone.
    auto it = nearest_clusters.find(device);
    if (it == nearest_clusters.end()) {
      nearest_clusters[device] = Cluster{{&op}, device};
      continue;
    }

    // Check if it is legal to merge op into nearest cluster of same device.
    // If positive, update cluster and move on to next operation.
    Cluster& nearest_cluster = it->second;
    if (CanMergeIntoCluster(nearest_cluster, &op)) {
      nearest_cluster.ops.emplace_back(&op);
      continue;
    }

    // If nearest cluster of same device can not absorb `op`, then that
    // cluster needs to be finalized by building a `tf_device.launch` op with
    // a region that contains all operations in clusters.
    BuildLaunchForCluster(nearest_cluster, &builder);

    // Create a new cluster to hold op alone and update nearest_clusters.
    nearest_clusters[device] = Cluster{{&op}, device};
  }

  // At the end, there might be left-over found clusters that need to be
  // built.
  for (auto& device_cluster : nearest_clusters)
    BuildLaunchForCluster(device_cluster.second, &builder);
}

void ClusterFormationPass::runOnFunction() {
  OpBuilder builder(getFunction().getContext());

  // Operates on individual blocks independently of if they are directly in the
  // function body or if they are nested in individual `tf_executor.island`.
  for (Block& block : getFunction().getBody()) BuildClusters(&block, builder);
  getFunction().walk([&](tf_executor::IslandOp island) {
    BuildClusters(&island.GetBody(), builder);
  });
}

}  // namespace

std::unique_ptr<OpPassBase<FuncOp>> CreateClusterFormationPass() {
  return std::make_unique<ClusterFormationPass>();
}

static PassRegistration<ClusterFormationPass> pass(
    "tf-device-cluster-formation",
    "Form clusters from instructions assigned to same device");

}  // namespace TFDevice
}  // namespace mlir
<|endoftext|>


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

YASK: Yet Another Stencil Kernel
Copyright (c) 2014-2018, Intel Corporation

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

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

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

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

// Base class for defining stencil equations.

#ifndef SOLN_HPP
#define SOLN_HPP

#include <map>
using namespace std;

namespace yask {

    typedef enum { STENCIL_CONTEXT } YASKSection;
    typedef vector<string> CodeList;
    typedef map<YASKSection, CodeList > ExtensionsList;

    class StencilSolution;
    class StencilBase;
    typedef map<string, StencilBase*> StencilList;

    // A base class for whole stencil solutions.  This is used by solutions
    // defined in C++ that are inherited from StencilBase as well as those
    // defined via the stencil-compiler API.
    class StencilSolution :
        public virtual yc_solution {
    protected:

        // Simple name for the stencil soln.
        string _name;

        // Debug output.
        yask_output_ptr _debug_output;
        ostream* _dos = &std::cout;

        // All vars accessible by the kernel.
        Grids _grids;       // keep track of all registered grids.

        // All equations defined in this solution.
        Eqs _eqs;

        // Settings for the solution.
        CompilerSettings _settings;

        // Code extensions that overload default functions from YASK in the
        // generated code for this solution.
        ExtensionsList _extensions;

    private:

        // Intermediate data needed to format output.
        Dimensions _dims;       // various dimensions.
        EqGroups _eqGroups;     // eq-groups for scalar and vector.
        EqGroups _clusterEqGroups; // eq-groups for scalar and vector.

        // Create the intermediate data.
        void analyze_solution(int vlen,
                              bool is_folding_efficient);

    public:
        StencilSolution(const string& name) :
            _name(name) {
            yask_output_factory ofac;
            set_debug_output(ofac.new_stdout_output());
        }
        virtual ~StencilSolution() {}

        // Identification.
        virtual const string& getName() const { return _name; }

        // Simple accessors.
        virtual Grids& getGrids() { return _grids; }
        virtual Eqs& getEqs() { return _eqs; }
        virtual CompilerSettings& getSettings() { return _settings; }

        // Get user-provided code for the given section.
        CodeList * getExtensionCode(YASKSection section)
        {
            auto elem = _extensions.find(section);
            if ( elem != _extensions.end() ) {
                return &elem->second;
            }
            return NULL;
        }

        // Define grid values relative to current domain indices in each dimension.
        // This must be implemented by each concrete stencil solution.
        virtual void define() = 0;

        // stencil_solution APIs.
        // See yask_stencil_api.hpp for documentation.
        virtual void set_debug_output(yask_output_ptr debug) {
            _debug_output = debug;     // to share ownership of referent.
            _dos = &_debug_output->get_ostream();
        }
        virtual void set_name(std::string name) {
            _name = name;
        }
        virtual const std::string& get_name() const {
            return _name;
        }

        virtual yc_grid_ptr new_grid(const std::string& name,
                                     const std::vector<yc_index_node_ptr>& dims);
        virtual yc_grid_ptr new_grid(const std::string& name,
                                     const std::initializer_list<yc_index_node_ptr>& dims) {
            std::vector<yc_index_node_ptr> dim_vec(dims);
            return new_grid(name, dim_vec);
        }
        virtual int get_num_grids() const {
            return int(_grids.size());
        }
        virtual yc_grid_ptr get_grid(const std::string& name) {
            for (int i = 0; i < get_num_grids(); i++)
                if (_grids.at(i)->getName() == name)
                    return _grids.at(i);
            return nullptr;
        }
        virtual std::vector<yc_grid_ptr> get_grids() {
            std::vector<yc_grid_ptr> gv;
            for (int i = 0; i < get_num_grids(); i++)
                gv.push_back(_grids.at(i));
            return gv;
        }

        virtual int get_num_equations() const {
            return _eqs.getNumEqs();
        }
        virtual yc_equation_node_ptr get_equation(int n) {
            assert(n >= 0 && n < get_num_equations());
            return _eqs.getEqs().at(n);
        }
        virtual void set_fold(const std::string& dim, int len) {
            auto& fold = _settings._foldOptions;
            auto* p = fold.lookup(dim);
            if (p)
                *p = len;
            else
                fold.addDimBack(dim, len);
        }
        virtual void set_fold_len(const yc_index_node_ptr, int len);
        virtual void clear_folding() { _settings._foldOptions.clear(); }
        virtual void set_cluster_mult(const yc_index_node_ptr, int mult);
        virtual void clear_clustering() { _settings._clusterOptions.clear(); }
        virtual void set_element_bytes(int nbytes) { _settings._elem_bytes = nbytes; }
        virtual int get_element_bytes() const { return _settings._elem_bytes; }
        virtual void format(const std::string& format_type,
                            yask_output_ptr output) ;
    };

    // A stencil solution that does not define any grids.
    // This is used by a program via the compiler API to add grids
    // programmatically.
    class EmptyStencil : public StencilSolution {

        // Do not define any dims.
        // Do not define any grids.

    public:
        EmptyStencil(std::string name) :
            StencilSolution(name) { }

        // Do not define any equations.
        virtual void define() { }
    };

    // An interface for all objects that participate in stencil definitions.
    // This allows a programmer to use object composition in addition to
    // inheritance from StencilBase to define stencils.
    class StencilPart {

    public:
        StencilPart() {}
        virtual ~StencilPart() {}

        // Return a reference to the main stencil object.
        virtual StencilSolution& get_stencil_solution() =0;
    };

    // The class all C++ stencil solutions must implement.
    class StencilBase : public StencilSolution,
                        public StencilPart {

    public:
        // Initialize name and register this new object in a list.
        StencilBase(const string name, StencilList& stencils) :
            StencilSolution(name)
        {
            stencils[name] = this;
        }
        virtual ~StencilBase() { }

        // Return a reference to the main stencil-solution object.
        // For StencilBase, simply this object.
        virtual StencilSolution& get_stencil_solution() {
            return *this;
        }

        // Radius stub methods.
        virtual bool usesRadius() const { return false; }
        virtual bool setRadius(int radius) { return false; }
        virtual int getRadius() const { return 0; }

    };

    // A base class for stencils that have a 'radius'.
    class StencilRadiusBase : public StencilBase {
    protected:
        int _radius;         // stencil radius.

    public:
        StencilRadiusBase(const string name, StencilList& stencils, int radius) :
            StencilBase(name, stencils), _radius(radius) {}

        // Does use radius.
        virtual bool usesRadius() const { return true; }

        // Set radius.
        // Return true if successful.
        virtual bool setRadius(int radius) {
            _radius = radius;
            return radius >= 0;  // support only non-neg. radius.
        }

        // Get radius.
        virtual int getRadius() { return _radius; }
    };

} // namespace yask.

// Convenience macro for registering a stencil in a list.
#define REGISTER_STENCIL(Class) static Class registered_ ## Class(stencils)

// Convenience macros for adding 'extension' code to a stencil.
#define REGISTER_CODE_EXTENSION(section, code) _extensions[section].push_back(code);
#define REGISTER_STENCIL_CONTEXT_EXTENSION(...) REGISTER_CODE_EXTENSION(STENCIL_CONTEXT, #__VA_ARGS__)

// Convenience macro for declaring dims.
#define MAKE_STEP_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, STEP_INDEX);
#define MAKE_DOMAIN_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, DOMAIN_INDEX);
#define MAKE_MISC_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, MISC_INDEX);

// Convenience macros for creating grids in a class implementing StencilPart.
// The 'gvar' arg is the var name and the grid name.
// The remaining args are the dimension names.
#define MAKE_GRID(gvar, ...)                                            \
    Grid gvar = Grid(#gvar, &get_stencil_solution(), ##__VA_ARGS__)
#define MAKE_SCALAR(gvar) MAKE_GRID(gvar)
#define MAKE_ARRAY(gvar, d1) MAKE_GRID(gvar, d1)

#endif
<commit_msg>Remove gratuitous added space.<commit_after>/*****************************************************************************

YASK: Yet Another Stencil Kernel
Copyright (c) 2014-2018, Intel Corporation

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

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

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

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

// Base class for defining stencil equations.

#ifndef SOLN_HPP
#define SOLN_HPP

#include <map>
using namespace std;

namespace yask {

    typedef enum { STENCIL_CONTEXT } YASKSection;
    typedef vector<string> CodeList;
    typedef map<YASKSection, CodeList > ExtensionsList;

    class StencilSolution;
    class StencilBase;
    typedef map<string, StencilBase*> StencilList;

    // A base class for whole stencil solutions.  This is used by solutions
    // defined in C++ that are inherited from StencilBase as well as those
    // defined via the stencil-compiler API.
    class StencilSolution :
        public virtual yc_solution {
    protected:

        // Simple name for the stencil soln.
        string _name;

        // Debug output.
        yask_output_ptr _debug_output;
        ostream* _dos = &std::cout;

        // All vars accessible by the kernel.
        Grids _grids;       // keep track of all registered grids.

        // All equations defined in this solution.
        Eqs _eqs;

        // Settings for the solution.
        CompilerSettings _settings;

        // Code extensions that overload default functions from YASK in the
        // generated code for this solution.
        ExtensionsList _extensions;

    private:

        // Intermediate data needed to format output.
        Dimensions _dims;       // various dimensions.
        EqGroups _eqGroups;     // eq-groups for scalar and vector.
        EqGroups _clusterEqGroups; // eq-groups for scalar and vector.

        // Create the intermediate data.
        void analyze_solution(int vlen,
                              bool is_folding_efficient);

    public:
        StencilSolution(const string& name) :
            _name(name) {
            yask_output_factory ofac;
            set_debug_output(ofac.new_stdout_output());
        }
        virtual ~StencilSolution() {}

        // Identification.
        virtual const string& getName() const { return _name; }

        // Simple accessors.
        virtual Grids& getGrids() { return _grids; }
        virtual Eqs& getEqs() { return _eqs; }
        virtual CompilerSettings& getSettings() { return _settings; }

        // Get user-provided code for the given section.
        CodeList * getExtensionCode(YASKSection section)
        {
            auto elem = _extensions.find(section);
            if ( elem != _extensions.end() ) {
                return &elem->second;
            }
            return NULL;
        }

        // Define grid values relative to current domain indices in each dimension.
        // This must be implemented by each concrete stencil solution.
        virtual void define() = 0;

        // stencil_solution APIs.
        // See yask_stencil_api.hpp for documentation.
        virtual void set_debug_output(yask_output_ptr debug) {
            _debug_output = debug;     // to share ownership of referent.
            _dos = &_debug_output->get_ostream();
        }
        virtual void set_name(std::string name) {
            _name = name;
        }
        virtual const std::string& get_name() const {
            return _name;
        }

        virtual yc_grid_ptr new_grid(const std::string& name,
                                     const std::vector<yc_index_node_ptr>& dims);
        virtual yc_grid_ptr new_grid(const std::string& name,
                                     const std::initializer_list<yc_index_node_ptr>& dims) {
            std::vector<yc_index_node_ptr> dim_vec(dims);
            return new_grid(name, dim_vec);
        }
        virtual int get_num_grids() const {
            return int(_grids.size());
        }
        virtual yc_grid_ptr get_grid(const std::string& name) {
            for (int i = 0; i < get_num_grids(); i++)
                if (_grids.at(i)->getName() == name)
                    return _grids.at(i);
            return nullptr;
        }
        virtual std::vector<yc_grid_ptr> get_grids() {
            std::vector<yc_grid_ptr> gv;
            for (int i = 0; i < get_num_grids(); i++)
                gv.push_back(_grids.at(i));
            return gv;
        }

        virtual int get_num_equations() const {
            return _eqs.getNumEqs();
        }
        virtual yc_equation_node_ptr get_equation(int n) {
            assert(n >= 0 && n < get_num_equations());
            return _eqs.getEqs().at(n);
        }
        virtual void set_fold(const std::string& dim, int len) {
            auto& fold = _settings._foldOptions;
            auto* p = fold.lookup(dim);
            if (p)
                *p = len;
            else
                fold.addDimBack(dim, len);
        }
        virtual void set_fold_len(const yc_index_node_ptr, int len);
        virtual void clear_folding() { _settings._foldOptions.clear(); }
        virtual void set_cluster_mult(const yc_index_node_ptr, int mult);
        virtual void clear_clustering() { _settings._clusterOptions.clear(); }
        virtual void set_element_bytes(int nbytes) { _settings._elem_bytes = nbytes; }
        virtual int get_element_bytes() const { return _settings._elem_bytes; }
        virtual void format(const std::string& format_type,
                            yask_output_ptr output);
    };

    // A stencil solution that does not define any grids.
    // This is used by a program via the compiler API to add grids
    // programmatically.
    class EmptyStencil : public StencilSolution {

        // Do not define any dims.
        // Do not define any grids.

    public:
        EmptyStencil(std::string name) :
            StencilSolution(name) { }

        // Do not define any equations.
        virtual void define() { }
    };

    // An interface for all objects that participate in stencil definitions.
    // This allows a programmer to use object composition in addition to
    // inheritance from StencilBase to define stencils.
    class StencilPart {

    public:
        StencilPart() {}
        virtual ~StencilPart() {}

        // Return a reference to the main stencil object.
        virtual StencilSolution& get_stencil_solution() =0;
    };

    // The class all C++ stencil solutions must implement.
    class StencilBase : public StencilSolution,
                        public StencilPart {

    public:
        // Initialize name and register this new object in a list.
        StencilBase(const string name, StencilList& stencils) :
            StencilSolution(name)
        {
            stencils[name] = this;
        }
        virtual ~StencilBase() { }

        // Return a reference to the main stencil-solution object.
        // For StencilBase, simply this object.
        virtual StencilSolution& get_stencil_solution() {
            return *this;
        }

        // Radius stub methods.
        virtual bool usesRadius() const { return false; }
        virtual bool setRadius(int radius) { return false; }
        virtual int getRadius() const { return 0; }

    };

    // A base class for stencils that have a 'radius'.
    class StencilRadiusBase : public StencilBase {
    protected:
        int _radius;         // stencil radius.

    public:
        StencilRadiusBase(const string name, StencilList& stencils, int radius) :
            StencilBase(name, stencils), _radius(radius) {}

        // Does use radius.
        virtual bool usesRadius() const { return true; }

        // Set radius.
        // Return true if successful.
        virtual bool setRadius(int radius) {
            _radius = radius;
            return radius >= 0;  // support only non-neg. radius.
        }

        // Get radius.
        virtual int getRadius() { return _radius; }
    };

} // namespace yask.

// Convenience macro for registering a stencil in a list.
#define REGISTER_STENCIL(Class) static Class registered_ ## Class(stencils)

// Convenience macros for adding 'extension' code to a stencil.
#define REGISTER_CODE_EXTENSION(section, code) _extensions[section].push_back(code);
#define REGISTER_STENCIL_CONTEXT_EXTENSION(...) REGISTER_CODE_EXTENSION(STENCIL_CONTEXT, #__VA_ARGS__)

// Convenience macro for declaring dims.
#define MAKE_STEP_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, STEP_INDEX);
#define MAKE_DOMAIN_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, DOMAIN_INDEX);
#define MAKE_MISC_INDEX(d) IndexExprPtr d = make_shared<IndexExpr>(#d, MISC_INDEX);

// Convenience macros for creating grids in a class implementing StencilPart.
// The 'gvar' arg is the var name and the grid name.
// The remaining args are the dimension names.
#define MAKE_GRID(gvar, ...)                                            \
    Grid gvar = Grid(#gvar, &get_stencil_solution(), ##__VA_ARGS__)
#define MAKE_SCALAR(gvar) MAKE_GRID(gvar)
#define MAKE_ARRAY(gvar, d1) MAKE_GRID(gvar, d1)

#endif
<|endoftext|>