<commit_before>#include "Model.h"

using namespace qReal;

using namespace model;

Model::Model()
{
	mClient = new client::Client();
	rootItem = new ModelTreeItem(ROOT_ID,NULL);
}

Model::~Model()
{
	delete mClient;
}

Qt::ItemFlags Model::flags( const QModelIndex &index ) const
{
	if (index.isValid()) {
		return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
			| Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
	} else {
		return Qt::NoItemFlags;
	}
}

QVariant Model::data( const QModelIndex &index, int role) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				return mClient->property(item->id(),"Name");
		}
		return QVariant();
	} else {
		return QVariant();
	}
}

QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0 ) {
		return QVariant("Name");
	} else {
		return QVariant();
	}
}

int Model::rowCount( const QModelIndex &parent ) const
{
	if (parent.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(parent.internalPointer());
		return item->children().size();
	} else {
		return 0;
	}
}

int Model::columnCount( const QModelIndex &parent ) const
{
	Q_UNUSED(parent)
		return 1;
}

bool Model::setData( const QModelIndex &index, const QVariant &value, int role )
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				mClient->setProperty(item->id(),"Name",value);
				return true;
		}
		return false;
	} else {
		return false;
	}
}

bool Model::removeRows( int row, int count, const QModelIndex &parent )
{
	if (parent.isValid()) {
		ModelTreeItem *parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		if (parentItem->children().size() < row + count) {
			return false;
		} else {
			for (int i = row; i < row + count; i++) {
				removeModelItems(parentItem->children().at(i));
			}
			return true;
		}
	} else {
		return false;
	}
}

void Model::removeModelItems( ModelTreeItem *root )
{
	foreach (ModelTreeItem *child, root->children()) {
		removeModelItems(child);
		child->parent()->removeChild(child);
		treeItems.remove(child->id(),child);
		// мб надо удалить из клиента его конфигурацию на данной диаграмме.
		if (treeItems.count(child->id())==0) {
			mClient->removeChild(root->id(),child->id());
		}
	}
}

QModelIndex Model::index( int row, int column, const QModelIndex &parent ) const
{
	if (parent.isValid()) {
		ModelTreeItem *parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		ModelTreeItem *item = parentItem->children().at(row);
		return createIndex(row,column,item);
	} else {
		return QModelIndex();
	}
}

QModelIndex Model::parent( const QModelIndex &index ) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		ModelTreeItem *parentItem = item->parent();
		if (parentItem==rootItem) {
			return QModelIndex();
		} else{
			return createIndex(parentItem->row(),0,parentItem);
		}
	} else {
		return QModelIndex();
	}
}

Qt::DropActions Model::supportedDropActions() const
{
	return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

QStringList Model::mimeTypes() const
{
	QStringList types;
	types.append("application/x-real-uml-data");
	return types;
}

QMimeData* Model::mimeData( const QModelIndexList &indexes ) const
{
	return new QMimeData();
}

bool Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
	return false;
}<commit_msg>small fix model<commit_after>#include "Model.h"

using namespace qReal;

using namespace model;

Model::Model()
{
	mClient = new client::Client();
	rootItem = new ModelTreeItem(ROOT_ID,NULL);
}

Model::~Model()
{
	delete mClient;
}

Qt::ItemFlags Model::flags( const QModelIndex &index ) const
{
	if (index.isValid()) {
		return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled
			| Qt::ItemIsDropEnabled | Qt::ItemIsEnabled;
	} else {
		return Qt::NoItemFlags;
	}
}

QVariant Model::data( const QModelIndex &index, int role) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				return mClient->property(item->id(),"Name");
		}
		return QVariant();
	} else {
		return QVariant();
	}
}

QVariant Model::headerData( int section, Qt::Orientation orientation, int role ) const
{
	if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0 ) {
		return QVariant("Name");
	} else {
		return QVariant();
	}
}

int Model::rowCount( const QModelIndex &parent ) const
{
	if (parent.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(parent.internalPointer());
		return item->children().size();
	} else {
		return 0;
	}
}

int Model::columnCount( const QModelIndex &parent ) const
{
	if (parent.isValid()) {
		return 1;
	} else {
		return 0;
	}
}

bool Model::setData( const QModelIndex &index, const QVariant &value, int role )
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		switch (role) {
			case Qt::DisplayRole:
			case Qt::EditRole:
				mClient->setProperty(item->id(),"Name",value);
				return true;
		}
		return false;
	} else {
		return false;
	}
}

bool Model::removeRows( int row, int count, const QModelIndex &parent )
{
	if (parent.isValid()) {
		ModelTreeItem *parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		if (parentItem->children().size() < row + count) {
			return false;
		} else {
			beginRemoveRows(parent,row,row+count-1);
			for (int i = row; i < row + count; i++) {
				removeModelItems(parentItem->children().at(i));
			}
			endRemoveRows();
			return true;
		}
	} else {
		return false;
	}
}

void Model::removeModelItems( ModelTreeItem *root )
{
	foreach (ModelTreeItem *child, root->children()) {
		removeModelItems(child);
		child->parent()->removeChild(child);
		treeItems.remove(child->id(),child);
		// мб надо удалить из клиента его конфигурацию на данной диаграмме.
		if (treeItems.count(child->id())==0) {
			mClient->removeChild(root->id(),child->id());
		}
	}
}

QModelIndex Model::index( int row, int column, const QModelIndex &parent ) const
{
	if (parent.isValid()) {
		ModelTreeItem *parentItem = static_cast<ModelTreeItem*>(parent.internalPointer());
		ModelTreeItem *item = parentItem->children().at(row);
		return createIndex(row,column,item);
	} else {
		return QModelIndex();
	}
}

QModelIndex Model::parent( const QModelIndex &index ) const
{
	if (index.isValid()) {
		ModelTreeItem *item = static_cast<ModelTreeItem*>(index.internalPointer());
		ModelTreeItem *parentItem = item->parent();
		if (parentItem==rootItem) {
			return QModelIndex();
		} else{
			return createIndex(parentItem->row(),0,parentItem);
		}
	} else {
		return QModelIndex();
	}
}

Qt::DropActions Model::supportedDropActions() const
{
	return Qt::CopyAction | Qt::MoveAction | Qt::LinkAction;
}

QStringList Model::mimeTypes() const
{
	QStringList types;
	types.append("application/x-real-uml-data");
	return types;
}

QMimeData* Model::mimeData( const QModelIndexList &indexes ) const
{
	return new QMimeData();
}

bool Model::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent )
{
	return false;
}<|endoftext|>


<commit_before>#include "FVlib_OpenLog.h"

// Delay OpenLog, needed for the OpenLog to process the buffer
  #define dOL 30 // Less than 30 will give problems 30ok

// Constructor:
openLog::openLog(HardwareSerial &_port, unsigned int MBfileSizeLimit) {
  hardPort = &_port;
  (*hardPort).begin(9600);

}

/*openLog::openLog(SoftwareSerial &_port) {
  hspSel = false;
  softPort = &_port;
}*/

byte openLog::appendToLastLoggingSession(String loggingFileName, String textToAppend) {
// Return 0:Ok 1:Error
  char recivedChar;

  // Initialize SD, useful if SD stopped working
  (*hardPort).println("init");
  if (!waitForChar('>')) return 1;

  lastLoggingSession = findLastLoggingSession(loggingFileName);
  if (lastLoggingSession == 255) return 1;

  olCommand = String("append " + loggingFileName + lastLoggingSession + ".txt");

  // Clear the buffer:
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).println("");
  if (!waitForChar('>')) return 1;

  // Enter append mode:
  (*hardPort).println(olCommand);
  if (waitForChar('<')) {
    // We're in append mode now
    (*hardPort).print(textToAppend);
  }
  else {
    // Append mode could not be reached
    return 1;
  }

  // Exit append mode:
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).write(26);
  if (waitForChar('>')) {
    (*hardPort).println("sync");
    if (waitForChar('>'))  return 0; // Back to the command mode, everything was done!
  }
  else return 1; // We got stuck in the command mode, error.
}

byte openLog::findLastLoggingSession(String loggingFileName) {
  byte index;
  long loggingFileSize;

  // Check file from 9 to 1
  for (index = 9; index != 0; index--) {
    olCommand = String(loggingFileName + String(index) + ".txt");
    loggingFileSize = fileSize(olCommand);
    Serial.print(olCommand);
    Serial.println(loggingFileSize);
    if ((loggingFileSize != 0) && (index == 9)) return 255; // No available logging sessions
    if (loggingFileSize != 0) return index; // Available logging session found
  }
  return 1; // Logging session '1' is the last one
}

long openLog::fileSize(String fileName) {
  long loggingFileSize;
  char recivedChar;

  // Clear the buffer:
  (*hardPort).println("");
  if (!waitForChar('>')) return 0;

  // Find the size:
  olCommand = String("size " + fileName);
  (*hardPort).println(olCommand);
  delay(dOL);
  loggingFileSize = 0;
  recivedChar = (*hardPort).read();
  if (recivedChar == '\r') {
    recivedChar = (*hardPort).read();
    if (recivedChar == '\n') {
      while((*hardPort).available() > 0) {
        recivedChar = (*hardPort).read();
        if ((recivedChar == '!') || (recivedChar == '-')) {
          while((*hardPort).available() > 0) (*hardPort).read();
          return 0;
        }
        else if ((recivedChar >= '0') && (recivedChar <= '9')) {
          loggingFileSize = loggingFileSize + (recivedChar - '0');
          if (loggingFileSize < 1000000000) loggingFileSize = loggingFileSize * 10;
        }
      }
      if (loggingFileSize < 1000000000) loggingFileSize = loggingFileSize / 10;
      return loggingFileSize;
    }
  }
  else {
    // Error:
    return 0;
  }
}

boolean openLog::waitForChar(char whichChar) { // Wait for the OL to give us the char 'whichChar'
  char recivedChar;
  timeOut = millis();
  while((millis() - timeOut) < 2000) {
    if ((*hardPort).available() > 0) {
      recivedChar = (*hardPort).read();
      //Serial.print('.');
      if (recivedChar == whichChar) {
        return true;
      }
    }
  }
  return false;
}
<commit_msg>Mode fixes<commit_after>#include "FVlib_OpenLog.h"

// Delay OpenLog, needed for the OpenLog to process the buffer
  #define dOL 30 // Less than 30 will give problems 30ok

// Constructor:
openLog::openLog(HardwareSerial &_port, unsigned int MBfileSizeLimit) {
  hardPort = &_port;
  (*hardPort).begin(9600);

}

/*openLog::openLog(SoftwareSerial &_port) {
  hspSel = false;
  softPort = &_port;
}*/

byte openLog::appendToLastLoggingSession(String loggingFileName, String textToAppend) {
// Return 0:Ok 1:Error
  char recivedChar;

  // Initialize SD, useful if SD stopped working
  (*hardPort).println("init");
  if (!waitForChar('>')) return 1;

  lastLoggingSession = findLastLoggingSession(loggingFileName);
  if (lastLoggingSession == 255) return 1;

  olCommand = String("append " + loggingFileName + lastLoggingSession + ".txt");

  // Clear the buffer:
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).println("");
  if (!waitForChar('>')) return 1;

  // Enter append mode:
  (*hardPort).println(olCommand);
  if (waitForChar('<')) {
    // We're in append mode now
    (*hardPort).print(textToAppend);
  }
  else {
    // Append mode could not be reached
    return 1;
  }

  // Exit append mode:
  (*hardPort).write(26);
  (*hardPort).write(26);
  (*hardPort).write(26);
  if (waitForChar('>')) {
    (*hardPort).println("sync");
    if (waitForChar('>'))  return 0; // Back to the command mode, everything was done!
  }
  else return 1; // We got stuck in the command mode, error.
}

byte openLog::findLastLoggingSession(String loggingFileName) {
  byte index;
  long loggingFileSize;

  // Check file from 9 to 1
  for (index = 9; index != 0; index--) {
    olCommand = String(loggingFileName + String(index) + ".txt");
    loggingFileSize = fileSize(olCommand);
    Serial.print(olCommand);
    Serial.println(loggingFileSize);
    if ((loggingFileSize != 0) && (index == 9)) return 255; // No available logging sessions
    if (loggingFileSize != 0) return index; // Available logging session found
  }
  return 1; // Logging session '1' is the last one
}

long openLog::fileSize(String fileName) {
//Return: 0:Error !=0:File Size
  long loggingFileSize;
  char recivedChar;

  // Clear the buffer:
  (*hardPort).println("");
  if (!waitForChar('>')) return 0;

  // Find the size:
  olCommand = String("size " + fileName);
  (*hardPort).println(olCommand);
  delay(dOL);
  loggingFileSize = 0;

  if (waitForChar('\r') == true) {
    recivedChar = (*hardPort).read();
    if (recivedChar == '\n') {
      while((*hardPort).available() > 0) {
        recivedChar = (*hardPort).read();
        if ((recivedChar == '!') || (recivedChar == '-')) {
          while((*hardPort).available() > 0) (*hardPort).read();
          return 0;
        }
        else if ((recivedChar >= '0') && (recivedChar <= '9')) {
          loggingFileSize = loggingFileSize + (recivedChar - '0');
          if (loggingFileSize < 1000000000) loggingFileSize = loggingFileSize * 10;
        }
      }
      if (loggingFileSize < 1000000000) loggingFileSize = loggingFileSize / 10;
      return loggingFileSize;
    }
  }
  else {
    // Error:
    return 0;
  }
}

boolean openLog::waitForChar(char whichChar) { // Wait for the OL to give us the char 'whichChar'
  char recivedChar;
  timeOut = millis();
  while((millis() - timeOut) < 2000) {
    if ((*hardPort).available() > 0) {
      recivedChar = (*hardPort).read();
      //Serial.print('.');
      if (whichChar == 1) {
        return true;
      }
      else {
        if (recivedChar == whichChar) {
          return true;
        }
      }
    }
  }
  return false;
}
<|endoftext|>


<commit_before>#include "stream.h"

#include <node_buffer.h>
#include <glib.h>

#include "agent.h"
#include "helper.h"

using namespace v8;

v8::Persistent<v8::Function> Stream::constructor;

// helper

const char* state_to_string(int state_) {
	// to get notified if we miss a state
	const NiceComponentState state = (NiceComponentState) state_;

	switch(state) {
		case NICE_COMPONENT_STATE_DISCONNECTED:
			return "disconnected";
		case NICE_COMPONENT_STATE_GATHERING:
			return "gathering";
		case NICE_COMPONENT_STATE_CONNECTING:
			return "connecting";
		case NICE_COMPONENT_STATE_CONNECTED:
			return "connected";
		case NICE_COMPONENT_STATE_READY:
			return "ready";
		case NICE_COMPONENT_STATE_FAILED:
			return "failed";
		case NICE_COMPONENT_STATE_LAST:
			// not really a state
			break;
	}

	return "unknown";
}

// lifecycle

void Stream::init(v8::Handle<v8::Object> exports) {
	// Prepare constructor template
	Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
	tpl->SetClassName(String::NewSymbol("NiceStream"));
	tpl->InstanceTemplate()->SetInternalFieldCount(1);
	// protoype
	NODE_SET_PROTOTYPE_METHOD(tpl, "gatherCandidates", gatherCandidates);
	NODE_SET_PROTOTYPE_METHOD(tpl, "setRemoteCredentials", setRemoteCredentials);
	NODE_SET_PROTOTYPE_METHOD(tpl, "getLocalCredentials", getLocalCredentials);
	NODE_SET_PROTOTYPE_METHOD(tpl, "addRemoteIceCandidate", addRemoteIceCandidate);
	NODE_SET_PROTOTYPE_METHOD(tpl, "getLocalIceCandidates", getLocalIceCandidates);
	NODE_SET_PROTOTYPE_METHOD(tpl, "send", send);
	NODE_SET_PROTOTYPE_METHOD(tpl, "setTos", setTos);
	NODE_SET_PROTOTYPE_METHOD(tpl, "close", close);
	constructor = Persistent<Function>::New(tpl->GetFunction());
	// export
	exports->Set(String::NewSymbol("NiceStream"), constructor);
}

Stream::Stream(Handle<Object> js_agent, int stream_id, int components)
	: _js_agent(Persistent<Object>::New(js_agent)), _stream_id(stream_id), _components(components) {
	DEBUG("stream " << stream_id << " with " << components << " components created");
	Agent *agent = node::ObjectWrap::Unwrap<Agent>(js_agent);
	_nice_agent = agent->agent();
}

Stream::~Stream() {
	DEBUG("stream " << _stream_id << " is dying");

	Agent *agent = node::ObjectWrap::Unwrap<Agent>(_js_agent);

	agent->removeStream(_stream_id);

	_js_agent.Dispose();
}

// callback forwarder

void Stream::receive(int component, const char* buf, size_t size) {
	HandleScope scope;

	const int argc = 3;
	Handle<Value> argv[argc] = {
		String::New("receive"),
		Integer::New(component),
		node::Buffer::New(buf, size)->handle_,
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

void Stream::stateChanged(int component, int state) {
	HandleScope scope;

	const int argc = 3;
	Handle<Value> argv[argc] = {
		String::New("stateChanged"),
		Integer::New(component),
		String::New(state_to_string(state)),
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

void Stream::gatheringDone() {
	HandleScope scope;

	DEBUG("emitting callback");

	const int argc = 2;
	Handle<Value> argv[argc] = {
		String::New("gatheringDone"),
		getLocalIceCandidates(),
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

// js functions

v8::Handle<v8::Value> Stream::New(const v8::Arguments& args) {
	HandleScope scope;

	if (args.IsConstructCall()) {
		// Invoked as constructor: `new MyObject(...)`
		Stream* obj = new Stream(args[0]->ToObject(), args[1]->IntegerValue(), args[2]->IntegerValue());
		obj->Wrap(args.This());

		return args.This();
	} else {
		// Invoked as plain function `MyObject(...)`, turn into construct call.
		const int argc = 1;
		Local<Value> argv[1] = { argv[0] };
		return scope.Close(constructor->NewInstance(argc, argv));
	}
}

v8::Handle<v8::Value> Stream::gatherCandidates(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	nice_agent_gather_candidates(nice_agent, stream_id);

	return scope.Close(Undefined());
}

v8::Handle<v8::Value> Stream::setRemoteCredentials(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	v8::String::Utf8Value ufrag(args[0]->ToString());
	v8::String::Utf8Value pwd(args[1]->ToString());

	DEBUG("set remote credentials on stream " << stream_id << " to " << *ufrag << " " << *pwd);

	nice_agent_set_remote_credentials(nice_agent, stream_id, *ufrag, *pwd);

	return scope.Close(Undefined());
}

v8::Handle<v8::Value> Stream::getLocalCredentials(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	gchar *ufrag, *pwd;

	nice_agent_get_local_credentials(nice_agent, stream_id, &ufrag, &pwd);

	Local<Object> res = Object::New();
	res->Set(String::New("ufrag"), String::New(ufrag));
	res->Set(String::New("pwd"), String::New(pwd));

	DEBUG("local credentials are '" << ufrag << "' and '" << pwd << "'");

	g_free(ufrag);
	g_free(pwd);

	return scope.Close(res);
}

v8::Handle<v8::Value> Stream::addRemoteIceCandidate(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());

	v8::String::Utf8Value sdp(args[0]->ToString());

	bool res = stream->addRemoteIceCandidate(*sdp);

	return scope.Close(Boolean::New(res));
}

v8::Handle<v8::Value> Stream::getLocalIceCandidates(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());

	Handle<Value> res = stream->getLocalIceCandidates();

	return scope.Close(res);
}

v8::Handle<v8::Value> Stream::send(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	int component = args[0]->IntegerValue();

	if(!node::Buffer::HasInstance(args[1])) {
		ThrowException(Exception::TypeError(String::New("Expected buffer")));
	}

	Local<Object> buffer = args[1]->ToObject();

	size_t size = node::Buffer::Length(buffer);
	char* buf = node::Buffer::Data(buffer);

	DEBUG("sending " << size << " bytes");

	nice_agent_send(nice_agent, stream_id, component, size, buf);

	return scope.Close(Undefined());
}

v8::Handle<v8::Value> Stream::setTos(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	int tos = args[0]->IntegerValue();

	nice_agent_set_stream_tos(nice_agent, stream_id, tos);

	return scope.Close(Undefined());
}

v8::Handle<v8::Value> Stream::close(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	Agent *agent = node::ObjectWrap::Unwrap<Agent>(stream->_js_agent);
	int stream_id = stream->_stream_id;

	agent->removeStream(stream_id);

	return scope.Close(Undefined());
}

// helpers

v8::Handle<v8::Value> Stream::getLocalIceCandidates() {
	HandleScope scope;

	Local<Array> res = Array::New();
	Local<Function> push = Local<Function>::Cast(res->Get(String::New("push")));

	for(int i = 1; i <= _components; ++i) {
		GSList* root = nice_agent_get_local_candidates(_nice_agent, _stream_id, i);

		for(GSList* it = root; it; it = g_slist_next(it)) {
			auto candidate = reinterpret_cast<NiceCandidate*>(it->data);

			auto str = nice_agent_generate_local_candidate_sdp(_nice_agent, candidate);

			const int argc = 1;
			Local<Value> argv[argc] = {
				String::New(str),
			};
			push->Call(res, argc, argv);

			g_free(str);
		}

		g_slist_free(root);

	}

	return scope.Close(res);
}

bool Stream::addRemoteIceCandidate(const char* sdp_) {
	// sanitize

	std::string sdp(sdp_);

	DEBUG("adding candidate '" << trim(sdp) << "' to stream " << _stream_id);

	size_t small_udp = sdp.find(" udp ");

	if(small_udp != std::string::npos) {
		sdp.replace(small_udp, 5, " UDP ");
	}

	// parse sdp

	auto nice_candidate = nice_agent_parse_remote_candidate_sdp(_nice_agent, _stream_id, sdp.c_str());

	if(nice_candidate == NULL) {
		DEBUG("was unable to parse the candidate");
		return false;
	}

	if(nice_candidate->component_id > _components) {
		DEBUG("component was invalid");
		return false;
	}

	// insert into canidate list

	GSList *candidates = nice_agent_get_remote_candidates(_nice_agent, _stream_id, nice_candidate->component_id);

	candidates = g_slist_append(candidates, nice_candidate);

	nice_agent_set_remote_candidates(_nice_agent, _stream_id, nice_candidate->component_id, candidates);

	g_slist_free(candidates);

	return true;
}

<commit_msg>Add some return values<commit_after>#include "stream.h"

#include <node_buffer.h>
#include <glib.h>

#include "agent.h"
#include "helper.h"

using namespace v8;

v8::Persistent<v8::Function> Stream::constructor;

// helper

const char* state_to_string(int state_) {
	// to get notified if we miss a state
	const NiceComponentState state = (NiceComponentState) state_;

	switch(state) {
		case NICE_COMPONENT_STATE_DISCONNECTED:
			return "disconnected";
		case NICE_COMPONENT_STATE_GATHERING:
			return "gathering";
		case NICE_COMPONENT_STATE_CONNECTING:
			return "connecting";
		case NICE_COMPONENT_STATE_CONNECTED:
			return "connected";
		case NICE_COMPONENT_STATE_READY:
			return "ready";
		case NICE_COMPONENT_STATE_FAILED:
			return "failed";
		case NICE_COMPONENT_STATE_LAST:
			// not really a state
			break;
	}

	return "unknown";
}

// lifecycle

void Stream::init(v8::Handle<v8::Object> exports) {
	// Prepare constructor template
	Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
	tpl->SetClassName(String::NewSymbol("NiceStream"));
	tpl->InstanceTemplate()->SetInternalFieldCount(1);
	// protoype
	NODE_SET_PROTOTYPE_METHOD(tpl, "gatherCandidates", gatherCandidates);
	NODE_SET_PROTOTYPE_METHOD(tpl, "setRemoteCredentials", setRemoteCredentials);
	NODE_SET_PROTOTYPE_METHOD(tpl, "getLocalCredentials", getLocalCredentials);
	NODE_SET_PROTOTYPE_METHOD(tpl, "addRemoteIceCandidate", addRemoteIceCandidate);
	NODE_SET_PROTOTYPE_METHOD(tpl, "getLocalIceCandidates", getLocalIceCandidates);
	NODE_SET_PROTOTYPE_METHOD(tpl, "send", send);
	NODE_SET_PROTOTYPE_METHOD(tpl, "setTos", setTos);
	NODE_SET_PROTOTYPE_METHOD(tpl, "close", close);
	constructor = Persistent<Function>::New(tpl->GetFunction());
	// export
	exports->Set(String::NewSymbol("NiceStream"), constructor);
}

Stream::Stream(Handle<Object> js_agent, int stream_id, int components)
	: _js_agent(Persistent<Object>::New(js_agent)), _stream_id(stream_id), _components(components) {
	DEBUG("stream " << stream_id << " with " << components << " components created");
	Agent *agent = node::ObjectWrap::Unwrap<Agent>(js_agent);
	_nice_agent = agent->agent();
}

Stream::~Stream() {
	DEBUG("stream " << _stream_id << " is dying");

	Agent *agent = node::ObjectWrap::Unwrap<Agent>(_js_agent);

	agent->removeStream(_stream_id);

	_js_agent.Dispose();
}

// callback forwarder

void Stream::receive(int component, const char* buf, size_t size) {
	HandleScope scope;

	const int argc = 3;
	Handle<Value> argv[argc] = {
		String::New("receive"),
		Integer::New(component),
		node::Buffer::New(buf, size)->handle_,
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

void Stream::stateChanged(int component, int state) {
	HandleScope scope;

	const int argc = 3;
	Handle<Value> argv[argc] = {
		String::New("stateChanged"),
		Integer::New(component),
		String::New(state_to_string(state)),
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

void Stream::gatheringDone() {
	HandleScope scope;

	DEBUG("emitting callback");

	const int argc = 2;
	Handle<Value> argv[argc] = {
		String::New("gatheringDone"),
		getLocalIceCandidates(),
	};

	node::MakeCallback(handle_, "emit", argc, argv);
}

// js functions

v8::Handle<v8::Value> Stream::New(const v8::Arguments& args) {
	HandleScope scope;

	if (args.IsConstructCall()) {
		// Invoked as constructor: `new MyObject(...)`
		Stream* obj = new Stream(args[0]->ToObject(), args[1]->IntegerValue(), args[2]->IntegerValue());
		obj->Wrap(args.This());

		return args.This();
	} else {
		// Invoked as plain function `MyObject(...)`, turn into construct call.
		const int argc = 1;
		Local<Value> argv[1] = { argv[0] };
		return scope.Close(constructor->NewInstance(argc, argv));
	}
}

v8::Handle<v8::Value> Stream::gatherCandidates(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	bool res = nice_agent_gather_candidates(nice_agent, stream_id);

	return scope.Close(Boolean::New(res));
}

v8::Handle<v8::Value> Stream::setRemoteCredentials(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	v8::String::Utf8Value ufrag(args[0]->ToString());
	v8::String::Utf8Value pwd(args[1]->ToString());

	DEBUG("set remote credentials on stream " << stream_id << " to " << *ufrag << " " << *pwd);

	bool res = nice_agent_set_remote_credentials(nice_agent, stream_id, *ufrag, *pwd);

	return scope.Close(Boolean::New(res));
}

v8::Handle<v8::Value> Stream::getLocalCredentials(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	gchar *ufrag, *pwd;

	nice_agent_get_local_credentials(nice_agent, stream_id, &ufrag, &pwd);

	Local<Object> res = Object::New();
	res->Set(String::New("ufrag"), String::New(ufrag));
	res->Set(String::New("pwd"), String::New(pwd));

	DEBUG("local credentials are '" << ufrag << "' and '" << pwd << "'");

	g_free(ufrag);
	g_free(pwd);

	return scope.Close(res);
}

v8::Handle<v8::Value> Stream::addRemoteIceCandidate(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());

	v8::String::Utf8Value sdp(args[0]->ToString());

	bool res = stream->addRemoteIceCandidate(*sdp);

	return scope.Close(Boolean::New(res));
}

v8::Handle<v8::Value> Stream::getLocalIceCandidates(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());

	Handle<Value> res = stream->getLocalIceCandidates();

	return scope.Close(res);
}

v8::Handle<v8::Value> Stream::send(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	int component = args[0]->IntegerValue();

	if(!node::Buffer::HasInstance(args[1])) {
		ThrowException(Exception::TypeError(String::New("Expected buffer")));
	}

	Local<Object> buffer = args[1]->ToObject();

	size_t size = node::Buffer::Length(buffer);
	char* buf = node::Buffer::Data(buffer);

	DEBUG("sending " << size << " bytes");

	int ret = nice_agent_send(nice_agent, stream_id, component, size, buf);

	return scope.Close(Integer::New(ret));
}

v8::Handle<v8::Value> Stream::setTos(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	NiceAgent *nice_agent = stream->_nice_agent;
	int stream_id = stream->_stream_id;

	int tos = args[0]->IntegerValue();

	nice_agent_set_stream_tos(nice_agent, stream_id, tos);

	return scope.Close(Undefined());
}

v8::Handle<v8::Value> Stream::close(const v8::Arguments& args) {
	HandleScope scope;

	Stream *stream = node::ObjectWrap::Unwrap<Stream>(args.This()->ToObject());
	Agent *agent = node::ObjectWrap::Unwrap<Agent>(stream->_js_agent);
	int stream_id = stream->_stream_id;

	bool res = agent->removeStream(stream_id);

	return scope.Close(Boolean::New(res));
}

// helpers

v8::Handle<v8::Value> Stream::getLocalIceCandidates() {
	HandleScope scope;

	Local<Array> res = Array::New();
	Local<Function> push = Local<Function>::Cast(res->Get(String::New("push")));

	for(int i = 1; i <= _components; ++i) {
		GSList* root = nice_agent_get_local_candidates(_nice_agent, _stream_id, i);

		for(GSList* it = root; it; it = g_slist_next(it)) {
			auto candidate = reinterpret_cast<NiceCandidate*>(it->data);

			auto str = nice_agent_generate_local_candidate_sdp(_nice_agent, candidate);

			const int argc = 1;
			Local<Value> argv[argc] = {
				String::New(str),
			};
			push->Call(res, argc, argv);

			g_free(str);
		}

		g_slist_free(root);

	}

	return scope.Close(res);
}

bool Stream::addRemoteIceCandidate(const char* sdp_) {
	// sanitize

	std::string sdp(sdp_);

	DEBUG("adding candidate '" << trim(sdp) << "' to stream " << _stream_id);

	size_t small_udp = sdp.find(" udp ");

	if(small_udp != std::string::npos) {
		sdp.replace(small_udp, 5, " UDP ");
	}

	// parse sdp

	auto nice_candidate = nice_agent_parse_remote_candidate_sdp(_nice_agent, _stream_id, sdp.c_str());

	if(nice_candidate == NULL) {
		DEBUG("was unable to parse the candidate");
		return false;
	}

	if(nice_candidate->component_id > _components) {
		DEBUG("component was invalid");
		return false;
	}

	// insert into canidate list

	GSList *candidates = nice_agent_get_remote_candidates(_nice_agent, _stream_id, nice_candidate->component_id);

	candidates = g_slist_append(candidates, nice_candidate);

	nice_agent_set_remote_candidates(_nice_agent, _stream_id, nice_candidate->component_id, candidates);

	g_slist_free(candidates);

	return true;
}

<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkDistributedStreamTracer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDistributedStreamTracer.h"

#include "vtkCellData.h"
#include "vtkFloatArray.h"
#include "vtkIdList.h"
#include "vtkIntArray.h"
#include "vtkInterpolatedVelocityField.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkRungeKutta2.h"

vtkCxxRevisionMacro(vtkDistributedStreamTracer, "1.2");
vtkStandardNewMacro(vtkDistributedStreamTracer);

vtkDistributedStreamTracer::vtkDistributedStreamTracer()
{
}

vtkDistributedStreamTracer::~vtkDistributedStreamTracer()
{
}

void vtkDistributedStreamTracer::ForwardTask(float seed[3],
                                             int direction,
                                             int isNewSeed,
                                             int lastId,
                                             int lastCellId,
                                             int currentLine,
                                             float* firstNormal)
{
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();
  int nextid;
  if (myid == numProcs-1)
    {
    nextid = 0;
    }
  else
    {
    nextid = myid+1;
    }

  this->Controller->Send(&isNewSeed, 1, nextid, 311);
  this->Controller->Send(&lastId, 1, nextid, 322);
  if (isNewSeed != 2)
    {
    this->Controller->Send(&lastCellId, 1, nextid, 322);
    this->Controller->Send(seed, 3, nextid, 333);
    this->Controller->Send(&direction, 1, nextid, 344);
    this->Controller->Send(&currentLine, 1, nextid, 355);
    float tmpNormal[4];
    if (firstNormal)
      {
      tmpNormal[0] = 1;
      memcpy(tmpNormal+1, firstNormal, 3*sizeof(float));
      }
    else
      {
      tmpNormal[0] = 0;
      }
    this->Controller->Send(tmpNormal, 4, nextid, 366);
    }
}

int vtkDistributedStreamTracer::ReceiveAndProcessTask()
{
  int isNewSeed = 0;
  int lastId = 0;
  int lastCellId = 0;
  int currentLine = 0;
  int direction=FORWARD;
  float seed[3] = {0.0, 0.0, 0.0};
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();

  this->Controller->Receive(&isNewSeed,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            311);
  this->Controller->Receive(&lastId,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);

  // isNewSeed == 2 means that we were to stop.
  if ( isNewSeed == 2 )
    {
    if ( (( myid == numProcs-1 && lastId == 0 ) ||
          ( myid != numProcs-1 && lastId == myid + 1) ))
      {
      // All processes have been already told to stop. No need to tell
      // the next one.
      return 0;
      }
    this->ForwardTask(seed, direction, 2, lastId, lastCellId, 0, 0);
    return 0;
    }
  this->Controller->Receive(&lastCellId,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);
  this->Controller->Receive(seed,
                            3,
                            vtkMultiProcessController::ANY_SOURCE,
                            333);
  this->Controller->Receive(&direction,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            344);
  this->Controller->Receive(&currentLine,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            355);
  float tmpNormal[4];
  this->Controller->Receive(tmpNormal,
                            4,
                            vtkMultiProcessController::ANY_SOURCE,
                            366);
  float* firstNormal=0;
  if (tmpNormal[0] != 0)
    {
    firstNormal = &(tmpNormal[1]);
    }
  return this->ProcessTask(
    seed, direction, isNewSeed, lastId, lastCellId, currentLine, firstNormal);

}

int vtkDistributedStreamTracer::ProcessNextLine(int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();

  vtkIdType numLines = this->SeedIds->GetNumberOfIds();
  currentLine++;
  if ( currentLine < numLines )
    {
    return this->ProcessTask(
      this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
      this->IntegrationDirections->GetValue(currentLine),
      1, myid, -1, currentLine, 0);
    }

  // All done. Tell everybody to stop.
  float seed[3] = {0.0, 0.0, 0.0};
  this->ForwardTask(seed, 0, 2, myid, 0, 0, 0);
  return 0;

}

// Integrate a streamline
int vtkDistributedStreamTracer::ProcessTask(float seed[3],
                                            int direction,
                                            int isNewSeed,
                                            int lastId,
                                            int lastCellId,
                                            int currentLine,
                                            float* firstNormal)
{
  int myid = this->Controller->GetLocalProcessId();

  // This seed was visited by everybody and nobody had it.
  // Must be out of domain.
  if (isNewSeed == 0 && lastId == myid)
    {
    return this->ProcessNextLine(currentLine);
    }

  float velocity[3];
  // We don't have it, let's forward it to the next guy
  this->Interpolator->ClearLastCellId();
  int retVal = this->Interpolator->FunctionValues(seed, velocity);
  if (!retVal)
    {
    this->ForwardTask(
      seed, direction, 0, lastId, lastCellId, currentLine, firstNormal);
    return 1;
    }

  // We have it, let's integrate
  float lastPoint[3];

  vtkFloatArray* seeds = vtkFloatArray::New();
  seeds->SetNumberOfComponents(3);
  seeds->InsertNextTuple(seed);

  vtkIdList* seedIds = vtkIdList::New();
  seedIds->InsertNextId(0);

  vtkIntArray* integrationDirections = vtkIntArray::New();
  integrationDirections->InsertNextValue(direction);

  // Keep track of all streamlines by adding them to TmpOutputs.
  // They will be appended together after all the integration is done.
  vtkPolyData* tmpOutput = vtkPolyData::New();
  this->TmpOutputs.push_back(tmpOutput);

  vtkInterpolatedVelocityField* func;
  int maxCellSize = 0;
  this->CheckInputs(func, &maxCellSize);

  this->Integrate(tmpOutput,
                  seeds,
                  seedIds,
                  integrationDirections,
                  lastPoint,
                  func,
                  maxCellSize);
  this->GenerateNormals(tmpOutput, firstNormal);

  // These are used to keep track of where the seed came from
  // and where it will go. Used later to fill the gaps between
  // streamlines.
  vtkIntArray* strOrigin = vtkIntArray::New();
  strOrigin->SetNumberOfComponents(2);
  strOrigin->SetNumberOfTuples(1);
  strOrigin->SetName("Streamline Origin");
  strOrigin->SetValue(0, lastId);
  strOrigin->SetValue(1, lastCellId);
  tmpOutput->GetCellData()->AddArray(strOrigin);
  strOrigin->Delete();

  vtkIntArray* streamIds = vtkIntArray::New();
  streamIds->SetNumberOfTuples(1);
  streamIds->SetName("Streamline Ids");
  lastCellId = this->TmpOutputs.size() - 1;
  streamIds->SetComponent(0, 0, lastCellId);
  tmpOutput->GetCellData()->AddArray(streamIds);
  streamIds->Delete();

  // We have to know why the integration terminated
  vtkIntArray* resTermArray = vtkIntArray::SafeDownCast(
    tmpOutput->GetCellData()->GetArray("ReasonForTermination"));
  int resTerm=vtkStreamTracer::OUT_OF_DOMAIN;
  if (resTermArray)
    {
    resTerm = resTermArray->GetValue(0);
    }

  int numPoints = tmpOutput->GetNumberOfPoints();
  // If the interation terminated due to something other than
  // moving outside the domain, move to the next seed.
  if (numPoints == 0 || resTerm != vtkStreamTracer::OUT_OF_DOMAIN)
    {
    int retVal = this->ProcessNextLine(currentLine);
    seeds->Delete();
    seedIds->Delete();
    integrationDirections->Delete();
    tmpOutput->Delete();
    func->Delete();
    return retVal;
    }

  // Continue the integration a bit further to obtain a point
  // outside. The main integration step can not always be used
  // for this, specially if the integration is not 2nd order.
  tmpOutput->GetPoint(numPoints-1, lastPoint);

  vtkInitialValueProblemSolver* ivp = this->Integrator;
  ivp->Register(this);

  vtkRungeKutta2* tmpSolver = vtkRungeKutta2::New();
  this->SetIntegrator(tmpSolver);
  tmpSolver->Delete();

  float tmpseed[3];
  memcpy(tmpseed, lastPoint, 3*sizeof(float));
  this->SimpleIntegrate(tmpseed, lastPoint, this->LastUsedTimeStep, func);
  func->Delete();

  this->SetIntegrator(ivp);
  ivp->UnRegister(this);

  float* lastNormal = 0;
  vtkDataArray* normals = tmpOutput->GetPointData()->GetArray("Normals");
  if (normals)
    {
    lastNormal = new float[3];
    normals->GetTuple(normals->GetNumberOfTuples()-1, lastNormal);
    }

  tmpOutput->GetPoints()->SetPoint(numPoints-1, lastPoint);
  tmpOutput->Delete();

  // New seed, send it to the next guy
  this->ForwardTask(lastPoint, direction, 1, myid, lastCellId,
                    currentLine, lastNormal);

  delete[] lastNormal;

  seeds->Delete();
  seedIds->Delete();
  integrationDirections->Delete();

  return 1;
}

void vtkDistributedStreamTracer::ParallelIntegrate()
{

  int myid = this->Controller->GetLocalProcessId();
  if (this->Seeds)
    {
    int doLoop = 1;
    // First process starts by integrating the first point
    if (myid == 0)
      {
      int currentLine = 0;
      doLoop = this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1, myid, -1,currentLine, 0);
      }
    // Wait for someone to send us a seed to start from.
    while(doLoop)
      {
      if (!this->ReceiveAndProcessTask()) { break; }
      }
    }
}

void vtkDistributedStreamTracer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<commit_msg>Removed warning<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkDistributedStreamTracer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkDistributedStreamTracer.h"

#include "vtkCellData.h"
#include "vtkFloatArray.h"
#include "vtkIdList.h"
#include "vtkIntArray.h"
#include "vtkInterpolatedVelocityField.h"
#include "vtkMultiProcessController.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkRungeKutta2.h"

vtkCxxRevisionMacro(vtkDistributedStreamTracer, "1.3");
vtkStandardNewMacro(vtkDistributedStreamTracer);

vtkDistributedStreamTracer::vtkDistributedStreamTracer()
{
}

vtkDistributedStreamTracer::~vtkDistributedStreamTracer()
{
}

void vtkDistributedStreamTracer::ForwardTask(float seed[3],
                                             int direction,
                                             int isNewSeed,
                                             int lastId,
                                             int lastCellId,
                                             int currentLine,
                                             float* firstNormal)
{
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();
  int nextid;
  if (myid == numProcs-1)
    {
    nextid = 0;
    }
  else
    {
    nextid = myid+1;
    }

  this->Controller->Send(&isNewSeed, 1, nextid, 311);
  this->Controller->Send(&lastId, 1, nextid, 322);
  if (isNewSeed != 2)
    {
    this->Controller->Send(&lastCellId, 1, nextid, 322);
    this->Controller->Send(seed, 3, nextid, 333);
    this->Controller->Send(&direction, 1, nextid, 344);
    this->Controller->Send(&currentLine, 1, nextid, 355);
    float tmpNormal[4];
    if (firstNormal)
      {
      tmpNormal[0] = 1;
      memcpy(tmpNormal+1, firstNormal, 3*sizeof(float));
      }
    else
      {
      tmpNormal[0] = 0;
      }
    this->Controller->Send(tmpNormal, 4, nextid, 366);
    }
}

int vtkDistributedStreamTracer::ReceiveAndProcessTask()
{
  int isNewSeed = 0;
  int lastId = 0;
  int lastCellId = 0;
  int currentLine = 0;
  int direction=FORWARD;
  float seed[3] = {0.0, 0.0, 0.0};
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();

  this->Controller->Receive(&isNewSeed,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            311);
  this->Controller->Receive(&lastId,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);

  // isNewSeed == 2 means that we were to stop.
  if ( isNewSeed == 2 )
    {
    if ( (( myid == numProcs-1 && lastId == 0 ) ||
          ( myid != numProcs-1 && lastId == myid + 1) ))
      {
      // All processes have been already told to stop. No need to tell
      // the next one.
      return 0;
      }
    this->ForwardTask(seed, direction, 2, lastId, lastCellId, 0, 0);
    return 0;
    }
  this->Controller->Receive(&lastCellId,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);
  this->Controller->Receive(seed,
                            3,
                            vtkMultiProcessController::ANY_SOURCE,
                            333);
  this->Controller->Receive(&direction,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            344);
  this->Controller->Receive(&currentLine,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            355);
  float tmpNormal[4];
  this->Controller->Receive(tmpNormal,
                            4,
                            vtkMultiProcessController::ANY_SOURCE,
                            366);
  float* firstNormal=0;
  if (tmpNormal[0] != 0)
    {
    firstNormal = &(tmpNormal[1]);
    }
  return this->ProcessTask(
    seed, direction, isNewSeed, lastId, lastCellId, currentLine, firstNormal);

}

int vtkDistributedStreamTracer::ProcessNextLine(int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();

  vtkIdType numLines = this->SeedIds->GetNumberOfIds();
  currentLine++;
  if ( currentLine < numLines )
    {
    return this->ProcessTask(
      this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
      this->IntegrationDirections->GetValue(currentLine),
      1, myid, -1, currentLine, 0);
    }

  // All done. Tell everybody to stop.
  float seed[3] = {0.0, 0.0, 0.0};
  this->ForwardTask(seed, 0, 2, myid, 0, 0, 0);
  return 0;

}

// Integrate a streamline
int vtkDistributedStreamTracer::ProcessTask(float seed[3],
                                            int direction,
                                            int isNewSeed,
                                            int lastId,
                                            int lastCellId,
                                            int currentLine,
                                            float* firstNormal)
{
  int myid = this->Controller->GetLocalProcessId();

  // This seed was visited by everybody and nobody had it.
  // Must be out of domain.
  if (isNewSeed == 0 && lastId == myid)
    {
    return this->ProcessNextLine(currentLine);
    }

  float velocity[3];
  // We don't have it, let's forward it to the next guy
  this->Interpolator->ClearLastCellId();
  int retVal = this->Interpolator->FunctionValues(seed, velocity);
  if (!retVal)
    {
    this->ForwardTask(
      seed, direction, 0, lastId, lastCellId, currentLine, firstNormal);
    return 1;
    }

  // We have it, let's integrate
  float lastPoint[3];

  vtkFloatArray* seeds = vtkFloatArray::New();
  seeds->SetNumberOfComponents(3);
  seeds->InsertNextTuple(seed);

  vtkIdList* seedIds = vtkIdList::New();
  seedIds->InsertNextId(0);

  vtkIntArray* integrationDirections = vtkIntArray::New();
  integrationDirections->InsertNextValue(direction);

  // Keep track of all streamlines by adding them to TmpOutputs.
  // They will be appended together after all the integration is done.
  vtkPolyData* tmpOutput = vtkPolyData::New();
  this->TmpOutputs.push_back(tmpOutput);

  vtkInterpolatedVelocityField* func;
  int maxCellSize = 0;
  this->CheckInputs(func, &maxCellSize);

  this->Integrate(tmpOutput,
                  seeds,
                  seedIds,
                  integrationDirections,
                  lastPoint,
                  func,
                  maxCellSize);
  this->GenerateNormals(tmpOutput, firstNormal);

  // These are used to keep track of where the seed came from
  // and where it will go. Used later to fill the gaps between
  // streamlines.
  vtkIntArray* strOrigin = vtkIntArray::New();
  strOrigin->SetNumberOfComponents(2);
  strOrigin->SetNumberOfTuples(1);
  strOrigin->SetName("Streamline Origin");
  strOrigin->SetValue(0, lastId);
  strOrigin->SetValue(1, lastCellId);
  tmpOutput->GetCellData()->AddArray(strOrigin);
  strOrigin->Delete();

  vtkIntArray* streamIds = vtkIntArray::New();
  streamIds->SetNumberOfTuples(1);
  streamIds->SetName("Streamline Ids");
  lastCellId = static_cast<int>(this->TmpOutputs.size()) - 1;
  streamIds->SetComponent(0, 0, lastCellId);
  tmpOutput->GetCellData()->AddArray(streamIds);
  streamIds->Delete();

  // We have to know why the integration terminated
  vtkIntArray* resTermArray = vtkIntArray::SafeDownCast(
    tmpOutput->GetCellData()->GetArray("ReasonForTermination"));
  int resTerm=vtkStreamTracer::OUT_OF_DOMAIN;
  if (resTermArray)
    {
    resTerm = resTermArray->GetValue(0);
    }

  int numPoints = tmpOutput->GetNumberOfPoints();
  // If the interation terminated due to something other than
  // moving outside the domain, move to the next seed.
  if (numPoints == 0 || resTerm != vtkStreamTracer::OUT_OF_DOMAIN)
    {
    int retVal = this->ProcessNextLine(currentLine);
    seeds->Delete();
    seedIds->Delete();
    integrationDirections->Delete();
    tmpOutput->Delete();
    func->Delete();
    return retVal;
    }

  // Continue the integration a bit further to obtain a point
  // outside. The main integration step can not always be used
  // for this, specially if the integration is not 2nd order.
  tmpOutput->GetPoint(numPoints-1, lastPoint);

  vtkInitialValueProblemSolver* ivp = this->Integrator;
  ivp->Register(this);

  vtkRungeKutta2* tmpSolver = vtkRungeKutta2::New();
  this->SetIntegrator(tmpSolver);
  tmpSolver->Delete();

  float tmpseed[3];
  memcpy(tmpseed, lastPoint, 3*sizeof(float));
  this->SimpleIntegrate(tmpseed, lastPoint, this->LastUsedTimeStep, func);
  func->Delete();

  this->SetIntegrator(ivp);
  ivp->UnRegister(this);

  float* lastNormal = 0;
  vtkDataArray* normals = tmpOutput->GetPointData()->GetArray("Normals");
  if (normals)
    {
    lastNormal = new float[3];
    normals->GetTuple(normals->GetNumberOfTuples()-1, lastNormal);
    }

  tmpOutput->GetPoints()->SetPoint(numPoints-1, lastPoint);
  tmpOutput->Delete();

  // New seed, send it to the next guy
  this->ForwardTask(lastPoint, direction, 1, myid, lastCellId,
                    currentLine, lastNormal);

  delete[] lastNormal;

  seeds->Delete();
  seedIds->Delete();
  integrationDirections->Delete();

  return 1;
}

void vtkDistributedStreamTracer::ParallelIntegrate()
{

  int myid = this->Controller->GetLocalProcessId();
  if (this->Seeds)
    {
    int doLoop = 1;
    // First process starts by integrating the first point
    if (myid == 0)
      {
      int currentLine = 0;
      doLoop = this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1, myid, -1,currentLine, 0);
      }
    // Wait for someone to send us a seed to start from.
    while(doLoop)
      {
      if (!this->ReceiveAndProcessTask()) { break; }
      }
    }
}

void vtkDistributedStreamTracer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
}
<|endoftext|>


<commit_before>#ifndef ITER_DROPWHILE_H_
#define ITER_DROPWHILE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>
#include <initializer_list>

namespace iter {
  namespace impl {
    template <typename FilterFunc, typename Container>
    class Dropper;
  }

  template <typename FilterFunc, typename Container>
  impl::Dropper<FilterFunc, Container> dropwhile(FilterFunc, Container&&);

  template <typename FilterFunc, typename T>
  impl::Dropper<FilterFunc, std::initializer_list<T>> dropwhile(
      FilterFunc, std::initializer_list<T>);
}

template <typename FilterFunc, typename Container>
class iter::impl::Dropper {
 private:
  Container container;
  FilterFunc filter_func;

  friend Dropper iter::dropwhile<FilterFunc, Container>(
      FilterFunc, Container&&);

  template <typename FF, typename T>
  friend Dropper<FF, std::initializer_list<T>> iter::dropwhile(
      FF, std::initializer_list<T>);

  Dropper(FilterFunc in_filter_func, Container&& in_container)
      : container(std::forward<Container>(in_container)),
        filter_func(in_filter_func) {}

 public:
  Dropper(Dropper&&) = default;
  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<Container>> {
   private:
    using Holder = DerefHolder<iterator_deref<Container>>;
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    Holder item;
    FilterFunc* filter_func;

    void inc_sub_iter() {
      ++this->sub_iter;
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
    }

    // skip all values for which the predicate is true
    void skip_passes() {
      while (this->sub_iter != this->sub_end
             && (*this->filter_func)(this->item.get())) {
        this->inc_sub_iter();
      }
    }

   public:
    Iterator(iterator_type<Container>&& iter, iterator_type<Container>&& end,
        FilterFunc& in_filter_func)
        : sub_iter{std::move(iter)},
          sub_end{std::move(end)},
          filter_func(&in_filter_func) {
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
      this->skip_passes();
    }

    typename Holder::reference operator*() {
      return this->item.get();
    }

    typename Holder::pointer operator->() {
      return this->item.get_ptr();
    }

    Iterator& operator++() {
      this->inc_sub_iter();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container),
        this->filter_func};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container),
        this->filter_func};
  }
};

template <typename FilterFunc, typename Container>
iter::impl::Dropper<FilterFunc, Container> iter::dropwhile(
    FilterFunc filter_func, Container&& container) {
  return {filter_func, std::forward<Container>(container)};
}

template <typename FilterFunc, typename T>
iter::impl::Dropper<FilterFunc, std::initializer_list<T>> iter::dropwhile(
    FilterFunc filter_func, std::initializer_list<T> il) {
  return {filter_func, std::move(il)};
}

#endif
<commit_msg>drops init list support from dropwhile<commit_after>#ifndef ITER_DROPWHILE_H_
#define ITER_DROPWHILE_H_

#include "internal/iterbase.hpp"

#include <utility>
#include <iterator>

namespace iter {
  namespace impl {
    template <typename FilterFunc, typename Container>
    class Dropper;
  }

  template <typename FilterFunc, typename Container>
  impl::Dropper<FilterFunc, Container> dropwhile(FilterFunc, Container&&);

}

template <typename FilterFunc, typename Container>
class iter::impl::Dropper {
 private:
  Container container;
  FilterFunc filter_func;

  friend Dropper iter::dropwhile<FilterFunc, Container>(
      FilterFunc, Container&&);

  Dropper(FilterFunc in_filter_func, Container&& in_container)
      : container(std::forward<Container>(in_container)),
        filter_func(in_filter_func) {}

 public:
  Dropper(Dropper&&) = default;
  class Iterator : public std::iterator<std::input_iterator_tag,
                       iterator_traits_deref<Container>> {
   private:
    using Holder = DerefHolder<iterator_deref<Container>>;
    iterator_type<Container> sub_iter;
    iterator_type<Container> sub_end;
    Holder item;
    FilterFunc* filter_func;

    void inc_sub_iter() {
      ++this->sub_iter;
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
    }

    // skip all values for which the predicate is true
    void skip_passes() {
      while (this->sub_iter != this->sub_end
             && (*this->filter_func)(this->item.get())) {
        this->inc_sub_iter();
      }
    }

   public:
    Iterator(iterator_type<Container>&& iter, iterator_type<Container>&& end,
        FilterFunc& in_filter_func)
        : sub_iter{std::move(iter)},
          sub_end{std::move(end)},
          filter_func(&in_filter_func) {
      if (this->sub_iter != this->sub_end) {
        this->item.reset(*this->sub_iter);
      }
      this->skip_passes();
    }

    typename Holder::reference operator*() {
      return this->item.get();
    }

    typename Holder::pointer operator->() {
      return this->item.get_ptr();
    }

    Iterator& operator++() {
      this->inc_sub_iter();
      return *this;
    }

    Iterator operator++(int) {
      auto ret = *this;
      ++*this;
      return ret;
    }

    bool operator!=(const Iterator& other) const {
      return this->sub_iter != other.sub_iter;
    }

    bool operator==(const Iterator& other) const {
      return !(*this != other);
    }
  };

  Iterator begin() {
    return {std::begin(this->container), std::end(this->container),
        this->filter_func};
  }

  Iterator end() {
    return {std::end(this->container), std::end(this->container),
        this->filter_func};
  }
};

template <typename FilterFunc, typename Container>
iter::impl::Dropper<FilterFunc, Container> iter::dropwhile(
    FilterFunc filter_func, Container&& container) {
  return {filter_func, std::forward<Container>(container)};
}

#endif
<|endoftext|>


<commit_before>#include "adaptor.h"

#include <map>
#include <array>
#include <functional>

#include <QHBoxLayout>
#include <QMessageBox>

#include <dependency_graph/node.inl>

#include "node_data.h"
#include "connected_edge.h"
#include "io/io.h"

namespace {

/// creates a unique colour for a datatype
QColor colour(const std::string& datatype) {
	static std::map<std::string, QColor> s_colours;
	auto it = s_colours.find(datatype);
	if(it != s_colours.end())
		return it->second;

	const unsigned hash = std::hash<std::string>()(datatype);
	QColor result(
		(unsigned char)hash,
		(unsigned char)(hash >> 8),
		(unsigned char)(hash >> 16)
	);

	s_colours.insert(std::make_pair(datatype, result));

	return result;
}

}

Adaptor::Adaptor(dependency_graph::Graph* graph) : m_graph(graph) {
	// register callbacks
	m_signals.push_back(graph->onAddNode(
		[&](dependency_graph::Node& node) { onAddNode(node); }
	));

	m_signals.push_back(graph->onRemoveNode(
		[&](dependency_graph::Node& node) { onRemoveNode(node); }
	));

	m_signals.push_back(graph->onConnect(
		[&](dependency_graph::Port& p1, dependency_graph::Port& p2) { onConnect(p1, p2); }
	));

	m_signals.push_back(graph->onDisconnect(
		[&](dependency_graph::Port& p1, dependency_graph::Port& p2) { onDisconnect(p1, p2); }
	));

	m_signals.push_back(graph->onBlindDataChanged(
		[&](dependency_graph::Node& n) { onBlindDataChanged(n); }
	));

	// instantiate the graph widget
	QHBoxLayout* layout = new QHBoxLayout(this);
	layout->setContentsMargins(0,0,0,0);
	setLayout(layout);

	m_graphWidget = new node_editor::GraphWidget();
	layout->addWidget(m_graphWidget);

	m_graphWidget->scene().setMouseConnectionCallback([&](node_editor::Port& p1, node_editor::Port& p2) {
		// find the two nodes that were connected
		auto n1 = m_nodes.right.find(&p1.parentNode());
		assert(n1 != m_nodes.right.end());
		auto n2 = m_nodes.right.find(&p2.parentNode());
		assert(n2 != m_nodes.right.end());

		// and connect them in the graph as well
		try {
			n1->second->port(p1.index()).connect(n2->second->port(p2.index()));
		}
		catch(std::runtime_error& err) {
			// something went wrong during connecting, undo it
			m_graphWidget->scene().disconnect(p1, p2);
			// and make an error dialog with the problem
			QMessageBox::critical(m_graphWidget, "Error connecting nodes", err.what());
		}
	});

	m_graphWidget->scene().setNodeMoveCallback([&](node_editor::Node& node) {
		auto n = m_nodes.right.find(&node);
		assert(n != m_nodes.right.end());

		n->second->setBlindData<NodeData>(NodeData{n->first->pos()});
	});

	// and instantiate the current graph state
	for(auto& n : m_graph->nodes())
		onAddNode(n);

	for(auto& c : m_graph->connections())
		onConnect(c.first, c.second);
}

Adaptor::~Adaptor() {
	for(auto& c : m_signals)
		c.disconnect();
}

void Adaptor::onAddNode(dependency_graph::Node& node) {
	// get the blind data, containing the node's position
	const NodeData& data = node.blindData<NodeData>();

	// instantiate new graphical item
	node_editor::Node& newNode = m_graphWidget->scene().addNode(
		node.name().c_str(), data.position);

	// add all ports, based on the node's metadata
	for(size_t a = 0; a < node.metadata().attributeCount(); ++a) {
		const dependency_graph::Attr& attr = node.metadata().attr(a);

		newNode.addPort(node_editor::Node::PortDefinition {
			attr.name().c_str(),
			attr.category() == dependency_graph::Attr::kInput ? node_editor::Port::kInput : node_editor::Port::kOutput,
			colour(attr.type().name())
		});
	}

	// and register the node in the internal map
	m_nodes.left.insert(std::make_pair(&node, &newNode));
}

void Adaptor::onRemoveNode(dependency_graph::Node& node) {
	// find the item to be deleted
	auto it = m_nodes.left.find(&node);
	assert(it != m_nodes.left.end());

	// and remove it
	m_graphWidget->scene().removeNode(*(it->second));
}

void Adaptor::onConnect(dependency_graph::Port& p1, dependency_graph::Port& p2) {
	// find the two nodes to be connected
	auto n1 = m_nodes.left.find(&p1.node());
	assert(n1 != m_nodes.left.end());
	auto n2 = m_nodes.left.find(&p2.node());
	assert(n2 != m_nodes.left.end());

	// instantiate the connection
	m_graphWidget->scene().connect(n1->second->port(p1.index()), n2->second->port(p2.index()));
}

void Adaptor::onDisconnect(dependency_graph::Port& p1, dependency_graph::Port& p2) {
	// find the two nodes to be disconnected
	auto n1 = m_nodes.left.find(&p1.node());
	assert(n1 != m_nodes.left.end());
	auto n2 = m_nodes.left.find(&p2.node());
	assert(n2 != m_nodes.left.end());

	// remove the connection
	m_graphWidget->scene().disconnect(n1->second->port(p1.index()), n2->second->port(p2.index()));
}

void Adaptor::onBlindDataChanged(dependency_graph::Node& node) {
	auto n = m_nodes.left.find(&node);
	assert(n != m_nodes.left.end());

	const NodeData& data = node.blindData<NodeData>();

	n->second->setPos(data.position);
}

QPointF Adaptor::mapToScene(QPoint pos) const {
	return m_graphWidget->mapToScene(pos);
}

void Adaptor::deleteSelected() {
	unsigned ei = 0;
	while(ei < m_graphWidget->scene().edgeCount()) {
		node_editor::ConnectedEdge& e = m_graphWidget->scene().edge(ei);
		if(e.isSelected()) {
			auto n1 = m_nodes.right.find(&(e.fromPort().parentNode()));
			assert(n1 != m_nodes.right.end());

			auto n2 = m_nodes.right.find(&(e.toPort().parentNode()));
			assert(n2 != m_nodes.right.end());

			n1->second->port(e.fromPort().index()).disconnect(n2->second->port(e.toPort().index()));
		}
		else
			++ei;
	}

	unsigned ni = 0;
	while(ni < m_graphWidget->scene().nodeCount()) {
		node_editor::Node& n = m_graphWidget->scene().node(ni);
		if(n.isSelected()) {
			auto node = m_nodes.right.find(&n);
			assert(node != m_nodes.right.end());

			auto toErase = std::find_if(m_graph->nodes().begin(), m_graph->nodes().end(),
				[&](const dependency_graph::Node& n) {
					return &n == node->second;
				}
			);
			assert(toErase != m_graph->nodes().end());

			m_graph->nodes().erase(toErase);
		}
		else
			++ni;
	}
}

std::vector<std::reference_wrapper<dependency_graph::Node>> Adaptor::selectedNodes() {
	std::vector<std::reference_wrapper<dependency_graph::Node>> result;

	for(unsigned ni=0; ni<m_graphWidget->scene().nodeCount(); ++ni) {
		node_editor::Node& n = m_graphWidget->scene().node(ni);
		if(n.isSelected()) {
			auto node = m_nodes.right.find(&n);
			assert(node != m_nodes.right.end());

			auto nodeRef = std::find_if(m_graph->nodes().begin(), m_graph->nodes().end(),
				[&](const dependency_graph::Node& n) {
					return &n == node->second;
				}
			);

			// deselection happens during the Qt object destruction -> the original
			//   node might not exist
			if(nodeRef != m_graph->nodes().end())
				result.push_back(*nodeRef);
		}
	}

	return result;
}

node_editor::GraphScene& Adaptor::scene() {
	return m_graphWidget->scene();
}

const node_editor::GraphScene& Adaptor::scene() const {
	return m_graphWidget->scene();
}

dependency_graph::Graph& Adaptor::graph() {
	return *m_graph;
}
<commit_msg>Fixed onRemove() callback in Adaptor to correctly remove nodes from the node-to-UI bimap<commit_after>#include "adaptor.h"

#include <map>
#include <array>
#include <functional>

#include <QHBoxLayout>
#include <QMessageBox>

#include <dependency_graph/node.inl>

#include "node_data.h"
#include "connected_edge.h"
#include "io/io.h"

namespace {

/// creates a unique colour for a datatype
QColor colour(const std::string& datatype) {
	static std::map<std::string, QColor> s_colours;
	auto it = s_colours.find(datatype);
	if(it != s_colours.end())
		return it->second;

	const unsigned hash = std::hash<std::string>()(datatype);
	QColor result(
		(unsigned char)hash,
		(unsigned char)(hash >> 8),
		(unsigned char)(hash >> 16)
	);

	s_colours.insert(std::make_pair(datatype, result));

	return result;
}

}

Adaptor::Adaptor(dependency_graph::Graph* graph) : m_graph(graph) {
	// register callbacks
	m_signals.push_back(graph->onAddNode(
		[this](dependency_graph::Node& node) { onAddNode(node); }
	));

	m_signals.push_back(graph->onRemoveNode(
		[this](dependency_graph::Node& node) { onRemoveNode(node); }
	));

	m_signals.push_back(graph->onConnect(
		[this](dependency_graph::Port& p1, dependency_graph::Port& p2) { onConnect(p1, p2); }
	));

	m_signals.push_back(graph->onDisconnect(
		[this](dependency_graph::Port& p1, dependency_graph::Port& p2) { onDisconnect(p1, p2); }
	));

	m_signals.push_back(graph->onBlindDataChanged(
		[this](dependency_graph::Node& n) { onBlindDataChanged(n); }
	));

	// instantiate the graph widget
	QHBoxLayout* layout = new QHBoxLayout(this);
	layout->setContentsMargins(0,0,0,0);
	setLayout(layout);

	m_graphWidget = new node_editor::GraphWidget();
	layout->addWidget(m_graphWidget);

	m_graphWidget->scene().setMouseConnectionCallback([&](node_editor::Port& p1, node_editor::Port& p2) {
		// find the two nodes that were connected
		auto n1 = m_nodes.right.find(&p1.parentNode());
		assert(n1 != m_nodes.right.end());
		auto n2 = m_nodes.right.find(&p2.parentNode());
		assert(n2 != m_nodes.right.end());

		// and connect them in the graph as well
		try {
			n1->second->port(p1.index()).connect(n2->second->port(p2.index()));
		}
		catch(std::runtime_error& err) {
			// something went wrong during connecting, undo it
			m_graphWidget->scene().disconnect(p1, p2);
			// and make an error dialog with the problem
			QMessageBox::critical(m_graphWidget, "Error connecting nodes", err.what());
		}
	});

	m_graphWidget->scene().setNodeMoveCallback([&](node_editor::Node& node) {
		auto n = m_nodes.right.find(&node);
		assert(n != m_nodes.right.end());

		n->second->setBlindData<NodeData>(NodeData{n->first->pos()});
	});

	// and instantiate the current graph state
	for(auto& n : m_graph->nodes())
		onAddNode(n);

	for(auto& c : m_graph->connections())
		onConnect(c.first, c.second);
}

Adaptor::~Adaptor() {
	for(auto& c : m_signals)
		c.disconnect();
}

void Adaptor::onAddNode(dependency_graph::Node& node) {
	// get the blind data, containing the node's position
	const NodeData& data = node.blindData<NodeData>();

	// instantiate new graphical item
	node_editor::Node& newNode = m_graphWidget->scene().addNode(
		node.name().c_str(), data.position);

	// add all ports, based on the node's metadata
	for(size_t a = 0; a < node.metadata().attributeCount(); ++a) {
		const dependency_graph::Attr& attr = node.metadata().attr(a);

		newNode.addPort(node_editor::Node::PortDefinition {
			attr.name().c_str(),
			attr.category() == dependency_graph::Attr::kInput ? node_editor::Port::kInput : node_editor::Port::kOutput,
			colour(attr.type().name())
		});
	}

	// and register the node in the internal map
	m_nodes.left.insert(std::make_pair(&node, &newNode));
}

void Adaptor::onRemoveNode(dependency_graph::Node& node) {
	// find the item to be deleted
	auto it = m_nodes.left.find(&node);
	assert(it != m_nodes.left.end());

	// and remove it
	m_graphWidget->scene().removeNode(*(it->second));

	// and delete it from the list of nodes
	m_nodes.left.erase(it);
}

void Adaptor::onConnect(dependency_graph::Port& p1, dependency_graph::Port& p2) {
	// find the two nodes to be connected
	auto n1 = m_nodes.left.find(&p1.node());
	assert(n1 != m_nodes.left.end());
	auto n2 = m_nodes.left.find(&p2.node());
	assert(n2 != m_nodes.left.end());

	assert(n1->second->portCount() > p1.index());
	assert(n2->second->portCount() > p2.index());

	// instantiate the connection
	m_graphWidget->scene().connect(n1->second->port(p1.index()), n2->second->port(p2.index()));
}

void Adaptor::onDisconnect(dependency_graph::Port& p1, dependency_graph::Port& p2) {
	// find the two nodes to be disconnected
	auto n1 = m_nodes.left.find(&p1.node());
	assert(n1 != m_nodes.left.end());
	auto n2 = m_nodes.left.find(&p2.node());
	assert(n2 != m_nodes.left.end());

	// remove the connection
	m_graphWidget->scene().disconnect(n1->second->port(p1.index()), n2->second->port(p2.index()));
}

void Adaptor::onBlindDataChanged(dependency_graph::Node& node) {
	auto n = m_nodes.left.find(&node);
	assert(n != m_nodes.left.end());

	const NodeData& data = node.blindData<NodeData>();

	n->second->setPos(data.position);
}

QPointF Adaptor::mapToScene(QPoint pos) const {
	return m_graphWidget->mapToScene(pos);
}

void Adaptor::deleteSelected() {
	unsigned ei = 0;
	while(ei < m_graphWidget->scene().edgeCount()) {
		node_editor::ConnectedEdge& e = m_graphWidget->scene().edge(ei);
		if(e.isSelected()) {
			auto n1 = m_nodes.right.find(&(e.fromPort().parentNode()));
			assert(n1 != m_nodes.right.end());

			auto n2 = m_nodes.right.find(&(e.toPort().parentNode()));
			assert(n2 != m_nodes.right.end());

			n1->second->port(e.fromPort().index()).disconnect(n2->second->port(e.toPort().index()));
		}
		else
			++ei;
	}

	unsigned ni = 0;
	while(ni < m_graphWidget->scene().nodeCount()) {
		node_editor::Node& n = m_graphWidget->scene().node(ni);
		if(n.isSelected()) {
			auto node = m_nodes.right.find(&n);
			assert(node != m_nodes.right.end());

			auto toErase = std::find_if(m_graph->nodes().begin(), m_graph->nodes().end(),
				[&](const dependency_graph::Node& n) {
					return &n == node->second;
				}
			);
			assert(toErase != m_graph->nodes().end());

			m_graph->nodes().erase(toErase);
		}
		else
			++ni;
	}
}

std::vector<std::reference_wrapper<dependency_graph::Node>> Adaptor::selectedNodes() {
	std::vector<std::reference_wrapper<dependency_graph::Node>> result;

	for(unsigned ni=0; ni<m_graphWidget->scene().nodeCount(); ++ni) {
		node_editor::Node& n = m_graphWidget->scene().node(ni);
		if(n.isSelected()) {
			auto node = m_nodes.right.find(&n);
			assert(node != m_nodes.right.end());

			auto nodeRef = std::find_if(m_graph->nodes().begin(), m_graph->nodes().end(),
				[&](const dependency_graph::Node& n) {
					return &n == node->second;
				}
			);

			// deselection happens during the Qt object destruction -> the original
			//   node might not exist
			if(nodeRef != m_graph->nodes().end())
				result.push_back(*nodeRef);
		}
	}

	return result;
}

node_editor::GraphScene& Adaptor::scene() {
	return m_graphWidget->scene();
}

const node_editor::GraphScene& Adaptor::scene() const {
	return m_graphWidget->scene();
}

dependency_graph::Graph& Adaptor::graph() {
	return *m_graph;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2007-2008 The Florida State University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Stephen Hines
 */
#ifndef __ARCH_ARM_INSTS_PREDINST_HH__
#define __ARCH_ARM_INSTS_PREDINST_HH__

#include "arch/arm/insts/static_inst.hh"
#include "base/trace.hh"

namespace ArmISA
{
static inline uint32_t
rotate_imm(uint32_t immValue, int rotateValue)
{
    return ((immValue >> (rotateValue & 31)) |
            (immValue << (32 - (rotateValue & 31))));
}

static inline uint32_t
modified_imm(uint8_t ctrlImm, uint8_t dataImm)
{
    uint32_t bigData = dataImm;
    uint32_t bigCtrl = ctrlImm;
    if (bigCtrl < 4) {
        switch (bigCtrl) {
          case 0:
            return bigData;
          case 1:
            return bigData | (bigData << 16);
          case 2:
            return (bigData << 8) | (bigData << 24);
          case 3:
            return (bigData << 0) | (bigData << 8) |
                   (bigData << 16) | (bigData << 24);
        }
    }
    bigCtrl = (bigCtrl << 1) | ((bigData >> 7) & 0x1);
    bigData |= (1 << 7);
    return bigData << (32 - bigCtrl);
}

static inline uint64_t
simd_modified_imm(bool op, uint8_t cmode, uint8_t data)
{
    uint64_t bigData = data;
    switch (cmode) {
      case 0x0:
      case 0x1:
        bigData = (bigData << 0) | (bigData << 32);
        break;
      case 0x2:
      case 0x3:
        bigData = (bigData << 8) | (bigData << 40);
        break;
      case 0x4:
      case 0x5:
        bigData = (bigData << 16) | (bigData << 48);
        break;
      case 0x6:
      case 0x7:
        bigData = (bigData << 24) | (bigData << 56);
        break;
      case 0x8:
      case 0x9:
        bigData = (bigData << 0) | (bigData << 16) |
                  (bigData << 32) | (bigData << 48);
        break;
      case 0xa:
      case 0xb:
        bigData = (bigData << 8) | (bigData << 24) |
                  (bigData << 40) | (bigData << 56);
        break;
      case 0xc:
        bigData = (0xffULL << 0) | (bigData << 8) |
                  (0xffULL << 32) | (bigData << 40);
        break;
      case 0xd:
        bigData = (0xffffULL << 0) | (bigData << 16) |
                  (0xffffULL << 32) | (bigData << 48);
        break;
      case 0xe:
        if (op) {
            bigData = (bigData << 0)  | (bigData << 8)  |
                      (bigData << 16) | (bigData << 24) |
                      (bigData << 32) | (bigData << 40) |
                      (bigData << 48) | (bigData << 56);
        } else {
            bigData = 0;
            for (int i = 7; i >= 0; i--) {
                if (bits(data, i)) {
                    bigData |= (0xFF << (i * 8));
                }
            }
        }
      case 0xf:
        if (!op) {
            uint64_t bVal = bits(bigData, 6) ? (0x1F) : (0x20);
            bigData = (bits(bigData, 5, 0) << 19) |
                      (bVal << 25) | (bits(bigData, 7) << 31);
            bigData |= (bigData << 32);
        }
        // Fall through
      default:
        panic("Illegal modified SIMD immediate parameters.\n");
    }
    return bigData;
}

/**
 * Base class for predicated integer operations.
 */
class PredOp : public ArmStaticInst
{
  protected:

    ConditionCode condCode;

    /// Constructor
    PredOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
           ArmStaticInst(mnem, _machInst, __opClass),
           condCode((ConditionCode)(unsigned)machInst.condCode)
    {
    }
};

/**
 * Base class for predicated immediate operations.
 */
class PredImmOp : public PredOp
{
    protected:

    uint32_t imm;
    uint32_t rotated_imm;
    uint32_t rotated_carry;
    uint32_t rotate;

    /// Constructor
    PredImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
              PredOp(mnem, _machInst, __opClass),
              imm(machInst.imm), rotated_imm(0), rotated_carry(0),
              rotate(machInst.rotate << 1)
    {
        rotated_imm = rotate_imm(imm, rotate);
        if (rotate != 0)
            rotated_carry = bits(rotated_imm, 31);
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated integer operations.
 */
class PredIntOp : public PredOp
{
    protected:

    uint32_t shift_size;
    uint32_t shift;

    /// Constructor
    PredIntOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
              PredOp(mnem, _machInst, __opClass),
              shift_size(machInst.shiftSize), shift(machInst.shift)
    {
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataImmOp : public PredOp
{
  protected:
    IntRegIndex dest, op1;
    uint32_t imm;
    // Whether the carry flag should be modified if that's an option for
    // this instruction.
    bool rotC;

    DataImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
              IntRegIndex _dest, IntRegIndex _op1, uint32_t _imm, bool _rotC) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), imm(_imm), rotC(_rotC)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataRegOp : public PredOp
{
  protected:
    IntRegIndex dest, op1, op2;
    int32_t shiftAmt;
    ArmShiftType shiftType;

    DataRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
              IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
              int32_t _shiftAmt, ArmShiftType _shiftType) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), op2(_op2),
        shiftAmt(_shiftAmt), shiftType(_shiftType)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataRegRegOp : public PredOp
{
  protected:
    IntRegIndex dest, op1, op2, shift;
    ArmShiftType shiftType;

    DataRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
                 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
                 IntRegIndex _shift, ArmShiftType _shiftType) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), op2(_op2), shift(_shift),
        shiftType(_shiftType)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated macro-operations.
 */
class PredMacroOp : public PredOp
{
    protected:

    uint32_t numMicroops;
    StaticInstPtr * microOps;

    /// Constructor
    PredMacroOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
                PredOp(mnem, _machInst, __opClass),
                numMicroops(0)
    {
        // We rely on the subclasses of this object to handle the
        // initialization of the micro-operations, since they are
        // all of variable length
        flags[IsMacroop] = true;
    }

    ~PredMacroOp()
    {
        if (numMicroops)
            delete [] microOps;
    }

    StaticInstPtr
    fetchMicroop(MicroPC microPC)
    {
        assert(microPC < numMicroops);
        return microOps[microPC];
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated micro-operations.
 */
class PredMicroop : public PredOp
{
    /// Constructor
    PredMicroop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
                PredOp(mnem, _machInst, __opClass)
    {
        flags[IsMicroop] = true;
    }
};
}

#endif //__ARCH_ARM_INSTS_PREDINST_HH__
<commit_msg>ARM: Add a function to decode VFP modified immediate constants.<commit_after>/*
 * Copyright (c) 2010 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2007-2008 The Florida State University
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Stephen Hines
 */
#ifndef __ARCH_ARM_INSTS_PREDINST_HH__
#define __ARCH_ARM_INSTS_PREDINST_HH__

#include "arch/arm/insts/static_inst.hh"
#include "base/trace.hh"

namespace ArmISA
{
static inline uint32_t
rotate_imm(uint32_t immValue, int rotateValue)
{
    return ((immValue >> (rotateValue & 31)) |
            (immValue << (32 - (rotateValue & 31))));
}

static inline uint32_t
modified_imm(uint8_t ctrlImm, uint8_t dataImm)
{
    uint32_t bigData = dataImm;
    uint32_t bigCtrl = ctrlImm;
    if (bigCtrl < 4) {
        switch (bigCtrl) {
          case 0:
            return bigData;
          case 1:
            return bigData | (bigData << 16);
          case 2:
            return (bigData << 8) | (bigData << 24);
          case 3:
            return (bigData << 0) | (bigData << 8) |
                   (bigData << 16) | (bigData << 24);
        }
    }
    bigCtrl = (bigCtrl << 1) | ((bigData >> 7) & 0x1);
    bigData |= (1 << 7);
    return bigData << (32 - bigCtrl);
}

static inline uint64_t
simd_modified_imm(bool op, uint8_t cmode, uint8_t data)
{
    uint64_t bigData = data;
    switch (cmode) {
      case 0x0:
      case 0x1:
        bigData = (bigData << 0) | (bigData << 32);
        break;
      case 0x2:
      case 0x3:
        bigData = (bigData << 8) | (bigData << 40);
        break;
      case 0x4:
      case 0x5:
        bigData = (bigData << 16) | (bigData << 48);
        break;
      case 0x6:
      case 0x7:
        bigData = (bigData << 24) | (bigData << 56);
        break;
      case 0x8:
      case 0x9:
        bigData = (bigData << 0) | (bigData << 16) |
                  (bigData << 32) | (bigData << 48);
        break;
      case 0xa:
      case 0xb:
        bigData = (bigData << 8) | (bigData << 24) |
                  (bigData << 40) | (bigData << 56);
        break;
      case 0xc:
        bigData = (0xffULL << 0) | (bigData << 8) |
                  (0xffULL << 32) | (bigData << 40);
        break;
      case 0xd:
        bigData = (0xffffULL << 0) | (bigData << 16) |
                  (0xffffULL << 32) | (bigData << 48);
        break;
      case 0xe:
        if (op) {
            bigData = (bigData << 0)  | (bigData << 8)  |
                      (bigData << 16) | (bigData << 24) |
                      (bigData << 32) | (bigData << 40) |
                      (bigData << 48) | (bigData << 56);
        } else {
            bigData = 0;
            for (int i = 7; i >= 0; i--) {
                if (bits(data, i)) {
                    bigData |= (0xFF << (i * 8));
                }
            }
        }
      case 0xf:
        if (!op) {
            uint64_t bVal = bits(bigData, 6) ? (0x1F) : (0x20);
            bigData = (bits(bigData, 5, 0) << 19) |
                      (bVal << 25) | (bits(bigData, 7) << 31);
            bigData |= (bigData << 32);
        }
        // Fall through
      default:
        panic("Illegal modified SIMD immediate parameters.\n");
    }
    return bigData;
}

static inline uint64_t
vfp_modified_imm(uint8_t data, bool wide)
{
    uint64_t bigData = data;
    uint64_t repData;
    if (wide) {
        repData = bits(data, 6) ? 0xFF : 0;
        bigData = (bits(bigData, 5, 0) << 48) |
                  (repData << 54) | (bits(~bigData, 6) << 62) |
                  (bits(bigData, 7) << 63);
    } else {
        repData = bits(data, 6) ? 0x1F : 0;
        bigData = (bits(bigData, 5, 0) << 19) |
                  (repData << 25) | (bits(~bigData, 6) << 30) |
                  (bits(bigData, 7) << 31);
    }
    return bigData;
}

/**
 * Base class for predicated integer operations.
 */
class PredOp : public ArmStaticInst
{
  protected:

    ConditionCode condCode;

    /// Constructor
    PredOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
           ArmStaticInst(mnem, _machInst, __opClass),
           condCode((ConditionCode)(unsigned)machInst.condCode)
    {
    }
};

/**
 * Base class for predicated immediate operations.
 */
class PredImmOp : public PredOp
{
    protected:

    uint32_t imm;
    uint32_t rotated_imm;
    uint32_t rotated_carry;
    uint32_t rotate;

    /// Constructor
    PredImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
              PredOp(mnem, _machInst, __opClass),
              imm(machInst.imm), rotated_imm(0), rotated_carry(0),
              rotate(machInst.rotate << 1)
    {
        rotated_imm = rotate_imm(imm, rotate);
        if (rotate != 0)
            rotated_carry = bits(rotated_imm, 31);
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated integer operations.
 */
class PredIntOp : public PredOp
{
    protected:

    uint32_t shift_size;
    uint32_t shift;

    /// Constructor
    PredIntOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
              PredOp(mnem, _machInst, __opClass),
              shift_size(machInst.shiftSize), shift(machInst.shift)
    {
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataImmOp : public PredOp
{
  protected:
    IntRegIndex dest, op1;
    uint32_t imm;
    // Whether the carry flag should be modified if that's an option for
    // this instruction.
    bool rotC;

    DataImmOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
              IntRegIndex _dest, IntRegIndex _op1, uint32_t _imm, bool _rotC) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), imm(_imm), rotC(_rotC)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataRegOp : public PredOp
{
  protected:
    IntRegIndex dest, op1, op2;
    int32_t shiftAmt;
    ArmShiftType shiftType;

    DataRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
              IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
              int32_t _shiftAmt, ArmShiftType _shiftType) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), op2(_op2),
        shiftAmt(_shiftAmt), shiftType(_shiftType)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

class DataRegRegOp : public PredOp
{
  protected:
    IntRegIndex dest, op1, op2, shift;
    ArmShiftType shiftType;

    DataRegRegOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
                 IntRegIndex _dest, IntRegIndex _op1, IntRegIndex _op2,
                 IntRegIndex _shift, ArmShiftType _shiftType) :
        PredOp(mnem, _machInst, __opClass),
        dest(_dest), op1(_op1), op2(_op2), shift(_shift),
        shiftType(_shiftType)
    {}

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated macro-operations.
 */
class PredMacroOp : public PredOp
{
    protected:

    uint32_t numMicroops;
    StaticInstPtr * microOps;

    /// Constructor
    PredMacroOp(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
                PredOp(mnem, _machInst, __opClass),
                numMicroops(0)
    {
        // We rely on the subclasses of this object to handle the
        // initialization of the micro-operations, since they are
        // all of variable length
        flags[IsMacroop] = true;
    }

    ~PredMacroOp()
    {
        if (numMicroops)
            delete [] microOps;
    }

    StaticInstPtr
    fetchMicroop(MicroPC microPC)
    {
        assert(microPC < numMicroops);
        return microOps[microPC];
    }

    std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};

/**
 * Base class for predicated micro-operations.
 */
class PredMicroop : public PredOp
{
    /// Constructor
    PredMicroop(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
                PredOp(mnem, _machInst, __opClass)
    {
        flags[IsMicroop] = true;
    }
};
}

#endif //__ARCH_ARM_INSTS_PREDINST_HH__
<|endoftext|>