<commit_before>/**
  Based on https://gist.github.com/jvranish/4441299
 */

#include "stacktrace.hpp"

#include "log.hpp"

#include <iostream>

#ifdef STACKTRACE

	#include <sstream>
	#include <cstdio>

	#ifdef WIN
		#include <windows.h>
		#include <imagehlp.h>
	#else
		#include <signal.h>
		#include <execinfo.h>
	#endif

	namespace core {
	namespace util {

		namespace {
			void set_signal_handler();

			std::string EXE_NAME;

			std::string demangleStacktraceEntry(void* t) {
				FILE *fp;
				char var[40];

				std::stringstream buffer;
				#ifdef __APPLE__
					buffer<<"atos -o "<<t<<" \""<<EXE_NAME<<"\"";
				#else
					buffer<<"addr2line -C -s -f -p "<<t<<" -e \""<<EXE_NAME<<"\"";
				#endif

				std::string command = buffer.str();

				fp = popen(command.c_str(), "r");

				buffer.str(std::string());

				while (fgets(var, sizeof(var), fp) != NULL)
					buffer<<var;

				pclose(fp);

				return buffer.str();
			}
			void printStackTrace(std::string error) {
				CRASH_REPORT("\n"<<error);
			}
		}

		bool is_stacktrace_available() {
			return !EXE_NAME.empty();
		}

	#ifdef _WIN32

		namespace {
			typedef void ( * RtlCaptureContextFunc ) ( CONTEXT * ContextRecord );
			RtlCaptureContextFunc rtlCaptureContext;
		}

		void init_stacktrace(std::string exeName) {
			EXE_NAME = exeName;

			HINSTANCE kernel32 = LoadLibrary("Kernel32.dll");

			rtlCaptureContext = (RtlCaptureContextFunc) GetProcAddress( kernel32, "RtlCaptureContext" );

			set_signal_handler();
			INFO("Startet from "<<exeName);
		}

		namespace {
			std::string windows_print_stacktrace(CONTEXT* context) {
				std::stringstream ret;
				SymInitialize(GetCurrentProcess(), 0, TRUE);

				DWORD MachineType;
				bool first = true;

				/* setup initial stack frame */
				#ifdef _M_IX86
				  MachineType                 = IMAGE_FILE_MACHINE_I386;
				  STACKFRAME frame;

				  frame.AddrPC.Offset    = context->Eip;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->Ebp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrStack.Offset = context->Esp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#elif _M_X64
				  MachineType                 = IMAGE_FILE_MACHINE_AMD64;
				  STACKFRAME64 frame;

				  frame.AddrPC.Offset    = context->Rip;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->Rbp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrStack.Offset = context->Rsp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#elif _M_IA64
				  MachineType                 = IMAGE_FILE_MACHINE_IA64;
				  STACKFRAME64 frame;

				  frame.AddrPC.Offset    = context->StIIP;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->IntSp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrBStore.Offset= context->RsBSP;
				  frame.AddrBStore.Mode  = AddrModeFlat;
				  frame.AddrStack.Offset = context->IntSp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#else
				  #error "Unsupported platform"
				#endif

				memset(&frame, 0, sizeof(frame));

				#ifdef _M_IX86
					while (StackWalk(  MachineType ,
									   GetCurrentProcess(),
									   GetCurrentThread(),
									   &frame,
									   context,
									   0,
									   SymFunctionTableAccess,
									   SymGetModuleBase,
									   0 ) ) {
						if(first) first=false;
						else      ret<<"Called From ";
						ret<<demangleStacktraceEntry((void*)frame.AddrPC.Offset)<<std::endl;
					}

				#else
					while (StackWalk64(  MachineType ,
									   GetCurrentProcess(),
									   GetCurrentThread(),
									   &frame,
									   context,
									   0,
									   SymFunctionTableAccess64,
									   SymGetModuleBase64,
									   0 ) ) {
						if(first) first=false;
						else      ret<<"Called From ";
						ret<<demangleStacktraceEntry((void*)frame.AddrPC.Offset)<<std::endl;
					}
				#endif

				SymCleanup( GetCurrentProcess() );

				return ret.str();
			}

			LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo) {
			  switch(ExceptionInfo->ExceptionRecord->ExceptionCode) {
					case EXCEPTION_ACCESS_VIOLATION:
						std::cerr<<"Error: EXCEPTION_ACCESS_VIOLATION";
						break;
					case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
						std::cerr<<"Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
						break;
					case EXCEPTION_BREAKPOINT:
						std::cerr<<"Error: EXCEPTION_BREAKPOINT";
						break;
					case EXCEPTION_DATATYPE_MISALIGNMENT:
						std::cerr<<"Error: EXCEPTION_DATATYPE_MISALIGNMENT";
						break;
					case EXCEPTION_FLT_DENORMAL_OPERAND:
						std::cerr<<"Error: EXCEPTION_FLT_DENORMAL_OPERAND";
						break;
					case EXCEPTION_FLT_DIVIDE_BY_ZERO:
						std::cerr<<"Error: EXCEPTION_FLT_DIVIDE_BY_ZERO";
						break;
					case EXCEPTION_FLT_INEXACT_RESULT:
						std::cerr<<"Error: EXCEPTION_FLT_INEXACT_RESULT";
						break;
					case EXCEPTION_FLT_INVALID_OPERATION:
						std::cerr<<"Error: EXCEPTION_FLT_INVALID_OPERATION";
						break;
					case EXCEPTION_FLT_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_FLT_OVERFLOW";
						break;
					case EXCEPTION_FLT_STACK_CHECK:
						std::cerr<<"Error: EXCEPTION_FLT_STACK_CHECK";
						break;
					case EXCEPTION_FLT_UNDERFLOW:
						std::cerr<<"Error: EXCEPTION_FLT_UNDERFLOW";
						break;
					case EXCEPTION_ILLEGAL_INSTRUCTION:
						std::cerr<<"Error: EXCEPTION_ILLEGAL_INSTRUCTION";
						break;
					case EXCEPTION_IN_PAGE_ERROR:
						std::cerr<<"Error: EXCEPTION_IN_PAGE_ERROR";
						break;
					case EXCEPTION_INT_DIVIDE_BY_ZERO:
						std::cerr<<"Error: EXCEPTION_INT_DIVIDE_BY_ZERO";
						break;
					case EXCEPTION_INT_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_INT_OVERFLOW";
						break;
					case EXCEPTION_INVALID_DISPOSITION:
						std::cerr<<"Error: EXCEPTION_INVALID_DISPOSITION";
						break;
					case EXCEPTION_NONCONTINUABLE_EXCEPTION:
						std::cerr<<"Error: EXCEPTION_NONCONTINUABLE_EXCEPTION";
						break;
					case EXCEPTION_PRIV_INSTRUCTION:
						std::cerr<<"Error: EXCEPTION_PRIV_INSTRUCTION";
						break;
					case EXCEPTION_SINGLE_STEP:
						std::cerr<<"Error: EXCEPTION_SINGLE_STEP";
						break;
					case EXCEPTION_STACK_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_STACK_OVERFLOW";
						break;
					default:
						std::cerr<<"Error: Unrecognized Exception";
						break;
				}
				std::cerr<<" at ";

				/* If this is a stack overflow then we can't walk the stack, so just show
				  where the error happened */
				if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
					std::cerr<<windows_print_stacktrace(ExceptionInfo->ContextRecord)<<std::endl;

				else
					#ifdef _M_IX86
						std::cerr<<demangleStacktraceEntry((void*)ExceptionInfo->ContextRecord->Eip)<<"; Sorry, no stacktrace for windows here :-(\n Please upgrade to Linux"<<std::endl;
					#else
						std::cerr<<demangleStacktraceEntry((void*)ExceptionInfo->ContextRecord->Rip)<<"; Sorry, no stacktrace for windows here :-(\n Please upgrade to Linux"<<std::endl;
					#endif

				return EXCEPTION_EXECUTE_HANDLER;
			}

			void set_signal_handler() {
				SetUnhandledExceptionFilter(windows_exception_handler);
			}
		}

		std::string gen_stacktrace(int framesToSkip) {
			std::stringstream ret;

			CONTEXT context;
			memset(&context, 0, sizeof(context));
			context.ContextFlags = CONTEXT_CONTROL;

			// Capture the thread context
			rtlCaptureContext( & context );

			ret<<windows_print_stacktrace(&context)<<std::endl;

			return ret.str();
		}

	#else
		void init_stacktrace(std::string exeName) {
			EXE_NAME = exeName;
			set_signal_handler();
			INFO("Startet from "<<exeName);
		}

		namespace {
			void posix_signal_handler(int sig, siginfo_t *siginfo, void *context) {
			  (void)context;
			  switch(sig) {
				case SIGSEGV:
				  printStackTrace("Caught SIGSEGV: Segmentation Fault");
				  break;
				case SIGINT:
				  printStackTrace("Caught SIGINT: Interactive attention signal, (usually ctrl+c)");
				  break;
				case SIGFPE:
				  switch(siginfo->si_code) {
					case FPE_INTDIV:
					  printStackTrace("Caught SIGFPE: (integer divide by zero)");
					  break;
					case FPE_INTOVF:
					  printStackTrace("Caught SIGFPE: (integer overflow)");
					  break;
					case FPE_FLTDIV:
					  printStackTrace("Caught SIGFPE: (floating-point divide by zero)");
					  break;
					case FPE_FLTOVF:
					  printStackTrace("Caught SIGFPE: (floating-point overflow)");
					  break;
					case FPE_FLTUND:
					  printStackTrace("Caught SIGFPE: (floating-point underflow)");
					  break;
					case FPE_FLTRES:
					  printStackTrace("Caught SIGFPE: (floating-point inexact result)");
					  break;
					case FPE_FLTINV:
					  printStackTrace("Caught SIGFPE: (floating-point invalid operation)");
					  break;
					case FPE_FLTSUB:
					  printStackTrace("Caught SIGFPE: (subscript out of range)");
					  break;
					default:
					  printStackTrace("Caught SIGFPE: Arithmetic Exception");
					  break;
				  }
				  case SIGILL:
						switch(siginfo->si_code) {
						  case ILL_ILLOPC:
							printStackTrace("Caught SIGILL: (illegal opcode)");
							break;
						  case ILL_ILLOPN:
							printStackTrace("Caught SIGILL: (illegal operand)");
							break;
						  case ILL_ILLADR:
							printStackTrace("Caught SIGILL: (illegal addressing mode)");
							break;
						  case ILL_ILLTRP:
							printStackTrace("Caught SIGILL: (illegal trap)");
							break;
						  case ILL_PRVOPC:
							printStackTrace("Caught SIGILL: (privileged opcode)");
							break;
						  case ILL_PRVREG:
							printStackTrace("Caught SIGILL: (privileged register)");
							break;
						  case ILL_COPROC:
							printStackTrace("Caught SIGILL: (coprocessor error)");
							break;
						  case ILL_BADSTK:
							printStackTrace("Caught SIGILL: (internal stack error)");
							break;
						  default:
							printStackTrace("Caught SIGILL: Illegal Instruction");
							break;
						}
						break;
					  case SIGTERM:
						printStackTrace("Caught SIGTERM: a termination request was sent to the program");
						break;
					  case SIGABRT:
						printStackTrace("Caught SIGABRT: usually caused by an abort() or assert()");
						break;
					  default:
						break;
					}
					_Exit(1);
				  }

			char alternate_stack[SIGSTKSZ*2];

			void set_signal_handler() {
			  /* setup alternate stack */
			  {
				stack_t ss;
				/* malloc is usually used here, I'm not 100% sure my static allocation
				   is valid but it seems to work just fine. */
				ss.ss_sp = (void*)alternate_stack;
				ss.ss_size = sizeof(alternate_stack);
				ss.ss_flags = 0;

				if (sigaltstack(&ss, NULL) != 0)
					std::cerr<<"failed to create alternate stack for handlers!"<<std::endl;
			  }

			  /* register our signal handlers */
			  {
				struct sigaction sig_action;
				sig_action.sa_sigaction = posix_signal_handler;
				sigemptyset(&sig_action.sa_mask);

				#ifdef __APPLE__
					/* for some reason we backtrace() doesn't work on osx
					   when we use an alternate stack */
					sig_action.sa_flags = SA_SIGINFO;
				#else
					sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
				#endif

				if (sigaction(SIGSEGV, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGSEGV!");
				if (sigaction(SIGFPE,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGFPE!");
				if (sigaction(SIGINT,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGINT!");
				if (sigaction(SIGILL,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGILL!");
				if (sigaction(SIGTERM, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGTERM!");
				if (sigaction(SIGABRT, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGABRT!");
			  }
			}
		}

		std::string gen_stacktrace(int framesToSkip) {
			std::stringstream ret;
			void *trace[32];

			auto trace_size = backtrace(trace, 32);
			char** messages = backtrace_symbols(trace, trace_size);

			/* skip first stack frame (points here) */

			bool first=true;

			for (auto i=1+framesToSkip; i<trace_size; ++i) {
				if(first) first=false;
				else      ret<<"Called From ";
				ret<<messages[i]<<std::endl<<"    "<<demangleStacktraceEntry(trace[i])<<std::endl;
			}

			return ret.str();
		}
	#endif
	}
	}

#else
	namespace core {
	namespace util {
		void init_stacktrace(std::string exeName) {
		}

		std::string gen_stacktrace(int stacksToSkip) {
			return "";
		}

		bool is_stacktrace_available() {
			return false;
		}
	}
	}
#endif
<commit_msg>tilemap renderer some fixes<commit_after>/**
  Based on https://gist.github.com/jvranish/4441299
 */

#include "stacktrace.hpp"

#include "log.hpp"

#include <iostream>

#ifdef STACKTRACE

	#include <sstream>
	#include <cstdio>

	#ifdef WIN
		#include <windows.h>
		#include <imagehlp.h>
	#else
		#include <signal.h>
		#include <execinfo.h>
	#endif

	namespace core {
	namespace util {

		namespace {
			void set_signal_handler();

			std::string EXE_NAME;

			std::string demangleStacktraceEntry(void* t) {
				FILE *fp;
				char var[40];

				std::stringstream buffer;
				#ifdef __APPLE__
					buffer<<"atos -o "<<t<<" \""<<EXE_NAME<<"\"";
				#else
					buffer<<"addr2line -C -s -f -p "<<t<<" -e \""<<EXE_NAME<<"\"";
				#endif

				std::string command = buffer.str();

				fp = popen(command.c_str(), "r");

				buffer.str(std::string());

				while (fgets(var, sizeof(var), fp) != NULL)
					buffer<<var;

				pclose(fp);

				return buffer.str();
			}
			/*void printStackTrace(std::string error) {
				CRASH_REPORT("\n"<<error);
			}*/
		}

		bool is_stacktrace_available() {
			return !EXE_NAME.empty();
		}

	#ifdef _WIN32

		namespace {
			typedef void ( * RtlCaptureContextFunc ) ( CONTEXT * ContextRecord );
			RtlCaptureContextFunc rtlCaptureContext;
		}

		void init_stacktrace(std::string exeName) {
			EXE_NAME = exeName;

			HINSTANCE kernel32 = LoadLibrary("Kernel32.dll");

			rtlCaptureContext = (RtlCaptureContextFunc) GetProcAddress( kernel32, "RtlCaptureContext" );

			set_signal_handler();
			INFO("Startet from "<<exeName);
		}

		namespace {
			std::string windows_print_stacktrace(CONTEXT* context) {
				std::stringstream ret;
				SymInitialize(GetCurrentProcess(), 0, TRUE);

				DWORD MachineType;
				bool first = true;

				/* setup initial stack frame */
				#ifdef _M_IX86
				  MachineType                 = IMAGE_FILE_MACHINE_I386;
				  STACKFRAME frame;

				  frame.AddrPC.Offset    = context->Eip;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->Ebp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrStack.Offset = context->Esp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#elif _M_X64
				  MachineType                 = IMAGE_FILE_MACHINE_AMD64;
				  STACKFRAME64 frame;

				  frame.AddrPC.Offset    = context->Rip;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->Rbp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrStack.Offset = context->Rsp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#elif _M_IA64
				  MachineType                 = IMAGE_FILE_MACHINE_IA64;
				  STACKFRAME64 frame;

				  frame.AddrPC.Offset    = context->StIIP;
				  frame.AddrPC.Mode      = AddrModeFlat;
				  frame.AddrFrame.Offset = context->IntSp;
				  frame.AddrFrame.Mode   = AddrModeFlat;
				  frame.AddrBStore.Offset= context->RsBSP;
				  frame.AddrBStore.Mode  = AddrModeFlat;
				  frame.AddrStack.Offset = context->IntSp;
				  frame.AddrStack.Mode   = AddrModeFlat;
				#else
				  #error "Unsupported platform"
				#endif

				memset(&frame, 0, sizeof(frame));

				#ifdef _M_IX86
					while (StackWalk(  MachineType ,
									   GetCurrentProcess(),
									   GetCurrentThread(),
									   &frame,
									   context,
									   0,
									   SymFunctionTableAccess,
									   SymGetModuleBase,
									   0 ) ) {
						if(first) first=false;
						else      ret<<"Called From ";
						ret<<demangleStacktraceEntry((void*)frame.AddrPC.Offset)<<std::endl;
					}

				#else
					while (StackWalk64(  MachineType ,
									   GetCurrentProcess(),
									   GetCurrentThread(),
									   &frame,
									   context,
									   0,
									   SymFunctionTableAccess64,
									   SymGetModuleBase64,
									   0 ) ) {
						if(first) first=false;
						else      ret<<"Called From ";
						ret<<demangleStacktraceEntry((void*)frame.AddrPC.Offset)<<std::endl;
					}
				#endif

				SymCleanup( GetCurrentProcess() );

				return ret.str();
			}

			LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo) {
			  switch(ExceptionInfo->ExceptionRecord->ExceptionCode) {
					case EXCEPTION_ACCESS_VIOLATION:
						std::cerr<<"Error: EXCEPTION_ACCESS_VIOLATION";
						break;
					case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
						std::cerr<<"Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
						break;
					case EXCEPTION_BREAKPOINT:
						std::cerr<<"Error: EXCEPTION_BREAKPOINT";
						break;
					case EXCEPTION_DATATYPE_MISALIGNMENT:
						std::cerr<<"Error: EXCEPTION_DATATYPE_MISALIGNMENT";
						break;
					case EXCEPTION_FLT_DENORMAL_OPERAND:
						std::cerr<<"Error: EXCEPTION_FLT_DENORMAL_OPERAND";
						break;
					case EXCEPTION_FLT_DIVIDE_BY_ZERO:
						std::cerr<<"Error: EXCEPTION_FLT_DIVIDE_BY_ZERO";
						break;
					case EXCEPTION_FLT_INEXACT_RESULT:
						std::cerr<<"Error: EXCEPTION_FLT_INEXACT_RESULT";
						break;
					case EXCEPTION_FLT_INVALID_OPERATION:
						std::cerr<<"Error: EXCEPTION_FLT_INVALID_OPERATION";
						break;
					case EXCEPTION_FLT_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_FLT_OVERFLOW";
						break;
					case EXCEPTION_FLT_STACK_CHECK:
						std::cerr<<"Error: EXCEPTION_FLT_STACK_CHECK";
						break;
					case EXCEPTION_FLT_UNDERFLOW:
						std::cerr<<"Error: EXCEPTION_FLT_UNDERFLOW";
						break;
					case EXCEPTION_ILLEGAL_INSTRUCTION:
						std::cerr<<"Error: EXCEPTION_ILLEGAL_INSTRUCTION";
						break;
					case EXCEPTION_IN_PAGE_ERROR:
						std::cerr<<"Error: EXCEPTION_IN_PAGE_ERROR";
						break;
					case EXCEPTION_INT_DIVIDE_BY_ZERO:
						std::cerr<<"Error: EXCEPTION_INT_DIVIDE_BY_ZERO";
						break;
					case EXCEPTION_INT_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_INT_OVERFLOW";
						break;
					case EXCEPTION_INVALID_DISPOSITION:
						std::cerr<<"Error: EXCEPTION_INVALID_DISPOSITION";
						break;
					case EXCEPTION_NONCONTINUABLE_EXCEPTION:
						std::cerr<<"Error: EXCEPTION_NONCONTINUABLE_EXCEPTION";
						break;
					case EXCEPTION_PRIV_INSTRUCTION:
						std::cerr<<"Error: EXCEPTION_PRIV_INSTRUCTION";
						break;
					case EXCEPTION_SINGLE_STEP:
						std::cerr<<"Error: EXCEPTION_SINGLE_STEP";
						break;
					case EXCEPTION_STACK_OVERFLOW:
						std::cerr<<"Error: EXCEPTION_STACK_OVERFLOW";
						break;
					default:
						std::cerr<<"Error: Unrecognized Exception";
						break;
				}
				std::cerr<<" at ";

				/* If this is a stack overflow then we can't walk the stack, so just show
				  where the error happened */
				if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode)
					std::cerr<<windows_print_stacktrace(ExceptionInfo->ContextRecord)<<std::endl;

				else
					#ifdef _M_IX86
						std::cerr<<demangleStacktraceEntry((void*)ExceptionInfo->ContextRecord->Eip)<<"; Sorry, no stacktrace for windows here :-(\n Please upgrade to Linux"<<std::endl;
					#else
						std::cerr<<demangleStacktraceEntry((void*)ExceptionInfo->ContextRecord->Rip)<<"; Sorry, no stacktrace for windows here :-(\n Please upgrade to Linux"<<std::endl;
					#endif

				return EXCEPTION_EXECUTE_HANDLER;
			}

			void set_signal_handler() {
				SetUnhandledExceptionFilter(windows_exception_handler);
			}
		}

		std::string gen_stacktrace(int framesToSkip) {
			std::stringstream ret;

			CONTEXT context;
			memset(&context, 0, sizeof(context));
			context.ContextFlags = CONTEXT_CONTROL;

			// Capture the thread context
			rtlCaptureContext( & context );

			ret<<windows_print_stacktrace(&context)<<std::endl;

			return ret.str();
		}

	#else
		void init_stacktrace(std::string exeName) {
			EXE_NAME = exeName;
			set_signal_handler();
			INFO("Startet from "<<exeName);
		}

		namespace {
			void posix_signal_handler(int sig, siginfo_t *siginfo, void *context) {
			  (void)context;
			  switch(sig) {
				case SIGSEGV:
				  printStackTrace("Caught SIGSEGV: Segmentation Fault");
				  break;
				case SIGINT:
				  printStackTrace("Caught SIGINT: Interactive attention signal, (usually ctrl+c)");
				  break;
				case SIGFPE:
				  switch(siginfo->si_code) {
					case FPE_INTDIV:
					  printStackTrace("Caught SIGFPE: (integer divide by zero)");
					  break;
					case FPE_INTOVF:
					  printStackTrace("Caught SIGFPE: (integer overflow)");
					  break;
					case FPE_FLTDIV:
					  printStackTrace("Caught SIGFPE: (floating-point divide by zero)");
					  break;
					case FPE_FLTOVF:
					  printStackTrace("Caught SIGFPE: (floating-point overflow)");
					  break;
					case FPE_FLTUND:
					  printStackTrace("Caught SIGFPE: (floating-point underflow)");
					  break;
					case FPE_FLTRES:
					  printStackTrace("Caught SIGFPE: (floating-point inexact result)");
					  break;
					case FPE_FLTINV:
					  printStackTrace("Caught SIGFPE: (floating-point invalid operation)");
					  break;
					case FPE_FLTSUB:
					  printStackTrace("Caught SIGFPE: (subscript out of range)");
					  break;
					default:
					  printStackTrace("Caught SIGFPE: Arithmetic Exception");
					  break;
				  }
				  case SIGILL:
						switch(siginfo->si_code) {
						  case ILL_ILLOPC:
							printStackTrace("Caught SIGILL: (illegal opcode)");
							break;
						  case ILL_ILLOPN:
							printStackTrace("Caught SIGILL: (illegal operand)");
							break;
						  case ILL_ILLADR:
							printStackTrace("Caught SIGILL: (illegal addressing mode)");
							break;
						  case ILL_ILLTRP:
							printStackTrace("Caught SIGILL: (illegal trap)");
							break;
						  case ILL_PRVOPC:
							printStackTrace("Caught SIGILL: (privileged opcode)");
							break;
						  case ILL_PRVREG:
							printStackTrace("Caught SIGILL: (privileged register)");
							break;
						  case ILL_COPROC:
							printStackTrace("Caught SIGILL: (coprocessor error)");
							break;
						  case ILL_BADSTK:
							printStackTrace("Caught SIGILL: (internal stack error)");
							break;
						  default:
							printStackTrace("Caught SIGILL: Illegal Instruction");
							break;
						}
						break;
					  case SIGTERM:
						printStackTrace("Caught SIGTERM: a termination request was sent to the program");
						break;
					  case SIGABRT:
						printStackTrace("Caught SIGABRT: usually caused by an abort() or assert()");
						break;
					  default:
						break;
					}
					_Exit(1);
				  }

			char alternate_stack[SIGSTKSZ*2];

			void set_signal_handler() {
			  /* setup alternate stack */
			  {
				stack_t ss;
				/* malloc is usually used here, I'm not 100% sure my static allocation
				   is valid but it seems to work just fine. */
				ss.ss_sp = (void*)alternate_stack;
				ss.ss_size = sizeof(alternate_stack);
				ss.ss_flags = 0;

				if (sigaltstack(&ss, NULL) != 0)
					std::cerr<<"failed to create alternate stack for handlers!"<<std::endl;
			  }

			  /* register our signal handlers */
			  {
				struct sigaction sig_action;
				sig_action.sa_sigaction = posix_signal_handler;
				sigemptyset(&sig_action.sa_mask);

				#ifdef __APPLE__
					/* for some reason we backtrace() doesn't work on osx
					   when we use an alternate stack */
					sig_action.sa_flags = SA_SIGINFO;
				#else
					sig_action.sa_flags = SA_SIGINFO | SA_ONSTACK;
				#endif

				if (sigaction(SIGSEGV, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGSEGV!");
				if (sigaction(SIGFPE,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGFPE!");
				if (sigaction(SIGINT,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGINT!");
				if (sigaction(SIGILL,  &sig_action, NULL) != 0) ERROR("failed to register handler for SIGILL!");
				if (sigaction(SIGTERM, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGTERM!");
				if (sigaction(SIGABRT, &sig_action, NULL) != 0) ERROR("failed to register handler for SIGABRT!");
			  }
			}
		}

		std::string gen_stacktrace(int framesToSkip) {
			std::stringstream ret;
			void *trace[32];

			auto trace_size = backtrace(trace, 32);
			char** messages = backtrace_symbols(trace, trace_size);

			/* skip first stack frame (points here) */

			bool first=true;

			for (auto i=1+framesToSkip; i<trace_size; ++i) {
				if(first) first=false;
				else      ret<<"Called From ";
				ret<<messages[i]<<std::endl<<"    "<<demangleStacktraceEntry(trace[i])<<std::endl;
			}

			return ret.str();
		}
	#endif
	}
	}

#else
	namespace core {
	namespace util {
		void init_stacktrace(std::string exeName) {
		}

		std::string gen_stacktrace(int stacksToSkip) {
			return "";
		}

		bool is_stacktrace_available() {
			return false;
		}
	}
	}
#endif
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc
 *
 *   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 "config.h"

#include <dirent.h>
#include <string.h>

#include "couch-kvstore/dirutils.h"

namespace CouchKVStoreDirectoryUtilities
{
    using namespace std;

    static string split(const string &input, bool directory)
    {
        string::size_type path = input.find_last_of("\\/");
        string file;
        string dir;

        if (path == string::npos) {
            dir = ".";
            file = input;
        } else {
            dir = input.substr(0, path);
            if (dir.length() == 0) {
                dir = input.substr(0, 1);
            }
            file = input.substr(path + 1);
        }

        if (directory) {
            return dir;
        } else {
            return file;
        }
    }

    string dirname(const string &dir)
    {
        return split(dir, true);
    }

    string basename(const string &name)
    {
        return split(name, false);
    }

    vector<string> findFilesWithPrefix(const string &dir, const string &name)
    {
        vector<string> files;
        DIR *dp = opendir(dir.c_str());
        if (dp != NULL) {
            struct dirent *de;
            while ((de = readdir(dp)) != NULL) {
                if (strncmp(de->d_name, name.c_str(), name.length()) == 0) {
                    string entry = dir;
                    entry.append("/");
                    entry.append(de->d_name);
                    files.push_back(entry);
                }
            }

            closedir(dp);
        }
        return files;
    }

    vector<string> findFilesWithPrefix(const string &name)
    {
        return findFilesWithPrefix(dirname(name), basename(name));
    }

    vector<string> findFilesContaining(const string &dir, const string &name)
    {
        vector<string> files;
        DIR *dp = opendir(dir.c_str());
        if (dp != NULL) {
            struct dirent *de;
            while ((de = readdir(dp)) != NULL) {
                if (name.empty() || strstr(de->d_name, name.c_str()) != NULL) {
                    string entry = dir;
                    entry.append("/");
                    entry.append(de->d_name);
                    files.push_back(entry);
                }
            }

            closedir(dp);
        }

        return files;
    }
}
<commit_msg>Fix directory utilities for win32<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2012 Couchbase, Inc
 *
 *   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 "config.h"

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

#include <string.h>

#include "couch-kvstore/dirutils.h"

namespace CouchKVStoreDirectoryUtilities
{
    using namespace std;

    static string split(const string &input, bool directory)
    {
        string::size_type path = input.find_last_of("\\/");
        string file;
        string dir;

        if (path == string::npos) {
            dir = ".";
            file = input;
        } else {
            dir = input.substr(0, path);
            if (dir.length() == 0) {
                dir = input.substr(0, 1);
            }
            file = input.substr(path + 1);
        }

        if (directory) {
            return dir;
        } else {
            return file;
        }
    }

    string dirname(const string &dir)
    {
        return split(dir, true);
    }

    string basename(const string &name)
    {
        return split(name, false);
    }

#ifdef _MSC_VER
    vector<string> findFilesWithPrefix(const string &dir, const string &name)
    {
        vector<string> files;
        std::string match = dir + "\\" + name + "*";
        WIN32_FIND_DATA FindFileData;

        HANDLE hFind = FindFirstFileEx(match.c_str(), FindExInfoStandard,
                                       &FindFileData, FindExSearchNameMatch,
                                       NULL, 0);

        if (hFind != INVALID_HANDLE_VALUE) {
            do {
                string entry = dir;
                entry.append("\\");
                entry.append(FindFileData.cFileName);
                files.push_back(entry);
            } while (FindNextFile(hFind, &FindFileData));

            FindClose(hFind);
        }
        return files;
    }
#else
    vector<string> findFilesWithPrefix(const string &dir, const string &name)
    {
        vector<string> files;
        DIR *dp = opendir(dir.c_str());
        if (dp != NULL) {
            struct dirent *de;
            while ((de = readdir(dp)) != NULL) {
                if (strncmp(de->d_name, name.c_str(), name.length()) == 0) {
                    string entry = dir;
                    entry.append("/");
                    entry.append(de->d_name);
                    files.push_back(entry);
                }
            }

            closedir(dp);
        }
        return files;
    }
#endif

    vector<string> findFilesWithPrefix(const string &name)
    {
        return findFilesWithPrefix(dirname(name), basename(name));
    }

#ifdef _MSC_VER
    vector<string> findFilesContaining(const string &dir, const string &name)
    {
        vector<string> files;
        std::string match = dir + "\\*" + name + "*";
        WIN32_FIND_DATA FindFileData;

        HANDLE hFind = FindFirstFileEx(match.c_str(), FindExInfoStandard,
                                       &FindFileData, FindExSearchNameMatch,
                                       NULL, 0);

        if (hFind != INVALID_HANDLE_VALUE) {
            do {
                string entry = dir;
                entry.append("\\");
                entry.append(FindFileData.cFileName);
                files.push_back(entry);
            } while (FindNextFile(hFind, &FindFileData));

            FindClose(hFind);
        }
        return files;
    }
#else
    vector<string> findFilesContaining(const string &dir, const string &name)
    {
        vector<string> files;
        DIR *dp = opendir(dir.c_str());
        if (dp != NULL) {
            struct dirent *de;
            while ((de = readdir(dp)) != NULL) {
                if (name.empty() || strstr(de->d_name, name.c_str()) != NULL) {
                    string entry = dir;
                    entry.append("/");
                    entry.append(de->d_name);
                    files.push_back(entry);
                }
            }

            closedir(dp);
        }

        return files;
    }
#endif
}
<|endoftext|>


<commit_before>#include "dashplayer.hpp"

using namespace player;

DashPlayer::DashPlayer(std::string MPD, string adaptionlogic_name, int interest_lifetime)
{
    this->adaptionlogic_name = adaptionlogic_name;
    this->interest_lifetime = interest_lifetime;

    streaming_active = false;

    mpd_url=MPD;
    mpd = NULL;

    base_url = "";

    max_buffered_seconds=50;
    mbuffer = boost::shared_ptr<MultimediaBuffer>(new MultimediaBuffer(max_buffered_seconds));

    //factory - to be replaced
    alogic = AdaptationLogicFactory::Create(adaptionlogic_name, this); //TODO
    downloader = boost::shared_ptr<FileDownloader>(new FileDownloader(this->interest_lifetime ));

    hasDownloadedAllSegments = false;
    isStalling=false;

    last_requestedRepresentation = NULL;
    last_requestedSegmentNr = 0;
}

DashPlayer::~DashPlayer()
{
}

void DashPlayer::startStreaming ()
{
  //1fetch MPD and parse MPD
  std::string mpd_path("/tmp/video.mpd");
  shared_ptr<itec::Buffer> mpd_data = downloader->getFile (mpd_url);

  if(mpd_data == NULL)
  {
    fprintf(stderr, "Error fetching MPD! Exiting..\n");
    return;
  }

  writeFileToDisk(mpd_data, mpd_path);

  fprintf(stderr, "parsing...\n");

  if(!parseMPD(mpd_path))
    return;

  alogic->SetAvailableRepresentations (availableRepresentations);

  //2. start streaming (1. thread)
  boost::thread downloadThread(&DashPlayer::scheduleDownloadNextSegment, this);

  //3. start consuming (2. thread)
  boost::thread playbackThread(&DashPlayer::schedulePlayback, this);

  //wait until threads finished
  downloadThread.join ();
  playbackThread.join ();

  exit(0);
}

void DashPlayer::scheduleDownloadNextSegment ()
{
  const dash::mpd::IRepresentation* requestedRepresentation = NULL;
  unsigned int requestedSegmentNr = 0;
  dash::mpd::ISegmentURL* requestedSegmentURL = alogic->GetNextSegment(&requestedSegmentNr, &requestedRepresentation, &hasDownloadedAllSegments);

  if(hasDownloadedAllSegments) // we got all segmetns, exit download thread
    return;

  if(requestedSegmentURL == NULL) // IDLE e.g. buffer is full
  {
    boost::this_thread::sleep(boost::posix_time::milliseconds(500));
    scheduleDownloadNextSegment();
    return;
  }

  fprintf(stderr, "downloading segment = %s\n",(base_url+requestedSegmentURL->GetMediaURI()).c_str ());

  last_requestedRepresentation = requestedRepresentation;
  last_requestedSegmentNr = requestedSegmentNr;

  shared_ptr<itec::Buffer> segmentData = downloader->getFile (base_url+requestedSegmentURL->GetMediaURI());

  if(segmentData != NULL)
  {
    mbuffer->addToBuffer (requestedSegmentNr, requestedRepresentation);
  }

  scheduleDownloadNextSegment();
}

void DashPlayer::schedulePlayback ()
{

  fprintf(stderr, "Schedule playback\n");

  unsigned int buffer_level = mbuffer->getBufferedSeconds();

  // did we finish streaming yet?
  if (buffer_level == 0 && hasDownloadedAllSegments == true)
     return; //finished streaming

  player::MultimediaBuffer::BufferRepresentationEntry entry = mbuffer->consumeFromBuffer ();
  double consumedSeconds = entry.segmentDuration;
  if ( consumedSeconds > 0)
  {
    fprintf(stderr, "Consumed Segment %d, with Rep %s for %f seconds\n",entry.segmentNumber,entry.repId.c_str(), entry.segmentDuration);

    if (isStalling)
    {
      boost::posix_time::ptime stallEndTime = boost::posix_time::ptime(boost::posix_time::microsec_clock::local_time());
      boost::posix_time::time_duration stallDuration;

      // we had a freeze/stall, but we can continue playing now
      stallDuration = (stallEndTime - stallStartTime);
      isStalling = false;
    }

    /*m_playerTracer(this, entry.segmentNumber, entry.segmentDuration, entry.repId,
                   entry.bitrate_bit_s, freezeTime, entry.depIds);*/
  }
  else
  {
    // could not consume, means buffer is empty
    if ( isStalling == false)
    {
      isStalling = true;
      stallStartTime = boost::posix_time::ptime(boost::posix_time::microsec_clock::local_time());
    }
  }

  if(consumedSeconds == 0.0) // we are stalling
  {
    //check for download abort
    if(last_requestedRepresentation != NULL && !hasDownloadedAllSegments && last_requestedRepresentation->GetDependencyId ().size ()>0)
    {
      if(alogic->hasMinBufferLevel (last_requestedRepresentation))
      {
        //TODO abort download of current segment!
      }
    }
    boost::this_thread::sleep(boost::posix_time::milliseconds(500));
  }
  else
  {
    boost::this_thread::sleep(boost::posix_time::milliseconds(consumedSeconds*1000));
  }
  schedulePlayback();
}

bool DashPlayer::parseMPD(std::string mpd_path)
{
  dash::IDASHManager *manager;
  manager = CreateDashManager();
  mpd = manager->Open((char*)mpd_path.c_str ());

  // We don't need the manager anymore...
  manager->Delete();
  manager = NULL;

  if (mpd == NULL)
  {
    fprintf(stderr, "MPD - Parsing Error. Exiting..\n");
    return false;
  }

  // we are assuming there is only 1 period, get the first one
  IPeriod *currentPeriod = mpd->GetPeriods().at(0);

  // get base URL (we take first always)
  std::vector<dash::mpd::IBaseUrl*> baseUrls = mpd->GetBaseUrls ();
  if(baseUrls.size () < 1)
  {
    fprintf(stderr, "No BaseUrl detected!\n");
    return false;
  }
  base_url = baseUrls.at (0)->GetUrl();

  // Get the adaptation sets, though we are only consider the first one
  std::vector<IAdaptationSet *> allAdaptationSets = currentPeriod->GetAdaptationSets();

  if (allAdaptationSets.size() < 1)
  {
    fprintf(stderr, "No adaptation sets found in MPD!\n");
    return false;
  }

  IAdaptationSet* adaptationSet = allAdaptationSets.at(0);
  std::vector<IRepresentation*> reps = adaptationSet->GetRepresentation();

  if(reps.size () < 1)
  {
    fprintf(stderr, "No represntations found in MPD!\n");
    return false;
  }

  availableRepresentations.clear();
  for (IRepresentation* rep : reps)
  {
    std::string repId = rep->GetId();
    availableRepresentations[repId] = rep;
  }

  return true;
}

void DashPlayer::writeFileToDisk(shared_ptr<itec::Buffer> buf, string file_path)
{
  ofstream outputStream;
  outputStream.open(file_path, ios::out | ios::binary);
  outputStream.write(buf->getData(), buf->getSize());
  outputStream.close();
}

//
// Main entry-point
//
int main(int argc, char** argv)
{
  string appName = boost::filesystem::basename(argv[0]);

  options_description desc("Programm Options");
  desc.add_options ()
      ("name,p", value<string>()->required (), "The name of the interest to be sent (Required)")
      ("adaptionlogic,a",value<string>()->required(), "The name of the adaption-logic to be used (Required)")
      ("lifetime,s", value<int>(), "The lifetime of the interest in milliseconds. (Default 1000ms)");

  positional_options_description positionalOptions;
  variables_map vm;

  try
  {
    store(command_line_parser(argc, argv).options(desc)
                .positional(positionalOptions).run(),
              vm); // throws on error

    notify(vm); //notify if required parameters are not provided.
  }
  catch(boost::program_options::required_option& e)
  {
    // user forgot to provide a required option
    cerr << "name           ... The name of the interest to be sent (Required)" << endl;
    cerr << "adaptionlogic  ... The name of the adaption-logic to be used (Required, buffer or rate)" << endl;
    cerr << "lifetime       ... The lifetime of the interest in milliseconds. (Default 1000ms)" << endl;
    cerr << "usage-example: " << "./" << appName << " --name /example/testApp/randomData --adaptionlogic buffer" << endl;
    cerr << "usage-example: " << "./" << appName << " --name /example/testApp/randomData --adaptionlogic buffer --lifetime 1000" << endl;

    cerr << "ERROR: " << e.what() << endl << endl;
    return -1;
  }
  catch(boost::program_options::error& e)
  {
    // a given parameter is faulty (e.g. given a string, asked for int)
    cerr << "ERROR: " << e.what() << endl << endl;
    return -1;
  }
  catch(exception& e)
  {
    cerr << "Unhandled Exception reached the top of main: "
              << e.what() << ", application will now exit" << endl;
    return -1;
  }

  int lifetime = 1000;
  if(vm.count ("lifetime"))
  {
    lifetime = vm["lifetime"].as<int>();
  }

  // create new DashPlayer instance with given parameters
  DashPlayer consumer(vm["name"].as<string>(),vm["adaptionlogic"].as<string>(), lifetime);

  try
  {
    //get MPD and start streaming
    consumer.startStreaming();
  }
  catch (const exception& e)
  {
    // shit happens
    cerr << "ERROR: " << e.what() << endl;
  }

  return 0;
}

double DashPlayer::GetBufferLevel(std::string repId)
{
  if(repId.compare ("NULL") == 0)
    return mbuffer->getBufferedSeconds ();
  else
    return mbuffer->getBufferedSeconds (repId);
}

unsigned int DashPlayer::nextSegmentNrToConsume ()
{
  return mbuffer->nextSegmentNrToBeConsumed ();
}

unsigned int DashPlayer::getHighestBufferedSegmentNr(std::string repId)
{
  return mbuffer->getHighestBufferedSegmentNr (repId);
}
<commit_msg>added "http" replacment for baseurl.<commit_after>#include "dashplayer.hpp"

using namespace player;

DashPlayer::DashPlayer(std::string MPD, string adaptionlogic_name, int interest_lifetime)
{
    this->adaptionlogic_name = adaptionlogic_name;
    this->interest_lifetime = interest_lifetime;

    streaming_active = false;

    mpd_url=MPD;
    mpd = NULL;

    base_url = "";

    max_buffered_seconds=50;
    mbuffer = boost::shared_ptr<MultimediaBuffer>(new MultimediaBuffer(max_buffered_seconds));

    //factory - to be replaced
    alogic = AdaptationLogicFactory::Create(adaptionlogic_name, this); //TODO
    downloader = boost::shared_ptr<FileDownloader>(new FileDownloader(this->interest_lifetime ));

    hasDownloadedAllSegments = false;
    isStalling=false;

    last_requestedRepresentation = NULL;
    last_requestedSegmentNr = 0;
}

DashPlayer::~DashPlayer()
{
}

void DashPlayer::startStreaming ()
{
  //1fetch MPD and parse MPD
  std::string mpd_path("/tmp/video.mpd");
  shared_ptr<itec::Buffer> mpd_data = downloader->getFile (mpd_url);

  if(mpd_data == NULL)
  {
    fprintf(stderr, "Error fetching MPD! Exiting..\n");
    return;
  }

  writeFileToDisk(mpd_data, mpd_path);

  fprintf(stderr, "parsing...\n");

  if(!parseMPD(mpd_path))
    return;

  alogic->SetAvailableRepresentations (availableRepresentations);

  //2. start streaming (1. thread)
  boost::thread downloadThread(&DashPlayer::scheduleDownloadNextSegment, this);

  //3. start consuming (2. thread)
  boost::thread playbackThread(&DashPlayer::schedulePlayback, this);

  //wait until threads finished
  downloadThread.join ();
  playbackThread.join ();

  exit(0);
}

void DashPlayer::scheduleDownloadNextSegment ()
{
  const dash::mpd::IRepresentation* requestedRepresentation = NULL;
  unsigned int requestedSegmentNr = 0;
  dash::mpd::ISegmentURL* requestedSegmentURL = alogic->GetNextSegment(&requestedSegmentNr, &requestedRepresentation, &hasDownloadedAllSegments);

  if(hasDownloadedAllSegments) // we got all segmetns, exit download thread
    return;

  if(requestedSegmentURL == NULL) // IDLE e.g. buffer is full
  {
    boost::this_thread::sleep(boost::posix_time::milliseconds(500));
    scheduleDownloadNextSegment();
    return;
  }

  fprintf(stderr, "downloading segment = %s\n",(base_url+requestedSegmentURL->GetMediaURI()).c_str ());

  last_requestedRepresentation = requestedRepresentation;
  last_requestedSegmentNr = requestedSegmentNr;

  shared_ptr<itec::Buffer> segmentData = downloader->getFile (base_url+requestedSegmentURL->GetMediaURI());

  if(segmentData != NULL)
  {
    mbuffer->addToBuffer (requestedSegmentNr, requestedRepresentation);
  }

  scheduleDownloadNextSegment();
}

void DashPlayer::schedulePlayback ()
{

  fprintf(stderr, "Schedule playback\n");

  unsigned int buffer_level = mbuffer->getBufferedSeconds();

  // did we finish streaming yet?
  if (buffer_level == 0 && hasDownloadedAllSegments == true)
     return; //finished streaming

  player::MultimediaBuffer::BufferRepresentationEntry entry = mbuffer->consumeFromBuffer ();
  double consumedSeconds = entry.segmentDuration;
  if ( consumedSeconds > 0)
  {
    fprintf(stderr, "Consumed Segment %d, with Rep %s for %f seconds\n",entry.segmentNumber,entry.repId.c_str(), entry.segmentDuration);

    if (isStalling)
    {
      boost::posix_time::ptime stallEndTime = boost::posix_time::ptime(boost::posix_time::microsec_clock::local_time());
      boost::posix_time::time_duration stallDuration;

      // we had a freeze/stall, but we can continue playing now
      stallDuration = (stallEndTime - stallStartTime);
      isStalling = false;
    }

    /*m_playerTracer(this, entry.segmentNumber, entry.segmentDuration, entry.repId,
                   entry.bitrate_bit_s, freezeTime, entry.depIds);*/
  }
  else
  {
    // could not consume, means buffer is empty
    if ( isStalling == false)
    {
      isStalling = true;
      stallStartTime = boost::posix_time::ptime(boost::posix_time::microsec_clock::local_time());
    }
  }

  if(consumedSeconds == 0.0) // we are stalling
  {
    //check for download abort
    if(last_requestedRepresentation != NULL && !hasDownloadedAllSegments && last_requestedRepresentation->GetDependencyId ().size ()>0)
    {
      if(alogic->hasMinBufferLevel (last_requestedRepresentation))
      {
        //TODO abort download of current segment!
      }
    }
    boost::this_thread::sleep(boost::posix_time::milliseconds(500));
  }
  else
  {
    boost::this_thread::sleep(boost::posix_time::milliseconds(consumedSeconds*1000));
  }
  schedulePlayback();
}

bool DashPlayer::parseMPD(std::string mpd_path)
{
  dash::IDASHManager *manager;
  manager = CreateDashManager();
  mpd = manager->Open((char*)mpd_path.c_str ());

  // We don't need the manager anymore...
  manager->Delete();
  manager = NULL;

  if (mpd == NULL)
  {
    fprintf(stderr, "MPD - Parsing Error. Exiting..\n");
    return false;
  }

  // we are assuming there is only 1 period, get the first one
  IPeriod *currentPeriod = mpd->GetPeriods().at(0);

  // get base URL (we take first always)
  std::vector<dash::mpd::IBaseUrl*> baseUrls = mpd->GetBaseUrls ();
  if(baseUrls.size () < 1)
  {
    fprintf(stderr, "No BaseUrl detected!\n");
    return false;
  }
  base_url = baseUrls.at (0)->GetUrl();
  if(base_url.substr (0,7).compare ("http://") == 0)
    base_url = base_url.substr(6,base_url.length ());

  // Get the adaptation sets, though we are only consider the first one
  std::vector<IAdaptationSet *> allAdaptationSets = currentPeriod->GetAdaptationSets();

  if (allAdaptationSets.size() < 1)
  {
    fprintf(stderr, "No adaptation sets found in MPD!\n");
    return false;
  }

  IAdaptationSet* adaptationSet = allAdaptationSets.at(0);
  std::vector<IRepresentation*> reps = adaptationSet->GetRepresentation();

  if(reps.size () < 1)
  {
    fprintf(stderr, "No represntations found in MPD!\n");
    return false;
  }

  availableRepresentations.clear();
  for (IRepresentation* rep : reps)
  {
    std::string repId = rep->GetId();
    availableRepresentations[repId] = rep;
  }

  return true;
}

void DashPlayer::writeFileToDisk(shared_ptr<itec::Buffer> buf, string file_path)
{
  ofstream outputStream;
  outputStream.open(file_path, ios::out | ios::binary);
  outputStream.write(buf->getData(), buf->getSize());
  outputStream.close();
}

//
// Main entry-point
//
int main(int argc, char** argv)
{
  string appName = boost::filesystem::basename(argv[0]);

  options_description desc("Programm Options");
  desc.add_options ()
      ("name,p", value<string>()->required (), "The name of the interest to be sent (Required)")
      ("adaptionlogic,a",value<string>()->required(), "The name of the adaption-logic to be used (Required)")
      ("lifetime,s", value<int>(), "The lifetime of the interest in milliseconds. (Default 1000ms)");

  positional_options_description positionalOptions;
  variables_map vm;

  try
  {
    store(command_line_parser(argc, argv).options(desc)
                .positional(positionalOptions).run(),
              vm); // throws on error

    notify(vm); //notify if required parameters are not provided.
  }
  catch(boost::program_options::required_option& e)
  {
    // user forgot to provide a required option
    cerr << "name           ... The name of the interest to be sent (Required)" << endl;
    cerr << "adaptionlogic  ... The name of the adaption-logic to be used (Required, buffer or rate)" << endl;
    cerr << "lifetime       ... The lifetime of the interest in milliseconds. (Default 1000ms)" << endl;
    cerr << "usage-example: " << "./" << appName << " --name /example/testApp/randomData --adaptionlogic buffer" << endl;
    cerr << "usage-example: " << "./" << appName << " --name /example/testApp/randomData --adaptionlogic buffer --lifetime 1000" << endl;

    cerr << "ERROR: " << e.what() << endl << endl;
    return -1;
  }
  catch(boost::program_options::error& e)
  {
    // a given parameter is faulty (e.g. given a string, asked for int)
    cerr << "ERROR: " << e.what() << endl << endl;
    return -1;
  }
  catch(exception& e)
  {
    cerr << "Unhandled Exception reached the top of main: "
              << e.what() << ", application will now exit" << endl;
    return -1;
  }

  int lifetime = 1000;
  if(vm.count ("lifetime"))
  {
    lifetime = vm["lifetime"].as<int>();
  }

  // create new DashPlayer instance with given parameters
  DashPlayer consumer(vm["name"].as<string>(),vm["adaptionlogic"].as<string>(), lifetime);

  try
  {
    //get MPD and start streaming
    consumer.startStreaming();
  }
  catch (const exception& e)
  {
    // shit happens
    cerr << "ERROR: " << e.what() << endl;
  }

  return 0;
}

double DashPlayer::GetBufferLevel(std::string repId)
{
  if(repId.compare ("NULL") == 0)
    return mbuffer->getBufferedSeconds ();
  else
    return mbuffer->getBufferedSeconds (repId);
}

unsigned int DashPlayer::nextSegmentNrToConsume ()
{
  return mbuffer->nextSegmentNrToBeConsumed ();
}

unsigned int DashPlayer::getHighestBufferedSegmentNr(std::string repId)
{
  return mbuffer->getHighestBufferedSegmentNr (repId);
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015, Jozef Stefan Institute, Quintelligence d.o.o. and contributors
 * All rights reserved.
 *
 * This source code is licensed under the FreeBSD license found in the
 * LICENSE file in the root directory of this source tree.
 */

using namespace TRegression;

///////////////////////////////////////////
// Logistic Regression
TLogReg::TLogReg(const double& _Lambda, const bool _IncludeIntercept, const bool _Verbose):
		Lambda(_Lambda),
		WgtV(),
		IncludeIntercept(_IncludeIntercept),
		Verbose(_Verbose),
		Notify(Verbose ? TNotify::StdNotify : TNotify::NullNotify) {}

TLogReg::TLogReg(TSIn& SIn):
		Lambda(TFlt(SIn)),
		WgtV(SIn),
		IncludeIntercept(TBool(SIn)),
		Verbose(TBool(SIn)),
		Notify(nullptr) {

	Notify = Verbose ? TNotify::StdNotify : TNotify::NullNotify;
}

void TLogReg::Save(TSOut& SOut) const {
	TFlt(Lambda).Save(SOut);
	WgtV.Save(SOut);
	TBool(IncludeIntercept).Save(SOut);
	TBool(Verbose).Save(SOut);
}

void TLogReg::Fit(const TFltVV& _X, const TFltV& y, const double& Eps) {
	TFltVV X(_X);

	if (IncludeIntercept) {
		// add 1s into the last row
		X.AddXDim();
		for (int i = 0; i < X.GetCols(); i++) {
			X(X.GetRows()-1, i) = 1;
		}
	}

	const int NInst = X.GetCols();
	const int Dim = X.GetRows();
	const int OrigDim = IncludeIntercept ? Dim-1 : Dim;

	// minimize the following objective function:
	// L(w) = (sum(log(1 + exp(w*x_i)) - y_i*w*x_i) + lambda*beta*beta'/2) / m
	// using Newton-Raphson algorithm:
	// w <- w - H^(-1)(w)*g(w)
	// g(w) = (X*(s(beta*x) - y)' + lambda*beta')
	// H(w) = X*W*X^(-1) + lambda*I
	// where H is the Hessian at point w, g is the gradient of the objective function at point w
	// W is a diagonal matrix defined as W_ii = p_i(1 - p_i)

	// temporary variables
	TFltV ProbV(NInst, NInst);					// vector of probabilities
	TFltV PrevProbV(NInst, NInst);				// vector of probs in the previous step, used to terminate the procedure
	TFltV DeltaWgtV(Dim, Dim);					// the step used to update the weights
	TFltV YMinP(NInst, NInst);
	TFltV GradV(Dim, Dim);						// gradient
	TFltVV XTimesW(Dim, NInst);					// temporary variable to compute (X*W)*X'
	TFltVV H(Dim, Dim);							// Hessian
	TFltVV X_t(X.GetCols(), X.GetRows());	TLinAlg::Transpose(X, X_t);		// the transposed instance matrix
	TVec<TIntFltKdV> WgtColSpVV(NInst, NInst);	// weight matrix

	// generate weight matrix with only ones on the diagonal
	// so you don't recreate all the object every iteration
	for (int i = 0; i < NInst; i++) {
		WgtColSpVV[i].Add(TIntFltKd(i, 1));
	}

	WgtV.Gen(Dim);

	// perform the algorithm
	double Diff = TFlt::NInf;
	double AbsDiff;
	int k = 1;
	do {
		if (k % 10 == 0) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Step: %d, diff: %.3f", k, Diff);
		}

		// compute the probabilities p_i = 1 / (1 + exp(-w*x_i)) and
		// compute the weight matrix diagonal W_ii = p_i(1 - p_i)
		TLinAlg::Multiply(X_t, WgtV, ProbV);
		for (int i = 0; i < NInst; i++) {
			ProbV[i] = 1 / (1 + TMath::Power(TMath::E, -ProbV[i]));
			WgtColSpVV[i][0].Dat = ProbV[i]*(1 - ProbV[i]);
		}

		// compute the Hessian H = X*W*X' + lambda*I
		// 1) compute X*W
		TLinAlg::Multiply(X, WgtColSpVV, XTimesW);
		// 2) compute H = (X*W)*X'
		TLinAlg::Multiply(XTimesW, X_t, H);
		// 3) add lambda to the diagonal of H, exclude the punishment for the intercept
		for (int i = 0; i < OrigDim; i++) {
			H(i,i) += Lambda;
		}

		// compute the gradient g(w) = X*(y - p)' + lambda * w
		// 1) compute (y - p)
		TLinAlg::LinComb(1, y, -1, ProbV, YMinP);
		// 2) compute X*(y - p)
		TLinAlg::Multiply(X, YMinP, GradV);
		// 3) add lambda * w, exclude the punishment for the intercept
		for (int i = 0; i < OrigDim; i++) {
			GradV[i] += Lambda*WgtV[i];
		}

		// compute delta_w = H(w) \ (g(w))
#ifdef LAPACKE
		const TFlt SingEps = 1e-10;

		if (H.GetRows() == 1) {	// fix for a bug in SVD factorization
			DeltaWgtV[0] = GradV[0] / H(0,0);
		} else {
			TLinAlg::SVDSolve(H, DeltaWgtV, GradV, SingEps);
		}
#else
		throw TExcept::New("Should include LAPACKE!!");
#endif

		if (TFlt::IsNan(TLinAlg::Norm(DeltaWgtV))) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Got NaNs while fitting logistic regression! The weights could still be OK.");
			break;
		}

		// update the current weight vector
		for (int i = 0; i < Dim; i++) {
			WgtV[i] += DeltaWgtV[i];
		}

		// recompute the termination criteria and store the probabilities for
		// the next iteration
		Diff = TFlt::NInf;
		for (int i = 0; i < NInst; i++) {
			AbsDiff = TFlt::Abs(PrevProbV[i] - ProbV[i]);
			if (AbsDiff > Diff) { Diff = AbsDiff; }

			PrevProbV[i] = ProbV[i];
		}

		k++;
	} while (Diff > Eps);

	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Converged. Diff: %.5f", Diff);
}

double TLogReg::Predict(const TFltV& x) const {
	if (IncludeIntercept) {
		TFltV x1(x);	x1.Add(1);
		return PredictWithoutIntercept(x1);
	} else {
		return PredictWithoutIntercept(x);
	}
}

void TLogReg::GetWgtV(TFltV& _WgtV) const {
	_WgtV = WgtV;
	if (IncludeIntercept) {
		_WgtV.DelLast();
	}
}

double TLogReg::PredictWithoutIntercept(const TFltV& x) const {
	if (!Initialized()) { return 0; }
	EAssertR(x.Len() == WgtV.Len(), "Dimension mismatch while predicting!");
	return 1 / (1 + TMath::Power(TMath::E, -TLinAlg::DotProduct(WgtV, x)));
}

///////////////////////////////////////////
// Proportional Hazards model

TPropHazards::TPropHazards(const double& _Lambda, const bool _Verbose):
		Lambda(_Lambda),
		WgtV(),
		Verbose(_Verbose),
		Notify(_Verbose ? TNotify::StdNotify : TNotify::NullNotify) {}

TPropHazards::TPropHazards(TSIn& SIn):
		Lambda(TFlt(SIn)),
		WgtV(SIn),
		Verbose(TBool(SIn)) {
	Notify = Verbose ? TNotify::StdNotify : TNotify::NullNotify;
}

void TPropHazards::Save(TSOut& SOut) const {
	TFlt(Lambda).Save(SOut);
	WgtV.Save(SOut);
	TBool(Verbose).Save(SOut);
}

void TPropHazards::Fit(const TFltVV& _X, const TFltV& t, const double& Eps) {
	const int NInst = _X.GetCols();
	const int Dim = _X.GetRows() + 1;

	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Fitting proportional hazards model on %d instances ...", NInst);

	TFltVV X(_X.GetRows()+1, NInst);
	for (int ColN = 0; ColN < NInst; ColN++) {
		X(0, ColN) = 1;
		for (int RowN = 0; RowN < _X.GetRows(); RowN++) {
			X(RowN+1, ColN) = _X(RowN, ColN);
		}
	}

	WgtV.Gen(Dim);

	TFltVV X_t(X);	X_t.Transpose();	// TODO slow
	TFltVV XTimesW(X.GetRows(), X.GetCols());
	TFltVV H(Dim, Dim);

	TFltV TempNInstV(NInst, NInst);
	TFltV GradV(Dim, Dim);
	TFltV DeltaWgtV(Dim, Dim);
	TSpVV WgtColSpVV(NInst, NInst);

	double IntensTimesT;

	// generate weight matrix with only ones on the diagonal
	// so you don't recreate all the object every iteration
	for (int i = 0; i < NInst; i++) {
		WgtColSpVV[i].Add(TIntFltKd(i, 1));
	}

	int k = 0;
	double Diff = TFlt::PInf;
	while (Diff > Eps) {
		// construct the intensity vector
		PredictInternal(X, TempNInstV);

		// I) construct the Hessian: X*W*X' + lambda*I
		// prepare W and t .* intens - 1
		for (int i = 0; i < NInst; i++) {
			IntensTimesT = t[i] * TempNInstV[i];
			TempNInstV[i] = IntensTimesT - 1;
			WgtColSpVV[i][0].Dat = IntensTimesT;
		}
		// 1) compute X*W
		TLinAlg::Multiply(X, WgtColSpVV, XTimesW);
		// 2) compute (X*W)*X'
		TLinAlg::Multiply(XTimesW, X_t, H);
		// 3) (X*W*X') + lambda*I, exclude the base hazard
		if (Lambda > 0) {
			for (int i = 1; i < Dim; i++) {
				H(i,i) += Lambda;
			}
		}

		// II) construct the gradient: (t .* intens - 1) * X' + lambda*[0, w(2:end)]
		// 1) (t .* intens - 1) * X'
		TLinAlg::Multiply(X, TempNInstV, GradV);
		// 2) ((t .* intens - 1) * X') + lambda*[0, w(2:end)]
		if (Lambda > 0) {
			for (int i = 1; i < Dim; i++) {
				GradV[i] += Lambda * WgtV[i];
			}
		}

		// III) compute: delta_w = H \ grad
#ifdef LAPACKE
		const TFlt SingEps = 1e-10;

		if (H.GetRows() == 1) {	// fix for a bug in SVD factorization
			DeltaWgtV[0] = GradV[0] / H(0,0);
		} else {
			TLinAlg::SVDSolve(H, DeltaWgtV, GradV, SingEps);
		}
#else
		throw TExcept::New("Should include LAPACKE!!");
#endif

		// IV) w <= w - delta_w
		for (int i = 0; i < Dim; i++) {
			WgtV[i] -= DeltaWgtV[i];
		}

		Diff = TLinAlg::Norm(DeltaWgtV);
		EAssertR(!TFlt::IsNan(Diff), "nans in delta wgt vector!");

		if (++k % 10 == 0) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Step: %d, diff: %.3f", k, Diff);
		}
	}

	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Converged. Diff: %.5f", Diff);
}

double TPropHazards::Predict(const TFltV& x) const {
	if (WgtV.Empty()) { return 0; }

	double Pred = WgtV[0];
	for (int i = 1; i < WgtV.Len(); i++) {
		Pred += x[i-1]*WgtV[i];
	}

	return exp(Pred);
}

void TPropHazards::GetWgtV(TFltV& _WgtV) const {
	for (int i = 1; i < WgtV.Len(); i++) {
		_WgtV.Add(WgtV[i]);
	}
}

void TPropHazards::PredictInternal(const TFltVV& X, TFltV& IntensV) const {
	const int NInst = X.GetCols();

	TLinAlg::MultiplyT(X, WgtV, IntensV);
	for (int i = 0; i < NInst; i++) {
		IntensV[i] = exp(IntensV[i]);
	}
}

/////////////////////////////////////////////
// Ridge Regression
void TRidgeReg::Fit(const TFltVV& X, const TFltV& y) {
    TNumericalStuff::LeastSquares(X, y, Gamma, WgtV);
}

double TRidgeReg::Predict(const TFltV& x) const {
    EAssertR(x.Len() == WgtV.Len(), "TRegression::TRidgeReg::Predict: model and data dimension mismatch");
    return TLinAlg::DotProduct(x, WgtV);
}

<commit_msg>added asserts that check for input consistency in logistic regression and proportional hazards model<commit_after>/**
 * Copyright (c) 2015, Jozef Stefan Institute, Quintelligence d.o.o. and contributors
 * All rights reserved.
 *
 * This source code is licensed under the FreeBSD license found in the
 * LICENSE file in the root directory of this source tree.
 */

using namespace TRegression;

///////////////////////////////////////////
// Logistic Regression
TLogReg::TLogReg(const double& _Lambda, const bool _IncludeIntercept, const bool _Verbose):
		Lambda(_Lambda),
		WgtV(),
		IncludeIntercept(_IncludeIntercept),
		Verbose(_Verbose),
		Notify(Verbose ? TNotify::StdNotify : TNotify::NullNotify) {}

TLogReg::TLogReg(TSIn& SIn):
		Lambda(TFlt(SIn)),
		WgtV(SIn),
		IncludeIntercept(TBool(SIn)),
		Verbose(TBool(SIn)),
		Notify(nullptr) {

	Notify = Verbose ? TNotify::StdNotify : TNotify::NullNotify;
}

void TLogReg::Save(TSOut& SOut) const {
	TFlt(Lambda).Save(SOut);
	WgtV.Save(SOut);
	TBool(IncludeIntercept).Save(SOut);
	TBool(Verbose).Save(SOut);
}

void TLogReg::Fit(const TFltVV& _X, const TFltV& y, const double& Eps) {
	TFltVV X(_X);

	if (IncludeIntercept) {
		// add 1s into the last row
		X.AddXDim();
		for (int i = 0; i < X.GetCols(); i++) {
			X(X.GetRows()-1, i) = 1;
		}
	}

	const int NInst = X.GetCols();
	const int Dim = X.GetRows();
	const int OrigDim = IncludeIntercept ? Dim-1 : Dim;
	EAssertR(NInst == y.Len(), "TLogReg::Fit the number of instances in X.GetCols() and y.Len() do not match");
	// minimize the following objective function:
	// L(w) = (sum(log(1 + exp(w*x_i)) - y_i*w*x_i) + lambda*beta*beta'/2) / m
	// using Newton-Raphson algorithm:
	// w <- w - H^(-1)(w)*g(w)
	// g(w) = (X*(s(beta*x) - y)' + lambda*beta')
	// H(w) = X*W*X^(-1) + lambda*I
	// where H is the Hessian at point w, g is the gradient of the objective function at point w
	// W is a diagonal matrix defined as W_ii = p_i(1 - p_i)

	// temporary variables
	TFltV ProbV(NInst, NInst);					// vector of probabilities
	TFltV PrevProbV(NInst, NInst);				// vector of probs in the previous step, used to terminate the procedure
	TFltV DeltaWgtV(Dim, Dim);					// the step used to update the weights
	TFltV YMinP(NInst, NInst);
	TFltV GradV(Dim, Dim);						// gradient
	TFltVV XTimesW(Dim, NInst);					// temporary variable to compute (X*W)*X'
	TFltVV H(Dim, Dim);							// Hessian
	TFltVV X_t(X.GetCols(), X.GetRows());	TLinAlg::Transpose(X, X_t);		// the transposed instance matrix
	TVec<TIntFltKdV> WgtColSpVV(NInst, NInst);	// weight matrix

	// generate weight matrix with only ones on the diagonal
	// so you don't recreate all the object every iteration
	for (int i = 0; i < NInst; i++) {
		WgtColSpVV[i].Add(TIntFltKd(i, 1));
	}

	WgtV.Gen(Dim);

	// perform the algorithm
	double Diff = TFlt::NInf;
	double AbsDiff;
	int k = 1;
	do {
		if (k % 10 == 0) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Step: %d, diff: %.3f", k, Diff);
		}

		// compute the probabilities p_i = 1 / (1 + exp(-w*x_i)) and
		// compute the weight matrix diagonal W_ii = p_i(1 - p_i)
		TLinAlg::Multiply(X_t, WgtV, ProbV);
		for (int i = 0; i < NInst; i++) {
			ProbV[i] = 1 / (1 + TMath::Power(TMath::E, -ProbV[i]));
			WgtColSpVV[i][0].Dat = ProbV[i]*(1 - ProbV[i]);
		}

		// compute the Hessian H = X*W*X' + lambda*I
		// 1) compute X*W
		TLinAlg::Multiply(X, WgtColSpVV, XTimesW);
		// 2) compute H = (X*W)*X'
		TLinAlg::Multiply(XTimesW, X_t, H);
		// 3) add lambda to the diagonal of H, exclude the punishment for the intercept
		for (int i = 0; i < OrigDim; i++) {
			H(i,i) += Lambda;
		}

		// compute the gradient g(w) = X*(y - p)' + lambda * w
		// 1) compute (y - p)
		TLinAlg::LinComb(1, y, -1, ProbV, YMinP);
		// 2) compute X*(y - p)
		TLinAlg::Multiply(X, YMinP, GradV);
		// 3) add lambda * w, exclude the punishment for the intercept
		for (int i = 0; i < OrigDim; i++) {
			GradV[i] += Lambda*WgtV[i];
		}

		// compute delta_w = H(w) \ (g(w))
#ifdef LAPACKE
		const TFlt SingEps = 1e-10;

		if (H.GetRows() == 1) {	// fix for a bug in SVD factorization
			DeltaWgtV[0] = GradV[0] / H(0,0);
		} else {
			TLinAlg::SVDSolve(H, DeltaWgtV, GradV, SingEps);
		}
#else
		throw TExcept::New("Should include LAPACKE!!");
#endif

		if (TFlt::IsNan(TLinAlg::Norm(DeltaWgtV))) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Got NaNs while fitting logistic regression! The weights could still be OK.");
			break;
		}

		// update the current weight vector
		for (int i = 0; i < Dim; i++) {
			WgtV[i] += DeltaWgtV[i];
		}

		// recompute the termination criteria and store the probabilities for
		// the next iteration
		Diff = TFlt::NInf;
		for (int i = 0; i < NInst; i++) {
			AbsDiff = TFlt::Abs(PrevProbV[i] - ProbV[i]);
			if (AbsDiff > Diff) { Diff = AbsDiff; }

			PrevProbV[i] = ProbV[i];
		}

		k++;
	} while (Diff > Eps);

	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Converged. Diff: %.5f", Diff);
}

double TLogReg::Predict(const TFltV& x) const {
	if (IncludeIntercept) {
		TFltV x1(x);	x1.Add(1);
		return PredictWithoutIntercept(x1);
	} else {
		return PredictWithoutIntercept(x);
	}
}

void TLogReg::GetWgtV(TFltV& _WgtV) const {
	_WgtV = WgtV;
	if (IncludeIntercept) {
		_WgtV.DelLast();
	}
}

double TLogReg::PredictWithoutIntercept(const TFltV& x) const {
	if (!Initialized()) { return 0; }
	EAssertR(x.Len() == WgtV.Len(), "Dimension mismatch while predicting!");
	return 1 / (1 + TMath::Power(TMath::E, -TLinAlg::DotProduct(WgtV, x)));
}

///////////////////////////////////////////
// Proportional Hazards model

TPropHazards::TPropHazards(const double& _Lambda, const bool _Verbose):
		Lambda(_Lambda),
		WgtV(),
		Verbose(_Verbose),
		Notify(_Verbose ? TNotify::StdNotify : TNotify::NullNotify) {}

TPropHazards::TPropHazards(TSIn& SIn):
		Lambda(TFlt(SIn)),
		WgtV(SIn),
		Verbose(TBool(SIn)) {
	Notify = Verbose ? TNotify::StdNotify : TNotify::NullNotify;
}

void TPropHazards::Save(TSOut& SOut) const {
	TFlt(Lambda).Save(SOut);
	WgtV.Save(SOut);
	TBool(Verbose).Save(SOut);
}

void TPropHazards::Fit(const TFltVV& _X, const TFltV& t, const double& Eps) {
	const int NInst = _X.GetCols();
	const int Dim = _X.GetRows() + 1;
	EAssertR(NInst == t.Len(), "TPropHazards::Fit the number of instances in X.GetCols() and t.Len() do not match");
	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Fitting proportional hazards model on %d instances ...", NInst);

	TFltVV X(_X.GetRows()+1, NInst);
	for (int ColN = 0; ColN < NInst; ColN++) {
		X(0, ColN) = 1;
		for (int RowN = 0; RowN < _X.GetRows(); RowN++) {
			X(RowN+1, ColN) = _X(RowN, ColN);
		}
	}

	WgtV.Gen(Dim);

	TFltVV X_t(X);	X_t.Transpose();	// TODO slow
	TFltVV XTimesW(X.GetRows(), X.GetCols());
	TFltVV H(Dim, Dim);

	TFltV TempNInstV(NInst, NInst);
	TFltV GradV(Dim, Dim);
	TFltV DeltaWgtV(Dim, Dim);
	TSpVV WgtColSpVV(NInst, NInst);

	double IntensTimesT;

	// generate weight matrix with only ones on the diagonal
	// so you don't recreate all the object every iteration
	for (int i = 0; i < NInst; i++) {
		WgtColSpVV[i].Add(TIntFltKd(i, 1));
	}

	int k = 0;
	double Diff = TFlt::PInf;
	while (Diff > Eps) {
		// construct the intensity vector
		PredictInternal(X, TempNInstV);

		// I) construct the Hessian: X*W*X' + lambda*I
		// prepare W and t .* intens - 1
		for (int i = 0; i < NInst; i++) {
			IntensTimesT = t[i] * TempNInstV[i];
			TempNInstV[i] = IntensTimesT - 1;
			WgtColSpVV[i][0].Dat = IntensTimesT;
		}
		// 1) compute X*W
		TLinAlg::Multiply(X, WgtColSpVV, XTimesW);
		// 2) compute (X*W)*X'
		TLinAlg::Multiply(XTimesW, X_t, H);
		// 3) (X*W*X') + lambda*I, exclude the base hazard
		if (Lambda > 0) {
			for (int i = 1; i < Dim; i++) {
				H(i,i) += Lambda;
			}
		}

		// II) construct the gradient: (t .* intens - 1) * X' + lambda*[0, w(2:end)]
		// 1) (t .* intens - 1) * X'
		TLinAlg::Multiply(X, TempNInstV, GradV);
		// 2) ((t .* intens - 1) * X') + lambda*[0, w(2:end)]
		if (Lambda > 0) {
			for (int i = 1; i < Dim; i++) {
				GradV[i] += Lambda * WgtV[i];
			}
		}

		// III) compute: delta_w = H \ grad
#ifdef LAPACKE
		const TFlt SingEps = 1e-10;

		if (H.GetRows() == 1) {	// fix for a bug in SVD factorization
			DeltaWgtV[0] = GradV[0] / H(0,0);
		} else {
			TLinAlg::SVDSolve(H, DeltaWgtV, GradV, SingEps);
		}
#else
		throw TExcept::New("Should include LAPACKE!!");
#endif

		// IV) w <= w - delta_w
		for (int i = 0; i < Dim; i++) {
			WgtV[i] -= DeltaWgtV[i];
		}

		Diff = TLinAlg::Norm(DeltaWgtV);
		EAssertR(!TFlt::IsNan(Diff), "nans in delta wgt vector!");

		if (++k % 10 == 0) {
			Notify->OnNotifyFmt(TNotifyType::ntInfo, "Step: %d, diff: %.3f", k, Diff);
		}
	}

	Notify->OnNotifyFmt(TNotifyType::ntInfo, "Converged. Diff: %.5f", Diff);
}

double TPropHazards::Predict(const TFltV& x) const {
	if (WgtV.Empty()) { return 0; }

	double Pred = WgtV[0];
	for (int i = 1; i < WgtV.Len(); i++) {
		Pred += x[i-1]*WgtV[i];
	}

	return exp(Pred);
}

void TPropHazards::GetWgtV(TFltV& _WgtV) const {
	for (int i = 1; i < WgtV.Len(); i++) {
		_WgtV.Add(WgtV[i]);
	}
}

void TPropHazards::PredictInternal(const TFltVV& X, TFltV& IntensV) const {
	const int NInst = X.GetCols();

	TLinAlg::MultiplyT(X, WgtV, IntensV);
	for (int i = 0; i < NInst; i++) {
		IntensV[i] = exp(IntensV[i]);
	}
}

/////////////////////////////////////////////
// Ridge Regression
void TRidgeReg::Fit(const TFltVV& X, const TFltV& y) {
    TNumericalStuff::LeastSquares(X, y, Gamma, WgtV);
}

double TRidgeReg::Predict(const TFltV& x) const {
    EAssertR(x.Len() == WgtV.Len(), "TRegression::TRidgeReg::Predict: model and data dimension mismatch");
    return TLinAlg::DotProduct(x, WgtV);
}

<|endoftext|>


<commit_before>#include <maya/MArgList.h>
#include <maya/MStatus.h>
#include <maya/MDGModifier.h>
#include <maya/MFnMesh.h>
#include <maya/MIntArray.h>
#include <maya/MFloatPointArray.h>

#include "assetCommand.h"
#include "assetManager.h"
#include "util.h"

AssetCommand::AssetCommand()
{
    cerr << "AssetCommand constructor" << endl;
}

AssetCommand::~AssetCommand()
{
    cerr << "AssetCommand destructor" << endl;
}

void* AssetCommand::creator()
{
    cerr << "AssetCommand creator" << endl;
    return new AssetCommand();
}

MStatus AssetCommand::doIt(const MArgList& args)
{
    cerr << "AssetCommand doIt" << endl;

    MString filePath = args.asString(0);
    AssetManager::createManager(filePath);

}
<commit_msg>Build fix on Maya plugin.<commit_after>#include <maya/MArgList.h>
#include <maya/MStatus.h>
#include <maya/MDGModifier.h>
#include <maya/MFnMesh.h>
#include <maya/MIntArray.h>
#include <maya/MFloatPointArray.h>

#include "assetCommand.h"
#include "assetManager.h"
#include "util.h"

AssetCommand::AssetCommand()
{
    cerr << "AssetCommand constructor" << endl;
}

AssetCommand::~AssetCommand()
{
    cerr << "AssetCommand destructor" << endl;
}

void* AssetCommand::creator()
{
    cerr << "AssetCommand creator" << endl;
    return new AssetCommand();
}

MStatus AssetCommand::doIt(const MArgList& args)
{
    cerr << "AssetCommand doIt" << endl;

    MString filePath = args.asString(0);
    AssetManager::createManager(filePath);

    return MS::MStatusCode::kSuccess;
}
<|endoftext|>


<commit_before>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "jstreamsconfig.h"
#include "query.h"
#include "jstreamsconfig.h"
#include "indexreader.h"
#include <ctype.h>
using namespace std;
using namespace Strigi;

Query::Query() {
}
/**
 * The constructor parses the query in include and exclude statements.
 * The following lines contain example queries.
 * hi
 * 'hi'
 * hi Jos
 * 'hi Jos'
 * "hi Jos"
 * -hi Jos
 * path:"hi Jos"
 * -path:"hi Jos"
 * So the syntax is something like this:
 * query ::= [term]*
 * term ::= [-][prefix]:("searchphrase"|searchphrase)
 **/
Query::Query(int max, int offset) {
    this->max = max;
    this->offset = offset;
}
QueryParser::QueryParser() {
    defaultFields.push_back("content");
    defaultFields.push_back("artist");
    defaultFields.push_back("filename");
    defaultFields.push_back("album");
    defaultFields.push_back("title");
}
Query
QueryParser::buildQuery(const string& querystring, int32_t max, int32_t offset){
    const char* q = querystring.c_str();
    const char* end = q + querystring.length();
    const char* p = q;
    Query query(max, offset);
    Query term;
    Query lastterm;
    bool hadOr = false;
    while (p < end) {
        term.clear();
        p = parseQuery(p, term);
        if (term.expression == "OR") {
            hadOr = true;
            Query q;
            addQuery(q, lastterm);
        } else {
            addQuery(query, lastterm);
            lastterm = term;
        }
    }
    addQuery(query, lastterm);
    return query;
}/*
bool
operator<(const Query&a,const Query&b) {
    return &a < &b;
}*/
void
QueryParser::addQuery(Query& query, const Query& subquery) const {
    // if the subquery is empty, do not add it
    if (subquery.terms.size() == 0 && subquery.expression.size() == 0) return;
    // if the subquery has no field name, use the default field names
    if (subquery.expression.size() > 0 && subquery.fieldname.size() == 0
            && defaultFields.size() > 0) {
        if (defaultFields.size() == 1) {
            Query sq = subquery;
            sq.fieldname = *defaultFields.begin();
            query.terms.push_back(sq);
        } else {
            list<string>::const_iterator i;
            Query orQuery;
            orQuery.occurrence = subquery.occurrence;
            for (i = defaultFields.begin(); i != defaultFields.end(); ++i) {
                Query sub;
                sub.fieldname = *i;
                sub.expression = subquery.expression;
                sub.occurrence = Query::SHOULD;
                orQuery.terms.push_back(sub);
             }
             query.terms.push_back(orQuery);
        }
    } else {
        query.terms.push_back(subquery);
    }
}
const char*
QueryParser::parseQuery(const char* s, Query& parsedterm) const {
    bool include = true;
    const char* p = s;
    // skip whitespace
    while (*p != '\0' && isspace(*p)) p++;
    if (*p == '\0') return p;

    // check for a - sign
    if (*p == '-') {
        include = false;
        p++;
    }
    // skip whitespace
    while (*p != '\0' && isspace(*p)) p++;
    if (*p == '\0') return p;

    char quote = 0;
    if (*p == '\'' || *p == '"') {
        quote = *p++;
        if (*p == '\0') return p;
    }
    const char* prefix = 0;
    const char* prefend = 0;
    const char* term = p;
    // skip until end of string or closing quote or colon or whitespace
    while (*p != '\0' && ((quote == 0 && !isspace(*p))
            || (quote != 0 && *p != quote))) {
        if (quote == 0 && *p == ':') {
            // define the prefix
            prefix = term;
            prefend = p;
            ++p;
            if (*p == '\0') return p;
            if (*p == '\'' || *p == '"') {
                quote = *p++;
                if (*p == '\0') return p;
            }
            term = p;
        }
        ++p;
    }
    if (*term == '\0') return term;
    if (p - term > 0) {
        parsedterm.occurrence = (include) ?Query::MUST :Query::MUST_NOT;
        if (prefix != 0 && term - prefix > 1) {
            parsedterm.fieldname = string(prefix, prefend-prefix);
        }
        parsedterm.expression = string(term, p-term);
    }
    // skip the terminating character
    if (p != '\0') p++;
    return p;
}

void
replaceall(string& text, const string& a, const string& b) {
    size_t pos = 0;
    pos = text.find(a);
    while (pos != string::npos) {
        text.replace(pos, a.length(), "<");
        pos = text.find('<');
    }
}
void
Query::clear() {
    terms.clear();
    occurrence = MUST;
    fieldname = expression = "";
}
string
Query::highlight(const string& text) const {
    return text;
    int pre = 5, post = 5, maxlen = 100;
    string t = text;
    replaceall(t, "<", "<");
    replaceall(t, ">", ">");
    string lt = t;
    for (unsigned i=0; i<t.length(); ++i) {
        lt[i] = tolower(lt[i]);
    }
    vector<string> re;
    list<Query>::const_iterator i;
    for (i = terms.begin(); i != terms.end(); ++i) {
        if (i->occurrence != MUST_NOT) {
            string s = i->expression;
            for (unsigned k = 0; k < s.length(); ++k) {
                s[k] = tolower(s[k]);
            }
            re.push_back(s);
        }
    }
    string out;
    int pos = 0;
    string::size_type last1 = string::npos;
    //int last2 = string::npos;
    //int last3 = string::npos;
    string::size_type last4 = string::npos;
    vector<string>::const_iterator k;
    while (pos >= 0 && (int)(out.length()+last1-last4) < maxlen) {
        string::size_type rep = string::npos;
        int len;
        for (k = re.begin(); k != re.end(); ++k) {
            unsigned p = lt.find(*k, pos);
            if (p > 0 && (rep == string::npos || p < rep)) {
                rep = p;
                len = k->length();
            }
        }
        if (rep != string::npos) {
            string::size_type p1 = t.find(" ", rep-pre);
            if (p1 == string::npos) p1 = rep-pre;
            string::size_type p4 = t.find(" ", rep+len+post);
            if (p4 == string::npos) p4 = t.length();
            out += t.substr(p1, rep-p1);
            out += "";
            out += t.substr(rep, len);
            out += "";
            out += t.substr(rep+len, p4-(rep+len));
            out += " ... ";
            /* if (lasts == string::npos) {
                lasts = s;
            } else if (s > laste) {
                if (out.length() == 0 && lasts > 0) out += "... ";
                out += t.substr(lasts, laste - lasts) + " ... ";
                lasts = s;
            }
            laste = e;*/
            pos = rep+1;
        } else {
            pos = rep;
        }
    }
   /* if (lasts != string::npos) {
        if (out.length() == 0 && lasts > 0) out += "... ";
        out += t.substr(lasts, laste - lasts) + " ... ";
    }
    for (k = re.begin(); k != re.end(); ++k) {
        replaceall(out, *k, "great");
    }*/
    if (out.length() == 0) {
        out = t.substr(0, 100);
    }
    return out;
}
<commit_msg>don't compare pointers to char (CID 3143)<commit_after>/* This file is part of Strigi Desktop Search
 *
 * Copyright (C) 2006 Jos van den Oever <jos@vandenoever.info>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */
#include "jstreamsconfig.h"
#include "query.h"
#include "jstreamsconfig.h"
#include "indexreader.h"
#include <ctype.h>
using namespace std;
using namespace Strigi;

Query::Query() {
}
/**
 * The constructor parses the query in include and exclude statements.
 * The following lines contain example queries.
 * hi
 * 'hi'
 * hi Jos
 * 'hi Jos'
 * "hi Jos"
 * -hi Jos
 * path:"hi Jos"
 * -path:"hi Jos"
 * So the syntax is something like this:
 * query ::= [term]*
 * term ::= [-][prefix]:("searchphrase"|searchphrase)
 **/
Query::Query(int max, int offset) {
    this->max = max;
    this->offset = offset;
}
QueryParser::QueryParser() {
    defaultFields.push_back("content");
    defaultFields.push_back("artist");
    defaultFields.push_back("filename");
    defaultFields.push_back("album");
    defaultFields.push_back("title");
}
Query
QueryParser::buildQuery(const string& querystring, int32_t max, int32_t offset){
    const char* q = querystring.c_str();
    const char* end = q + querystring.length();
    const char* p = q;
    Query query(max, offset);
    Query term;
    Query lastterm;
    bool hadOr = false;
    while (p < end) {
        term.clear();
        p = parseQuery(p, term);
        if (term.expression == "OR") {
            hadOr = true;
            Query q;
            addQuery(q, lastterm);
        } else {
            addQuery(query, lastterm);
            lastterm = term;
        }
    }
    addQuery(query, lastterm);
    return query;
}/*
bool
operator<(const Query&a,const Query&b) {
    return &a < &b;
}*/
void
QueryParser::addQuery(Query& query, const Query& subquery) const {
    // if the subquery is empty, do not add it
    if (subquery.terms.size() == 0 && subquery.expression.size() == 0) return;
    // if the subquery has no field name, use the default field names
    if (subquery.expression.size() > 0 && subquery.fieldname.size() == 0
            && defaultFields.size() > 0) {
        if (defaultFields.size() == 1) {
            Query sq = subquery;
            sq.fieldname = *defaultFields.begin();
            query.terms.push_back(sq);
        } else {
            list<string>::const_iterator i;
            Query orQuery;
            orQuery.occurrence = subquery.occurrence;
            for (i = defaultFields.begin(); i != defaultFields.end(); ++i) {
                Query sub;
                sub.fieldname = *i;
                sub.expression = subquery.expression;
                sub.occurrence = Query::SHOULD;
                orQuery.terms.push_back(sub);
             }
             query.terms.push_back(orQuery);
        }
    } else {
        query.terms.push_back(subquery);
    }
}
const char*
QueryParser::parseQuery(const char* s, Query& parsedterm) const {
    bool include = true;
    const char* p = s;
    // skip whitespace
    while (*p != '\0' && isspace(*p)) p++;
    if (*p == '\0') return p;

    // check for a - sign
    if (*p == '-') {
        include = false;
        p++;
    }
    // skip whitespace
    while (*p != '\0' && isspace(*p)) p++;
    if (*p == '\0') return p;

    char quote = 0;
    if (*p == '\'' || *p == '"') {
        quote = *p++;
        if (*p == '\0') return p;
    }
    const char* prefix = 0;
    const char* prefend = 0;
    const char* term = p;
    // skip until end of string or closing quote or colon or whitespace
    while (*p != '\0' && ((quote == 0 && !isspace(*p))
            || (quote != 0 && *p != quote))) {
        if (quote == 0 && *p == ':') {
            // define the prefix
            prefix = term;
            prefend = p;
            ++p;
            if (*p == '\0') return p;
            if (*p == '\'' || *p == '"') {
                quote = *p++;
                if (*p == '\0') return p;
            }
            term = p;
        }
        ++p;
    }
    if (*term == '\0') return term;
    if (p - term > 0) {
        parsedterm.occurrence = (include) ?Query::MUST :Query::MUST_NOT;
        if (prefix != 0 && term - prefix > 1) {
            parsedterm.fieldname = string(prefix, prefend-prefix);
        }
        parsedterm.expression = string(term, p-term);
    }
    // skip the terminating character
    if (*p != '\0') p++;
    return p;
}

void
replaceall(string& text, const string& a, const string& b) {
    size_t pos = 0;
    pos = text.find(a);
    while (pos != string::npos) {
        text.replace(pos, a.length(), "<");
        pos = text.find('<');
    }
}
void
Query::clear() {
    terms.clear();
    occurrence = MUST;
    fieldname = expression = "";
}
string
Query::highlight(const string& text) const {
    return text;
    int pre = 5, post = 5, maxlen = 100;
    string t = text;
    replaceall(t, "<", "<");
    replaceall(t, ">", ">");
    string lt = t;
    for (unsigned i=0; i<t.length(); ++i) {
        lt[i] = tolower(lt[i]);
    }
    vector<string> re;
    list<Query>::const_iterator i;
    for (i = terms.begin(); i != terms.end(); ++i) {
        if (i->occurrence != MUST_NOT) {
            string s = i->expression;
            for (unsigned k = 0; k < s.length(); ++k) {
                s[k] = tolower(s[k]);
            }
            re.push_back(s);
        }
    }
    string out;
    int pos = 0;
    string::size_type last1 = string::npos;
    //int last2 = string::npos;
    //int last3 = string::npos;
    string::size_type last4 = string::npos;
    vector<string>::const_iterator k;
    while (pos >= 0 && (int)(out.length()+last1-last4) < maxlen) {
        string::size_type rep = string::npos;
        int len;
        for (k = re.begin(); k != re.end(); ++k) {
            unsigned p = lt.find(*k, pos);
            if (p > 0 && (rep == string::npos || p < rep)) {
                rep = p;
                len = k->length();
            }
        }
        if (rep != string::npos) {
            string::size_type p1 = t.find(" ", rep-pre);
            if (p1 == string::npos) p1 = rep-pre;
            string::size_type p4 = t.find(" ", rep+len+post);
            if (p4 == string::npos) p4 = t.length();
            out += t.substr(p1, rep-p1);
            out += "";
            out += t.substr(rep, len);
            out += "";
            out += t.substr(rep+len, p4-(rep+len));
            out += " ... ";
            /* if (lasts == string::npos) {
                lasts = s;
            } else if (s > laste) {
                if (out.length() == 0 && lasts > 0) out += "... ";
                out += t.substr(lasts, laste - lasts) + " ... ";
                lasts = s;
            }
            laste = e;*/
            pos = rep+1;
        } else {
            pos = rep;
        }
    }
   /* if (lasts != string::npos) {
        if (out.length() == 0 && lasts > 0) out += "... ";
        out += t.substr(lasts, laste - lasts) + " ... ";
    }
    for (k = re.begin(); k != re.end(); ++k) {
        replaceall(out, *k, "great");
    }*/
    if (out.length() == 0) {
        out = t.substr(0, 100);
    }
    return out;
}
<|endoftext|>


<commit_before>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "test_math/pch.h"
#include "test/unit/coTest.h"
#include "math/quaternion/coQuat_f.h"

coTEST(coQuat_f, coNormalize)
{
	coEXPECT(coNearEqual(coNormalize(coQuat(-7, 0, 0, 0)), coQuat(-1, 0, 0, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, -7, 0, 0)), coQuat(0, -1, 0, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, 0, -7, 0)), coQuat(0, 0, -1, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, 0, 0, -7)), coQuat(0, 0, 0, -1)));
}

coTEST(coQuat_f, coConjugate)
{
	coEXPECT(coConjugate(coQuat(0, 0, 0, 0)) == coQuat(0, 0, 0, 0));
	coEXPECT(coConjugate(coQuat(7, 0, 0, 0)) == coQuat(-7, 0, 0, 0));
	coEXPECT(coConjugate(coQuat(0, 7, 0, 0)) == coQuat(0, -7, 0, 0));
	coEXPECT(coConjugate(coQuat(0, 0, 7, 0)) == coQuat(0, 0, -7, 0));
	coEXPECT(coConjugate(coQuat(0, 0, 0, 7)) == coQuat(0, 0, 0, -7));
}

coTEST(coQuat_f, coRotation)
{

}

coTEST(coQuat_f, coRotateVector)
{
	{
		const coQuat q = coRotation(coFloatx3(0, 0, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(3, 0, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 3, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(0, 0, 3)));
	}

	{
		const coQuat q = coRotation(coFloatx3(coFloat_halfPi, 0, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(3, 0, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 0, -3)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(0, 3, 0)));
	}

	{
		const coQuat q = coRotation(coFloatx3(0, coFloat_halfPi, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(0, 0, 3)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 3, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(-3, 0, 0)));
	}
}
<commit_msg>testssdfsd<commit_after>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "test_math/pch.h"
#include "test/unit/coTest.h"
#include "math/quaternion/coQuat_f.h"

coTEST(coQuat_f, coNormalize)
{
	coEXPECT(coNearEqual(coNormalize(coQuat(-7, 0, 0, 0)), coQuat(-1, 0, 0, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, -7, 0, 0)), coQuat(0, -1, 0, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, 0, -7, 0)), coQuat(0, 0, -1, 0)));
	coEXPECT(coNearEqual(coNormalize(coQuat(0, 0, 0, -7)), coQuat(0, 0, 0, -1)));
}

coTEST(coQuat_f, coConjugate)
{
	coEXPECT(coConjugate(coQuat(0, 0, 0, 0)) == coQuat(0, 0, 0, 0));
	coEXPECT(coConjugate(coQuat(7, 0, 0, 0)) == coQuat(-7, 0, 0, 0));
	coEXPECT(coConjugate(coQuat(0, 7, 0, 0)) == coQuat(0, -7, 0, 0));
	coEXPECT(coConjugate(coQuat(0, 0, 7, 0)) == coQuat(0, 0, -7, 0));
	coEXPECT(coConjugate(coQuat(0, 0, 0, 7)) == coQuat(0, 0, 0, -7));
}

coTEST(coQuat_f, coRotation)
{
	coEXPECT(coNearEqual(coRotation(coFloatx3(7, 0, 0), coFloatx3(7, 0, 0)), coRotation(coFloatx3(0, 0, 0))));
	coEXPECT(coNearEqual(coRotation(coFloatx3(7, 0, 0), coFloatx3(0, 7, 0)), coRotation(coFloatx3(0, 0, coFloat_halfPi))));
	coEXPECT(coNearEqual(coRotation(coFloatx3(7, 0, 0), coFloatx3(0, 0, 7)), coRotation(coFloatx3(0, coFloat_halfPi, 0))));
	coEXPECT(coNearEqual(coRotation(coFloatx3(0, 0, 7), coFloatx3(0, 7, 0)), coRotation(coFloatx3(coFloat_halfPi, 0, 0))));
}

coTEST(coQuat_f, coRotateVector)
{
	{
		const coQuat q = coRotation(coFloatx3(0, 0, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(3, 0, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 3, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(0, 0, 3)));
	}

	{
		const coQuat q = coRotation(coFloatx3(coFloat_halfPi, 0, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(3, 0, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 0, -3)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(0, 3, 0)));
	}

	{
		const coQuat q = coRotation(coFloatx3(0, coFloat_halfPi, 0));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(3, 0, 0)), coFloatx3(0, 0, 3)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 3, 0)), coFloatx3(0, 3, 0)));
		coEXPECT(coNearEqual(coRotateVector(q, coFloatx3(0, 0, 3)), coFloatx3(-3, 0, 0)));
	}
}
<|endoftext|>