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

#include <assert.h>
#include <stdio.h>
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>

#include "app/src/assert.h"
#include "app/src/cleanup_notifier.h"
#include "app/src/include/firebase/app.h"
#include "app/src/include/firebase/future.h"
#include "app/src/include/firebase/internal/common.h"
#include "app/src/include/firebase/version.h"
#include "app/src/mutex.h"
#include "app/src/semaphore.h"
#include "app/src/util.h"
#include "auth/src/common.h"
#include "auth/src/data.h"
#include "auth/src/include/firebase/auth.h"

// Workaround MSVC's incompatible libc headers.
#ifdef _WIN32
#define snprintf _snprintf
#endif  // _WIN32

// Register the module initializer.
FIREBASE_APP_REGISTER_CALLBACKS(
    auth,
    {
      FIREBASE_UTIL_RETURN_FAILURE_IF_GOOGLE_PLAY_UNAVAILABLE(*app);
      return ::firebase::kInitResultSuccess;
    },
    {
        // Nothing to tear down.
    });

namespace firebase {
namespace auth {

DEFINE_FIREBASE_VERSION_STRING(FirebaseAuth);

// The global map of Apps to Auths. Each App can have at most one Auth,
// and an Auth requires an App. So, the user acquires the Auth via an App
// reference.
// TODO(jsanmiya): Ensure all the Auths are destroyed on shutdown.
std::map<App*, Auth*> g_auths;
Mutex g_auths_mutex;  // NOLINT

// static
Auth* Auth::GetAuth(App* app, InitResult* init_result_out) {
  MutexLock lock(g_auths_mutex);
  // Return the Auth if it already exists.
  std::map<App*, Auth*>::iterator it = g_auths.find(app);
  if (it != g_auths.end()) {
    if (init_result_out != nullptr) *init_result_out = kInitResultSuccess;
    return it->second;
  }
  FIREBASE_UTIL_RETURN_NULL_IF_GOOGLE_PLAY_UNAVAILABLE(*app, init_result_out);

  // Create the platform dependent version of Auth.
  void* auth_impl = CreatePlatformAuth(app, app->data_);
  if (!auth_impl) return nullptr;

  // Create a new Auth and initialize.
  Auth* auth = new Auth(app, auth_impl);
  LogDebug("Creating Auth %p for App %p", auth, app);

  // Stick it in the global map so we remember it, and can delete it on
  // shutdown.
  g_auths[app] = auth;

  if (init_result_out) *init_result_out = kInitResultSuccess;
  return auth;
}

// Auth uses the pimpl mechanism to hide internal data types from the interface.
Auth::Auth(App* app, void* auth_impl) : auth_data_(new AuthData) {
  FIREBASE_ASSERT(app != nullptr && auth_impl != nullptr);
  auth_data_->app = app;
  auth_data_->auth = this;
  auth_data_->auth_impl = auth_impl;
  InitPlatformAuth(auth_data_);

  std::string* future_id = &auth_data_->future_api_id;
  static const char* kApiIdentifier = "Auth";
  future_id->reserve(strlen(kApiIdentifier) +
                     16 /* hex characters in the pointer */ +
                     1 /* null terminator */);
  snprintf(&((*future_id)[0]), future_id->capacity(), "%s0x%016llx",
           kApiIdentifier,
           static_cast<unsigned long long>(  // NOLINT
               reinterpret_cast<intptr_t>(this)));

  // Cleanup this object if app is destroyed.
  CleanupNotifier* notifier = CleanupNotifier::FindByOwner(app);
  assert(notifier);
  notifier->RegisterObject(this, [](void* object) {
    Auth* auth = reinterpret_cast<Auth*>(object);
    LogWarning(
        "Auth object 0x%08x should be deleted before the App 0x%08x it "
        "depends upon.",
        static_cast<int>(reinterpret_cast<intptr_t>(auth)),
        static_cast<int>(reinterpret_cast<intptr_t>(auth->auth_data_->app)));
    auth->DeleteInternal();
  });
}

void Auth::DeleteInternal() {
  MutexLock lock(g_auths_mutex);

  if (!auth_data_) return;

  CleanupNotifier* notifier = CleanupNotifier::FindByOwner(auth_data_->app);
  assert(notifier);
  notifier->UnregisterObject(this);

  int num_auths_remaining = 0;
  {
    // Remove `this` from the g_auths map.
    // The mapping is 1:1, so we should only ever delete one.
    for (auto it = g_auths.begin(); it != g_auths.end(); ++it) {
      if (it->second == this) {
        LogDebug("Deleting Auth %p for App %p", this, it->first);
        g_auths.erase(it);
        break;
      }
    }

    num_auths_remaining = g_auths.size();
  }

  auth_data_->ClearListeners();

  // If this is the last Auth instance to be cleaned up, also clean up data for
  // Credentials.
  if (num_auths_remaining == 0) {
    CleanupCredentialFutureImpl();
  }

  // Destroy the platform-specific object.
  DestroyPlatformAuth(auth_data_);

  // Delete the pimpl data.
  delete auth_data_;
  auth_data_ = nullptr;
}

Auth::~Auth() { DeleteInternal(); }

// It's safe to return a direct pointer to `current_user` because that class
// holds nothing but a pointer to AuthData, which never changes.
// All User functions that require synchronization go through AuthData's mutex.
User* Auth::current_user() {
  MutexLock lock(auth_data_->future_impl.mutex());
  User* user =
      auth_data_->user_impl == nullptr ? nullptr : &auth_data_->current_user;
  return user;
}

// Always non-nullptr since set in constructor.
App& Auth::app() { return *auth_data_->app; }

template <typename T>
static bool PushBackIfMissing(const T& entry, std::vector<T>* v) {
  auto it = std::find(v->begin(), v->end(), entry);
  if (it != v->end()) return false;

  v->push_back(entry);
  return true;
}

// Store a unique listener of type T in a listener_vector and unique auth
// object in auth_vector.  Both vectors must be in sync, i.e addition must
// either succeed or fail otherwise this method asserts.
template <typename T>
static void AddListener(T listener, std::vector<T>* listener_vector, Auth* auth,
                        std::vector<Auth*>* auth_vector, Mutex* mutex) {
  MutexLock lock(*mutex);
  // Add to array of listeners if not already there.
  const bool listener_added = PushBackIfMissing(listener, listener_vector);
  // Add auth to array of Auths if not already there.
  const bool auth_added = PushBackIfMissing(auth, auth_vector);

  // The listener and Auth should either point at each other or not point
  // at each other.
  FIREBASE_ASSERT_RETURN_VOID(listener_added == auth_added);
  (void)auth_added;
  (void)listener_added;
}

void Auth::AddAuthStateListener(AuthStateListener* listener) {
  AddListener(listener, &auth_data_->listeners, this, &listener->auths_,
              &auth_data_->listeners_mutex);
}

void Auth::AddIdTokenListener(IdTokenListener* listener) {
  int listener_count = auth_data_->id_token_listeners.size();
  AddListener(listener, &auth_data_->id_token_listeners, this,
              &listener->auths_, &auth_data_->listeners_mutex);
  // AddListener is valid even if the listener is already registered.
  // This makes sure that we only increase the reference count if a listener
  // was actually added.
  if (auth_data_->id_token_listeners.size() > listener_count) {
    EnableTokenAutoRefresh(auth_data_);
  }
}

template <typename T>
static bool ReplaceEntryWithBack(const T& entry, std::vector<T>* v) {
  auto it = std::find(v->begin(), v->end(), entry);
  if (it == v->end()) return false;

#if defined(FIREBASE_USE_MOVE_OPERATORS)
  *it = std::move(v->back());
#else
  *it = v->back();
#endif  // defined(FIREBASE_USE_MOVE_OPERATORS)

  v->pop_back();
  return true;
}

// Remove a listener of type T from listener_vector and unique auth object in
// auth_vector.  Both vectors must be in sync, i.e addition must either
// succeed or fail otherwise this method asserts.
template <typename T>
static void RemoveListener(T listener, std::vector<T>* listener_vector,
                           Auth* auth, std::vector<Auth*>* auth_vector,
                           Mutex* mutex) {
  MutexLock lock(*mutex);
  // Remove `listener` from our vector of listeners.
  ReplaceEntryWithBack(listener, listener_vector);
  // Remove this Auth from the listener's vector of Auths.
  // This ensures the listener doesn't try to unregister itself again when it is
  // destroyed.
  ReplaceEntryWithBack(auth, auth_vector);
}

void Auth::RemoveAuthStateListener(AuthStateListener* listener) {
  RemoveListener(listener, &auth_data_->listeners, this, &listener->auths_,
                 &auth_data_->listeners_mutex);
}

void Auth::RemoveIdTokenListener(IdTokenListener* listener) {
  int listener_count = auth_data_->id_token_listeners.size();
  RemoveListener(listener, &auth_data_->id_token_listeners, this,
                 &listener->auths_, &auth_data_->listeners_mutex);
  // RemoveListener is valid even if the listener is not registered.
  // This makes sure that we only decrease the reference count if a listener
  // was actually removed.
  if (auth_data_->id_token_listeners.size() < listener_count) {
    DisableTokenAutoRefresh(auth_data_);
  }
}

AuthStateListener::~AuthStateListener() {
  // Removing the listener edits the auths list, hence the while loop.
  while (!auths_.empty()) {
    (*auths_.begin())->RemoveAuthStateListener(this);
  }
}

IdTokenListener::~IdTokenListener() {
  // Removing the listener edits the auths list, hence the while loop.
  while (!auths_.empty()) {
    (*auths_.begin())->RemoveIdTokenListener(this);
  }
}

template <typename T>
static inline bool VectorContains(const T& entry, const std::vector<T>& v) {
  return std::find(v.begin(), v.end(), entry) != v.end();
}

// Generate a method that notifies a vector of listeners using listeners_method.
#define AUTH_NOTIFY_LISTENERS(notify_method_name, notification_name,           \
                              listeners_vector, notification_method)           \
  void notify_method_name(AuthData* auth_data) {                               \
    MutexLock lock(auth_data->listeners_mutex);                                \
                                                                               \
    /* Make a copy of the listener list in case it gets modified during */     \
    /* notification_method(). Note that modification is possible because */    \
    /* the same thread is allowed to reaquire the `listeners_mutex` */         \
    /* multiple times. */                                                      \
    auto listeners = auth_data->listeners_vector;                              \
    LogDebug(notification_name " changed. Notifying %d listeners.",            \
             listeners.size());                                                \
                                                                               \
    for (auto it = listeners.begin(); it != listeners.end(); ++it) {           \
      /* Skip any listeners that have been removed in notification_method() */ \
      /* on earlier iterations of this loop. */                                \
      auto* listener = *it;                                                    \
      if (!VectorContains(listener, auth_data->listeners_vector)) {            \
        continue;                                                              \
      }                                                                        \
                                                                               \
      /* Notify the listener. */                                               \
      listener->notification_method(auth_data->auth);                          \
    }                                                                          \
  }

AUTH_NOTIFY_LISTENERS(NotifyAuthStateListeners, "Auth state", listeners,
                      OnAuthStateChanged);
AUTH_NOTIFY_LISTENERS(NotifyIdTokenListeners, "ID token", id_token_listeners,
                      OnIdTokenChanged);

AUTH_RESULT_FN(Auth, FetchProvidersForEmail, Auth::FetchProvidersResult)
AUTH_RESULT_FN(Auth, SignInWithCustomToken, User*)
AUTH_RESULT_FN(Auth, SignInWithCredential, User*)
AUTH_RESULT_FN(Auth, SignInAndRetrieveDataWithCredential, SignInResult)
AUTH_RESULT_FN(Auth, SignInAnonymously, User*)
AUTH_RESULT_FN(Auth, SignInWithEmailAndPassword, User*)
AUTH_RESULT_FN(Auth, CreateUserWithEmailAndPassword, User*)
AUTH_RESULT_FN(Auth, SendPasswordResetEmail, void)

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

#include <assert.h>
#include <stdio.h>
#include <algorithm>
#include <cstdint>
#include <map>
#include <string>

#include "app/src/assert.h"
#include "app/src/cleanup_notifier.h"
#include "app/src/include/firebase/app.h"
#include "app/src/include/firebase/future.h"
#include "app/src/include/firebase/internal/common.h"
#include "app/src/include/firebase/version.h"
#include "app/src/mutex.h"
#include "app/src/semaphore.h"
#include "app/src/util.h"
#include "auth/src/common.h"
#include "auth/src/data.h"
#include "auth/src/include/firebase/auth.h"

// Workaround MSVC's incompatible libc headers.
#ifdef _WIN32
#define snprintf _snprintf
#endif  // _WIN32

// Register the module initializer.
FIREBASE_APP_REGISTER_CALLBACKS(
    auth,
    {
      FIREBASE_UTIL_RETURN_FAILURE_IF_GOOGLE_PLAY_UNAVAILABLE(*app);
      return ::firebase::kInitResultSuccess;
    },
    {
        // Nothing to tear down.
    });

namespace firebase {
namespace auth {

DEFINE_FIREBASE_VERSION_STRING(FirebaseAuth);

// The global map of Apps to Auths. Each App can have at most one Auth,
// and an Auth requires an App. So, the user acquires the Auth via an App
// reference.
// TODO(jsanmiya): Ensure all the Auths are destroyed on shutdown.
std::map<App*, Auth*> g_auths;
Mutex g_auths_mutex;  // NOLINT

// static
Auth* Auth::GetAuth(App* app, InitResult* init_result_out) {
  MutexLock lock(g_auths_mutex);
  // Return the Auth if it already exists.
  std::map<App*, Auth*>::iterator it = g_auths.find(app);
  if (it != g_auths.end()) {
    if (init_result_out != nullptr) *init_result_out = kInitResultSuccess;
    return it->second;
  }
  FIREBASE_UTIL_RETURN_NULL_IF_GOOGLE_PLAY_UNAVAILABLE(*app, init_result_out);

  // Create the platform dependent version of Auth.
  void* auth_impl = CreatePlatformAuth(app, app->data_);
  if (!auth_impl) return nullptr;

  // Create a new Auth and initialize.
  Auth* auth = new Auth(app, auth_impl);
  LogDebug("Creating Auth %p for App %p", auth, app);

  // Stick it in the global map so we remember it, and can delete it on
  // shutdown.
  g_auths[app] = auth;

  if (init_result_out) *init_result_out = kInitResultSuccess;
  return auth;
}

// Auth uses the pimpl mechanism to hide internal data types from the interface.
Auth::Auth(App* app, void* auth_impl) : auth_data_(new AuthData) {
  FIREBASE_ASSERT(app != nullptr && auth_impl != nullptr);
  auth_data_->app = app;
  auth_data_->auth = this;
  auth_data_->auth_impl = auth_impl;
  InitPlatformAuth(auth_data_);

  std::string* future_id = &auth_data_->future_api_id;
  static const char* kApiIdentifier = "Auth";
  future_id->reserve(strlen(kApiIdentifier) +
                     16 /* hex characters in the pointer */ +
                     1 /* null terminator */);
  snprintf(&((*future_id)[0]), future_id->capacity(), "%s0x%016llx",
           kApiIdentifier,
           static_cast<unsigned long long>(  // NOLINT
               reinterpret_cast<intptr_t>(this)));

  // Cleanup this object if app is destroyed.
  CleanupNotifier* notifier = CleanupNotifier::FindByOwner(app);
  assert(notifier);
  notifier->RegisterObject(this, [](void* object) {
    Auth* auth = reinterpret_cast<Auth*>(object);
    LogWarning(
        "Auth object 0x%08x should be deleted before the App 0x%08x it "
        "depends upon.",
        static_cast<int>(reinterpret_cast<intptr_t>(auth)),
        static_cast<int>(reinterpret_cast<intptr_t>(auth->auth_data_->app)));
    auth->DeleteInternal();
  });
}

void Auth::DeleteInternal() {
  MutexLock lock(g_auths_mutex);

  if (!auth_data_) return;

  CleanupNotifier* notifier = CleanupNotifier::FindByOwner(auth_data_->app);
  assert(notifier);
  notifier->UnregisterObject(this);

  int num_auths_remaining = 0;
  {
    // Remove `this` from the g_auths map.
    // The mapping is 1:1, so we should only ever delete one.
    for (auto it = g_auths.begin(); it != g_auths.end(); ++it) {
      if (it->second == this) {
        LogDebug("Deleting Auth %p for App %p", this, it->first);
        g_auths.erase(it);
        break;
      }
    }

    num_auths_remaining = g_auths.size();
  }

  auth_data_->ClearListeners();

  // If this is the last Auth instance to be cleaned up, also clean up data for
  // Credentials.
  if (num_auths_remaining == 0) {
    CleanupCredentialFutureImpl();
  }

  // Destroy the platform-specific object.
  DestroyPlatformAuth(auth_data_);

  // Delete the pimpl data.
  delete auth_data_;
  auth_data_ = nullptr;
}

Auth::~Auth() { DeleteInternal(); }

// It's safe to return a direct pointer to `current_user` because that class
// holds nothing but a pointer to AuthData, which never changes.
// All User functions that require synchronization go through AuthData's mutex.
User* Auth::current_user() {
  if (!auth_data_) return nullptr;
  MutexLock lock(auth_data_->future_impl.mutex());
  User* user =
      auth_data_->user_impl == nullptr ? nullptr : &auth_data_->current_user;
  return user;
}

// Always non-nullptr since set in constructor.
App& Auth::app() {
  FIREBASE_ASSERT(auth_data_ != nullptr);
  return *auth_data_->app;
}

template <typename T>
static bool PushBackIfMissing(const T& entry, std::vector<T>* v) {
  auto it = std::find(v->begin(), v->end(), entry);
  if (it != v->end()) return false;

  v->push_back(entry);
  return true;
}

// Store a unique listener of type T in a listener_vector and unique auth
// object in auth_vector.  Both vectors must be in sync, i.e addition must
// either succeed or fail otherwise this method asserts.
template <typename T>
static void AddListener(T listener, std::vector<T>* listener_vector, Auth* auth,
                        std::vector<Auth*>* auth_vector, Mutex* mutex) {
  MutexLock lock(*mutex);
  // Add to array of listeners if not already there.
  const bool listener_added = PushBackIfMissing(listener, listener_vector);
  // Add auth to array of Auths if not already there.
  const bool auth_added = PushBackIfMissing(auth, auth_vector);

  // The listener and Auth should either point at each other or not point
  // at each other.
  FIREBASE_ASSERT_RETURN_VOID(listener_added == auth_added);
  (void)auth_added;
  (void)listener_added;
}

void Auth::AddAuthStateListener(AuthStateListener* listener) {
  if (!auth_data_) return;
  AddListener(listener, &auth_data_->listeners, this, &listener->auths_,
              &auth_data_->listeners_mutex);
}

void Auth::AddIdTokenListener(IdTokenListener* listener) {
  if (!auth_data_) return;
  int listener_count = auth_data_->id_token_listeners.size();
  AddListener(listener, &auth_data_->id_token_listeners, this,
              &listener->auths_, &auth_data_->listeners_mutex);
  // AddListener is valid even if the listener is already registered.
  // This makes sure that we only increase the reference count if a listener
  // was actually added.
  if (auth_data_->id_token_listeners.size() > listener_count) {
    EnableTokenAutoRefresh(auth_data_);
  }
}

template <typename T>
static bool ReplaceEntryWithBack(const T& entry, std::vector<T>* v) {
  auto it = std::find(v->begin(), v->end(), entry);
  if (it == v->end()) return false;

#if defined(FIREBASE_USE_MOVE_OPERATORS)
  *it = std::move(v->back());
#else
  *it = v->back();
#endif  // defined(FIREBASE_USE_MOVE_OPERATORS)

  v->pop_back();
  return true;
}

// Remove a listener of type T from listener_vector and unique auth object in
// auth_vector.  Both vectors must be in sync, i.e addition must either
// succeed or fail otherwise this method asserts.
template <typename T>
static void RemoveListener(T listener, std::vector<T>* listener_vector,
                           Auth* auth, std::vector<Auth*>* auth_vector,
                           Mutex* mutex) {
  MutexLock lock(*mutex);
  // Remove `listener` from our vector of listeners.
  ReplaceEntryWithBack(listener, listener_vector);
  // Remove this Auth from the listener's vector of Auths.
  // This ensures the listener doesn't try to unregister itself again when it is
  // destroyed.
  ReplaceEntryWithBack(auth, auth_vector);
}

void Auth::RemoveAuthStateListener(AuthStateListener* listener) {
  if (!auth_data_) return;
  RemoveListener(listener, &auth_data_->listeners, this, &listener->auths_,
                 &auth_data_->listeners_mutex);
}

void Auth::RemoveIdTokenListener(IdTokenListener* listener) {
  if (!auth_data_) return;
  int listener_count = auth_data_->id_token_listeners.size();
  RemoveListener(listener, &auth_data_->id_token_listeners, this,
                 &listener->auths_, &auth_data_->listeners_mutex);
  // RemoveListener is valid even if the listener is not registered.
  // This makes sure that we only decrease the reference count if a listener
  // was actually removed.
  if (auth_data_->id_token_listeners.size() < listener_count) {
    DisableTokenAutoRefresh(auth_data_);
  }
}

AuthStateListener::~AuthStateListener() {
  // Removing the listener edits the auths list, hence the while loop.
  while (!auths_.empty()) {
    (*auths_.begin())->RemoveAuthStateListener(this);
  }
}

IdTokenListener::~IdTokenListener() {
  // Removing the listener edits the auths list, hence the while loop.
  while (!auths_.empty()) {
    (*auths_.begin())->RemoveIdTokenListener(this);
  }
}

template <typename T>
static inline bool VectorContains(const T& entry, const std::vector<T>& v) {
  return std::find(v.begin(), v.end(), entry) != v.end();
}

// Generate a method that notifies a vector of listeners using listeners_method.
#define AUTH_NOTIFY_LISTENERS(notify_method_name, notification_name,           \
                              listeners_vector, notification_method)           \
  void notify_method_name(AuthData* auth_data) {                               \
    MutexLock lock(auth_data->listeners_mutex);                                \
                                                                               \
    /* Make a copy of the listener list in case it gets modified during */     \
    /* notification_method(). Note that modification is possible because */    \
    /* the same thread is allowed to reaquire the `listeners_mutex` */         \
    /* multiple times. */                                                      \
    auto listeners = auth_data->listeners_vector;                              \
    LogDebug(notification_name " changed. Notifying %d listeners.",            \
             listeners.size());                                                \
                                                                               \
    for (auto it = listeners.begin(); it != listeners.end(); ++it) {           \
      /* Skip any listeners that have been removed in notification_method() */ \
      /* on earlier iterations of this loop. */                                \
      auto* listener = *it;                                                    \
      if (!VectorContains(listener, auth_data->listeners_vector)) {            \
        continue;                                                              \
      }                                                                        \
                                                                               \
      /* Notify the listener. */                                               \
      listener->notification_method(auth_data->auth);                          \
    }                                                                          \
  }

AUTH_NOTIFY_LISTENERS(NotifyAuthStateListeners, "Auth state", listeners,
                      OnAuthStateChanged);
AUTH_NOTIFY_LISTENERS(NotifyIdTokenListeners, "ID token", id_token_listeners,
                      OnIdTokenChanged);

AUTH_RESULT_FN(Auth, FetchProvidersForEmail, Auth::FetchProvidersResult)
AUTH_RESULT_FN(Auth, SignInWithCustomToken, User*)
AUTH_RESULT_FN(Auth, SignInWithCredential, User*)
AUTH_RESULT_FN(Auth, SignInAndRetrieveDataWithCredential, SignInResult)
AUTH_RESULT_FN(Auth, SignInAnonymously, User*)
AUTH_RESULT_FN(Auth, SignInWithEmailAndPassword, User*)
AUTH_RESULT_FN(Auth, CreateUserWithEmailAndPassword, User*)
AUTH_RESULT_FN(Auth, SendPasswordResetEmail, void)

}  // namespace auth
}  // namespace firebase
<|endoftext|>


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

#include "log.hpp"

#include <qicore/logmessage.hpp>

#include <std_msgs/String.h>

#include <boost/algorithm/string.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/foreach.hpp>
#define for_each BOOST_FOREACH

namespace alros
{
namespace converter
{

/** mutex to change the logs list */
boost::mutex MUTEX_LOGS;
/** list of ogs in which the NAOqi callback will write its logs */
std::list<rosgraph_msgs::Log> LOGS;
/** Vector where at index NAOQI_LOG_LEVEL, there is the matching ROS level */
std::vector<rosgraph_msgs::Log::_level_type> LOG_LEVELS;
/** Latest time at which the updates happened */
ros::Time last_log_update_ = ros::TIME_MIN;

void logCallback(const qi::LogMessage& msg)
{
  // Convert the NAOqi log to a ROS log
  rosgraph_msgs::Log log;

  std::vector<std::string> results;
  boost::split(results, msg.source, boost::is_any_of(":"));
  log.file = results[0];
  log.function = results[1];
  log.line = atoi(results[2].c_str());
  log.level = LOG_LEVELS[msg.level];
  log.name = msg.category;
  log.msg = msg.message;
  log.header.stamp = ros::Time(msg.timestamp.tv_sec, msg.timestamp.tv_usec);

  // If we are not publishing, the queue will increase, so we have to prevent an explosion
  // We only keep a log if it's within 5 second of the last publish (totally arbitrary)
  if ((log.header.stamp - last_log_update_) < ros::Duration(5))
  {
    boost::mutex::scoped_lock lock( MUTEX_LOGS );
    LOGS.push_back(log);
  }
}

LogConverter::LogConverter( const std::string& name, float frequency, const qi::SessionPtr& session )
  : BaseConverter( name, frequency, session ),
    logger_( session->service("LogManager") )
{
  float levels[] = {rosgraph_msgs::Log::DEBUG, rosgraph_msgs::Log::FATAL, rosgraph_msgs::Log::ERROR,
    rosgraph_msgs::Log::WARN, rosgraph_msgs::Log::INFO, rosgraph_msgs::Log::DEBUG, rosgraph_msgs::Log::DEBUG};
  LOG_LEVELS = std::vector<rosgraph_msgs::Log::_level_type>(levels, levels + 7);

  listener_ = logger_->getListener();
  listener_->onLogMessage.connect(logCallback);
}

void LogConverter::registerCallback( const message_actions::MessageAction action, Callback_t cb )
{
  callbacks_[action] = cb;
}

void LogConverter::callAll( const std::vector<message_actions::MessageAction>& actions )
{
  while ( !LOGS.empty() )
  {
    rosgraph_msgs::Log& log_msg = LOGS.front();
    for_each( const message_actions::MessageAction& action, actions)
    {
      callbacks_[action](log_msg);
    }
    {
      boost::mutex::scoped_lock lock( MUTEX_LOGS );
      LOGS.pop_front();
    }
  }
  last_log_update_ = ros::Time::now();
}

void LogConverter::reset( )
{
}

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

#include "log.hpp"

#include <qicore/logmessage.hpp>
#include <queue>

#include <std_msgs/String.h>

#include <boost/algorithm/string.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/foreach.hpp>
#define for_each BOOST_FOREACH

namespace alros
{
namespace converter
{

/** mutex to change the logs list */
boost::mutex MUTEX_LOGS;
/** list of ogs in which the NAOqi callback will write its logs */
std::queue<rosgraph_msgs::Log> LOGS;
/** Vector where at index NAOQI_LOG_LEVEL, there is the matching ROS level */
std::vector<rosgraph_msgs::Log::_level_type> LOG_LEVELS;

void logCallback(const qi::LogMessage& msg)
{
  // Convert the NAOqi log to a ROS log
  rosgraph_msgs::Log log;

  std::vector<std::string> results;
  boost::split(results, msg.source, boost::is_any_of(":"));
  log.file = results[0];
  log.function = results[1];
  log.line = atoi(results[2].c_str());
  log.level = LOG_LEVELS[msg.level];
  log.name = msg.category;
  log.msg = msg.message;
  log.header.stamp = ros::Time(msg.timestamp.tv_sec, msg.timestamp.tv_usec);

  // If we are not publishing, the queue will increase, so we have to prevent an explosion
  // We only keep a log if it's within 5 second of the last publish (totally arbitrary)
  boost::mutex::scoped_lock lock( MUTEX_LOGS );
  while (LOGS.size() > 1000)
  {
    LOGS.pop();
  }
  LOGS.push(log);
}

LogConverter::LogConverter( const std::string& name, float frequency, const qi::SessionPtr& session )
  : BaseConverter( name, frequency, session ),
    logger_( session->service("LogManager") )
{
  float levels[] = {rosgraph_msgs::Log::DEBUG, rosgraph_msgs::Log::FATAL, rosgraph_msgs::Log::ERROR,
    rosgraph_msgs::Log::WARN, rosgraph_msgs::Log::INFO, rosgraph_msgs::Log::DEBUG, rosgraph_msgs::Log::DEBUG};
  LOG_LEVELS = std::vector<rosgraph_msgs::Log::_level_type>(levels, levels + 7);

  listener_ = logger_->getListener();
  listener_->onLogMessage.connect(logCallback);
}

void LogConverter::registerCallback( const message_actions::MessageAction action, Callback_t cb )
{
  callbacks_[action] = cb;
}

void LogConverter::callAll( const std::vector<message_actions::MessageAction>& actions )
{
  while ( !LOGS.empty() )
  {
    rosgraph_msgs::Log& log_msg = LOGS.front();
    for_each( const message_actions::MessageAction& action, actions)
    {
      callbacks_[action](log_msg);
    }
    {
      boost::mutex::scoped_lock lock( MUTEX_LOGS );
      LOGS.pop();
    }
  }
}

void LogConverter::reset( )
{
}

} // publisher
} //alros
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libdui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QObject>
#include <QDebug>
#include <QStringListModel>
#include <DuiTheme>
#include <DuiList>
#include <DuiApplication>

#include "memorybenchmark.h"
#include "memorybenchmark.inl"
#include "mt_duilist.h"

DuiApplication *app;

void Mt_DuiList::initTestCase()
{
    int argc = 1;
    const char *argv[argc];
    char appName[] = "./mt_duilist";
    argv[0] = appName;
    app = new DuiApplication(argc, (char **)argv);
}

void Mt_DuiList::cleanupTestCase()
{
    delete app;
}

void Mt_DuiList::memoryBenchmark_data()
{
    QTest::addColumn<qint32>("width");
    QTest::addColumn<qint32>("height");
    QTest::addColumn<qint32>("labelHeight");
    QTest::addColumn<QStringList>("text");

    QTest::newRow("64x64")    << 64 << 64 << 16 << (QStringList() << "Silence" << "is" << "disturbing!");
    QTest::newRow("128x128")  << 128  << 128 << 40 << (QStringList() << "Silence" << "is" << "not" << "disturbing!");
    QTest::newRow("256x256")  << 256  << 256 << 60 << (QStringList() << "XXXX" << "XXXX" << "XXXX" \
                              << "XXXX" << "XXXX" << "XXXX" \
                              << "XXXX" << "XXXX" << "XXXX");
}

void Mt_DuiList::memoryBenchmark()
{
    /*
     #MS - empty TC, should be tested some other way
    // get size dimensions for test
    QFETCH(qint32, width);
    QFETCH(qint32, height);
    QFETCH(qint32, labelHeight);
    QFETCH(QStringList, text);

    Q_UNUSED(labelHeight);

    // create pixmap paintdevice
    QPixmap *pixmap = new QPixmap(width, height);
    pixmap->fill(QColor(0, 0, 0, 0));
    QPainter *painter = new QPainter(pixmap);

    beginMemoryBenchmark();

    // create widget, set size
    DuiList *list = new DuiList();
    list->setMinimumSize(width, height);
    list->setMaximumSize(width, height);

    QStringListModel *stringModel = new QStringListModel(text);

    list->setItemModel(stringModel);

    list->paint(painter, NULL); //#MS - here is expected "option" param in DuiFastListView::drawForeground

    // Print used memory, it will be recorded in a log
    outputAllocatedMemorySize();

    delete list;

    endMemoryBenchmark();

    delete painter;
    delete pixmap;
    */
}

QTEST_APPLESS_MAIN(Mt_DuiList)
<commit_msg>Changes: Benchmarks - Mt_DuiList - memory benchmark corrected and back in testing RevBy: TrustMe Details:<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libdui.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include <QObject>
#include <QDebug>
#include <QStringListModel>
#include <DuiTheme>
#include <DuiList>
#include <DuiApplication>

#include "memorybenchmark.h"
#include "memorybenchmark.inl"
#include "mt_duilist.h"

DuiApplication *app(NULL);

void Mt_DuiList::initTestCase()
{
    int argc = 1;
    const char *argv[argc];
    char appName[] = "./mt_duilist";
    argv[0] = appName;
    app = new DuiApplication(argc, (char **)argv);
}

void Mt_DuiList::cleanupTestCase()
{
    delete app; app = NULL;
}

void Mt_DuiList::memoryBenchmark_data()
{
    QTest::addColumn<qint32>("width");
    QTest::addColumn<qint32>("height");
    QTest::addColumn<qint32>("labelHeight");
    QTest::addColumn<QStringList>("text");

    QTest::newRow("64x64")    << 64 << 64 << 16 << (QStringList() << "Silence" << "is" << "disturbing!");
    QTest::newRow("128x128")  << 128  << 128 << 40 << (QStringList() << "Silence" << "is" << "not" << "disturbing!");
    QTest::newRow("256x256")  << 256  << 256 << 60 << (QStringList() << "XXXX" << "XXXX" << "XXXX" \
                              << "XXXX" << "XXXX" << "XXXX" \
                              << "XXXX" << "XXXX" << "XXXX");
}

void Mt_DuiList::memoryBenchmark()
{

    // get size dimensions for test
    QFETCH(qint32, width);
    QFETCH(qint32, height);
    QFETCH(qint32, labelHeight);
    QFETCH(QStringList, text);

    Q_UNUSED(labelHeight);

    // create pixmap paintdevice
    QPixmap *pixmap = new QPixmap(width, height);
    pixmap->fill(QColor(0, 0, 0, 0));
    QPainter *painter = new QPainter(pixmap);
    QStyleOptionGraphicsItem* option = new QStyleOptionGraphicsItem();

    beginMemoryBenchmark();

    // create widget, set size
    DuiList *list = new DuiList();
    list->setMinimumSize(width, height);
    list->setMaximumSize(width, height);

    QStringListModel *stringModel = new QStringListModel(text);

    list->setItemModel(stringModel);

    list->paint(painter, option);

    // Print used memory, it will be recorded in a log
    outputAllocatedMemorySize();

    delete list; list = NULL;

    endMemoryBenchmark();

    delete option; option = NULL;
    delete painter;painter = NULL;
    delete pixmap; pixmap = NULL;
}

QTEST_APPLESS_MAIN(Mt_DuiList)
<|endoftext|>


<commit_before>#include "utils.h"
#include "engine/crc32.h"
#include "engine/math_utils.h"
#include "engine/path.h"
#include "engine/path_utils.h"
#include "engine/property_register.h"
#include "editor/render_interface.h"
#include "editor/world_editor.h"
#include "imgui/imgui.h"
#include "engine/universe/universe.h"

void getEntityListDisplayName(Lumix::WorldEditor& editor, char* buf, int max_size, Lumix::Entity entity)
{
	const char* name = editor.getUniverse()->getEntityName(entity);
	static const auto RENDERABLE_TYPE = Lumix::PropertyRegister::getComponentType("renderable");
	Lumix::ComponentHandle renderable = editor.getUniverse()->getComponent(entity, RENDERABLE_TYPE).handle;
	if (Lumix::isValid(renderable))
	{
		auto* render_interface = editor.getRenderInterface();
		auto path = render_interface->getRenderablePath(renderable);
		if (path.isValid())
		{
			char basename[Lumix::MAX_PATH_LENGTH];
			Lumix::copyString(buf, max_size, path.c_str());
			Lumix::PathUtils::getBasename(basename, Lumix::MAX_PATH_LENGTH, path.c_str());
			if (name && name[0] != '\0')
				Lumix::copyString(buf, max_size, name);
			else
				Lumix::toCString(entity.index, buf, max_size);

			Lumix::catString(buf, max_size, " - ");
			Lumix::catString(buf, max_size, basename);
			return;
		}
	}

	if (name && name[0] != '\0')
	{
		Lumix::copyString(buf, max_size, name);
	}
	else
	{
		Lumix::toCString(entity.index, buf, max_size);
	}
}

<commit_msg>fixed crash when lua property has no entity set<commit_after>#include "utils.h"
#include "engine/crc32.h"
#include "engine/math_utils.h"
#include "engine/path.h"
#include "engine/path_utils.h"
#include "engine/property_register.h"
#include "editor/render_interface.h"
#include "editor/world_editor.h"
#include "imgui/imgui.h"
#include "engine/universe/universe.h"

void getEntityListDisplayName(Lumix::WorldEditor& editor, char* buf, int max_size, Lumix::Entity entity)
{
	if (!Lumix::isValid(entity))
	{
		*buf = '\0';
		return;
	}
	const char* name = editor.getUniverse()->getEntityName(entity);
	static const auto RENDERABLE_TYPE = Lumix::PropertyRegister::getComponentType("renderable");
	Lumix::ComponentHandle renderable = editor.getUniverse()->getComponent(entity, RENDERABLE_TYPE).handle;
	if (Lumix::isValid(renderable))
	{
		auto* render_interface = editor.getRenderInterface();
		auto path = render_interface->getRenderablePath(renderable);
		if (path.isValid())
		{
			char basename[Lumix::MAX_PATH_LENGTH];
			Lumix::copyString(buf, max_size, path.c_str());
			Lumix::PathUtils::getBasename(basename, Lumix::MAX_PATH_LENGTH, path.c_str());
			if (name && name[0] != '\0')
				Lumix::copyString(buf, max_size, name);
			else
				Lumix::toCString(entity.index, buf, max_size);

			Lumix::catString(buf, max_size, " - ");
			Lumix::catString(buf, max_size, basename);
			return;
		}
	}

	if (name && name[0] != '\0')
	{
		Lumix::copyString(buf, max_size, name);
	}
	else
	{
		Lumix::toCString(entity.index, buf, max_size);
	}
}

<|endoftext|>


<commit_before>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

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

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

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <config.h>
#include <errno.h>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>

#include "utils.h"
#include "socket.h"

libhttppp::ClientSocket::ClientSocket(){
  Socket = 0;
  _SSL=nullptr;
  _ClientAddr = new struct sockaddr;
}

libhttppp::ClientSocket::~ClientSocket(){
    Close();
    if(_SSL)
        SSL_free(_SSL);
    delete _ClientAddr;
}

void libhttppp::ClientSocket::Close(){
    HTTPException exp;
    if(close(Socket)<0){
#ifdef __GLIBCXX__
        char errbuf[255];
        exp[HTTPException::Error] << "Can't close Socket: " << strerror_r(errno, errbuf, 255);
#else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        exp[HTTPException::Error] << "Can't close Socket: " << errbuf;
#endif
        throw exp;
    }
}

void libhttppp::ClientSocket::setnonblocking(){
    fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
}

libhttppp::ServerSocket::ServerSocket(const char* uxsocket,int maxconnections){
    HTTPException httpexception;
    int optval = 1;
    _Maxconnections=maxconnections;
    _UXSocketAddr = new sockaddr_un;
    _UXSocketAddr->sun_family = AF_UNIX;
    try {
        scopy(uxsocket,uxsocket+getlen(uxsocket),_UXSocketAddr->sun_path);
    }catch(...){
        httpexception[HTTPException::Critical] << "Can't copy Server UnixSocket";
        throw httpexception;
    }

    if ((Socket = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0){
        httpexception[HTTPException::Critical] << "Can't create Socket UnixSocket";
        throw httpexception;
    }

    setsockopt(Socket,SOL_SOCKET,SO_REUSEADDR,&optval, sizeof(optval));

    if (bind(Socket, (struct sockaddr *)_UXSocketAddr, sizeof(struct sockaddr)) < 0){
        #ifdef __GLIBCXX__
        char errbuf[255];
        httpexception[HTTPException::Error] << "Can't bind Server UnixSocket"
                                            << strerror_r(errno, errbuf, 255);
        #else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        httpexception[HTTPException::Critical] << "Can't bind Server UnixSocket" << errbuf;
        #endif
        throw httpexception;
    }
}

libhttppp::ServerSocket::ServerSocket(int socket) {
    Socket = socket;
    _Maxconnections = MAXDEFAULTCONN;
    _UXSocketAddr = NULL;
}

libhttppp::ServerSocket::ServerSocket(const char* addr, int port,int maxconnections){
    HTTPException httpexception;
    _Maxconnections=maxconnections;
    _UXSocketAddr = NULL;

    char port_buffer[6];
    snprintf(port_buffer,6, "%d", port);
    struct addrinfo *result, *rp;
    memset(&_SockAddr, 0, sizeof(struct addrinfo));
    _SockAddr.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    _SockAddr.ai_socktype = SOCK_STREAM; /* Datagram socket */
    _SockAddr.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
    _SockAddr.ai_protocol = 0;          /* Any protocol */
    _SockAddr.ai_canonname = NULL;
    _SockAddr.ai_addr = NULL;
    _SockAddr.ai_next = NULL;

    int s = getaddrinfo(addr, port_buffer, &_SockAddr, &result);
    if (s != 0) {
        httpexception[HTTPException::Critical] << "getaddrinfo failed " << gai_strerror(s);
        throw httpexception;
    }

    /* getaddrinfo() returns a list of address structures.
     *  Try each address until we successfully bind(2).
     *  If socket(2) (or bind(2)) fails, we (close the socket
     *  and) try the next address. */

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        Socket = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);
        if (Socket == -1)
            continue;

        int optval = 1;
        setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

        if (bind(Socket, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                  /* Success */

        close(Socket);
    }

    if (rp == NULL) {               /* No address succeeded */
        httpexception[HTTPException::Critical] << "Could not bind\n";
        throw httpexception;
    }
    freeaddrinfo(result);
}

libhttppp::ServerSocket::~ServerSocket(){
    if(_UXSocketAddr)
        unlink(_UXSocketAddr->sun_path);
    delete _UXSocketAddr;
}

void libhttppp::ServerSocket::setnonblocking(){
    fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
}

void libhttppp::ServerSocket::listenSocket(){
    HTTPException httpexception;
    if(listen(Socket, _Maxconnections) < 0){
        httpexception[HTTPException::Critical] << "Can't listen Server Socket"<< errno;
        throw httpexception;
    }
}

int libhttppp::ServerSocket::getSocket(){
    return Socket;
}

int libhttppp::ServerSocket::getMaxconnections(){
    return _Maxconnections;
}

int libhttppp::ServerSocket::acceptEvent(ClientSocket *clientsocket){
    HTTPException httpexception;
    clientsocket->_ClientAddrLen=sizeof(clientsocket);
    int socket = accept(Socket,clientsocket->_ClientAddr, &clientsocket->_ClientAddrLen);
    if(socket<0){
#ifdef __GLIBCXX__
        char errbuf[255];
        httpexception[HTTPException::Error] << "Can't accept on  Socket" << strerror_r(errno, errbuf, 255);
#else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        httpexception[HTTPException::Error] << "Can't accept on  Socket" << errbuf;
#endif
    }
    clientsocket->Socket=socket;
    if(isSSLTrue()){
        clientsocket->_SSL = SSL_new(_CTX);
        SSL_set_fd(clientsocket->_SSL, socket);
        if (SSL_accept(clientsocket->_SSL) <= 0) {
            ERR_print_errors_fp(stderr);
            return -1;
        }
    }
    return socket;
}

ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size){
    return sendData(socket,data,size,0);
}

ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size,int flags){
    HTTPException httpexception;
    ssize_t rval=0;
    if(isSSLTrue() && socket->_SSL){
        rval=SSL_write(socket->_SSL,data,size);
    }else{
        rval=sendto(socket->Socket,data,size,flags,(struct sockaddr*)socket->_ClientAddr,sizeof(struct sockaddr));
    }
    if(rval<0){
        char errbuf[255];
#ifdef __GLIBCXX__
        if(errno==EAGAIN)
            httpexception[HTTPException::Warning] << "Socket sendata:" << strerror_r(errno,errbuf,255);
        else
            httpexception[HTTPException::Error] << "Socket sendata:" << strerror_r(errno,errbuf,255);
#else
        strerror_r(errno,errbuf,255);
        if(errno == EAGAIN)
            httpexception[HTTPException::Warning] << "Socket sendata:" << errbuf;
        else
            httpexception[HTTPException::Error] << "Socket sendata:" << errbuf;
#endif
        throw httpexception;
    }
    return rval;
}

ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size){
    return recvData(socket,data,size,0);
}

ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size,int flags){
    HTTPException httpexception;
    ssize_t recvsize=0;
    if(isSSLTrue() && socket->_SSL){
        recvsize=SSL_read(socket->_SSL,data,size);
    }else{
        recvsize=recvfrom(socket->Socket,data, size,flags,
                          socket->_ClientAddr, &socket->_ClientAddrLen);
    }
    if(recvsize<0){
        char errbuf[255];
#ifdef __GLIBCXX__
        if(errno==EAGAIN){
            httpexception[HTTPException::Warning] << "Socket recvdata "  <<  socket->Socket << ": "<< strerror_r(errno,errbuf,255);
        }else{
            httpexception[HTTPException::Error] << "Socket recvdata " << socket->Socket << ": " << strerror_r(errno,errbuf,255);
        }
#else
        strerror_r(errno,errbuf,255);
        if(errno == EAGAIN)
            httpexception[HTTPException::Warning] << "Socket recvdata:" << socket->Socket << ": " << errbuf;
        else
            httpexception[HTTPException::Critical] << "Socket recvdata:" << socket->Socket << ":" <<  errbuf;
#endif
        throw httpexception;
    }
    return recvsize;
}
<commit_msg>added missing include<commit_after>/*******************************************************************************
Copyright (c) 2014, Jan Koester jan.koester@gmx.net
All rights reserved.

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

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

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <config.h>
#include <errno.h>
#include <cstring>

#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509.h>

#include "utils.h"
#include "socket.h"

libhttppp::ClientSocket::ClientSocket(){
  Socket = 0;
  _SSL=nullptr;
  _ClientAddr = new struct sockaddr;
}

libhttppp::ClientSocket::~ClientSocket(){
    Close();
    if(_SSL)
        SSL_free(_SSL);
    delete _ClientAddr;
}

void libhttppp::ClientSocket::Close(){
    HTTPException exp;
    if(close(Socket)<0){
#ifdef __GLIBCXX__
        char errbuf[255];
        exp[HTTPException::Error] << "Can't close Socket: " << strerror_r(errno, errbuf, 255);
#else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        exp[HTTPException::Error] << "Can't close Socket: " << errbuf;
#endif
        throw exp;
    }
}

void libhttppp::ClientSocket::setnonblocking(){
    fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
}

libhttppp::ServerSocket::ServerSocket(const char* uxsocket,int maxconnections){
    HTTPException httpexception;
    int optval = 1;
    _Maxconnections=maxconnections;
    _UXSocketAddr = new sockaddr_un;
    _UXSocketAddr->sun_family = AF_UNIX;
    try {
        scopy(uxsocket,uxsocket+getlen(uxsocket),_UXSocketAddr->sun_path);
    }catch(...){
        httpexception[HTTPException::Critical] << "Can't copy Server UnixSocket";
        throw httpexception;
    }

    if ((Socket = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0){
        httpexception[HTTPException::Critical] << "Can't create Socket UnixSocket";
        throw httpexception;
    }

    setsockopt(Socket,SOL_SOCKET,SO_REUSEADDR,&optval, sizeof(optval));

    if (bind(Socket, (struct sockaddr *)_UXSocketAddr, sizeof(struct sockaddr)) < 0){
        #ifdef __GLIBCXX__
        char errbuf[255];
        httpexception[HTTPException::Error] << "Can't bind Server UnixSocket"
                                            << strerror_r(errno, errbuf, 255);
        #else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        httpexception[HTTPException::Critical] << "Can't bind Server UnixSocket" << errbuf;
        #endif
        throw httpexception;
    }
}

libhttppp::ServerSocket::ServerSocket(int socket) {
    Socket = socket;
    _Maxconnections = MAXDEFAULTCONN;
    _UXSocketAddr = NULL;
}

libhttppp::ServerSocket::ServerSocket(const char* addr, int port,int maxconnections){
    HTTPException httpexception;
    _Maxconnections=maxconnections;
    _UXSocketAddr = NULL;

    char port_buffer[6];
    snprintf(port_buffer,6, "%d", port);
    struct addrinfo *result, *rp;
    memset(&_SockAddr, 0, sizeof(struct addrinfo));
    _SockAddr.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    _SockAddr.ai_socktype = SOCK_STREAM; /* Datagram socket */
    _SockAddr.ai_flags = AI_PASSIVE;    /* For wildcard IP address */
    _SockAddr.ai_protocol = 0;          /* Any protocol */
    _SockAddr.ai_canonname = NULL;
    _SockAddr.ai_addr = NULL;
    _SockAddr.ai_next = NULL;

    int s = getaddrinfo(addr, port_buffer, &_SockAddr, &result);
    if (s != 0) {
        httpexception[HTTPException::Critical] << "getaddrinfo failed " << gai_strerror(s);
        throw httpexception;
    }

    /* getaddrinfo() returns a list of address structures.
     *  Try each address until we successfully bind(2).
     *  If socket(2) (or bind(2)) fails, we (close the socket
     *  and) try the next address. */

    for (rp = result; rp != NULL; rp = rp->ai_next) {
        Socket = socket(rp->ai_family, rp->ai_socktype,rp->ai_protocol);
        if (Socket == -1)
            continue;

        int optval = 1;
        setsockopt(Socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

        if (bind(Socket, rp->ai_addr, rp->ai_addrlen) == 0)
            break;                  /* Success */

        close(Socket);
    }

    if (rp == NULL) {               /* No address succeeded */
        httpexception[HTTPException::Critical] << "Could not bind\n";
        throw httpexception;
    }
    freeaddrinfo(result);
}

libhttppp::ServerSocket::~ServerSocket(){
    if(_UXSocketAddr)
        unlink(_UXSocketAddr->sun_path);
    delete _UXSocketAddr;
}

void libhttppp::ServerSocket::setnonblocking(){
    fcntl(Socket, F_SETFL, fcntl(Socket, F_GETFL, 0) | O_NONBLOCK);
}

void libhttppp::ServerSocket::listenSocket(){
    HTTPException httpexception;
    if(listen(Socket, _Maxconnections) < 0){
        httpexception[HTTPException::Critical] << "Can't listen Server Socket"<< errno;
        throw httpexception;
    }
}

int libhttppp::ServerSocket::getSocket(){
    return Socket;
}

int libhttppp::ServerSocket::getMaxconnections(){
    return _Maxconnections;
}

int libhttppp::ServerSocket::acceptEvent(ClientSocket *clientsocket){
    HTTPException httpexception;
    clientsocket->_ClientAddrLen=sizeof(clientsocket);
    int socket = accept(Socket,clientsocket->_ClientAddr, &clientsocket->_ClientAddrLen);
    if(socket<0){
#ifdef __GLIBCXX__
        char errbuf[255];
        httpexception[HTTPException::Error] << "Can't accept on  Socket" << strerror_r(errno, errbuf, 255);
#else
        char errbuf[255];
        strerror_r(errno, errbuf, 255);
        httpexception[HTTPException::Error] << "Can't accept on  Socket" << errbuf;
#endif
    }
    clientsocket->Socket=socket;
    if(isSSLTrue()){
        clientsocket->_SSL = SSL_new(_CTX);
        SSL_set_fd(clientsocket->_SSL, socket);
        if (SSL_accept(clientsocket->_SSL) <= 0) {
            ERR_print_errors_fp(stderr);
            return -1;
        }
    }
    return socket;
}

ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size){
    return sendData(socket,data,size,0);
}

ssize_t libhttppp::ServerSocket::sendData(ClientSocket* socket, void* data, size_t size,int flags){
    HTTPException httpexception;
    ssize_t rval=0;
    if(isSSLTrue() && socket->_SSL){
        rval=SSL_write(socket->_SSL,data,size);
    }else{
        rval=sendto(socket->Socket,data,size,flags,(struct sockaddr*)socket->_ClientAddr,sizeof(struct sockaddr));
    }
    if(rval<0){
        char errbuf[255];
#ifdef __GLIBCXX__
        if(errno==EAGAIN)
            httpexception[HTTPException::Warning] << "Socket sendata:" << strerror_r(errno,errbuf,255);
        else
            httpexception[HTTPException::Error] << "Socket sendata:" << strerror_r(errno,errbuf,255);
#else
        strerror_r(errno,errbuf,255);
        if(errno == EAGAIN)
            httpexception[HTTPException::Warning] << "Socket sendata:" << errbuf;
        else
            httpexception[HTTPException::Error] << "Socket sendata:" << errbuf;
#endif
        throw httpexception;
    }
    return rval;
}

ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size){
    return recvData(socket,data,size,0);
}

ssize_t libhttppp::ServerSocket::recvData(ClientSocket* socket, void* data, size_t size,int flags){
    HTTPException httpexception;
    ssize_t recvsize=0;
    if(isSSLTrue() && socket->_SSL){
        recvsize=SSL_read(socket->_SSL,data,size);
    }else{
        recvsize=recvfrom(socket->Socket,data, size,flags,
                          socket->_ClientAddr, &socket->_ClientAddrLen);
    }
    if(recvsize<0){
        char errbuf[255];
#ifdef __GLIBCXX__
        if(errno==EAGAIN)
            httpexception[HTTPException::Warning] << "Socket recvdata "  <<  socket->Socket << ": "<< strerror_r(errno,errbuf,255);
        else
            httpexception[HTTPException::Error] << "Socket recvdata " << socket->Socket << ": " << strerror_r(errno,errbuf,255);
#else
        strerror_r(errno,errbuf,255);
        if(errno == EAGAIN)
            httpexception[HTTPException::Warning] << "Socket recvdata:" << socket->Socket << ": " << errbuf;
        else
            httpexception[HTTPException::Critical] << "Socket recvdata:" << socket->Socket << ":" <<  errbuf;
#endif
        throw httpexception;
    }
    return recvsize;
}
<|endoftext|>


<commit_before>/*==========================================================================
               SeqAn - The Library for Sequence Analysis
                         http://www.seqan.de
============================================================================
Copyright (C) 2007

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

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

#define SEQAN_PROFILE

#include <seqan/basic.h>

// Profiling
#ifdef SEQAN_PROFILE
		SEQAN_PROTIMESTART(__myProfileTime);
#endif

#include <seqan/consensus.h>
#include <seqan/modifier.h>
#include <seqan/misc/misc_cmdparser.h>

#include <iostream>
#include <fstream>

using namespace seqan;

//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////

inline void
_addVersion(CommandLineParser& parser) {
	::std::string rev = "$Revision: 4663 $";
	addVersionLine(parser, "Version 0.22 (06. August 2009) Revision: " + rev.substr(11, 4) + "");
}

//////////////////////////////////////////////////////////////////////////////////

int main(int argc, const char *argv[]) {
	// Command line parsing
	CommandLineParser parser;
	_addVersion(parser);

	addTitleLine(parser, "***************************************");
	addTitleLine(parser, "* Multi-read alignment - SeqCons      *");
	addTitleLine(parser, "* (c) Copyright 2009 by Tobias Rausch *");
	addTitleLine(parser, "***************************************");

	addUsageLine(parser, "-r <FASTA file with reads> [Options]");
	addUsageLine(parser, "-a <AMOS message file> [Options]");

	addSection(parser, "Main Options:");
	addOption(parser, addArgumentText(CommandLineOption("r", "reads", "file with reads", OptionType::String), "<FASTA reads file>"));
	addOption(parser, addArgumentText(CommandLineOption("a", "afg", "message file", OptionType::String), "<AMOS afg file>"));
	addOption(parser, addArgumentText(CommandLineOption("o", "outfile", "output filename", OptionType::String, "align.txt"), "<Filename>"));
	addOption(parser, addArgumentText(CommandLineOption("f", "format", "output format", OptionType::String, "afg"), "[seqan | afg]"));
	addOption(parser, addArgumentText(CommandLineOption("m", "method", "multi-read alignment method", OptionType::String, "realign"), "[realign | msa]"));
	addOption(parser, addArgumentText(CommandLineOption("b", "bandwidth", "bandwidth", OptionType::Int, 8), "<Int>"));
	addOption(parser, CommandLineOption("n", "noalign", "no align, only convert input", OptionType::Boolean));

	addSection(parser, "MSA Method Options:");
	addOption(parser, addArgumentText(CommandLineOption("ma", "matchlength", "minimum overlap length", OptionType::Int, 15), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("qu", "quality", "minimum overlap precent identity", OptionType::Int, 80), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("ov", "overlaps", "minimum number of overlaps per read", OptionType::Int, 3), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("wi", "window", "window size", OptionType::Int, 0), "<Int>"));
	addHelpLine(parser, "/*If this parameter is > 0 then all");
	addHelpLine(parser, "  overlaps within a given window");
	addHelpLine(parser, "  are computed.*/");

	addSection(parser, "ReAlign Method Options:");
	addOption(parser, CommandLineOption("in", "include", "include contig sequence", OptionType::Boolean));
	addOption(parser, addArgumentText(CommandLineOption("rm", "rmethod", "realign method", OptionType::String, "gotoh"), "[nw | gotoh]"));

	if (argc == 1)
	{
		shortHelp(parser, std::cerr);	// print short help and exit
		return 0;
	}

	if (!parse(parser, argc, argv, ::std::cerr)) return 1;
	if (isSetLong(parser, "help") || isSetLong(parser, "version")) return 0;	// print help or version and exit

	// Get all command line options
	ConsensusOptions consOpt;

	// Main options
	getOptionValueLong(parser, "reads", consOpt.readsfile);
	getOptionValueLong(parser, "afg", consOpt.afgfile);
	getOptionValueLong(parser, "outfile", consOpt.outfile);
	String<char> optionVal;
	getOptionValueLong(parser, "format", optionVal);
	if (optionVal == "seqan") consOpt.output = 0;
	else if (optionVal == "afg") consOpt.output = 1;
	else if (optionVal == "frg") consOpt.output = 2;
	else if (optionVal == "cgb") consOpt.output = 3;
	getOptionValueLong(parser, "method", optionVal);
	if (optionVal == "realign") consOpt.method = 0;
	else if (optionVal == "msa") consOpt.method = 1;
	getOptionValueLong(parser, "bandwidth", consOpt.bandwidth);
#ifdef CELERA_OFFSET
	if (!isSetLong(parser, "bandwidth")) consOpt.bandwidth = 15;
#endif
	getOptionValueLong(parser, "noalign", consOpt.noalign);

	// Msa options
	getOptionValueLong(parser, "matchlength", consOpt.matchlength);
	getOptionValueLong(parser, "quality", consOpt.quality);
	getOptionValueLong(parser, "overlaps", consOpt.overlaps);
#ifdef CELERA_OFFSET
	if (!isSetLong(parser, "overlaps")) consOpt.overlaps = 5;
#endif
	getOptionValueLong(parser, "window", consOpt.window);

	// ReAlign options
	getOptionValueLong(parser, "include", consOpt.include);
	getOptionValueLong(parser, "rmethod", optionVal);
	if (optionVal == "nw") consOpt.rmethod = 0;
	else if (optionVal == "gotoh") consOpt.rmethod = 1;

	// Create a new fragment store
	typedef FragmentStore<> TFragmentStore;
	typedef Size<TFragmentStore>::Type TSize;
	TFragmentStore fragStore;

	// Load the reads and layout positions
	TSize numberOfContigs = 0;
	if (!empty(consOpt.readsfile)) {
		// Load simple read file
		FILE* strmReads = fopen(consOpt.readsfile.c_str(), "rb");
		bool moveToFront = false;
		if (consOpt.noalign) moveToFront = true;
		bool success = _convertSimpleReadFile(strmReads, fragStore, consOpt.readsfile, moveToFront);
		fclose(strmReads);
		if (!success) {
			shortHelp(parser, std::cerr);
			return 0;
		}
		numberOfContigs = 1;
	} else if (!empty(consOpt.afgfile)) {
		// Load Amos message file
		FILE* strmReads = fopen(consOpt.afgfile.c_str(), "rb");
		read(strmReads, fragStore, Amos());
		fclose(strmReads);
		numberOfContigs = length(fragStore.contigStore);
	} else {
		shortHelp(parser, std::cerr);
		return 0;
	}

	// Multi-realignment desired or just conversion of the input
	if (!consOpt.noalign) {

		// Profiling
#ifdef SEQAN_PROFILE
				SEQAN_PROTIMEUPDATE(__myProfileTime);
#endif

		// Iterate over all contigs
		for(TSize currentContig = 0; currentContig < numberOfContigs; ++currentContig) {

			if (consOpt.method == 0) {
#ifdef SEQAN_PROFILE
				::std::cout << "ReAlign method" << ::std::endl;
				if (consOpt.rmethod == 0) ::std::cout << "Realign algorithm: Needleman-Wunsch" << ::std::endl;
				else if (consOpt.rmethod == 1) ::std::cout << "Realign algorithm: Gotoh" << ::std::endl;
				::std::cout << "Bandwidth: " << consOpt.bandwidth << ::std::endl;
				::std::cout << "Include reference: " << consOpt.include << ::std::endl;
#endif
				Score<int, WeightedConsensusScore<Score<int, FractionalScore>, Score<int, ConsensusScore> > > combinedScore;
				reAlign(fragStore, combinedScore, currentContig, consOpt.rmethod, consOpt.bandwidth, consOpt.include);

#ifdef SEQAN_PROFILE
				::std::cout << "ReAlignment done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << ::std::endl;
#endif
			} else {

#ifdef SEQAN_PROFILE
				::std::cout << "MSA method" << ::std::endl;
				::std::cout << "Bandwidth: " << consOpt.bandwidth << ::std::endl;
				::std::cout << "Matchlength: " << consOpt.matchlength << ::std::endl;
				::std::cout << "Quality: " << consOpt.quality << ::std::endl;
				::std::cout << "Overlaps: " << consOpt.overlaps << ::std::endl;
				::std::cout << "Window: " << consOpt.window << ::std::endl;
#endif

				// Import all reads of the given contig
				typedef TFragmentStore::TReadSeq TReadSeq;
				StringSet<TReadSeq, Owner<> > readSet;
				String<Pair<TSize, TSize> > begEndPos;
				_loadContigReads(readSet, begEndPos, fragStore, currentContig);
				if (!length(readSet)) continue;

#ifdef SEQAN_PROFILE
				::std::cout << "Import sequences done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << ::std::endl;
#endif

				// Align the reads
				typedef StringSet<TReadSeq, Dependent<> > TStringSet;
				typedef Graph<Alignment<TStringSet, void, WithoutEdgeId> > TAlignGraph;
				TAlignGraph gOut(readSet);
				consensusAlignment(gOut, begEndPos, consOpt);
#ifdef SEQAN_PROFILE
				std::cout << "Multi-read Alignment done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << std::endl;
#endif

				// Update the contig in the fragment store
				updateContig(fragStore, gOut, currentContig);
				clear(gOut);
#ifdef SEQAN_PROFILE
				std::cout << "Update contig done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << std::endl;
#endif

				//// Debug code for CA
				//mtRandInit();
				//String<char> fileTmp1 = "tmp1";
				//String<char> fileTmp2 = "tmp2";
				//for(int i = 0; i<10; ++i) {
				//	int file = (mtRand() % 20) + 65;
				//	appendValue(fileTmp1, char(file));
				//	appendValue(fileTmp2, char(file));
				//}
				//std::fstream strm3;
				//strm3.open(toCString(fileTmp2), std::ios_base::out | std::ios_base::trunc);
				//for(int i = 0;i<(int) length(origStrSet); ++i) {
				//	std::stringstream name;
				//	name << value(begEndPos, i).i1 << "," << value(begEndPos, i).i2;
				//	String<char> myTitle = name.str();
				//	write(strm3, origStrSet[i], myTitle, Fasta());
				//	if (value(begEndPos, i).i1 > value(begEndPos, i).i2) reverseComplementInPlace(origStrSet[i]);
				//}
				//strm3.close();
			}
		} // end loop over all contigs
	}

	// Output
	if (consOpt.output == 0) {
		// Write old SeqAn multi-read alignment format
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		write(strmWrite, fragStore, FastaReadFormat());
		fclose(strmWrite);
	} else if (consOpt.output == 1) {
		// Write Amos
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		write(strmWrite, fragStore, Amos());
		fclose(strmWrite);
	} else if (consOpt.output == 2) {
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		_writeCeleraFrg(strmWrite, fragStore);
		fclose(strmWrite);
	} else if (consOpt.output == 3) {
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		_writeCeleraCgb(strmWrite, fragStore);
		fclose(strmWrite);
	}

	return 0;
}
<commit_msg><commit_after>/*==========================================================================
               SeqAn - The Library for Sequence Analysis
                         http://www.seqan.de
============================================================================
Copyright (C) 2007

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

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

#define SEQAN_PROFILE

#include <seqan/basic.h>

// Profiling
#ifdef SEQAN_PROFILE
		SEQAN_PROTIMESTART(__myProfileTime);
#endif

#include <seqan/consensus.h>
#include <seqan/modifier.h>
#include <seqan/misc/misc_cmdparser.h>

#include <iostream>
#include <fstream>

using namespace seqan;

//////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////

inline void
_addVersion(CommandLineParser& parser) {
	::std::string rev = "$Revision: 4663 $";
	addVersionLine(parser, "Version 0.22 (06. August 2009) Revision: " + rev.substr(11, 4) + "");
}

//////////////////////////////////////////////////////////////////////////////////

int main(int argc, const char *argv[]) {
	// Command line parsing
	CommandLineParser parser;
	_addVersion(parser);

	addTitleLine(parser, "***************************************");
	addTitleLine(parser, "* Multi-read alignment - SeqCons      *");
	addTitleLine(parser, "* (c) Copyright 2009 by Tobias Rausch *");
	addTitleLine(parser, "***************************************");

	addUsageLine(parser, "-r <FASTA file with reads> [Options]");
	addUsageLine(parser, "-a <AMOS message file> [Options]");

	addSection(parser, "Main Options:");
	addOption(parser, addArgumentText(CommandLineOption("r", "reads", "file with reads", OptionType::String), "<FASTA reads file>"));
	addOption(parser, addArgumentText(CommandLineOption("a", "afg", "message file", OptionType::String), "<AMOS afg file>"));
	addOption(parser, addArgumentText(CommandLineOption("o", "outfile", "output filename", OptionType::String, "align.txt"), "<Filename>"));
	addOption(parser, addArgumentText(CommandLineOption("f", "format", "output format", OptionType::String, "afg"), "[seqan | afg]"));
	addOption(parser, addArgumentText(CommandLineOption("m", "method", "alignment method", OptionType::String, "realign"), "[realign | msa]"));
	addOption(parser, addArgumentText(CommandLineOption("b", "bandwidth", "bandwidth", OptionType::Int, 8), "<Int>"));
	addOption(parser, CommandLineOption("n", "noalign", "no align, only convert input", OptionType::Boolean));

	addSection(parser, "MSA Method Options:");
	addOption(parser, addArgumentText(CommandLineOption("ma", "matchlength", "min. overlap length", OptionType::Int, 15), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("qu", "quality", "min. overlap precent identity", OptionType::Int, 80), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("ov", "overlaps", "min. number of overlaps per read", OptionType::Int, 3), "<Int>"));
	addOption(parser, addArgumentText(CommandLineOption("wi", "window", "window size", OptionType::Int, 0), "<Int>"));
	addHelpLine(parser, "/*If this parameter is > 0 then all");
	addHelpLine(parser, "  overlaps within a given window");
	addHelpLine(parser, "  are computed.*/");

	addSection(parser, "ReAlign Method Options:");
	addOption(parser, CommandLineOption("in", "include", "include contig sequence", OptionType::Boolean));
	addOption(parser, addArgumentText(CommandLineOption("rm", "rmethod", "realign method", OptionType::String, "gotoh"), "[nw | gotoh]"));

	if (argc == 1)
	{
		shortHelp(parser, std::cerr);	// print short help and exit
		return 0;
	}

	if (!parse(parser, argc, argv, ::std::cerr)) return 1;
	if (isSetLong(parser, "help") || isSetLong(parser, "version")) return 0;	// print help or version and exit

	// Get all command line options
	ConsensusOptions consOpt;

	// Main options
	getOptionValueLong(parser, "reads", consOpt.readsfile);
	getOptionValueLong(parser, "afg", consOpt.afgfile);
	getOptionValueLong(parser, "outfile", consOpt.outfile);
	String<char> optionVal;
	getOptionValueLong(parser, "format", optionVal);
	if (optionVal == "seqan") consOpt.output = 0;
	else if (optionVal == "afg") consOpt.output = 1;
	else if (optionVal == "frg") consOpt.output = 2;
	else if (optionVal == "cgb") consOpt.output = 3;
	getOptionValueLong(parser, "method", optionVal);
	if (optionVal == "realign") consOpt.method = 0;
	else if (optionVal == "msa") consOpt.method = 1;
	getOptionValueLong(parser, "bandwidth", consOpt.bandwidth);
#ifdef CELERA_OFFSET
	if (!isSetLong(parser, "bandwidth")) consOpt.bandwidth = 15;
#endif
	getOptionValueLong(parser, "noalign", consOpt.noalign);

	// Msa options
	getOptionValueLong(parser, "matchlength", consOpt.matchlength);
	getOptionValueLong(parser, "quality", consOpt.quality);
	getOptionValueLong(parser, "overlaps", consOpt.overlaps);
#ifdef CELERA_OFFSET
	if (!isSetLong(parser, "overlaps")) consOpt.overlaps = 5;
#endif
	getOptionValueLong(parser, "window", consOpt.window);

	// ReAlign options
	getOptionValueLong(parser, "include", consOpt.include);
	getOptionValueLong(parser, "rmethod", optionVal);
	if (optionVal == "nw") consOpt.rmethod = 0;
	else if (optionVal == "gotoh") consOpt.rmethod = 1;

	// Create a new fragment store
	typedef FragmentStore<> TFragmentStore;
	typedef Size<TFragmentStore>::Type TSize;
	TFragmentStore fragStore;

	// Load the reads and layout positions
	TSize numberOfContigs = 0;
	if (!empty(consOpt.readsfile)) {
		// Load simple read file
		FILE* strmReads = fopen(consOpt.readsfile.c_str(), "rb");
		bool moveToFront = false;
		if (consOpt.noalign) moveToFront = true;
		bool success = _convertSimpleReadFile(strmReads, fragStore, consOpt.readsfile, moveToFront);
		fclose(strmReads);
		if (!success) {
			shortHelp(parser, std::cerr);
			return 0;
		}
		numberOfContigs = 1;
	} else if (!empty(consOpt.afgfile)) {
		// Load Amos message file
		FILE* strmReads = fopen(consOpt.afgfile.c_str(), "rb");
		read(strmReads, fragStore, Amos());
		fclose(strmReads);
		numberOfContigs = length(fragStore.contigStore);
	} else {
		shortHelp(parser, std::cerr);
		return 0;
	}

	// Multi-realignment desired or just conversion of the input
	if (!consOpt.noalign) {

		// Profiling
#ifdef SEQAN_PROFILE
				SEQAN_PROTIMEUPDATE(__myProfileTime);
#endif

		// Iterate over all contigs
		for(TSize currentContig = 0; currentContig < numberOfContigs; ++currentContig) {

			if (consOpt.method == 0) {
#ifdef SEQAN_PROFILE
				::std::cout << "ReAlign method" << ::std::endl;
				if (consOpt.rmethod == 0) ::std::cout << "Realign algorithm: Needleman-Wunsch" << ::std::endl;
				else if (consOpt.rmethod == 1) ::std::cout << "Realign algorithm: Gotoh" << ::std::endl;
				::std::cout << "Bandwidth: " << consOpt.bandwidth << ::std::endl;
				::std::cout << "Include reference: " << consOpt.include << ::std::endl;
#endif
				Score<int, WeightedConsensusScore<Score<int, FractionalScore>, Score<int, ConsensusScore> > > combinedScore;
				reAlign(fragStore, combinedScore, currentContig, consOpt.rmethod, consOpt.bandwidth, consOpt.include);

#ifdef SEQAN_PROFILE
				::std::cout << "ReAlignment done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << ::std::endl;
#endif
			} else {

#ifdef SEQAN_PROFILE
				::std::cout << "MSA method" << ::std::endl;
				::std::cout << "Bandwidth: " << consOpt.bandwidth << ::std::endl;
				::std::cout << "Matchlength: " << consOpt.matchlength << ::std::endl;
				::std::cout << "Quality: " << consOpt.quality << ::std::endl;
				::std::cout << "Overlaps: " << consOpt.overlaps << ::std::endl;
				::std::cout << "Window: " << consOpt.window << ::std::endl;
#endif

				// Import all reads of the given contig
				typedef TFragmentStore::TReadSeq TReadSeq;
				StringSet<TReadSeq, Owner<> > readSet;
				String<Pair<TSize, TSize> > begEndPos;
				_loadContigReads(readSet, begEndPos, fragStore, currentContig);
				if (!length(readSet)) continue;

#ifdef SEQAN_PROFILE
				::std::cout << "Import sequences done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << ::std::endl;
#endif

				// Align the reads
				typedef StringSet<TReadSeq, Dependent<> > TStringSet;
				typedef Graph<Alignment<TStringSet, void, WithoutEdgeId> > TAlignGraph;
				TAlignGraph gOut(readSet);
				consensusAlignment(gOut, begEndPos, consOpt);
#ifdef SEQAN_PROFILE
				std::cout << "Multi-read Alignment done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << std::endl;
#endif

				// Update the contig in the fragment store
				updateContig(fragStore, gOut, currentContig);
				clear(gOut);
#ifdef SEQAN_PROFILE
				std::cout << "Update contig done: " << SEQAN_PROTIMEUPDATE(__myProfileTime) << " seconds" << std::endl;
#endif

				//// Debug code for CA
				//mtRandInit();
				//String<char> fileTmp1 = "tmp1";
				//String<char> fileTmp2 = "tmp2";
				//for(int i = 0; i<10; ++i) {
				//	int file = (mtRand() % 20) + 65;
				//	appendValue(fileTmp1, char(file));
				//	appendValue(fileTmp2, char(file));
				//}
				//std::fstream strm3;
				//strm3.open(toCString(fileTmp2), std::ios_base::out | std::ios_base::trunc);
				//for(int i = 0;i<(int) length(origStrSet); ++i) {
				//	std::stringstream name;
				//	name << value(begEndPos, i).i1 << "," << value(begEndPos, i).i2;
				//	String<char> myTitle = name.str();
				//	write(strm3, origStrSet[i], myTitle, Fasta());
				//	if (value(begEndPos, i).i1 > value(begEndPos, i).i2) reverseComplementInPlace(origStrSet[i]);
				//}
				//strm3.close();
			}
		} // end loop over all contigs
	}

	// Output
	if (consOpt.output == 0) {
		// Write old SeqAn multi-read alignment format
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		write(strmWrite, fragStore, FastaReadFormat());
		fclose(strmWrite);
	} else if (consOpt.output == 1) {
		// Write Amos
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		write(strmWrite, fragStore, Amos());
		fclose(strmWrite);
	} else if (consOpt.output == 2) {
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		_writeCeleraFrg(strmWrite, fragStore);
		fclose(strmWrite);
	} else if (consOpt.output == 3) {
		FILE* strmWrite = fopen(consOpt.outfile.c_str(), "w");
		_writeCeleraCgb(strmWrite, fragStore);
		fclose(strmWrite);
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <typeinfo>
#include <time.h>
#include <cstdio>
#include <vector>
#include <time.h>

#define SEQAN_DEBUG
#define SEQAN_TEST
#define TEST_PATH "projects/tests/index/"

#include <seqan/index.h>
#include <seqan/file.h>

using namespace std;
using namespace seqan;

void testGappedShapes()
{
	String<char> shape_string = "0010011011101";
	Shape<Dna,GenericShape> shape1;
	stringToShape(shape1, shape_string);
	Shape<Dna,GenericShape> shape2 = Shape<Dna,GenericShape>(shape1);

	SEQAN_ASSERT(shape1.weight == shape2.weight);
	SEQAN_ASSERT(shape1.span == shape2.span);
	SEQAN_ASSERT(shape1.diffs == shape2.diffs);
	SEQAN_ASSERT(length(shape1) == length(shape2));
	SEQAN_ASSERT(weight(shape1) == weight(shape2));
/*
	Shape<Dna,GenericShape> shape3 = Shape<Dna,GenericShape>(5, 13);
	shape3[0]=2;
	shape3[1]=2;
	shape3[2]=1;
	shape3[3]=1;
	shape3[4]=2;
	shape3[5]=1;
	shape3[6]=1;
	shape3[7]=2;
	for(int i = 0; i < 8; ++i)
        SEQAN_ASSERT(shape1[i] == shape3[i]);
*/
}

void testUngappedShapes()
{
	Shape<Dna,SimpleShape> shape1;
	resize(shape1, 4);
	Shape<Dna,SimpleShape> shape2 = Shape<Dna,SimpleShape>(shape1);

	SEQAN_ASSERT(shape1.span == shape2.span);
	SEQAN_ASSERT(shape1.leftFactor == shape2.leftFactor);
	SEQAN_ASSERT(length(shape1) == length(shape2));
	SEQAN_ASSERT(weight(shape1) == weight(shape2));

	Shape<Dna,SimpleShape> shape3 = Shape<Dna,SimpleShape>(4);
	SEQAN_ASSERT(shape3.leftFactor == 64);
	SEQAN_ASSERT(shape1.leftFactor == shape3.leftFactor);

}

/*
void testQGramIndexSchnell()
{
	clock_t start, finish;
	double duration;

	String<Dna> text;
	fstream strm_t;
	strm_t.open(TEST_PATH "fasta.txt", ios_base::in);
	read(strm_t, text, Fasta());
	String<Dna> next;
	resize(next,length(text));
	for(int i = 0; i < 1; ++i)							// datei zu ende?
	{
		arrayCopyForward(begin(text),end(text),begin(next));
		append(text, next);
	}
	strm_t.close();

	String<char> shape_string = "1000100100001110011";
	int q = length(shape_string);
	Shape<Dna,GenericShape> shape;
	stringToShape(shape, shape_string);

	typedef Position<String<Dna> >::Type TPosition;
	String<TPosition> index;
	resize(index, length(text) - q + 2);

	String<TPosition> pos;
	int pos_size = _intPow((unsigned)ValueSize<Dna>::VALUE, weight(shape));
	pos_size += 1;
	resize(pos, pos_size);

	start = clock();
	Nothing nothing;
	createQGramIndex(index, pos, nothing, text, shape, 1);
	finish = clock();
	duration = (double)(finish - start) / CLOCKS_PER_SEC;
	//cout << "\nQGramIndex bauen dauert: " << duration << " Sekunden.\n\n";

}
*/
/*
void testGappedQGramIndex()
{
	String<Dna> text = "CTGAACCCTAAACCCT";
	String<char> shape_string = "101";
	int q = length(shape_string);
	Shape<Dna,GenericShape> shape;
	stringToShape(shape, shape_string);

	typedef Position<String<Dna> >::Type TPosition;
	String<TPosition> index;
	resize(index, length(text) - q + 2);

	String<TPosition> pos;
    int pos_size = _intPow((unsigned)ValueSize<Dna>::VALUE, weight(shape));
	pos_size += 1;
	resize(pos, pos_size);

	Nothing nothing;
	createQGramIndex(index, pos, nothing, text, shape, 1);

	SEQAN_ASSERT(pos[0] == 0);
	SEQAN_ASSERT(pos[1] == 1);
	SEQAN_ASSERT(pos[2] == 5);
	SEQAN_ASSERT(pos[3] == 5);
	SEQAN_ASSERT(pos[4] == 5);
	SEQAN_ASSERT(pos[5] == 6);
	SEQAN_ASSERT(pos[6] == 8);
	SEQAN_ASSERT(pos[7] == 9);
	SEQAN_ASSERT(pos[8] == 11);
	SEQAN_ASSERT(pos[9] == 12);
	SEQAN_ASSERT(pos[10] == 12);
	SEQAN_ASSERT(pos[11] == 12);
	SEQAN_ASSERT(pos[12] == 12);
	SEQAN_ASSERT(pos[13] == 14);
	SEQAN_ASSERT(pos[14] == 14);
	SEQAN_ASSERT(pos[15] == 14);
	SEQAN_ASSERT(pos[16] == 14);

	SEQAN_ASSERT(index[0] == 9);
	SEQAN_ASSERT(index[1] == 11);
	SEQAN_ASSERT(index[2] == 10);
	SEQAN_ASSERT(index[3] == 4);
	SEQAN_ASSERT(index[4] == 3);
	SEQAN_ASSERT(index[5] == 7);
	SEQAN_ASSERT(index[6] == 12);
	SEQAN_ASSERT(index[7] == 5);
	SEQAN_ASSERT(index[8] == 0);
	SEQAN_ASSERT(index[9] == 13);
	SEQAN_ASSERT(index[10] == 6);
	SEQAN_ASSERT(index[11] == 2);
	SEQAN_ASSERT(index[12] == 8);
	SEQAN_ASSERT(index[13] == 1);

}
*/
void testUngappedQGramIndex()
{
	String<Dna> text = "CTGAACCCTAAACCCT";
	int q = 2;
	Shape<Dna,SimpleShape> shape;
	resize(shape, q);

	typedef Position<String<Dna> >::Type TPosition;
	String<TPosition> index;
	resize(index, length(text) - q + 1);

	String<TPosition> pos;
    int pos_size = _intPow((unsigned)ValueSize<Dna>::VALUE, q);
	pos_size += 1;
	resize(pos, pos_size);

	Nothing nothing;
	createQGramIndex(index, pos, nothing, text, shape, 1);

	SEQAN_ASSERT(pos[0] == 0);
	SEQAN_ASSERT(pos[1] == 3);
	SEQAN_ASSERT(pos[2] == 5);
	SEQAN_ASSERT(pos[3] == 5);
	SEQAN_ASSERT(pos[4] == 5);
	SEQAN_ASSERT(pos[5] == 5);
	SEQAN_ASSERT(pos[6] == 9);
	SEQAN_ASSERT(pos[7] == 9);
	SEQAN_ASSERT(pos[8] == 12);
	SEQAN_ASSERT(pos[9] == 13);
	SEQAN_ASSERT(pos[10] == 13);
	SEQAN_ASSERT(pos[11] == 13);
	SEQAN_ASSERT(pos[12] == 13);
	SEQAN_ASSERT(pos[13] == 14);
	SEQAN_ASSERT(pos[14] == 14);
	SEQAN_ASSERT(pos[15] == 15);

	SEQAN_ASSERT(index[0] == 3);
	SEQAN_ASSERT(index[1] == 9);
	SEQAN_ASSERT(index[2] == 10);
	SEQAN_ASSERT(index[3] == 4);
	SEQAN_ASSERT(index[4] == 11);
	SEQAN_ASSERT(index[5] == 5);
	SEQAN_ASSERT(index[6] == 6);
	SEQAN_ASSERT(index[7] == 12);
	SEQAN_ASSERT(index[8] == 13);
	SEQAN_ASSERT(index[9] == 0);
	SEQAN_ASSERT(index[10] == 7);
	SEQAN_ASSERT(index[11] == 14);
	SEQAN_ASSERT(index[12] == 2);
	SEQAN_ASSERT(index[13] == 8);
	SEQAN_ASSERT(index[14] == 1);
}

//////////////////////////////////////////////////////////////////////////////

void testQGramFind()
{
	typedef Index<String<char>, Index_QGram<UngappedShape<2> > > TQGramIndex;
	TQGramIndex idx("to be or not to be");
	Finder<TQGramIndex> finder(idx);

	SEQAN_ASSERT_TRUE(find(finder, "be"));
	SEQAN_ASSERT_TRUE(position(finder) == 3);
	SEQAN_ASSERT_TRUE(find(finder, "be"));
	SEQAN_ASSERT_TRUE(position(finder) == 16);
	SEQAN_ASSERT_TRUE(!find(finder, "be"));
/*
	while (find(finder, "be"))
	{
		cout << position(finder) << "\n";
	}
*/
}

//////////////////////////////////////////////////////////////////////////////

void testQGramIndex()
{
	SEQAN_TREPORT("TEST QGRAM BEGIN")

//	testGappedQGramIndex();
	testUngappedQGramIndex();
//	testQGramIndexSchnell();
	testGappedShapes();
	testUngappedShapes();

	testQGramFind();

	debug::verifyCheckpoints("projects/library/seqan/index/index_qgram.h");
	debug::verifyCheckpoints("projects/library/seqan/index/shape_base.h");
	debug::verifyCheckpoints("projects/library/seqan/index/shape_gapped.h");

	debug::verifyCheckpoints("projects/library/seqan/index/index_qgram_find.h");

	SEQAN_TREPORT("TEST QGRAM END")
}
<commit_msg>removed old cpps<commit_after><|endoftext|>


<commit_before>#include "gui_main_window.h"
#include "ui_gui_main_window.h"
#include "parse_batch.h"
#include "../decompose_imf_lib/optimization_task.h"
#include "../cpp_utils/std_make_unique.h"
#include "../cpp_utils/exception_handling.h"

#include <list>
#include <QSettings>

static const char * tasksTextName = "tasksText";

namespace gui {

struct MainWindow::Impl
{
    std::list<dimf::OptimizationParams> optParams;
    Ui::MainWindow ui;
    dimf::OptimizationTask optTask;

    void updateState()
    {
        ui.runNextOptimizationPushButton->setEnabled( !optParams.empty() );
        ui.statusbar->showMessage(
                    QString("%1 optimization runs left.")
                    .arg(optParams.size()) );
    }
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow{parent}
    , m{ std::make_unique<Impl>() }
{
    m->ui.setupUi(this);
    m->ui.textEditor->setPlainText(
                QSettings().value( tasksTextName ).toString() );
    m->updateState();
}

MainWindow::~MainWindow()
{
    CU_SWALLOW_ALL_EXCEPTIONS_FROM
    {
        QSettings().setValue(
                    tasksTextName,
                    m->ui.textEditor->toPlainText() );
    };
}

void MainWindow::parse()
{
    auto optParams = parseBatch(
                std::istringstream(
                    m->ui.textEditor->toPlainText().toStdString()) );
    decltype(m->optParams)(
                make_move_iterator(begin(optParams)),
                make_move_iterator(end(optParams)) ).swap(m->optParams);
    m->updateState();
}

void MainWindow::runNextOptimization()
{
    m->optTask.restart( m->optParams.front() );
    m->optParams.pop_front();
    m->updateState();
}

} // namespace gui
<commit_msg>Implemented automatic cancelling of an optimization task after a given number of iterations.<commit_after>#include "gui_main_window.h"
#include "ui_gui_main_window.h"
#include "parse_batch.h"
#include "../decompose_imf_lib/optimization_task.h"
#include "../qt_utils/invoke_in_thread.h"
#include "../cpp_utils/std_make_unique.h"
#include "../cpp_utils/exception_handling.h"

#include <list>
#include <QSettings>

static const char * tasksTextName = "tasksText";

namespace gui {

struct MainWindow::Impl
{
    std::list<BatchOptimizationParams> optParams;
    Ui::MainWindow ui;
    dimf::OptimizationTask optTask;

    void updateState()
    {
        ui.runNextOptimizationPushButton->setEnabled( !optParams.empty() );
        ui.statusbar->showMessage(
                    QString("%1 optimization runs left.")
                    .arg(optParams.size()) );
    }
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow{parent}
    , m{ std::make_unique<Impl>() }
{
    m->ui.setupUi(this);
    m->ui.textEditor->setPlainText(
                QSettings().value( tasksTextName ).toString() );
    m->updateState();
}

MainWindow::~MainWindow()
{
    CU_SWALLOW_ALL_EXCEPTIONS_FROM
    {
        QSettings().setValue(
                    tasksTextName,
                    m->ui.textEditor->toPlainText() );
    };
}

void MainWindow::parse()
{
    auto optParams = parseBatch(
                std::istringstream(
                    m->ui.textEditor->toPlainText().toStdString()) );
    decltype(m->optParams)(
                make_move_iterator(begin(optParams)),
                make_move_iterator(end(optParams)) ).swap(m->optParams);
    m->updateState();
}

void MainWindow::runNextOptimization()
{
    if ( m->optParams.empty() )
        return;

    auto & nextOptimization = m->optParams.front();
    const auto stepLimit = nextOptimization.stepLimit;
    nextOptimization.shallCancel =
            [this,stepLimit]( size_t nIter )
    {
        if ( nIter >= stepLimit )
            return true;
        qu::invokeInGuiThread( [this](){ runNextOptimization(); } );
        return false;
    };
    m->optTask.restart( nextOptimization );
    m->optParams.pop_front();
    m->updateState();
}

} // namespace gui
<|endoftext|>