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

#include "chrome_frame/com_message_event.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"

ComMessageEvent::ComMessageEvent() {
}

ComMessageEvent::~ComMessageEvent() {
}

bool ComMessageEvent::Initialize(IOleContainer* container,
                                 const std::string& message,
                                 const std::string& origin,
                                 const std::string& event_type) {
  DCHECK(container);
  message_ = message;
  origin_ = origin;
  type_ = event_type;

  // May remain NULL if container not IE
  ScopedComPtr<IHTMLEventObj> basic_event;
  ScopedComPtr<IHTMLDocument2> doc;

  // Fetching doc may fail in non-IE containers.
  container->QueryInterface(doc.Receive());
  if (doc) {
    ScopedComPtr<IHTMLDocument4> doc4;
    doc4.QueryFrom(doc);
    DCHECK(doc4);  // supported by IE5.5 and higher
    if (doc4) {
      // IHTMLEventObj5 is only supported in IE8 and later, so we provide our
      // own (minimalistic) implementation of it.
      doc4->createEventObject(NULL, basic_event.Receive());
      DCHECK(basic_event);
    }
  }

  basic_event_ = basic_event;
  return true;
}

STDMETHODIMP ComMessageEvent::GetTypeInfoCount(UINT* info) {
  // Don't DCHECK as python scripts might still call this function
  // inadvertently.
  DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
  return E_NOTIMPL;
}

STDMETHODIMP ComMessageEvent::GetTypeInfo(UINT which_info, LCID lcid,
                                          ITypeInfo** type_info) {
  DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
  return E_NOTIMPL;
}

STDMETHODIMP ComMessageEvent::GetIDsOfNames(REFIID iid, LPOLESTR* names,
                                            UINT count_names, LCID lcid,
                                            DISPID* dispids) {
  HRESULT hr = S_OK;

  // Note that since we're using LowerCaseEqualsASCII for string comparison,
  // the second argument _must_ be all lower case.  I.e. we cannot compare
  // against L"messagePort" since it has a capital 'P'.
  for (UINT i = 0; SUCCEEDED(hr) && i < count_names; ++i) {
    const wchar_t* name_begin = names[i];
    const wchar_t* name_end = name_begin + wcslen(name_begin);
    if (LowerCaseEqualsASCII(name_begin, name_end, "data")) {
      dispids[i] = DISPID_MESSAGE_EVENT_DATA;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "origin")) {
      dispids[i] = DISPID_MESSAGE_EVENT_ORIGIN;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "lasteventid")) {
      dispids[i] = DISPID_MESSAGE_EVENT_LAST_EVENT_ID;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "source")) {
      dispids[i] = DISPID_MESSAGE_EVENT_SOURCE;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "messageport")) {
      dispids[i] = DISPID_MESSAGE_EVENT_MESSAGE_PORT;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "type")) {
      dispids[i] = DISPID_MESSAGE_EVENT_TYPE;
    } else {
      if (basic_event_) {
        hr = basic_event_->GetIDsOfNames(IID_IDispatch, &names[i], 1, lcid,
                                         &dispids[i]);
      } else {
        hr = DISP_E_MEMBERNOTFOUND;
      }

      if (FAILED(hr)) {
        DLOG(WARNING) << "member not found: " << names[i]
                      << StringPrintf(L"0x%08X", hr);
      }
    }
  }
  return hr;
}

STDMETHODIMP ComMessageEvent::Invoke(DISPID dispid, REFIID iid, LCID lcid,
                                     WORD flags, DISPPARAMS* params,
                                     VARIANT* result, EXCEPINFO* excepinfo,
                                     UINT* arg_err) {
  HRESULT hr = DISP_E_MEMBERNOTFOUND;
  switch (dispid) {
    case DISPID_MESSAGE_EVENT_DATA:
      hr = GetStringProperty(flags, UTF8ToWide(message_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_ORIGIN:
      hr = GetStringProperty(flags, UTF8ToWide(origin_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_TYPE:
      hr = GetStringProperty(flags, UTF8ToWide(type_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_LAST_EVENT_ID:
      hr = GetStringProperty(flags, L"", result);
      break;

    case DISPID_MESSAGE_EVENT_SOURCE:
    case DISPID_MESSAGE_EVENT_MESSAGE_PORT:
      if (flags & DISPATCH_PROPERTYGET) {
        result->vt = VT_NULL;
        hr = S_OK;
      } else {
        hr = DISP_E_TYPEMISMATCH;
      }
      break;

    default:
      if (basic_event_) {
        hr = basic_event_->Invoke(dispid, iid, lcid, flags, params, result,
                                  excepinfo, arg_err);
      }
      break;
  }

  return hr;
}

HRESULT ComMessageEvent::GetStringProperty(WORD flags, const wchar_t* value,
                                           VARIANT* result) {
  if (!result)
    return E_INVALIDARG;

  HRESULT hr;
  if (flags & DISPATCH_PROPERTYGET) {
    result->vt = VT_BSTR;
    result->bstrVal = ::SysAllocString(value);
    hr = S_OK;
  } else {
    hr = DISP_E_TYPEMISMATCH;
  }
  return hr;
}
<commit_msg>Check the container for NULLness before dereferencing.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome_frame/com_message_event.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"

ComMessageEvent::ComMessageEvent() {
}

ComMessageEvent::~ComMessageEvent() {
}

bool ComMessageEvent::Initialize(IOleContainer* container,
                                 const std::string& message,
                                 const std::string& origin,
                                 const std::string& event_type) {
  DLOG_IF(WARNING, !container) << __FUNCTION__ << " no container";
  message_ = message;
  origin_ = origin;
  type_ = event_type;

  // May remain NULL if container not IE
  ScopedComPtr<IHTMLEventObj> basic_event;
  ScopedComPtr<IHTMLDocument2> doc;

  // Fetching doc may fail in non-IE containers
  // and container might be NULL in some applications.
  if (container)
    container->QueryInterface(doc.Receive());
  if (doc) {
    ScopedComPtr<IHTMLDocument4> doc4;
    doc4.QueryFrom(doc);
    DCHECK(doc4);  // supported by IE5.5 and higher
    if (doc4) {
      // IHTMLEventObj5 is only supported in IE8 and later, so we provide our
      // own (minimalistic) implementation of it.
      doc4->createEventObject(NULL, basic_event.Receive());
      DCHECK(basic_event);
    }
  }

  basic_event_ = basic_event;
  return true;
}

STDMETHODIMP ComMessageEvent::GetTypeInfoCount(UINT* info) {
  // Don't DCHECK as python scripts might still call this function
  // inadvertently.
  DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
  return E_NOTIMPL;
}

STDMETHODIMP ComMessageEvent::GetTypeInfo(UINT which_info, LCID lcid,
                                          ITypeInfo** type_info) {
  DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
  return E_NOTIMPL;
}

STDMETHODIMP ComMessageEvent::GetIDsOfNames(REFIID iid, LPOLESTR* names,
                                            UINT count_names, LCID lcid,
                                            DISPID* dispids) {
  HRESULT hr = S_OK;

  // Note that since we're using LowerCaseEqualsASCII for string comparison,
  // the second argument _must_ be all lower case.  I.e. we cannot compare
  // against L"messagePort" since it has a capital 'P'.
  for (UINT i = 0; SUCCEEDED(hr) && i < count_names; ++i) {
    const wchar_t* name_begin = names[i];
    const wchar_t* name_end = name_begin + wcslen(name_begin);
    if (LowerCaseEqualsASCII(name_begin, name_end, "data")) {
      dispids[i] = DISPID_MESSAGE_EVENT_DATA;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "origin")) {
      dispids[i] = DISPID_MESSAGE_EVENT_ORIGIN;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "lasteventid")) {
      dispids[i] = DISPID_MESSAGE_EVENT_LAST_EVENT_ID;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "source")) {
      dispids[i] = DISPID_MESSAGE_EVENT_SOURCE;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "messageport")) {
      dispids[i] = DISPID_MESSAGE_EVENT_MESSAGE_PORT;
    } else if (LowerCaseEqualsASCII(name_begin, name_end, "type")) {
      dispids[i] = DISPID_MESSAGE_EVENT_TYPE;
    } else {
      if (basic_event_) {
        hr = basic_event_->GetIDsOfNames(IID_IDispatch, &names[i], 1, lcid,
                                         &dispids[i]);
      } else {
        hr = DISP_E_MEMBERNOTFOUND;
      }

      if (FAILED(hr)) {
        DLOG(WARNING) << "member not found: " << names[i]
                      << StringPrintf(L"0x%08X", hr);
      }
    }
  }
  return hr;
}

STDMETHODIMP ComMessageEvent::Invoke(DISPID dispid, REFIID iid, LCID lcid,
                                     WORD flags, DISPPARAMS* params,
                                     VARIANT* result, EXCEPINFO* excepinfo,
                                     UINT* arg_err) {
  HRESULT hr = DISP_E_MEMBERNOTFOUND;
  switch (dispid) {
    case DISPID_MESSAGE_EVENT_DATA:
      hr = GetStringProperty(flags, UTF8ToWide(message_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_ORIGIN:
      hr = GetStringProperty(flags, UTF8ToWide(origin_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_TYPE:
      hr = GetStringProperty(flags, UTF8ToWide(type_).c_str(), result);
      break;

    case DISPID_MESSAGE_EVENT_LAST_EVENT_ID:
      hr = GetStringProperty(flags, L"", result);
      break;

    case DISPID_MESSAGE_EVENT_SOURCE:
    case DISPID_MESSAGE_EVENT_MESSAGE_PORT:
      if (flags & DISPATCH_PROPERTYGET) {
        result->vt = VT_NULL;
        hr = S_OK;
      } else {
        hr = DISP_E_TYPEMISMATCH;
      }
      break;

    default:
      if (basic_event_) {
        hr = basic_event_->Invoke(dispid, iid, lcid, flags, params, result,
                                  excepinfo, arg_err);
      }
      break;
  }

  return hr;
}

HRESULT ComMessageEvent::GetStringProperty(WORD flags, const wchar_t* value,
                                           VARIANT* result) {
  if (!result)
    return E_INVALIDARG;

  HRESULT hr;
  if (flags & DISPATCH_PROPERTYGET) {
    result->vt = VT_BSTR;
    result->bstrVal = ::SysAllocString(value);
    hr = S_OK;
  } else {
    hr = DISP_E_TYPEMISMATCH;
  }
  return hr;
}
<|endoftext|>


<commit_before>#include <ciri/gfx/gl/GLShader.hpp>
#include <ciri/gfx/gl/GLConstantBuffer.hpp>
#include <ciri/util/File.hpp>

namespace ciri {
	GLShader::GLShader()
		: IShader(), _vsFile(""), _gsFile(""), _psFile(""), _vertexShader(0), _geometryShader(0), _pixelShader(0), _program(0) {
	}

	GLShader::~GLShader() {
	}

	void GLShader::addVertexShader( const char* filename ) {
		_vsFile = filename;
	}

	void GLShader::addGeometryShader( const char* filename ) {
		_gsFile = filename;
	}

	void GLShader::addPixelShader( const char* filename ) {
		_psFile = filename;
	}

	void GLShader::addInputElement( const VertexElement& element ) {
		_vertexDeclaration.add(element);
	}

	err::ErrorCode GLShader::addConstants( IConstantBuffer* buffer, const char* name, int shaderTypeFlags ) {
		if( nullptr == buffer || nullptr == name ) {
			return err::CIRI_INVALID_ARGUMENT;
		}

		if( !isValid() ) {
			return err::CIRI_SHADER_INVALID;
		}

		GLConstantBuffer* glBuffer = reinterpret_cast<GLConstantBuffer*>(buffer);

		const GLuint blockIndex = glGetUniformBlockIndex(_program, name);
		if( GL_INVALID_INDEX == blockIndex ) {
			return err::CIRI_UNKNOWN_ERROR;
		}

		_constantBuffers.push_back(glBuffer);

		glBindBufferBase(GL_UNIFORM_BUFFER, _constantBuffers.size()-1, glBuffer->getUbo());
		glUniformBlockBinding(_program, blockIndex, _constantBuffers.size()-1);

		return err::CIRI_OK;
	}

	err::ErrorCode GLShader::build() {
		// must have at least VS and PS
		if( _vsFile.empty() && _psFile.empty() ) {
			return err::CIRI_SHADER_INCOMPLETE;
		}

		const int ERROR_LOG_SIZE = 1024;

		GLint status = GL_TRUE;

		// build the vertex shader
		if( !_vsFile.empty() ) {
			File file(_vsFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _vsFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_vertexShader = glCreateShader(GL_VERTEX_SHADER);
			glShaderSource(_vertexShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_vertexShader);
			glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_vertexShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// build the geometry shader
		if( !_gsFile.empty() ) {
			File file(_gsFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _gsFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_geometryShader = glCreateShader(GL_GEOMETRY_SHADER);
			glShaderSource(_geometryShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_geometryShader);
			glGetShaderiv(_geometryShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_geometryShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// build the fragment shader
		if( !_psFile.empty() ) {
			File file(_psFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _psFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
			glShaderSource(_pixelShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_pixelShader);
			glGetShaderiv(_pixelShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_pixelShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// todo: link

		// create the program and link the shaders
		_program = glCreateProgram();
		if( !_vsFile.empty() ) {
			glAttachShader(_program, _vertexShader);
		}
		if( !_gsFile.empty() ) {
			glAttachShader(_program, _geometryShader);
		}
		if( !_psFile.empty() ) {
			glAttachShader(_program, _pixelShader);
		}
		glLinkProgram(_program);
		glGetProgramiv(_program, GL_LINK_STATUS, &status);
		if( status != GL_TRUE ) {
			GLchar log[ERROR_LOG_SIZE] = "";
			glGetProgramInfoLog(_program, ERROR_LOG_SIZE, 0, log);
			_lastError = err::getString(err::CIRI_SHADER_LINK_FAILED) + std::string(": ") + std::string(log);
			destroy();
			return err::CIRI_SHADER_LINK_FAILED;
		}

		return err::CIRI_OK;
	}

	err::ErrorCode GLShader::rebuild() {
		destroy();
		return build();
	}

	void GLShader::destroy() {
		if( _vertexShader != 0 ) {
			glDeleteShader(_vertexShader);
			_vertexShader = 0;
		}

		if( _geometryShader != 0 ) {
			glDeleteShader(_geometryShader);
			_geometryShader = 0;
		}

		if( _pixelShader != 0 ) {
			glDeleteShader(_pixelShader);
			_pixelShader = 0;
		}

		if( _program != 0 ) {
			glDeleteProgram(_program);
			_program = 0;
		}
	}

	const char* GLShader::getLastError() const {
		return _lastError.c_str();
	}

	bool GLShader::isValid() const {
		return (_vertexShader != 0) && (_pixelShader != 0);
	}

	GLuint GLShader::getVertexShader() const {
		return _vertexShader;
	}

	GLuint GLShader::getGeometryShader() const {
		return _geometryShader;
	}

	GLuint GLShader::getPixelShader() const {
		return _pixelShader;
	}

	GLuint GLShader::getProgram() const {
		return _program;
	}

	const VertexDeclaration& GLShader::getVertexDeclaration() const {
		return _vertexDeclaration;
	}
} // ciri<commit_msg>Removed unneeded todo.<commit_after>#include <ciri/gfx/gl/GLShader.hpp>
#include <ciri/gfx/gl/GLConstantBuffer.hpp>
#include <ciri/util/File.hpp>

namespace ciri {
	GLShader::GLShader()
		: IShader(), _vsFile(""), _gsFile(""), _psFile(""), _vertexShader(0), _geometryShader(0), _pixelShader(0), _program(0) {
	}

	GLShader::~GLShader() {
	}

	void GLShader::addVertexShader( const char* filename ) {
		_vsFile = filename;
	}

	void GLShader::addGeometryShader( const char* filename ) {
		_gsFile = filename;
	}

	void GLShader::addPixelShader( const char* filename ) {
		_psFile = filename;
	}

	void GLShader::addInputElement( const VertexElement& element ) {
		_vertexDeclaration.add(element);
	}

	err::ErrorCode GLShader::addConstants( IConstantBuffer* buffer, const char* name, int shaderTypeFlags ) {
		if( nullptr == buffer || nullptr == name ) {
			return err::CIRI_INVALID_ARGUMENT;
		}

		if( !isValid() ) {
			return err::CIRI_SHADER_INVALID;
		}

		GLConstantBuffer* glBuffer = reinterpret_cast<GLConstantBuffer*>(buffer);

		const GLuint blockIndex = glGetUniformBlockIndex(_program, name);
		if( GL_INVALID_INDEX == blockIndex ) {
			return err::CIRI_UNKNOWN_ERROR;
		}

		_constantBuffers.push_back(glBuffer);

		glBindBufferBase(GL_UNIFORM_BUFFER, _constantBuffers.size()-1, glBuffer->getUbo());
		glUniformBlockBinding(_program, blockIndex, _constantBuffers.size()-1);

		return err::CIRI_OK;
	}

	err::ErrorCode GLShader::build() {
		// must have at least VS and PS
		if( _vsFile.empty() && _psFile.empty() ) {
			return err::CIRI_SHADER_INCOMPLETE;
		}

		const int ERROR_LOG_SIZE = 1024;

		GLint status = GL_TRUE;

		// build the vertex shader
		if( !_vsFile.empty() ) {
			File file(_vsFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _vsFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_vertexShader = glCreateShader(GL_VERTEX_SHADER);
			glShaderSource(_vertexShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_vertexShader);
			glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_vertexShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// build the geometry shader
		if( !_gsFile.empty() ) {
			File file(_gsFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _gsFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_geometryShader = glCreateShader(GL_GEOMETRY_SHADER);
			glShaderSource(_geometryShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_geometryShader);
			glGetShaderiv(_geometryShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_geometryShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// build the fragment shader
		if( !_psFile.empty() ) {
			File file(_psFile.c_str());
			if( !file.isOpen() ) {
				_lastError = err::getString(err::CIRI_FILE_NOT_FOUND) + std::string(" (") + _psFile + std::string(")");;
				destroy();
				return err::CIRI_FILE_NOT_FOUND;
			}
			const std::string str = file.toString();
			const char* ptr = str.c_str();
			_pixelShader = glCreateShader(GL_FRAGMENT_SHADER);
			glShaderSource(_pixelShader, 1, (const GLchar**)&ptr, 0);
			glCompileShader(_pixelShader);
			glGetShaderiv(_pixelShader, GL_COMPILE_STATUS, &status);
			if( status != GL_TRUE ) {
				GLchar log[ERROR_LOG_SIZE] = "";
				glGetShaderInfoLog(_pixelShader, ERROR_LOG_SIZE, 0, log);
				_lastError = err::getString(err::CIRI_SHADER_COMPILE_FAILED) + std::string(": ") + std::string(log);
				destroy();
				return err::CIRI_SHADER_COMPILE_FAILED;
			}
		}

		// create the program and link the shaders
		_program = glCreateProgram();
		if( !_vsFile.empty() ) {
			glAttachShader(_program, _vertexShader);
		}
		if( !_gsFile.empty() ) {
			glAttachShader(_program, _geometryShader);
		}
		if( !_psFile.empty() ) {
			glAttachShader(_program, _pixelShader);
		}
		glLinkProgram(_program);
		glGetProgramiv(_program, GL_LINK_STATUS, &status);
		if( status != GL_TRUE ) {
			GLchar log[ERROR_LOG_SIZE] = "";
			glGetProgramInfoLog(_program, ERROR_LOG_SIZE, 0, log);
			_lastError = err::getString(err::CIRI_SHADER_LINK_FAILED) + std::string(": ") + std::string(log);
			destroy();
			return err::CIRI_SHADER_LINK_FAILED;
		}

		return err::CIRI_OK;
	}

	err::ErrorCode GLShader::rebuild() {
		destroy();
		return build();
	}

	void GLShader::destroy() {
		if( _vertexShader != 0 ) {
			glDeleteShader(_vertexShader);
			_vertexShader = 0;
		}

		if( _geometryShader != 0 ) {
			glDeleteShader(_geometryShader);
			_geometryShader = 0;
		}

		if( _pixelShader != 0 ) {
			glDeleteShader(_pixelShader);
			_pixelShader = 0;
		}

		if( _program != 0 ) {
			glDeleteProgram(_program);
			_program = 0;
		}
	}

	const char* GLShader::getLastError() const {
		return _lastError.c_str();
	}

	bool GLShader::isValid() const {
		return (_vertexShader != 0) && (_pixelShader != 0);
	}

	GLuint GLShader::getVertexShader() const {
		return _vertexShader;
	}

	GLuint GLShader::getGeometryShader() const {
		return _geometryShader;
	}

	GLuint GLShader::getPixelShader() const {
		return _pixelShader;
	}

	GLuint GLShader::getProgram() const {
		return _program;
	}

	const VertexDeclaration& GLShader::getVertexDeclaration() const {
		return _vertexDeclaration;
	}
} // ciri<|endoftext|>


<commit_before>#define CATCH_CONFIG_MAIN
#include "catch.hpp" //requires Catch
#include "zoo.h"

using namespace zoo;

TEST_CASE("Nodes can be created") {
	Tag node("node");
	REQUIRE(node.toString() == "<node></node>");
}

TEST_CASE("Documents can be created") {
	HTMLDocument doc;
	REQUIRE(doc.toString() == "<!DOCTYPE html>");
}

TEST_CASE("Nodes can be modified") {
	Tag p{ "p" };

	SECTION("Adding elements to nodes") {
		p.add(Text{ "Hello World" });
		REQUIRE(p.toString() == "
Hello World
");
		p.add(Text{ "Goodbye World" });
		REQUIRE(p.toString() == "
Hello WorldGoodbye World
");

		p.add(Tag{ "b" })->add(Text{ "bold text" });
		REQUIRE(p.toString() == "
Hello WorldGoodbye Worldbold text
");

	}

	SECTION("Adding attributes to node") {
		p.setAttribute("style", "color:blue;");
		REQUIRE(p.toString() == "

");
		p.setAttribute("class", "sometext");
		REQUIRE(p.toString() == "

");

	}
}

TEST_CASE("Documents can be modified") {
	HTMLDocument doc;
	doc.add(Tag{ "header",
		Tag{ "h1",
			Text{"Hello World"}}});

	doc.add(Tag{ "content",
		Tag{"b",
			Text{"this is bold text"}},
		Tag{"i",
			Text{"this is italic text"}}
	});
	REQUIRE(doc.toString() == "<!DOCTYPE html>
Hello World
<content>this is bold textthis is italic text</content>");

}

<commit_msg>Tests for new syntax and tags<commit_after>#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "zoo.h"

using namespace zoo;

TEST_CASE("Nodes can be created") {
	Tag node("node");
	REQUIRE(node.toString() == "<node></node>");
}

TEST_CASE("Documents can be created") {
	HTMLDocument doc;
	REQUIRE(doc.toString() == "<!DOCTYPE html>");
}

TEST_CASE("Nodes can be modified") {
	Tag p{ "p" };

	SECTION("Adding elements to nodes") {
		p.add(Text{ "Hello World" });
		REQUIRE(p.toString() == "
Hello World
");
		p.add(Text{ "Goodbye World" });
		REQUIRE(p.toString() == "
Hello WorldGoodbye World
");

		p.add(Tag{ "b" })->add(Text{ "bold text" });
		REQUIRE(p.toString() == "
Hello WorldGoodbye Worldbold text
");

	}

	SECTION("Adding attributes to node") {
		p.setAttribute("style", "color:blue;");
		REQUIRE(p.toString() == "

");
		p.setAttribute("class", "sometext");
		REQUIRE(p.toString() == "

");

	}
}

TEST_CASE("Documents can be modified") {
	HTMLDocument doc;
	doc.head(
		Tag( "title",
			Text("Hello World" )));
	doc.body(
		Div(
			H1(Text("Heading")),
			H2(Text("Subheading"))),
		Div(
			Div(Strong(Text("a list"))),
			Ul(
				Li(Text("item 1")),
				Li(Text("item 2")),
				Li(Text("item 3")))));

	REQUIRE(doc.toString() == "<!DOCTYPE html><title>Hello World</title>

Heading

Subheading

a list

item 1

item 2

item 3

");

}

<|endoftext|>


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

#include <media/MediaPlayer.h>
#include "PlayerWorker.h"
#include "MediaPlayerImpl.h"

#include <debug.h>
#include "audio/audio_manager.h"

namespace media {
MediaPlayerImpl::MediaPlayerImpl()
{
	mPlayerObserver = nullptr;
	mCurState = PLAYER_STATE_NONE;
	mBuffer = nullptr;
	mInputDataSource = nullptr;

	static int playerId = 1;
	mId = playerId++;
}

player_result_t MediaPlayerImpl::create()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer create\n");
	if (mCurState != PLAYER_STATE_NONE) {
		meddbg("MediaPlayer create fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.startWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	mCurState = PLAYER_STATE_IDLE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::destroy()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer destroy\n");
	if (mCurState != PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer destroy fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);
	mpw.stopWorker();

	PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
	pow.stopWorker();

	mCurState = PLAYER_STATE_NONE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::prepare()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer prepare\n");
	if (mCurState != PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer prepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	if (mInputDataSource == nullptr) {
		meddbg("MediaPlayer prepare fail : mInputDataSource is not set\n");
		return PLAYER_ERROR;
	}

	if (!mInputDataSource->open()) {
		meddbg("MediaPlayer prepare fail : file open fail\n");
		return PLAYER_ERROR;
	}

	if (set_audio_stream_out(mInputDataSource->getChannels(), mInputDataSource->getSampleRate(),
							 mInputDataSource->getPcmFormat()) != AUDIO_MANAGER_SUCCESS) {
		meddbg("MediaPlayer prepare fail : set_audio_stream_out fail\n");
		return PLAYER_ERROR;
	}

	mBufSize = get_output_frames_byte_size(get_output_frame_count());
	medvdbg("MediaPlayer mBuffer size : %d\n", mBufSize);

	mBuffer = new unsigned char[mBufSize];
	if (!mBuffer) {
		meddbg("MediaPlayer prepare fail : mBuffer allocation fail\n");
		return PLAYER_ERROR;
	}

	mCurState = PLAYER_STATE_READY;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::unprepare()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer unprepare\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer unprepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	if (mBuffer) {
		delete[] mBuffer;
		mBuffer = nullptr;
	}
	mBufSize = 0;

	if (reset_audio_stream_out() != AUDIO_MANAGER_SUCCESS) {
		meddbg("MediaPlayer unprepare fail : reset_audio_stream_out fail\n");
		return PLAYER_ERROR;
	}

	mInputDataSource->close();

	mCurState = PLAYER_STATE_IDLE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::start()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer start\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer unprepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::startPlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::stop()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer stop\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer stop fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::stopPlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::pause()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer pause\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer pause fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::pausePlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

int MediaPlayerImpl::getVolume()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer getVolume\n");
	if (mCurState == PLAYER_STATE_NONE) {
		meddbg("MediaPlayer getVolume fail : wrong state\n");
		return -1;
	}

	return get_output_audio_volume();
}

player_result_t MediaPlayerImpl::setVolume(int vol)
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setVolume\n");
	if (mCurState == PLAYER_STATE_NONE) {
		meddbg("MediaPlayer setVolume fail : wrong state\n");
		return PLAYER_ERROR;
	}

	if (vol < 0 || vol > 31) {
		meddbg("MediaPlayer setVolume fail : invalid argument. volume level should be 0(Min) ~ 31(Max)\n");
		return PLAYER_ERROR;
	}

	if (!set_output_audio_volume(vol)) {
		mCurVolume = vol;
		return PLAYER_OK;
	} else {
		return PLAYER_ERROR;
	}
}

player_result_t MediaPlayerImpl::setDataSource(std::unique_ptr<stream::InputDataSource> source)
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setDataSource\n");
	if (!source) {
		meddbg("MediaPlayer setDataSource fail : invalid argument. DataSource should not be nullptr\n");
		return PLAYER_ERROR;
	}

	mInputDataSource = std::move(source);
	return PLAYER_OK;
}

void MediaPlayerImpl::setObserver(std::shared_ptr<MediaPlayerObserverInterface> observer)
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setObserver\n");
	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);
	PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
	pow.startWorker();
	mPlayerObserver = observer;
}

player_state_t MediaPlayerImpl::getState()
{
	medvdbg("MediaPlayer getState\n");
	return mCurState;
}

player_result_t MediaPlayerImpl::seekTo(int msec)
{
	medvdbg("MediaPlayer seekTo %d msec\n", msec);
	// TODO : implementation of seekTo
	return PLAYER_OK;
}

void MediaPlayerImpl::notifySync()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	mSyncCv.notify_one();
}

void MediaPlayerImpl::notifyObserver(player_observer_command_t cmd)
{
	if (mPlayerObserver != nullptr) {
		PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
		switch (cmd) {
		case PLAYER_OBSERVER_COMMAND_STARTED:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackStarted, mPlayerObserver, mId);
			break;
		case PLAYER_OBSERVER_COMMAND_FINISHIED:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackFinished, mPlayerObserver, mId);
			break;
		case PLAYER_OBSERVER_COMMAND_ERROR:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackError, mPlayerObserver, mId);
			break;
		}
	}
}

int MediaPlayerImpl::playback(int size)
{
	return start_audio_stream_out(mBuffer, get_output_bytes_frame_count(size));
}

MediaPlayerImpl::~MediaPlayerImpl()
{
	player_result_t ret;

	if (mCurState > PLAYER_STATE_IDLE) {
		ret = unprepare();
		if (ret != PLAYER_OK) {
			meddbg("~MediaPlayer fail : unprepare fail\n");
		}
	}

	if (mCurState == PLAYER_STATE_IDLE) {
		ret = destroy();
		if (ret != PLAYER_OK) {
			meddbg("~MediaPlayer fail : destroy fail\n");
		}
	}
}
} // namespace media
<commit_msg>media: Use get_max_audio_volume instead of literal<commit_after>/* ****************************************************************
 *
 * Copyright 2018 Samsung Electronics All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************/

#include <media/MediaPlayer.h>
#include "PlayerWorker.h"
#include "MediaPlayerImpl.h"

#include <debug.h>
#include "audio/audio_manager.h"

namespace media {
MediaPlayerImpl::MediaPlayerImpl()
{
	mPlayerObserver = nullptr;
	mCurState = PLAYER_STATE_NONE;
	mBuffer = nullptr;
	mInputDataSource = nullptr;

	static int playerId = 1;
	mId = playerId++;
}

player_result_t MediaPlayerImpl::create()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer create\n");
	if (mCurState != PLAYER_STATE_NONE) {
		meddbg("MediaPlayer create fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.startWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	mCurState = PLAYER_STATE_IDLE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::destroy()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer destroy\n");
	if (mCurState != PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer destroy fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);
	mpw.stopWorker();

	PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
	pow.stopWorker();

	mCurState = PLAYER_STATE_NONE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::prepare()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer prepare\n");
	if (mCurState != PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer prepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	if (mInputDataSource == nullptr) {
		meddbg("MediaPlayer prepare fail : mInputDataSource is not set\n");
		return PLAYER_ERROR;
	}

	if (!mInputDataSource->open()) {
		meddbg("MediaPlayer prepare fail : file open fail\n");
		return PLAYER_ERROR;
	}

	if (set_audio_stream_out(mInputDataSource->getChannels(), mInputDataSource->getSampleRate(),
							 mInputDataSource->getPcmFormat()) != AUDIO_MANAGER_SUCCESS) {
		meddbg("MediaPlayer prepare fail : set_audio_stream_out fail\n");
		return PLAYER_ERROR;
	}

	mBufSize = get_output_frames_byte_size(get_output_frame_count());
	medvdbg("MediaPlayer mBuffer size : %d\n", mBufSize);

	mBuffer = new unsigned char[mBufSize];
	if (!mBuffer) {
		meddbg("MediaPlayer prepare fail : mBuffer allocation fail\n");
		return PLAYER_ERROR;
	}

	mCurState = PLAYER_STATE_READY;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::unprepare()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer unprepare\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer unprepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);

	if (mBuffer) {
		delete[] mBuffer;
		mBuffer = nullptr;
	}
	mBufSize = 0;

	if (reset_audio_stream_out() != AUDIO_MANAGER_SUCCESS) {
		meddbg("MediaPlayer unprepare fail : reset_audio_stream_out fail\n");
		return PLAYER_ERROR;
	}

	mInputDataSource->close();

	mCurState = PLAYER_STATE_IDLE;
	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::start()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer start\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer unprepare fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::startPlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::stop()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer stop\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer stop fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::stopPlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

player_result_t MediaPlayerImpl::pause()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer pause\n");
	if (mCurState == PLAYER_STATE_NONE || mCurState == PLAYER_STATE_IDLE) {
		meddbg("MediaPlayer pause fail : wrong state\n");
		return PLAYER_ERROR;
	}

	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&PlayerWorker::pausePlayer, &mpw, shared_from_this());

	return PLAYER_OK;
}

int MediaPlayerImpl::getVolume()
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer getVolume\n");
	if (mCurState == PLAYER_STATE_NONE) {
		meddbg("MediaPlayer getVolume fail : wrong state\n");
		return -1;
	}

	return get_output_audio_volume();
}

player_result_t MediaPlayerImpl::setVolume(int vol)
{
	int vol_max = get_max_audio_volume();
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setVolume\n");
	if (mCurState == PLAYER_STATE_NONE) {
		meddbg("MediaPlayer setVolume fail : wrong state\n");
		return PLAYER_ERROR;
	}

	if (vol < 0 || vol > vol_max) {
		meddbg("MediaPlayer setVolume fail : invalid argument. volume level should be 0(Min) ~ %d(Max)\n", vol_max);
		return PLAYER_ERROR;
	}

	if (!set_output_audio_volume(vol)) {
		mCurVolume = vol;
		return PLAYER_OK;
	} else {
		return PLAYER_ERROR;
	}
}

player_result_t MediaPlayerImpl::setDataSource(std::unique_ptr<stream::InputDataSource> source)
{
	std::lock_guard<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setDataSource\n");
	if (!source) {
		meddbg("MediaPlayer setDataSource fail : invalid argument. DataSource should not be nullptr\n");
		return PLAYER_ERROR;
	}

	mInputDataSource = std::move(source);
	return PLAYER_OK;
}

void MediaPlayerImpl::setObserver(std::shared_ptr<MediaPlayerObserverInterface> observer)
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	medvdbg("MediaPlayer setObserver\n");
	PlayerWorker& mpw = PlayerWorker::getWorker();
	mpw.getQueue().enQueue(&MediaPlayerImpl::notifySync, shared_from_this());
	mSyncCv.wait(lock);
	PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
	pow.startWorker();
	mPlayerObserver = observer;
}

player_state_t MediaPlayerImpl::getState()
{
	medvdbg("MediaPlayer getState\n");
	return mCurState;
}

player_result_t MediaPlayerImpl::seekTo(int msec)
{
	medvdbg("MediaPlayer seekTo %d msec\n", msec);
	// TODO : implementation of seekTo
	return PLAYER_OK;
}

void MediaPlayerImpl::notifySync()
{
	std::unique_lock<std::mutex> lock(mCmdMtx);
	mSyncCv.notify_one();
}

void MediaPlayerImpl::notifyObserver(player_observer_command_t cmd)
{
	if (mPlayerObserver != nullptr) {
		PlayerObserverWorker& pow = PlayerObserverWorker::getWorker();
		switch (cmd) {
		case PLAYER_OBSERVER_COMMAND_STARTED:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackStarted, mPlayerObserver, mId);
			break;
		case PLAYER_OBSERVER_COMMAND_FINISHIED:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackFinished, mPlayerObserver, mId);
			break;
		case PLAYER_OBSERVER_COMMAND_ERROR:
			pow.getQueue().enQueue(&MediaPlayerObserverInterface::onPlaybackError, mPlayerObserver, mId);
			break;
		}
	}
}

int MediaPlayerImpl::playback(int size)
{
	return start_audio_stream_out(mBuffer, get_output_bytes_frame_count(size));
}

MediaPlayerImpl::~MediaPlayerImpl()
{
	player_result_t ret;

	if (mCurState > PLAYER_STATE_IDLE) {
		ret = unprepare();
		if (ret != PLAYER_OK) {
			meddbg("~MediaPlayer fail : unprepare fail\n");
		}
	}

	if (mCurState == PLAYER_STATE_IDLE) {
		ret = destroy();
		if (ret != PLAYER_OK) {
			meddbg("~MediaPlayer fail : destroy fail\n");
		}
	}
}
} // namespace media
<|endoftext|>


<commit_before>// Copyright (c) 2009-2017 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: askeys

#include "FIREEnergyMinimizer.h"

using namespace std;
namespace py = pybind11;

/*! \file FIREEnergyMinimizer.h
    \brief Contains code for the FIREEnergyMinimizer class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param dt maximum step size

    \post The method is constructed with the given particle data and a NULL profiler.
*/
FIREEnergyMinimizer::FIREEnergyMinimizer(std::shared_ptr<SystemDefinition> sysdef, Scalar dt)
    :   IntegratorTwoStep(sysdef, dt),
        m_nmin(5),
        m_finc(Scalar(1.1)),
        m_fdec(Scalar(0.5)),
        m_alpha_start(Scalar(0.1)),
        m_falpha(Scalar(0.99)),
        m_ftol(Scalar(1e-1)),
        m_wtol(Scalar(1e-1)),
        m_etol(Scalar(1e-3)),
        m_deltaT_max(dt),
        m_deltaT_set(dt/Scalar(10.0)),
        m_run_minsteps(10)
    {
    m_exec_conf->msg->notice(5) << "Constructing FIREEnergyMinimizer" << endl;

    // sanity check
    assert(m_sysdef);
    assert(m_pdata);
    reset();
    }

FIREEnergyMinimizer::~FIREEnergyMinimizer()
    {
    m_exec_conf->msg->notice(5) << "Destroying FIREEnergyMinimizer" << endl;
    }

/*! \param finc is the new fractional increase to set
*/
void FIREEnergyMinimizer::setFinc(Scalar finc)
    {
    if (!(finc > 1.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: fractional increase in timestep should be > 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_finc = finc;
    }

/*! \param fdec is the new fractional decrease to set
*/
void FIREEnergyMinimizer::setFdec(Scalar fdec)
    {
    if (!(fdec < 1.0 && fdec >= 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: fractional decrease in timestep should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_fdec = fdec;
    }

/*! \param alpha_start is the new initial coupling parameter to set

The coupling parameter "alpha" enters into the equations of motion as
v = v*(1-alpha) + alpha*(f_unit*|v|).  Thus, the stronger the coupling, the
more important the "f dot v" term.  When the search direction is successful
for > Nmin steps alpha is decreased by falpha.
*/
void FIREEnergyMinimizer::setAlphaStart(Scalar alpha_start)
    {
    if (!(alpha_start < 1.0 && alpha_start > 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: alpha_start should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_alpha_start = alpha_start;
    }

/*! \param falpha is the fractional decrease in alpha upon finding a valid search direction

The coupling parameter "alpha" enters into the equations of motion as
v = v*(1-alpha) + alpha*(f_unit*|v|).  Thus, the stronger the coupling, the
more important the "f dot v" term.  When the search direction is successful
for > Nmin steps alpha is decreased by falpha.
*/
void FIREEnergyMinimizer::setFalpha(Scalar falpha)
    {
    if (!(falpha < 1.0 && falpha > 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: falpha should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_falpha = falpha;
    }

void FIREEnergyMinimizer::reset()
    {
    m_converged = false;
    m_n_since_negative = m_nmin+1;
    m_n_since_start = 0;
    m_alpha = m_alpha_start;
    m_was_reset = true;

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);

    unsigned int n = m_pdata->getN();
    for (unsigned int i=0; i<n; i++)
        {
        h_vel.data[i].x = Scalar(0.0);
        h_vel.data[i].y = Scalar(0.0);
        h_vel.data[i].z = Scalar(0.0);

        h_angmom.data[i] = make_scalar4(0,0,0,0);
        }

    setDeltaT(m_deltaT_set);
    }

/*! \param timesteps is the current timestep
*/
void FIREEnergyMinimizer::update(unsigned int timesteps)
    {
    if (m_converged)
        return;

    IntegratorTwoStep::update(timesteps);

    Scalar Pt(0.0); //translational power
    Scalar Pr(0.0); //rotational power
    Scalar vnorm(0.0);
    Scalar fnorm(0.0);
    Scalar tnorm(0.0);
    Scalar wnorm(0.0);

    // Calculate the per-particle potential energy over particles in the group
    Scalar energy(0.0);

    unsigned int total_group_size = 0;

    {
    const GPUArray< Scalar4 >& net_force = m_pdata->getNetForce();
    ArrayHandle<Scalar4> h_net_force(net_force, access_location::host, access_mode::read);

    // total potential energy
    double pe_total = 0.0;

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        total_group_size += group_size;

        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            pe_total += (double)h_net_force.data[j].w;
            }
        }

    energy = pe_total/Scalar(total_group_size);
    }

    if (m_was_reset)
        {
        m_was_reset = false;
        m_old_energy = energy + Scalar(100000)*m_etol;
        }

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar3> h_accel(m_pdata->getAccelerations(), access_location::host, access_mode::readwrite);

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            Pt += h_accel.data[j].x*h_vel.data[j].x + h_accel.data[j].y*h_vel.data[j].y + h_accel.data[j].z*h_vel.data[j].z;
            fnorm += h_accel.data[j].x*h_accel.data[j].x+h_accel.data[j].y*h_accel.data[j].y+h_accel.data[j].z*h_accel.data[j].z;
            vnorm += h_vel.data[j].x*h_vel.data[j].x+ h_vel.data[j].y*h_vel.data[j].y + h_vel.data[j].z*h_vel.data[j].z;
            }

        if ((*method)->getAnisotropic())
            {
            ArrayHandle<Scalar4> h_net_torque(m_pdata->getNetTorqueArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::read);

            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);

                vec3<Scalar> t(h_net_torque.data[j]);
                quat<Scalar> p(h_angmom.data[j]);
                quat<Scalar> q(h_orientation.data[j]);

                // s is the pure imaginary quaternion with im. part equal to true angular velocity
                vec3<Scalar> s;
                s = (Scalar(1./2.) * conj(q) * p).v;

                // rotational power = torque * angvel
                Pr += dot(t,s);
                tnorm += dot(t,t);
                wnorm += dot(s,s);
                }
            }
        }

    fnorm = sqrt(fnorm);
    vnorm = sqrt(vnorm);

    tnorm = sqrt(tnorm);
    wnorm = sqrt(wnorm);

    unsigned int ndof = m_sysdef->getNDimensions()*total_group_size;
    if ((fnorm/sqrt(Scalar(ndof)) < m_ftol && wnorm/sqrt(Scalar(ndof)) < m_wtol  && fabs(energy-m_old_energy) < m_etol) && m_n_since_start >= m_run_minsteps)
        {
        m_converged = true;
        return;
        }

    Scalar invfnorm = 1.0/fnorm;

    Scalar factor_r = 0.0;

    if (fabs(tnorm) > EPSILON)
        factor_r = m_alpha * wnorm / tnorm;
    else
        factor_r = 1.0;

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            h_vel.data[j].x = h_vel.data[j].x*(1.0-m_alpha) + m_alpha*h_accel.data[j].x*invfnorm*vnorm;
            h_vel.data[j].y = h_vel.data[j].y*(1.0-m_alpha) + m_alpha*h_accel.data[j].y*invfnorm*vnorm;
            h_vel.data[j].z = h_vel.data[j].z*(1.0-m_alpha) + m_alpha*h_accel.data[j].z*invfnorm*vnorm;
            }

        if ((*method)->getAnisotropic())
            {
            ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);
            ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_net_torque(m_pdata->getNetTorqueArray(), access_location::host, access_mode::read);

            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);
                vec3<Scalar> t(h_net_torque.data[j]);
                quat<Scalar> p(h_angmom.data[j]);
                quat<Scalar> q(h_orientation.data[j]);

                // update angular momentum
                p = p*Scalar(1.0-m_alpha) + Scalar(2.0)*q*t*factor_r;
                h_angmom.data[j] = quat_to_scalar4(p);
                }
            }
        }

    // A simply naive measure is to sum up the power coming from translational and rotational motions,
    // more sophisticated measure can be devised later
    Scalar P = Pt + Pr;

    if (P > Scalar(0.0))
        {
        m_n_since_negative++;
        if (m_n_since_negative > m_nmin)
            {
            IntegratorTwoStep::setDeltaT(std::min(m_deltaT*m_finc, m_deltaT_max));
            m_alpha *= m_falpha;
            }
        }
    else if (P <= Scalar(0.0))
        {
        IntegratorTwoStep::setDeltaT(m_deltaT*m_fdec);
        m_alpha = m_alpha_start;
        m_n_since_negative = 0;

        for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
            {
            std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
            unsigned int group_size = current_group->getIndexArray().getNumElements();
            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);
                h_vel.data[j].x = Scalar(0.0);
                h_vel.data[j].y = Scalar(0.0);
                h_vel.data[j].z = Scalar(0.0);
                }

            if ((*method)->getAnisotropic())
                {
                ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);
                for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                    {
                    unsigned int j = current_group->getMemberIndex(group_idx);
                    h_angmom.data[j] = make_scalar4(0,0,0,0);
                    }
                }

            }
        }
    m_n_since_start++;
    m_old_energy = energy;

    }

void export_FIREEnergyMinimizer(py::module& m)
    {
    py::class_<FIREEnergyMinimizer, std::shared_ptr<FIREEnergyMinimizer> >(m, "FIREEnergyMinimizer", py::base<IntegratorTwoStep>())
        .def(py::init< std::shared_ptr<SystemDefinition>, Scalar>())
        .def("reset", &FIREEnergyMinimizer::reset)
        .def("setDeltaT", &FIREEnergyMinimizer::setDeltaT)
        .def("hasConverged", &FIREEnergyMinimizer::hasConverged)
        .def("setNmin", &FIREEnergyMinimizer::setNmin)
        .def("setFinc", &FIREEnergyMinimizer::setFinc)
        .def("setFdec", &FIREEnergyMinimizer::setFdec)
        .def("setAlphaStart", &FIREEnergyMinimizer::setAlphaStart)
        .def("setFalpha", &FIREEnergyMinimizer::setFalpha)
        .def("setFtol", &FIREEnergyMinimizer::setFtol)
        .def("setEtol", &FIREEnergyMinimizer::setEtol)
        .def("setMinSteps", &FIREEnergyMinimizer::setMinSteps)
        ;
    }
<commit_msg>also reset accelerations<commit_after>// Copyright (c) 2009-2017 The Regents of the University of Michigan
// This file is part of the HOOMD-blue project, released under the BSD 3-Clause License.

// Maintainer: askeys

#include "FIREEnergyMinimizer.h"

using namespace std;
namespace py = pybind11;

/*! \file FIREEnergyMinimizer.h
    \brief Contains code for the FIREEnergyMinimizer class
*/

/*! \param sysdef SystemDefinition this method will act on. Must not be NULL.
    \param dt maximum step size

    \post The method is constructed with the given particle data and a NULL profiler.
*/
FIREEnergyMinimizer::FIREEnergyMinimizer(std::shared_ptr<SystemDefinition> sysdef, Scalar dt)
    :   IntegratorTwoStep(sysdef, dt),
        m_nmin(5),
        m_finc(Scalar(1.1)),
        m_fdec(Scalar(0.5)),
        m_alpha_start(Scalar(0.1)),
        m_falpha(Scalar(0.99)),
        m_ftol(Scalar(1e-1)),
        m_wtol(Scalar(1e-1)),
        m_etol(Scalar(1e-3)),
        m_deltaT_max(dt),
        m_deltaT_set(dt/Scalar(10.0)),
        m_run_minsteps(10)
    {
    m_exec_conf->msg->notice(5) << "Constructing FIREEnergyMinimizer" << endl;

    // sanity check
    assert(m_sysdef);
    assert(m_pdata);
    reset();
    }

FIREEnergyMinimizer::~FIREEnergyMinimizer()
    {
    m_exec_conf->msg->notice(5) << "Destroying FIREEnergyMinimizer" << endl;
    }

/*! \param finc is the new fractional increase to set
*/
void FIREEnergyMinimizer::setFinc(Scalar finc)
    {
    if (!(finc > 1.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: fractional increase in timestep should be > 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_finc = finc;
    }

/*! \param fdec is the new fractional decrease to set
*/
void FIREEnergyMinimizer::setFdec(Scalar fdec)
    {
    if (!(fdec < 1.0 && fdec >= 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: fractional decrease in timestep should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_fdec = fdec;
    }

/*! \param alpha_start is the new initial coupling parameter to set

The coupling parameter "alpha" enters into the equations of motion as
v = v*(1-alpha) + alpha*(f_unit*|v|).  Thus, the stronger the coupling, the
more important the "f dot v" term.  When the search direction is successful
for > Nmin steps alpha is decreased by falpha.
*/
void FIREEnergyMinimizer::setAlphaStart(Scalar alpha_start)
    {
    if (!(alpha_start < 1.0 && alpha_start > 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: alpha_start should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_alpha_start = alpha_start;
    }

/*! \param falpha is the fractional decrease in alpha upon finding a valid search direction

The coupling parameter "alpha" enters into the equations of motion as
v = v*(1-alpha) + alpha*(f_unit*|v|).  Thus, the stronger the coupling, the
more important the "f dot v" term.  When the search direction is successful
for > Nmin steps alpha is decreased by falpha.
*/
void FIREEnergyMinimizer::setFalpha(Scalar falpha)
    {
    if (!(falpha < 1.0 && falpha > 0.0))
        {
        m_exec_conf->msg->error() << "integrate.mode_minimize_fire: falpha should be between 0 and 1" << endl;
        throw runtime_error("Error setting parameters for FIREEnergyMinimizer");
        }
        m_falpha = falpha;
    }

void FIREEnergyMinimizer::reset()
    {
    m_converged = false;
    m_n_since_negative = m_nmin+1;
    m_n_since_start = 0;
    m_alpha = m_alpha_start;
    m_was_reset = true;

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar3> h_accel(m_pdata->getAccelerations(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);

    unsigned int n = m_pdata->getN();
    for (unsigned int i=0; i<n; i++)
        {
        h_vel.data[i].x = Scalar(0.0);
        h_vel.data[i].y = Scalar(0.0);
        h_vel.data[i].z = Scalar(0.0);
        h_accel.data[i] = make_scalar3(0,0,0);
        h_angmom.data[i] = make_scalar4(0,0,0,0);
        }

    setDeltaT(m_deltaT_set);
    }

/*! \param timesteps is the current timestep
*/
void FIREEnergyMinimizer::update(unsigned int timesteps)
    {
    if (m_converged)
        return;

    IntegratorTwoStep::update(timesteps);

    Scalar Pt(0.0); //translational power
    Scalar Pr(0.0); //rotational power
    Scalar vnorm(0.0);
    Scalar fnorm(0.0);
    Scalar tnorm(0.0);
    Scalar wnorm(0.0);

    // Calculate the per-particle potential energy over particles in the group
    Scalar energy(0.0);

    unsigned int total_group_size = 0;

    {
    const GPUArray< Scalar4 >& net_force = m_pdata->getNetForce();
    ArrayHandle<Scalar4> h_net_force(net_force, access_location::host, access_mode::read);

    // total potential energy
    double pe_total = 0.0;

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        total_group_size += group_size;

        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            pe_total += (double)h_net_force.data[j].w;
            }
        }

    energy = pe_total/Scalar(total_group_size);
    }

    if (m_was_reset)
        {
        m_was_reset = false;
        m_old_energy = energy + Scalar(100000)*m_etol;
        }

    ArrayHandle<Scalar4> h_vel(m_pdata->getVelocities(), access_location::host, access_mode::readwrite);
    ArrayHandle<Scalar3> h_accel(m_pdata->getAccelerations(), access_location::host, access_mode::readwrite);

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            Pt += h_accel.data[j].x*h_vel.data[j].x + h_accel.data[j].y*h_vel.data[j].y + h_accel.data[j].z*h_vel.data[j].z;
            fnorm += h_accel.data[j].x*h_accel.data[j].x+h_accel.data[j].y*h_accel.data[j].y+h_accel.data[j].z*h_accel.data[j].z;
            vnorm += h_vel.data[j].x*h_vel.data[j].x+ h_vel.data[j].y*h_vel.data[j].y + h_vel.data[j].z*h_vel.data[j].z;
            }

        if ((*method)->getAnisotropic())
            {
            ArrayHandle<Scalar4> h_net_torque(m_pdata->getNetTorqueArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::read);

            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);

                vec3<Scalar> t(h_net_torque.data[j]);
                quat<Scalar> p(h_angmom.data[j]);
                quat<Scalar> q(h_orientation.data[j]);

                // s is the pure imaginary quaternion with im. part equal to true angular velocity
                vec3<Scalar> s;
                s = (Scalar(1./2.) * conj(q) * p).v;

                // rotational power = torque * angvel
                Pr += dot(t,s);
                tnorm += dot(t,t);
                wnorm += dot(s,s);
                }
            }
        }

    fnorm = sqrt(fnorm);
    vnorm = sqrt(vnorm);

    tnorm = sqrt(tnorm);
    wnorm = sqrt(wnorm);

    unsigned int ndof = m_sysdef->getNDimensions()*total_group_size;
    if ((fnorm/sqrt(Scalar(ndof)) < m_ftol && wnorm/sqrt(Scalar(ndof)) < m_wtol  && fabs(energy-m_old_energy) < m_etol) && m_n_since_start >= m_run_minsteps)
        {
        m_converged = true;
        return;
        }

    Scalar invfnorm = 1.0/fnorm;

    Scalar factor_r = 0.0;

    if (fabs(tnorm) > EPSILON)
        factor_r = m_alpha * wnorm / tnorm;
    else
        factor_r = 1.0;

    for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
        {
        std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
        unsigned int group_size = current_group->getIndexArray().getNumElements();
        for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
            {
            unsigned int j = current_group->getMemberIndex(group_idx);
            h_vel.data[j].x = h_vel.data[j].x*(1.0-m_alpha) + m_alpha*h_accel.data[j].x*invfnorm*vnorm;
            h_vel.data[j].y = h_vel.data[j].y*(1.0-m_alpha) + m_alpha*h_accel.data[j].y*invfnorm*vnorm;
            h_vel.data[j].z = h_vel.data[j].z*(1.0-m_alpha) + m_alpha*h_accel.data[j].z*invfnorm*vnorm;
            }

        if ((*method)->getAnisotropic())
            {
            ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);
            ArrayHandle<Scalar4> h_orientation(m_pdata->getOrientationArray(), access_location::host, access_mode::read);
            ArrayHandle<Scalar4> h_net_torque(m_pdata->getNetTorqueArray(), access_location::host, access_mode::read);

            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);
                vec3<Scalar> t(h_net_torque.data[j]);
                quat<Scalar> p(h_angmom.data[j]);
                quat<Scalar> q(h_orientation.data[j]);

                // update angular momentum
                p = p*Scalar(1.0-m_alpha) + Scalar(2.0)*q*t*factor_r;
                h_angmom.data[j] = quat_to_scalar4(p);
                }
            }
        }

    // A simply naive measure is to sum up the power coming from translational and rotational motions,
    // more sophisticated measure can be devised later
    Scalar P = Pt + Pr;

    if (P > Scalar(0.0))
        {
        m_n_since_negative++;
        if (m_n_since_negative > m_nmin)
            {
            IntegratorTwoStep::setDeltaT(std::min(m_deltaT*m_finc, m_deltaT_max));
            m_alpha *= m_falpha;
            }
        }
    else if (P <= Scalar(0.0))
        {
        IntegratorTwoStep::setDeltaT(m_deltaT*m_fdec);
        m_alpha = m_alpha_start;
        m_n_since_negative = 0;

        for (auto method = m_methods.begin(); method != m_methods.end(); ++method)
            {
            std::shared_ptr<ParticleGroup> current_group = (*method)->getGroup();
            unsigned int group_size = current_group->getIndexArray().getNumElements();
            for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                {
                unsigned int j = current_group->getMemberIndex(group_idx);
                h_vel.data[j].x = Scalar(0.0);
                h_vel.data[j].y = Scalar(0.0);
                h_vel.data[j].z = Scalar(0.0);
                }

            if ((*method)->getAnisotropic())
                {
                ArrayHandle<Scalar4> h_angmom(m_pdata->getAngularMomentumArray(), access_location::host, access_mode::readwrite);
                for (unsigned int group_idx = 0; group_idx < group_size; group_idx++)
                    {
                    unsigned int j = current_group->getMemberIndex(group_idx);
                    h_angmom.data[j] = make_scalar4(0,0,0,0);
                    }
                }

            }
        }
    m_n_since_start++;
    m_old_energy = energy;

    }

void export_FIREEnergyMinimizer(py::module& m)
    {
    py::class_<FIREEnergyMinimizer, std::shared_ptr<FIREEnergyMinimizer> >(m, "FIREEnergyMinimizer", py::base<IntegratorTwoStep>())
        .def(py::init< std::shared_ptr<SystemDefinition>, Scalar>())
        .def("reset", &FIREEnergyMinimizer::reset)
        .def("setDeltaT", &FIREEnergyMinimizer::setDeltaT)
        .def("hasConverged", &FIREEnergyMinimizer::hasConverged)
        .def("setNmin", &FIREEnergyMinimizer::setNmin)
        .def("setFinc", &FIREEnergyMinimizer::setFinc)
        .def("setFdec", &FIREEnergyMinimizer::setFdec)
        .def("setAlphaStart", &FIREEnergyMinimizer::setAlphaStart)
        .def("setFalpha", &FIREEnergyMinimizer::setFalpha)
        .def("setFtol", &FIREEnergyMinimizer::setFtol)
        .def("setEtol", &FIREEnergyMinimizer::setEtol)
        .def("setMinSteps", &FIREEnergyMinimizer::setMinSteps)
        ;
    }
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2016

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

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

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

#include "handle_branching.h"
#include "flowcontrolinstructions.h"

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <fstream>

#include <iostream>
#include <cassert>

using namespace std;
using namespace llvm;
using namespace cocl::flowcontrol;

namespace cocl {

vector<unique_ptr<Block> > blocks; // doesnt include the root. I guess. ???
map<BasicBlock *, Block *> blockByBasicBlock;

template<typename T>
void vectorErase(vector<T> &targetvector, T &element) {
    int i = 0;
    bool found = false;
    for(auto it=targetvector.begin(); it != targetvector.end(); it++) {
        const T &thiselement = *it;
        if(thiselement == element) {
            found = true;
            break;
        }
        i++;
    }
    if(found) {
        targetvector.erase(targetvector.begin() + i);
        return;
    }
    throw runtime_error("couldnt find element to erease");
}

void eraseBlock(Block *block) {
    int id = 0;
    bool found = false;
    for(auto it=blocks.begin(); it != blocks.end(); it++) {
        Block *thisblock = it->get();
        if(thisblock == block) {
            found = true;
            break;
        }
        id++;
    }
    if(found) {
        blocks.erase(blocks.begin() + id);
        return;
    }
    throw runtime_error("couldnt find block to erease");
}

void swapChildInParents(Block *oldChild, Block *newChild) {
    for(auto it=oldChild->incoming.begin(); it != oldChild->incoming.end(); it++) {
        Block *incoming = *it;
        newChild->incoming.push_back(incoming);
        incoming->replaceChildOrSuccessor(oldChild, newChild);
    }
    oldChild->incoming.clear();
}

// void swapParentInChildren(Block *oldParent, Block *newParent) {
//     if(oldParent->numSuccessors() != 1) {
//         throw runtime_error("not yet implemented: more than one child");
//     }
//     Block *successor = oldParent->getSuccessor(0);
//     successor->replaceIncoming(oldParent, newParent);
// }

bool mergeSequences(Block *root) {
    // basically we look for any block with one single incoming, and that incoming is a basicblockblock
    bool didAMerge = true;
    int numChanges = 0;
    while(didAMerge) {
        didAMerge = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(block->incoming.size() != 1) {
                continue;
            }
            // cout << "block " << block->id << " has only one incoming" << endl;
            Block *parent = block->incoming[0];
            if(parent->numSuccessors() != 1) {
                continue;
            }
            if(block->numSuccessors() != 1) {
                continue;
            }
            if(parent->getSuccessor(0) != block) {
                continue;
            }
            // so merge...
            cout << "merging ... " << block->id << ", " << parent->id << endl;
            unique_ptr<Sequence> sequence(new Sequence());
            sequence->children.push_back(parent);
            sequence->children.push_back(block);
            swapChildInParents(parent, sequence.get());
            parent->incoming.push_back(sequence.get());
            parent->replaceSuccessor(block, 0);
            block->incoming.clear();
            block->incoming.push_back(sequence.get());
            Block *blockSuccessor = block->getSuccessor(0);
            blockSuccessor->replaceIncoming(block, sequence.get());
            sequence->next = blockSuccessor;
            block->replaceSuccessor(blockSuccessor, 0);
            blocks.push_back(std::move(sequence));
            didAMerge = true;
            numChanges++;
            return true;
        }
    }
    return numChanges > 0;
}
bool huntTrueIfs(Block *block) {
    // an 'if' looks like (we're handling only the 'true' case ):
    // (something)
    // ConditionalBlock
    // true: BlockA => BlockB
    // false: BlockB (constraint: 1 successor exactly)
    int numChanges = 0;
    bool foundFor = true;
    while(foundFor) {
        foundFor = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(ConditionalBranch *cond = dynamic_cast<ConditionalBranch *>(block)) {
                Block *trueChild = cond->trueNext;
                Block *falseChild = cond->falseNext;
                if(trueChild->numSuccessors() != 1) {
                    cout << "truechild numsuccessors not 1" << endl;
                    continue;
                }
                if(trueChild->incoming.size() != 1) {
                    cout << "truechild incoming not 1" << endl;
                    continue;
                }
                if(trueChild->getSuccessor(0) != falseChild) {
                    cout << "truechild successor not falsechild" << endl;
                    continue;
                }
                // if(falseChild->incoming.size() != 1) {
                //     continue;
                // }
                // if(falseChild->numSuccessors() != 1) {
                //     continue;
                // }
                // if(falseChild->getSuccessor(0) == trueChild) {
                //     continue;
                // }
                // if(falseChild->getSuccessor(0) == cond) {
                //     continue;
                // }
                cout << "found a true-if" << endl;
                cout << "cond: " << cond->id << endl;
                cout << "true: " << trueChild->id << endl;
                cout << "false: " << falseChild->id << endl;

                unique_ptr<If> ifBlock(new If());
                swapChildInParents(cond, ifBlock.get());
                ifBlock->condition = cond->condition;
                ifBlock->trueBlock = trueChild;
                ifBlock->falseBlock = 0;
                ifBlock->next = falseChild;

                trueChild->incoming.clear();
                trueChild->incoming.push_back(ifBlock.get());
                trueChild->replaceSuccessor(falseChild, 0);

                falseChild->replaceIncoming(trueChild, ifBlock.get());
                falseChild->removeIncoming(cond);
                // falseChild->incoming.clear();
                // falseChild->incoming.push_back(ifBlock.get());

                // falseChild has one successor
                // we need to swap its successor to be linked into ifBlock
                // Block *successor = falseChild->getSuccessor(0);
                // successor->replaceIncoming(falseChild, ifBlock.get());
                // successor->removeIncoming(trueChild);

                // falseChild->replaceSuccessor
                eraseBlock(cond);
                blocks.push_back(std::move(ifBlock));
                foundFor = true;
                numChanges++;
                return true;
            }
        }
    }
    return numChanges > 0;
}
void huntWhiles(Block *block) {
    // BlockA
    // ConditonalBlock
    // true: BlockA
    // false: BlockB
}
bool huntFors(Block *block) {
    //BlockA
    //ConditionalBlock
    // true: BlockB => blockA
    // false: blockC
    // blockC
    int numChanges = 0;
    bool foundFor = true;
    while(foundFor) {
        foundFor = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(ConditionalBranch *cond = dynamic_cast<ConditionalBranch *>(block)) {
                if(cond->incoming.size() != 1) {
                    continue;
                }
                Block *parent = cond->incoming[0];
                Block *child = cond->trueNext;
                if(child->incoming.size() != 1) {
                    continue;
                }
                if(child->numSuccessors() != 1) {
                    continue;
                }
                if(child->getSuccessor(0) != parent) {
                    continue;
                }
                cout << "found a for :-)" << endl;
                cout << "pre: " << parent->id << endl;
                cout << "condiiotn: " << block->id << endl;
                cout << "body: " << child->id << endl;
                cout << "next: " << cond->falseNext->id << endl;

                unique_ptr<For> forBlock(new For());
                // swapChildInParents(parent, forBlock.get());
                // vectorErase(forBlock->incoming, child);
                for(auto parentincit = parent->incoming.begin(); parentincit != parent->incoming.end(); parentincit++) {
                    Block *parentinc = *parentincit;
                    if(parentinc != child) {
                        cout << "parentinc " << parentinc->id << endl;
                        forBlock->incoming.push_back(parentinc);
                        parentinc->replaceSuccessor(parent, forBlock.get());
                    }
                }
                parent->incoming.clear();
                parent->replaceSuccessor(cond, 0);
                child->replaceSuccessor(parent, 0);
                child->incoming.clear();
                forBlock->next = cond->falseNext;
                forBlock->preBlock = parent;
                forBlock->bodyBlock = child;
                forBlock->condition = cond->condition;
                cond->falseNext->replaceIncoming(cond, forBlock.get());
                eraseBlock(cond);
                blocks.push_back(std::move(forBlock));
                foundFor = true;
                numChanges++;
            }
        }
    }
    return numChanges > 0;
}
void handle_branching_simplify(Function *F) {
    cout << "simplify " << string(F->getName()) << endl;
    unique_ptr<RootBlock> root(new RootBlock());
    for(auto it=F->begin(); it != F->end(); it++) {
        cout << "block" << endl;
        BasicBlock *basicBlock = &*it;
        unique_ptr<BasicBlockBlock> block(new BasicBlockBlock());
        block->basicBlock = basicBlock;
        for(auto instit=basicBlock->begin(); instit != basicBlock->end(); instit++) {
            Instruction *inst = &*instit;
            // skip branches, phis and so on, which we'll handle later, somehow...
            if(isa<BranchInst>(inst)) {
                continue;
            }
            if(isa<PHINode>(inst)) {
                continue;
            }
            if(isa<ReturnInst>(inst)) {
                continue;
            }
            block->instructions.push_back(inst);
        }
        blockByBasicBlock[basicBlock] = block.get();
        blocks.push_back(std::move(block));
    }

    root->first = blockByBasicBlock[&F->getEntryBlock()];
    root->first->incoming.push_back(root.get());
    // go through, and start linking stuff togehter, now that we have a map from basic block to block
    for(auto it=F->begin(); it != F->end(); it++) {
        BasicBlock *basicBlock = &*it;
        BasicBlockBlock *block = dynamic_cast<BasicBlockBlock *>(blockByBasicBlock[basicBlock]);
        // I think that each block has to end initially either with a branch or a return?
        Instruction *lastInst = basicBlock->getTerminator();
        cout << "lastinst:" << endl;
        lastInst->dump();
        cout << endl;
        if(isa<ReturnInst>(lastInst)) {
            cout << "finishes in ret" << endl;
            unique_ptr<ReturnBlock> retBlock(new ReturnBlock());
            block->next = retBlock.get();
            block->next->incoming.push_back(block);
            blocks.push_back(std::move(retBlock));
        } else if(BranchInst* branchInst = dyn_cast<BranchInst>(lastInst)) {
            cout << "its a branch" << endl;
            // if its unconditional, we just link directly to the next block
            // otherwise we link to a ConditionalBranch block
            if(branchInst->isUnconditional()) {
                cout << "unconditonal branch" << endl;
                BasicBlock *next = branchInst->getSuccessor(0);
                Block *nextBlock = blockByBasicBlock[next];
                block->next = nextBlock;
                block->next->incoming.push_back(block);
            } else {
                // conditional
                // create a ConditionalBranch block
                cout << "conditonal branch" << endl;
                unique_ptr<ConditionalBranch> conditionalBranch(new ConditionalBranch());
                BasicBlock *trueBasicBlock = branchInst->getSuccessor(0);
                Block *trueBlock = blockByBasicBlock[trueBasicBlock];
                conditionalBranch->trueNext = trueBlock;
                conditionalBranch->trueNext->incoming.push_back(conditionalBranch.get());
                conditionalBranch->falseNext = 0;
                if(branchInst->getNumSuccessors() == 2) {
                    BasicBlock *falseBasicBlock = branchInst->getSuccessor(1);
                    Block *falseBlock = blockByBasicBlock[falseBasicBlock];
                    conditionalBranch->falseNext = falseBlock;
                    conditionalBranch->falseNext->incoming.push_back(conditionalBranch.get());
                }
                block->next = conditionalBranch.get();
                block->next->incoming.push_back(block);
                blocks.push_back(std::move(conditionalBranch));
            }
        } else {
            cout << "hmmm, how did we get here???" << endl;
            cout << "lastinst:" << endl;
            lastInst->dump();
            cout << endl;
            throw runtime_error("dont know how we got here...");
        }
    }

    set<const Block *>seen;
    root->dump(seen, "");

    // int numChanges = 1;
    bool madeChanges =  true;
    while(madeChanges > 0) {
        madeChanges = false;
        if(mergeSequences(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        if(huntTrueIfs(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        if(huntFors(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        // if(huntWhiles(root.get())) {
        //     madeChanges = true;
        //     seen.clear();
        //     root->dump(seen, "");
        // }

        // seen.clear();
        // root->dump(seen, "");
    }

}

} // namespace cocl
<commit_msg>make sure to clear vectors at start of siplify<commit_after>// Copyright Hugh Perkins 2016

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

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

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

#include "handle_branching.h"
#include "flowcontrolinstructions.h"

#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SourceMgr.h"
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <map>
#include <set>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <fstream>

#include <iostream>
#include <cassert>

using namespace std;
using namespace llvm;
using namespace cocl::flowcontrol;

namespace cocl {

vector<unique_ptr<Block> > blocks; // doesnt include the root. I guess. ???
map<BasicBlock *, Block *> blockByBasicBlock;

template<typename T>
void vectorErase(vector<T> &targetvector, T &element) {
    int i = 0;
    bool found = false;
    for(auto it=targetvector.begin(); it != targetvector.end(); it++) {
        const T &thiselement = *it;
        if(thiselement == element) {
            found = true;
            break;
        }
        i++;
    }
    if(found) {
        targetvector.erase(targetvector.begin() + i);
        return;
    }
    throw runtime_error("couldnt find element to erease");
}

void eraseBlock(Block *block) {
    int id = 0;
    bool found = false;
    for(auto it=blocks.begin(); it != blocks.end(); it++) {
        Block *thisblock = it->get();
        if(thisblock == block) {
            found = true;
            break;
        }
        id++;
    }
    if(found) {
        blocks.erase(blocks.begin() + id);
        return;
    }
    throw runtime_error("couldnt find block to erease");
}

void swapChildInParents(Block *oldChild, Block *newChild) {
    for(auto it=oldChild->incoming.begin(); it != oldChild->incoming.end(); it++) {
        Block *incoming = *it;
        newChild->incoming.push_back(incoming);
        incoming->replaceChildOrSuccessor(oldChild, newChild);
    }
    oldChild->incoming.clear();
}

// void swapParentInChildren(Block *oldParent, Block *newParent) {
//     if(oldParent->numSuccessors() != 1) {
//         throw runtime_error("not yet implemented: more than one child");
//     }
//     Block *successor = oldParent->getSuccessor(0);
//     successor->replaceIncoming(oldParent, newParent);
// }

bool mergeSequences(Block *root) {
    // basically we look for any block with one single incoming, and that incoming is a basicblockblock
    bool didAMerge = true;
    int numChanges = 0;
    while(didAMerge) {
        didAMerge = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(block->incoming.size() != 1) {
                continue;
            }
            // cout << "block " << block->id << " has only one incoming" << endl;
            Block *parent = block->incoming[0];
            if(parent->numSuccessors() != 1) {
                continue;
            }
            if(block->numSuccessors() != 1) {
                continue;
            }
            if(parent->getSuccessor(0) != block) {
                continue;
            }
            // so merge...
            cout << "merging ... " << block->id << ", " << parent->id << endl;
            unique_ptr<Sequence> sequence(new Sequence());
            sequence->children.push_back(parent);
            sequence->children.push_back(block);
            swapChildInParents(parent, sequence.get());
            parent->incoming.push_back(sequence.get());
            parent->replaceSuccessor(block, 0);
            block->incoming.clear();
            block->incoming.push_back(sequence.get());
            Block *blockSuccessor = block->getSuccessor(0);
            blockSuccessor->replaceIncoming(block, sequence.get());
            sequence->next = blockSuccessor;
            block->replaceSuccessor(blockSuccessor, 0);
            blocks.push_back(std::move(sequence));
            didAMerge = true;
            numChanges++;
            return true;
        }
    }
    return numChanges > 0;
}
bool huntTrueIfs(Block *block) {
    // an 'if' looks like (we're handling only the 'true' case ):
    // (something)
    // ConditionalBlock
    // true: BlockA => BlockB
    // false: BlockB (constraint: 1 successor exactly)
    int numChanges = 0;
    bool foundFor = true;
    while(foundFor) {
        foundFor = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(ConditionalBranch *cond = dynamic_cast<ConditionalBranch *>(block)) {
                Block *trueChild = cond->trueNext;
                Block *falseChild = cond->falseNext;
                if(trueChild->numSuccessors() != 1) {
                    cout << "truechild numsuccessors not 1" << endl;
                    continue;
                }
                if(trueChild->incoming.size() != 1) {
                    cout << "truechild incoming not 1" << endl;
                    continue;
                }
                if(trueChild->getSuccessor(0) != falseChild) {
                    cout << "truechild successor not falsechild" << endl;
                    continue;
                }
                // if(falseChild->incoming.size() != 1) {
                //     continue;
                // }
                // if(falseChild->numSuccessors() != 1) {
                //     continue;
                // }
                // if(falseChild->getSuccessor(0) == trueChild) {
                //     continue;
                // }
                // if(falseChild->getSuccessor(0) == cond) {
                //     continue;
                // }
                cout << "found a true-if" << endl;
                cout << "cond: " << cond->id << endl;
                cout << "true: " << trueChild->id << endl;
                cout << "false: " << falseChild->id << endl;

                unique_ptr<If> ifBlock(new If());
                swapChildInParents(cond, ifBlock.get());
                ifBlock->condition = cond->condition;
                ifBlock->trueBlock = trueChild;
                ifBlock->falseBlock = 0;
                ifBlock->next = falseChild;

                trueChild->incoming.clear();
                trueChild->incoming.push_back(ifBlock.get());
                trueChild->replaceSuccessor(falseChild, 0);

                falseChild->replaceIncoming(trueChild, ifBlock.get());
                falseChild->removeIncoming(cond);
                // falseChild->incoming.clear();
                // falseChild->incoming.push_back(ifBlock.get());

                // falseChild has one successor
                // we need to swap its successor to be linked into ifBlock
                // Block *successor = falseChild->getSuccessor(0);
                // successor->replaceIncoming(falseChild, ifBlock.get());
                // successor->removeIncoming(trueChild);

                // falseChild->replaceSuccessor
                eraseBlock(cond);
                blocks.push_back(std::move(ifBlock));
                foundFor = true;
                numChanges++;
                return true;
            }
        }
    }
    return numChanges > 0;
}
void huntWhiles(Block *block) {
    // BlockA
    // ConditonalBlock
    // true: BlockA
    // false: BlockB
}
bool huntFors(Block *block) {
    //BlockA
    //ConditionalBlock
    // true: BlockB => blockA
    // false: blockC
    // blockC
    int numChanges = 0;
    bool foundFor = true;
    while(foundFor) {
        foundFor = false;
        for(auto it = blocks.begin(); it != blocks.end(); it++) {
            Block *block = it->get();
            if(ConditionalBranch *cond = dynamic_cast<ConditionalBranch *>(block)) {
                if(cond->incoming.size() != 1) {
                    continue;
                }
                Block *parent = cond->incoming[0];
                Block *child = cond->trueNext;
                if(child->incoming.size() != 1) {
                    continue;
                }
                if(child->numSuccessors() != 1) {
                    continue;
                }
                if(child->getSuccessor(0) != parent) {
                    continue;
                }
                cout << "found a for :-)" << endl;
                cout << "pre: " << parent->id << endl;
                cout << "condiiotn: " << block->id << endl;
                cout << "body: " << child->id << endl;
                cout << "next: " << cond->falseNext->id << endl;

                unique_ptr<For> forBlock(new For());
                // swapChildInParents(parent, forBlock.get());
                // vectorErase(forBlock->incoming, child);
                for(auto parentincit = parent->incoming.begin(); parentincit != parent->incoming.end(); parentincit++) {
                    Block *parentinc = *parentincit;
                    if(parentinc != child) {
                        cout << "parentinc " << parentinc->id << endl;
                        forBlock->incoming.push_back(parentinc);
                        parentinc->replaceSuccessor(parent, forBlock.get());
                    }
                }
                parent->incoming.clear();
                parent->replaceSuccessor(cond, 0);
                child->replaceSuccessor(parent, 0);
                child->incoming.clear();
                forBlock->next = cond->falseNext;
                forBlock->preBlock = parent;
                forBlock->bodyBlock = child;
                forBlock->condition = cond->condition;
                cond->falseNext->replaceIncoming(cond, forBlock.get());
                eraseBlock(cond);
                blocks.push_back(std::move(forBlock));
                foundFor = true;
                numChanges++;
            }
        }
    }
    return numChanges > 0;
}
void handle_branching_simplify(Function *F) {
    blocks.clear();
    blockByBasicBlock.clear();
    cout << "simplify " << string(F->getName()) << endl;
    unique_ptr<RootBlock> root(new RootBlock());
    for(auto it=F->begin(); it != F->end(); it++) {
        cout << "block" << endl;
        BasicBlock *basicBlock = &*it;
        unique_ptr<BasicBlockBlock> block(new BasicBlockBlock());
        block->basicBlock = basicBlock;
        for(auto instit=basicBlock->begin(); instit != basicBlock->end(); instit++) {
            Instruction *inst = &*instit;
            // skip branches, phis and so on, which we'll handle later, somehow...
            if(isa<BranchInst>(inst)) {
                continue;
            }
            if(isa<PHINode>(inst)) {
                continue;
            }
            if(isa<ReturnInst>(inst)) {
                continue;
            }
            block->instructions.push_back(inst);
        }
        blockByBasicBlock[basicBlock] = block.get();
        blocks.push_back(std::move(block));
    }

    root->first = blockByBasicBlock[&F->getEntryBlock()];
    root->first->incoming.push_back(root.get());
    // go through, and start linking stuff togehter, now that we have a map from basic block to block
    for(auto it=F->begin(); it != F->end(); it++) {
        BasicBlock *basicBlock = &*it;
        BasicBlockBlock *block = dynamic_cast<BasicBlockBlock *>(blockByBasicBlock[basicBlock]);
        // I think that each block has to end initially either with a branch or a return?
        Instruction *lastInst = basicBlock->getTerminator();
        cout << "lastinst:" << endl;
        lastInst->dump();
        cout << endl;
        if(isa<ReturnInst>(lastInst)) {
            cout << "finishes in ret" << endl;
            unique_ptr<ReturnBlock> retBlock(new ReturnBlock());
            block->next = retBlock.get();
            block->next->incoming.push_back(block);
            blocks.push_back(std::move(retBlock));
        } else if(BranchInst* branchInst = dyn_cast<BranchInst>(lastInst)) {
            cout << "its a branch" << endl;
            // if its unconditional, we just link directly to the next block
            // otherwise we link to a ConditionalBranch block
            if(branchInst->isUnconditional()) {
                cout << "unconditonal branch" << endl;
                BasicBlock *next = branchInst->getSuccessor(0);
                Block *nextBlock = blockByBasicBlock[next];
                block->next = nextBlock;
                block->next->incoming.push_back(block);
            } else {
                // conditional
                // create a ConditionalBranch block
                cout << "conditonal branch" << endl;
                unique_ptr<ConditionalBranch> conditionalBranch(new ConditionalBranch());
                BasicBlock *trueBasicBlock = branchInst->getSuccessor(0);
                Block *trueBlock = blockByBasicBlock[trueBasicBlock];
                conditionalBranch->trueNext = trueBlock;
                conditionalBranch->trueNext->incoming.push_back(conditionalBranch.get());
                conditionalBranch->falseNext = 0;
                if(branchInst->getNumSuccessors() == 2) {
                    BasicBlock *falseBasicBlock = branchInst->getSuccessor(1);
                    Block *falseBlock = blockByBasicBlock[falseBasicBlock];
                    conditionalBranch->falseNext = falseBlock;
                    conditionalBranch->falseNext->incoming.push_back(conditionalBranch.get());
                }
                block->next = conditionalBranch.get();
                block->next->incoming.push_back(block);
                blocks.push_back(std::move(conditionalBranch));
            }
        } else {
            cout << "hmmm, how did we get here???" << endl;
            cout << "lastinst:" << endl;
            lastInst->dump();
            cout << endl;
            throw runtime_error("dont know how we got here...");
        }
    }

    set<const Block *>seen;
    root->dump(seen, "");

    // int numChanges = 1;
    bool madeChanges =  true;
    while(madeChanges > 0) {
        madeChanges = false;
        if(mergeSequences(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        if(huntTrueIfs(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        if(huntFors(root.get())) {
            madeChanges = true;
            seen.clear();
            root->dump(seen, "");
        }

        // if(huntWhiles(root.get())) {
        //     madeChanges = true;
        //     seen.clear();
        //     root->dump(seen, "");
        // }

        // seen.clear();
        // root->dump(seen, "");
    }

}

} // namespace cocl
<|endoftext|>