<commit_before>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "filesystem/RealFD.h"
#include "filesystem/InterixVFSNode.h"
#include "filesystem/PtsVFSNode.h"
#include "filesystem/FakeFile.h"
#include <stdlib.h>
#include <limits.h>
#include <sys/mkdev.h>

PtsVFSNode::PtsVFSNode(VFSNode* parent, const string& name):
	FakeVFSNode(parent, name)
{
	AddFile(new TunnelledFakeDirectory("ptms", "/dev/ptmx"));
}

PtsVFSNode::~PtsVFSNode()
{
}

static string findpty(const string& name)
{
	u32 number = strtoul(name.c_str(), NULL, 10);
	if ((number == 0) || (number == ULONG_MAX))
		return "";

	char buffer[16] = "/dev/tty";
	*(u32*) (buffer+8) = number;
	buffer[12] = '\0';

	/* A brief gesture to security checking. */
	if (!buffer[8])
		return "";
	for (int i = 8; i < 12; i++)
	{
		if (buffer[i] &&
		    ((buffer[i] == '/') || (buffer[i] < 32) || (buffer[i] > 126)))
			return "";
	}

	return buffer;
}

void PtsVFSNode::StatFile(const string& name, struct stat& st)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int i = stat(f.c_str(), &st);
		if (i == -1)
			throw errno;

		/* libc expects slave devices to have a particular rdev.
		 * So we have to fake it here.
		 */
		st.st_rdev = mkdev(3, 0);
		return;
	}
	return FakeVFSNode::StatFile(name, st);
}

Ref<FD> PtsVFSNode::OpenFile(const string& name, int flags, int mode)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int newfd = open(f.c_str(), flags, mode);
		if (newfd == -1)
			throw errno;

		return new RealFD(newfd);
	}
	return FakeVFSNode::OpenFile(name, flags, mode);
}

int PtsVFSNode::Access(const string& name, int mode)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int i = access(f.c_str(), mode);
		if (i == -1)
			throw errno;
		return i;
	}
	return FakeVFSNode::Access(name, mode);
}

void PtsVFSNode::Chown(const string& name, uid_t owner, gid_t group)
{
	string f = findpty(name);
	if (!f.empty())
	{
		if (Options.FakeRoot)
			return;

		int i = chown(f.c_str(), owner, group);
		if (i == -1)
			throw errno;
		return;
	}
	return FakeVFSNode::Chown(name, owner, group);
}
<commit_msg>Fixed typo in name of /dev/pts/ptmx.<commit_after>/* © 2010 David Given.
 * LBW is licensed under the MIT open source license. See the COPYING
 * file in this distribution for the full text.
 */

#include "globals.h"
#include "filesystem/RealFD.h"
#include "filesystem/InterixVFSNode.h"
#include "filesystem/PtsVFSNode.h"
#include "filesystem/FakeFile.h"
#include <stdlib.h>
#include <limits.h>
#include <sys/mkdev.h>

PtsVFSNode::PtsVFSNode(VFSNode* parent, const string& name):
	FakeVFSNode(parent, name)
{
	AddFile(new TunnelledFakeDirectory("ptmx", "/dev/ptmx"));
}

PtsVFSNode::~PtsVFSNode()
{
}

static string findpty(const string& name)
{
	u32 number = strtoul(name.c_str(), NULL, 10);
	if ((number == 0) || (number == ULONG_MAX))
		return "";

	char buffer[16] = "/dev/tty";
	*(u32*) (buffer+8) = number;
	buffer[12] = '\0';

	/* A brief gesture to security checking. */
	if (!buffer[8])
		return "";
	for (int i = 8; i < 12; i++)
	{
		if (buffer[i] &&
		    ((buffer[i] == '/') || (buffer[i] < 32) || (buffer[i] > 126)))
			return "";
	}

	return buffer;
}

void PtsVFSNode::StatFile(const string& name, struct stat& st)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int i = stat(f.c_str(), &st);
		if (i == -1)
			throw errno;

		/* libc expects slave devices to have a particular rdev.
		 * So we have to fake it here.
		 */
		st.st_rdev = mkdev(3, 0);
		return;
	}
	return FakeVFSNode::StatFile(name, st);
}

Ref<FD> PtsVFSNode::OpenFile(const string& name, int flags, int mode)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int newfd = open(f.c_str(), flags, mode);
		if (newfd == -1)
			throw errno;

		return new RealFD(newfd);
	}
	return FakeVFSNode::OpenFile(name, flags, mode);
}

int PtsVFSNode::Access(const string& name, int mode)
{
	string f = findpty(name);
	if (!f.empty())
	{
		int i = access(f.c_str(), mode);
		if (i == -1)
			throw errno;
		return i;
	}
	return FakeVFSNode::Access(name, mode);
}

void PtsVFSNode::Chown(const string& name, uid_t owner, gid_t group)
{
	string f = findpty(name);
	if (!f.empty())
	{
		if (Options.FakeRoot)
			return;

		int i = chown(f.c_str(), owner, group);
		if (i == -1)
			throw errno;
		return;
	}
	return FakeVFSNode::Chown(name, owner, group);
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef ECL_LIB_UTILS_ERR_HPP_
#define ECL_LIB_UTILS_ERR_HPP_

namespace ecl
{

//! theCore system-wide errors
//! \details Rudely taken from http://en.cppreference.com/w/cpp/error/errno_macros
enum class err : int
{
    ok               =   0,    //! Successfully completed
    tobig            =  -1,    //! Argument list too long
    acces            =  -2,    //! Permission denied
    addrinuse        =  -3,    //! Address in use
    addrnotavail     =  -4,    //! Address not available
    afnosupport      =  -5,    //! Address family not supported
    again            =  -6,    //! Resource unavailable
    already          =  -7,    //! Connection already in progress
    badf             =  -8,    //! Bad file descriptor
    badmsg           =  -9,    //! Bad message
    busy             = -10,    //! Device or resource busy
    canceled         = -11,    //! Operation canceled
    child            = -12,    //! No child processes
    connaborted      = -13,    //! Connection aborted
    connrefused      = -14,    //! Connection refused
    connreset        = -15,    //! Connection reset
    deadlk           = -16,    //! Resource deadlock would occur
    destaddrreq      = -17,    //! Destination address required
    dom              = -18,    //! Mathematics argument out of domain of function
    exist            = -19,    //! File exists
    fault            = -20,    //! Bad address
    fbig             = -21,    //! File too large
    hostunreach      = -22,    //! Host is unreachable
    idrm             = -23,    //! Identifier removed
    ilseq            = -24,    //! Illegal byte sequence
    inprogress       = -25,    //! Operation in progress
    intr             = -26,    //! Interrupted function
    inval            = -27,    //! Invalid argument
    io               = -28,    //! I/O error
    isconn           = -29,    //! Socket is connected
    isdir            = -30,    //! Is a directory
    loop             = -31,    //! Too many levels of symbolic links
    mfile            = -32,    //! File descriptor value too large
    mlink            = -33,    //! Too many links
    msgsize          = -34,    //! Message too large
    nametoolong      = -35,    //! Filename too long
    netdown          = -36,    //! Network is down
    netreset         = -37,    //! Connection aborted by network
    netunreach       = -38,    //! Network unreachable
    nfile            = -39,    //! Too many files open in system
    nobufs           = -40,    //! No buffer space available
    nodata           = -41,    //! No message is available on the STREAM head read queue
    nodev            = -42,    //! No such device
    noent            = -43,    //! No such file or directory
    noexec           = -44,    //! Executable file format error
    nolck            = -45,    //! No locks available
    nolink           = -46,    //! Link has been severed
    nomem            = -47,    //! Not enough space
    nomsg            = -48,    //! No message of the desired type
    noprotoopt       = -49,    //! Protocol not available
    nospc            = -50,    //! No space left on device
    nosr             = -51,    //! No STREAM resources
    nostr            = -52,    //! Not a STREAM
    nosys            = -53,    //! Function not supported
    notconn          = -54,    //! The socket is not connected
    notdir           = -55,    //! Not a directory
    notempty         = -56,    //! Directory not empty
    notrecoverable   = -57,    //! State not recoverable
    notsock          = -58,    //! Not a socket
    notsup           = -59,    //! Not supported
    notty            = -60,    //! Inappropriate I/O control operation
    nxio             = -61,    //! No such device or address
    opnotsupp        = -62,    //! Operation not supported on socket
    overflow         = -63,    //! Value too large to be stored in data type
    ownerdead        = -64,    //! Previous owner died
    perm             = -65,    //! Operation not permitted
    pipe             = -66,    //! Broken pipe
    proto            = -67,    //! Protocol error
    protonosupport   = -68,    //! Protocol not supported
    prototype        = -69,    //! Protocol wrong type for socket
    range            = -70,    //! Result too large
    rofs             = -71,    //! Read-only file system
    spipe            = -72,    //! Invalid seek
    srch             = -73,    //! No such process
    time             = -74,    //! Stream ioctl() timeout
    timedout         = -75,    //! Connection timed out
    txtbsy           = -76,    //! Text file busy
    wouldblock       = -77,    //! Operation would block
    xdev             = -78,    //! Cross-device link
    generic          = -79,    //! Generic error
};

static inline bool is_error(err error)
{
    return error != err::ok;
}

static inline bool is_ok(err error)
{
    return !is_error(error);
}

const char* err_to_str(err error);

} // namespace ecl

#ifdef CORE_TESTS_ENABLED
#include <CppUTest/SimpleString.h>

static inline SimpleString StringFrom(ecl::err err)
{
    return SimpleString{ecl::err_to_str(err)};
}
#endif // CORE_TESTS_ENABLED

#endif // ECL_LIB_UTILS_ERR_HPP_
<commit_msg>lib/types: add err code to handle EOF condition<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef ECL_LIB_UTILS_ERR_HPP_
#define ECL_LIB_UTILS_ERR_HPP_

namespace ecl
{

//! theCore system-wide errors
//! \details Rudely taken from http://en.cppreference.com/w/cpp/error/errno_macros
enum class err : int
{
    ok               =   0,    //! Successfully completed
    tobig            =  -1,    //! Argument list too long
    acces            =  -2,    //! Permission denied
    addrinuse        =  -3,    //! Address in use
    addrnotavail     =  -4,    //! Address not available
    afnosupport      =  -5,    //! Address family not supported
    again            =  -6,    //! Resource unavailable
    already          =  -7,    //! Connection already in progress
    badf             =  -8,    //! Bad file descriptor
    badmsg           =  -9,    //! Bad message
    busy             = -10,    //! Device or resource busy
    canceled         = -11,    //! Operation canceled
    child            = -12,    //! No child processes
    connaborted      = -13,    //! Connection aborted
    connrefused      = -14,    //! Connection refused
    connreset        = -15,    //! Connection reset
    deadlk           = -16,    //! Resource deadlock would occur
    destaddrreq      = -17,    //! Destination address required
    dom              = -18,    //! Mathematics argument out of domain of function
    exist            = -19,    //! File exists
    fault            = -20,    //! Bad address
    fbig             = -21,    //! File too large
    hostunreach      = -22,    //! Host is unreachable
    idrm             = -23,    //! Identifier removed
    ilseq            = -24,    //! Illegal byte sequence
    inprogress       = -25,    //! Operation in progress
    intr             = -26,    //! Interrupted function
    inval            = -27,    //! Invalid argument
    io               = -28,    //! I/O error
    isconn           = -29,    //! Socket is connected
    isdir            = -30,    //! Is a directory
    loop             = -31,    //! Too many levels of symbolic links
    mfile            = -32,    //! File descriptor value too large
    mlink            = -33,    //! Too many links
    msgsize          = -34,    //! Message too large
    nametoolong      = -35,    //! Filename too long
    netdown          = -36,    //! Network is down
    netreset         = -37,    //! Connection aborted by network
    netunreach       = -38,    //! Network unreachable
    nfile            = -39,    //! Too many files open in system
    nobufs           = -40,    //! No buffer space available
    nodata           = -41,    //! No message is available on the STREAM head read queue
    nodev            = -42,    //! No such device
    noent            = -43,    //! No such file or directory
    noexec           = -44,    //! Executable file format error
    nolck            = -45,    //! No locks available
    nolink           = -46,    //! Link has been severed
    nomem            = -47,    //! Not enough space
    nomsg            = -48,    //! No message of the desired type
    noprotoopt       = -49,    //! Protocol not available
    nospc            = -50,    //! No space left on device
    nosr             = -51,    //! No STREAM resources
    nostr            = -52,    //! Not a STREAM
    nosys            = -53,    //! Function not supported
    notconn          = -54,    //! The socket is not connected
    notdir           = -55,    //! Not a directory
    notempty         = -56,    //! Directory not empty
    notrecoverable   = -57,    //! State not recoverable
    notsock          = -58,    //! Not a socket
    notsup           = -59,    //! Not supported
    notty            = -60,    //! Inappropriate I/O control operation
    nxio             = -61,    //! No such device or address
    opnotsupp        = -62,    //! Operation not supported on socket
    overflow         = -63,    //! Value too large to be stored in data type
    ownerdead        = -64,    //! Previous owner died
    perm             = -65,    //! Operation not permitted
    pipe             = -66,    //! Broken pipe
    proto            = -67,    //! Protocol error
    protonosupport   = -68,    //! Protocol not supported
    prototype        = -69,    //! Protocol wrong type for socket
    range            = -70,    //! Result too large
    rofs             = -71,    //! Read-only file system
    spipe            = -72,    //! Invalid seek
    srch             = -73,    //! No such process
    time             = -74,    //! Stream ioctl() timeout
    timedout         = -75,    //! Connection timed out
    txtbsy           = -76,    //! Text file busy
    wouldblock       = -77,    //! Operation would block
    xdev             = -78,    //! Cross-device link
    generic          = -79,    //! Generic error
    eof              = -255,   //! End-of-file reached
};

static inline bool is_error(err error)
{
    return error != err::ok;
}

static inline bool is_ok(err error)
{
    return !is_error(error);
}

const char* err_to_str(err error);

} // namespace ecl

#ifdef CORE_TESTS_ENABLED
#include <CppUTest/SimpleString.h>

static inline SimpleString StringFrom(ecl::err err)
{
    return SimpleString{ecl::err_to_str(err)};
}
#endif // CORE_TESTS_ENABLED

#endif // ECL_LIB_UTILS_ERR_HPP_
<|endoftext|>


<commit_before>
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <ctype.h>

#include "Assert.h"
#include "String.h"

String::Data String::emptyData("");
String::Data* String::firstFreeData = 0;

String::String(const char* str, int length)
{
  if(length < 0)
    length = strlen(str);
  init(length, str, length);
}

String::~String()
{
  free();
}

void String::init(unsigned int size, const char* str, unsigned int length)
{
  ASSERT(size >= length);
  if(firstFreeData)
  {
    data = firstFreeData;
    firstFreeData = firstFreeData->next;
    data->refs = 1;

    if(data->size < size)
    {
      delete[] (char*)data->str;
      data->size = size + 16 + (size >> 1); // badass growing strategy
      data->str = new char[data->size + 1];
    }
  }
  else
  {
    data = new Data;
    data->refs = 1;
    data->size = size + 16 + (size >> 1); // badass growing strategy
    data->str = new char[data->size + 1];
  }
  if(length)
    memcpy((char*)data->str, str, length);
  ((char*)data->str)[length] = '\0';
  data->length = length;
}

void String::free()
{
  --data->refs;
  if(data->refs == 0)
  {
    data->next = firstFreeData;
    firstFreeData = data;
  }
}

void String::grow(unsigned int size, unsigned int length)
{
  ASSERT(size >= length);
  ASSERT(length <= data->size);
  if(data->refs > 1)
  {
    Data* otherData = data;
    --otherData->refs;

    init(size, otherData->str, length);
  }
  else if(data->size < size)
  {
    char* otherStr = (char*)data->str;
    data->size = size + 16 + (size >> 1); // badass growing strategy
    data->str = new char[data->size + 1];
    if(length)
      memcpy((char*)data->str, otherStr, length);
    delete[] otherStr;

    data->length = length;
    ((char*)data->str)[length] = '\0';
  }
}

String& String::operator=(const String& other)
{
  free();
  data = other.data;
  ++data->refs;
  return *this;
}

bool String::operator==(const String& other) const
{
  return data->length == other.data->length && memcmp(data->str, other.data->str, data->length) == 0;
}

bool String::operator!=(const String& other) const
{
  return data->length != other.data->length || memcmp(data->str, other.data->str, data->length) != 0;
}

char* String::getData(unsigned int size)
{
  grow(size, 0);
  return (char*)data->str;
}

void String::setCapacity(unsigned int size)
{
  grow(size < data->length ? data->length : size, data->length); // enforce detach
}

String& String::append(char c)
{
  unsigned int newLength = data->length + 1;
  grow(newLength, data->length);
  ((char*)data->str)[data->length] = c;
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::append(const String& str)
{
  unsigned int newLength = data->length + str.data->length;
  grow(newLength, data->length);
  memcpy(((char*)data->str) + data->length, str.data->str, str.data->length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::append(const char* str, unsigned int length)
{
  unsigned int newLength = data->length + length;
  grow(newLength, data->length);
  memcpy(((char*)data->str) + data->length, str, length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::prepend(const String& str)
{
  // TODO: optimize this using memmove when possible?
  String old(*this);
  unsigned int newLength = data->length + str.data->length;
  grow(newLength, 0);
  memcpy((char*)data->str, str.data->str, str.data->length);
  memcpy(((char*)data->str) + str.data->length, old.data->str, old.data->length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

void String::clear()
{
  if(data->refs == 1)
  {
    *(char*)data->str = '\0';
    data->length = 0;
  }
  else
  {
    free();
    data = &emptyData;
    ++data->refs;
  }
}

void String::setLength(unsigned int length)
{
  grow(length, length); // detach
  ((char*)data->str)[length] = '\0';
  data->length = length;
}

String& String::format(unsigned int size, const char* format, ...)
{
  int length;
  va_list ap;
  va_start(ap, format);
#ifdef _MSC_VER
  length = vsprintf_s(getData(size), size, format, ap);
#else
  length = ::vsnprintf(getData(size), size, format, ap);
  if(length < 0)
    length = size;
#endif
  va_end(ap);
  ((char*)data->str)[length] = '\0';
  data->length = length;
  return *this;
}

String String::substr(int start, int length) const
{
  if(start < 0)
  {
    start = (int)data->length + start;
    if(start < 0)
      start = 0;
  }
  else if((unsigned int)start > data->length)
    start = data->length;

  int end;
  if(length >= 0)
  {
    end = start + length;
    if((unsigned int)end > data->length)
      end = data->length;
  }
  else
    end = data->length;

  length = end - start;
  String result(length);
  memcpy((char*)result.data->str, data->str + start, length);
  ((char*)result.data->str)[length] = '\0';
  result.data->length = length;
  return result;
}

int String::subst(const String& from, const String& to)
{
  String result(data->length + to.data->length * 2);
  const char* str = data->str;
  const char* f = from.data->str;
  unsigned int flen = from.data->length;
  const char* start = str;
  int i = 0;
  while(*str)
    if(*str == *f && strncmp(str, f, flen) == 0)
    {
      if(str > start)
        result.append(start, str - start);
      result.append(to);
      str += flen;
      start = str;
      ++i;
    }
    else
      ++str;
  if(str > start)
    result.append(start, str - start);
  *this = result;
  return i;
}

static bool szWildMatch7(const char* pat, const char* str);
static bool szWildMatch1(const char* pat, const char* str, const char*& matchstart, const char*& matchend);

bool String::patmatch(const String& pattern) const
{
  return szWildMatch7(pattern.data->str, data->str);
}

bool String::patsubst(const String& pattern, const String& replace)
{
  const char* matchstart;
  const char* matchend;
  if(!szWildMatch1(pattern.data->str, data->str, matchstart, matchend))
    return false;

  unsigned int matchlen = matchend - matchstart;
  String result(matchlen + replace.data->length);
  char* dest = (char*)result.data->str;
  for(const char* src = replace.data->str; *src; ++src)
    if(*src == '\\' && (src[1] == '%' || (src[1] == '\\' && src[2] == '%')))
    {
      ++src;
      *(dest++) = *src;
    }
    else if(*src == '%')
    {
      memcpy(dest, matchstart, matchlen);
      dest += matchlen;
      ++src;
      unsigned int left = replace.data->length - (src - replace.data->str);
      memcpy(dest, src, left);
      dest += left;
      break;
    }
    else
      *(dest++) = *src;
  *dest = '\0';
  result.data->length = dest - result.data->str;
  *this = result;
  return true;
}

/*
slightly modified wildcard matching functions based on Alessandro Cantatore's algorithms
http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html
*/

static bool szWildMatch7(const char* pat, const char* str) {
    const char* s, * p;
    bool star = false;

loopStart:
    for (s = str, p = pat; *s; ++s, ++p) {
      switch (*p) {
          case '%':
            star = true;
            str = s, pat = p;
            do { ++pat; } while (*pat == '%');
            if (!*++pat) return true;
            goto loopStart;
          default:
            if (*s != *p) goto starCheck;
            break;
      }
    }
    while (*p == '%') ++p;
    return !*p;

starCheck:
    if (!star) return false;
    str++;
    goto loopStart;
}

static bool szWildMatch1(const char* pat, const char* str, const char*& matchstart, const char*& matchend)
{
  while(*str)
  {
    switch(*pat)
    {
    case '%':
      matchstart = str;
      do { ++pat; } while(*pat == '%');
      if(!*pat)
      {
        matchend = matchstart + strlen(matchstart);
        return true;
      }
      while(*str)
        if(szWildMatch7(pat, str++))
        {
          matchend = str - 1;
          return true;
        }
      return false;
    default:
      if(*str != *pat)
        return false;
      break;
    }
    ++pat, ++str;
  }
  while(*pat == '%')
    ++pat;
  if(!*pat)
  {
    matchstart = matchend = str;
    return true;
  }
  return false;
}

String& String::lowercase()
{
  grow(data->length, data->length); // detach
  for(char* str = (char*)data->str; *str; ++str)
    *str = tolower(*(unsigned char*)str);
  return *this;
}

String& String::uppercase()
{
  grow(data->length, data->length); // detach
  for(char* str = (char*)data->str; *str; ++str)
    *str = toupper(*(unsigned char*)str);
  return *this;
}
<commit_msg>Fix not working pattern matching and substitution (filter, patsubst)<commit_after>
#include <cstring>
#include <cstdarg>
#include <cstdio>
#include <ctype.h>

#include "Assert.h"
#include "String.h"

String::Data String::emptyData("");
String::Data* String::firstFreeData = 0;

String::String(const char* str, int length)
{
  if(length < 0)
    length = strlen(str);
  init(length, str, length);
}

String::~String()
{
  free();
}

void String::init(unsigned int size, const char* str, unsigned int length)
{
  ASSERT(size >= length);
  if(firstFreeData)
  {
    data = firstFreeData;
    firstFreeData = firstFreeData->next;
    data->refs = 1;

    if(data->size < size)
    {
      delete[] (char*)data->str;
      data->size = size + 16 + (size >> 1); // badass growing strategy
      data->str = new char[data->size + 1];
    }
  }
  else
  {
    data = new Data;
    data->refs = 1;
    data->size = size + 16 + (size >> 1); // badass growing strategy
    data->str = new char[data->size + 1];
  }
  if(length)
    memcpy((char*)data->str, str, length);
  ((char*)data->str)[length] = '\0';
  data->length = length;
}

void String::free()
{
  --data->refs;
  if(data->refs == 0)
  {
    data->next = firstFreeData;
    firstFreeData = data;
  }
}

void String::grow(unsigned int size, unsigned int length)
{
  ASSERT(size >= length);
  ASSERT(length <= data->size);
  if(data->refs > 1)
  {
    Data* otherData = data;
    --otherData->refs;

    init(size, otherData->str, length);
  }
  else if(data->size < size)
  {
    char* otherStr = (char*)data->str;
    data->size = size + 16 + (size >> 1); // badass growing strategy
    data->str = new char[data->size + 1];
    if(length)
      memcpy((char*)data->str, otherStr, length);
    delete[] otherStr;

    data->length = length;
    ((char*)data->str)[length] = '\0';
  }
}

String& String::operator=(const String& other)
{
  free();
  data = other.data;
  ++data->refs;
  return *this;
}

bool String::operator==(const String& other) const
{
  return data->length == other.data->length && memcmp(data->str, other.data->str, data->length) == 0;
}

bool String::operator!=(const String& other) const
{
  return data->length != other.data->length || memcmp(data->str, other.data->str, data->length) != 0;
}

char* String::getData(unsigned int size)
{
  grow(size, 0);
  return (char*)data->str;
}

void String::setCapacity(unsigned int size)
{
  grow(size < data->length ? data->length : size, data->length); // enforce detach
}

String& String::append(char c)
{
  unsigned int newLength = data->length + 1;
  grow(newLength, data->length);
  ((char*)data->str)[data->length] = c;
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::append(const String& str)
{
  unsigned int newLength = data->length + str.data->length;
  grow(newLength, data->length);
  memcpy(((char*)data->str) + data->length, str.data->str, str.data->length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::append(const char* str, unsigned int length)
{
  unsigned int newLength = data->length + length;
  grow(newLength, data->length);
  memcpy(((char*)data->str) + data->length, str, length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

String& String::prepend(const String& str)
{
  // TODO: optimize this using memmove when possible?
  String old(*this);
  unsigned int newLength = data->length + str.data->length;
  grow(newLength, 0);
  memcpy((char*)data->str, str.data->str, str.data->length);
  memcpy(((char*)data->str) + str.data->length, old.data->str, old.data->length);
  ((char*)data->str)[newLength] = '\0';
  data->length = newLength;
  return *this;
}

void String::clear()
{
  if(data->refs == 1)
  {
    *(char*)data->str = '\0';
    data->length = 0;
  }
  else
  {
    free();
    data = &emptyData;
    ++data->refs;
  }
}

void String::setLength(unsigned int length)
{
  grow(length, length); // detach
  ((char*)data->str)[length] = '\0';
  data->length = length;
}

String& String::format(unsigned int size, const char* format, ...)
{
  int length;
  va_list ap;
  va_start(ap, format);
#ifdef _MSC_VER
  length = vsprintf_s(getData(size), size, format, ap);
#else
  length = ::vsnprintf(getData(size), size, format, ap);
  if(length < 0)
    length = size;
#endif
  va_end(ap);
  ((char*)data->str)[length] = '\0';
  data->length = length;
  return *this;
}

String String::substr(int start, int length) const
{
  if(start < 0)
  {
    start = (int)data->length + start;
    if(start < 0)
      start = 0;
  }
  else if((unsigned int)start > data->length)
    start = data->length;

  int end;
  if(length >= 0)
  {
    end = start + length;
    if((unsigned int)end > data->length)
      end = data->length;
  }
  else
    end = data->length;

  length = end - start;
  String result(length);
  memcpy((char*)result.data->str, data->str + start, length);
  ((char*)result.data->str)[length] = '\0';
  result.data->length = length;
  return result;
}

int String::subst(const String& from, const String& to)
{
  String result(data->length + to.data->length * 2);
  const char* str = data->str;
  const char* f = from.data->str;
  unsigned int flen = from.data->length;
  const char* start = str;
  int i = 0;
  while(*str)
    if(*str == *f && strncmp(str, f, flen) == 0)
    {
      if(str > start)
        result.append(start, str - start);
      result.append(to);
      str += flen;
      start = str;
      ++i;
    }
    else
      ++str;
  if(str > start)
    result.append(start, str - start);
  *this = result;
  return i;
}

static bool szWildMatch7(const char* pat, const char* str);
static bool szWildMatch1(const char* pat, const char* str, const char*& matchstart, const char*& matchend);

bool String::patmatch(const String& pattern) const
{
  return szWildMatch7(pattern.data->str, data->str);
}

bool String::patsubst(const String& pattern, const String& replace)
{
  const char* matchstart;
  const char* matchend;
  if(!szWildMatch1(pattern.data->str, data->str, matchstart, matchend))
    return false;

  unsigned int matchlen = matchend - matchstart;
  String result(matchlen + replace.data->length);
  char* dest = (char*)result.data->str;
  for(const char* src = replace.data->str; *src; ++src)
    if(*src == '\\' && (src[1] == '%' || (src[1] == '\\' && src[2] == '%')))
    {
      ++src;
      *(dest++) = *src;
    }
    else if(*src == '%')
    {
      memcpy(dest, matchstart, matchlen);
      dest += matchlen;
      ++src;
      unsigned int left = replace.data->length - (src - replace.data->str);
      memcpy(dest, src, left);
      dest += left;
      break;
    }
    else
      *(dest++) = *src;
  *dest = '\0';
  result.data->length = dest - result.data->str;
  *this = result;
  return true;
}

/*
slightly modified wildcard matching functions based on Alessandro Cantatore's algorithms
http://xoomer.virgilio.it/acantato/dev/wildcard/wildmatch.html
*/

static bool szWildMatch7(const char* pat, const char* str) {
    const char* s, * p;
    bool star = false;

loopStart:
    for (s = str, p = pat; *s; ++s, ++p) {
      switch (*p) {
          case '%':
            star = true;
            str = s, pat = p;
            do { ++pat; } while (*pat == '%');
            if (!*pat) return true;
            goto loopStart;
          default:
            if (*s != *p) goto starCheck;
            break;
      }
    }
    while (*p == '%') ++p;
    return !*p;

starCheck:
    if (!star) return false;
    str++;
    goto loopStart;
}

static bool szWildMatch1(const char* pat, const char* str, const char*& matchstart, const char*& matchend)
{
  while(*str)
  {
    switch(*pat)
    {
    case '%':
      matchstart = str;
      do { ++pat; } while(*pat == '%');
      if(!*pat)
      {
        matchend = matchstart + strlen(matchstart);
        return true;
      }
      while(*str)
        if(szWildMatch7(pat, str++))
        {
          matchend = str - 1;
          return true;
        }
      return false;
    default:
      if(*str != *pat)
        return false;
      break;
    }
    ++pat, ++str;
  }
  while(*pat == '%')
    ++pat;
  if(!*pat)
  {
    matchstart = matchend = str;
    return true;
  }
  return false;
}

String& String::lowercase()
{
  grow(data->length, data->length); // detach
  for(char* str = (char*)data->str; *str; ++str)
    *str = tolower(*(unsigned char*)str);
  return *this;
}

String& String::uppercase()
{
  grow(data->length, data->length); // detach
  for(char* str = (char*)data->str; *str; ++str)
    *str = toupper(*(unsigned char*)str);
  return *this;
}
<|endoftext|>


<commit_before>#include <SDL2/SDL.h>
#include <stdio.h>
#include <iostream>
#include <string>

#include <Vect2.h>

#include "Systems/RenderSystem.h"
#include "Systems/ComponentManager.h"
#include "Systems/EntitySystem.h"
#include "Components/Sprite.h"
#include "Components/Transform.h"
#include "Components/BoxCollider.h"
#include "Components/SpriteSheet.h"
#include "Components/Animation.h"
#include "Components/SlopeCollider.h"
#include "Systems/ECS.h"
#include "Core.h"
#include "Systems/MovementSystem.h"

#include "Input/KeyboardController.h"
#include "Input/GameController.h"
#include "Utility/TextureLoader.h"
#include "Utility/TextureStore.h"
#include "Utility/ImageStore.h"
#include "Utility/ImageMod.h"
#include "Utility/MapFileLoader.h"

using namespace std;

int main(int argc, char* argv[])
{
	Core core;
	SDL_Renderer* render = core.getRenderer();

	//draw a grid - pre render a static image.
	const float tileWidth = 56;
	const float tileHeight = 56;
	const int level_width = 800;
	const int level_height = 600;
	const int tiles_per_row = level_width / (int)tileWidth;
	const int tiles_per_col = level_height / (int)tileHeight;
	const int x_offset = 17 / 2;
	const int y_offset = 41 / 2;

	SDL_Texture* grid = SDL_CreateTexture(render, SDL_GetWindowPixelFormat(core.getWindow()), SDL_TEXTUREACCESS_TARGET, level_width, level_height);
	SDL_SetTextureBlendMode(grid, SDL_BlendMode::SDL_BLENDMODE_BLEND);
	SDL_SetRenderTarget(render, grid);
	//transparent background
	SDL_SetRenderDrawColor(render, 255, 255, 255, 0);
	SDL_RenderClear(render);
	//black
	SDL_SetRenderDrawColor(render, 0, 0, 0, 255);
	for (int r = 0;r < tiles_per_col;++r)
	{
		for (int c = 0;c < tiles_per_row;++c)
		{
			SDL_Rect gridBox;
			gridBox.x = c * (int)tileWidth + x_offset;
			gridBox.y = r * (int)tileHeight + y_offset;
			gridBox.w = (int)tileWidth;
			gridBox.h = (int)tileHeight;
			SDL_RenderDrawRect(render,&gridBox);
		}
	}

	SDL_RenderPresent(render);
	//set the render target back to the window's screen.
	SDL_SetRenderTarget(render, NULL);

	//setup texture file paths
	string mainPath(SDL_GetBasePath());
	mainPath += string("resources\\");

	string backgroundPath = mainPath + string("hills.png");
	string tilePath = mainPath + string("box.png");

	ImageStore store(render);
	store.Load("hills.png", backgroundPath);
	store.Load("box.png", tilePath);

	ECS ecs;

	int bgID = ecs.entitySystem.CreateEntity("Background");
	auto bgTransform = new Transform();
	bgTransform->position = Vect2(0.0f, 0.0f);
	auto bgSprite = new Sprite(store.Get("hills.png"));
	ecs.transforms.AddComponent(bgID, bgTransform);
	ecs.sprites.AddComponent(bgID, bgSprite);

	//initialize systems
	RenderSystem renderSys(&ecs);
	renderSys.Init(SCREEN_WIDTH, SCREEN_HEIGHT);

	SDL_Point mousePos{ 0,0 };
	//screen to game world coordinates as ints
	SDL_Point gameCoords{ 0,0 };

	//---------------- Game Loop ------------------//

	//observedDeltaTime is measured in milliseconds
	float observedDeltaTime = core.getTargetDeltaTime();
	float deltaTime = observedDeltaTime / 1000.0f;//converts from milliseconds to seconds
	//to avoid unnecessary context switches os might do (which I have no control over.. cache the target delta time)
	float targetDeltaTime = core.getTargetDeltaTime();
	Uint64 observedFPS = core.getTargetFPS();
	float currentTime = 0.0f;
	Uint64 performanceFrequency = SDL_GetPerformanceFrequency();
	Uint64 startCount = SDL_GetPerformanceCounter();
	Uint64 endCount;
	bool running = true;
	while (running)
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
				running = false;

			if (event.type == SDL_MOUSEBUTTONDOWN)
			{
				if (event.button.button == SDL_BUTTON_LEFT)
				{
					printf("left mouse click (%d,%d)\n", mousePos.x, mousePos.y);
					printf("game world coords(%d, %d)\n", gameCoords.x, gameCoords.y);
					//if (mousePos.x > 0 && mousePos.x + (int)tileWidth < SCREEN_WIDTH)
					//{
						int tileID = ecs.entitySystem.CreateEntity("Tile");
						Vect2 tilePosition;
					//	tilePosition.x = (float)gameCoords.x;
					//	tilePosition.y = (float)gameCoords.y;

						//clamp tile position to grid.
						int r = gameCoords.y / (int)tileHeight;
						int c = gameCoords.x / (int)tileWidth;
						tilePosition.x = c * tileWidth + x_offset;
						tilePosition.y = r * tileHeight + y_offset;

						ecs.transforms.AddComponent(tileID, new Transform(tilePosition));

						Sprite* sprite = new Sprite(store.Get("box.png"));
						sprite->width = (int)tileWidth;
						sprite->height = (int)tileHeight;
						ecs.sprites.AddComponent(tileID, sprite);
					//}

				}
			}
			else if (event.type == SDL_MOUSEMOTION)
			{
				mousePos.x = event.button.x;
				mousePos.y = event.button.y;
				gameCoords.x = renderSys.camera.x + mousePos.x;
				gameCoords.y = renderSys.camera.y + mousePos.y;
			}
		}
		//pixels per frame
		int camSpeed = 2;
		if (mousePos.x + 5 > SCREEN_WIDTH)
		{
			if (renderSys.camera.x + renderSys.camera.w < level_width)
			{
				renderSys.camera.x += camSpeed;
			}
		}

		if (mousePos.x < 5)
		{
			if (renderSys.camera.x > 0)
				renderSys.camera.x -= camSpeed;
		}

		if (mousePos.y + 5 > SCREEN_HEIGHT)
		{
			int level_height = 600;
			if (renderSys.camera.y + renderSys.camera.h < level_height)
				renderSys.camera.y += camSpeed;
		}

		if (mousePos.y < 5)
		{
			if (renderSys.camera.y > 0)
				renderSys.camera.y -= camSpeed;
		}

		renderSys.Update(render);
		SDL_RenderCopy(render, grid, &renderSys.camera, NULL);
		renderSys.Draw(render);

		endCount = SDL_GetPerformanceCounter();
		observedDeltaTime = (1000.0f * (endCount - startCount)) / performanceFrequency;//gives ms
		observedFPS = performanceFrequency / (endCount - startCount);

		//if the computer can process the update and draw functions faster than 60 fps...
		//cap the frame-rate here to ensure that all computers play roughly around the same fps
		float msDifference = targetDeltaTime - observedDeltaTime;
		if (msDifference > 0)
		{
			SDL_Delay((Uint32)msDifference);
			//Note: must re-record the times after the delay since the times before the delay maybe
			//under 16.666 ms
			endCount = SDL_GetPerformanceCounter();
			observedDeltaTime = (1000.0f * (endCount - startCount)) / performanceFrequency;//gives ms
			observedFPS = performanceFrequency / (endCount - startCount);
		}

		currentTime += observedDeltaTime;
		deltaTime = observedDeltaTime / 1000.0f;
		startCount = endCount;

		//display fps text in title
		std::string title("Beat Em Left");
		title += std::string(" | FPS: ") + std::to_string(observedFPS);
		SDL_SetWindowTitle(core.getWindow(), title.c_str());

	}

	SDL_DestroyTexture(grid);

	return 0;
}<commit_msg>WIP tile removal button<commit_after>#include <SDL2/SDL.h>
#include <stdio.h>
#include <iostream>
#include <string>

#include <Vect2.h>

#include "Systems/RenderSystem.h"
#include "Systems/ComponentManager.h"
#include "Systems/EntitySystem.h"
#include "Components/Sprite.h"
#include "Components/Transform.h"
#include "Components/BoxCollider.h"
#include "Components/SpriteSheet.h"
#include "Components/Animation.h"
#include "Components/SlopeCollider.h"
#include "Systems/ECS.h"
#include "Core.h"
#include "Systems/MovementSystem.h"

#include "Input/KeyboardController.h"
#include "Input/GameController.h"
#include "Utility/TextureLoader.h"
#include "Utility/TextureStore.h"
#include "Utility/ImageStore.h"
#include "Utility/ImageMod.h"
#include "Utility/MapFileLoader.h"

using namespace std;

int main(int argc, char* argv[])
{
	Core core;
	SDL_Renderer* render = core.getRenderer();

	//draw a grid - pre render a static image.
	const float tileWidth = 56;
	const float tileHeight = 56;
	const int level_width = 800;
	const int level_height = 600;
	const int tiles_per_row = level_width / (int)tileWidth;
	const int tiles_per_col = level_height / (int)tileHeight;
	const int x_offset = 17 / 2;
	const int y_offset = 41 / 2;

	SDL_Texture* grid = SDL_CreateTexture(render, SDL_GetWindowPixelFormat(core.getWindow()), SDL_TEXTUREACCESS_TARGET, level_width, level_height);
	SDL_SetTextureBlendMode(grid, SDL_BlendMode::SDL_BLENDMODE_BLEND);
	SDL_SetRenderTarget(render, grid);
	//transparent background
	SDL_SetRenderDrawColor(render, 255, 255, 255, 0);
	SDL_RenderClear(render);
	//black
	SDL_SetRenderDrawColor(render, 0, 0, 0, 255);
	for (int r = 0;r < tiles_per_col;++r)
	{
		for (int c = 0;c < tiles_per_row;++c)
		{
			SDL_Rect gridBox;
			gridBox.x = c * (int)tileWidth + x_offset;
			gridBox.y = r * (int)tileHeight + y_offset;
			gridBox.w = (int)tileWidth;
			gridBox.h = (int)tileHeight;
			SDL_RenderDrawRect(render,&gridBox);
		}
	}

	SDL_RenderPresent(render);
	//set the render target back to the window's screen.
	SDL_SetRenderTarget(render, NULL);

	//setup texture file paths
	string mainPath(SDL_GetBasePath());
	mainPath += string("resources\\");

	string backgroundPath = mainPath + string("hills.png");
	string tilePath = mainPath + string("box.png");

	ImageStore store(render);
	store.Load("hills.png", backgroundPath);
	store.Load("box.png", tilePath);

	ECS ecs;

	int bgID = ecs.entitySystem.CreateEntity("Background");
	auto bgTransform = new Transform();
	bgTransform->position = Vect2(0.0f, 0.0f);
	auto bgSprite = new Sprite(store.Get("hills.png"));
	ecs.transforms.AddComponent(bgID, bgTransform);
	ecs.sprites.AddComponent(bgID, bgSprite);

	//initialize systems
	RenderSystem renderSys(&ecs);
	renderSys.Init(SCREEN_WIDTH, SCREEN_HEIGHT);

	SDL_Point mousePos{ 0,0 };
	//screen to game world coordinates as ints
	SDL_Point gameCoords{ 0,0 };

	//---------------- Game Loop ------------------//

	//observedDeltaTime is measured in milliseconds
	float observedDeltaTime = core.getTargetDeltaTime();
	float deltaTime = observedDeltaTime / 1000.0f;//converts from milliseconds to seconds
	//to avoid unnecessary context switches os might do (which I have no control over.. cache the target delta time)
	float targetDeltaTime = core.getTargetDeltaTime();
	Uint64 observedFPS = core.getTargetFPS();
	float currentTime = 0.0f;
	Uint64 performanceFrequency = SDL_GetPerformanceFrequency();
	Uint64 startCount = SDL_GetPerformanceCounter();
	Uint64 endCount;
	bool running = true;
	while (running)
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
				running = false;

			if (event.type == SDL_MOUSEBUTTONDOWN)
			{
				//add a tile
				if (event.button.button == SDL_BUTTON_LEFT)
				{
					printf("left mouse click (%d,%d)\n", mousePos.x, mousePos.y);
					printf("game world coords(%d, %d)\n", gameCoords.x, gameCoords.y);
					//if (mousePos.x > 0 && mousePos.x + (int)tileWidth < SCREEN_WIDTH)
					//{
						int tileID = ecs.entitySystem.CreateEntity("Tile");
						Vect2 tilePosition;
					//	tilePosition.x = (float)gameCoords.x;
					//	tilePosition.y = (float)gameCoords.y;

						//clamp tile position to grid.
						int r = gameCoords.y / (int)tileHeight;
						int c = gameCoords.x / (int)tileWidth;
						tilePosition.x = c * tileWidth + x_offset;
						tilePosition.y = r * tileHeight + y_offset;

						ecs.transforms.AddComponent(tileID, new Transform(tilePosition));

						Sprite* sprite = new Sprite(store.Get("box.png"));
						sprite->width = (int)tileWidth;
						sprite->height = (int)tileHeight;
						ecs.sprites.AddComponent(tileID, sprite);
					//}

				}

				//TODO: remove at tile (create a simple data structure that tells us if a tile is occupying a space or not
				if (event.button.button == SDL_BUTTON_RIGHT)
				{
					//check if point overlaps in a rectangle!
					SDL_Point pixelCoords;
					pixelCoords.y = gameCoords.y / (int)tileHeight;
					pixelCoords.x = gameCoords.x / (int)tileWidth;
					pixelCoords.y = (pixelCoords.y * (int)tileHeight) + y_offset;
					pixelCoords.x = (pixelCoords.x * (int)tileWidth) + x_offset;

					//.....

					printf("remove tile at: (%d,%d)\n", gameCoords.x, gameCoords.y);
				}
			}
			else if (event.type == SDL_MOUSEMOTION)
			{
				mousePos.x = event.button.x;
				mousePos.y = event.button.y;
				gameCoords.x = renderSys.camera.x + mousePos.x;
				gameCoords.y = renderSys.camera.y + mousePos.y;
			}
		}
		//pixels per frame
		int camSpeed = 2;
		if (mousePos.x + 5 > SCREEN_WIDTH)
		{
			if (renderSys.camera.x + renderSys.camera.w < level_width)
			{
				renderSys.camera.x += camSpeed;
			}
		}

		if (mousePos.x < 5)
		{
			if (renderSys.camera.x > 0)
				renderSys.camera.x -= camSpeed;
		}

		if (mousePos.y + 5 > SCREEN_HEIGHT)
		{
			int level_height = 600;
			if (renderSys.camera.y + renderSys.camera.h < level_height)
				renderSys.camera.y += camSpeed;
		}

		if (mousePos.y < 5)
		{
			if (renderSys.camera.y > 0)
				renderSys.camera.y -= camSpeed;
		}

		renderSys.Update(render);
		SDL_RenderCopy(render, grid, &renderSys.camera, NULL);
		renderSys.Draw(render);

		endCount = SDL_GetPerformanceCounter();
		observedDeltaTime = (1000.0f * (endCount - startCount)) / performanceFrequency;//gives ms
		observedFPS = performanceFrequency / (endCount - startCount);

		//if the computer can process the update and draw functions faster than 60 fps...
		//cap the frame-rate here to ensure that all computers play roughly around the same fps
		float msDifference = targetDeltaTime - observedDeltaTime;
		if (msDifference > 0)
		{
			SDL_Delay((Uint32)msDifference);
			//Note: must re-record the times after the delay since the times before the delay maybe
			//under 16.666 ms
			endCount = SDL_GetPerformanceCounter();
			observedDeltaTime = (1000.0f * (endCount - startCount)) / performanceFrequency;//gives ms
			observedFPS = performanceFrequency / (endCount - startCount);
		}

		currentTime += observedDeltaTime;
		deltaTime = observedDeltaTime / 1000.0f;
		startCount = endCount;

		//display fps text in title
		std::string title("Beat Em Left");
		title += std::string(" | FPS: ") + std::to_string(observedFPS);
		SDL_SetWindowTitle(core.getWindow(), title.c_str());

	}

	SDL_DestroyTexture(grid);

	return 0;
}<|endoftext|>


<commit_before>#include <Box2D/Box2D.h>
#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/Rand.h"
#include "Attractor.h"
#include "Particle.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class Ex56ForcesApp : public AppNative {
  public:
	void setup();
	void mouseDown( MouseEvent event );
    void mouseUp( MouseEvent event );
    void mouseMove( MouseEvent event );
    void mouseDrag( MouseEvent event );
	void update();
	void draw();
    void shutdown();

    b2World *world;
    float32 timeStep;
    float32 velocityIterations;
    int32 positionIterations;

    Attractor attractor;
    vector<Particle> particles;
    Vec2f mouseLocation;
};

void Ex56ForcesApp::setup() {
    world = new b2World( b2Vec2( 0.0f, 0.0f ) ); // no gravity in this example!
    timeStep = 1.0f / 60.0f;
    velocityIterations = 8;
    positionIterations = 3;

    attractor = Attractor( world, getWindowCenter().x, getWindowCenter().y );
    for (int i = 0; i < 100; ++i) {
        particles.push_back( Particle(world, Vec2f( Rand::randFloat( getWindowWidth() ), Rand::randFloat( getWindowHeight() ) ), randFloat( 7.0f, 14.0f ) ) );
    }
}

void Ex56ForcesApp::mouseDown( MouseEvent event ) {
    attractor.clicked( event.getPos() );
}

void Ex56ForcesApp::mouseUp( MouseEvent event ) {
    attractor.stopDragging();
}

void Ex56ForcesApp::mouseMove( MouseEvent event ) {
    mouseLocation = event.getPos();
}

void Ex56ForcesApp::mouseDrag( MouseEvent event ) {
    mouseLocation = event.getPos();
}

void Ex56ForcesApp::update() {
    world->Step( timeStep, velocityIterations, positionIterations );
    attractor.hover( mouseLocation );
    attractor.drag( mouseLocation );

    for ( auto& particle : particles ) {
        particle.update( world, attractor.attract( particle ) );
    }
}

void Ex56ForcesApp::draw() {
	gl::clear( Color( 0, 0, 0 ) );

    attractor.draw();

    for ( auto& particle : particles ) {
        particle.draw();
    }
}

void Ex56ForcesApp::shutdown() {
    for ( auto& particle : particles ) {
        particle.killBody( world );
    }
    attractor.killBody( world );
    delete world;
}

CINDER_APP_NATIVE( Ex56ForcesApp, RendererGl )
<commit_msg>Example 5.6 Updated<commit_after>#include <Box2D/Box2D.h>
#include "cinder/app/AppNative.h"
#include "cinder/gl/gl.h"
#include "cinder/Rand.h"
#include "Attractor.h"
#include "Particle.h"

using namespace ci;
using namespace ci::app;
using namespace std;

class Ex56ForcesApp : public AppNative {
  public:
	void setup();
	void mouseDown( MouseEvent event );
    void mouseUp( MouseEvent event );
    void mouseMove( MouseEvent event );
    void mouseDrag( MouseEvent event );
	void update();
	void draw();
    void shutdown();

    b2World *world;
    float32 timeStep;
    float32 velocityIterations;
    int32 positionIterations;

    Attractor attractor;
    vector<Particle> particles;
    Vec2f mouseLocation;
};

void Ex56ForcesApp::setup() {
    world = new b2World( b2Vec2( 0.0f, 0.0f ) ); // no gravity in this example!
    timeStep = 1.0f / 60.0f;
    velocityIterations = 8;
    positionIterations = 3;

    attractor = Attractor( world, getWindowCenter().x, getWindowCenter().y );
    for (int i = 0; i < 100; ++i) {
        particles.push_back( Particle(world, Vec2f( Rand::randFloat( getWindowWidth() ), Rand::randFloat( getWindowHeight() ) ), randFloat( 7.0f, 14.0f ) ) );
    }
}

void Ex56ForcesApp::mouseDown( MouseEvent event ) {
    attractor.clicked( event.getPos() );
}

void Ex56ForcesApp::mouseUp( MouseEvent event ) {
    attractor.stopDragging();
}

void Ex56ForcesApp::mouseMove( MouseEvent event ) {
    mouseLocation = event.getPos();
}

void Ex56ForcesApp::mouseDrag( MouseEvent event ) {
    mouseLocation = event.getPos();
}

void Ex56ForcesApp::update() {
    attractor.hover( mouseLocation );
    attractor.drag( mouseLocation );
    for ( auto& particle : particles ) {
        particle.update( world, attractor.attract( particle ) );
    }
    world->Step( timeStep, velocityIterations, positionIterations );
    world->ClearForces();
}

void Ex56ForcesApp::draw() {
	gl::clear( Color( 0, 0, 0 ) );

    attractor.draw();

    for ( auto& particle : particles ) {
        particle.draw();
    }
}

void Ex56ForcesApp::shutdown() {
    for ( auto& particle : particles ) {
        particle.killBody( world );
    }
    attractor.killBody( world );
    delete world;
}

CINDER_APP_NATIVE( Ex56ForcesApp, RendererGl )
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <string>
#include <vector>

#include <gmock/gmock.h>

#include <process/future.hpp>
#include <process/gtest.hpp>
#include <process/owned.hpp>

#include <stout/gtest.hpp>
#include <stout/try.hpp>

#include <mesos/master/detector.hpp>

#include <mesos/mesos.hpp>
#include <mesos/scheduler.hpp>

#include "slave/flags.hpp"
#include "tests/cluster.hpp"
#include "tests/environment.hpp"
#include "tests/mesos.hpp"

using mesos::master::detector::MasterDetector;

using process::Future;
using process::Owned;

using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace tests {

class PosixRLimitsIsolatorTest : public MesosTest {};

// This test confirms that if a task exceeds configured resource
// limits it is forcibly terminated.
TEST_F(PosixRLimitsIsolatorTest, TaskExceedingLimit)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "posix/rlimits";

  Owned<MasterDetector> detector = master.get()->createDetector();

  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
  ASSERT_SOME(slave);

  MockScheduler sched;

  MesosSchedulerDriver driver(
      &sched,
      DEFAULT_FRAMEWORK_INFO,
      master.get()->pid,
      DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(_, _, _))
    .Times(1);

  Future<vector<Offer>> offers;
  EXPECT_CALL(sched, resourceOffers(_, _))
      .WillOnce(FutureArg<1>(&offers))
      .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_NE(0u, offers->size());

  // The task attempts to use an infinite amount of CPU time.
  TaskInfo task = createTask(
      offers.get()[0].slave_id(),
      offers.get()[0].resources(),
      "while true; do true; done");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);

  // Limit the process to use maximally 1 second of CPU time.
  RLimitInfo rlimitInfo;
  RLimitInfo::RLimit* cpuLimit = rlimitInfo.add_rlimits();
  cpuLimit->set_type(RLimitInfo::RLimit::RLMT_CPU);
  cpuLimit->set_soft(1);
  cpuLimit->set_hard(1);

  container->mutable_rlimit_info()->CopyFrom(rlimitInfo);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFailed;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&statusRunning))
    .WillOnce(FutureArg<1>(&statusFailed));

  driver.launchTasks(offers.get()[0].id(), {task});

  AWAIT_READY(statusRunning);
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFailed);
  EXPECT_EQ(task.task_id(), statusFailed->task_id());
  EXPECT_EQ(TASK_FAILED, statusFailed->state());

  driver.stop();
  driver.join();
}

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<commit_msg>Extended test coverage of posix/rlimits isolator.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 <string>
#include <vector>

#include <gmock/gmock.h>

#include <process/future.hpp>
#include <process/gtest.hpp>
#include <process/owned.hpp>

#include <stout/gtest.hpp>
#include <stout/try.hpp>

#include <mesos/master/detector.hpp>

#include <mesos/mesos.hpp>
#include <mesos/scheduler.hpp>

#include "slave/flags.hpp"
#include "tests/cluster.hpp"
#include "tests/environment.hpp"
#include "tests/mesos.hpp"

using mesos::master::detector::MasterDetector;

using process::Future;
using process::Owned;

using std::string;
using std::vector;

namespace mesos {
namespace internal {
namespace tests {

class PosixRLimitsIsolatorTest : public MesosTest {};

// This test checks the behavior of passed invalid limits.
TEST_F(PosixRLimitsIsolatorTest, InvalidLimits)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "posix/rlimits";

  Owned<MasterDetector> detector = master.get()->createDetector();

  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
  ASSERT_SOME(slave);

  MockScheduler sched;

  MesosSchedulerDriver driver(
      &sched,
      DEFAULT_FRAMEWORK_INFO,
      master.get()->pid, DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(_, _, _))
      .Times(1);

  Future<vector<Offer>> offers;

  EXPECT_CALL(sched, resourceOffers(_, _))
      .WillOnce(FutureArg<1>(&offers))
      .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_NE(0u, offers->size());

  TaskInfo task = createTask(
      offers.get()[0].slave_id(),
      offers.get()[0].resources(),
      "true");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);

  // Set impossible limit soft > hard.
  RLimitInfo rlimitInfo;
  RLimitInfo::RLimit* rlimit = rlimitInfo.add_rlimits();
  rlimit->set_type(RLimitInfo::RLimit::RLMT_CPU);
  rlimit->set_soft(100);
  rlimit->set_hard(1);

  container->mutable_rlimit_info()->CopyFrom(rlimitInfo);

  Future<TaskStatus> taskStatus;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
      .WillOnce(FutureArg<1>(&taskStatus));

  driver.launchTasks(offers.get()[0].id(), {task});

  AWAIT_READY(taskStatus);
  EXPECT_EQ(task.task_id(), taskStatus->task_id());
  EXPECT_EQ(TASK_FAILED, taskStatus->state());
  EXPECT_EQ(TaskStatus::REASON_EXECUTOR_TERMINATED, taskStatus->reason());

  driver.stop();
  driver.join();
}

// This test confirms that setting no values for the soft and hard
// limits implies an unlimited resource.
TEST_F(PosixRLimitsIsolatorTest, UnsetLimits) {
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "posix/rlimits";

  Owned<MasterDetector> detector = master.get()->createDetector();

  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
  ASSERT_SOME(slave);

  MockScheduler sched;

  MesosSchedulerDriver driver(
      &sched,
      DEFAULT_FRAMEWORK_INFO,
      master.get()->pid,
      DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(_, _, _))
      .Times(1);

  Future<vector<Offer>> offers;

  EXPECT_CALL(sched, resourceOffers(_, _))
      .WillOnce(FutureArg<1>(&offers))
      .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_NE(0u, offers->size());

  TaskInfo task = createTask(
      offers.get()[0].slave_id(),
      offers.get()[0].resources(),
      "exit `ulimit -c | grep -q unlimited`");

  // Force usage of C locale as we interpret a potentially translated
  // string in the task's command.
  mesos::Environment::Variable* locale =
      task.mutable_command()->mutable_environment()->add_variables();
  locale->set_name("LC_ALL");
  locale->set_value("C");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);

  // Setting rlimit for core without soft or hard limit signifies
  // unlimited range.
  RLimitInfo rlimitInfo;
  RLimitInfo::RLimit* rlimit = rlimitInfo.add_rlimits();
  rlimit->set_type(RLimitInfo::RLimit::RLMT_CORE);

  container->mutable_rlimit_info()->CopyFrom(rlimitInfo);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFinal;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
      .WillOnce(FutureArg<1>(&statusRunning))
      .WillOnce(FutureArg<1>(&statusFinal));

  driver.launchTasks(offers.get()[0].id(), {task});

  AWAIT_READY(statusRunning);
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFinal);
  EXPECT_EQ(task.task_id(), statusFinal->task_id());
  EXPECT_EQ(TASK_FINISHED, statusFinal->state());

  driver.stop();
  driver.join();
}

// This test confirms that setting just one of the soft/hard limits is
// an error.
TEST_F(PosixRLimitsIsolatorTest, BothSoftAndHardLimitSet)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "posix/rlimits";

  Owned<MasterDetector> detector = master.get()->createDetector();

  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
  ASSERT_SOME(slave);

  MockScheduler sched;

  MesosSchedulerDriver driver(
      &sched,
      DEFAULT_FRAMEWORK_INFO,
      master.get()->pid,
      DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(_, _, _))
      .Times(1);

  Future<vector<Offer>> offers;

  EXPECT_CALL(sched, resourceOffers(_, _))
      .WillOnce(FutureArg<1>(&offers))
      .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_NE(0u, offers->size());

  TaskInfo task = createTask(
      offers.get()[0].slave_id(),
      offers.get()[0].resources(),
      "true");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);

  RLimitInfo rlimitInfo;
  RLimitInfo::RLimit* rlimit = rlimitInfo.add_rlimits();
  rlimit->set_type(RLimitInfo::RLimit::RLMT_CORE);
  rlimit->set_soft(1);

  container->mutable_rlimit_info()->CopyFrom(rlimitInfo);

  Future<TaskStatus> status;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
      .WillOnce(FutureArg<1>(&status));

  driver.launchTasks(offers.get()[0].id(), {task});

  AWAIT_READY(status);
  EXPECT_EQ(task.task_id(), status->task_id());
  EXPECT_EQ(TASK_FAILED, status->state());
  EXPECT_EQ(TaskStatus::REASON_EXECUTOR_TERMINATED, status->reason());

  driver.stop();
  driver.join();
}

// This test confirms that if a task exceeds configured resource
// limits it is forcibly terminated.
TEST_F(PosixRLimitsIsolatorTest, TaskExceedingLimit)
{
  Try<Owned<cluster::Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "posix/rlimits";

  Owned<MasterDetector> detector = master.get()->createDetector();

  Try<Owned<cluster::Slave>> slave = StartSlave(detector.get(), flags);
  ASSERT_SOME(slave);

  MockScheduler sched;

  MesosSchedulerDriver driver(
      &sched,
      DEFAULT_FRAMEWORK_INFO,
      master.get()->pid,
      DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(_, _, _))
      .Times(1);

  Future<vector<Offer>> offers;

  EXPECT_CALL(sched, resourceOffers(_, _))
      .WillOnce(FutureArg<1>(&offers))
      .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_NE(0u, offers->size());

  // The task attempts to use an infinite amount of CPU time.
  TaskInfo task = createTask(
      offers.get()[0].slave_id(),
      offers.get()[0].resources(),
      "while true; do true; done");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);

  // Limit the process to use maximally 1 second of CPU time.
  RLimitInfo rlimitInfo;
  RLimitInfo::RLimit* cpuLimit = rlimitInfo.add_rlimits();
  cpuLimit->set_type(RLimitInfo::RLimit::RLMT_CPU);
  cpuLimit->set_soft(1);
  cpuLimit->set_hard(1);

  container->mutable_rlimit_info()->CopyFrom(rlimitInfo);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFailed;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&statusRunning))
    .WillOnce(FutureArg<1>(&statusFailed));

  driver.launchTasks(offers.get()[0].id(), {task});

  AWAIT_READY(statusRunning);
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFailed);
  EXPECT_EQ(task.task_id(), statusFailed->task_id());
  EXPECT_EQ(TASK_FAILED, statusFailed->state());

  driver.stop();
  driver.join();
}

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef	_Stroika_Foundation_Containers_TimedCache_inl_
#define	_Stroika_Foundation_Containers_TimedCache_inl_	1

#include	"../Debug/Assertions.h"

namespace	Stroika {
	namespace	Foundation {
		namespace	Containers {

			template	<typename	KEY, typename RESULT>
				TimedCache<KEY,RESULT>::TimedCache (bool accessFreshensDate, Stroika::Foundation::Time::DurationSecondsType timeoutInSeconds):
					fMap (),
					fAccessFreshensDate (accessFreshensDate),
					fTimeout (timeoutInSeconds),
					fNextAutoClearAt (Time::GetTickCount () + timeoutInSeconds)
					#if		qKeepTimedCacheStats
						,fCachedCollected_Hits (0)
						,fCachedCollected_Misses (0)
					#endif
					{
						Require (fTimeout > 0.0f);
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::SetTimeout (Stroika::Foundation::Time::DurationSecondsType timeoutInSeconds)
					{
						Require (timeoutInSeconds > 0.0f);
						if (fTimeout != timeoutInSeconds) {
							ClearIfNeeded_ ();
							fTimeout = timeoutInSeconds;
							ClearIfNeeded_ ();
						}
					}
			template	<typename	KEY, typename RESULT>
				bool	TimedCache<KEY,RESULT>::AccessElement (const KEY& key, RESULT* result)
					{
						ClearIfNeeded_ ();
						map<KEY,MyResult>::iterator i = fMap.find (key);
						if (i == fMap.end ()) {
							#if		qKeepTimedCacheStats
								fCachedCollected_Misses++;
							#endif
							return false;
						}
						else {
							if (fAccessFreshensDate) {
								i->second.fLastAccessedAt = Time::GetTickCount ();
							}
							if (result != NULL) {
								*result = i->second.fResult;
							}
							#if		qKeepTimedCacheStats
								fCachedCollected_Hits++;
							#endif
							return true;
						}
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::AddElement (const KEY& key, const RESULT& result)
					{
						ClearIfNeeded_ ();
						map<KEY,MyResult>::iterator i = fMap.find (key);
						if (i == fMap.end ()) {
							fMap.insert (map<KEY,MyResult>::value_type (key, MyResult (result)));
						}
						else {
							i->second = MyResult (result);	// overwrite if its already there
						}
					}
			template	<typename	KEY, typename RESULT>
				inline	void	TimedCache<KEY,RESULT>::DoBookkeeping ()
					{
						ClearOld_ ();
					}
			template	<typename	KEY, typename RESULT>
				inline	void	TimedCache<KEY,RESULT>::ClearIfNeeded_ ()
					{
						if (fNextAutoClearAt < Time::GetTickCount ()) {
							ClearOld_ ();
						}
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::ClearOld_ ()
					{
						Stroika::Foundation::Time::DurationSecondsType	now	=	Time::GetTickCount ();
						fNextAutoClearAt = now + fTimeout/2.0f;	// somewhat arbitrary how far into the future we do this...
						Stroika::Foundation::Time::DurationSecondsType	lastAccessThreshold	=	now - fTimeout;
						for (map<KEY,MyResult>::iterator i = fMap.begin (); i != fMap.end (); ) {
							if (i->second.fLastAccessedAt < lastAccessThreshold) {
								i = fMap.erase (i);
							}
							else {
								++i;
							}
						}
					}
			#if		qKeepTimedCacheStats
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::DbgTraceStats (const TCHAR* label) const
					{
						size_t	total	=	fCachedCollected_Hits + fCachedCollected_Misses;
						if (total == 0) {
							total = 1;	// avoid divide by zero
						}
						DbgTrace (_T ("%s stats: hits=%d, misses=%d, hit%% %f."), label, fCachedCollected_Hits, fCachedCollected_Misses, float (fCachedCollected_Hits)/(float (total)));
					}
			#endif

		}
	}
}

#endif	/*_Stroika_Foundation_Containers_TimedCache_inl_*/
<commit_msg>small include fix<commit_after>
/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#ifndef	_Stroika_Foundation_Containers_TimedCache_inl_
#define	_Stroika_Foundation_Containers_TimedCache_inl_	1

#include	"../Debug/Assertions.h"
#include	"../Debug/Trace.h"

namespace	Stroika {
	namespace	Foundation {
		namespace	Containers {

			template	<typename	KEY, typename RESULT>
				TimedCache<KEY,RESULT>::TimedCache (bool accessFreshensDate, Stroika::Foundation::Time::DurationSecondsType timeoutInSeconds):
					fMap (),
					fAccessFreshensDate (accessFreshensDate),
					fTimeout (timeoutInSeconds),
					fNextAutoClearAt (Time::GetTickCount () + timeoutInSeconds)
					#if		qKeepTimedCacheStats
						,fCachedCollected_Hits (0)
						,fCachedCollected_Misses (0)
					#endif
					{
						Require (fTimeout > 0.0f);
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::SetTimeout (Stroika::Foundation::Time::DurationSecondsType timeoutInSeconds)
					{
						Require (timeoutInSeconds > 0.0f);
						if (fTimeout != timeoutInSeconds) {
							ClearIfNeeded_ ();
							fTimeout = timeoutInSeconds;
							ClearIfNeeded_ ();
						}
					}
			template	<typename	KEY, typename RESULT>
				bool	TimedCache<KEY,RESULT>::AccessElement (const KEY& key, RESULT* result)
					{
						ClearIfNeeded_ ();
						map<KEY,MyResult>::iterator i = fMap.find (key);
						if (i == fMap.end ()) {
							#if		qKeepTimedCacheStats
								fCachedCollected_Misses++;
							#endif
							return false;
						}
						else {
							if (fAccessFreshensDate) {
								i->second.fLastAccessedAt = Time::GetTickCount ();
							}
							if (result != NULL) {
								*result = i->second.fResult;
							}
							#if		qKeepTimedCacheStats
								fCachedCollected_Hits++;
							#endif
							return true;
						}
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::AddElement (const KEY& key, const RESULT& result)
					{
						ClearIfNeeded_ ();
						map<KEY,MyResult>::iterator i = fMap.find (key);
						if (i == fMap.end ()) {
							fMap.insert (map<KEY,MyResult>::value_type (key, MyResult (result)));
						}
						else {
							i->second = MyResult (result);	// overwrite if its already there
						}
					}
			template	<typename	KEY, typename RESULT>
				inline	void	TimedCache<KEY,RESULT>::DoBookkeeping ()
					{
						ClearOld_ ();
					}
			template	<typename	KEY, typename RESULT>
				inline	void	TimedCache<KEY,RESULT>::ClearIfNeeded_ ()
					{
						if (fNextAutoClearAt < Time::GetTickCount ()) {
							ClearOld_ ();
						}
					}
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::ClearOld_ ()
					{
						Stroika::Foundation::Time::DurationSecondsType	now	=	Time::GetTickCount ();
						fNextAutoClearAt = now + fTimeout/2.0f;	// somewhat arbitrary how far into the future we do this...
						Stroika::Foundation::Time::DurationSecondsType	lastAccessThreshold	=	now - fTimeout;
						for (map<KEY,MyResult>::iterator i = fMap.begin (); i != fMap.end (); ) {
							if (i->second.fLastAccessedAt < lastAccessThreshold) {
								i = fMap.erase (i);
							}
							else {
								++i;
							}
						}
					}
			#if		qKeepTimedCacheStats
			template	<typename	KEY, typename RESULT>
				void	TimedCache<KEY,RESULT>::DbgTraceStats (const TCHAR* label) const
					{
						size_t	total	=	fCachedCollected_Hits + fCachedCollected_Misses;
						if (total == 0) {
							total = 1;	// avoid divide by zero
						}
						DbgTrace (_T ("%s stats: hits=%d, misses=%d, hit%% %f."), label, fCachedCollected_Hits, fCachedCollected_Misses, float (fCachedCollected_Hits)/(float (total)));
					}
			#endif

		}
	}
}

#endif	/*_Stroika_Foundation_Containers_TimedCache_inl_*/
<|endoftext|>


<commit_before>#include "erl_nif.h"

static ErlNifResourceType* bulleterl_RESOURCE = NULL;

typedef struct
{
} bulleterl_handle;

// Prototypes
static ERL_NIF_TERM bulleterl_new(ErlNifEnv* env, int argc,
                                   const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bulleterl_myfunction(ErlNifEnv* env, int argc,
                                          const ERL_NIF_TERM argv[]);

static ErlNifFunc nif_funcs[] =
{
    {"new", 0, bulleterl_new},
    {"myfunction", 1, bulleterl_myfunction}
};

static ERL_NIF_TERM bulleterl_new(ErlNifEnv* env, int argc,
                                   const ERL_NIF_TERM argv[])
{
    bulleterl_handle* handle = enif_alloc_resource(bulleterl_RESOURCE,
                                                    sizeof(bulleterl_handle));
    ERL_NIF_TERM result = enif_make_resource(env, handle);
    enif_release_resource(handle);
    return enif_make_tuple2(env, enif_make_atom(env, "ok"), result);
}

static ERL_NIF_TERM bulleterl_myfunction(ErlNifEnv* env, int argc,
                                          const ERL_NIF_TERM argv[])
{
    return enif_make_atom(env, "ok");
}

static void bulleterl_resource_cleanup(ErlNifEnv* env, void* arg)
{
    /* Delete any dynamically allocated memory stored in bulleterl_handle */
    /* bulleterl_handle* handle = (bulleterl_handle*)arg; */
}

static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
    ErlNifResourceFlags flags = ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER;
    ErlNifResourceType* rt = enif_open_resource_type(env, NULL,
                                                     "bulleterl_resource",
                                                     &bulleterl_resource_cleanup,
                                                     flags, NULL);
    if (rt == NULL)
        return -1;

    bulleterl_RESOURCE = rt;

    return 0;
}

ERL_NIF_INIT(bulleterl, nif_funcs, &on_load, NULL, NULL, NULL);
<commit_msg>Corrected C++ errors, since C++ seems to be more stringent about types than C.<commit_after>#include "erl_nif.h"

static ErlNifResourceType* bulleterl_RESOURCE = NULL;

typedef struct
{
} bulleterl_handle;

// Prototypes
static ERL_NIF_TERM bulleterl_new(ErlNifEnv* env, int argc,
                                   const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM bulleterl_myfunction(ErlNifEnv* env, int argc,
                                          const ERL_NIF_TERM argv[]);

static ErlNifFunc nif_funcs[] =
{
    {"new", 0, bulleterl_new},
    {"myfunction", 1, bulleterl_myfunction}
};

static ERL_NIF_TERM bulleterl_new(ErlNifEnv* env, int argc,
                                   const ERL_NIF_TERM argv[])
{
    bulleterl_handle* handle = (bulleterl_handle*) enif_alloc_resource(bulleterl_RESOURCE,
                                                    sizeof(bulleterl_handle));
    ERL_NIF_TERM result = enif_make_resource(env, handle);
    enif_release_resource(handle);
    return enif_make_tuple2(env, enif_make_atom(env, "ok"), result);
}

static ERL_NIF_TERM bulleterl_myfunction(ErlNifEnv* env, int argc,
                                          const ERL_NIF_TERM argv[])
{
    return enif_make_atom(env, "ok");
}

static void bulleterl_resource_cleanup(ErlNifEnv* env, void* arg)
{
    /* Delete any dynamically allocated memory stored in bulleterl_handle */
    /* bulleterl_handle* handle = (bulleterl_handle*)arg; */
}

static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
{
    ErlNifResourceFlags flags = ErlNifResourceFlags(ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER);
    ErlNifResourceType* rt = enif_open_resource_type(env, NULL,
                                                     "bulleterl_resource",
                                                     &bulleterl_resource_cleanup,
                                                     flags, NULL);
    if (rt == NULL)
        return -1;

    bulleterl_RESOURCE = rt;

    return 0;
}

ERL_NIF_INIT(bulleterl, nif_funcs, &on_load, NULL, NULL, NULL);
<|endoftext|>


<commit_before>#include "ovpCTestCodecToolkit.h"

using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace OpenViBE::Plugins;

using namespace OpenViBEPlugins;
using namespace OpenViBEPlugins::Samples;

using namespace OpenViBEToolkit;

boolean CTestCodecToolkit::initialize(void)
{
	m_oStreamedMatrixDecoder.initialize(*this);
	m_oStreamedMatrixEncoder.initialize(*this);
	m_oStreamedMatrixEncoder.getInputMatrix().setReferenceTarget(m_oStreamedMatrixDecoder.getOutputMatrix());
	m_vDecoders.push_back(&m_oStreamedMatrixDecoder);
	m_vEncoders.push_back(&m_oStreamedMatrixEncoder);

	m_oChannelLocalisationDecoder.initialize(*this);
	m_oChannelLocalisationEncoder.initialize(*this);
	m_oChannelLocalisationEncoder.getInputLocalisationMatrix().setReferenceTarget(m_oChannelLocalisationDecoder.getOutputLocalisationMatrix());
	m_vDecoders.push_back(&m_oChannelLocalisationDecoder);
	m_vEncoders.push_back(&m_oChannelLocalisationEncoder);

	m_oFeatureVectorDecoder.initialize(*this);
	m_oFeatureVectorEncoder.initialize(*this);
	m_oFeatureVectorEncoder.getInputVector().setReferenceTarget(m_oFeatureVectorDecoder.getOutputVector());
	m_vDecoders.push_back(&m_oFeatureVectorDecoder);
	m_vEncoders.push_back(&m_oFeatureVectorEncoder);

	m_oSpectrumDecoder.initialize(*this);
	m_oSpectrumEncoder.initialize(*this);
	m_oSpectrumEncoder.getInputMatrix().setReferenceTarget(m_oSpectrumDecoder.getOutputMatrix());
	m_oSpectrumEncoder.getInputMinMaxFrequencyBands().setReferenceTarget(m_oSpectrumDecoder.getOutputMinMaxFrequencyBands());
	m_vDecoders.push_back(&m_oSpectrumDecoder);
	m_vEncoders.push_back(&m_oSpectrumEncoder);

	m_oSignalDecoder.initialize(*this);
	m_oSignalEncoder.initialize(*this);
	m_oSignalEncoder.getInputMatrix().setReferenceTarget(m_oSignalDecoder.getOutputMatrix());
	m_oSignalEncoder.getInputSamplingRate().setReferenceTarget(m_oSignalDecoder.getOutputSamplingRate());
	m_vDecoders.push_back(&m_oSignalDecoder);
	m_vEncoders.push_back(&m_oSignalEncoder);

	m_oStimDecoder.initialize(*this);
	m_oStimEncoder.initialize(*this);
	m_oStimEncoder.getInputStimulationSet().setReferenceTarget(m_oStimDecoder.getOutputStimulationSet());
	m_vDecoders.push_back(&m_oStimDecoder);
	m_vEncoders.push_back(&m_oStimEncoder);

	m_oExperimentInformationDecoder.initialize(*this);
	m_oExperimentInformationEncoder.initialize(*this);
	m_oExperimentInformationEncoder.getInputExperimentIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputExperimentIdentifier());
	m_oExperimentInformationEncoder.getInputExperimentDate().setReferenceTarget(m_oExperimentInformationDecoder.getOutputExperimentDate());
	m_oExperimentInformationEncoder.getInputSubjectIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectIdentifier());
	m_oExperimentInformationEncoder.getInputSubjectName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectName());
	m_oExperimentInformationEncoder.getInputSubjectAge().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectAge());
	m_oExperimentInformationEncoder.getInputSubjectGender().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectGender());
	m_oExperimentInformationEncoder.getInputLaboratoryIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputLaboratoryIdentifier());
	m_oExperimentInformationEncoder.getInputLaboratoryName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputLaboratoryName());
	m_oExperimentInformationEncoder.getInputTechnicianIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputTechnicianIdentifier());
	m_oExperimentInformationEncoder.getInputTechnicianName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputTechnicianName());
	m_vDecoders.push_back(&m_oExperimentInformationDecoder);
	m_vEncoders.push_back(&m_oExperimentInformationEncoder);

	return true;
}

boolean CTestCodecToolkit::uninitialize(void)
{
	for(uint32 i = 0; i< m_vDecoders.size(); i++)
	{
		m_vDecoders[i]->uninitialize();
	}
	for(uint32 i = 0; i< m_vEncoders.size(); i++)
	{
		m_vEncoders[i]->uninitialize();
	}

	return true;
}

boolean CTestCodecToolkit::processInput(uint32 ui32InputIndex)
{
	this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();

	return true;
}

boolean CTestCodecToolkit::process(void)
{
	IBoxIO& l_rDynamicBoxContext=this->getDynamicBoxContext();
	IBox& l_rStaticBoxContext=this->getStaticBoxContext();

	for(uint32 i=0; i<l_rStaticBoxContext.getInputCount(); i++)
	{
		for(uint32 j=0; j<l_rDynamicBoxContext.getInputChunkCount(i); j++)
		{
			// we can manipulate decoders and encoders without knowing their types
			m_vDecoders[i]->setInputChunk(l_rDynamicBoxContext.getInputChunk(i, j));
			m_vEncoders[i]->setOutputChunk(l_rDynamicBoxContext.getOutputChunk(i));

			m_vDecoders[i]->decode();

			if(m_vDecoders[i]->isHeaderReceived())
			{
				m_vEncoders[i]->encodeHeader();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}
			if(m_vDecoders[i]->isBufferReceived())
			{
				//let's check what is inside the buffer
				CIdentifier l_oInputType;
				l_rStaticBoxContext.getInputType(i, l_oInputType);
				if(l_oInputType==OV_TypeId_StreamedMatrix)
				{
					IMatrix* l_pMatrix = m_oStreamedMatrixDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Streamed Matrix buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_ChannelLocalisation)
				{
					IMatrix* l_pMatrix = m_oChannelLocalisationDecoder.getOutputLocalisationMatrix();
					this->getLogManager() << LogLevel_Info << "Channel localisation buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_FeatureVector)
				{
					IMatrix* l_pMatrix = m_oFeatureVectorDecoder.getOutputVector();
					this->getLogManager() << LogLevel_Info << "Feature Vector buffer received ("<<l_pMatrix->getBufferElementCount()<<" features in vector).\n";
				}
				else if(l_oInputType==OV_TypeId_Spectrum)
				{
					IMatrix* l_pMatrix = m_oSpectrumDecoder.getOutputMatrix();
					IMatrix* l_pMinMax = m_oSpectrumDecoder.getOutputMinMaxFrequencyBands();
					this->getLogManager() << LogLevel_Info << "Spectrum buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_Signal)
				{
					IMatrix* l_pMatrix = m_oSignalDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Signal buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_Stimulations)
				{
					IStimulationSet* l_pStimulations =  m_oStimDecoder.getOutputStimulationSet();
					// as we constantly receive stimulations on the stream, we will check if the incoming set is empty or not
					if(l_pStimulations->getStimulationCount() != 0)
						this->getLogManager() << LogLevel_Info << "Stimulation Set buffer received ("<<l_pStimulations->getStimulationCount()<<" stims in set).\n";
				}
				else if(l_oInputType==OV_TypeId_ExperimentationInformation)
				{
					uint64 l_pXPid = m_oExperimentInformationDecoder.getOutputExperimentIdentifier();
					this->getLogManager() << LogLevel_Info << "Experiment information buffer received (xp ID: "<<l_pXPid<<").\n";
				}
				else
				{
					this->getLogManager() << LogLevel_Error << "Undefined input type.\n";
					return true;
				}
				m_vEncoders[i]->encodeBuffer();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}
			if(m_vDecoders[i]->isEndReceived())
			{
				m_vEncoders[i]->encodeEnd();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}

			l_rDynamicBoxContext.markInputAsDeprecated(i, j);
		}
	}

	return true;
}
<commit_msg>openvibeopenvibe-plugins/samples * ovpCTestCodecToolkit.cpp : update to latest toolkit revision.<commit_after>#include "ovpCTestCodecToolkit.h"

using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace OpenViBE::Plugins;

using namespace OpenViBEPlugins;
using namespace OpenViBEPlugins::Samples;

using namespace OpenViBEToolkit;

boolean CTestCodecToolkit::initialize(void)
{
	m_oStreamedMatrixDecoder.initialize(*this);
	m_oStreamedMatrixEncoder.initialize(*this);
	m_oStreamedMatrixEncoder.getInputMatrix().setReferenceTarget(m_oStreamedMatrixDecoder.getOutputMatrix());
	m_vDecoders.push_back(&m_oStreamedMatrixDecoder);
	m_vEncoders.push_back(&m_oStreamedMatrixEncoder);

	m_oChannelLocalisationDecoder.initialize(*this);
	m_oChannelLocalisationEncoder.initialize(*this);
	m_oChannelLocalisationEncoder.getInputMatrix().setReferenceTarget(m_oChannelLocalisationDecoder.getOutputMatrix());
	m_oChannelLocalisationEncoder.getInputDynamic().setReferenceTarget(m_oChannelLocalisationDecoder.getOutputDynamic());
	m_vDecoders.push_back(&m_oChannelLocalisationDecoder);
	m_vEncoders.push_back(&m_oChannelLocalisationEncoder);

	m_oFeatureVectorDecoder.initialize(*this);
	m_oFeatureVectorEncoder.initialize(*this);
	m_oFeatureVectorEncoder.getInputMatrix().setReferenceTarget(m_oFeatureVectorDecoder.getOutputMatrix());
	m_vDecoders.push_back(&m_oFeatureVectorDecoder);
	m_vEncoders.push_back(&m_oFeatureVectorEncoder);

	m_oSpectrumDecoder.initialize(*this);
	m_oSpectrumEncoder.initialize(*this);
	m_oSpectrumEncoder.getInputMatrix().setReferenceTarget(m_oSpectrumDecoder.getOutputMatrix());
	m_oSpectrumEncoder.getInputMinMaxFrequencyBands().setReferenceTarget(m_oSpectrumDecoder.getOutputMinMaxFrequencyBands());
	m_vDecoders.push_back(&m_oSpectrumDecoder);
	m_vEncoders.push_back(&m_oSpectrumEncoder);

	m_oSignalDecoder.initialize(*this);
	m_oSignalEncoder.initialize(*this);
	m_oSignalEncoder.getInputMatrix().setReferenceTarget(m_oSignalDecoder.getOutputMatrix());
	m_oSignalEncoder.getInputSamplingRate().setReferenceTarget(m_oSignalDecoder.getOutputSamplingRate());
	m_vDecoders.push_back(&m_oSignalDecoder);
	m_vEncoders.push_back(&m_oSignalEncoder);

	m_oStimDecoder.initialize(*this);
	m_oStimEncoder.initialize(*this);
	m_oStimEncoder.getInputStimulationSet().setReferenceTarget(m_oStimDecoder.getOutputStimulationSet());
	m_vDecoders.push_back(&m_oStimDecoder);
	m_vEncoders.push_back(&m_oStimEncoder);

	m_oExperimentInformationDecoder.initialize(*this);
	m_oExperimentInformationEncoder.initialize(*this);
	m_oExperimentInformationEncoder.getInputExperimentIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputExperimentIdentifier());
	m_oExperimentInformationEncoder.getInputExperimentDate().setReferenceTarget(m_oExperimentInformationDecoder.getOutputExperimentDate());
	m_oExperimentInformationEncoder.getInputSubjectIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectIdentifier());
	m_oExperimentInformationEncoder.getInputSubjectName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectName());
	m_oExperimentInformationEncoder.getInputSubjectAge().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectAge());
	m_oExperimentInformationEncoder.getInputSubjectGender().setReferenceTarget(m_oExperimentInformationDecoder.getOutputSubjectGender());
	m_oExperimentInformationEncoder.getInputLaboratoryIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputLaboratoryIdentifier());
	m_oExperimentInformationEncoder.getInputLaboratoryName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputLaboratoryName());
	m_oExperimentInformationEncoder.getInputTechnicianIdentifier().setReferenceTarget(m_oExperimentInformationDecoder.getOutputTechnicianIdentifier());
	m_oExperimentInformationEncoder.getInputTechnicianName().setReferenceTarget(m_oExperimentInformationDecoder.getOutputTechnicianName());
	m_vDecoders.push_back(&m_oExperimentInformationDecoder);
	m_vEncoders.push_back(&m_oExperimentInformationEncoder);

	return true;
}

boolean CTestCodecToolkit::uninitialize(void)
{
	for(uint32 i = 0; i< m_vDecoders.size(); i++)
	{
		m_vDecoders[i]->uninitialize();
	}
	for(uint32 i = 0; i< m_vEncoders.size(); i++)
	{
		m_vEncoders[i]->uninitialize();
	}

	return true;
}

boolean CTestCodecToolkit::processInput(uint32 ui32InputIndex)
{
	this->getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();

	return true;
}

boolean CTestCodecToolkit::process(void)
{
	IBoxIO& l_rDynamicBoxContext=this->getDynamicBoxContext();
	IBox& l_rStaticBoxContext=this->getStaticBoxContext();

	for(uint32 i=0; i<l_rStaticBoxContext.getInputCount(); i++)
	{
		for(uint32 j=0; j<l_rDynamicBoxContext.getInputChunkCount(i); j++)
		{
			// we can manipulate decoders and encoders without knowing their types
			m_vDecoders[i]->setInputChunk(l_rDynamicBoxContext.getInputChunk(i, j));
			m_vEncoders[i]->setOutputChunk(l_rDynamicBoxContext.getOutputChunk(i));

			m_vDecoders[i]->decode();

			if(m_vDecoders[i]->isHeaderReceived())
			{
				m_vEncoders[i]->encodeHeader();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}
			if(m_vDecoders[i]->isBufferReceived())
			{
				//let's check what is inside the buffer
				CIdentifier l_oInputType;
				l_rStaticBoxContext.getInputType(i, l_oInputType);
				if(l_oInputType==OV_TypeId_StreamedMatrix)
				{
					IMatrix* l_pMatrix = m_oStreamedMatrixDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Streamed Matrix buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_ChannelLocalisation)
				{
					IMatrix* l_pMatrix = m_oChannelLocalisationDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Channel localisation buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_FeatureVector)
				{
					IMatrix* l_pMatrix = m_oFeatureVectorDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Feature Vector buffer received ("<<l_pMatrix->getBufferElementCount()<<" features in vector).\n";
				}
				else if(l_oInputType==OV_TypeId_Spectrum)
				{
					IMatrix* l_pMatrix = m_oSpectrumDecoder.getOutputMatrix();
					IMatrix* l_pMinMax = m_oSpectrumDecoder.getOutputMinMaxFrequencyBands();
					this->getLogManager() << LogLevel_Info << "Spectrum buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_Signal)
				{
					IMatrix* l_pMatrix = m_oSignalDecoder.getOutputMatrix();
					this->getLogManager() << LogLevel_Info << "Signal buffer received ("<<l_pMatrix->getBufferElementCount()<<" elements in buffer).\n";
				}
				else if(l_oInputType==OV_TypeId_Stimulations)
				{
					IStimulationSet* l_pStimulations =  m_oStimDecoder.getOutputStimulationSet();
					// as we constantly receive stimulations on the stream, we will check if the incoming set is empty or not
					if(l_pStimulations->getStimulationCount() != 0)
						this->getLogManager() << LogLevel_Info << "Stimulation Set buffer received ("<<l_pStimulations->getStimulationCount()<<" stims in set).\n";
				}
				else if(l_oInputType==OV_TypeId_ExperimentationInformation)
				{
					uint64 l_pXPid = m_oExperimentInformationDecoder.getOutputExperimentIdentifier();
					this->getLogManager() << LogLevel_Info << "Experiment information buffer received (xp ID: "<<l_pXPid<<").\n";
				}
				else
				{
					this->getLogManager() << LogLevel_Error << "Undefined input type.\n";
					return true;
				}
				m_vEncoders[i]->encodeBuffer();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}
			if(m_vDecoders[i]->isEndReceived())
			{
				m_vEncoders[i]->encodeEnd();
				l_rDynamicBoxContext.markOutputAsReadyToSend(i, l_rDynamicBoxContext.getInputChunkStartTime(i, j), l_rDynamicBoxContext.getInputChunkEndTime(i, j));
			}

			l_rDynamicBoxContext.markInputAsDeprecated(i, j);
		}
	}

	return true;
}
<|endoftext|>