<commit_before>/*
 * Copyright 2009 Ian Monroe <imonroe@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "QtScriptSmokeBinding.h"

#include <QtDebug>
#include <QtScript/QScriptValue>

#include "global.h"
#include "virtualmethodcall.h"
#include "SmokeQtScriptUtils.h"

namespace QtScriptSmoke {

Binding::Binding(Smoke* s)
    : SmokeBinding(s) { }

char* Binding::className(Smoke::Index classId)
{
    qDebug() << "QtScriptSmoke::Binding::className " << smoke->className(classId);
    // Convert '::' to '.' here
    return (char *) smoke->className(classId);
}

//!method called when a virtual method of a smoke-owned object is called. eg QWidget::mousePressEvent
bool Binding::callMethod(Smoke::Index method, void* ptr, Smoke::Stack args, bool isAbstract)
{
    QScriptValue * obj = Global::getScriptValue(ptr);
    if (obj == 0) {
        if ((Debug::DoDebug & Debug::Virtual) != 0) {
            qWarning("Cannot find object for virtual method %p -> %p", ptr, obj);
        }

        return false;
    }

    QByteArray methodName(smoke->methodNames[smoke->methods[method].name]);

    if (    methodName == "metaObject"
            || methodName == "qt_metacast"
            || methodName == "qt_metacall"
            || methodName == "minimumSizeHint"
            || methodName == "maximumSizeHint"
            || methodName == "x11Event"
            || methodName == "sizeHint" )
    {
         return false;
    }

    if ((Debug::DoDebug & Debug::Virtual) != 0) {
        Smoke::ModuleIndex methodId = { smoke, method };

        qWarning(   "module: %s virtual %p->%s::%s called",
                    smoke->moduleName(),
                    ptr,
                    smoke->classes[smoke->methods[method].classId].className,
                    methodToString(methodId).toLatin1().constData() );
    }

    Object::Instance * instance = Object::Instance::get(*obj);
    if (instance == 0) {
        if ((Debug::DoDebug & Debug::Virtual) != 0) {
            qWarning("Cannot find instance for virtual method %p -> %p", ptr, obj);
        }

        return false;
    }

    // If the virtual method hasn't been overriden, return false and just call the C++ one.
    if (obj->propertyFlags(methodName) != 0) {
        return false;
    }

    if ((Debug::DoDebug & Debug::Virtual) != 0) {
        qWarning("Method '%s' overriden", methodName.constData());
    }

    QScriptValue function = obj->property(QString(methodName));
    VirtualMethodCall methodCall(smoke, method, args, *obj, function);
    methodCall.next();
    return true;
}

void Binding::deleted(Smoke::Index classId, void* ptr)
{
    QScriptValue * obj = Global::getScriptValue(ptr);
    Object::Instance * instance = Object::Instance::get(*obj);

    if ((Debug::DoDebug & Debug::GC) != 0) {
        qWarning("%p->~%s()", ptr, smoke->className(classId));
    }

    if (instance == 0 || instance->value == 0) {
        return;
    }

    Global::unmapPointer(instance, instance->classId.index, 0);
    instance->value = 0;
    return;
}

}
<commit_msg>* Special case the 'contentsMargins' virtual method, and don't allow it to be overriden<commit_after>/*
 * Copyright 2009 Ian Monroe <imonroe@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) version 3, or any
 * later version accepted by the membership of KDE e.V. (or its
 * successor approved by the membership of KDE e.V.), which shall
 * act as a proxy defined in Section 6 of version 3 of the license.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "QtScriptSmokeBinding.h"

#include <QtDebug>
#include <QtScript/QScriptValue>

#include "global.h"
#include "virtualmethodcall.h"
#include "SmokeQtScriptUtils.h"

namespace QtScriptSmoke {

Binding::Binding(Smoke* s)
    : SmokeBinding(s) { }

char* Binding::className(Smoke::Index classId)
{
    qDebug() << "QtScriptSmoke::Binding::className " << smoke->className(classId);
    // Convert '::' to '.' here
    return (char *) smoke->className(classId);
}

//!method called when a virtual method of a smoke-owned object is called. eg QWidget::mousePressEvent
bool Binding::callMethod(Smoke::Index method, void* ptr, Smoke::Stack args, bool isAbstract)
{
    QScriptValue * obj = Global::getScriptValue(ptr);
    if (obj == 0) {
        if ((Debug::DoDebug & Debug::Virtual) != 0) {
            qWarning("Cannot find object for virtual method %p -> %p", ptr, obj);
        }

        return false;
    }

    QByteArray methodName(smoke->methodNames[smoke->methods[method].name]);

    if (    methodName == "metaObject"
            || methodName == "qt_metacast"
            || methodName == "qt_metacall"
            || methodName == "minimumSizeHint"
            || methodName == "maximumSizeHint"
            || methodName == "x11Event"
            || methodName == "contentsMargins"
            || methodName == "sizeHint" )
    {
         return false;
    }

    if ((Debug::DoDebug & Debug::Virtual) != 0) {
        Smoke::ModuleIndex methodId = { smoke, method };

        qWarning(   "module: %s virtual %p->%s::%s called",
                    smoke->moduleName(),
                    ptr,
                    smoke->classes[smoke->methods[method].classId].className,
                    methodToString(methodId).toLatin1().constData() );
    }

    Object::Instance * instance = Object::Instance::get(*obj);
    if (instance == 0) {
        if ((Debug::DoDebug & Debug::Virtual) != 0) {
            qWarning("Cannot find instance for virtual method %p -> %p", ptr, obj);
        }

        return false;
    }

    // If the virtual method hasn't been overriden, return false and just call the C++ one.
    if (obj->propertyFlags(methodName) != 0) {
        return false;
    }

    if ((Debug::DoDebug & Debug::Virtual) != 0) {
        qWarning("Method '%s' overriden", methodName.constData());
    }

    QScriptValue function = obj->property(QString(methodName));
    VirtualMethodCall methodCall(smoke, method, args, *obj, function);
    methodCall.next();
    return true;
}

void Binding::deleted(Smoke::Index classId, void* ptr)
{
    QScriptValue * obj = Global::getScriptValue(ptr);
    Object::Instance * instance = Object::Instance::get(*obj);

    if ((Debug::DoDebug & Debug::GC) != 0) {
        qWarning("%p->~%s()", ptr, smoke->className(classId));
    }

    if (instance == 0 || instance->value == 0) {
        return;
    }

    Global::unmapPointer(instance, instance->classId.index, 0);
    instance->value = 0;
    return;
}

}
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2018 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <string>
#include "os/os_specific.h"
#include "strings/string_utils.h"

#include "posix_network.h"

using std::string;

// because strerror_r is a complete mess...
static std::string errno_string(int err)
{
  switch(err)
  {
#if EAGAIN != EWOULDBLOCK
    case EAGAIN:
#endif
    case EWOULDBLOCK: return "EWOULDBLOCK: Operation would block.";
    case EINVAL: return "EINVAL: Invalid argument.";
    case EADDRINUSE: return "EADDRINUSE: Address already in use.";
    case ECONNRESET: return "ECONNRESET: A connection was forcibly closed by a peer.";
    case EINPROGRESS: return "EINPROGRESS: Operation now in progress.";
    case EINTR:
      return "EINTR: The function was interrupted by a signal that was caught, before any data was "
             "available.";
    case ETIMEDOUT: return "ETIMEDOUT: A socket operation timed out.";
    case ECONNABORTED: return "ECONNABORTED: A connection has been aborted.";
    case ECONNREFUSED: return "ECONNREFUSED: A connection was refused.";
    case EHOSTDOWN: return "EHOSTDOWN: Host is down.";
    case EHOSTUNREACH: return "EHOSTUNREACH: No route to host.";
    default: break;
  }

  return StringFormat::Fmt("Unknown error %d", err);
}

namespace Network
{
void Init()
{
}

void Shutdown()
{
}

Socket::~Socket()
{
  Shutdown();
}

void Socket::Shutdown()
{
  if(Connected())
  {
    shutdown((int)socket, SHUT_RDWR);
    close((int)socket);
    socket = -1;
  }
}

bool Socket::Connected() const
{
  return (int)socket != -1;
}

Socket *Socket::AcceptClient(bool wait)
{
  do
  {
    int s = accept(socket, NULL, NULL);

    if(s != -1)
    {
      int flags = fcntl(s, F_GETFL, 0);
      fcntl(s, F_SETFL, flags | O_NONBLOCK);

      int nodelay = 1;
      setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));

      return new Socket((ptrdiff_t)s);
    }

    int err = errno;

    if(err != EWOULDBLOCK && err != EAGAIN)
    {
      RDCWARN("accept: %s", errno_string(err).c_str());
      Shutdown();
    }

    Threading::Sleep(4);
  } while(wait);

  return NULL;
}

bool Socket::SendDataBlocking(const void *buf, uint32_t length)
{
  if(length == 0)
    return true;

  uint32_t sent = 0;

  char *src = (char *)buf;

  int flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

  timeval oldtimeout = {0};
  socklen_t len = sizeof(oldtimeout);
  getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&oldtimeout, &len);

  timeval timeout = {0};
  timeout.tv_sec = (timeoutMS / 1000);
  timeout.tv_usec = (timeoutMS % 1000) * 1000;
  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));

  while(sent < length)
  {
    int ret = send(socket, src, length - sent, 0);

    if(ret <= 0)
    {
      int err = errno;

      if(err == EWOULDBLOCK || err == EAGAIN)
      {
        RDCWARN("Timeout in send");
        Shutdown();
        return false;
      }
      else
      {
        RDCWARN("send: %s", errno_string(err).c_str());
        Shutdown();
        return false;
      }
    }

    sent += ret;
    src += ret;
  }

  flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);

  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&oldtimeout, sizeof(oldtimeout));

  RDCASSERT(sent == length);

  return true;
}

bool Socket::IsRecvDataWaiting()
{
  char dummy;
  int ret = recv(socket, &dummy, 1, MSG_PEEK);

  if(ret == 0)
  {
    Shutdown();
    return false;
  }
  else if(ret <= 0)
  {
    int err = errno;

    if(err == EWOULDBLOCK || err == EAGAIN)
    {
      ret = 0;
    }
    else
    {
      RDCWARN("recv: %s", errno_string(err).c_str());
      Shutdown();
      return false;
    }
  }

  return ret > 0;
}

bool Socket::RecvDataNonBlocking(void *buf, uint32_t &length)
{
  if(length == 0)
    return true;

  // socket is already blocking, don't have to change anything
  int ret = recv(socket, (char *)buf, length, 0);

  if(ret > 0)
  {
    length = (uint32_t)ret;
  }
  else
  {
    length = 0;
    int err = errno;

    if(err == EWOULDBLOCK || err == EAGAIN)
    {
      return true;
    }
    else
    {
      RDCWARN("recv: %s", errno_string(err).c_str());
      Shutdown();
      return false;
    }
  }

  return true;
}

bool Socket::RecvDataBlocking(void *buf, uint32_t length)
{
  if(length == 0)
    return true;

  uint32_t received = 0;

  char *dst = (char *)buf;

  int flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

  timeval oldtimeout = {0};
  socklen_t len = sizeof(oldtimeout);
  getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&oldtimeout, &len);

  timeval timeout = {0};
  timeout.tv_sec = (timeoutMS / 1000);
  timeout.tv_usec = (timeoutMS % 1000) * 1000;
  setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));

  while(received < length)
  {
    int ret = recv(socket, dst, length - received, 0);

    if(ret == 0)
    {
      Shutdown();
      return false;
    }
    else if(ret <= 0)
    {
      int err = errno;

      if(err == EWOULDBLOCK || err == EAGAIN)
      {
        RDCWARN("Timeout in recv");
        Shutdown();
        return false;
      }
      else
      {
        RDCWARN("recv: %s", errno_string(err).c_str());
        Shutdown();
        return false;
      }
    }

    received += ret;
    dst += ret;
  }

  flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);

  setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&oldtimeout, sizeof(oldtimeout));

  RDCASSERT(received == length);

  return true;
}

uint32_t GetIPFromTCPSocket(int socket)
{
  sockaddr_in addr = {};
  socklen_t len = sizeof(addr);

  getpeername(socket, (sockaddr *)&addr, &len);

  return ntohl(addr.sin_addr.s_addr);
}

Socket *CreateTCPServerSocket(const char *bindaddr, uint16_t port, int queuesize)
{
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  int yes = 1;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

  if(s == -1)
    return NULL;

  sockaddr_in addr;
  RDCEraseEl(addr);

  hostent *hp = gethostbyname(bindaddr);

  addr.sin_family = AF_INET;
  memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
  addr.sin_port = htons(port);

  int result = bind(s, (sockaddr *)&addr, sizeof(addr));
  if(result == -1)
  {
    RDCWARN("Failed to bind to %s:%d - %d", bindaddr, port, errno);
    close(s);
    return NULL;
  }

  result = listen(s, queuesize);
  if(result == -1)
  {
    RDCWARN("Failed to listen on %s:%d - %d", bindaddr, port, errno);
    close(s);
    return NULL;
  }

  int flags = fcntl(s, F_GETFL, 0);
  fcntl(s, F_SETFL, flags | O_NONBLOCK);

  return new Socket((ptrdiff_t)s);
}

Socket *CreateAbstractServerSocket(uint16_t port, int queuesize)
{
  char socketName[17] = {0};
  StringFormat::snprintf(socketName, 16, "renderdoc_%d", port);
  int socketNameLength = strlen(socketName);
  int s = socket(AF_UNIX, SOCK_STREAM, 0);

  if(s == -1)
  {
    RDCWARN("Unable to create unix socket");
    return NULL;
  }

  sockaddr_un addr;
  RDCEraseEl(addr);

  addr.sun_family = AF_UNIX;
  // first char is '\0'
  addr.sun_path[0] = '\0';
  strncpy(addr.sun_path + 1, socketName, socketNameLength);

  int result = bind(s, (sockaddr *)&addr, offsetof(sockaddr_un, sun_path) + 1 + socketNameLength);
  if(result == -1)
  {
    RDCWARN("Failed to create abstract socket: %s", socketName);
    close(s);
    return NULL;
  }
  RDCLOG("Created and bind socket: %d", s);

  result = listen(s, queuesize);
  if(result == -1)
  {
    RDCWARN("Failed to listen on %s", socketName);
    close(s);
    return NULL;
  }

  int flags = fcntl(s, F_GETFL, 0);
  fcntl(s, F_SETFL, flags | O_NONBLOCK);

  return new Socket((ptrdiff_t)s);
}

Socket *CreateClientSocket(const char *host, uint16_t port, int timeoutMS)
{
  char portstr[7] = {0};
  StringFormat::snprintf(portstr, 6, "%d", port);

  addrinfo hints;
  RDCEraseEl(hints);
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;

  addrinfo *result = NULL;
  getaddrinfo(host, portstr, &hints, &result);

  for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
  {
    int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(s == -1)
      return NULL;

    int flags = fcntl(s, F_GETFL, 0);
    fcntl(s, F_SETFL, flags | O_NONBLOCK);

    int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen);
    if(result == -1)
    {
      fd_set set;
      FD_ZERO(&set);
      FD_SET(s, &set);

      int err = errno;

      if(err == EWOULDBLOCK || err == EINPROGRESS)
      {
        timeval timeout;
        timeout.tv_sec = (timeoutMS / 1000);
        timeout.tv_usec = (timeoutMS % 1000) * 1000;
        result = select(s + 1, NULL, &set, NULL, &timeout);

        if(result <= 0)
        {
          RDCDEBUG("Timed out");
          close(s);
          continue;
        }

        socklen_t len = sizeof(err);
        getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len);
      }

      if(err != 0)
      {
        RDCDEBUG("%s", errno_string(err).c_str());
        close(s);
        continue;
      }
    }

    int nodelay = 1;
    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));

    return new Socket((ptrdiff_t)s);
  }

  RDCDEBUG("Failed to connect to %s:%d", host, port);
  return NULL;
}

bool ParseIPRangeCIDR(const char *str, uint32_t &ip, uint32_t &mask)
{
  uint32_t a = 0, b = 0, c = 0, d = 0, num = 0;

  int ret = sscanf(str, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &num);

  if(ret != 5 || a > 255 || b > 255 || c > 255 || d > 255 || num > 32)
  {
    ip = 0;
    mask = 0;
    return false;
  }

  ip = MakeIP(a, b, c, d);

  if(num == 0)
  {
    mask = 0;
  }
  else
  {
    num = 32 - num;
    mask = ((~0U) >> num) << num;
  }

  return true;
}
};
<commit_msg>Copy trailing null byte to keep GCC warnings happy. Closes #1028<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2018 Baldur Karlsson
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 ******************************************************************************/

#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <string>
#include "os/os_specific.h"
#include "strings/string_utils.h"

#include "posix_network.h"

using std::string;

// because strerror_r is a complete mess...
static std::string errno_string(int err)
{
  switch(err)
  {
#if EAGAIN != EWOULDBLOCK
    case EAGAIN:
#endif
    case EWOULDBLOCK: return "EWOULDBLOCK: Operation would block.";
    case EINVAL: return "EINVAL: Invalid argument.";
    case EADDRINUSE: return "EADDRINUSE: Address already in use.";
    case ECONNRESET: return "ECONNRESET: A connection was forcibly closed by a peer.";
    case EINPROGRESS: return "EINPROGRESS: Operation now in progress.";
    case EINTR:
      return "EINTR: The function was interrupted by a signal that was caught, before any data was "
             "available.";
    case ETIMEDOUT: return "ETIMEDOUT: A socket operation timed out.";
    case ECONNABORTED: return "ECONNABORTED: A connection has been aborted.";
    case ECONNREFUSED: return "ECONNREFUSED: A connection was refused.";
    case EHOSTDOWN: return "EHOSTDOWN: Host is down.";
    case EHOSTUNREACH: return "EHOSTUNREACH: No route to host.";
    default: break;
  }

  return StringFormat::Fmt("Unknown error %d", err);
}

namespace Network
{
void Init()
{
}

void Shutdown()
{
}

Socket::~Socket()
{
  Shutdown();
}

void Socket::Shutdown()
{
  if(Connected())
  {
    shutdown((int)socket, SHUT_RDWR);
    close((int)socket);
    socket = -1;
  }
}

bool Socket::Connected() const
{
  return (int)socket != -1;
}

Socket *Socket::AcceptClient(bool wait)
{
  do
  {
    int s = accept(socket, NULL, NULL);

    if(s != -1)
    {
      int flags = fcntl(s, F_GETFL, 0);
      fcntl(s, F_SETFL, flags | O_NONBLOCK);

      int nodelay = 1;
      setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));

      return new Socket((ptrdiff_t)s);
    }

    int err = errno;

    if(err != EWOULDBLOCK && err != EAGAIN)
    {
      RDCWARN("accept: %s", errno_string(err).c_str());
      Shutdown();
    }

    Threading::Sleep(4);
  } while(wait);

  return NULL;
}

bool Socket::SendDataBlocking(const void *buf, uint32_t length)
{
  if(length == 0)
    return true;

  uint32_t sent = 0;

  char *src = (char *)buf;

  int flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

  timeval oldtimeout = {0};
  socklen_t len = sizeof(oldtimeout);
  getsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&oldtimeout, &len);

  timeval timeout = {0};
  timeout.tv_sec = (timeoutMS / 1000);
  timeout.tv_usec = (timeoutMS % 1000) * 1000;
  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&timeout, sizeof(timeout));

  while(sent < length)
  {
    int ret = send(socket, src, length - sent, 0);

    if(ret <= 0)
    {
      int err = errno;

      if(err == EWOULDBLOCK || err == EAGAIN)
      {
        RDCWARN("Timeout in send");
        Shutdown();
        return false;
      }
      else
      {
        RDCWARN("send: %s", errno_string(err).c_str());
        Shutdown();
        return false;
      }
    }

    sent += ret;
    src += ret;
  }

  flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);

  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (const char *)&oldtimeout, sizeof(oldtimeout));

  RDCASSERT(sent == length);

  return true;
}

bool Socket::IsRecvDataWaiting()
{
  char dummy;
  int ret = recv(socket, &dummy, 1, MSG_PEEK);

  if(ret == 0)
  {
    Shutdown();
    return false;
  }
  else if(ret <= 0)
  {
    int err = errno;

    if(err == EWOULDBLOCK || err == EAGAIN)
    {
      ret = 0;
    }
    else
    {
      RDCWARN("recv: %s", errno_string(err).c_str());
      Shutdown();
      return false;
    }
  }

  return ret > 0;
}

bool Socket::RecvDataNonBlocking(void *buf, uint32_t &length)
{
  if(length == 0)
    return true;

  // socket is already blocking, don't have to change anything
  int ret = recv(socket, (char *)buf, length, 0);

  if(ret > 0)
  {
    length = (uint32_t)ret;
  }
  else
  {
    length = 0;
    int err = errno;

    if(err == EWOULDBLOCK || err == EAGAIN)
    {
      return true;
    }
    else
    {
      RDCWARN("recv: %s", errno_string(err).c_str());
      Shutdown();
      return false;
    }
  }

  return true;
}

bool Socket::RecvDataBlocking(void *buf, uint32_t length)
{
  if(length == 0)
    return true;

  uint32_t received = 0;

  char *dst = (char *)buf;

  int flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags & ~O_NONBLOCK);

  timeval oldtimeout = {0};
  socklen_t len = sizeof(oldtimeout);
  getsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&oldtimeout, &len);

  timeval timeout = {0};
  timeout.tv_sec = (timeoutMS / 1000);
  timeout.tv_usec = (timeoutMS % 1000) * 1000;
  setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));

  while(received < length)
  {
    int ret = recv(socket, dst, length - received, 0);

    if(ret == 0)
    {
      Shutdown();
      return false;
    }
    else if(ret <= 0)
    {
      int err = errno;

      if(err == EWOULDBLOCK || err == EAGAIN)
      {
        RDCWARN("Timeout in recv");
        Shutdown();
        return false;
      }
      else
      {
        RDCWARN("recv: %s", errno_string(err).c_str());
        Shutdown();
        return false;
      }
    }

    received += ret;
    dst += ret;
  }

  flags = fcntl(socket, F_GETFL, 0);
  fcntl(socket, F_SETFL, flags | O_NONBLOCK);

  setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (const char *)&oldtimeout, sizeof(oldtimeout));

  RDCASSERT(received == length);

  return true;
}

uint32_t GetIPFromTCPSocket(int socket)
{
  sockaddr_in addr = {};
  socklen_t len = sizeof(addr);

  getpeername(socket, (sockaddr *)&addr, &len);

  return ntohl(addr.sin_addr.s_addr);
}

Socket *CreateTCPServerSocket(const char *bindaddr, uint16_t port, int queuesize)
{
  int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  int yes = 1;
  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));

  if(s == -1)
    return NULL;

  sockaddr_in addr;
  RDCEraseEl(addr);

  hostent *hp = gethostbyname(bindaddr);

  addr.sin_family = AF_INET;
  memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
  addr.sin_port = htons(port);

  int result = bind(s, (sockaddr *)&addr, sizeof(addr));
  if(result == -1)
  {
    RDCWARN("Failed to bind to %s:%d - %d", bindaddr, port, errno);
    close(s);
    return NULL;
  }

  result = listen(s, queuesize);
  if(result == -1)
  {
    RDCWARN("Failed to listen on %s:%d - %d", bindaddr, port, errno);
    close(s);
    return NULL;
  }

  int flags = fcntl(s, F_GETFL, 0);
  fcntl(s, F_SETFL, flags | O_NONBLOCK);

  return new Socket((ptrdiff_t)s);
}

Socket *CreateAbstractServerSocket(uint16_t port, int queuesize)
{
  char socketName[17] = {0};
  StringFormat::snprintf(socketName, 16, "renderdoc_%d", port);
  int socketNameLength = strlen(socketName);
  int s = socket(AF_UNIX, SOCK_STREAM, 0);

  if(s == -1)
  {
    RDCWARN("Unable to create unix socket");
    return NULL;
  }

  sockaddr_un addr;
  RDCEraseEl(addr);

  addr.sun_family = AF_UNIX;
  // first char is '\0'
  addr.sun_path[0] = '\0';
  strncpy(addr.sun_path + 1, socketName, socketNameLength + 1);

  int result = bind(s, (sockaddr *)&addr, offsetof(sockaddr_un, sun_path) + 1 + socketNameLength);
  if(result == -1)
  {
    RDCWARN("Failed to create abstract socket: %s", socketName);
    close(s);
    return NULL;
  }
  RDCLOG("Created and bind socket: %d", s);

  result = listen(s, queuesize);
  if(result == -1)
  {
    RDCWARN("Failed to listen on %s", socketName);
    close(s);
    return NULL;
  }

  int flags = fcntl(s, F_GETFL, 0);
  fcntl(s, F_SETFL, flags | O_NONBLOCK);

  return new Socket((ptrdiff_t)s);
}

Socket *CreateClientSocket(const char *host, uint16_t port, int timeoutMS)
{
  char portstr[7] = {0};
  StringFormat::snprintf(portstr, 6, "%d", port);

  addrinfo hints;
  RDCEraseEl(hints);
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_protocol = IPPROTO_TCP;

  addrinfo *result = NULL;
  getaddrinfo(host, portstr, &hints, &result);

  for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
  {
    int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if(s == -1)
      return NULL;

    int flags = fcntl(s, F_GETFL, 0);
    fcntl(s, F_SETFL, flags | O_NONBLOCK);

    int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen);
    if(result == -1)
    {
      fd_set set;
      FD_ZERO(&set);
      FD_SET(s, &set);

      int err = errno;

      if(err == EWOULDBLOCK || err == EINPROGRESS)
      {
        timeval timeout;
        timeout.tv_sec = (timeoutMS / 1000);
        timeout.tv_usec = (timeoutMS % 1000) * 1000;
        result = select(s + 1, NULL, &set, NULL, &timeout);

        if(result <= 0)
        {
          RDCDEBUG("Timed out");
          close(s);
          continue;
        }

        socklen_t len = sizeof(err);
        getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len);
      }

      if(err != 0)
      {
        RDCDEBUG("%s", errno_string(err).c_str());
        close(s);
        continue;
      }
    }

    int nodelay = 1;
    setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));

    return new Socket((ptrdiff_t)s);
  }

  RDCDEBUG("Failed to connect to %s:%d", host, port);
  return NULL;
}

bool ParseIPRangeCIDR(const char *str, uint32_t &ip, uint32_t &mask)
{
  uint32_t a = 0, b = 0, c = 0, d = 0, num = 0;

  int ret = sscanf(str, "%u.%u.%u.%u/%u", &a, &b, &c, &d, &num);

  if(ret != 5 || a > 255 || b > 255 || c > 255 || d > 255 || num > 32)
  {
    ip = 0;
    mask = 0;
    return false;
  }

  ip = MakeIP(a, b, c, d);

  if(num == 0)
  {
    mask = 0;
  }
  else
  {
    num = 32 - num;
    mask = ((~0U) >> num) << num;
  }

  return true;
}
};
<|endoftext|>


<commit_before>#include "GameProcess.h"
#include "Object.h"
#include "Engine.h"
#include "World.h"
#include "App.h"
#include "ToolsCamera.h"
#include "ControlsApp.h"
#include "MathLib.h"
#include "Game.h"
#include "Editor.h"
#include "Input.h"
#include "BlueRayUtils.h"

using namespace MathLib;

CGameProcess::CGameProcess(void)
{

}

CGameProcess::~CGameProcess(void)
{

}
int CGameProcess::Init()
{
	g_Engine.pFileSystem->CacheFilesFormExt("char");
	g_Engine.pFileSystem->CacheFilesFormExt("node");
	g_Engine.pFileSystem->CacheFilesFormExt("smesh");
	g_Engine.pFileSystem->CacheFilesFormExt("sanim");

	g_Engine.pWorld->LoadWorld("data/scene/terrain/test/test.world");
	//g_Engine.pWorld->LoadWorld("data/scene/terrain/cj/cj.world");
	g_Engine.pControls->SetKeyPressFunc(KeyPress);
	g_Engine.pControls->SetKeyReleaseFunc(KeyRelease);

	m_pRole = new CFPSRoleLocal();
	m_pRole->Init(10001, "data/role/hero/FpsRole/fps.char");		//ؽɫԴ

	m_pRole->SetActorPosition(vec3(0, 0, 0));	//ýɫʼλáŴΪԭ㣬άϵvec3
	m_pSkillSystem = new CSkillSystem(this);
	m_pCameraBase = new CCameraBase();
	m_pCameraBase->SetEnabled(1);
	g_pSysControl->SetMouseGrab(1);

	m_pStarControl = new CStarControl();
	m_pRayControl = new CRayControl();

	return 1;
}

int CGameProcess::ShutDown()			//رϷ
{
	delete m_pRole;
	delete m_pSkillSystem;
	delete m_pCameraBase;
	delete m_pStarControl;
	delete m_pRayControl;

	DelAllListen();
	return 0;
}

int CGameProcess::Update()
{
	float ifps = g_Engine.pGame->GetIFps();

	if (g_Engine.pInput->IsKeyDown('1'))
	{
		CAction* pAction = m_pRole->OrceAction("attack02");
		if (pAction)
		{
			pAction->SetupSkillThrow(vec3_zero, -1.0f, 2.0f);
			m_pRole->StopMove();
		}
	}
	else if (g_Engine.pInput->IsKeyDown('2'))
	{
		CAction* pAction = m_pRole->OrceAction("skill01");
		if (pAction)
		{
			m_pRole->StopMove();
		}
	}
	else if (g_Engine.pInput->IsKeyDown('3'))
	{
		CAction* pAction = m_pRole->OrceAction("skill02");
		if (pAction)
		{
			m_pRole->StopMove();
			CRoleBase* pTarget = NULL;

		}
	}
	for (int i = 0; i < 20; i++)
	{
		float l = (m_vAIList[i]->GetPosition() - m_pRole->GetPosition()).length();
		if (l > 5.0f && l < 15.0f)
		{
			pTarget = m_vAIList[i];
			break;
		}
	}
	if (pTarget)
	{
		CVector<int> vTarget;
		vTarget.Append(pTarget->GetRoleID());

	}

	return 0;
}

<commit_msg>Signed-off-by: mrlitong <litongtongxue@gmail.com><commit_after>#include "GameProcess.h"
#include "Object.h"
#include "Engine.h"
#include "World.h"
#include "App.h"
#include "ToolsCamera.h"
#include "ControlsApp.h"
#include "MathLib.h"
#include "Game.h"
#include "Editor.h"
#include "Input.h"
#include "BlueRayUtils.h"

using namespace MathLib;

CGameProcess::CGameProcess(void)
{

}

CGameProcess::~CGameProcess(void)
{

}
int CGameProcess::Init()
{
	g_Engine.pFileSystem->CacheFilesFormExt("char");
	g_Engine.pFileSystem->CacheFilesFormExt("node");
	g_Engine.pFileSystem->CacheFilesFormExt("smesh");
	g_Engine.pFileSystem->CacheFilesFormExt("sanim");

	g_Engine.pWorld->LoadWorld("data/scene/terrain/test/test.world");
	//g_Engine.pWorld->LoadWorld("data/scene/terrain/cj/cj.world");
	g_Engine.pControls->SetKeyPressFunc(KeyPress);
	g_Engine.pControls->SetKeyReleaseFunc(KeyRelease);

	m_pRole = new CFPSRoleLocal();
	m_pRole->Init(10001, "data/role/hero/FpsRole/fps.char");		//ؽɫԴ

	m_pRole->SetActorPosition(vec3(0, 0, 0));	//ýɫʼλáŴΪԭ㣬άϵvec3
	m_pSkillSystem = new CSkillSystem(this);
	m_pCameraBase = new CCameraBase();
	m_pCameraBase->SetEnabled(1);
	g_pSysControl->SetMouseGrab(1);

	m_pStarControl = new CStarControl();
	m_pRayControl = new CRayControl();

	return 1;
}

int CGameProcess::ShutDown()			//رϷ
{
	delete m_pRole;
	delete m_pSkillSystem;
	delete m_pCameraBase;
	delete m_pStarControl;
	delete m_pRayControl;

	DelAllListen();
	return 0;
}

int CGameProcess::Update()
{
	float ifps = g_Engine.pGame->GetIFps();

	if (g_Engine.pInput->IsKeyDown('1'))
	{
		CAction* pAction = m_pRole->OrceAction("attack02");
		if (pAction)
		{
			pAction->SetupSkillThrow(vec3_zero, -1.0f, 2.0f);
			m_pRole->StopMove();
		}
	}
	else if (g_Engine.pInput->IsKeyDown('2'))
	{
		CAction* pAction = m_pRole->OrceAction("skill01");
		if (pAction)
		{
			m_pRole->StopMove();
		}
	}
	else if (g_Engine.pInput->IsKeyDown('3'))
	{
		CAction* pAction = m_pRole->OrceAction("skill02");
		if (pAction)
		{
			m_pRole->StopMove();
			CRoleBase* pTarget = NULL;

		}
	}
	for (int i = 0; i < 20; i++)
	{
		float l = (m_vAIList[i]->GetPosition() - m_pRole->GetPosition()).length();
		if (l > 5.0f && l < 15.0f)
		{
			pTarget = m_vAIList[i];
			break;
		}
	}
	if (pTarget)
	{
		CVector<int> vTarget;
		vTarget.Append(pTarget->GetRoleID());
		pAction->SetupSkillBulletTarget(vTarget);

	}

	return 0;
}

<|endoftext|>


<commit_before>#include "Application.h"
#include "DefaultSettings.h"
#include "Database.h"
#include "Player.h"
#include "SmartmontoolsNotifier.h"
#include "CdromManager.h"
#include "OnlineDBPluginManager.h"
#include "Database.h"
#include "Player.h"

/*
 * Derived form QCoreApplication
 * Set Organization name, domain and application name
 *
 * Create Websocket server for API
 * Create DiscoveryServer for autodetection of clients
 *
 */

Application::Application(int & argc, char ** argv) :
    QCoreApplication(argc, argv)
{
    QCoreApplication::setOrganizationName("Enna");
    QCoreApplication::setOrganizationDomain("enna.me");
    QCoreApplication::setApplicationName("EnnaMediaServer");
    QSettings settings;

    /* Read value for websocket port */
    m_websocketPort = settings.value("main/websocket_port", EMS_WEBSOCKET_PORT).toInt();
    /* Save websocket back if it's not found in initial config file */
    settings.setValue("main/websocket_port", m_websocketPort);

    /* Read locations path in config and add them to the scanner object */
    int size = settings.beginReadArray("locations");
    for (int i = 0; i < size; ++i) {
        settings.setArrayIndex(i);
        m_scanner.locationAdd(settings.value("path").toString());
    }
    settings.endArray();

    /* Add online database plugins */
    OnlineDBPluginManager::instance()->registerAllPlugins();

    /* Open Database */
    Database::instance()->open();

    /* Start the CDROM manager */
    CdromManager::instance()->moveToThread(&m_cdromManagerWorker);
    connect(&m_cdromManagerWorker, &QThread::started, CdromManager::instance(), &CdromManager::startMonitor);
    connect(&m_cdromManagerWorker, &QThread::finished, CdromManager::instance(), &CdromManager::stopMonitor);
    m_cdromManagerWorker.start();
    /* Start the player */
    Player::instance()->start();
    /* Create Websocket server */
    m_webSocketServer = new WebSocketServer(m_websocketPort, this);
    /* Create Discovery Server */
    m_discoveryServer = new DiscoveryServer(BCAST_UDP_PORT, this);
    m_smartmontools = new SmartmontoolsNotifier(this);
}

Application::~Application()
{
    /* Stop the CDROM manager */
    m_cdromManagerWorker.quit();
    m_cdromManagerWorker.wait();

    /* Stop the player thread */
    Player::instance()->kill();
    Player::instance()->wait(1000);

    /* Close properly the database */
    Database::instance()->close();

}

<commit_msg>Load websocket port from seting file<commit_after>#include "Application.h"
#include "DefaultSettings.h"
#include "Database.h"
#include "Player.h"
#include "SmartmontoolsNotifier.h"
#include "CdromManager.h"
#include "OnlineDBPluginManager.h"
#include "Database.h"
#include "Player.h"

/*
 * Derived form QCoreApplication
 * Set Organization name, domain and application name
 *
 * Create Websocket server for API
 * Create DiscoveryServer for autodetection of clients
 *
 */

Application::Application(int & argc, char ** argv) :
    QCoreApplication(argc, argv)
{
    QCoreApplication::setOrganizationName("Enna");
    QCoreApplication::setOrganizationDomain("enna.me");
    QCoreApplication::setApplicationName("EnnaMediaServer");
    QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());

    /* Read value for websocket port */
    if (settings.contains("main/websocket_port"))
        m_websocketPort = settings.value("main/websocket_port").toInt();
    /* Save websocket back if it's not found in initial config file */
    else
    {
        m_websocketPort = EMS_WEBSOCKET_PORT;
        settings.setValue("main/websocket_port", m_websocketPort);
    }
    /* Read locations path in config and add them to the scanner object */
    int size = settings.beginReadArray("locations");
    for (int i = 0; i < size; ++i) {
        settings.setArrayIndex(i);
        m_scanner.locationAdd(settings.value("path").toString());
    }
    settings.endArray();

    /* Add online database plugins */
    OnlineDBPluginManager::instance()->registerAllPlugins();

    /* Open Database */
    Database::instance()->open();

    /* Start the CDROM manager */
    CdromManager::instance()->moveToThread(&m_cdromManagerWorker);
    connect(&m_cdromManagerWorker, &QThread::started, CdromManager::instance(), &CdromManager::startMonitor);
    connect(&m_cdromManagerWorker, &QThread::finished, CdromManager::instance(), &CdromManager::stopMonitor);
    m_cdromManagerWorker.start();
    /* Start the player */
    Player::instance()->start();
    /* Create Websocket server */
    m_webSocketServer = new WebSocketServer(m_websocketPort, this);
    /* Create Discovery Server */
    m_discoveryServer = new DiscoveryServer(BCAST_UDP_PORT, this);
    m_smartmontools = new SmartmontoolsNotifier(this);
}

Application::~Application()
{
    /* Stop the CDROM manager */
    m_cdromManagerWorker.quit();
    m_cdromManagerWorker.wait();

    /* Stop the player thread */
    Player::instance()->kill();
    Player::instance()->wait(1000);

    /* Close properly the database */
    Database::instance()->close();

}

<|endoftext|>


<commit_before>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2012-06-05 GONG Chen <chen.sst@gmail.com>
//
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/config.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/schema.h>
#include <rime/gear/chord_composer.h>

// U+FEFF works better with MacType
static const char* kZeroWidthSpace = "\xef\xbb\xbf";  //"\xe2\x80\x8b";

namespace rime {

ChordComposer::ChordComposer(const Ticket& ticket) : Processor(ticket) {
  if (!engine_)
    return;
  if (Config* config = engine_->schema()->config()) {
    string alphabet;
    config->GetString("chord_composer/alphabet", &alphabet);
    chording_keys_.Parse(alphabet);
    config->GetBool("chord_composer/use_control", &use_control_);
    config->GetBool("chord_composer/use_alt", &use_alt_);
    config->GetBool("chord_composer/use_shift", &use_shift_);
    config->GetString("speller/delimiter", &delimiter_);
    algebra_.Load(config->GetList("chord_composer/algebra"));
    output_format_.Load(config->GetList("chord_composer/output_format"));
    prompt_format_.Load(config->GetList("chord_composer/prompt_format"));
  }
  Context* ctx = engine_->context();
  ctx->set_option("_chord_typing", true);
  update_connection_ = ctx->update_notifier().connect(
      [this](Context* ctx) { OnContextUpdate(ctx); });
  unhandled_key_connection_ = ctx->unhandled_key_notifier().connect(
      [this](Context* ctx, const KeyEvent& key) { OnUnhandledKey(ctx, key); });
}

ChordComposer::~ChordComposer() {
  update_connection_.disconnect();
  unhandled_key_connection_.disconnect();
}

ProcessResult ChordComposer::ProcessFunctionKey(const KeyEvent& key_event) {
  if (key_event.release()) {
    return kNoop;
  }
  int ch = key_event.keycode();
  if (ch == XK_Return) {
    if (!raw_sequence_.empty()) {
      // commit raw input
      engine_->context()->set_input(raw_sequence_);
      // then the sequence should not be used again
      raw_sequence_.clear();
    }
    ClearChord();
  } else if (ch == XK_BackSpace || ch == XK_Escape) {
    // clear the raw sequence
    raw_sequence_.clear();
    ClearChord();
  }
  return kNoop;
}

// Note: QWERTY layout only.
static const char map_to_base_layer[] = {
  " 1'3457'908=,-./"
  "0123456789;;,=./"
  "2abcdefghijklmno"
  "pqrstuvwxyz[\\]6-"
  "`abcdefghijklmno"
  "pqrstuvwxyz[\\]`"
};

inline static int get_base_layer_key_code(const KeyEvent& key_event) {
  int ch = key_event.keycode();
  bool is_shift = key_event.shift();
  return (is_shift && ch >= 0x20 && ch <= 0x7e)
      ? map_to_base_layer[ch - 0x20] : ch;
}

ProcessResult ChordComposer::ProcessChordingKey(const KeyEvent& key_event) {
  if (key_event.ctrl() || key_event.alt()) {
    raw_sequence_.clear();
  }
  if (key_event.ctrl() && !use_control_ ||
      key_event.alt() && !use_alt_ ||
      key_event.shift() && !use_shift_) {
    ClearChord();
    return kNoop;
  }
  int ch = get_base_layer_key_code(key_event);
  // non chording key
  if (std::find(chording_keys_.begin(),
                chording_keys_.end(),
                KeyEvent{ch, 0}) == chording_keys_.end()) {
    ClearChord();
    return kNoop;
  }
  // chording key
  bool is_key_up = key_event.release();
  if (is_key_up) {
    if (pressed_.erase(ch) != 0 && pressed_.empty()) {
      FinishChord();
    }
  }
  else {  // key down
    pressed_.insert(ch);
    bool updated = chord_.insert(ch).second;
    if (updated)
      UpdateChord();
  }
  return kAccepted;
}

inline static bool is_composing_text(Context* ctx) {
  return ctx->IsComposing() && ctx->input() != kZeroWidthSpace;
}

ProcessResult ChordComposer::ProcessKeyEvent(const KeyEvent& key_event) {
  if (engine_->context()->get_option("ascii_mode")) {
    return kNoop;
  }
  if (pass_thru_) {
    return ProcessFunctionKey(key_event);
  }
  bool is_key_up = key_event.release();
  int ch = key_event.keycode();
  if (!is_key_up && ch >= 0x20 && ch <= 0x7e) {
    // save raw input
    if (!is_composing_text(engine_->context()) || !raw_sequence_.empty()) {
      raw_sequence_.push_back(ch);
      DLOG(INFO) << "update raw sequence: " << raw_sequence_;
    }
  }
  auto result = ProcessChordingKey(key_event);
  if (result != kNoop) {
    return result;
  }
  return ProcessFunctionKey(key_event);
}

string ChordComposer::SerializeChord() {
  KeySequence key_sequence;
  for (KeyEvent key : chording_keys_) {
    if (chord_.find(key.keycode()) != chord_.end())
      key_sequence.push_back(key);
  }
  string code = key_sequence.repr();
  algebra_.Apply(&code);
  return code;
}

void ChordComposer::UpdateChord() {
  if (!engine_)
    return;
  Context* ctx = engine_->context();
  Composition& comp = ctx->composition();
  string code = SerializeChord();
  prompt_format_.Apply(&code);
  if (comp.empty()) {
    // add an invisbile place holder segment
    // 1. to cheat ctx->IsComposing() == true
    // 2. to attach chord prompt to while chording
    ctx->PushInput(kZeroWidthSpace);
    if (comp.empty()) {
      LOG(ERROR) << "failed to update chord.";
      return;
    }
    comp.back().tags.insert("phony");
  }
  comp.back().tags.insert("chord_prompt");
  comp.back().prompt = code;
}

void ChordComposer::FinishChord() {
  if (!engine_)
    return;
  string code = SerializeChord();
  output_format_.Apply(&code);
  ClearChord();

  KeySequence key_sequence;
  if (key_sequence.Parse(code) && !key_sequence.empty()) {
    pass_thru_ = true;
    for (const KeyEvent& key : key_sequence) {
      if (!engine_->ProcessKey(key)) {
        // direct commit
        engine_->CommitText(string(1, key.keycode()));
        // exclude the character (eg. space) from the raw sequence
        raw_sequence_.clear();
      }
    }
    pass_thru_ = false;
  }
}

void ChordComposer::ClearChord() {
  pressed_.clear();
  chord_.clear();
  if (!engine_)
    return;
  Context* ctx = engine_->context();
  Composition& comp = ctx->composition();
  if (comp.empty()) {
    return;
  }
  if (comp.input().substr(comp.back().start) == kZeroWidthSpace) {
    ctx->PopInput(ctx->caret_pos() - comp.back().start);
  }
  else if (comp.back().HasTag("chord_prompt")) {
    comp.back().prompt.clear();
    comp.back().tags.erase("chord_prompt");
  }
}

void ChordComposer::OnContextUpdate(Context* ctx) {
  if (is_composing_text(ctx)) {
    composing_ = true;
  }
  else if (composing_) {
    composing_ = false;
    raw_sequence_.clear();
    DLOG(INFO) << "clear raw sequence.";
  }
}

void ChordComposer::OnUnhandledKey(Context* ctx, const KeyEvent& key) {
  // directly committed ascii should not be captured into the raw sequence
  // test case:
  // 3.14{Return} should not commit an extra sequence '14'
  if ((key.modifier() & ~kShiftMask) == 0 &&
      key.keycode() >= 0x20 && key.keycode() <= 0x7e) {
    raw_sequence_.clear();
    DLOG(INFO) << "clear raw sequence.";
  }
}

}  // namespace rime
<commit_msg>fix(chord_composer): more safely handle the placeholder ZWSP<commit_after>//
// Copyright RIME Developers
// Distributed under the BSD License
//
// 2012-06-05 GONG Chen <chen.sst@gmail.com>
//
#include <rime/common.h>
#include <rime/composition.h>
#include <rime/config.h>
#include <rime/context.h>
#include <rime/engine.h>
#include <rime/key_event.h>
#include <rime/schema.h>
#include <rime/gear/chord_composer.h>

static const char* kZeroWidthSpace = "\xe2\x80\x8b";  // U+200B

namespace rime {

ChordComposer::ChordComposer(const Ticket& ticket) : Processor(ticket) {
  if (!engine_)
    return;
  if (Config* config = engine_->schema()->config()) {
    string alphabet;
    config->GetString("chord_composer/alphabet", &alphabet);
    chording_keys_.Parse(alphabet);
    config->GetBool("chord_composer/use_control", &use_control_);
    config->GetBool("chord_composer/use_alt", &use_alt_);
    config->GetBool("chord_composer/use_shift", &use_shift_);
    config->GetString("speller/delimiter", &delimiter_);
    algebra_.Load(config->GetList("chord_composer/algebra"));
    output_format_.Load(config->GetList("chord_composer/output_format"));
    prompt_format_.Load(config->GetList("chord_composer/prompt_format"));
  }
  Context* ctx = engine_->context();
  ctx->set_option("_chord_typing", true);
  update_connection_ = ctx->update_notifier().connect(
      [this](Context* ctx) { OnContextUpdate(ctx); });
  unhandled_key_connection_ = ctx->unhandled_key_notifier().connect(
      [this](Context* ctx, const KeyEvent& key) { OnUnhandledKey(ctx, key); });
}

ChordComposer::~ChordComposer() {
  update_connection_.disconnect();
  unhandled_key_connection_.disconnect();
}

ProcessResult ChordComposer::ProcessFunctionKey(const KeyEvent& key_event) {
  if (key_event.release()) {
    return kNoop;
  }
  int ch = key_event.keycode();
  if (ch == XK_Return) {
    if (!raw_sequence_.empty()) {
      // commit raw input
      engine_->context()->set_input(raw_sequence_);
      // then the sequence should not be used again
      raw_sequence_.clear();
    }
    ClearChord();
  } else if (ch == XK_BackSpace || ch == XK_Escape) {
    // clear the raw sequence
    raw_sequence_.clear();
    ClearChord();
  }
  return kNoop;
}

// Note: QWERTY layout only.
static const char map_to_base_layer[] = {
  " 1'3457'908=,-./"
  "0123456789;;,=./"
  "2abcdefghijklmno"
  "pqrstuvwxyz[\\]6-"
  "`abcdefghijklmno"
  "pqrstuvwxyz[\\]`"
};

inline static int get_base_layer_key_code(const KeyEvent& key_event) {
  int ch = key_event.keycode();
  bool is_shift = key_event.shift();
  return (is_shift && ch >= 0x20 && ch <= 0x7e)
      ? map_to_base_layer[ch - 0x20] : ch;
}

ProcessResult ChordComposer::ProcessChordingKey(const KeyEvent& key_event) {
  if (key_event.ctrl() || key_event.alt()) {
    raw_sequence_.clear();
  }
  if (key_event.ctrl() && !use_control_ ||
      key_event.alt() && !use_alt_ ||
      key_event.shift() && !use_shift_) {
    ClearChord();
    return kNoop;
  }
  int ch = get_base_layer_key_code(key_event);
  // non chording key
  if (std::find(chording_keys_.begin(),
                chording_keys_.end(),
                KeyEvent{ch, 0}) == chording_keys_.end()) {
    ClearChord();
    return kNoop;
  }
  // chording key
  bool is_key_up = key_event.release();
  if (is_key_up) {
    if (pressed_.erase(ch) != 0 && pressed_.empty()) {
      FinishChord();
    }
  }
  else {  // key down
    pressed_.insert(ch);
    bool updated = chord_.insert(ch).second;
    if (updated)
      UpdateChord();
  }
  return kAccepted;
}

inline static bool is_composing(Context* ctx) {
  return !ctx->composition().empty() &&
      !ctx->composition().back().HasTag("phony");
}

ProcessResult ChordComposer::ProcessKeyEvent(const KeyEvent& key_event) {
  if (engine_->context()->get_option("ascii_mode")) {
    return kNoop;
  }
  if (pass_thru_) {
    return ProcessFunctionKey(key_event);
  }
  bool is_key_up = key_event.release();
  int ch = key_event.keycode();
  if (!is_key_up && ch >= 0x20 && ch <= 0x7e) {
    // save raw input
    if (!is_composing(engine_->context()) || !raw_sequence_.empty()) {
      raw_sequence_.push_back(ch);
      DLOG(INFO) << "update raw sequence: " << raw_sequence_;
    }
  }
  auto result = ProcessChordingKey(key_event);
  if (result != kNoop) {
    return result;
  }
  return ProcessFunctionKey(key_event);
}

string ChordComposer::SerializeChord() {
  KeySequence key_sequence;
  for (KeyEvent key : chording_keys_) {
    if (chord_.find(key.keycode()) != chord_.end())
      key_sequence.push_back(key);
  }
  string code = key_sequence.repr();
  algebra_.Apply(&code);
  return code;
}

void ChordComposer::UpdateChord() {
  if (!engine_)
    return;
  Context* ctx = engine_->context();
  Composition& comp = ctx->composition();
  string code = SerializeChord();
  prompt_format_.Apply(&code);
  if (comp.empty()) {
    // add a placeholder segment
    // 1. to cheat ctx->IsComposing() == true
    // 2. to attach chord prompt to while chording
    ctx->set_input(kZeroWidthSpace);
    Segment placeholder(0, ctx->input().length());
    placeholder.tags.insert("phony");
    ctx->composition().AddSegment(placeholder);
  }
  auto& last_segment = comp.back();
  last_segment.tags.insert("chord_prompt");
  last_segment.prompt = code;
}

void ChordComposer::FinishChord() {
  if (!engine_)
    return;
  string code = SerializeChord();
  output_format_.Apply(&code);
  ClearChord();

  KeySequence key_sequence;
  if (key_sequence.Parse(code) && !key_sequence.empty()) {
    pass_thru_ = true;
    for (const KeyEvent& key : key_sequence) {
      if (!engine_->ProcessKey(key)) {
        // direct commit
        engine_->CommitText(string(1, key.keycode()));
        // exclude the character (eg. space) from the raw sequence
        raw_sequence_.clear();
      }
    }
    pass_thru_ = false;
  }
}

void ChordComposer::ClearChord() {
  pressed_.clear();
  chord_.clear();
  if (!engine_)
    return;
  Context* ctx = engine_->context();
  Composition& comp = ctx->composition();
  if (comp.empty())
    return;
  auto& last_segment = comp.back();
  if (comp.size() == 1 && last_segment.HasTag("phony")) {
    ctx->Clear();
  }
  else if (last_segment.HasTag("chord_prompt")) {
    last_segment.prompt.clear();
    last_segment.tags.erase("chord_prompt");
  }
}

void ChordComposer::OnContextUpdate(Context* ctx) {
  if (is_composing(ctx)) {
    composing_ = true;
  }
  else if (composing_) {
    composing_ = false;
    raw_sequence_.clear();
    DLOG(INFO) << "clear raw sequence.";
  }
}

void ChordComposer::OnUnhandledKey(Context* ctx, const KeyEvent& key) {
  // directly committed ascii should not be captured into the raw sequence
  // test case:
  // 3.14{Return} should not commit an extra sequence '14'
  if ((key.modifier() & ~kShiftMask) == 0 &&
      key.keycode() >= 0x20 && key.keycode() <= 0x7e) {
    raw_sequence_.clear();
    DLOG(INFO) << "clear raw sequence.";
  }
}

}  // namespace rime
<|endoftext|>


<commit_before>// Day18.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const static size_t FieldSize = 100;

typedef std::array<bool, FieldSize> Row;
typedef std::array<Row, FieldSize> Field;
typedef std::shared_ptr<Field> PField;

static PField CreateField(const std::string & InputFile);
static size_t GetTurnedOnLights(PField Lights, size_t Steps);

static bool GetNewLightSate(PField Lights, size_t X, size_t Y);
static size_t GetTurnedOnNeighbors(PField Lights, size_t X, size_t Y);

int main()
{
	PField Lights = CreateField("Input.txt");
	size_t LightsOn = GetTurnedOnLights(Lights, 100);

	std::cout << "Lights on: " << LightsOn << std::endl;

	system("pause");

    return 0;
}

static PField CreateField(const std::string & InputFile)
{
	PField Lights = std::make_shared<Field>();

	StringVector InputLines = GetFileLines(InputFile);
	Field::iterator RowIter = Lights->begin();

	for (const std::string & Line : InputLines)
	{
		Row::iterator LightIter = (RowIter++)->begin();
		for (const char & Char : Line)
		{
			(*(LightIter++)) = (Char == '#');
		}
	}

	return Lights;
}

static size_t GetTurnedOnLights(PField Lights, size_t Steps)
{
	PField Buffer = std::make_shared<Field>();
	size_t LightsOn = 0;

	for (size_t i = 0; i < Steps; i++)
	{
		LightsOn = 0;

		for (size_t x = 0; x < FieldSize; x++)
			for (size_t y = 0; y < FieldSize; y++)
			{
				bool NewState = GetNewLightSate(Lights, x, y);
				(*Buffer)[x][y] = NewState;

				if (NewState)
				{
					++LightsOn;
				}
			}

		Buffer.swap(Lights);
	}

	return LightsOn;
}

static bool GetNewLightSate(PField Lights, size_t X, size_t Y)
{
	size_t TurnedOnNeighbors = GetTurnedOnNeighbors(Lights, X, Y);

	if ((*Lights)[X][Y])
	{
		return ((TurnedOnNeighbors == 2) || (TurnedOnNeighbors == 3));
	}
	else
	{
		return (TurnedOnNeighbors == 3);
	}
}

static size_t GetTurnedOnNeighbors(PField Lights, size_t X, size_t Y)
{
	size_t LightsOn = 0;

	for (size_t TX = (X > 0) ? X - 1 : X; TX <= std::min(X + 1, FieldSize - 1); ++TX)
		for (size_t TY = (Y > 0) ? Y - 1 : Y; TY <= std::min(Y + 1, FieldSize - 1); ++TY)
		{
			if ((TX == X) && (TY == Y))
			{
				continue;
			}

			LightsOn += ((*Lights)[TX][TY]) ? 1 : 0;
		}

	return LightsOn;
}<commit_msg>Add solution for Day 18 part two<commit_after>// Day18.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const static size_t FieldSize = 100;

typedef std::array<bool, FieldSize> Row;
typedef std::array<Row, FieldSize> Field;
typedef std::shared_ptr<Field> PField;

typedef std::pair<size_t, size_t> FieldCoord;
typedef std::vector<FieldCoord> CoordVector;

static PField CreateField(const std::string & InputFile);
static size_t GetTurnedOnLights(PField Lights, size_t Steps, const CoordVector & StuckedLights = CoordVector());

static bool GetNewLightSate(PField Lights, size_t X, size_t Y);
static size_t GetTurnedOnNeighbors(PField Lights, size_t X, size_t Y);
static void TurnOnStuckedLights(PField Lights, const CoordVector & StuckedLights, size_t & LightsOnCount);

int main()
{
	PField Lights = CreateField("Input.txt");
	size_t LightsOn = GetTurnedOnLights(Lights, 100);

	std::cout << "Lights on (non-stucked): " << LightsOn << std::endl;

	Lights = CreateField("Input.txt");
	LightsOn = GetTurnedOnLights(Lights, 100, { {0,0},{ 0,FieldSize - 1 },{ FieldSize - 1,0 },{ FieldSize - 1,FieldSize - 1 } });

	std::cout << "Lights on (stucked): " << LightsOn << std::endl;

	system("pause");

	return 0;
}

static PField CreateField(const std::string & InputFile)
{
	PField Lights = std::make_shared<Field>();

	StringVector InputLines = GetFileLines(InputFile);
	Field::iterator RowIter = Lights->begin();

	for (const std::string & Line : InputLines)
	{
		Row::iterator LightIter = (RowIter++)->begin();
		for (const char & Char : Line)
		{
			(*(LightIter++)) = (Char == '#');
		}
	}

	return Lights;
}

static size_t GetTurnedOnLights(PField Lights, size_t Steps, const CoordVector & StuckedLights)
{
	PField Buffer = std::make_shared<Field>();
	size_t LightsOn = 0;

	TurnOnStuckedLights(Lights, StuckedLights, LightsOn);

	for (size_t i = 0; i < Steps; i++)
	{
		LightsOn = 0;

		for (size_t x = 0; x < FieldSize; x++)
			for (size_t y = 0; y < FieldSize; y++)
			{
				bool NewState = GetNewLightSate(Lights, x, y);
				(*Buffer)[x][y] = NewState;

				if (NewState)
				{
					++LightsOn;
				}
			}

		TurnOnStuckedLights(Buffer, StuckedLights, LightsOn);
		Buffer.swap(Lights);
	}

	return LightsOn;
}

static bool GetNewLightSate(PField Lights, size_t X, size_t Y)
{
	size_t TurnedOnNeighbors = GetTurnedOnNeighbors(Lights, X, Y);

	if ((*Lights)[X][Y])
	{
		return ((TurnedOnNeighbors == 2) || (TurnedOnNeighbors == 3));
	}
	else
	{
		return (TurnedOnNeighbors == 3);
	}
}

static size_t GetTurnedOnNeighbors(PField Lights, size_t X, size_t Y)
{
	size_t LightsOn = 0;

	for (size_t TX = (X > 0) ? X - 1 : X; TX <= std::min(X + 1, FieldSize - 1); ++TX)
		for (size_t TY = (Y > 0) ? Y - 1 : Y; TY <= std::min(Y + 1, FieldSize - 1); ++TY)
		{
			if ((TX == X) && (TY == Y))
			{
				continue;
			}

			LightsOn += ((*Lights)[TX][TY]) ? 1 : 0;
		}

	return LightsOn;
}

static void TurnOnStuckedLights(PField Lights, const CoordVector & StuckedLights, size_t & LightsOnCount)
{
	for (const FieldCoord & StuckedLight : StuckedLights)
	{
		bool & Light = (*Lights)[StuckedLight.first][StuckedLight.second];
		if (!Light)
		{
			Light = true;
			++LightsOnCount;
		}
	}
}<|endoftext|>


<commit_before>/*
Copyright (c) 2012, Oliver Woodford
Copyright (c) 2014, Florian Franzen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __MEX_HPP__
#define __MEX_HPP__

#include "mex.h"
#include <stdint.h>
#include <string>
#include <cstring>
#include <typeinfo>
#include <iostream>
#include <sstream>
#include <exception>

#include "Eigen/Core"
using Eigen::Map;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::ColMajor;

#define MEX_CLASS_HANDLE_SIGNATURE 0x434d544d

template<class BaseClass> class MEXClassHandle {
public:

    static mxArray* wrap(BaseClass* ptr) {
        mexLock();
        mxArray *out = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
        *((uint64_t *)mxGetData(out)) = reinterpret_cast<uint64_t>(new MEXClassHandle<BaseClass>(ptr));
        return out;
    }

    static BaseClass* unwrap(const mxArray *in) {
        return fromMxArray(in)->getPointer();
    }

    static void free(const mxArray *in) {
        delete fromMxArray(in);
        mexUnlock();
    }

private:
    MEXClassHandle(BaseClass* pointer) : mPointer(pointer), mName(typeid(BaseClass).name()), mSignature(MEX_CLASS_HANDLE_SIGNATURE) {}

    ~MEXClassHandle() {
        mSignature = 0;
        delete mPointer;
    }

    bool isValid() {
        return ((mSignature == MEX_CLASS_HANDLE_SIGNATURE) &&
                !strcmp(mName.c_str(), typeid(BaseClass).name()));
    }

    BaseClass* getPointer() {
        return mPointer;
    }

    static MEXClassHandle* fromMxArray(const mxArray *in) {
        if (mxGetNumberOfElements(in) != 1 || !mxIsUint64(in) || mxIsComplex(in))
            mexErrMsgIdAndTxt("MEXClassHandle:notAHandle", "Handle must be a real uint64 scalar.");

        MEXClassHandle<BaseClass> *handle = reinterpret_cast<MEXClassHandle<BaseClass> *>(*((uint64_t*) mxGetData(in)));

        if (!handle->isValid())
            mexErrMsgIdAndTxt("MEXClassHandle:invalidHandle", "Handle is not valid.");

        return handle;
    }

    uint32_t    mSignature;
    std::string mName;
    BaseClass*  mPointer;
};

class MEXInput {
public:
    MEXInput(int size, const mxArray** data) : mSize(size), mData(data) {}

    int size() const {
        return mSize;
    }

    bool has(int i) const {
        return i >= 0 && i < mSize;
    }

    enum Type { // ToDo: Decide if you want to add vectors
        Unknown,
        BoolScalar,
        IntScalar,
        FloatScalar,
        BoolMatrix,
        IntMatrix,
        FloatMatrix,
        String,
        Struct,
        Cell
    };

    class Converter {
    public:
        Converter(const mxArray* data, int index) : mData(data), mIndex(index) {}

        bool isEmpty() {
            return mxIsEmpty(mData);
        }

        MEXInput::Type getType() {
            switch (mxGetClassID(mData)) {
                case mxCHAR_CLASS:
                    return MEXInput::String;
                case mxSTRUCT_CLASS:
                    return MEXInput::Struct;
                case mxCELL_CLASS:
                    return MEXInput::Cell;
                case mxLOGICAL_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::BoolScalar : MEXInput::BoolMatrix;
                case mxINT8_CLASS:
                case mxUINT8_CLASS:
                case mxINT16_CLASS:
                case mxUINT16_CLASS:
                case mxINT32_CLASS:
                case mxUINT32_CLASS:
                case mxINT64_CLASS:
                case mxUINT64_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::IntScalar : MEXInput::IntMatrix;
                case mxSINGLE_CLASS:
                case mxDOUBLE_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::FloatScalar : MEXInput::FloatMatrix;
                case mxUNKNOWN_CLASS:
                    mexErrMsgTxt("Unknown class.");
                default:
                    mexErrMsgTxt("Unidentified class.");
            }
            return MEXInput::Unknown;
        }

        bool isType(MEXInput::Type t) {
            return (getType() == t);
        }

        template<class BaseClass> BaseClass* unwrap() {
            return MEXClassHandle<BaseClass>::unwrap(mData);
        }

        operator MatrixXd () {
            if(!isType(MEXInput::FloatMatrix)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double matrix.", mIndex + 1);
            }

            if(mxIsSparse(mData)) {
                mexErrMsgIdAndTxt("MEXInput:sparseMatrixNotSupported", "Sparse matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add sparse matrix support.
            }

            if(mxGetNumberOfDimensions(mData) > 2) {
                mexErrMsgIdAndTxt("MEXInput:moreThenTwoDimensions", "3D matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add 3d matrix support.
            }

            return Map<MatrixXd,ColMajor>(mxGetPr(mData), mxGetM(mData), mxGetN(mData));
         }

        operator VectorXd () {
            if(!isType(MEXInput::FloatMatrix) or mxGetN(mData) != 1) {
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double column vector.", mIndex + 1);
            }

            if(mxIsSparse(mData)) {
                mexErrMsgIdAndTxt("MEXInput:sparseMatrixNotSupported", "Sparse matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add sparse matrix support.
            }

            if(mxGetNumberOfDimensions(mData) > 2) {
                mexErrMsgIdAndTxt("MEXInput:moreThenTwoDimensions", "3D matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add 3d matrix support.
            }

            return Map<VectorXd,ColMajor>(mxGetPr(mData), mxGetM(mData));

        }

        operator double () {
            if(!isType(MEXInput::FloatScalar)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double scalar.", mIndex + 1);
            }

            return mxGetScalar(mData);
        }

        operator int () {
            if(!isType(MEXInput::IntScalar)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a integer scalar.", mIndex + 1);
            }

            return static_cast<int>(round(mxGetScalar(mData)));
        }

        operator bool () {
            if(!isType(MEXInput::BoolScalar)){
                mexErrMsgTxt("This should be a boolean scalar!");
            }

            return mxGetScalar(mData) != 0;
        }

    private:
        const mxArray* mData;
        int mIndex; // Only needed for error messages
    };

    MEXInput::Converter operator[](int i) const {
        if(!has(i)) {
            mexErrMsgIdAndTxt("MEXInput:missingArgument", "Not enough argument supplied! Could not access argument #%d.", i + 1);
        }

        return Converter(mData[i], i);
    }

private:
    int mSize;
    const mxArray** mData;
};

class MEXOutput {

public:
    MEXOutput(int size, mxArray** data) : mSize(size), mData(data) {}

    int size() {
        return mSize;
    }

    int has(int index) {
        return index >= 0 && index < mSize;
    }

    class Converter {
        public:
            Converter(mxArray** data) : mData(data) {}

            Converter& operator=(const MatrixXd& output) {
                (*mData) = mxCreateDoubleMatrix(output.rows(), output.cols(), mxREAL);
                Map<MatrixXd,ColMajor> data_wrapper(mxGetPr(*mData), output.rows(), output.cols());
                data_wrapper = output;
                return *this;
            }

            // Converter& operator=(const MatrixXb& output) {
            //     (*mData) = mxCreateLogicalMatrix(output.rows(), output.cols());
            //     Map<MatrixXb,ColMajor> data_wrapper(mxGetPr(*mData), output.rows(), output.cols());
            //     data_wrapper = output;
            //     return *this;
            // }

            Converter& operator=(const bool& b) {
                std::cout << "Bool: " << b << std::endl;
                (*mData) = mxCreateLogicalScalar(b);
                return *this;
            }

            Converter& operator=(const int& i) {
                const mwSize dims = 1;
                (*mData) = mxCreateNumericArray(1, &dims, mxINT32_CLASS, mxREAL);
                (*mxGetPr(*mData)) = i;
                return *this;
            }

            Converter& operator=(const double& d) {
                std::cout << "Double: " << d << std::endl;
                (*mData) = mxCreateDoubleScalar(d);
                return *this;
            }

            Converter& operator=(const std::string& s) {
                (*mData) = mxCreateString(s.c_str());
                return *this;
            }

        private:
            mxArray** mData;
    };

    MEXOutput::Converter operator[](int index) {
        if(!has(index)) {
            mexErrMsgIdAndTxt("MEXOutput:missingArgument", "Not enough ouput argument required! Could not access argument #%d.", index + 1);
        }

        return Converter(mData + index);
    }

private:
    int mSize;
    mxArray** mData;
};

// streambuffer that writes everything to mexPrintf. Usefull to reroute cout.
class mexstreambuf : public std::streambuf {
protected:
    std::streamsize xsputn(const char *s, std::streamsize n) {
        mexPrintf("%.*s",n,s);
        return n;
    }

    int overflow(int c = EOF) {
        if (c != EOF) {
            mexPrintf("%.1s",&c);
        }
        return 1;
    }

};

/**
 * Mex wrapper function, that takes care of object creation, storage and deletion and passes everything else onto parser function.
 *
 * @param creator function that parses matlab data to call class constructor
 * @param parser function that parses matlab data and forwards the appropiate function
 */
template<class BaseClass> inline void mexWrapper(BaseClass* (*creator)(MEXInput), bool (*parser)(BaseClass*, std::string, MEXOutput, MEXInput), int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Redirect cout
    mexstreambuf mexoutbuf;
    std::streambuf* coutbuf = std::cout.rdbuf(&mexoutbuf);

    // Get the command string
    char cmd[64];
    if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd)))
        mexErrMsgIdAndTxt("mexWrapper:invalidCommandstring", "First input should be a command string less than 64 characters long.");

    std::cout << "+++ DEBUG: Call to '" << cmd << "' with " << nrhs << " inputs and " << nlhs << " ouput value(s). +++" << std::endl;

    // New
    if (!strcmp("new", cmd)) {
        // Check parameters
        if (nlhs != 1)
            mexErrMsgIdAndTxt("mexWrapper:invalidOutput", "New: One output expected.");

        try {
            BaseClass* ptr = creator(MEXInput(nrhs - 1, prhs + 1));
            // Return a handle to a new C++ instance
            plhs[0] = MEXClassHandle<BaseClass>::wrap(ptr);
            return;
        } catch (std::exception& e) {
            mexErrMsgIdAndTxt("mexWrapper:constructor:exceptionCaught", "Exception in constructor: \n\t%s", e.what());
        }
    }

    // Check there is a second input, which should be the class instance handle
    if (nrhs < 2)
        mexErrMsgIdAndTxt("mexWrapper:missingClassHandle", "Second input should be a class instance handle.");

    // Delete
    if (!strcmp("delete", cmd)) {
        // Destroy the C++ object
        MEXClassHandle<BaseClass>::free(prhs[1]);
        // Warn if other commands were ignored
        if (nlhs != 0 || nrhs != 2)
            mexWarnMsgIdAndTxt("mexWrapper:ignoredArgurments", "Delete: Unexpected arguments ignored.");
        return;
    }

    // Get the class instance pointer from the second input
    BaseClass* instance = MEXClassHandle<BaseClass>::unwrap(prhs[1]);

    try {
        if(!parser(instance, cmd, MEXOutput(nlhs, plhs), MEXInput(nrhs - 2, prhs + 2)))
            mexErrMsgIdAndTxt("mexParse:unknownCommand", "Command '%s' not recognized!", cmd);
    } catch (std::exception& e) {
        mexErrMsgIdAndTxt("mexWrapper:methodAndPropertyParser:exceptionCaught", "Exception in method and property parser: \n\t%s", e.what());
    }

    // Reset cout
    std::cout.rdbuf(coutbuf);
}

#endif // __MEX_HPP__
<commit_msg>Removes debugging.<commit_after>/*
Copyright (c) 2012, Oliver Woodford
Copyright (c) 2014, Florian Franzen
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef __MEX_HPP__
#define __MEX_HPP__

#include "mex.h"
#include <stdint.h>
#include <string>
#include <cstring>
#include <typeinfo>
#include <iostream>
#include <sstream>
#include <exception>

#include "Eigen/Core"
using Eigen::Map;
using Eigen::MatrixXd;
using Eigen::VectorXd;
using Eigen::ColMajor;

#define MEX_CLASS_HANDLE_SIGNATURE 0x434d544d

template<class BaseClass> class MEXClassHandle {
public:

    static mxArray* wrap(BaseClass* ptr) {
        mexLock();
        mxArray *out = mxCreateNumericMatrix(1, 1, mxUINT64_CLASS, mxREAL);
        *((uint64_t *)mxGetData(out)) = reinterpret_cast<uint64_t>(new MEXClassHandle<BaseClass>(ptr));
        return out;
    }

    static BaseClass* unwrap(const mxArray *in) {
        return fromMxArray(in)->getPointer();
    }

    static void free(const mxArray *in) {
        delete fromMxArray(in);
        mexUnlock();
    }

private:
    MEXClassHandle(BaseClass* pointer) : mPointer(pointer), mName(typeid(BaseClass).name()), mSignature(MEX_CLASS_HANDLE_SIGNATURE) {}

    ~MEXClassHandle() {
        mSignature = 0;
        delete mPointer;
    }

    bool isValid() {
        return ((mSignature == MEX_CLASS_HANDLE_SIGNATURE) &&
                !strcmp(mName.c_str(), typeid(BaseClass).name()));
    }

    BaseClass* getPointer() {
        return mPointer;
    }

    static MEXClassHandle* fromMxArray(const mxArray *in) {
        if (mxGetNumberOfElements(in) != 1 || !mxIsUint64(in) || mxIsComplex(in))
            mexErrMsgIdAndTxt("MEXClassHandle:notAHandle", "Handle must be a real uint64 scalar.");

        MEXClassHandle<BaseClass> *handle = reinterpret_cast<MEXClassHandle<BaseClass> *>(*((uint64_t*) mxGetData(in)));

        if (!handle->isValid())
            mexErrMsgIdAndTxt("MEXClassHandle:invalidHandle", "Handle is not valid.");

        return handle;
    }

    uint32_t    mSignature;
    std::string mName;
    BaseClass*  mPointer;
};

class MEXInput {
public:
    MEXInput(int size, const mxArray** data) : mSize(size), mData(data) {}

    int size() const {
        return mSize;
    }

    bool has(int i) const {
        return i >= 0 && i < mSize;
    }

    enum Type { // ToDo: Decide if you want to add vectors
        Unknown,
        BoolScalar,
        IntScalar,
        FloatScalar,
        BoolMatrix,
        IntMatrix,
        FloatMatrix,
        String,
        Struct,
        Cell
    };

    class Converter {
    public:
        Converter(const mxArray* data, int index) : mData(data), mIndex(index) {}

        bool isEmpty() {
            return mxIsEmpty(mData);
        }

        MEXInput::Type getType() {
            switch (mxGetClassID(mData)) {
                case mxCHAR_CLASS:
                    return MEXInput::String;
                case mxSTRUCT_CLASS:
                    return MEXInput::Struct;
                case mxCELL_CLASS:
                    return MEXInput::Cell;
                case mxLOGICAL_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::BoolScalar : MEXInput::BoolMatrix;
                case mxINT8_CLASS:
                case mxUINT8_CLASS:
                case mxINT16_CLASS:
                case mxUINT16_CLASS:
                case mxINT32_CLASS:
                case mxUINT32_CLASS:
                case mxINT64_CLASS:
                case mxUINT64_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::IntScalar : MEXInput::IntMatrix;
                case mxSINGLE_CLASS:
                case mxDOUBLE_CLASS:
                    return (mxGetNumberOfElements(mData) == 1) ? MEXInput::FloatScalar : MEXInput::FloatMatrix;
                case mxUNKNOWN_CLASS:
                    mexErrMsgTxt("Unknown class.");
                default:
                    mexErrMsgTxt("Unidentified class.");
            }
            return MEXInput::Unknown;
        }

        bool isType(MEXInput::Type t) {
            return (getType() == t);
        }

        template<class BaseClass> BaseClass* unwrap() {
            return MEXClassHandle<BaseClass>::unwrap(mData);
        }

        operator MatrixXd () {
            if(!isType(MEXInput::FloatMatrix)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double matrix.", mIndex + 1);
            }

            if(mxIsSparse(mData)) {
                mexErrMsgIdAndTxt("MEXInput:sparseMatrixNotSupported", "Sparse matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add sparse matrix support.
            }

            if(mxGetNumberOfDimensions(mData) > 2) {
                mexErrMsgIdAndTxt("MEXInput:moreThenTwoDimensions", "3D matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add 3d matrix support.
            }

            return Map<MatrixXd,ColMajor>(mxGetPr(mData), mxGetM(mData), mxGetN(mData));
         }

        operator VectorXd () {
            if(!isType(MEXInput::FloatMatrix) or mxGetN(mData) != 1) {
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double column vector.", mIndex + 1);
            }

            if(mxIsSparse(mData)) {
                mexErrMsgIdAndTxt("MEXInput:sparseMatrixNotSupported", "Sparse matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add sparse matrix support.
            }

            if(mxGetNumberOfDimensions(mData) > 2) {
                mexErrMsgIdAndTxt("MEXInput:moreThenTwoDimensions", "3D matrix are not supported (argument #%d).", mIndex + 1); // ToDo: Add 3d matrix support.
            }

            return Map<VectorXd,ColMajor>(mxGetPr(mData), mxGetM(mData));

        }

        operator double () {
            if(!isType(MEXInput::FloatScalar)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a single or double scalar.", mIndex + 1);
            }

            return mxGetScalar(mData);
        }

        operator int () {
            if(!isType(MEXInput::IntScalar)){
                mexErrMsgIdAndTxt("MEXInput:typeMismatch", "Argument #%d should be a integer scalar.", mIndex + 1);
            }

            return static_cast<int>(round(mxGetScalar(mData)));
        }

        operator bool () {
            if(!isType(MEXInput::BoolScalar)){
                mexErrMsgTxt("This should be a boolean scalar!");
            }

            return mxGetScalar(mData) != 0;
        }

    private:
        const mxArray* mData;
        int mIndex; // Only needed for error messages
    };

    MEXInput::Converter operator[](int i) const {
        if(!has(i)) {
            mexErrMsgIdAndTxt("MEXInput:missingArgument", "Not enough argument supplied! Could not access argument #%d.", i + 1);
        }

        return Converter(mData[i], i);
    }

private:
    int mSize;
    const mxArray** mData;
};

class MEXOutput {

public:
    MEXOutput(int size, mxArray** data) : mSize(size), mData(data) {}

    int size() {
        return mSize;
    }

    int has(int index) {
        return index >= 0 && index < mSize;
    }

    class Converter {
        public:
            Converter(mxArray** data) : mData(data) {}

            Converter& operator=(const MatrixXd& output) {
                (*mData) = mxCreateDoubleMatrix(output.rows(), output.cols(), mxREAL);
                Map<MatrixXd,ColMajor> data_wrapper(mxGetPr(*mData), output.rows(), output.cols());
                data_wrapper = output;
                return *this;
            }

            // Converter& operator=(const MatrixXb& output) {
            //     (*mData) = mxCreateLogicalMatrix(output.rows(), output.cols());
            //     Map<MatrixXb,ColMajor> data_wrapper(mxGetPr(*mData), output.rows(), output.cols());
            //     data_wrapper = output;
            //     return *this;
            // }

            Converter& operator=(const bool& b) {
                (*mData) = mxCreateLogicalScalar(b);
                return *this;
            }

            Converter& operator=(const int& i) {
                const mwSize dims = 1;
                (*mData) = mxCreateNumericArray(1, &dims, mxINT32_CLASS, mxREAL);
                (*mxGetPr(*mData)) = i;
                return *this;
            }

            Converter& operator=(const double& d) {
                std::cout << "Double: " << d << std::endl;
                (*mData) = mxCreateDoubleScalar(d);
                return *this;
            }

            Converter& operator=(const std::string& s) {
                (*mData) = mxCreateString(s.c_str());
                return *this;
            }

        private:
            mxArray** mData;
    };

    MEXOutput::Converter operator[](int index) {
        if(!has(index)) {
            mexErrMsgIdAndTxt("MEXOutput:missingArgument", "Not enough ouput argument required! Could not access argument #%d.", index + 1);
        }

        return Converter(mData + index);
    }

private:
    int mSize;
    mxArray** mData;
};

// streambuffer that writes everything to mexPrintf. Usefull to reroute cout.
class mexstreambuf : public std::streambuf {
protected:
    std::streamsize xsputn(const char *s, std::streamsize n) {
        mexPrintf("%.*s",n,s);
        return n;
    }

    int overflow(int c = EOF) {
        if (c != EOF) {
            mexPrintf("%.1s",&c);
        }
        return 1;
    }

};

/**
 * Mex wrapper function, that takes care of object creation, storage and deletion and passes everything else onto parser function.
 *
 * @param creator function that parses matlab data to call class constructor
 * @param parser function that parses matlab data and forwards the appropiate function
 */
template<class BaseClass> inline void mexWrapper(BaseClass* (*creator)(MEXInput), bool (*parser)(BaseClass*, std::string, MEXOutput, MEXInput), int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    // Redirect cout
    mexstreambuf mexoutbuf;
    std::streambuf* coutbuf = std::cout.rdbuf(&mexoutbuf);

    // Get the command string
    char cmd[64];
    if (nrhs < 1 || mxGetString(prhs[0], cmd, sizeof(cmd)))
        mexErrMsgIdAndTxt("mexWrapper:invalidCommandstring", "First input should be a command string less than 64 characters long.");

    std::cout << "+++ DEBUG: Call to '" << cmd << "' with " << nrhs << " inputs and " << nlhs << " ouput value(s). +++" << std::endl;

    // New
    if (!strcmp("new", cmd)) {
        // Check parameters
        if (nlhs != 1)
            mexErrMsgIdAndTxt("mexWrapper:invalidOutput", "New: One output expected.");

        try {
            BaseClass* ptr = creator(MEXInput(nrhs - 1, prhs + 1));
            // Return a handle to a new C++ instance
            plhs[0] = MEXClassHandle<BaseClass>::wrap(ptr);
            return;
        } catch (std::exception& e) {
            mexErrMsgIdAndTxt("mexWrapper:constructor:exceptionCaught", "Exception in constructor: \n\t%s", e.what());
        }
    }

    // Check there is a second input, which should be the class instance handle
    if (nrhs < 2)
        mexErrMsgIdAndTxt("mexWrapper:missingClassHandle", "Second input should be a class instance handle.");

    // Delete
    if (!strcmp("delete", cmd)) {
        // Destroy the C++ object
        MEXClassHandle<BaseClass>::free(prhs[1]);
        // Warn if other commands were ignored
        if (nlhs != 0 || nrhs != 2)
            mexWarnMsgIdAndTxt("mexWrapper:ignoredArgurments", "Delete: Unexpected arguments ignored.");
        return;
    }

    // Get the class instance pointer from the second input
    BaseClass* instance = MEXClassHandle<BaseClass>::unwrap(prhs[1]);

    try {
        if(!parser(instance, cmd, MEXOutput(nlhs, plhs), MEXInput(nrhs - 2, prhs + 2)))
            mexErrMsgIdAndTxt("mexParse:unknownCommand", "Command '%s' not recognized!", cmd);
    } catch (std::exception& e) {
        mexErrMsgIdAndTxt("mexWrapper:methodAndPropertyParser:exceptionCaught", "Exception in method and property parser: \n\t%s", e.what());
    }

    // Reset cout
    std::cout.rdbuf(coutbuf);
}

#endif // __MEX_HPP__
<|endoftext|>


<commit_before>/*
 * VariableList.hpp
 *
 *  Created on: 18.04.2016
 *      Author: Marc Hartung
 */

#ifndef INCLUDE_VARIABLELIST_HPP_
#define INCLUDE_VARIABLELIST_HPP_

#include "AdditionalTypes.hpp"
#include <iostream>
#include <vector>

namespace NetOff
{
    /*! \brief
     *
     * todo Marc!
     */
    class VariableList : public SharedDataAccessable
    {
     public:

        VariableList();

        VariableList(const std::vector<std::string> & realVars, const std::vector<std::string> & intVars, const std::vector<std::string> & boolVars);

        /*! \brief Adds a real variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addReal(const std::string & varName);

        /*! \brief Adds a integer variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addInt(const std::string & varName);

        /*! \brief Adds a boolean variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addBool(const std::string & varName);

        /*! \brief Adds a vector of real variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addReals(const std::vector<std::string> & varNames);

        /*! \brief Adds a vector of integer variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addInts(const std::vector<std::string> & varNames);

        /*! \brief Adds a vector of boolean variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addBools(const std::vector<std::string> & varNames);

        const std::vector<std::string> & getReals() const;
        const std::vector<std::string> & getInts() const;
        const std::vector<std::string> & getBools() const;

        /*! Returns size of real container, i.e., number of stored real variable names. */
        size_t sizeReals() const;
        size_t sizeInts() const;
        size_t sizeBools() const;

        /*! \brief Returns true, if the container is empty. */
        bool empty() const;

        size_t dataSize() const;

        std::shared_ptr<const char> data() const;

        std::shared_ptr<char> data();

        void saveVariablesTo(char * data) const;

        static VariableList getVariableListFromData(const char * data);

        friend std::ostream & operator<<(std::ostream & out, const VariableList & in);

        bool isSubsetOf(const VariableList & in) const;

        size_t findRealVariableNameIndex(const std::string & varName) const;

     private:
        /*! _vars[0] = Vector containing names of real variables.
         *  _vars[1] = Vector containing names of integer variables.
         *  _vars[2] = Vector containing names of boolean variables.
         */
        std::vector<std::vector<std::string>> _vars;

        VariableList(const std::shared_ptr<char> & data);
    };
}
#endif /* INCLUDE_VARIABLELIST_HPP_ */
<commit_msg>Add some comments for documentary<commit_after>/*
 * VariableList.hpp
 *
 *  Created on: 18.04.2016
 *      Author: Marc Hartung
 */

#ifndef INCLUDE_VARIABLELIST_HPP_
#define INCLUDE_VARIABLELIST_HPP_

#include "AdditionalTypes.hpp"
#include <iostream>
#include <vector>

namespace NetOff
{
    /*! \brief
     *
     * todo Marc!
     */
    class VariableList : public SharedDataAccessable
    {
     public:

        VariableList();

        VariableList(const std::vector<std::string> & realVars, const std::vector<std::string> & intVars, const std::vector<std::string> & boolVars);

        /*! \brief Adds a real variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addReal(const std::string & varName);

        /*! \brief Adds a integer variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addInt(const std::string & varName);

        /*! \brief Adds a boolean variable to the container.
         *
         * @param varName Name of the variable.
         */
        void addBool(const std::string & varName);

        /*! \brief Adds a vector of real variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addReals(const std::vector<std::string> & varNames);

        /*! \brief Adds a vector of integer variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addInts(const std::vector<std::string> & varNames);

        /*! \brief Adds a vector of boolean variables to the container.
         *
         * @param varNames Vector of the variable names.
         */
        void addBools(const std::vector<std::string> & varNames);

        const std::vector<std::string> & getReals() const;
        const std::vector<std::string> & getInts() const;
        const std::vector<std::string> & getBools() const;

        /*! Returns size of real container, i.e., number of stored real variable names. */
        size_t sizeReals() const;
        /*! Returns size of integer container, i.e., number of stored integer variable names. */
        size_t sizeInts() const;
        /*! Returns size of boolean container, i.e., number of stored boolean variable names. */
        size_t sizeBools() const;

        /*! \brief Returns true, if the container is empty. */
        bool empty() const;

        size_t dataSize() const;

        std::shared_ptr<const char> data() const;

        std::shared_ptr<char> data();

        void saveVariablesTo(char * data) const;

        static VariableList getVariableListFromData(const char * data);

        friend std::ostream & operator<<(std::ostream & out, const VariableList & in);

        bool isSubsetOf(const VariableList & in) const;

        size_t findRealVariableNameIndex(const std::string & varName) const;

     private:
        /*! _vars[0] = Vector containing names of real variables.
         *  _vars[1] = Vector containing names of integer variables.
         *  _vars[2] = Vector containing names of boolean variables.
         */
        std::vector<std::vector<std::string>> _vars;

        VariableList(const std::shared_ptr<char> & data);
    };
}
#endif /* INCLUDE_VARIABLELIST_HPP_ */
<|endoftext|>