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

#include "chrome/browser/speech/speech_input_bubble_controller.h"

#include "chrome/browser/browser_thread.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "gfx/rect.h"

namespace speech_input {

SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate)
    : delegate_(delegate),
      current_bubble_caller_id_(0),
      registrar_(new NotificationRegistrar) {
}

SpeechInputBubbleController::~SpeechInputBubbleController() {
  DCHECK(bubbles_.size() == 0);
}

void SpeechInputBubbleController::CreateBubble(int caller_id,
                                               int render_process_id,
                                               int render_view_id,
                                               const gfx::Rect& element_rect) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(this, &SpeechInputBubbleController::CreateBubble,
                          caller_id, render_process_id, render_view_id,
                          element_rect));
    return;
  }
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  TabContents* tab_contents = tab_util::GetTabContentsByID(render_process_id,
                                                           render_view_id);

  DCHECK_EQ(0u, bubbles_.count(caller_id));
  SpeechInputBubble* bubble = SpeechInputBubble::Create(tab_contents, this,
                                                        element_rect);
  if (!bubble)  // could be null if tab or display rect were invalid.
    return;

  bubbles_[caller_id] = bubble;

  UpdateTabContentsSubscription(caller_id, BUBBLE_ADDED);
}

void SpeechInputBubbleController::CloseBubble(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0);
}

void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE,
                           string16(), 0);
}

void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE,
                           string16(), 0);
}

void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id,
                                                       float volume) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(),
                           volume);
}

void SpeechInputBubbleController::SetBubbleMessage(int caller_id,
                                                   const string16& text) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0);
}

void SpeechInputBubbleController::UpdateTabContentsSubscription(
    int caller_id, ManageSubscriptionAction action) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If there are any other bubbles existing for the same TabContents, we would
  // have subscribed to tab close notifications on their behalf and we need to
  // stay registered. So we don't change the subscription in such cases.
  TabContents* tab_contents = bubbles_[caller_id]->tab_contents();
  for (BubbleCallerIdMap::iterator iter = bubbles_.begin();
       iter != bubbles_.end(); ++iter) {
    if (iter->second->tab_contents() == tab_contents &&
        iter->first != caller_id) {
      // At least one other bubble exists for the same TabContents. So don't
      // make any change to the subscription.
      return;
    }
  }

  if (action == BUBBLE_ADDED) {
    registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                    Source<TabContents>(tab_contents));
  } else {
    registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
                    Source<TabContents>(tab_contents));
  }
}

void SpeechInputBubbleController::Observe(NotificationType type,
                                          const NotificationSource& source,
                                          const NotificationDetails& details) {
  if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
    // Cancel all bubbles and active recognition sessions for this tab.
    TabContents* tab_contents = Source<TabContents>(source).ptr();
    BubbleCallerIdMap::iterator iter = bubbles_.begin();
    while (iter != bubbles_.end()) {
      if (iter->second->tab_contents() == tab_contents) {
        BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
            NewRunnableMethod(
                this,
                &SpeechInputBubbleController::InvokeDelegateButtonClicked,
                iter->first, SpeechInputBubble::BUTTON_CANCEL));
        CloseBubble(iter->first);
        // We expect to have a very small number of items in this map so
        // redo-ing from start is ok.
        iter = bubbles_.begin();
      } else {
        ++iter;
      }
    }
  } else {
    NOTREACHED() << "Unknown notification";
  }
}

void SpeechInputBubbleController::ProcessRequestInUiThread(
    int caller_id, RequestType type, const string16& text, float volume) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
        this, &SpeechInputBubbleController::ProcessRequestInUiThread,
        caller_id, type, text, volume));
    return;
  }
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // The bubble may have been closed before we got a chance to process this
  // request. So check before proceeding.
  if (!bubbles_.count(caller_id))
    return;

  bool change_active_bubble = (type == REQUEST_SET_RECORDING_MODE ||
                               type == REQUEST_SET_MESSAGE);
  if (change_active_bubble) {
    if (current_bubble_caller_id_ && current_bubble_caller_id_ != caller_id)
      bubbles_[current_bubble_caller_id_]->Hide();
    current_bubble_caller_id_ = caller_id;
  }

  SpeechInputBubble* bubble = bubbles_[caller_id];
  switch (type) {
    case REQUEST_SET_RECORDING_MODE:
      bubble->SetRecordingMode();
      break;
    case REQUEST_SET_RECOGNIZING_MODE:
      bubble->SetRecognizingMode();
      break;
    case REQUEST_SET_MESSAGE:
      bubble->SetMessage(text);
      break;
    case REQUEST_SET_INPUT_VOLUME:
      bubble->SetInputVolume(volume);
      break;
    case REQUEST_CLOSE:
      if (current_bubble_caller_id_ == caller_id)
        current_bubble_caller_id_ = 0;
      UpdateTabContentsSubscription(caller_id, BUBBLE_REMOVED);
      delete bubble;
      bubbles_.erase(caller_id);
      break;
    default:
      NOTREACHED();
      break;
  }

  if (change_active_bubble)
    bubble->Show();
}

void SpeechInputBubbleController::InfoBubbleButtonClicked(
    SpeechInputBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(current_bubble_caller_id_);

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(
          this,
          &SpeechInputBubbleController::InvokeDelegateButtonClicked,
          current_bubble_caller_id_, button));
}

void SpeechInputBubbleController::InfoBubbleFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(current_bubble_caller_id_);

  int old_bubble_caller_id = current_bubble_caller_id_;
  current_bubble_caller_id_ = 0;
  bubbles_[old_bubble_caller_id]->Hide();

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(
          this,
          &SpeechInputBubbleController::InvokeDelegateFocusChanged,
          old_bubble_caller_id));
}

void SpeechInputBubbleController::InvokeDelegateButtonClicked(
    int caller_id, SpeechInputBubble::Button button) {
  delegate_->InfoBubbleButtonClicked(caller_id, button);
}

void SpeechInputBubbleController::InvokeDelegateFocusChanged(int caller_id) {
  delegate_->InfoBubbleFocusChanged(caller_id);
}

}  // namespace speech_input
<commit_msg>Avoid closing speech input UI bubble twice.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/speech/speech_input_bubble_controller.h"

#include "chrome/browser/browser_thread.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_source.h"
#include "chrome/common/notification_type.h"
#include "gfx/rect.h"

namespace speech_input {

SpeechInputBubbleController::SpeechInputBubbleController(Delegate* delegate)
    : delegate_(delegate),
      current_bubble_caller_id_(0),
      registrar_(new NotificationRegistrar) {
}

SpeechInputBubbleController::~SpeechInputBubbleController() {
  DCHECK(bubbles_.size() == 0);
}

void SpeechInputBubbleController::CreateBubble(int caller_id,
                                               int render_process_id,
                                               int render_view_id,
                                               const gfx::Rect& element_rect) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        NewRunnableMethod(this, &SpeechInputBubbleController::CreateBubble,
                          caller_id, render_process_id, render_view_id,
                          element_rect));
    return;
  }
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  TabContents* tab_contents = tab_util::GetTabContentsByID(render_process_id,
                                                           render_view_id);

  DCHECK_EQ(0u, bubbles_.count(caller_id));
  SpeechInputBubble* bubble = SpeechInputBubble::Create(tab_contents, this,
                                                        element_rect);
  if (!bubble)  // could be null if tab or display rect were invalid.
    return;

  bubbles_[caller_id] = bubble;

  UpdateTabContentsSubscription(caller_id, BUBBLE_ADDED);
}

void SpeechInputBubbleController::CloseBubble(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_CLOSE, string16(), 0);
}

void SpeechInputBubbleController::SetBubbleRecordingMode(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_RECORDING_MODE,
                           string16(), 0);
}

void SpeechInputBubbleController::SetBubbleRecognizingMode(int caller_id) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_RECOGNIZING_MODE,
                           string16(), 0);
}

void SpeechInputBubbleController::SetBubbleInputVolume(int caller_id,
                                                       float volume) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_INPUT_VOLUME, string16(),
                           volume);
}

void SpeechInputBubbleController::SetBubbleMessage(int caller_id,
                                                   const string16& text) {
  ProcessRequestInUiThread(caller_id, REQUEST_SET_MESSAGE, text, 0);
}

void SpeechInputBubbleController::UpdateTabContentsSubscription(
    int caller_id, ManageSubscriptionAction action) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // If there are any other bubbles existing for the same TabContents, we would
  // have subscribed to tab close notifications on their behalf and we need to
  // stay registered. So we don't change the subscription in such cases.
  TabContents* tab_contents = bubbles_[caller_id]->tab_contents();
  for (BubbleCallerIdMap::iterator iter = bubbles_.begin();
       iter != bubbles_.end(); ++iter) {
    if (iter->second->tab_contents() == tab_contents &&
        iter->first != caller_id) {
      // At least one other bubble exists for the same TabContents. So don't
      // make any change to the subscription.
      return;
    }
  }

  if (action == BUBBLE_ADDED) {
    registrar_->Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
                    Source<TabContents>(tab_contents));
  } else {
    registrar_->Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
                    Source<TabContents>(tab_contents));
  }
}

void SpeechInputBubbleController::Observe(NotificationType type,
                                          const NotificationSource& source,
                                          const NotificationDetails& details) {
  if (type == NotificationType::TAB_CONTENTS_DESTROYED) {
    // Cancel all bubbles and active recognition sessions for this tab.
    TabContents* tab_contents = Source<TabContents>(source).ptr();
    BubbleCallerIdMap::iterator iter = bubbles_.begin();
    while (iter != bubbles_.end()) {
      if (iter->second->tab_contents() == tab_contents) {
        BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
            NewRunnableMethod(
                this,
                &SpeechInputBubbleController::InvokeDelegateButtonClicked,
                iter->first, SpeechInputBubble::BUTTON_CANCEL));
        CloseBubble(iter->first);
        // We expect to have a very small number of items in this map so
        // redo-ing from start is ok.
        iter = bubbles_.begin();
      } else {
        ++iter;
      }
    }
  } else {
    NOTREACHED() << "Unknown notification";
  }
}

void SpeechInputBubbleController::ProcessRequestInUiThread(
    int caller_id, RequestType type, const string16& text, float volume) {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
        this, &SpeechInputBubbleController::ProcessRequestInUiThread,
        caller_id, type, text, volume));
    return;
  }
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // The bubble may have been closed before we got a chance to process this
  // request. So check before proceeding.
  if (!bubbles_.count(caller_id))
    return;

  bool change_active_bubble = (type == REQUEST_SET_RECORDING_MODE ||
                               type == REQUEST_SET_MESSAGE);
  if (change_active_bubble) {
    if (current_bubble_caller_id_ && current_bubble_caller_id_ != caller_id)
      bubbles_[current_bubble_caller_id_]->Hide();
    current_bubble_caller_id_ = caller_id;
  }

  SpeechInputBubble* bubble = bubbles_[caller_id];
  switch (type) {
    case REQUEST_SET_RECORDING_MODE:
      bubble->SetRecordingMode();
      break;
    case REQUEST_SET_RECOGNIZING_MODE:
      bubble->SetRecognizingMode();
      break;
    case REQUEST_SET_MESSAGE:
      bubble->SetMessage(text);
      break;
    case REQUEST_SET_INPUT_VOLUME:
      bubble->SetInputVolume(volume);
      break;
    case REQUEST_CLOSE:
      if (current_bubble_caller_id_ == caller_id)
        current_bubble_caller_id_ = 0;
      UpdateTabContentsSubscription(caller_id, BUBBLE_REMOVED);
      delete bubble;
      bubbles_.erase(caller_id);
      break;
    default:
      NOTREACHED();
      break;
  }

  if (change_active_bubble)
    bubble->Show();
}

void SpeechInputBubbleController::InfoBubbleButtonClicked(
    SpeechInputBubble::Button button) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(current_bubble_caller_id_);

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(
          this,
          &SpeechInputBubbleController::InvokeDelegateButtonClicked,
          current_bubble_caller_id_, button));
}

void SpeechInputBubbleController::InfoBubbleFocusChanged() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(current_bubble_caller_id_);

  int old_bubble_caller_id = current_bubble_caller_id_;
  current_bubble_caller_id_ = 0;

  BrowserThread::PostTask(
      BrowserThread::IO, FROM_HERE,
      NewRunnableMethod(
          this,
          &SpeechInputBubbleController::InvokeDelegateFocusChanged,
          old_bubble_caller_id));
}

void SpeechInputBubbleController::InvokeDelegateButtonClicked(
    int caller_id, SpeechInputBubble::Button button) {
  delegate_->InfoBubbleButtonClicked(caller_id, button);
}

void SpeechInputBubbleController::InvokeDelegateFocusChanged(int caller_id) {
  delegate_->InfoBubbleFocusChanged(caller_id);
}

}  // namespace speech_input
<|endoftext|>


<commit_before>#pragma once

#include "debug.hpp"

#include <ostream>
#include <bitset>

namespace utki{

/**
 * @brief class representing a set of flags.
 * If you define an enumeration according to the following rules:
 * - enumeration is a 'enum class'.
 * - there is no direct assignment of values to enumeration items, i.e. values are in strict ascending order
 * - the very last item is enum_size
 *
 * For example:
 * @code
 * enum class my_enum{
 *     zeroth_item,
 *     first_item,
 *     second_item,
 *     third_item,
 *     ...
 *     enum_size
 * };
 *
 * @endcode
 * Then, the 'flags' can be used as follows:
 * @code
 * utki::flags<my_enum> fs;
 *
 * fs.set(my_enum::first_item, true).set(my_enum::third_item, true);
 *
 * if(fs.get(my_enum::first_item)){
 *     //first_item flag is set
 * }
 *
 * if(fs.get(my_enum::zeroth_item)){
 *     //Will not get here, since zeroth_item flag is not set
 * }
 *
 * @endcode
 */
template <class enum_type> class flags{
	static_assert(int(enum_type::enum_size) >= 0, "enumeration must define enum_size item");
	static_assert(unsigned(enum_type::enum_size) > 0, "enumeration must define at least one item");

	std::bitset<size_t(enum_type::enum_size)> bitset;
public:

	/**
	 * @brief Constructor.
	 * All flags are initialized to the same given value.
	 * @param initial_value - value which initializes all flags.
	 */
	flags(bool initial_value = false){
		if(initial_value){
			this->bitset.set();
		}
	}

	/**
	 * @brief Constructor.
	 * @param initially_set_flags - list of flags which will be set initially.
	 */
	flags(std::initializer_list<enum_type> initially_set_flags){
		for(auto v : initially_set_flags){
			this->bitset.set(size_t(v));
		}
	}

	/**
	 * @brief Constructor.
	 * Constructs a flags instance with only one flag set initially.
	 * @param e - flag to set.
	 */
	flags(enum_type e) :
			flags({e})
	{}

	constexpr size_t size()const noexcept{
		return this->bitset.size();
	}

	constexpr bool operator[](enum_type flag)const{
		return this->bitset[size_t(flag)];
	}

	typename std::bitset<size_t(enum_type::enum_size)>::reference operator[](enum_type flag){
		return this->bitset[size_t(flag)];
	}

	/**
	 * @brief Get value of a given flag.
	 * @param flag - flag to get value of.
	 * @return true if the flag is set.
	 * @return false otherwise.
	 */
	bool get(enum_type flag)const noexcept{
		ASSERT(flag < enum_type::enum_size)
		return this->bitset[size_t(flag)];
	}

	/**
	 * @brief Set value of a given flag.
	 * @param flag - flag to set value of.
	 * @param value - value to set.
	 * @return Reference to this Flags.
	 */
	flags& set(enum_type flag, bool value = true)noexcept{
		ASSERT(flag < enum_type::enum_size)
		this->bitset.set(size_t(flag), value);
		return *this;
	}

	/**
	 * @brief Set all flags to given value.
	 * @param value - value to set all flags to.
	 * @return Reference to this Flags.
	 */
	flags& set(bool value = true)noexcept{
		if(value){
			this->bitset.set();
		}else{
			this->bitset.reset();
		}
		return *this;
	}

	/**
	 * @brief Clear given flag.
	 * @param flag - flag to clear.
	 * @return Reference to this Flags.
	 */
	flags& clear(enum_type flag)noexcept{
		this->bitset.reset(size_t(flag));
		return *this;
	}

	/**
	 * @brief Clear all flags.
	 * @return Reference to this Flags.
	 */
	flags& clear()noexcept{
		this->bitset.reset();
		return *this;
	}

	/**
	 * @brief Check if all flags are cleared.
	 * @return true if all flags are cleared.
	 * @return false otherwise.
	 */
	bool is_clear()const noexcept{
		return this->bitset.none();
	}

	/**
	 * @brief Check if all flags are set.
	 * @return true if all flags are set.
	 * @return false otherwise.
	 */
	bool is_set()const noexcept{
		return this->bitset.all();
	}

	/**
	 * @brief Inverts all the flags.
	 * @return Reference to this Flags.
	 */
	flags& invert()noexcept{
		this->bitset.flip();
		return *this;
	}

	/**
	 * @brief Operator NOT.
	 * @return Inverted instance of Flags.
	 */
	flags operator~()const noexcept{
		return flags(*this).invert();
	}

	/**
	 * @brief Operator assignment AND.
	 * @param f - flags to perform AND operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator&=(const flags& f)noexcept{
		this->bitset &= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator AND.
	 * @param f - flags to perform AND operation with.
	 * @return Instance of Flags resulting from AND operation.
	 */
	flags operator&(const flags& f)const noexcept{
		return flags(*this).operator&=(f);
	}

	/**
	 * @brief Operator assignment OR.
	 * @param f - flags to perform OR operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator|=(const flags& f)noexcept{
		this->bitset |= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator OR.
	 * @param f - flags to perform OR operation with.
	 * @return Instance of Flags resulting from OR operation.
	 */
	flags operator|(const flags& f)const noexcept{
		return flags(*this).operator|=(f);
	}

	flags operator|(enum_type e)const noexcept{
		return flags(*this).set(e);
	}

	/**
	 * @brief Operator assignment XOR.
	 * @param f - flags to perform XOR operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator^=(const flags& f)noexcept{
		this->bitset ^= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator OR.
	 * @param f - flags to perform OR operation with.
	 * @return Instance of Flags resulting from OR operation.
	 */
	flags operator^(const flags& f)const noexcept{
		return flags(*this).operator^=(f);
	}

	friend std::ostream& operator<<(std::ostream& o, const flags& f){
		return o << f.bitset;
	}
};

/**
 * @brief Construct flags object.
 * @param initially_set_flags - list of flags which will be set initially.
 * @return newly created flags object.
 */
template <class T> flags<T> make_flags(std::initializer_list<T> initially_set_flags){
	return flags<T>(initially_set_flags);
}

}

template <class enum_type>
typename std::enable_if<
		std::is_enum<enum_type>::value,
		utki::flags<enum_type>
	>::type
operator|(enum_type e1, enum_type e2){
	return {e1, e2};
}
<commit_msg>make operator| only for enums defining enum_size<commit_after>#pragma once

#include "debug.hpp"

#include <ostream>
#include <bitset>

namespace utki{

/**
 * @brief class representing a set of flags.
 * If you define an enumeration according to the following rules:
 * - enumeration is a 'enum class'.
 * - there is no direct assignment of values to enumeration items, i.e. values are in strict ascending order
 * - the very last item is enum_size
 *
 * For example:
 * @code
 * enum class my_enum{
 *     zeroth_item,
 *     first_item,
 *     second_item,
 *     third_item,
 *     ...
 *     enum_size
 * };
 *
 * @endcode
 * Then, the 'flags' can be used as follows:
 * @code
 * utki::flags<my_enum> fs;
 *
 * fs.set(my_enum::first_item, true).set(my_enum::third_item, true);
 *
 * if(fs.get(my_enum::first_item)){
 *     //first_item flag is set
 * }
 *
 * if(fs.get(my_enum::zeroth_item)){
 *     //Will not get here, since zeroth_item flag is not set
 * }
 *
 * @endcode
 */
template <class enum_type> class flags{
	static_assert(int(enum_type::enum_size) >= 0, "enumeration must define enum_size item");
	static_assert(unsigned(enum_type::enum_size) > 0, "enumeration must define at least one item");

	std::bitset<size_t(enum_type::enum_size)> bitset;
public:

	/**
	 * @brief Constructor.
	 * All flags are initialized to the same given value.
	 * @param initial_value - value which initializes all flags.
	 */
	flags(bool initial_value = false){
		if(initial_value){
			this->bitset.set();
		}
	}

	/**
	 * @brief Constructor.
	 * @param initially_set_flags - list of flags which will be set initially.
	 */
	flags(std::initializer_list<enum_type> initially_set_flags){
		for(auto v : initially_set_flags){
			this->bitset.set(size_t(v));
		}
	}

	/**
	 * @brief Constructor.
	 * Constructs a flags instance with only one flag set initially.
	 * @param e - flag to set.
	 */
	flags(enum_type e) :
			flags({e})
	{}

	constexpr size_t size()const noexcept{
		return this->bitset.size();
	}

	constexpr bool operator[](enum_type flag)const{
		return this->bitset[size_t(flag)];
	}

	typename std::bitset<size_t(enum_type::enum_size)>::reference operator[](enum_type flag){
		return this->bitset[size_t(flag)];
	}

	/**
	 * @brief Get value of a given flag.
	 * @param flag - flag to get value of.
	 * @return true if the flag is set.
	 * @return false otherwise.
	 */
	bool get(enum_type flag)const noexcept{
		ASSERT(flag < enum_type::enum_size)
		return this->bitset[size_t(flag)];
	}

	/**
	 * @brief Set value of a given flag.
	 * @param flag - flag to set value of.
	 * @param value - value to set.
	 * @return Reference to this Flags.
	 */
	flags& set(enum_type flag, bool value = true)noexcept{
		ASSERT(flag < enum_type::enum_size)
		this->bitset.set(size_t(flag), value);
		return *this;
	}

	/**
	 * @brief Set all flags to given value.
	 * @param value - value to set all flags to.
	 * @return Reference to this Flags.
	 */
	flags& set(bool value = true)noexcept{
		if(value){
			this->bitset.set();
		}else{
			this->bitset.reset();
		}
		return *this;
	}

	/**
	 * @brief Clear given flag.
	 * @param flag - flag to clear.
	 * @return Reference to this Flags.
	 */
	flags& clear(enum_type flag)noexcept{
		this->bitset.reset(size_t(flag));
		return *this;
	}

	/**
	 * @brief Clear all flags.
	 * @return Reference to this Flags.
	 */
	flags& clear()noexcept{
		this->bitset.reset();
		return *this;
	}

	/**
	 * @brief Check if all flags are cleared.
	 * @return true if all flags are cleared.
	 * @return false otherwise.
	 */
	bool is_clear()const noexcept{
		return this->bitset.none();
	}

	/**
	 * @brief Check if all flags are set.
	 * @return true if all flags are set.
	 * @return false otherwise.
	 */
	bool is_set()const noexcept{
		return this->bitset.all();
	}

	/**
	 * @brief Inverts all the flags.
	 * @return Reference to this Flags.
	 */
	flags& invert()noexcept{
		this->bitset.flip();
		return *this;
	}

	/**
	 * @brief Operator NOT.
	 * @return Inverted instance of Flags.
	 */
	flags operator~()const noexcept{
		return flags(*this).invert();
	}

	/**
	 * @brief Operator assignment AND.
	 * @param f - flags to perform AND operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator&=(const flags& f)noexcept{
		this->bitset &= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator AND.
	 * @param f - flags to perform AND operation with.
	 * @return Instance of Flags resulting from AND operation.
	 */
	flags operator&(const flags& f)const noexcept{
		return flags(*this).operator&=(f);
	}

	/**
	 * @brief Operator assignment OR.
	 * @param f - flags to perform OR operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator|=(const flags& f)noexcept{
		this->bitset |= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator OR.
	 * @param f - flags to perform OR operation with.
	 * @return Instance of Flags resulting from OR operation.
	 */
	flags operator|(const flags& f)const noexcept{
		return flags(*this).operator|=(f);
	}

	flags operator|(enum_type e)const noexcept{
		return flags(*this).set(e);
	}

	/**
	 * @brief Operator assignment XOR.
	 * @param f - flags to perform XOR operation with.
	 * @return Reference to this Flags.
	 */
	flags& operator^=(const flags& f)noexcept{
		this->bitset ^= f.bitset;
		return *this;
	}

	/**
	 * @brief Operator OR.
	 * @param f - flags to perform OR operation with.
	 * @return Instance of Flags resulting from OR operation.
	 */
	flags operator^(const flags& f)const noexcept{
		return flags(*this).operator^=(f);
	}

	friend std::ostream& operator<<(std::ostream& o, const flags& f){
		return o << f.bitset;
	}
};

/**
 * @brief Construct flags object.
 * @param initially_set_flags - list of flags which will be set initially.
 * @return newly created flags object.
 */
template <class T> flags<T> make_flags(std::initializer_list<T> initially_set_flags){
	return flags<T>(initially_set_flags);
}

}

template <class enum_type>
typename std::enable_if<
		std::is_enum<enum_type>::value && (int(enum_type::enum_size) >= 0),
		utki::flags<enum_type>
	>::type
operator|(enum_type e1, enum_type e2){
	return {e1, e2};
}
<|endoftext|>


<commit_before>#include <fstream>
#include <sstream>
#include <string>

#include "slash/include/env.h"
#include "slash/include/rsync.h"
#include "slash/include/xdebug.h"

namespace slash {
// Clean files for rsync info, such as the lock, log, pid, conf file
static bool CleanRsyncInfo(const std::string& path) {
  return slash::DeleteDirIfExist(path + kRsyncSubDir);
}

int StartRsync(const std::string& raw_path, const std::string& module, const std::string& ip, const int port) {
  // Sanity check
  if (raw_path.empty() || module.empty()) {
    return -1;
  }
  std::string path(raw_path);
  if (path.back() != '/') {
    path += "/";
  }
  std::string rsync_path = path + kRsyncSubDir + "/";
  CreatePath(rsync_path);

  // Generate conf file
  std::string conf_file(rsync_path + kRsyncConfFile);
  std::ofstream conf_stream(conf_file.c_str());
  if (!conf_stream) {
    log_warn("Open rsync conf file failed!");
    return -1;
  }
  conf_stream << "uid = root" << std::endl;
  conf_stream << "gid = root" << std::endl;
  conf_stream << "use chroot = no" << std::endl;
  conf_stream << "max connections = 10" << std::endl;
  conf_stream << "lock file = " << rsync_path + kRsyncLockFile << std::endl;
  conf_stream << "log file = " << rsync_path + kRsyncLogFile << std::endl;
  conf_stream << "pid file = " << rsync_path + kRsyncPidFile << std::endl;
  conf_stream << "list = no" << std::endl;
  conf_stream << "strict modes = no" << std::endl;
  conf_stream << "[" << module << "]" << std::endl;
  conf_stream << "path = " << path << std::endl;
  conf_stream << "read only = no" << std::endl;
  conf_stream.close();

  // Execute rsync command
  std::stringstream ss;
  ss << "rsync --daemon --config=" << conf_file;
  ss << " --address=" << ip;
  if (port != 873) {
    ss << " --port=" << port;
  }
  std::string rsync_start_cmd = ss.str();
  int ret = system(rsync_start_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Start rsync deamon failed : %d!", ret);
  return ret;
}

int StopRsync(const std::string& raw_path) {
  // Sanity check
  if (raw_path.empty()) {
    log_warn("empty rsync path!");
    return -1;
  }
  std::string path(raw_path);
  if (path.back() != '/') {
    path += "/";
  }

  std::string pid_file(path + kRsyncSubDir + "/" + kRsyncPidFile);
  if (!FileExists(pid_file)) {
    log_warn("no rsync pid file found");
    return 0; // Rsync deamon is not exist
  }

  // Kill Rsync
  std::string rsync_stop_cmd = "kill -9 `cat " + pid_file + "`";
  int ret = system(rsync_stop_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    log_info("Stop rsync success!");
  } else {
    log_warn("Stop rsync deamon failed : %d!", ret);
  }
  CleanRsyncInfo(path);
  return ret;
}

int RsyncSendFile(const std::string& local_file_path, const std::string& remote_file_path, const RsyncRemote& remote) {
  std::stringstream ss;
  ss << """rsync -avP --bwlimit=" << remote.kbps
    << " --port=" << remote.port
    << " " << local_file_path
    << " " << remote.host
    << "::" << remote.module << "/" << remote_file_path;

  std::string rsync_cmd = ss.str();
  int ret = system(rsync_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Rsync send file failed : %d!", ret);
  return ret;
}

int RsyncSendClearTarget(const std::string& local_dir_path, const std::string& remote_dir_path, const RsyncRemote& remote) {
  if (local_dir_path.empty() || remote_dir_path.empty()) {
    return -2;
  }
  std::string local_dir(local_dir_path), remote_dir(remote_dir_path);
  if (local_dir_path.back() != '/') {
    local_dir.append("/");
  }
  if (remote_dir_path.back() != '/') {
    remote_dir.append("/");
  }
  std::stringstream ss;
  ss << "rsync -avP --delete --port=" << remote.port
    << " " << local_dir
    << " " << remote.host
    << "::" << remote.module << "/" << remote_dir;
  std::string rsync_cmd = ss.str();
  int ret = system(rsync_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Rsync send file failed : %d!", ret);
  return ret;
}

}  // namespace slash
<commit_msg>bugfix rsync (#10)<commit_after>#include <fstream>
#include <sstream>
#include <string>

#include "slash/include/env.h"
#include "slash/include/rsync.h"
#include "slash/include/xdebug.h"

namespace slash {
// Clean files for rsync info, such as the lock, log, pid, conf file
static bool CleanRsyncInfo(const std::string& path) {
  return slash::DeleteDirIfExist(path + kRsyncSubDir);
}

int StartRsync(const std::string& raw_path, const std::string& module, const std::string& ip, const int port) {
  // Sanity check
  if (raw_path.empty() || module.empty()) {
    return -1;
  }
  std::string path(raw_path);
  if (path.back() != '/') {
    path += "/";
  }
  std::string rsync_path = path + kRsyncSubDir + "/";
  CreatePath(rsync_path);

  // Generate conf file
  std::string conf_file(rsync_path + kRsyncConfFile);
  std::ofstream conf_stream(conf_file.c_str());
  if (!conf_stream) {
    log_warn("Open rsync conf file failed!");
    return -1;
  }
  conf_stream << "uid = root" << std::endl;
  conf_stream << "gid = root" << std::endl;
  conf_stream << "use chroot = no" << std::endl;
  conf_stream << "max connections = 10" << std::endl;
  conf_stream << "lock file = " << rsync_path + kRsyncLockFile << std::endl;
  conf_stream << "log file = " << rsync_path + kRsyncLogFile << std::endl;
  conf_stream << "pid file = " << rsync_path + kRsyncPidFile << std::endl;
  conf_stream << "list = no" << std::endl;
  conf_stream << "strict modes = no" << std::endl;
  conf_stream << "[" << module << "]" << std::endl;
  conf_stream << "path = " << path << std::endl;
  conf_stream << "read only = no" << std::endl;
  conf_stream.close();

  // Execute rsync command
  std::stringstream ss;
  ss << "rsync --daemon --config=" << conf_file;
  ss << " --address=" << ip;
  if (port != 873) {
    ss << " --port=" << port;
  }
  std::string rsync_start_cmd = ss.str();
  int ret = system(rsync_start_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Start rsync deamon failed : %d!", ret);
  return ret;
}

int StopRsync(const std::string& raw_path) {
  // Sanity check
  if (raw_path.empty()) {
    log_warn("empty rsync path!");
    return -1;
  }
  std::string path(raw_path);
  if (path.back() != '/') {
    path += "/";
  }

  std::string pid_file(path + kRsyncSubDir + "/" + kRsyncPidFile);
  if (!FileExists(pid_file)) {
    log_warn("no rsync pid file found");
    return 0; // Rsync deamon is not exist
  }

  // Kill Rsync
  std::string rsync_stop_cmd = "kill -- -$(ps -o pgid= `cat " + pid_file + "`)";
  int ret = system(rsync_stop_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    log_info("Stop rsync success!");
  } else {
    log_warn("Stop rsync deamon failed : %d!", ret);
  }
  CleanRsyncInfo(path);
  return ret;
}

int RsyncSendFile(const std::string& local_file_path, const std::string& remote_file_path, const RsyncRemote& remote) {
  std::stringstream ss;
  ss << """rsync -avP --bwlimit=" << remote.kbps
    << " --port=" << remote.port
    << " " << local_file_path
    << " " << remote.host
    << "::" << remote.module << "/" << remote_file_path;

  std::string rsync_cmd = ss.str();
  int ret = system(rsync_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Rsync send file failed : %d!", ret);
  return ret;
}

int RsyncSendClearTarget(const std::string& local_dir_path, const std::string& remote_dir_path, const RsyncRemote& remote) {
  if (local_dir_path.empty() || remote_dir_path.empty()) {
    return -2;
  }
  std::string local_dir(local_dir_path), remote_dir(remote_dir_path);
  if (local_dir_path.back() != '/') {
    local_dir.append("/");
  }
  if (remote_dir_path.back() != '/') {
    remote_dir.append("/");
  }
  std::stringstream ss;
  ss << "rsync -avP --delete --port=" << remote.port
    << " " << local_dir
    << " " << remote.host
    << "::" << remote.module << "/" << remote_dir;
  std::string rsync_cmd = ss.str();
  int ret = system(rsync_cmd.c_str());
  if (ret == 0 || (WIFEXITED(ret) && !WEXITSTATUS(ret))) {
    return 0;
  }
  log_warn("Rsync send file failed : %d!", ret);
  return ret;
}

}  // namespace slash
<|endoftext|>


<commit_before>/**
 * \file
 * \brief SortedContainer class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-12-02
 */

#ifndef INCLUDE_DISTORTOS_INTERNAL_CONTAINERS_SORTEDCONTAINER_HPP_
#define INCLUDE_DISTORTOS_INTERNAL_CONTAINERS_SORTEDCONTAINER_HPP_

#include <algorithm>

namespace distortos
{

namespace internal
{

/**
 * \brief SortedContainerBase class is a wrapper around Container which can be used as base of SortedContainer
 *
 * \tparam Container is the underlying container, it must provide following functions: begin(), emplace(), empty(),
 * end(), pop_front() and splice(). It must contain following types: allocator_type, const_iterator, iterator and
 * value_type. Optionally functions erase() and size() of Container are forwarded if they exist.
 */

template<typename Container>
class SortedContainerBase
{
public:

	/// iterator
	using iterator = typename Container::iterator;

	/// const_iterator
	using const_iterator = typename Container::const_iterator;

	/// value_type
	using value_type = typename Container::value_type;

	/// allocator_type
	using allocator_type = typename Container::allocator_type;

	/**
	 * \brief Primary template used to test presence of C::splice()
	 *
	 * \tparam C is the type of container that will be tested
	 * \tparam Signature is the signature of C::splice() that will be tested
	 */

	template<typename C, typename Signature>
	struct TestHasSplice;

	/**
	 * \brief Template used to test presence of R C::splice(Args...)
	 *
	 * \tparam C is the type of container that will be tested
	 * \tparam R is the type returned by tested C::splice()
	 * \tparam Args are the types of arguments for tested C::splice()
	 */

	template<typename C, typename R, typename... Args>
	struct TestHasSplice<C, R(Args...)>
	{
		/**
		* \brief Overload selected when R C::splice(Args...) function is present.
		*
		* \return std::true_type
		*/

		template<typename CC = C>
		constexpr static auto test(CC* p) ->
				typename std::is_same<decltype(p->splice(std::declval<Args>()...)), R>::type;

		/**
		* \brief Overload selected when R C::splice(Args...) function is not present.
		*
		* \return std::false_type
		*/

		constexpr static auto test(...) -> std::false_type;
	};

	/**
	 * \brief Predicate telling whether void Container::splice(iterator, Container&, iterator) function is present (it
	 * inherits from std::true_type in that case) or not (inherits from std::false_type).
	 *
	 * \note Correct prototype should be void Container::splice(const_iterator, Container&, const_iterator),
	 * but libstdc++v3 used \a iterator instead of \a const_iterator until release of GCC 4.9. The prototype used below
	 * works in any case, as \a iterator is convertible to \a const_iterator, but not the other way around.
	 */

	using HasSplice = decltype(TestHasSplice<Container, void(iterator, Container&, iterator)>::
			test(std::declval<Container*>()));

	/**
	 * \brief SortedContainerBase's constructor
	 *
	 * \param [in] allocator is a reference to allocator_type object used to copy-construct allocator of container
	 */

	constexpr explicit SortedContainerBase(const allocator_type& allocator = allocator_type{}) :
			container_{allocator}
	{

	}

	/**
	 * \brief Forwarding of Container::begin()
	 */

	decltype(std::declval<Container>().begin()) begin()
	{
		return container_.begin();
	}

	/**
	 * \brief Forwarding of Container::begin() const
	 */

	decltype(std::declval<const Container>().begin()) begin() const
	{
		return container_.begin();
	}

	/**
	 * \brief Forwarding of Container::empty() const
	 */

	decltype(std::declval<Container>().empty()) empty() const
	{
		return container_.empty();
	}

	/**
	 * \brief Forwarding of Container::end()
	 */

	decltype(std::declval<Container>().end()) end()
	{
		return container_.end();
	}

	/**
	 * \brief Forwarding of Container::end() const
	 */

	decltype(std::declval<const Container>().end()) end() const
	{
		return container_.end();
	}

	/**
	 * \brief Forwarding of Container::erase(...)
	 *
	 * \note forwarded only if Container::erase(Args&&...) exists
	 */

	template<typename... Args, typename C = Container>
	auto erase(Args&&... args) -> decltype(std::declval<C>().erase(std::forward<Args>(args)...))
	{
		return container_.erase(std::forward<Args>(args)...);
	}

	/**
	 * \brief Forwarding of Container::pop_front()
	 */

	decltype(std::declval<Container>().pop_front()) pop_front()
	{
		return container_.pop_front();
	}

protected:

	/// container used for keeping elements
	Container container_;
};

/**
 * \brief SortedContainer class is a container that keeps the elements sorted during emplace of transfer.
 *
 * \note The elements are sorted as long as the user does not modify the contents via iterators.
 *
 * \tparam Container is the underlying container, it must provide following functions: begin(), emplace(), empty(),
 * end(), pop_front() and splice(). It must contain following types: allocator_type, const_iterator, iterator and
 * value_type. Optionally functions erase() and size() of Container are forwarded if they exist.
 * \tparam Compare is a type of functor used for comparison, std::less results in descending order, std::greater - in
 * ascending order.
 * \tparam HasSplice selects implementation - std::true_type to use Container::emplace() and Container::splice();
 * std::false_type to use Container::emplace_front(), Container::splice_after() and Container::before_begin()
 */

template<typename Container, typename Compare, typename HasSplice = typename SortedContainerBase<Container>::HasSplice>
class SortedContainer : public SortedContainerBase<Container>
{
public:

	/// base of SortedContainer
	using Base = SortedContainerBase<Container>;

	/// import iterator type alias from Base
	using typename Base::iterator;

	/// import const_iterator type alias from Base
	using typename Base::const_iterator;

	/// import value_type type alias from Base
	using typename Base::value_type;

	/// import allocator_type type alias from Base
	using typename Base::allocator_type;

	/// import Base's constructor
	using Base::Base;

	/**
	 * \brief SortedContainer's constructor
	 *
	 * \param [in] compare is a reference to Compare object used to copy-construct comparison functor
	 * \param [in] allocator is a reference to allocator_type object used to copy-construct allocator of container
	 */

	constexpr explicit SortedContainer(const Compare& compare = Compare{},
			const allocator_type& allocator = allocator_type{}) :
			Base{allocator},
			compare_{compare}
	{

	}

	/**
	 * \brief Sorted emplace()
	 *
	 * \tparam Args are types of argument for value_type constructor
	 *
	 * \param [in] args are arguments for value_type constructor
	 *
	 * \return iterator to emplaced element
	 */

	template<typename... Args>
	iterator sortedEmplace(Args&&... args)
	{
		const auto it = Base::container_.emplace(Base::begin(), std::forward<Args>(args)...);
		sortedSplice(*this, it);
		return it;
	}

	/**
	 * \brief Sorted splice()
	 *
	 * \param [in] other is the container from which the object is transfered
	 * \param [in] otherPosition is the position of the transfered object in the other container
	 */

	void sortedSplice(SortedContainer& other, const iterator otherPosition)
	{
		const auto insertPosition = findInsertPosition(*otherPosition);
		Base::container_.splice(insertPosition, other.container_, otherPosition);
	}

private:

	/**
	 * \brief Finds insert position that satisfies sorting criteria.
	 *
	 * Finds the insert position where Compare of current element and provided value returns true.
	 *
	 * \param [in] value is the value that is going to be emplaced/transfered
	 */

	iterator findInsertPosition(const value_type& value)
	{
		return std::find_if(Base::begin(), Base::end(),
				[this, &value](const value_type& element) -> bool
				{
					return compare_(element, value);
				}
		);
	}

	/// instance of functor used for comparison
	Compare compare_;
};

/**
 * \brief SortedContainer specialization for Containers that don't have Container::emplace() and Container::splice() -
 * like std::forward_list. In this case Container::emplace_front(), Container::splice_after() and
 * Container::before_begin() are used.
 */

template<typename Container, typename Compare>
class SortedContainer<Container, Compare, std::false_type> : public SortedContainerBase<Container>
{
public:

	/// base of SortedContainer
	using Base = SortedContainerBase<Container>;

	/// import iterator type alias from Base
	using typename Base::iterator;

	/// import const_iterator type alias from Base
	using typename Base::const_iterator;

	/// import value_type type alias from Base
	using typename Base::value_type;

	/// import allocator_type type alias from Base
	using typename Base::allocator_type;

	/// import Base's constructor
	using Base::Base;

	/**
	 * \brief SortedContainer's constructor
	 *
	 * \param [in] compare is a reference to Compare object used to copy-construct comparison functor
	 * \param [in] allocator is a reference to allocator_type object used to copy-construct allocator of container
	 */

	constexpr explicit SortedContainer(const Compare& compare = Compare{},
			const allocator_type& allocator = allocator_type{}) :
			Base{allocator},
			compare_{compare}
	{

	}

	/**
	 * \brief Sorted emplace()
	 *
	 * \tparam Args are types of argument for value_type constructor
	 *
	 * \param [in] args are arguments for value_type constructor
	 *
	 * \return iterator to emplaced element
	 */

	template<typename... Args>
	iterator sortedEmplace(Args&&... args)
	{
		Base::container_.emplace_front(std::forward<Args>(args)...);
		const auto it = Base::container_.begin();
		sortedSpliceAfter(*this, Base::container_.before_begin());
		return it;
	}

	/**
	 * \brief Sorted splice_after()
	 *
	 * \param [in] other is the container from which the object is transfered
	 * \param [in] otherPositionBefore is the position before the transfered object in the other container
	 */

	void sortedSpliceAfter(SortedContainer& other, const iterator otherPositionBefore)
	{
		const auto next = std::next(otherPositionBefore);
		const auto insertPositionBefore = findInsertPositionBefore(*next);
		Base::container_.splice_after(insertPositionBefore, other.container_, otherPositionBefore);
	}

private:

	/**
	 * \brief Finds insert position "before" the position that satisfies sorting criteria.
	 *
	 * Finds the insert position "before" the position where Compare of current element and provided value returns true.
	 *
	 * \param [in] value is the value that is going to be emplaced/transfered
	 */

	iterator findInsertPositionBefore(const value_type& value)
	{
		auto it = Base::container_.before_begin();
		auto next = Base::container_.begin();
		const auto last = Base::container_.end();

		while (next != last)
		{
			if (compare_(*next, value) == true)
				return it;

			it = next;
			++next;
		}
		return it;
	}

	/// instance of functor used for comparison
	Compare compare_;
};

}	// namespace internal

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_INTERNAL_CONTAINERS_SORTEDCONTAINER_HPP_
<commit_msg>remove SortedContainer class<commit_after><|endoftext|>


<commit_before>#include "bamliquidator.h"
#include "threadsafe_queue.h"

#include <cmath>
#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
#include <sstream>
#include <thread>

#include <boost/atomic.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include <hdf5.h>
#include <hdf5_hl.h>

/* todo:

   - don't store strings in table records, e.g. have seperate tables for chromosomes, file names,
     and cell types.  in the count table records, just store integers representing the strings.
     this should speed up the writing and cut the file sizes
   - don't use seperate structs for counting and writing.  prepare the structs while counting,
     then write them in bulk
   - multithread the counting, and see if that improves performance (probably using a boost
     thread_group and asio to implement a thread pool)
 */

struct ChromosomeCounts
{
  const std::string chromosome; // e.g. chr1
  const std::string bam_file_name; // e.g. L228_121_DHL6_RNA_POL2.hg18.bwt.sorted.bam
  const std::string cell_type; // e.g. dhl6
  const unsigned int bin_size; // e.g. 100000 base pairs per bin
  const std::vector<double> bin_counts;
};

class ChromosomeLengths
{
public:
  ChromosomeLengths(const std::string &chrom_size_file)
  {
    const size_t chromosome_column = 0;
    const size_t type_column = 2;
    const size_t length_column = 4;

    std::ifstream size_file(chrom_size_file);
    if (!size_file.is_open())
    {
      throw std::runtime_error("failed to open chrom_size_file " + chrom_size_file);
    }

    for(std::string line; std::getline(size_file, line); )
    {
      std::vector<std::string> columns;
      boost::split(columns, line, boost::is_any_of("\t"));
      if (columns.size() < length_column + 1)
      {
        throw std::runtime_error("error parsing chrom_size_file");
      }
      m_type_to_chromosome_to_count[columns[type_column]][columns[chromosome_column]] =
        boost::lexical_cast<size_t>(columns[length_column]);
    }
  }

  size_t operator()(const std::string &bam_file, const std::string& chromosome) const
  {
    for (const auto type : m_type_to_chromosome_to_count)
    {
      if (bam_file.find(type.first) != std::string::npos)
      {
        const auto count = type.second.find(chromosome);
        if (count == type.second.end())
        {
          throw std::runtime_error("failed to find chromosome " + chromosome
                                   + " for " + type.first);
        }
        return count->second;
      }
    }
    throw std::runtime_error("failed to determine type of " + bam_file);
  }

private:
  typedef std::map<std::string, std::map<std::string, size_t>> TypeToChromosomeToCount;
  TypeToChromosomeToCount m_type_to_chromosome_to_count;
};

struct CountH5Record
{
  uint32_t bin_number;
  char cell_type[16];
  char chromosome[16];
  uint64_t count;
  char file_name[64];
};

void write_to_hdf5(threadsafe_queue<ChromosomeCounts> &computed_counts)
{
  hid_t file = H5Fopen("bin_counts.h5", H5F_ACC_RDWR, H5P_DEFAULT);

  const size_t record_size = sizeof(CountH5Record);

  size_t record_offset[] = { HOFFSET(CountH5Record, bin_number),
                             HOFFSET(CountH5Record, cell_type),
                             HOFFSET(CountH5Record, chromosome),
                             HOFFSET(CountH5Record, count),
                             HOFFSET(CountH5Record, file_name) };

  size_t field_sizes[] = { sizeof(CountH5Record::bin_number),
                           sizeof(CountH5Record::cell_type),
                           sizeof(CountH5Record::chromosome),
                           sizeof(CountH5Record::count),
                           sizeof(CountH5Record::file_name) };

  std::cout << "writer...\n";
  while (true)
  {
    std::shared_ptr<ChromosomeCounts> counts = computed_counts.wait_and_pop();

    if (counts == nullptr) return;

    CountH5Record record;
    record.bin_number = 0;
    strncpy(record.cell_type,  counts->cell_type.c_str(),     sizeof(CountH5Record::cell_type));
    strncpy(record.chromosome, counts->chromosome.c_str(),    sizeof(CountH5Record::chromosome));
    strncpy(record.file_name,  counts->bam_file_name.c_str(), sizeof(CountH5Record::file_name));

    std::cout << "writing " << counts->bin_counts.size() << " from "
              << counts->chromosome << std::endl;
    for (auto count : counts->bin_counts)
    {
      record.count = count;
      herr_t status = H5TBappend_records(file, "counts", 1, record_size, record_offset,
                                         field_sizes, &record);
      if (status != 0)
      {
        std::cerr << "Error appending record, status = " << status << std::endl;
      }

      ++record.bin_number;
    }
  }

  H5Fclose(file);
}

void count(threadsafe_queue<ChromosomeCounts> &computed_counts)
{
  const std::string bam_file_path("../copied_from_tod/");
  const std::string bam_file_name("04032013_D1L57ACXX_4.TTAGGC.hg18.bwt.sorted.bam");
  const std::string bam_file = bam_file_path+bam_file_name;
  const std::vector<std::string> chromosomes {"chr1", "chr2", "chr3", "chr4", "chr5",
    "chr6", "chr8", "chr9", "chr10", "chr11", "chr12", "chr13", "chr14", "chr15", "chr16",
    "chr17", "chr18", "chr19", "chr20", "chr21", "chr22", "chrX"};

  const int bin_size = 100000; // 100K

  const ChromosomeLengths lengths("../copied_from_tod/ucsc_chromSize.txt");

  for (auto chr : chromosomes)
  {
    int base_pairs = lengths(bam_file, chr);
    int bins = std::ceil(base_pairs / (double) bin_size);
    int max_base_pair = bins * bin_size;
    std::cout << "counting chromosome " << chr << std::endl;
    // pickup here: first just try a single thread counting from file,
    // and a single thread recording counts in hdf5
    // I'm not sure if samtools is thread safe -- try after I confirm 1 thread working
    // I need to write a script to compare hdf5 and mysql results or something
    // maybe I should just write both to txt and diff them
    computed_counts.push(ChromosomeCounts {chr, bam_file_name, "dhl6", bin_size,
      liquidate(bam_file, chr, 0, max_base_pair, '.', bins, 0)});
  }

  computed_counts.push(nullptr); // insert "poison pill" to signal to writer to stop
}

int main()
{
  threadsafe_queue<ChromosomeCounts> computed_counts;
  std::thread counter_thread(count, std::ref(computed_counts));
  std::thread writer_thread(write_to_hdf5, std::ref(computed_counts));

  counter_thread.join();
  writer_thread.join();

  return 0;
}

/* The MIT License (MIT)

   Copyright (c) 2013 John DiMatteo

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

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

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
 */
<commit_msg>parsing bam file name<commit_after>#include "bamliquidator.h"
#include "threadsafe_queue.h"

#include <cmath>
#include <fstream>
#include <iostream>
#include <map>
#include <stdexcept>
#include <sstream>
#include <thread>

#include <boost/atomic.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include <hdf5.h>
#include <hdf5_hl.h>

/* todo:

   - don't store strings in table records, e.g. have seperate tables for chromosomes, file names,
     and cell types.  in the count table records, just store integers representing the strings.
     this should speed up the writing and cut the file sizes
   - don't use seperate structs for counting and writing.  prepare the structs while counting,
     then write them in bulk
   - multithread the counting, and see if that improves performance (probably using a boost
     thread_group and asio to implement a thread pool)
 */

struct ChromosomeCounts
{
  const std::string chromosome; // e.g. chr1
  const std::string bam_file_name; // e.g. L228_121_DHL6_RNA_POL2.hg18.bwt.sorted.bam
  const std::string cell_type; // e.g. dhl6
  const unsigned int bin_size; // e.g. 100000 base pairs per bin
  const std::vector<double> bin_counts;
};

class ChromosomeLengths
{
public:
  ChromosomeLengths(const std::string &chrom_size_file)
  {
    const size_t chromosome_column = 0;
    const size_t type_column = 2;
    const size_t length_column = 4;

    std::ifstream size_file(chrom_size_file);
    if (!size_file.is_open())
    {
      throw std::runtime_error("failed to open chrom_size_file " + chrom_size_file);
    }

    for(std::string line; std::getline(size_file, line); )
    {
      std::vector<std::string> columns;
      boost::split(columns, line, boost::is_any_of("\t"));
      if (columns.size() < length_column + 1)
      {
        throw std::runtime_error("error parsing chrom_size_file");
      }
      m_type_to_chromosome_to_count[columns[type_column]][columns[chromosome_column]] =
        boost::lexical_cast<size_t>(columns[length_column]);
    }
  }

  size_t operator()(const std::string &bam_file, const std::string& chromosome) const
  {
    for (const auto type : m_type_to_chromosome_to_count)
    {
      if (bam_file.find(type.first) != std::string::npos)
      {
        const auto count = type.second.find(chromosome);
        if (count == type.second.end())
        {
          throw std::runtime_error("failed to find chromosome " + chromosome
                                   + " for " + type.first);
        }
        return count->second;
      }
    }
    throw std::runtime_error("failed to determine type of " + bam_file);
  }

private:
  typedef std::map<std::string, std::map<std::string, size_t>> TypeToChromosomeToCount;
  TypeToChromosomeToCount m_type_to_chromosome_to_count;
};

struct CountH5Record
{
  uint32_t bin_number;
  char cell_type[16];
  char chromosome[16];
  uint64_t count;
  char file_name[64];
};

void write_to_hdf5(threadsafe_queue<ChromosomeCounts> &computed_counts)
{
  hid_t file = H5Fopen("bin_counts.h5", H5F_ACC_RDWR, H5P_DEFAULT);

  const size_t record_size = sizeof(CountH5Record);

  size_t record_offset[] = { HOFFSET(CountH5Record, bin_number),
                             HOFFSET(CountH5Record, cell_type),
                             HOFFSET(CountH5Record, chromosome),
                             HOFFSET(CountH5Record, count),
                             HOFFSET(CountH5Record, file_name) };

  size_t field_sizes[] = { sizeof(CountH5Record::bin_number),
                           sizeof(CountH5Record::cell_type),
                           sizeof(CountH5Record::chromosome),
                           sizeof(CountH5Record::count),
                           sizeof(CountH5Record::file_name) };

  std::cout << "writer...\n";
  while (true)
  {
    std::shared_ptr<ChromosomeCounts> counts = computed_counts.wait_and_pop();

    if (counts == nullptr) return;

    CountH5Record record;
    record.bin_number = 0;
    strncpy(record.cell_type,  counts->cell_type.c_str(),     sizeof(CountH5Record::cell_type));
    strncpy(record.chromosome, counts->chromosome.c_str(),    sizeof(CountH5Record::chromosome));
    strncpy(record.file_name,  counts->bam_file_name.c_str(), sizeof(CountH5Record::file_name));

    std::cout << "writing " << counts->bin_counts.size() << " from "
              << counts->chromosome << std::endl;
    for (auto count : counts->bin_counts)
    {
      record.count = count;
      herr_t status = H5TBappend_records(file, "counts", 1, record_size, record_offset,
                                         field_sizes, &record);
      if (status != 0)
      {
        std::cerr << "Error appending record, status = " << status << std::endl;
      }

      ++record.bin_number;
    }
  }

  H5Fclose(file);
}

void count(threadsafe_queue<ChromosomeCounts> &computed_counts,
           const std::string& cell_type,
           const std::string& chrom_size_file,
           const std::string& bam_file)
{
  const size_t last_slash_position = bam_file.find_last_of("/");
  const std::string bam_file_name = last_slash_position == std::string::npos
                                  ? bam_file
                                  : bam_file.substr(last_slash_position);

  const std::vector<std::string> chromosomes {"chr1", "chr2", "chr3", "chr4", "chr5",
    "chr6", "chr8", "chr9", "chr10", "chr11", "chr12", "chr13", "chr14", "chr15", "chr16",
    "chr17", "chr18", "chr19", "chr20", "chr21", "chr22", "chrX"};

  const int bin_size = 100000; // 100K

  const ChromosomeLengths lengths(chrom_size_file);

  for (auto chr : chromosomes)
  {
    int base_pairs = lengths(bam_file, chr);
    int bins = std::ceil(base_pairs / (double) bin_size);
    int max_base_pair = bins * bin_size;
    std::cout << "counting chromosome " << chr << std::endl;
    computed_counts.push(ChromosomeCounts {chr, bam_file_name, cell_type, bin_size,
      liquidate(bam_file, chr, 0, max_base_pair, '.', bins, 0)});
  }

  computed_counts.push(nullptr); // insert "poison pill" to signal to writer to stop
}

int main(int argc, char* argv[])
{
  if (argc != 4)
  {
    std::cout << "usage: " << argv[0] << " cell_type ucsc_chrom_size_path bam_file_path\n"
      << "\ne.g. " << argv[0] << " mm1s /grail/annotations/ucsc_chromSize.txt"
      << "\n     /ifs/labs/bradner/bam/hg18/mm1s/04032013_D1L57ACXX_4.TTAGGC.hg18.bwt.sorted.bam"
      << std::endl;
    return -1;
  }

  threadsafe_queue<ChromosomeCounts> computed_counts;
  std::thread writer_thread(write_to_hdf5, std::ref(computed_counts));

  count(computed_counts, argv[1], argv[2], argv[3]);

  writer_thread.join();

  return 0;
}

/* The MIT License (MIT)

   Copyright (c) 2013 John DiMatteo

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

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

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


<commit_before>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Its purpose is to analyse the persistent homology of connectivity
  matrices. The tool bears some semblance to the *network analysis*
  tools, but focuses specifically on data sets whose weights are an
  interpretable correlation measure.
*/

#include <aleph/persistenceDiagrams/Entropy.hh>
#include <aleph/persistenceDiagrams/Norms.hh>

#include <aleph/persistenceDiagrams/io/JSON.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/io/AdjacencyMatrix.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/utilities/Filesystem.hh>

#include <cmath>

#include <algorithm>
#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <vector>

#include <getopt.h>

void usage()
{
  std::cerr << "Usage: connectivity_matrix_analysis [--dimension DIMENSION] [--infinity INF] FILENAMES\n"
            << "\n"
            << "Analyses a set of connectivity matrices. The matrices are optionally\n"
            << "expanded to a pre-defined dimension. By default, only information of\n"
            << "the zeroth persistent homology group will be shown.\n"
            << "\n"
            << "The value INF will be used to replace infinite values in the diagram\n"
            << "in order to facilitate the subsequent analysis.\n"
            << "\n"
            << "Flags:\n"
            << "  -k: keep & report unpaired simplices (infinite values)\n"
            << "  -v: verbose output\n"
            << "\n";
}

int main( int argc, char** argv )
{
  static option commandLineOptions[] =
  {
    { "dimension"     , required_argument, nullptr, 'd' },
    { "infinity"      , required_argument, nullptr, 'i' },
    { "keep-unpaired" , no_argument      , nullptr, 'k' },
    { "verbose"       , no_argument      , nullptr, 'v' },
    { nullptr         , 0                , nullptr,  0  }
  };

  unsigned dimension = 0;
  double infinity    = std::numeric_limits<double>::infinity();
  bool keepUnpaired  = false;
  bool verbose       = false;

  {
    int option = 0;

    while( ( option = getopt_long( argc, argv, "d:i:kv", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'd':
        dimension = static_cast<unsigned>( std::stoul(optarg) );
        break;
      case 'i':
        infinity = static_cast<double>( std::stod(optarg) );
        break;
      case 'k':
        keepUnpaired = true;
        break;
      }
    }
  }

  if( (argc - optind) < 1 )
  {
    usage();
    return -1;
  }

  using DataType           = double;
  using VertexType         = unsigned short;
  using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
  using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;
  using Point              = typename PersistenceDiagram::Point;

  std::vector<std::string> filenames;

  for( int i = optind; i < argc; i++ )
    filenames.push_back( argv[i] );

  aleph::topology::io::AdjacencyMatrixReader reader;
  reader.setIgnoreNaNs();
  reader.setIgnoreZeroWeights();

  // Whew, is there *really* no better way of specifying this strategy
  // here as a qualified name?
  reader.setVertexWeightAssignmentStrategy(
      aleph::topology::io::AdjacencyMatrixReader::VertexWeightAssignmentStrategy::AssignZero
  );

  std::cout << "{\n"
            << "\"diagrams\": [\n";

  for( auto&& filename : filenames )
  {
    if( verbose )
      std::cerr << "* Processing " << filename << "...";

    SimplicialComplex K;
    reader( filename, K );

    K.sort();

    bool dualize                    = true;
    bool includeAllUnpairedCreators = keepUnpaired;

    auto diagrams
      = aleph::calculatePersistenceDiagrams( K,
                                             dualize,
                                             includeAllUnpairedCreators );

    if( verbose )
      std::cerr << "finished\n";

    auto basename
      = aleph::utilities::basename( filename );

    for( auto&& diagram : diagrams )
    {
      if( std::isfinite( infinity ) )
      {
        std::transform( diagram.begin(), diagram.end(), diagram.begin(),
            [&infinity] ( const Point& p )
            {
              if( p.isUnpaired() )
                return Point( p.x(), infinity );
              else
                return Point( p.x(), p.y() );
            }
        );
      }

      // Stores additional data about each persistence diagram in order
      // to make it easier to keep track of information.
      std::map<std::string, std::string> kvs;

      kvs["total_persistence_1"] = std::to_string( aleph::totalPersistence( diagram, 1.0 ) );
      kvs["total_persistence_2"] = std::to_string( aleph::totalPersistence( diagram, 2.0 ) );

      kvs["persistent_entropy"]  = std::to_string( aleph::persistentEntropy( diagram ) );

      aleph::io::writeJSON( std::cout, diagram, basename, kvs );
    }
  }

  std::cout << "\n"
            << "]\n"
            << "}\n";
}
<commit_msg>Supplying the proper weight adjustment functor<commit_after>/*
  This is a tool shipped by 'Aleph - A Library for Exploring Persistent
  Homology'.

  Its purpose is to analyse the persistent homology of connectivity
  matrices. The tool bears some semblance to the *network analysis*
  tools, but focuses specifically on data sets whose weights are an
  interpretable correlation measure.
*/

#include <aleph/persistenceDiagrams/Entropy.hh>
#include <aleph/persistenceDiagrams/Norms.hh>

#include <aleph/persistenceDiagrams/io/JSON.hh>

#include <aleph/persistentHomology/Calculation.hh>

#include <aleph/topology/io/AdjacencyMatrix.hh>

#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>

#include <aleph/utilities/Filesystem.hh>

#include <cmath>

#include <algorithm>
#include <iostream>
#include <limits>
#include <map>
#include <string>
#include <vector>

#include <getopt.h>

void usage()
{
  std::cerr << "Usage: connectivity_matrix_analysis [--dimension DIMENSION] [--infinity INF] FILENAMES\n"
            << "\n"
            << "Analyses a set of connectivity matrices. The matrices are optionally\n"
            << "expanded to a pre-defined dimension. By default, only information of\n"
            << "the zeroth persistent homology group will be shown.\n"
            << "\n"
            << "The value INF will be used to replace infinite values in the diagram\n"
            << "in order to facilitate the subsequent analysis.\n"
            << "\n"
            << "Flags:\n"
            << "  -k: keep & report unpaired simplices (infinite values)\n"
            << "  -v: verbose output\n"
            << "\n";
}

int main( int argc, char** argv )
{
  static option commandLineOptions[] =
  {
    { "dimension"     , required_argument, nullptr, 'd' },
    { "infinity"      , required_argument, nullptr, 'i' },
    { "keep-unpaired" , no_argument      , nullptr, 'k' },
    { "verbose"       , no_argument      , nullptr, 'v' },
    { nullptr         , 0                , nullptr,  0  }
  };

  unsigned dimension = 0;
  double infinity    = std::numeric_limits<double>::infinity();
  bool keepUnpaired  = false;
  bool verbose       = false;

  {
    int option = 0;

    while( ( option = getopt_long( argc, argv, "d:i:kv", commandLineOptions, nullptr ) ) != -1 )
    {
      switch( option )
      {
      case 'd':
        dimension = static_cast<unsigned>( std::stoul(optarg) );
        break;
      case 'i':
        infinity = static_cast<double>( std::stod(optarg) );
        break;
      case 'k':
        keepUnpaired = true;
        break;
      }
    }
  }

  if( (argc - optind) < 1 )
  {
    usage();
    return -1;
  }

  using DataType           = double;
  using VertexType         = unsigned short;
  using Simplex            = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex  = aleph::topology::SimplicialComplex<Simplex>;
  using PersistenceDiagram = aleph::PersistenceDiagram<DataType>;
  using Point              = typename PersistenceDiagram::Point;

  std::vector<std::string> filenames;

  for( int i = optind; i < argc; i++ )
    filenames.push_back( argv[i] );

  aleph::topology::io::AdjacencyMatrixReader reader;
  reader.setIgnoreNaNs();
  reader.setIgnoreZeroWeights();

  // Whew, is there *really* no better way of specifying this strategy
  // here as a qualified name?
  reader.setVertexWeightAssignmentStrategy(
      aleph::topology::io::AdjacencyMatrixReader::VertexWeightAssignmentStrategy::AssignZero
  );

  std::cout << "{\n"
            << "\"diagrams\": [\n";

  for( auto&& filename : filenames )
  {
    if( verbose )
      std::cerr << "* Processing " << filename << "...";

    SimplicialComplex K;
    reader( filename, K,
      [] ( DataType maxWeight, DataType /* minWeight */, DataType weight )
      {
        // Transform the weight into a *distance* by negating it; this
        // ignores all other scaling mechanisms applied to the data.
        return maxWeight - weight;
      }
    );

    K.sort();

    bool dualize                    = true;
    bool includeAllUnpairedCreators = keepUnpaired;

    auto diagrams
      = aleph::calculatePersistenceDiagrams( K,
                                             dualize,
                                             includeAllUnpairedCreators );

    if( verbose )
      std::cerr << "finished\n";

    auto basename
      = aleph::utilities::basename( filename );

    for( auto&& diagram : diagrams )
    {
      if( std::isfinite( infinity ) )
      {
        std::transform( diagram.begin(), diagram.end(), diagram.begin(),
            [&infinity] ( const Point& p )
            {
              if( p.isUnpaired() )
                return Point( p.x(), infinity );
              else
                return Point( p.x(), p.y() );
            }
        );
      }

      // Stores additional data about each persistence diagram in order
      // to make it easier to keep track of information.
      std::map<std::string, std::string> kvs;

      kvs["total_persistence_1"] = std::to_string( aleph::totalPersistence( diagram, 1.0 ) );
      kvs["total_persistence_2"] = std::to_string( aleph::totalPersistence( diagram, 2.0 ) );

      kvs["persistent_entropy"]  = std::to_string( aleph::persistentEntropy( diagram ) );

      aleph::io::writeJSON( std::cout, diagram, basename, kvs );
    }
  }

  std::cout << "\n"
            << "]\n"
            << "}\n";
}
<|endoftext|>


<commit_before>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * hir_expand/reborrow.cpp
 * - Insert reborrows when a &mut would be moved
 */
#include <hir/visitor.hpp>
#include <hir/expr.hpp>
#include <hir_typeck/static.hpp>
#include <algorithm>
#include "main_bindings.hpp"

namespace {
    inline HIR::ExprNodeP mk_exprnodep(HIR::ExprNode* en, ::HIR::TypeRef ty){ en->m_res_type = mv$(ty); return HIR::ExprNodeP(en); }
}
#define NEWNODE(TY, CLASS, ...)  mk_exprnodep(new HIR::ExprNode_##CLASS(__VA_ARGS__), TY)

namespace {

    class ExprVisitor_Mutate:
        public ::HIR::ExprVisitorDef
    {
        const ::HIR::Crate& m_crate;

    public:
        ExprVisitor_Mutate(const ::HIR::Crate& crate):
            m_crate(crate)
        {
        }
        void visit_node_ptr(::HIR::ExprPtr& root) {
            const auto& node_ref = *root;
            const char* node_ty = typeid(node_ref).name();
            TRACE_FUNCTION_FR(&*root << " " << node_ty << " : " << root->m_res_type, node_ty);

            root->visit(*this);

            // 1. Convert into an ExprNodeP
            auto np = root.into_unique();
            // 2. Pass to do_reborrow
            np = do_reborrow(mv$(np));
            // 3. Convert back
            root.reset( np.release() );
        }

        void visit_node_ptr(::HIR::ExprNodeP& node) override {
            const auto& node_ref = *node;
            const char* node_ty = typeid(node_ref).name();
            TRACE_FUNCTION_FR(&*node << " " << node_ty << " : " << node->m_res_type, node_ty);
            assert( node );
            node->visit(*this);
        }

        ::HIR::ExprNodeP do_reborrow(::HIR::ExprNodeP node_ptr)
        {
            TU_IFLET( ::HIR::TypeRef::Data, node_ptr->m_res_type.m_data, Borrow, e,
                if( e.type == ::HIR::BorrowType::Unique )
                {
                    if( dynamic_cast< ::HIR::ExprNode_Index*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Variable*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Field*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Deref*>(node_ptr.get())
                        )
                    {
                        DEBUG("Insert reborrow - " << node_ptr->span() << " - type=" << node_ptr->m_res_type);
                        auto sp = node_ptr->span();
                        auto ty_mut = node_ptr->m_res_type.clone();
                        auto ty = e.inner->clone();
                        node_ptr = NEWNODE(mv$(ty_mut), Borrow, sp, ::HIR::BorrowType::Unique,
                            NEWNODE(mv$(ty), Deref, sp,  mv$(node_ptr))
                            );
                    }
                    // Recurse into blocks - Neater this way
                    else if( auto p = dynamic_cast< ::HIR::ExprNode_Block*>(node_ptr.get()) )
                    {
                        auto& last_node = p->m_nodes.back();
                        last_node = do_reborrow(mv$(last_node));
                    }
                    else
                    {
                        // Not a node that should have reborrow applied (likely generated an owned &mut)
                    }
                }
            )
            return node_ptr;
        }

        void visit(::HIR::ExprNode_Assign& node) override {
            node.m_value = do_reborrow(mv$(node.m_value));
        }
        void visit(::HIR::ExprNode_CallPath& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_CallValue& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_CallMethod& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }

        void visit(::HIR::ExprNode_ArrayList& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_vals) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_Tuple& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_vals) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_TupleVariant& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_StructLiteral& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_values) {
                arg.second = do_reborrow(mv$(arg.second));
            }
        }
    };
    class OuterVisitor:
        public ::HIR::Visitor
    {
        const ::HIR::Crate& m_crate;
    public:
        OuterVisitor(const ::HIR::Crate& crate):
            m_crate(crate)
        {
        }

        // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure
        void visit_expr(::HIR::ExprPtr& exp) override {
            BUG(Span(), "visit_expr hit in OuterVisitor");
        }

        void visit_type(::HIR::TypeRef& ty) override
        {
            TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
                this->visit_type( *e.inner );
                DEBUG("Array size " << ty);
                if( e.size ) {
                    ExprVisitor_Mutate  ev(m_crate);
                    ev.visit_node_ptr( *e.size );
                }
            )
            else {
                ::HIR::Visitor::visit_type(ty);
            }
        }
        // ------
        // Code-containing items
        // ------
        void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override {
            //auto _ = this->m_ms.set_item_generics(item.m_params);
            if( item.m_code )
            {
                DEBUG("Function code " << p);
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr( item.m_code );
            }
            else
            {
                DEBUG("Function code " << p << " (none)");
            }
        }
        void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override {
            if( item.m_value )
            {
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr(item.m_value);
            }
        }
        void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override {
            if( item.m_value )
            {
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr(item.m_value);
            }
        }
        void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
            for(auto& var : item.m_variants)
            {
                TU_IFLET(::HIR::Enum::Variant, var.second, Value, e,
                    DEBUG("Enum value " << p << " - " << var.first);

                    ExprVisitor_Mutate  ev(m_crate);
                    ev.visit_node_ptr(e.expr);
                )
            }
        }
    };
}   // namespace

void HIR_Expand_Reborrows(::HIR::Crate& crate)
{
    OuterVisitor    ov(crate);
    ov.visit_crate( crate );
}
<commit_msg>HIR Reborrow - Handle reborrow inside _Unize<commit_after>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * hir_expand/reborrow.cpp
 * - Insert reborrows when a &mut would be moved
 */
#include <hir/visitor.hpp>
#include <hir/expr.hpp>
#include <hir_typeck/static.hpp>
#include <algorithm>
#include "main_bindings.hpp"

namespace {
    inline HIR::ExprNodeP mk_exprnodep(HIR::ExprNode* en, ::HIR::TypeRef ty){ en->m_res_type = mv$(ty); return HIR::ExprNodeP(en); }
}
#define NEWNODE(TY, CLASS, ...)  mk_exprnodep(new HIR::ExprNode_##CLASS(__VA_ARGS__), TY)

namespace {

    class ExprVisitor_Mutate:
        public ::HIR::ExprVisitorDef
    {
        const ::HIR::Crate& m_crate;

    public:
        ExprVisitor_Mutate(const ::HIR::Crate& crate):
            m_crate(crate)
        {
        }
        void visit_node_ptr(::HIR::ExprPtr& root) {
            const auto& node_ref = *root;
            const char* node_ty = typeid(node_ref).name();
            TRACE_FUNCTION_FR(&*root << " " << node_ty << " : " << root->m_res_type, node_ty);

            root->visit(*this);

            // 1. Convert into an ExprNodeP
            auto np = root.into_unique();
            // 2. Pass to do_reborrow
            np = do_reborrow(mv$(np));
            // 3. Convert back
            root.reset( np.release() );
        }

        void visit_node_ptr(::HIR::ExprNodeP& node) override {
            const auto& node_ref = *node;
            const char* node_ty = typeid(node_ref).name();
            TRACE_FUNCTION_FR(&*node << " " << node_ty << " : " << node->m_res_type, node_ty);
            assert( node );
            node->visit(*this);
        }

        ::HIR::ExprNodeP do_reborrow(::HIR::ExprNodeP node_ptr)
        {
            TU_IFLET( ::HIR::TypeRef::Data, node_ptr->m_res_type.m_data, Borrow, e,
                if( e.type == ::HIR::BorrowType::Unique )
                {
                    if( dynamic_cast< ::HIR::ExprNode_Index*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Variable*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Field*>(node_ptr.get())
                     || dynamic_cast< ::HIR::ExprNode_Deref*>(node_ptr.get())
                        )
                    {
                        DEBUG("Insert reborrow - " << node_ptr->span() << " - type=" << node_ptr->m_res_type);
                        auto sp = node_ptr->span();
                        auto ty_mut = node_ptr->m_res_type.clone();
                        auto ty = e.inner->clone();
                        node_ptr = NEWNODE(mv$(ty_mut), Borrow, sp, ::HIR::BorrowType::Unique,
                            NEWNODE(mv$(ty), Deref, sp,  mv$(node_ptr))
                            );
                    }
                    // Recurse into blocks - Neater this way
                    else if( auto p = dynamic_cast< ::HIR::ExprNode_Block*>(node_ptr.get()) )
                    {
                        auto& last_node = p->m_nodes.back();
                        last_node = do_reborrow(mv$(last_node));
                    }
                    else
                    {
                        // Not a node that should have reborrow applied (likely generated an owned &mut)
                    }
                }
            )
            return node_ptr;
        }

        void visit(::HIR::ExprNode_Assign& node) override {
            node.m_value = do_reborrow(mv$(node.m_value));
        }
        void visit(::HIR::ExprNode_CallPath& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_CallValue& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_CallMethod& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }

        void visit(::HIR::ExprNode_ArrayList& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_vals) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_Tuple& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_vals) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_TupleVariant& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_args) {
                arg = do_reborrow(mv$(arg));
            }
        }
        void visit(::HIR::ExprNode_StructLiteral& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            for(auto& arg : node.m_values) {
                arg.second = do_reborrow(mv$(arg.second));
            }
        }
        void visit(::HIR::ExprNode_Unsize& node) override {
            ::HIR::ExprVisitorDef::visit(node);
            node.m_value = do_reborrow(mv$(node.m_value));
        }
    };
    class OuterVisitor:
        public ::HIR::Visitor
    {
        const ::HIR::Crate& m_crate;
    public:
        OuterVisitor(const ::HIR::Crate& crate):
            m_crate(crate)
        {
        }

        // NOTE: This is left here to ensure that any expressions that aren't handled by higher code cause a failure
        void visit_expr(::HIR::ExprPtr& exp) override {
            BUG(Span(), "visit_expr hit in OuterVisitor");
        }

        void visit_type(::HIR::TypeRef& ty) override
        {
            TU_IFLET(::HIR::TypeRef::Data, ty.m_data, Array, e,
                this->visit_type( *e.inner );
                DEBUG("Array size " << ty);
                if( e.size ) {
                    ExprVisitor_Mutate  ev(m_crate);
                    ev.visit_node_ptr( *e.size );
                }
            )
            else {
                ::HIR::Visitor::visit_type(ty);
            }
        }
        // ------
        // Code-containing items
        // ------
        void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override {
            //auto _ = this->m_ms.set_item_generics(item.m_params);
            if( item.m_code )
            {
                DEBUG("Function code " << p);
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr( item.m_code );
            }
            else
            {
                DEBUG("Function code " << p << " (none)");
            }
        }
        void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override {
            if( item.m_value )
            {
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr(item.m_value);
            }
        }
        void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override {
            if( item.m_value )
            {
                ExprVisitor_Mutate  ev(m_crate);
                ev.visit_node_ptr(item.m_value);
            }
        }
        void visit_enum(::HIR::ItemPath p, ::HIR::Enum& item) override {
            for(auto& var : item.m_variants)
            {
                TU_IFLET(::HIR::Enum::Variant, var.second, Value, e,
                    DEBUG("Enum value " << p << " - " << var.first);

                    ExprVisitor_Mutate  ev(m_crate);
                    ev.visit_node_ptr(e.expr);
                )
            }
        }
    };
}   // namespace

void HIR_Expand_Reborrows(::HIR::Crate& crate)
{
    OuterVisitor    ov(crate);
    ov.visit_crate( crate );
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

/**
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include <cstring>
#include <cstdlib>
#include "CoreVolume.h"

CoreVolume::CoreVolume() {}
CoreVolume::~CoreVolume() {}

bool CoreVolume::GetBrick(unsigned char**,
                          const std::vector<UINT64>&,
                          const std::vector<UINT64>&) const {
  return false;
}

void CoreVolume::SetHistogram(const std::vector<UINT32>& hist)
{
  if(m_pHist1D) { delete m_pHist1D; }
  m_pHist1D = new Histogram1D(hist.size());
  std::memcpy(m_pHist1D->GetDataPointer(), &(hist.at(0)),
              sizeof(UINT32)*hist.size());
}

void CoreVolume::SetHistogram(const std::vector<std::vector<UINT32> >& hist)
{
  if(m_pHist2D) { delete m_pHist2D; }
  // assume the 2D histogram is square: hist[0].size() == hist[1].size() == ...
  const VECTOR2<size_t> sz(hist.size(), hist[0].size());
  m_pHist2D = new Histogram2D(sz);

  UINT32 *data = m_pHist2D->GetDataPointer();
  for(std::vector<std::vector<UINT32> >::const_iterator iter = hist.begin();
      iter != hist.end(); ++iter) {
    std::memcpy(data, &(iter->at(0)), sizeof(UINT32)*iter->size());
    data += iter->size();
  }
}
<commit_msg>Create default (empty) histograms in the constructor.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

/**
  \author  Tom Fogal
           SCI Institute
           University of Utah
*/
#include <cstring>
#include <cstdlib>
#include "CoreVolume.h"

typedef std::vector<std::vector<UINT32> > hist2d;

CoreVolume::CoreVolume()
{
  // setup some default histograms.
  // default value is 1, since the `FilledSize' ignores 0-valued elements, so
  // other code would think a histogram filled with 0's is empty.
  std::vector<UINT32> h1d(8,1);
  hist2d h2d;
  h2d.resize(8);
  for(hist2d::iterator iter = h2d.begin(); iter < h2d.end(); ++iter) {
    iter->resize(8,1);
  }
  SetHistogram(h1d);
  SetHistogram(h2d);
}
CoreVolume::~CoreVolume() {}

bool CoreVolume::GetBrick(unsigned char**,
                          const std::vector<UINT64>&,
                          const std::vector<UINT64>&) const {
  return false;
}

void CoreVolume::SetHistogram(const std::vector<UINT32>& hist)
{
  if(m_pHist1D) { delete m_pHist1D; }
  m_pHist1D = new Histogram1D(hist.size());
  std::memcpy(m_pHist1D->GetDataPointer(), &(hist.at(0)),
              sizeof(UINT32)*hist.size());
}

void CoreVolume::SetHistogram(const std::vector<std::vector<UINT32> >& hist)
{
  if(m_pHist2D) { delete m_pHist2D; }
  // assume the 2D histogram is square: hist[0].size() == hist[1].size() == ...
  const VECTOR2<size_t> sz(hist.size(), hist[0].size());
  m_pHist2D = new Histogram2D(sz);

  UINT32 *data = m_pHist2D->GetDataPointer();
  for(hist2d::const_iterator iter = hist.begin(); iter < hist.end(); ++iter) {
    std::memcpy(data, &(iter->at(0)), sizeof(UINT32)*iter->size());
    data += iter->size();
  }
}
<|endoftext|>