<commit_before>/** Implementation of string conversions.
 *
 * Copyright (c) 2008-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#include "pqxx/compiler-internal.hxx"

#include <cmath>
#include <cstring>
#include <limits>
#include <locale>

#include "pqxx/except"
#include "pqxx/strconv"

using namespace pqxx::internal;

namespace
{

template<typename T> inline void set_to_Inf(T &t, int sign=1)
{
  T value = std::numeric_limits<T>::infinity();
  if (sign < 0) value = -value;
  t = value;
}

[[noreturn]] void report_overflow()
{
  throw pqxx::failure{
	"Could not convert string to integer: value out of range."};
}

/** Helper to check for underflow before multiplying a number by 10.
 *
 * Needed just so the compiler doesn't get to complain about an "if (n < 0)"
 * clause that's pointless for unsigned numbers.
 */
template<typename T, bool is_signed> struct underflow_check;

/* Specialization for signed types: check.
 */
template<typename T> struct underflow_check<T, true>
{
  static void check_before_adding_digit(T n)
  {
    constexpr T ten{10};
    if (n < 0 and (std::numeric_limits<T>::min() / ten) > n) report_overflow();
  }
};

/* Specialization for unsigned types: no check needed becaue negative
 * numbers don't exist.
 */
template<typename T> struct underflow_check<T, false>
{
  static void check_before_adding_digit(T) {}
};

/// Return 10*n, or throw exception if it overflows.
template<typename T> T safe_multiply_by_ten(T n)
{
  using limits = std::numeric_limits<T>;
  constexpr T ten{10};
  if (n > 0 and (limits::max() / n) < ten) report_overflow();
  underflow_check<T, limits::is_signed>::check_before_adding_digit(n);
  return T(n * ten);
}

/// Add a digit d to n, or throw exception if it overflows.
template<typename T> T safe_add_digit(T n, T d)
{
  assert((n >= 0 and d >= 0) or (n <=0 and d <= 0));
  if ((n > 0) and (n > (std::numeric_limits<T>::max() - d))) report_overflow();
  if ((n < 0) and (n < (std::numeric_limits<T>::min() - d))) report_overflow();
  return n + d;
}

/// For use in string parsing: add new numeric digit to intermediate value
template<typename L, typename R>
  inline L absorb_digit(L value, R digit)
{
  return L(safe_multiply_by_ten(value) + L(digit));
}

template<typename T> void from_string_signed(const char Str[], T &Obj)
{
  int i = 0;
  T result = 0;

  if (not isdigit(Str[i]))
  {
    if (Str[i] != '-')
      throw pqxx::failure{
        "Could not convert string to integer: '" + std::string{Str} + "'."};

    for (++i; isdigit(Str[i]); ++i)
      result = absorb_digit(result, -digit_to_number(Str[i]));
  }
  else
  {
    for (; isdigit(Str[i]); ++i)
      result = absorb_digit(result, digit_to_number(Str[i]));
  }

  if (Str[i])
    throw pqxx::failure{
      "Unexpected text after integer: '" + std::string{Str} + "'."};

  Obj = result;
}

template<typename T> void from_string_unsigned(const char Str[], T &Obj)
{
  int i = 0;
  T result = 0;

  if (not isdigit(Str[i]))
    throw pqxx::failure{
      "Could not convert string to unsigned integer: '" +
      std::string{Str} + "'."};

  for (; isdigit(Str[i]); ++i)
    result = absorb_digit(result, digit_to_number(Str[i]));

  if (Str[i])
    throw pqxx::failure{
      "Unexpected text after integer: '" + std::string{Str} + "'."};

  Obj = result;
}

namespace
{
/// C string comparison.
inline bool equal(const char lhs[], const char rhs[])
{
  return strcmp(lhs, rhs) == 0;
}
} // namespace

bool valid_infinity_string(const char str[]) noexcept
{
  return
	equal("infinity", str) or
	equal("Infinity", str) or
	equal("INFINITY", str) or
	equal("inf", str);
}

/// Wrapper for std::stringstream with C locale.
/** Some of our string conversions use the standard library.  But, they must
 * _not_ obey the system's locale settings, or a value like 1000.0 might end
 * up looking like "1.000,0".
 *
 * Initialising the stream (including locale and tweaked precision) seems to
 * be expensive though.  So, create thread-local instances which we re-use.
 * It's a lockless way of keeping global variables thread-safe, basically.
 *
 * The stream initialisation happens once per thread, in the constructor.
 * And that's why we need to wrap this in a class.  We can't just do it at the
 * call site, or we'd still be doing it for every call.
 */
template<typename T> class dumb_stringstream : public std::stringstream
{
public:
  dumb_stringstream() : std::stringstream()
  {
    this->imbue(std::locale::classic());

    // Kirit reports getting two more digits of precision than
    // numeric_limits::digits10 would give him, so we try not to make him lose
    // those last few bits.
    this->precision(std::numeric_limits<T>::digits10 + 2);
  }
};

/* These are hard.  Sacrifice performance of specialized, nonflexible,
 * non-localized code and lean on standard library.  Some special-case code
 * handles NaNs.
 */
template<typename T> inline void from_string_float(const char Str[], T &Obj)
{
  bool ok = false;
  T result;

  switch (Str[0])
  {
  case 'N':
  case 'n':
    // Accept "NaN," "nan," etc.
    ok = (
      (Str[1]=='A' or Str[1]=='a') and
      (Str[2]=='N' or Str[2]=='n') and
      (Str[3] == '\0'));
    result = std::numeric_limits<T>::quiet_NaN();
    break;

  case 'I':
  case 'i':
    ok = valid_infinity_string(Str);
    set_to_Inf(result);
    break;

  default:
    if (Str[0] == '-' and valid_infinity_string(&Str[1]))
    {
      ok = true;
      set_to_Inf(result, -1);
    }
    else
    {
      thread_local dumb_stringstream<T> S;
      // Visual Studio 2017 seems to fail on repeated conversions if the
      // clear() is done before the seekg().  Still don't know why!  See #124
      // and #125.
      S.seekg(0);
      S.clear();
      S.str(Str);
      ok = static_cast<bool>(S >> result);
    }
    break;
  }

  if (not ok)
    throw pqxx::failure{
      "Could not convert string to numeric value: '" +
      std::string{Str} + "'."};

  Obj = result;
}

template<typename T> inline std::string to_string_unsigned(T Obj)
{
  if (not Obj) return "0";

  // Every byte of width on T adds somewhere between 3 and 4 digits to the
  // maximum length of our decimal string.
  char buf[4*sizeof(T)+1];

  char *p = &buf[sizeof(buf)];
  *--p = '\0';
  while (Obj > 0)
  {
    *--p = number_to_digit(int(Obj%10));
    Obj /= 10;
  }
  return p;
}

template<typename T> inline std::string to_string_fallback(T Obj)
{
  thread_local dumb_stringstream<T> S;
  S.str("");
  S << Obj;
  return S.str();
}

template<typename T> inline std::string to_string_float(T Obj)
{
  if (std::isnan(Obj)) return "nan";
  if (std::isinf(Obj)) return Obj > 0 ? "infinity" : "-infinity";
  return to_string_fallback(Obj);
}

template<typename T> inline std::string to_string_signed(T Obj)
{
  if (Obj < 0)
  {
    // Remember--the smallest negative number for a given two's-complement type
    // cannot be negated.
    const bool negatable = (Obj != std::numeric_limits<T>::min());
    if (negatable)
      return '-' + to_string_unsigned(-Obj);
    else
      return to_string_fallback(Obj);
  }

  return to_string_unsigned(Obj);
}

} // namespace

namespace pqxx
{

namespace internal
{
void throw_null_conversion(const std::string &type)
{
  throw conversion_error{"Attempt to convert null to " + type + "."};
}
} // namespace pqxx::internal

void string_traits<bool>::from_string(const char Str[], bool &Obj)
{
  bool OK, result=false;

  switch (Str[0])
  {
  case 0:
    result = false;
    OK = true;
    break;

  case 'f':
  case 'F':
    result = false;
    OK = not (
	(Str[1] != '\0') and
	(not equal(Str+1, "alse")) and
	(not equal(Str+1, "ALSE")));
    break;

  case '0':
    {
      int I;
      string_traits<int>::from_string(Str, I);
      result = (I != 0);
      OK = ((I == 0) or (I == 1));
    }
    break;

  case '1':
    result = true;
    OK = (Str[1] != '\0');
    break;

  case 't':
  case 'T':
    result = true;
    OK = not (
	(Str[1] != '\0') and
	(not equal(Str+1, "rue")) and
	(not equal(Str+1, "RUE")));
    break;

  default:
    OK = false;
  }

  if (not OK)
    throw argument_error{
      "Failed conversion to bool: '" + std::string{Str} + "'."};

  Obj = result;
}

std::string string_traits<bool>::to_string(bool Obj)
{
  return Obj ? "true" : "false";
}

void string_traits<short>::from_string(const char Str[], short &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<short>::to_string(short Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned short>::from_string(
	const char Str[],
	unsigned short &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned short>::to_string(unsigned short Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<int>::from_string(const char Str[], int &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<int>::to_string(int Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned int>::from_string(
	const char Str[],
	unsigned int &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned int>::to_string(unsigned int Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<long>::from_string(const char Str[], long &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<long>::to_string(long Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned long>::from_string(
	const char Str[],
	unsigned long &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned long>::to_string(unsigned long Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<long long>::from_string(const char Str[], long long &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<long long>::to_string(long long Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned long long>::from_string(
	const char Str[],
	unsigned long long &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned long long>::to_string(
        unsigned long long Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<float>::from_string(const char Str[], float &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<float>::to_string(float Obj)
{
  return to_string_float(Obj);
}

void string_traits<double>::from_string(const char Str[], double &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<double>::to_string(double Obj)
{
  return to_string_float(Obj);
}

void string_traits<long double>::from_string(const char Str[], long double &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<long double>::to_string(long double Obj)
{
  return to_string_float(Obj);
}

} // namespace pqxx
<commit_msg>Remove problematic initialiser altogether.<commit_after>/** Implementation of string conversions.
 *
 * Copyright (c) 2008-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#include "pqxx/compiler-internal.hxx"

#include <cmath>
#include <cstring>
#include <limits>
#include <locale>

#include "pqxx/except"
#include "pqxx/strconv"

using namespace pqxx::internal;

namespace
{

template<typename T> inline void set_to_Inf(T &t, int sign=1)
{
  T value = std::numeric_limits<T>::infinity();
  if (sign < 0) value = -value;
  t = value;
}

[[noreturn]] void report_overflow()
{
  throw pqxx::failure{
	"Could not convert string to integer: value out of range."};
}

/** Helper to check for underflow before multiplying a number by 10.
 *
 * Needed just so the compiler doesn't get to complain about an "if (n < 0)"
 * clause that's pointless for unsigned numbers.
 */
template<typename T, bool is_signed> struct underflow_check;

/* Specialization for signed types: check.
 */
template<typename T> struct underflow_check<T, true>
{
  static void check_before_adding_digit(T n)
  {
    constexpr T ten{10};
    if (n < 0 and (std::numeric_limits<T>::min() / ten) > n) report_overflow();
  }
};

/* Specialization for unsigned types: no check needed becaue negative
 * numbers don't exist.
 */
template<typename T> struct underflow_check<T, false>
{
  static void check_before_adding_digit(T) {}
};

/// Return 10*n, or throw exception if it overflows.
template<typename T> T safe_multiply_by_ten(T n)
{
  using limits = std::numeric_limits<T>;
  constexpr T ten{10};
  if (n > 0 and (limits::max() / n) < ten) report_overflow();
  underflow_check<T, limits::is_signed>::check_before_adding_digit(n);
  return T(n * ten);
}

/// Add a digit d to n, or throw exception if it overflows.
template<typename T> T safe_add_digit(T n, T d)
{
  assert((n >= 0 and d >= 0) or (n <=0 and d <= 0));
  if ((n > 0) and (n > (std::numeric_limits<T>::max() - d))) report_overflow();
  if ((n < 0) and (n < (std::numeric_limits<T>::min() - d))) report_overflow();
  return n + d;
}

/// For use in string parsing: add new numeric digit to intermediate value
template<typename L, typename R>
  inline L absorb_digit(L value, R digit)
{
  return L(safe_multiply_by_ten(value) + L(digit));
}

template<typename T> void from_string_signed(const char Str[], T &Obj)
{
  int i = 0;
  T result = 0;

  if (not isdigit(Str[i]))
  {
    if (Str[i] != '-')
      throw pqxx::failure{
        "Could not convert string to integer: '" + std::string{Str} + "'."};

    for (++i; isdigit(Str[i]); ++i)
      result = absorb_digit(result, -digit_to_number(Str[i]));
  }
  else
  {
    for (; isdigit(Str[i]); ++i)
      result = absorb_digit(result, digit_to_number(Str[i]));
  }

  if (Str[i])
    throw pqxx::failure{
      "Unexpected text after integer: '" + std::string{Str} + "'."};

  Obj = result;
}

template<typename T> void from_string_unsigned(const char Str[], T &Obj)
{
  int i = 0;
  T result = 0;

  if (not isdigit(Str[i]))
    throw pqxx::failure{
      "Could not convert string to unsigned integer: '" +
      std::string{Str} + "'."};

  for (; isdigit(Str[i]); ++i)
    result = absorb_digit(result, digit_to_number(Str[i]));

  if (Str[i])
    throw pqxx::failure{
      "Unexpected text after integer: '" + std::string{Str} + "'."};

  Obj = result;
}

namespace
{
/// C string comparison.
inline bool equal(const char lhs[], const char rhs[])
{
  return strcmp(lhs, rhs) == 0;
}
} // namespace

bool valid_infinity_string(const char str[]) noexcept
{
  return
	equal("infinity", str) or
	equal("Infinity", str) or
	equal("INFINITY", str) or
	equal("inf", str);
}

/// Wrapper for std::stringstream with C locale.
/** Some of our string conversions use the standard library.  But, they must
 * _not_ obey the system's locale settings, or a value like 1000.0 might end
 * up looking like "1.000,0".
 *
 * Initialising the stream (including locale and tweaked precision) seems to
 * be expensive though.  So, create thread-local instances which we re-use.
 * It's a lockless way of keeping global variables thread-safe, basically.
 *
 * The stream initialisation happens once per thread, in the constructor.
 * And that's why we need to wrap this in a class.  We can't just do it at the
 * call site, or we'd still be doing it for every call.
 */
template<typename T> class dumb_stringstream : public std::stringstream
{
public:
  // Do not initialise the base-class object using "stringstream{}" (with curly
  // braces): that breaks on Visual C++.  The classic "stringstream()" syntax
  // (with parentheses) does work.
  dumb_stringstream()
  {
    this->imbue(std::locale::classic());

    // Kirit reports getting two more digits of precision than
    // numeric_limits::digits10 would give him, so we try not to make him lose
    // those last few bits.
    this->precision(std::numeric_limits<T>::digits10 + 2);
  }
};

/* These are hard.  Sacrifice performance of specialized, nonflexible,
 * non-localized code and lean on standard library.  Some special-case code
 * handles NaNs.
 */
template<typename T> inline void from_string_float(const char Str[], T &Obj)
{
  bool ok = false;
  T result;

  switch (Str[0])
  {
  case 'N':
  case 'n':
    // Accept "NaN," "nan," etc.
    ok = (
      (Str[1]=='A' or Str[1]=='a') and
      (Str[2]=='N' or Str[2]=='n') and
      (Str[3] == '\0'));
    result = std::numeric_limits<T>::quiet_NaN();
    break;

  case 'I':
  case 'i':
    ok = valid_infinity_string(Str);
    set_to_Inf(result);
    break;

  default:
    if (Str[0] == '-' and valid_infinity_string(&Str[1]))
    {
      ok = true;
      set_to_Inf(result, -1);
    }
    else
    {
      thread_local dumb_stringstream<T> S;
      // Visual Studio 2017 seems to fail on repeated conversions if the
      // clear() is done before the seekg().  Still don't know why!  See #124
      // and #125.
      S.seekg(0);
      S.clear();
      S.str(Str);
      ok = static_cast<bool>(S >> result);
    }
    break;
  }

  if (not ok)
    throw pqxx::failure{
      "Could not convert string to numeric value: '" +
      std::string{Str} + "'."};

  Obj = result;
}

template<typename T> inline std::string to_string_unsigned(T Obj)
{
  if (not Obj) return "0";

  // Every byte of width on T adds somewhere between 3 and 4 digits to the
  // maximum length of our decimal string.
  char buf[4*sizeof(T)+1];

  char *p = &buf[sizeof(buf)];
  *--p = '\0';
  while (Obj > 0)
  {
    *--p = number_to_digit(int(Obj%10));
    Obj /= 10;
  }
  return p;
}

template<typename T> inline std::string to_string_fallback(T Obj)
{
  thread_local dumb_stringstream<T> S;
  S.str("");
  S << Obj;
  return S.str();
}

template<typename T> inline std::string to_string_float(T Obj)
{
  if (std::isnan(Obj)) return "nan";
  if (std::isinf(Obj)) return Obj > 0 ? "infinity" : "-infinity";
  return to_string_fallback(Obj);
}

template<typename T> inline std::string to_string_signed(T Obj)
{
  if (Obj < 0)
  {
    // Remember--the smallest negative number for a given two's-complement type
    // cannot be negated.
    const bool negatable = (Obj != std::numeric_limits<T>::min());
    if (negatable)
      return '-' + to_string_unsigned(-Obj);
    else
      return to_string_fallback(Obj);
  }

  return to_string_unsigned(Obj);
}

} // namespace

namespace pqxx
{

namespace internal
{
void throw_null_conversion(const std::string &type)
{
  throw conversion_error{"Attempt to convert null to " + type + "."};
}
} // namespace pqxx::internal

void string_traits<bool>::from_string(const char Str[], bool &Obj)
{
  bool OK, result=false;

  switch (Str[0])
  {
  case 0:
    result = false;
    OK = true;
    break;

  case 'f':
  case 'F':
    result = false;
    OK = not (
	(Str[1] != '\0') and
	(not equal(Str+1, "alse")) and
	(not equal(Str+1, "ALSE")));
    break;

  case '0':
    {
      int I;
      string_traits<int>::from_string(Str, I);
      result = (I != 0);
      OK = ((I == 0) or (I == 1));
    }
    break;

  case '1':
    result = true;
    OK = (Str[1] != '\0');
    break;

  case 't':
  case 'T':
    result = true;
    OK = not (
	(Str[1] != '\0') and
	(not equal(Str+1, "rue")) and
	(not equal(Str+1, "RUE")));
    break;

  default:
    OK = false;
  }

  if (not OK)
    throw argument_error{
      "Failed conversion to bool: '" + std::string{Str} + "'."};

  Obj = result;
}

std::string string_traits<bool>::to_string(bool Obj)
{
  return Obj ? "true" : "false";
}

void string_traits<short>::from_string(const char Str[], short &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<short>::to_string(short Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned short>::from_string(
	const char Str[],
	unsigned short &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned short>::to_string(unsigned short Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<int>::from_string(const char Str[], int &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<int>::to_string(int Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned int>::from_string(
	const char Str[],
	unsigned int &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned int>::to_string(unsigned int Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<long>::from_string(const char Str[], long &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<long>::to_string(long Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned long>::from_string(
	const char Str[],
	unsigned long &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned long>::to_string(unsigned long Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<long long>::from_string(const char Str[], long long &Obj)
{
  from_string_signed(Str, Obj);
}

std::string string_traits<long long>::to_string(long long Obj)
{
  return to_string_signed(Obj);
}

void string_traits<unsigned long long>::from_string(
	const char Str[],
	unsigned long long &Obj)
{
  from_string_unsigned(Str, Obj);
}

std::string string_traits<unsigned long long>::to_string(
        unsigned long long Obj)
{
  return to_string_unsigned(Obj);
}

void string_traits<float>::from_string(const char Str[], float &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<float>::to_string(float Obj)
{
  return to_string_float(Obj);
}

void string_traits<double>::from_string(const char Str[], double &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<double>::to_string(double Obj)
{
  return to_string_float(Obj);
}

void string_traits<long double>::from_string(const char Str[], long double &Obj)
{
  from_string_float(Str, Obj);
}

std::string string_traits<long double>::to_string(long double Obj)
{
  return to_string_float(Obj);
}

} // namespace pqxx
<|endoftext|>


<commit_before>#include "nil.h"
#include "nilUtil.h"
#include "nilLogitech.h"

namespace Nil {

  System::System( HINSTANCE instance, HWND window, const Cooperation coop,
  SystemListener* listener ): mCooperation( coop ),
  mWindow( window ), mInstance( instance ), mDirectInput( nullptr ),
  mMonitor( nullptr ), mIDPool( 0 ), mInitializing( true ),
  mHIDManager( nullptr ), mLogitechGKeys( nullptr ), mLogitechLEDs( nullptr ),
  mListener( listener ), mMouseIndexPool( 0 ), mKeyboardIndexPool( 0 ),
  mControllerIndexPool( 0 ), mXInput( nullptr )
  {
    assert( mListener );

    // Validate the passes window handle
    if ( !IsWindow( mWindow ) )
      NIL_EXCEPT( "Window handle is invalid" );

    mLogitechGKeys = new Logitech::GKeySDK();
    mLogitechLEDs = new Logitech::LedSDK();

    mXInput = new XInput();
    if ( mXInput->initialize() != ExternalModule::Initialization_OK )
      NIL_EXCEPT( "Loading XInput failed" );

    // Create DirectInput instance
    auto hr = DirectInput8Create( mInstance, DIRECTINPUT_VERSION,
      IID_IDirectInput8W, (LPVOID*)&mDirectInput, NULL );
    if ( FAILED( hr ) )
      NIL_EXCEPT_DINPUT( hr, "Could not instantiate DirectInput 8" );

    // Initialize our event monitor
    mMonitor = new EventMonitor( mInstance, mCooperation );

    // Initialize our HID manager
    mHIDManager = new HIDManager();

    // Register the HID manager and ourselves as PnP event listeners
    mMonitor->registerPnPListener( mHIDManager );
    mMonitor->registerPnPListener( this );

    // Register ourselves as a raw event listener
    mMonitor->registerRawListener( this );

    // Fetch initial devices
    initializeDevices();
    refreshDevices();

    // Update the monitor once, to receive initial Raw devices
    mMonitor->update();

    mInitializing = false;
  }

  DeviceID System::getNextID()
  {
    return mIDPool++;
  }

  void System::onPnPPlug( const GUID& deviceClass, const wideString& devicePath )
  {
    // Refresh all currently connected devices,
    // since IDirectInput8::FindDevice doesn't do jack shit
    refreshDevices();
  }

  void System::onPnPUnplug( const GUID& deviceClass, const wideString& devicePath )
  {
    // Refresh all currently connected devices,
    // since IDirectInput8::FindDevice doesn't do jack shit
    refreshDevices();
  }

  void System::onRawArrival( HANDLE handle )
  {
    UINT pathLength = 0;

    if ( GetRawInputDeviceInfoW( handle, RIDI_DEVICENAME, NULL, &pathLength ) )
      NIL_EXCEPT_WINAPI( "GetRawInputDeviceInfoW failed" );

    wideString rawPath( pathLength, '\0' );

    GetRawInputDeviceInfoW( handle, RIDI_DEVICENAME, &rawPath[0], &pathLength );
    rawPath.resize( rawPath.length() - 1 );

    for ( auto device : mDevices )
    {
      if ( device->getHandler() != Device::Handler_RawInput )
        continue;

      auto rawDevice = static_cast<RawInputDevice*>( device );

      if ( !_wcsicmp( rawDevice->getRawPath().c_str(), rawPath.c_str() ) )
      {
        deviceConnect( rawDevice );
        return;
      }
    }

    auto device = new RawInputDevice( this, getNextID(), handle, rawPath );

    if ( isInitializing() )
      device->setStatus( Device::Status_Connected );
    else
      deviceConnect( device );

    mDevices.push_back( device );
  }

  void System::onRawMouseInput( HANDLE handle,
  const RAWMOUSE& input, const bool sinked )
  {
    if ( mInitializing || !handle )
      return;

    auto it = mMouseMapping.find( handle );
    if ( it != mMouseMapping.end() )
      it->second->onRawInput( input );
  }

  void System::onRawKeyboardInput( HANDLE handle,
  const RAWKEYBOARD& input, const bool sinked )
  {
    if ( mInitializing || !handle )
      return;

    auto it = mKeyboardMapping.find( handle );
    if ( it != mKeyboardMapping.end() )
      it->second->onRawInput( input );
  }

  void System::onRawRemoval( HANDLE handle )
  {
    for ( auto device : mDevices )
    {
      if ( device->getHandler() != Device::Handler_RawInput )
        continue;

      auto rawDevice = static_cast<RawInputDevice*>( device );

      if ( rawDevice->getRawHandle() == handle )
      {
        deviceDisconnect( rawDevice );
        return;
      }
    }
  }

  void System::mapMouse( HANDLE handle, RawInputMouse* mouse )
  {
    mMouseMapping[handle] = mouse;
  }

  void System::unmapMouse( HANDLE handle )
  {
    mMouseMapping.erase( handle );
  }

  void System::mapKeyboard( HANDLE handle, RawInputKeyboard* keyboard )
  {
    mKeyboardMapping[handle] = keyboard;
  }

  void System::unmapKeyboard( HANDLE handle )
  {
    mKeyboardMapping.erase( handle );
  }

  void System::initializeDevices()
  {
    mXInputIDs.resize( XUSER_MAX_COUNT );
    for ( int i = 0; i < XUSER_MAX_COUNT; i++ )
    {
      mXInputIDs[i] = getNextID();
      auto device = new XInputDevice( this, mXInputIDs[i], i );
      mDevices.push_back( device );
    }
  }

  void System::refreshDevices()
  {
    identifyXInputDevices();

    for ( Device* device : mDevices )
      if ( device->getHandler() == Device::Handler_DirectInput )
      {
        device->saveStatus();
        device->setStatus( Device::Status_Pending );
      }

    auto hr = mDirectInput->EnumDevices( DI8DEVCLASS_GAMECTRL,
      diDeviceEnumCallback, this, DIEDFL_ATTACHEDONLY );
    if ( FAILED( hr ) )
      NIL_EXCEPT_DINPUT( hr, "Could not enumerate DirectInput devices!" );

    for ( Device* device : mDevices )
      if ( device->getHandler() == Device::Handler_DirectInput
        && device->getSavedStatus() == Device::Status_Connected
        && device->getStatus() == Device::Status_Pending )
        deviceDisconnect( device );

    XINPUT_STATE state;
    for ( Device* device : mDevices )
    {
      if ( device->getHandler() == Device::Handler_XInput )
      {
        auto xDevice = static_cast<XInputDevice*>( device );
        auto status = mXInput->mFunctions.pfnXInputGetState( xDevice->getXInputID(), &state );
        if ( status == ERROR_DEVICE_NOT_CONNECTED )
        {
          if ( xDevice->getStatus() == Device::Status_Connected )
            deviceDisconnect( xDevice );
          else if ( xDevice->getStatus() == Device::Status_Pending )
            xDevice->setStatus( Device::Status_Disconnected );
        }
        else if ( status == ERROR_SUCCESS )
        {
          if ( xDevice->getStatus() == Device::Status_Disconnected )
            deviceConnect( xDevice );
          else if ( xDevice->getStatus() == Device::Status_Pending )
            xDevice->setStatus( Device::Status_Connected );
        }
        else
          NIL_EXCEPT( "XInputGetState failed" );
      }
    }
  }

  BOOL CALLBACK System::diDeviceEnumCallback( LPCDIDEVICEINSTANCEW instance,
  LPVOID referer )
  {
    auto system = reinterpret_cast<System*>( referer );

    for ( auto identifier : system->mXInputDeviceIDs )
      if ( instance->guidProduct.Data1 == identifier )
        return DIENUM_CONTINUE;

    for ( auto device : system->mDevices )
    {
      if ( device->getHandler() != Device::Handler_DirectInput )
        continue;

      auto diDevice = static_cast<DirectInputDevice*>( device );

      if ( diDevice->getInstanceID() == instance->guidInstance )
      {
        if ( device->getSavedStatus() == Device::Status_Disconnected )
          system->deviceConnect( device );
        else
          device->setStatus( Device::Status_Connected );

        return DIENUM_CONTINUE;
      }
    }

    Device* device = new DirectInputDevice( system, system->getNextID(), instance );

    if ( system->isInitializing() )
      device->setStatus( Device::Status_Connected );
    else
      system->deviceConnect( device );

    system->mDevices.push_back( device );

    return DIENUM_CONTINUE;
  }

  void System::deviceConnect( Device* device )
  {
    device->onConnect();
    mListener->onDeviceConnected( device );
  }

  void System::deviceDisconnect( Device* device )
  {
    device->onDisconnect();
    mListener->onDeviceDisconnected( device );
  }

  void System::mouseEnabled( Device* device, Mouse* instance )
  {
    mListener->onMouseEnabled( device, instance );
  }

  void System::mouseDisabled( Device* device, Mouse* instance )
  {
    mListener->onMouseDisabled( device, instance );
  }

  void System::keyboardEnabled( Device* device, Keyboard* instance )
  {
    mListener->onKeyboardEnabled( device, instance );
  }

  void System::keyboardDisabled( Device* device, Keyboard* instance )
  {
    mListener->onKeyboardDisabled( device, instance );
  }

  void System::controllerEnabled( Device* device, Controller* instance )
  {
    mListener->onControllerEnabled( device, instance );
  }

  void System::controllerDisabled( Device* device, Controller* instance )
  {
    mListener->onControllerDisabled( device, instance );
  }

  void System::identifyXInputDevices()
  {
    mXInputDeviceIDs.clear();
    for ( auto hidRecord : mHIDManager->getRecords() )
      if ( hidRecord->isXInput() )
        mXInputDeviceIDs.push_back( hidRecord->getIdentifier() );
  }

  DeviceList& System::getDevices()
  {
    return mDevices;
  }

  const bool System::isInitializing() const
  {
    return mInitializing;
  }

  int System::getNextMouseIndex()
  {
    return ++mMouseIndexPool;
  }

  int System::getNextKeyboardIndex()
  {
    return ++mKeyboardIndexPool;
  }

  int System::getNextControllerIndex()
  {
    return ++mControllerIndexPool;
  }

  void System::update()
  {
    // Run PnP & raw events if there are any
    mMonitor->update();

    // Make sure that we disconnect failed devices,
    // and update the rest
    for ( Device* device : mDevices )
      if ( device->isDisconnectFlagged() )
        deviceDisconnect( device );
      else
        device->update();

    // Run queued G-key events if using the SDK
    if ( mLogitechGKeys->isInitialized() )
      mLogitechGKeys->update();
  }

  Logitech::GKeySDK* System::getLogitechGKeys()
  {
    return mLogitechGKeys;
  }

  Logitech::LedSDK* System::getLogitechLEDs()
  {
    return mLogitechLEDs;
  }

  XInput* System::getXInput()
  {
    return mXInput;
  }

  System::~System()
  {
    for ( Device* device : mDevices )
      delete device;

    SAFE_DELETE( mHIDManager );
    SAFE_DELETE( mMonitor );
    SAFE_RELEASE( mDirectInput );
    SAFE_DELETE( mLogitechLEDs );
    SAFE_DELETE( mLogitechGKeys );
    SAFE_DELETE( mXInput );
  }

}<commit_msg>Disable all devices before deletion in System destructor, to avoid memory leaks in end-user application<commit_after>#include "nil.h"
#include "nilUtil.h"
#include "nilLogitech.h"

namespace Nil {

  System::System( HINSTANCE instance, HWND window, const Cooperation coop,
  SystemListener* listener ): mCooperation( coop ),
  mWindow( window ), mInstance( instance ), mDirectInput( nullptr ),
  mMonitor( nullptr ), mIDPool( 0 ), mInitializing( true ),
  mHIDManager( nullptr ), mLogitechGKeys( nullptr ), mLogitechLEDs( nullptr ),
  mListener( listener ), mMouseIndexPool( 0 ), mKeyboardIndexPool( 0 ),
  mControllerIndexPool( 0 ), mXInput( nullptr )
  {
    assert( mListener );

    // Validate the passes window handle
    if ( !IsWindow( mWindow ) )
      NIL_EXCEPT( "Window handle is invalid" );

    mLogitechGKeys = new Logitech::GKeySDK();
    mLogitechLEDs = new Logitech::LedSDK();

    mXInput = new XInput();
    if ( mXInput->initialize() != ExternalModule::Initialization_OK )
      NIL_EXCEPT( "Loading XInput failed" );

    // Create DirectInput instance
    auto hr = DirectInput8Create( mInstance, DIRECTINPUT_VERSION,
      IID_IDirectInput8W, (LPVOID*)&mDirectInput, NULL );
    if ( FAILED( hr ) )
      NIL_EXCEPT_DINPUT( hr, "Could not instantiate DirectInput 8" );

    // Initialize our event monitor
    mMonitor = new EventMonitor( mInstance, mCooperation );

    // Initialize our HID manager
    mHIDManager = new HIDManager();

    // Register the HID manager and ourselves as PnP event listeners
    mMonitor->registerPnPListener( mHIDManager );
    mMonitor->registerPnPListener( this );

    // Register ourselves as a raw event listener
    mMonitor->registerRawListener( this );

    // Fetch initial devices
    initializeDevices();
    refreshDevices();

    // Update the monitor once, to receive initial Raw devices
    mMonitor->update();

    mInitializing = false;
  }

  DeviceID System::getNextID()
  {
    return mIDPool++;
  }

  void System::onPnPPlug( const GUID& deviceClass, const wideString& devicePath )
  {
    // Refresh all currently connected devices,
    // since IDirectInput8::FindDevice doesn't do jack shit
    refreshDevices();
  }

  void System::onPnPUnplug( const GUID& deviceClass, const wideString& devicePath )
  {
    // Refresh all currently connected devices,
    // since IDirectInput8::FindDevice doesn't do jack shit
    refreshDevices();
  }

  void System::onRawArrival( HANDLE handle )
  {
    UINT pathLength = 0;

    if ( GetRawInputDeviceInfoW( handle, RIDI_DEVICENAME, NULL, &pathLength ) )
      NIL_EXCEPT_WINAPI( "GetRawInputDeviceInfoW failed" );

    wideString rawPath( pathLength, '\0' );

    GetRawInputDeviceInfoW( handle, RIDI_DEVICENAME, &rawPath[0], &pathLength );
    rawPath.resize( rawPath.length() - 1 );

    for ( auto device : mDevices )
    {
      if ( device->getHandler() != Device::Handler_RawInput )
        continue;

      auto rawDevice = static_cast<RawInputDevice*>( device );

      if ( !_wcsicmp( rawDevice->getRawPath().c_str(), rawPath.c_str() ) )
      {
        deviceConnect( rawDevice );
        return;
      }
    }

    auto device = new RawInputDevice( this, getNextID(), handle, rawPath );

    if ( isInitializing() )
      device->setStatus( Device::Status_Connected );
    else
      deviceConnect( device );

    mDevices.push_back( device );
  }

  void System::onRawMouseInput( HANDLE handle,
  const RAWMOUSE& input, const bool sinked )
  {
    if ( mInitializing || !handle )
      return;

    auto it = mMouseMapping.find( handle );
    if ( it != mMouseMapping.end() )
      it->second->onRawInput( input );
  }

  void System::onRawKeyboardInput( HANDLE handle,
  const RAWKEYBOARD& input, const bool sinked )
  {
    if ( mInitializing || !handle )
      return;

    auto it = mKeyboardMapping.find( handle );
    if ( it != mKeyboardMapping.end() )
      it->second->onRawInput( input );
  }

  void System::onRawRemoval( HANDLE handle )
  {
    for ( auto device : mDevices )
    {
      if ( device->getHandler() != Device::Handler_RawInput )
        continue;

      auto rawDevice = static_cast<RawInputDevice*>( device );

      if ( rawDevice->getRawHandle() == handle )
      {
        deviceDisconnect( rawDevice );
        return;
      }
    }
  }

  void System::mapMouse( HANDLE handle, RawInputMouse* mouse )
  {
    mMouseMapping[handle] = mouse;
  }

  void System::unmapMouse( HANDLE handle )
  {
    mMouseMapping.erase( handle );
  }

  void System::mapKeyboard( HANDLE handle, RawInputKeyboard* keyboard )
  {
    mKeyboardMapping[handle] = keyboard;
  }

  void System::unmapKeyboard( HANDLE handle )
  {
    mKeyboardMapping.erase( handle );
  }

  void System::initializeDevices()
  {
    mXInputIDs.resize( XUSER_MAX_COUNT );
    for ( int i = 0; i < XUSER_MAX_COUNT; i++ )
    {
      mXInputIDs[i] = getNextID();
      auto device = new XInputDevice( this, mXInputIDs[i], i );
      mDevices.push_back( device );
    }
  }

  void System::refreshDevices()
  {
    identifyXInputDevices();

    for ( Device* device : mDevices )
      if ( device->getHandler() == Device::Handler_DirectInput )
      {
        device->saveStatus();
        device->setStatus( Device::Status_Pending );
      }

    auto hr = mDirectInput->EnumDevices( DI8DEVCLASS_GAMECTRL,
      diDeviceEnumCallback, this, DIEDFL_ATTACHEDONLY );
    if ( FAILED( hr ) )
      NIL_EXCEPT_DINPUT( hr, "Could not enumerate DirectInput devices!" );

    for ( Device* device : mDevices )
      if ( device->getHandler() == Device::Handler_DirectInput
        && device->getSavedStatus() == Device::Status_Connected
        && device->getStatus() == Device::Status_Pending )
        deviceDisconnect( device );

    XINPUT_STATE state;
    for ( Device* device : mDevices )
    {
      if ( device->getHandler() == Device::Handler_XInput )
      {
        auto xDevice = static_cast<XInputDevice*>( device );
        auto status = mXInput->mFunctions.pfnXInputGetState( xDevice->getXInputID(), &state );
        if ( status == ERROR_DEVICE_NOT_CONNECTED )
        {
          if ( xDevice->getStatus() == Device::Status_Connected )
            deviceDisconnect( xDevice );
          else if ( xDevice->getStatus() == Device::Status_Pending )
            xDevice->setStatus( Device::Status_Disconnected );
        }
        else if ( status == ERROR_SUCCESS )
        {
          if ( xDevice->getStatus() == Device::Status_Disconnected )
            deviceConnect( xDevice );
          else if ( xDevice->getStatus() == Device::Status_Pending )
            xDevice->setStatus( Device::Status_Connected );
        }
        else
          NIL_EXCEPT( "XInputGetState failed" );
      }
    }
  }

  BOOL CALLBACK System::diDeviceEnumCallback( LPCDIDEVICEINSTANCEW instance,
  LPVOID referer )
  {
    auto system = reinterpret_cast<System*>( referer );

    for ( auto identifier : system->mXInputDeviceIDs )
      if ( instance->guidProduct.Data1 == identifier )
        return DIENUM_CONTINUE;

    for ( auto device : system->mDevices )
    {
      if ( device->getHandler() != Device::Handler_DirectInput )
        continue;

      auto diDevice = static_cast<DirectInputDevice*>( device );

      if ( diDevice->getInstanceID() == instance->guidInstance )
      {
        if ( device->getSavedStatus() == Device::Status_Disconnected )
          system->deviceConnect( device );
        else
          device->setStatus( Device::Status_Connected );

        return DIENUM_CONTINUE;
      }
    }

    Device* device = new DirectInputDevice( system, system->getNextID(), instance );

    if ( system->isInitializing() )
      device->setStatus( Device::Status_Connected );
    else
      system->deviceConnect( device );

    system->mDevices.push_back( device );

    return DIENUM_CONTINUE;
  }

  void System::deviceConnect( Device* device )
  {
    device->onConnect();
    mListener->onDeviceConnected( device );
  }

  void System::deviceDisconnect( Device* device )
  {
    device->onDisconnect();
    mListener->onDeviceDisconnected( device );
  }

  void System::mouseEnabled( Device* device, Mouse* instance )
  {
    mListener->onMouseEnabled( device, instance );
  }

  void System::mouseDisabled( Device* device, Mouse* instance )
  {
    mListener->onMouseDisabled( device, instance );
  }

  void System::keyboardEnabled( Device* device, Keyboard* instance )
  {
    mListener->onKeyboardEnabled( device, instance );
  }

  void System::keyboardDisabled( Device* device, Keyboard* instance )
  {
    mListener->onKeyboardDisabled( device, instance );
  }

  void System::controllerEnabled( Device* device, Controller* instance )
  {
    mListener->onControllerEnabled( device, instance );
  }

  void System::controllerDisabled( Device* device, Controller* instance )
  {
    mListener->onControllerDisabled( device, instance );
  }

  void System::identifyXInputDevices()
  {
    mXInputDeviceIDs.clear();
    for ( auto hidRecord : mHIDManager->getRecords() )
      if ( hidRecord->isXInput() )
        mXInputDeviceIDs.push_back( hidRecord->getIdentifier() );
  }

  DeviceList& System::getDevices()
  {
    return mDevices;
  }

  const bool System::isInitializing() const
  {
    return mInitializing;
  }

  int System::getNextMouseIndex()
  {
    return ++mMouseIndexPool;
  }

  int System::getNextKeyboardIndex()
  {
    return ++mKeyboardIndexPool;
  }

  int System::getNextControllerIndex()
  {
    return ++mControllerIndexPool;
  }

  void System::update()
  {
    // Run PnP & raw events if there are any
    mMonitor->update();

    // Make sure that we disconnect failed devices,
    // and update the rest
    for ( Device* device : mDevices )
      if ( device->isDisconnectFlagged() )
        deviceDisconnect( device );
      else
        device->update();

    // Run queued G-key events if using the SDK
    if ( mLogitechGKeys->isInitialized() )
      mLogitechGKeys->update();
  }

  Logitech::GKeySDK* System::getLogitechGKeys()
  {
    return mLogitechGKeys;
  }

  Logitech::LedSDK* System::getLogitechLEDs()
  {
    return mLogitechLEDs;
  }

  XInput* System::getXInput()
  {
    return mXInput;
  }

  System::~System()
  {
    for ( Device* device : mDevices )
    {
      device->disable();
      delete device;
    }

    SAFE_DELETE( mHIDManager );
    SAFE_DELETE( mMonitor );
    SAFE_RELEASE( mDirectInput );
    SAFE_DELETE( mLogitechLEDs );
    SAFE_DELETE( mLogitechGKeys );
    SAFE_DELETE( mXInput );
  }

}<|endoftext|>


<commit_before>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "support.h"

#include <cmath> // sqrt
#include <utility> // pair

namespace cura
{

/*
 * Algorithm:
 * From top layer to bottom layer:
 * - find overhang by looking at the difference between two consucutive layers
 * - join with support areas from layer above
 * - subtract current layer
 * - use the result for the next lower support layer (without doing XY-distance and Z bottom distance, so that a single support beam may move around the model a bit => more stability)
 * - perform inset using X/Y-distance and bottom Z distance
 *
 * for support buildplate only: purge all support not connected to buildplate
 */
void generateSupportAreas(SliceDataStorage& storage, SliceMeshStorage* object, int layer_count)
{
    // given settings
    ESupportType support_type = object->settings->getSettingAsSupportType("support_type");

    storage.support.generated = false;
    if (support_type == Support_None)
        return;

    double supportAngle = object->settings->getSettingInAngleRadians("support_angle");
    bool supportOnBuildplateOnly = support_type == Support_PlatformOnly;
    int supportXYDistance = object->settings->getSettingInMicrons("support_xy_distance");
    int supportZDistance = object->settings->getSettingInMicrons("support_z_distance");
    int supportZDistanceBottom = object->settings->getSettingInMicrons("support_bottom_distance");
    int supportZDistanceTop = object->settings->getSettingInMicrons("support_top_distance");
    int supportJoinDistance = object->settings->getSettingInMicrons("support_join_distance");
    int supportBottomStairDistance = object->settings->getSettingInMicrons("supportBottomStairDistance");
    int smoothing_distance = object->settings->getSettingInMicrons("support_area_smoothing");

    int supportTowerDiameter = object->settings->getSettingInMicrons("support_tower_diameter");
    int supportMinAreaSqrt = object->settings->getSettingInMicrons("support_minimal_diameter");
    double supportTowerRoofAngle = object->settings->getSettingInAngleRadians("support_tower_roof_angle");

    //std::cerr <<" towerDiameter=" << towerDiameter <<", supportMinAreaSqrt=" << supportMinAreaSqrt << std::endl;

    int min_smoothing_area = 100*100; // minimal area for which to perform smoothing
    int z_layer_distance_tower = 1; // start tower directly below overhang point

    int layerThickness = object->settings->getSettingInMicrons("layer_height");
    int extrusionWidth = object->settings->getSettingInMicrons("wall_line_width_x"); // TODO check for layer0extrusionWidth!

    // derived settings:

    if (supportZDistanceBottom < 0) supportZDistanceBottom = supportZDistance;
    if (supportZDistanceTop < 0)    supportZDistanceTop = supportZDistance;

    int supportLayerThickness = layerThickness;

    int layerZdistanceTop       = supportZDistanceTop / supportLayerThickness + 1; // support must always be 1 layer below overhang
    int layerZdistanceBottom    = supportZDistanceBottom / supportLayerThickness;

    double tanAngle = tan(supportAngle) - 0.01;  // the XY-component of the supportAngle
    int maxDistFromLowerLayer = tanAngle * supportLayerThickness; // max dist which can be bridged

    int support_layer_count = layer_count;

    double tanTowerRoofAngle = tan(supportTowerRoofAngle);
    int towerRoofExpansionDistance = layerThickness / tanTowerRoofAngle;

    // computation

    std::vector<Polygons> joinedLayers; // join model layers of all meshes into polygons and store small areas which need tower support
    std::vector<std::pair<int, std::vector<Polygons>>> overhang_points; // stores overhang_points along with the layer index at which the overhang point occurs
    AreaSupport::joinMeshesAndDetectOverhangPoints(storage, joinedLayers, overhang_points, layer_count, supportMinAreaSqrt, extrusionWidth);

    // initialization of supportAreasPerLayer
    for (int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
        storage.support.supportAreasPerLayer.emplace_back();

    int overhang_points_pos = overhang_points.size() - 1;
    Polygons supportLayer_last;
    std::vector<Polygons> towerRoofs;
    for (int layer_idx = support_layer_count - 1 - layerZdistanceTop; layer_idx >= 0 ; layer_idx--)
    {

        // compute basic overhang and put in right layer ([layerZdistanceTOp] layers below)
        Polygons supportLayer_supportee =  joinedLayers[layer_idx+layerZdistanceTop];
        Polygons supportLayer_supported =  joinedLayers[layer_idx-1+layerZdistanceTop].offset(maxDistFromLowerLayer);
        Polygons basic_overhang = supportLayer_supportee.difference(supportLayer_supported);

        Polygons support_extension = basic_overhang.offset(maxDistFromLowerLayer);
        support_extension = support_extension.intersection(supportLayer_supported);
        support_extension = support_extension.intersection(supportLayer_supportee);

        Polygons overhang =  basic_overhang.unionPolygons(support_extension);

        /* supported
         * .................
         *         ______________|
         * _______|         ^^^^^ basic overhang
         *
         *         ^^^^^^^^^      overhang extensions
         *         ^^^^^^^^^^^^^^ overhang
         */

        Polygons& supportLayer_this = overhang;

        supportLayer_this = supportLayer_this.simplify(50); // TODO: hardcoded value!

        if (supportMinAreaSqrt > 0)
        {
            // handle straight walls
            AreaSupport::handleWallStruts(supportLayer_this, supportMinAreaSqrt, supportTowerDiameter);
            // handle towers
            AreaSupport::handleTowers(supportLayer_this, towerRoofs, overhang_points, overhang_points_pos, layer_idx, towerRoofExpansionDistance, supportTowerDiameter, supportMinAreaSqrt, layer_count, z_layer_distance_tower);
        }

        if (layer_idx+1 < support_layer_count)
        { // join with support from layer up
            Polygons& supportLayer_up = supportLayer_last;

            Polygons joined = supportLayer_this.unionPolygons(supportLayer_up);
            // join different parts
            if (supportJoinDistance > 0)
            {
                joined = joined.offset(supportJoinDistance);
                joined = joined.offset(-supportJoinDistance);
            }
            if (smoothing_distance > 0)
                joined = joined.smooth(smoothing_distance, min_smoothing_area);

            // remove layer
            Polygons insetted = joined.difference(joinedLayers[layer_idx]);
            supportLayer_this = insetted;

        }

        supportLayer_last = supportLayer_this;

        // inset using X/Y distance
        if (supportLayer_this.size() > 0)
            supportLayer_this = supportLayer_this.difference(joinedLayers[layer_idx].offset(supportXYDistance));

        // move up from model
        if (layerZdistanceBottom > 0 && layer_idx >= layerZdistanceBottom)
        {
            int stepHeight = supportBottomStairDistance / supportLayerThickness + 1;
            int bottomLayer = ((layer_idx - layerZdistanceBottom) / stepHeight) * stepHeight;
            supportLayer_this = supportLayer_this.difference(joinedLayers[bottomLayer]);
        }

        storage.support.supportAreasPerLayer[layer_idx] = supportLayer_this;

    }

    // do stuff for when support on buildplate only
    if (supportOnBuildplateOnly)
    {
        Polygons touching_buildplate = storage.support.supportAreasPerLayer[0];
        for (unsigned int layer_idx = 1 ; layer_idx < storage.support.supportAreasPerLayer.size() ; layer_idx++)
        {
            Polygons& supportLayer = storage.support.supportAreasPerLayer[layer_idx];

            touching_buildplate = supportLayer.intersection(touching_buildplate); // from bottom to top, support areas can only decrease!

            storage.support.supportAreasPerLayer[layer_idx] = touching_buildplate;
        }
    }

    joinedLayers.clear();

    storage.support.generated = true;
}

void AreaSupport::joinMeshesAndDetectOverhangPoints(
    SliceDataStorage& storage,
    std::vector<Polygons>& joinedLayers,
    std::vector<std::pair<int, std::vector<Polygons>>>& overhang_points, // stores overhang_points along with the layer index at which the overhang point occurs)
    int layer_count,
    int supportMinAreaSqrt,
    int extrusionWidth
                  )
{
    for (int layer_idx = 0 ; layer_idx < layer_count ; layer_idx++)
    {
        joinedLayers.emplace_back();
        for (SliceMeshStorage& mesh : storage.meshes)
        {
            SliceLayer& layer = mesh.layers[layer_idx];
            for (SliceLayerPart& part : layer.parts)
            {

                if (part.outline[0].area() < supportMinAreaSqrt * supportMinAreaSqrt)
                {
                    Polygons part_poly = part.outline.offset(-extrusionWidth/2);
                    if (part_poly.size() > 0)
                    {
                        if (overhang_points.size() > 0 && overhang_points.back().first == layer_idx)
                            overhang_points.back().second.push_back(part_poly);
                        else
                        {
                            std::vector<Polygons> small_part_polys;
                            small_part_polys.push_back(part_poly);
                            overhang_points.emplace_back<std::pair<int, std::vector<Polygons>>>(std::make_pair(layer_idx, small_part_polys));
                        }
                    }

                }
                joinedLayers.back() = joinedLayers.back().unionPolygons(part.outline);

            }
        }
    }
}

void AreaSupport::handleTowers(
    Polygons& supportLayer_this,
    std::vector<Polygons>& towerRoofs,
    std::vector<std::pair<int, std::vector<Polygons>>>& overhang_points,
    int& overhang_points_pos,
    int layer_idx,
    int towerRoofExpansionDistance,
    int supportTowerDiameter,
    int supportMinAreaSqrt,
    int layer_count,
    int z_layer_distance_tower
)
{
    // handle new tower roof tops
    int layer_overhang_point =  layer_idx + z_layer_distance_tower;
    if (overhang_points_pos >= 0 && layer_overhang_point < layer_count &&
        overhang_points[overhang_points_pos].first == layer_overhang_point)
    {
        std::vector<Polygons>& overhang_points_here = overhang_points[overhang_points_pos].second;
        { // make sure we have the lowest point (make polys empty if they have small parts below)
            if (overhang_points_pos > 0 && overhang_points[overhang_points_pos - 1].first == layer_overhang_point - 1)
            {
                std::vector<Polygons>& overhang_points_below = overhang_points[overhang_points_pos - 1].second;
                for (Polygons& poly_here : overhang_points_here)
                {
                    for (Polygons& poly_below : overhang_points_below)
                    {
                        poly_here = poly_here.difference(poly_below.offset(supportMinAreaSqrt*2));
                    }
                }
            }
        }
        for (Polygons& poly : overhang_points_here)
            if (poly.size() > 0)
                towerRoofs.push_back(poly);
        overhang_points_pos--;
    }

    // make tower roofs
    //for (Polygons& tower_roof : towerRoofs)
    for (unsigned int r = 0; r < towerRoofs.size(); r++)
    {
        supportLayer_this = supportLayer_this.unionPolygons(towerRoofs[r]);

        Polygons& tower_roof = towerRoofs[r];
        if (tower_roof[0].area() < supportTowerDiameter * supportTowerDiameter)
        {
            towerRoofs[r] = tower_roof.offset(towerRoofExpansionDistance);
        }
    }
}

void AreaSupport::handleWallStruts(
    Polygons& supportLayer_this,
    int supportMinAreaSqrt,
    int supportTowerDiameter
    )
{
    for (unsigned int p = 0; p < supportLayer_this.size(); p++)
    {
        PolygonRef poly = supportLayer_this[p];
        if (poly.size() < 6) // might be a single wall
        {
            PolygonRef poly = supportLayer_this[p];
            int best = -1;
            int best_length2 = -1;
            for (unsigned int i = 0; i < poly.size(); i++)
            {
                int length2 = vSize2(poly[i] - poly[(i+1) % poly.size()]);
                if (length2 > best_length2)
                {
                    best = i;
                    best_length2 = length2;
                }
            }

            if (best_length2 < supportMinAreaSqrt * supportMinAreaSqrt)
                break; // this is a small area, not a wall!

            // an estimate of the width of the area
            int width = sqrt( poly.area() * poly.area() / best_length2 ); // sqrt (a^2 / l^2) instead of a / sqrt(l^2)

            // add square tower (strut) in the middle of the wall
            if (width < supportMinAreaSqrt)
            {
                Point mid = (poly[best] + poly[(best+1) % poly.size()] ) / 2;
                Polygons struts;
                PolygonRef strut = struts.newPoly();
                strut.add(mid + Point( supportTowerDiameter/2,  supportTowerDiameter/2));
                strut.add(mid + Point(-supportTowerDiameter/2,  supportTowerDiameter/2));
                strut.add(mid + Point(-supportTowerDiameter/2, -supportTowerDiameter/2));
                strut.add(mid + Point( supportTowerDiameter/2, -supportTowerDiameter/2));
                supportLayer_this = supportLayer_this.unionPolygons(struts);
            }
        }
    }
}

}//namespace cura
<commit_msg>Somehow the tower_roof size becomes 0 sometimes.<commit_after>/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "support.h"

#include <cmath> // sqrt
#include <utility> // pair

namespace cura
{

/*
 * Algorithm:
 * From top layer to bottom layer:
 * - find overhang by looking at the difference between two consucutive layers
 * - join with support areas from layer above
 * - subtract current layer
 * - use the result for the next lower support layer (without doing XY-distance and Z bottom distance, so that a single support beam may move around the model a bit => more stability)
 * - perform inset using X/Y-distance and bottom Z distance
 *
 * for support buildplate only: purge all support not connected to buildplate
 */
void generateSupportAreas(SliceDataStorage& storage, SliceMeshStorage* object, int layer_count)
{
    // given settings
    ESupportType support_type = object->settings->getSettingAsSupportType("support_type");

    storage.support.generated = false;
    if (support_type == Support_None)
        return;

    double supportAngle = object->settings->getSettingInAngleRadians("support_angle");
    bool supportOnBuildplateOnly = support_type == Support_PlatformOnly;
    int supportXYDistance = object->settings->getSettingInMicrons("support_xy_distance");
    int supportZDistance = object->settings->getSettingInMicrons("support_z_distance");
    int supportZDistanceBottom = object->settings->getSettingInMicrons("support_bottom_distance");
    int supportZDistanceTop = object->settings->getSettingInMicrons("support_top_distance");
    int supportJoinDistance = object->settings->getSettingInMicrons("support_join_distance");
    int supportBottomStairDistance = object->settings->getSettingInMicrons("supportBottomStairDistance");
    int smoothing_distance = object->settings->getSettingInMicrons("support_area_smoothing");

    int supportTowerDiameter = object->settings->getSettingInMicrons("support_tower_diameter");
    int supportMinAreaSqrt = object->settings->getSettingInMicrons("support_minimal_diameter");
    double supportTowerRoofAngle = object->settings->getSettingInAngleRadians("support_tower_roof_angle");

    //std::cerr <<" towerDiameter=" << towerDiameter <<", supportMinAreaSqrt=" << supportMinAreaSqrt << std::endl;

    int min_smoothing_area = 100*100; // minimal area for which to perform smoothing
    int z_layer_distance_tower = 1; // start tower directly below overhang point

    int layerThickness = object->settings->getSettingInMicrons("layer_height");
    int extrusionWidth = object->settings->getSettingInMicrons("wall_line_width_x"); // TODO check for layer0extrusionWidth!

    // derived settings:

    if (supportZDistanceBottom < 0) supportZDistanceBottom = supportZDistance;
    if (supportZDistanceTop < 0)    supportZDistanceTop = supportZDistance;

    int supportLayerThickness = layerThickness;

    int layerZdistanceTop       = supportZDistanceTop / supportLayerThickness + 1; // support must always be 1 layer below overhang
    int layerZdistanceBottom    = supportZDistanceBottom / supportLayerThickness;

    double tanAngle = tan(supportAngle) - 0.01;  // the XY-component of the supportAngle
    int maxDistFromLowerLayer = tanAngle * supportLayerThickness; // max dist which can be bridged

    int support_layer_count = layer_count;

    double tanTowerRoofAngle = tan(supportTowerRoofAngle);
    int towerRoofExpansionDistance = layerThickness / tanTowerRoofAngle;

    // computation

    std::vector<Polygons> joinedLayers; // join model layers of all meshes into polygons and store small areas which need tower support
    std::vector<std::pair<int, std::vector<Polygons>>> overhang_points; // stores overhang_points along with the layer index at which the overhang point occurs
    AreaSupport::joinMeshesAndDetectOverhangPoints(storage, joinedLayers, overhang_points, layer_count, supportMinAreaSqrt, extrusionWidth);

    // initialization of supportAreasPerLayer
    for (int layer_idx = 0; layer_idx < layer_count ; layer_idx++)
        storage.support.supportAreasPerLayer.emplace_back();

    int overhang_points_pos = overhang_points.size() - 1;
    Polygons supportLayer_last;
    std::vector<Polygons> towerRoofs;
    for (int layer_idx = support_layer_count - 1 - layerZdistanceTop; layer_idx >= 0 ; layer_idx--)
    {

        // compute basic overhang and put in right layer ([layerZdistanceTOp] layers below)
        Polygons supportLayer_supportee =  joinedLayers[layer_idx+layerZdistanceTop];
        Polygons supportLayer_supported =  joinedLayers[layer_idx-1+layerZdistanceTop].offset(maxDistFromLowerLayer);
        Polygons basic_overhang = supportLayer_supportee.difference(supportLayer_supported);

        Polygons support_extension = basic_overhang.offset(maxDistFromLowerLayer);
        support_extension = support_extension.intersection(supportLayer_supported);
        support_extension = support_extension.intersection(supportLayer_supportee);

        Polygons overhang =  basic_overhang.unionPolygons(support_extension);

        /* supported
         * .................
         *         ______________|
         * _______|         ^^^^^ basic overhang
         *
         *         ^^^^^^^^^      overhang extensions
         *         ^^^^^^^^^^^^^^ overhang
         */

        Polygons& supportLayer_this = overhang;

        supportLayer_this = supportLayer_this.simplify(50); // TODO: hardcoded value!

        if (supportMinAreaSqrt > 0)
        {
            // handle straight walls
            AreaSupport::handleWallStruts(supportLayer_this, supportMinAreaSqrt, supportTowerDiameter);
            // handle towers
            AreaSupport::handleTowers(supportLayer_this, towerRoofs, overhang_points, overhang_points_pos, layer_idx, towerRoofExpansionDistance, supportTowerDiameter, supportMinAreaSqrt, layer_count, z_layer_distance_tower);
        }

        if (layer_idx+1 < support_layer_count)
        { // join with support from layer up
            Polygons& supportLayer_up = supportLayer_last;

            Polygons joined = supportLayer_this.unionPolygons(supportLayer_up);
            // join different parts
            if (supportJoinDistance > 0)
            {
                joined = joined.offset(supportJoinDistance);
                joined = joined.offset(-supportJoinDistance);
            }
            if (smoothing_distance > 0)
                joined = joined.smooth(smoothing_distance, min_smoothing_area);

            // remove layer
            Polygons insetted = joined.difference(joinedLayers[layer_idx]);
            supportLayer_this = insetted;

        }

        supportLayer_last = supportLayer_this;

        // inset using X/Y distance
        if (supportLayer_this.size() > 0)
            supportLayer_this = supportLayer_this.difference(joinedLayers[layer_idx].offset(supportXYDistance));

        // move up from model
        if (layerZdistanceBottom > 0 && layer_idx >= layerZdistanceBottom)
        {
            int stepHeight = supportBottomStairDistance / supportLayerThickness + 1;
            int bottomLayer = ((layer_idx - layerZdistanceBottom) / stepHeight) * stepHeight;
            supportLayer_this = supportLayer_this.difference(joinedLayers[bottomLayer]);
        }

        storage.support.supportAreasPerLayer[layer_idx] = supportLayer_this;

    }

    // do stuff for when support on buildplate only
    if (supportOnBuildplateOnly)
    {
        Polygons touching_buildplate = storage.support.supportAreasPerLayer[0];
        for (unsigned int layer_idx = 1 ; layer_idx < storage.support.supportAreasPerLayer.size() ; layer_idx++)
        {
            Polygons& supportLayer = storage.support.supportAreasPerLayer[layer_idx];

            touching_buildplate = supportLayer.intersection(touching_buildplate); // from bottom to top, support areas can only decrease!

            storage.support.supportAreasPerLayer[layer_idx] = touching_buildplate;
        }
    }

    joinedLayers.clear();

    storage.support.generated = true;
}

void AreaSupport::joinMeshesAndDetectOverhangPoints(
    SliceDataStorage& storage,
    std::vector<Polygons>& joinedLayers,
    std::vector<std::pair<int, std::vector<Polygons>>>& overhang_points, // stores overhang_points along with the layer index at which the overhang point occurs)
    int layer_count,
    int supportMinAreaSqrt,
    int extrusionWidth
                  )
{
    for (int layer_idx = 0 ; layer_idx < layer_count ; layer_idx++)
    {
        joinedLayers.emplace_back();
        for (SliceMeshStorage& mesh : storage.meshes)
        {
            SliceLayer& layer = mesh.layers[layer_idx];
            for (SliceLayerPart& part : layer.parts)
            {

                if (part.outline[0].area() < supportMinAreaSqrt * supportMinAreaSqrt)
                {
                    Polygons part_poly = part.outline.offset(-extrusionWidth/2);
                    if (part_poly.size() > 0)
                    {
                        if (overhang_points.size() > 0 && overhang_points.back().first == layer_idx)
                            overhang_points.back().second.push_back(part_poly);
                        else
                        {
                            std::vector<Polygons> small_part_polys;
                            small_part_polys.push_back(part_poly);
                            overhang_points.emplace_back<std::pair<int, std::vector<Polygons>>>(std::make_pair(layer_idx, small_part_polys));
                        }
                    }

                }
                joinedLayers.back() = joinedLayers.back().unionPolygons(part.outline);

            }
        }
    }
}

void AreaSupport::handleTowers(
    Polygons& supportLayer_this,
    std::vector<Polygons>& towerRoofs,
    std::vector<std::pair<int, std::vector<Polygons>>>& overhang_points,
    int& overhang_points_pos,
    int layer_idx,
    int towerRoofExpansionDistance,
    int supportTowerDiameter,
    int supportMinAreaSqrt,
    int layer_count,
    int z_layer_distance_tower
)
{
    // handle new tower roof tops
    int layer_overhang_point =  layer_idx + z_layer_distance_tower;
    if (overhang_points_pos >= 0 && layer_overhang_point < layer_count &&
        overhang_points[overhang_points_pos].first == layer_overhang_point)
    {
        std::vector<Polygons>& overhang_points_here = overhang_points[overhang_points_pos].second;
        { // make sure we have the lowest point (make polys empty if they have small parts below)
            if (overhang_points_pos > 0 && overhang_points[overhang_points_pos - 1].first == layer_overhang_point - 1)
            {
                std::vector<Polygons>& overhang_points_below = overhang_points[overhang_points_pos - 1].second;
                for (Polygons& poly_here : overhang_points_here)
                {
                    for (Polygons& poly_below : overhang_points_below)
                    {
                        poly_here = poly_here.difference(poly_below.offset(supportMinAreaSqrt*2));
                    }
                }
            }
        }
        for (Polygons& poly : overhang_points_here)
            if (poly.size() > 0)
                towerRoofs.push_back(poly);
        overhang_points_pos--;
    }

    // make tower roofs
    //for (Polygons& tower_roof : towerRoofs)
    for (unsigned int r = 0; r < towerRoofs.size(); r++)
    {
        supportLayer_this = supportLayer_this.unionPolygons(towerRoofs[r]);

        Polygons& tower_roof = towerRoofs[r];
        if (tower_roof.size() > 0 && tower_roof[0].area() < supportTowerDiameter * supportTowerDiameter)
        {
            towerRoofs[r] = tower_roof.offset(towerRoofExpansionDistance);
        }
    }
}

void AreaSupport::handleWallStruts(
    Polygons& supportLayer_this,
    int supportMinAreaSqrt,
    int supportTowerDiameter
    )
{
    for (unsigned int p = 0; p < supportLayer_this.size(); p++)
    {
        PolygonRef poly = supportLayer_this[p];
        if (poly.size() < 6) // might be a single wall
        {
            PolygonRef poly = supportLayer_this[p];
            int best = -1;
            int best_length2 = -1;
            for (unsigned int i = 0; i < poly.size(); i++)
            {
                int length2 = vSize2(poly[i] - poly[(i+1) % poly.size()]);
                if (length2 > best_length2)
                {
                    best = i;
                    best_length2 = length2;
                }
            }

            if (best_length2 < supportMinAreaSqrt * supportMinAreaSqrt)
                break; // this is a small area, not a wall!

            // an estimate of the width of the area
            int width = sqrt( poly.area() * poly.area() / best_length2 ); // sqrt (a^2 / l^2) instead of a / sqrt(l^2)

            // add square tower (strut) in the middle of the wall
            if (width < supportMinAreaSqrt)
            {
                Point mid = (poly[best] + poly[(best+1) % poly.size()] ) / 2;
                Polygons struts;
                PolygonRef strut = struts.newPoly();
                strut.add(mid + Point( supportTowerDiameter/2,  supportTowerDiameter/2));
                strut.add(mid + Point(-supportTowerDiameter/2,  supportTowerDiameter/2));
                strut.add(mid + Point(-supportTowerDiameter/2, -supportTowerDiameter/2));
                strut.add(mid + Point( supportTowerDiameter/2, -supportTowerDiameter/2));
                supportLayer_this = supportLayer_this.unionPolygons(struts);
            }
        }
    }
}

}//namespace cura
<|endoftext|>


<commit_before>#include <glbinding/logging.h>

#include <atomic>
#include <condition_variable>
#include <fstream>
#include <mutex>
#include <sstream>
#include <thread>

#include "RingBuffer.h"

namespace
{
    const unsigned int LOG_BUFFER_SIZE = 1000000;

    std::atomic<bool> g_stop{false};
    std::atomic<bool> g_persisted{false};
    std::mutex g_lockfinish;
    std::condition_variable g_finishcheck;

    using FunctionCallBuffer = glbinding::RingBuffer<glbinding::logging::BufferType>;
    FunctionCallBuffer g_buffer{LOG_BUFFER_SIZE};
}

namespace glbinding
{

namespace logging
{

void start()
{
    auto now = std::chrono::system_clock::now();

    auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    auto ms = now_ms.count() % 1000;

    auto now_c = std::chrono::system_clock::to_time_t(now);
    char time_string[20];
    std::strftime(time_string, sizeof(time_string), "%Y-%m-%d_%H-%M-%S", std::localtime(&now_c));

    std::ostringstream ms_os;
    ms_os << std::setfill('0') << std::setw(3) << ms;

    std::ostringstream os;
    os << "logs/";
    os << time_string << "-" << ms_os.str();
    os << ".log";

    auto logname = os.str();

    start(logname);
}

void start(const std::string & filepath)
{
    addCallbackMask(CallbackMask::Logging);

    g_stop = false;
    g_persisted = false;

    std::thread writer([filepath]()
    {
        auto key = g_buffer.addTail();
        std::ofstream logfile;
        logfile.open (filepath, std::ios::out);

        while (!g_stop || (g_buffer.size(key) != 0))
        {
            auto i = g_buffer.cbegin(key);

            while (g_buffer.valid(key, i))
            {
                logfile << (*i)->toString();
                i = g_buffer.next(key, i);
            }

            logfile.flush();

            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }

        logfile.close();
        g_buffer.removeTail(key);
        g_persisted = true;
        g_finishcheck.notify_all();
    });

    writer.detach();
}

void stop()
{
    g_stop = true;
    std::unique_lock<std::mutex> locker(g_lockfinish);

    // Spurious wake-ups: http://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables
    while(!g_persisted)
    {
        g_finishcheck.wait(locker);
    }

    removeCallbackMask(CallbackMask::Logging);
}

void pause()
{
    removeCallbackMask(CallbackMask::Logging);
}

void resume()
{
    addCallbackMask(CallbackMask::Logging);
}

void log(bool enable)
{
    if (enable)
    {
        start();
    }
    else
    {
        stop();
    }
}

void log(FunctionCall * call)
{
    bool available = false;
    auto next = g_buffer.nextHead(available);

    while (!available)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        next = g_buffer.nextHead(available);
    }

    assert(!g_buffer.isFull());

    delete next;
    g_buffer.push(call);
}

TailIdentifier addTail()
{
    return g_buffer.addTail();
}

void removeTail(TailIdentifier key)
{
    g_buffer.removeTail(key);
}

const std::vector<BufferType>::const_iterator cbegin(TailIdentifier key)
{
    return g_buffer.cbegin(key);
}

bool valid(TailIdentifier key, const std::vector<BufferType>::const_iterator & it)
{
    return g_buffer.valid(key, it);
}

const std::vector<BufferType>::const_iterator next(TailIdentifier key, const std::vector<BufferType>::const_iterator & it)
{
    return g_buffer.next(key, it);
}

unsigned int size(TailIdentifier key)
{
    return g_buffer.size(key);
}

} // namespace logging
} // namespace glbinding
<commit_msg>Change position of removing Callback mask<commit_after>#include <glbinding/logging.h>

#include <atomic>
#include <condition_variable>
#include <fstream>
#include <mutex>
#include <sstream>
#include <thread>

#include "RingBuffer.h"

namespace
{
    const unsigned int LOG_BUFFER_SIZE = 1000000;

    std::atomic<bool> g_stop{false};
    std::atomic<bool> g_persisted{false};
    std::mutex g_lockfinish;
    std::condition_variable g_finishcheck;

    using FunctionCallBuffer = glbinding::RingBuffer<glbinding::logging::BufferType>;
    FunctionCallBuffer g_buffer{LOG_BUFFER_SIZE};
}

namespace glbinding
{

namespace logging
{

void start()
{
    auto now = std::chrono::system_clock::now();

    auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    auto ms = now_ms.count() % 1000;

    auto now_c = std::chrono::system_clock::to_time_t(now);
    char time_string[20];
    std::strftime(time_string, sizeof(time_string), "%Y-%m-%d_%H-%M-%S", std::localtime(&now_c));

    std::ostringstream ms_os;
    ms_os << std::setfill('0') << std::setw(3) << ms;

    std::ostringstream os;
    os << "logs/";
    os << time_string << "-" << ms_os.str();
    os << ".log";

    auto logname = os.str();

    start(logname);
}

void start(const std::string & filepath)
{
    addCallbackMask(CallbackMask::Logging);

    g_stop = false;
    g_persisted = false;

    std::thread writer([filepath]()
    {
        auto key = g_buffer.addTail();
        std::ofstream logfile;
        logfile.open (filepath, std::ios::out);

        while (!g_stop || (g_buffer.size(key) != 0))
        {
            auto i = g_buffer.cbegin(key);

            while (g_buffer.valid(key, i))
            {
                logfile << (*i)->toString();
                i = g_buffer.next(key, i);
            }

            logfile.flush();

            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }

        logfile.close();
        g_buffer.removeTail(key);
        g_persisted = true;
        g_finishcheck.notify_all();
    });

    writer.detach();
}

void stop()
{
    removeCallbackMask(CallbackMask::Logging);

    g_stop = true;
    std::unique_lock<std::mutex> locker(g_lockfinish);

    // Spurious wake-ups: http://www.codeproject.com/Articles/598695/Cplusplus-threads-locks-and-condition-variables
    while(!g_persisted)
    {
        g_finishcheck.wait(locker);
    }
}

void pause()
{
    removeCallbackMask(CallbackMask::Logging);
}

void resume()
{
    addCallbackMask(CallbackMask::Logging);
}

void log(bool enable)
{
    if (enable)
    {
        start();
    }
    else
    {
        stop();
    }
}

void log(FunctionCall * call)
{
    bool available = false;
    auto next = g_buffer.nextHead(available);

    while (!available)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        next = g_buffer.nextHead(available);
    }

    assert(!g_buffer.isFull());

    delete next;
    g_buffer.push(call);
}

TailIdentifier addTail()
{
    return g_buffer.addTail();
}

void removeTail(TailIdentifier key)
{
    g_buffer.removeTail(key);
}

const std::vector<BufferType>::const_iterator cbegin(TailIdentifier key)
{
    return g_buffer.cbegin(key);
}

bool valid(TailIdentifier key, const std::vector<BufferType>::const_iterator & it)
{
    return g_buffer.valid(key, it);
}

const std::vector<BufferType>::const_iterator next(TailIdentifier key, const std::vector<BufferType>::const_iterator & it)
{
    return g_buffer.next(key, it);
}

unsigned int size(TailIdentifier key)
{
    return g_buffer.size(key);
}

} // namespace logging
} // namespace glbinding
<|endoftext|>


<commit_before>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef configmanager_hh
#define configmanager_hh

#include <string>
#include <list>
#include <cstdlib>

#include "common.hh"

enum ConfigValueType{
	Boolean,
	Integer,
	String,
	StringList,
	Struct
};

struct ConfigItemDescriptor {
	ConfigValueType type;
	const char *name;
	const char *help;
	const char *default_value;
};

static const ConfigItemDescriptor config_item_end={Boolean,NULL,NULL,NULL};

class ConfigEntry{
	public:
		const std::string & getName()const{
			return mName;
		}
		ConfigValueType getType()const{
			return mType;
		}
		const std::string &getHelp()const{
			return mHelp;
		}
		ConfigEntry *getParent()const{
			return mParent;
		}
		virtual ~ConfigEntry(){
		}
		void setParent(ConfigEntry *parent);
	protected:
		ConfigEntry(const std::string &name, ConfigValueType type, const std::string &help);
	private:
		const std::string mName;
		const std::string mHelp;
		ConfigValueType mType;
		ConfigEntry *mParent;
};

class ConfigValue;

class ConfigStruct : public ConfigEntry{
	public:
		ConfigStruct(const std::string &name, const std::string &help);
		ConfigEntry * addChild(ConfigEntry *c);
		void addChildrenValues(ConfigItemDescriptor *items);
		std::list<ConfigEntry*> &getChildren();
		template <typename _retType>
		_retType *get(const char *name)const;
		~ConfigStruct();
		ConfigEntry *find(const char *name)const;
		ConfigEntry *findApproximate(const char *name)const;
	private:
		std::list<ConfigEntry*> mEntries;
};

class ConfigValue : public ConfigEntry{
	public:
		ConfigValue(const std::string &name, ConfigValueType  vt, const std::string &help, const std::string &default_value);
		void set(const std::string &value);
		const std::string &get()const;
		const std::string &getDefault()const;
		void setDefault(const std::string &value);
	private:
		std::string mValue;
		std::string mDefaultValue;
};

class ConfigBoolean : public ConfigValue{
	public:
		ConfigBoolean(const std::string &name, const std::string &help, const std::string &default_value);
		bool read()const;
};

class ConfigInt : public ConfigValue{
	public:
		ConfigInt(const std::string &name, const std::string &help, const std::string &default_value);
		int read()const;
};

class ConfigString : public ConfigValue{
	public:
		ConfigString(const std::string &name, const std::string &help, const std::string &default_value);
		const std::string & read()const;
};

class ConfigStringList : public ConfigValue{
	public:
		ConfigStringList(const std::string &name, const std::string &help, const std::string &default_value);
		std::list<std::string> read()const;
	private:
};

template <typename _retType>
_retType *ConfigStruct::get(const char *name)const{
	ConfigEntry *e=find(name);
	if (e==NULL) {
		LOGA("No ConfigEntry with name %s in struct %s",name,getName().c_str());
		return NULL;
	}
	_retType *ret=dynamic_cast<_retType *>(e);
	if (ret==NULL){
		LOGA("Config entry %s in struct %s does not have the expected type",name,e->getParent()->getName().c_str());
		return NULL;
	}
	return ret;
};

class FileConfigReader{
	public:
		FileConfigReader(ConfigStruct *root) : mRoot(root), mCfg(NULL), mHaveUnreads(false){
		}
		int read(const char *filename);
		int reload();
		void checkUnread();
		~FileConfigReader();
	private:
		int read2(ConfigEntry *entry, int level);
		static void onUnreadItem(void *p, const char *secname, const char *key, int lineno);
		void onUnreadItem(const char *secname, const char *key, int lineno);
		ConfigStruct *mRoot;
		struct _LpConfig *mCfg;
		bool mHaveUnreads;
};

class ConfigManager{
	friend class ConfigArea;
	public:
		static ConfigManager *get();
		void declareArea(const char *area_name, const char *help, ConfigItemDescriptor *items);
		int load(const char* configFile);
		ConfigStruct *getRoot();
		const ConfigStruct *getGlobal();
		void loadStrict();
	private:
		ConfigManager();
		static void atexit(); // Don't call directly!
		ConfigStruct mConfigRoot;
		FileConfigReader mReader;
		static ConfigManager *sInstance;
};

class FileConfigDumper{
	public:
		FileConfigDumper(ConfigStruct *root){
			mRoot=root;
		}
		std::ostream &dump(std::ostream & ostr)const;
	private:
		std::ostream & printHelp(std::ostream &os, const std::string &help, const std::string &comment_prefix)const;
		std::ostream &dump2(std::ostream & ostr, ConfigEntry *entry, int level)const;
		ConfigStruct *mRoot;
};

inline std::ostream & operator<<(std::ostream &ostr, const FileConfigDumper &dumper){
	return dumper.dump(ostr);
}

#endif
<commit_msg>Fix compilation.<commit_after>/*
	Flexisip, a flexible SIP proxy server with media capabilities.
    Copyright (C) 2010  Belledonne Communications SARL.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef configmanager_hh
#define configmanager_hh

#include <string>
#include <list>
#include <cstdlib>

#include "common.hh"

enum ConfigValueType{
	Boolean,
	Integer,
	String,
	StringList,
	Struct
};

struct ConfigItemDescriptor {
	ConfigValueType type;
	const char *name;
	const char *help;
	const char *default_value;
};

static const ConfigItemDescriptor config_item_end={Boolean,NULL,NULL,NULL};

class ConfigEntry{
	public:
		const std::string & getName()const{
			return mName;
		}
		ConfigValueType getType()const{
			return mType;
		}
		const std::string &getHelp()const{
			return mHelp;
		}
		ConfigEntry *getParent()const{
			return mParent;
		}
		virtual ~ConfigEntry(){
		}
		void setParent(ConfigEntry *parent);
	protected:
		ConfigEntry(const std::string &name, ConfigValueType type, const std::string &help);
	private:
		const std::string mName;
		const std::string mHelp;
		ConfigValueType mType;
		ConfigEntry *mParent;
};

class ConfigValue;

class ConfigStruct : public ConfigEntry{
	public:
		ConfigStruct(const std::string &name, const std::string &help);
		ConfigEntry * addChild(ConfigEntry *c);
		void addChildrenValues(ConfigItemDescriptor *items);
		std::list<ConfigEntry*> &getChildren();
		template <typename _retType>
		_retType *get(const char *name)const;
		~ConfigStruct();
		ConfigEntry *find(const char *name)const;
		ConfigEntry *findApproximate(const char *name)const;
	private:
		std::list<ConfigEntry*> mEntries;
};

class ConfigValue : public ConfigEntry{
	public:
		ConfigValue(const std::string &name, ConfigValueType  vt, const std::string &help, const std::string &default_value);
		void set(const std::string &value);
		const std::string &get()const;
		const std::string &getDefault()const;
		void setDefault(const std::string &value);
	private:
		std::string mValue;
		std::string mDefaultValue;
};

class ConfigBoolean : public ConfigValue{
	public:
		ConfigBoolean(const std::string &name, const std::string &help, const std::string &default_value);
		bool read()const;
};

class ConfigInt : public ConfigValue{
	public:
		ConfigInt(const std::string &name, const std::string &help, const std::string &default_value);
		int read()const;
};

class ConfigString : public ConfigValue{
	public:
		ConfigString(const std::string &name, const std::string &help, const std::string &default_value);
		const std::string & read()const;
};

class ConfigStringList : public ConfigValue{
	public:
		ConfigStringList(const std::string &name, const std::string &help, const std::string &default_value);
		std::list<std::string> read()const;
	private:
};

template <typename _retType>
_retType *ConfigStruct::get(const char *name)const{
	ConfigEntry *e=find(name);
	if (e==NULL) {
		LOGA("No ConfigEntry with name %s in struct %s",name,getName().c_str());
		return NULL;
	}
	_retType *ret=dynamic_cast<_retType *>(e);
	if (ret==NULL){
		LOGA("Config entry %s in struct %s does not have the expected type",name,e->getParent()->getName().c_str());
		return NULL;
	}
	return ret;
};

class FileConfigReader{
	public:
		FileConfigReader(ConfigStruct *root) : mRoot(root),mCfg(NULL),mHaveUnreads(false){
		}
		int read(const char *filename);
		int reload();
		void checkUnread();
		~FileConfigReader();
	private:
		int read2(ConfigEntry *entry, int level);
		static void onUnreadItem(void *p, const char *secname, const char *key, int lineno);
		void onUnreadItem(const char *secname, const char *key, int lineno);
		ConfigStruct *mRoot;
		struct _LpConfig *mCfg;
		bool mHaveUnreads;
};

class ConfigManager{
	friend class ConfigArea;
	public:
		static ConfigManager *get();
		void declareArea(const char *area_name, const char *help, ConfigItemDescriptor *items);
		int load(const char* configFile);
		ConfigStruct *getRoot();
		const ConfigStruct *getGlobal();
		void loadStrict();
	private:
		ConfigManager();
		static void atexit(); // Don't call directly!
		ConfigStruct mConfigRoot;
		FileConfigReader mReader;
		static ConfigManager *sInstance;
};

class FileConfigDumper{
	public:
		FileConfigDumper(ConfigStruct *root){
			mRoot=root;
		}
		std::ostream &dump(std::ostream & ostr)const;
	private:
		std::ostream & printHelp(std::ostream &os, const std::string &help, const std::string &comment_prefix)const;
		std::ostream &dump2(std::ostream & ostr, ConfigEntry *entry, int level)const;
		ConfigStruct *mRoot;
};

inline std::ostream & operator<<(std::ostream &ostr, const FileConfigDumper &dumper){
	return dumper.dump(ostr);
}

#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include <dukat/sysutil.h>
#include <dukat/log.h>

#ifndef WIN32
#include <dirent.h>
#endif

namespace dukat
{
	void gl_check_error(void)
	{
		GLenum err;
		while (GL_NO_ERROR != (err = glGetError()))
		{
			std::string error;
			switch (err)
			{
				case GL_INVALID_ENUM:
					error = "GL_INVALID_ENUM";
					break;
				case GL_INVALID_VALUE:
					error = "GL_INVALID_VALUE";
					break;
				case GL_INVALID_OPERATION:
					error = "GL_INVALID_OPERATION";
					break;
				case GL_INVALID_FRAMEBUFFER_OPERATION:
					error = "GL_INVALID_FRAMEBUFFER_OPERATION";
					break;
				case GL_OUT_OF_MEMORY:
					error = "GL_OUT_OF_MEMORY";
					break;
#ifndef __ANDROID__
				case GL_STACK_UNDERFLOW:
					error = "GL_STACK_UNDERFLOW";
					break;
				case GL_STACK_OVERFLOW:
					error = "GL_STACK_OVERFLOW";
					break;
#endif
				default:
					error = "unknown";
					break;
			}
			log->error("glError: {}", error);
		}
	}

	void crash_dump(const std::vector<std::string>& paths)
	{
		const auto now = time(nullptr);
		const auto dir_name = "crash_" + std::to_string(now);
		if (!create_directory(dir_name))
		{
			log->error("Failed to create crash dir: {}", dir_name);
			return;
		}

		for (const auto& it : paths)
		{
			if (file_exists(it))
			{
				const auto name = file_name(it);
				copy_file(it, dir_name + "/" + name);
			}
		}
	}

	bool file_exists(const std::string& path)
	{
		struct stat tmp;
		return stat(path.c_str(), &tmp) == 0;
	}

	bool directory_exists(const std::string& path)
	{
		struct stat tmp;
		return (stat(path.c_str(), &tmp) == 0) && (tmp.st_mode & S_IFDIR);
	}

	bool create_directory(const std::string& path)
	{
#ifdef WIN32
		auto res = _mkdir(path.c_str());
#else
		mode_t mode = 0755;
		auto res = mkdir(path.c_str(), mode);
#endif
		return (res == 0);
	}

	bool copy_file(const std::string& source, const std::string& dest)
	{
		std::ifstream src(source, std::ios::binary);
		if (!src)
			return false;

		std::ofstream dst(dest, std::ios::binary);
		if (!dst)
			return false;

		dst << src.rdbuf();

		return true;
	}

	std::vector<std::string> list_files(const std::string& path)
	{
		std::vector<std::string> res;
#ifdef WIN32
		// TODO: implement
#else
		auto ptr = opendir(path.c_str());
		if (ptr)
		{
			dirent* fp;
			while ((fp = readdir(ptr)) != nullptr)
				res.push_back(std::string(fp->d_name));
			closedir(ptr);
		}
#endif
		return res;
	}
}<commit_msg>Implemented win32 version of list_files<commit_after>#include "stdafx.h"
#include <dukat/sysutil.h>
#include <dukat/log.h>

#ifndef WIN32
#include <dirent.h>
#endif

namespace dukat
{
	void gl_check_error(void)
	{
		GLenum err;
		while (GL_NO_ERROR != (err = glGetError()))
		{
			std::string error;
			switch (err)
			{
				case GL_INVALID_ENUM:
					error = "GL_INVALID_ENUM";
					break;
				case GL_INVALID_VALUE:
					error = "GL_INVALID_VALUE";
					break;
				case GL_INVALID_OPERATION:
					error = "GL_INVALID_OPERATION";
					break;
				case GL_INVALID_FRAMEBUFFER_OPERATION:
					error = "GL_INVALID_FRAMEBUFFER_OPERATION";
					break;
				case GL_OUT_OF_MEMORY:
					error = "GL_OUT_OF_MEMORY";
					break;
#ifndef __ANDROID__
				case GL_STACK_UNDERFLOW:
					error = "GL_STACK_UNDERFLOW";
					break;
				case GL_STACK_OVERFLOW:
					error = "GL_STACK_OVERFLOW";
					break;
#endif
				default:
					error = "unknown";
					break;
			}
			log->error("glError: {}", error);
		}
	}

	void crash_dump(const std::vector<std::string>& paths)
	{
		const auto now = time(nullptr);
		const auto dir_name = "crash_" + std::to_string(now);
		if (!create_directory(dir_name))
		{
			log->error("Failed to create crash dir: {}", dir_name);
			return;
		}

		for (const auto& it : paths)
		{
			if (file_exists(it))
			{
				const auto name = file_name(it);
				copy_file(it, dir_name + "/" + name);
			}
		}
	}

	bool file_exists(const std::string& path)
	{
		struct stat tmp;
		return stat(path.c_str(), &tmp) == 0;
	}

	bool directory_exists(const std::string& path)
	{
		struct stat tmp;
		return (stat(path.c_str(), &tmp) == 0) && (tmp.st_mode & S_IFDIR);
	}

	bool create_directory(const std::string& path)
	{
#ifdef WIN32
		auto res = _mkdir(path.c_str());
#else
		mode_t mode = 0755;
		auto res = mkdir(path.c_str(), mode);
#endif
		return (res == 0);
	}

	bool copy_file(const std::string& source, const std::string& dest)
	{
		std::ifstream src(source, std::ios::binary);
		if (!src)
			return false;

		std::ofstream dst(dest, std::ios::binary);
		if (!dst)
			return false;

		dst << src.rdbuf();

		return true;
	}

	std::vector<std::string> list_files(const std::string& path)
	{
		std::vector<std::string> res;
#ifdef WIN32
		const auto filename = path + "\\*";
		WIN32_FIND_DATAA data;
		auto handle = FindFirstFileA(filename.c_str(), &data);
		if (handle == INVALID_HANDLE_VALUE)
			return res;
		do
		{
			if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
			{
				res.push_back(std::string(data.cFileName));
			}
		}
		while (FindNextFileA(handle, &data) != 0);
		FindClose(handle);
#else
		auto ptr = opendir(path.c_str());
		if (ptr)
		{
			dirent* fp;
			while ((fp = readdir(ptr)) != nullptr)
				res.push_back(std::string(fp->d_name));
			closedir(ptr);
		}
#endif
		return res;
	}
}<|endoftext|>