<commit_before>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2011-2016 Senscape s.r.l.
// All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "Serializer.h"
#include "Audio.h"
#include "CameraManager.h"
#include "Control.h"
#include "Node.h"
#include "Room.h"
#include "Spot.h"
#include "TimerManager.h"
#include "Version.h"

#include <cstring>
#include <climits>

namespace dagon {

////////////////////////////////////////////////////////////
// Implementation - Constructor & Destructor
////////////////////////////////////////////////////////////

Serializer::Serializer(lua_State *L, SDL_RWops *rw) : _L(L), _rw(rw) {}

Serializer::~Serializer() {
  SDL_RWclose(_rw);
}

////////////////////////////////////////////////////////////
// Implementation - Private
////////////////////////////////////////////////////////////

bool Serializer::writeField(const std::string &key, const std::string &val) {
  return SDL_WriteBE16(_rw, key.length() + val.length() + 1) && // +1 because of =
         SDL_RWwrite(_rw, key.c_str(), key.length(), 1) &&
         SDL_WriteU8(_rw, '=') &&
         SDL_RWwrite(_rw, val.c_str(), val.length(), 1);
}

int32_t Serializer::writeTable(const std::string parentKey) {
  // Handle cycles
  for (const auto &table : _tblMap) {
    lua_rawgeti(_L, LUA_REGISTRYINDEX, table.first);

    if (lua_equal(_L, -1, -2)) { // Maybe a cycle...
      lua_pop(_L, 1);
      if (!writeField(parentKey, table.second))
        return -1;
      return 1;
    }
    else
      lua_pop(_L, 1);
  }

  { // Store this table
    int ref = luaL_ref(_L, LUA_REGISTRYINDEX);
    _tblMap[ref] = parentKey;
  }

  lua_pushnil(_L);
  int32_t numFields = 0;
  while (lua_next(_L, -2) != 0) {
    if (!lua_isstring(_L, -2)) {
      lua_pop(_L, 1);
      continue;
    }

    std::string val;
    std::string fullKey = parentKey + '[';
    if (lua_type(_L, -2) == LUA_TSTRING)
      fullKey += '"';
    lua_pushvalue(_L, -2);
    fullKey += lua_tostring(_L, -1);
    lua_pop(_L, 1);
    if (lua_type(_L, -2) == LUA_TSTRING)
      fullKey += '"';
    fullKey += ']';

    switch (lua_type(_L, -1)) {
    case LUA_TTABLE: {
      int32_t numNewFields = writeTable(fullKey);
      if (numNewFields < 0)
        return -1;
      numFields += numNewFields;

      lua_pop(_L, 1);
      continue;
    }
    case LUA_TBOOLEAN: {
      val = lua_toboolean(_L, -1) ? "true" : "false";
      break;
    }
    case LUA_TSTRING:
      val += '"';
      // Fallthrough
    case LUA_TNUMBER: {
      val += lua_tostring(_L, -1);
      if (val[0] == '"')
        val += '"';
      break;
    }
    default: {
      lua_pop(_L, 1);
      continue;
    }
    }

    if (!writeField(fullKey, val))
      return -1;

    numFields++;
    lua_pop(_L, 1);
  }

  return numFields;
}

int Serializer::writeFunction(lua_State *L, const void *p, size_t sz, void *ud) {
  SDL_RWops *rw = reinterpret_cast<SDL_RWops*>(ud);
  if (!SDL_RWwrite(rw, p, sz, 1))
    return 1;
  return 0;
}

////////////////////////////////////////////////////////////
// Implementation - Public
////////////////////////////////////////////////////////////

bool Serializer::writeHeader() {
  // Write version information
  {
    const size_t len = UCHAR_MAX > strlen(DAGON_VERSION_STRING) ? strlen(DAGON_VERSION_STRING) :
                                                                  UCHAR_MAX;
    if (!SDL_WriteU8(_rw, len))
      return false;
    if (!SDL_RWwrite(_rw, DAGON_VERSION_STRING, len, 1))
      return false;
  }

  // Write preview
  {
    const std::string desc = Control::instance().currentNode()->description();
    const size_t len = UCHAR_MAX > desc.length() ? desc.length() : UCHAR_MAX;

    if (!SDL_WriteU8(_rw, len))
      return false;
    if (!SDL_RWwrite(_rw, desc.c_str(), len, 1))
      return false;
  }

  // Write current room name
  const std::string name = Control::instance().currentRoom()->name();
  if (!SDL_WriteU8(_rw, name.length()))
    return false;
  if (!SDL_RWwrite(_rw, name.c_str(), name.length(), 1))
    return false;

  return true;
}

bool Serializer::writeScriptData() {
  int64_t fieldsPtr = SDL_RWtell(_rw);
  if (fieldsPtr < 0)
    return false;
  if (!SDL_WriteBE32(_rw, 0)) // 4 placeholder bytes for the actual number of fields
    return false;

  lua_getglobal(_L, "dgPersistence");
  int32_t numFields = writeTable("dgPersistence");
  if (numFields < 0)
    return false;

  if (SDL_RWseek(_rw, fieldsPtr, RW_SEEK_SET) < 0) // Restore file pointer to 4 placeholder bytes
    return false;
  if (!SDL_WriteBE32(_rw, numFields))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  return true;
}

bool Serializer::writeRoomData() {
  Room *room = Control::instance().currentRoom();

  // Write the enable status for the spots of all nodes
  uint16_t numNodes = 0;
  if (room->hasNodes()) {
    int64_t nodesPtr = SDL_RWtell(_rw);
    if (nodesPtr < 0)
      return false;
    if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of nodes
      return false;

    room->beginIteratingNodes();
    do {
      Node *node = room->iterator();

      uint16_t numSpots = 0;
      if (node->hasSpots()) {
        int64_t spotsPtr = SDL_RWtell(_rw);
        if (spotsPtr < 0)
          return false;
        if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of spots
          return false;

        node->beginIteratingSpots();
        do {
          Spot *spot = node->currentSpot();
          if (!SDL_WriteU8(_rw, spot->isEnabled()))
            return false;
          numSpots++;
        } while (node->iterateSpots());

        if (SDL_RWseek(_rw, spotsPtr, RW_SEEK_SET) < 0)
          return false;
      }

      if (!SDL_WriteBE16(_rw, numSpots))
        return false;
      if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
        return false;

      numNodes++;
    } while (room->iterateNodes());

    if (SDL_RWseek(_rw, nodesPtr, RW_SEEK_SET) < 0)
      return false;
  }

  if (!SDL_WriteBE16(_rw, numNodes))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  // Write node number
  uint16_t nodeIdx = 0;
  if (room->hasNodes()) {
    room->beginIteratingNodes();
    do {
      if (room->iterator() == room->currentNode())
        break;

      nodeIdx++;
    } while (room->iterateNodes());
  }

  if (!SDL_WriteBE16(_rw, nodeIdx))
    return false;

  // Write camera angles
  if (!SDL_WriteBE16(_rw, CameraManager::instance().angleHorizontal()))
    return false;
  if (!SDL_WriteBE16(_rw, CameraManager::instance().angleVertical()))
    return false;

  // Write audio states
  if (!SDL_WriteBE16(_rw, room->arrayOfAudios().size()))
    return false;

  for (Audio *audio : room->arrayOfAudios()) {
    if (!SDL_WriteU8(_rw, audio->state()))
      return false;
  }

  // Write timers
  int64_t timersPtr = SDL_RWtell(_rw);
  if (timersPtr < 0)
    return false;
  if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of timers
    return false;

  uint16_t numTimers = 0;
  for (const auto &timer : TimerManager::instance().timers()) {
    if (timer.type != DGTimerNormal || !timer.isEnabled ||
        (!timer.isLoopable && timer.hasTriggered))
      continue;

    double timeLeft = TimerManager::instance().timeLeft(timer);
    if (timeLeft > 0) {
      const std::string triggerStr = std::to_string(timer.trigger);
      if (!SDL_WriteU8(_rw, timer.isLoopable))
        return false;
      if (!SDL_WriteU8(_rw, triggerStr.length()))
        return false;
      if (!SDL_RWwrite(_rw, triggerStr.c_str(), triggerStr.length(), 1))
        return false;

      const std::string timerTime = std::to_string(timeLeft);
      if (!SDL_WriteU8(_rw, timerTime.length()))
        return false;
      if (!SDL_RWwrite(_rw, timerTime.c_str(), timerTime.length(), 1))
        return false;

      lua_rawgeti(_L, LUA_REGISTRYINDEX, timer.luaHandler); // Push timer function to top of stack

      int64_t funcSizePtr = SDL_RWtell(_rw);
      if (funcSizePtr < 0)
        return false;
      if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual function size
        return false;

      int64_t beforeFuncPtr = SDL_RWtell(_rw);
      if (beforeFuncPtr < 0)
        return false;
      int errCode = lua_dump(_L, writeFunction, _rw);
      if (errCode != 0)
        return false;
      int64_t afterFuncPtr = SDL_RWtell(_rw);
      if (afterFuncPtr < 0)
        return false;

      uint16_t numBytesWritten = afterFuncPtr - beforeFuncPtr;
      if (SDL_RWseek(_rw, funcSizePtr, RW_SEEK_SET) < 0)
        return false;
      if (!SDL_WriteBE16(_rw, numBytesWritten))
        return false;

      if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
        return false;

      numTimers++;
    }
  }

  if (SDL_RWseek(_rw, timersPtr, RW_SEEK_SET) < 0)
    return false;
  if (!SDL_WriteBE16(_rw, numTimers))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  // Write control mode
  if (!SDL_WriteU8(_rw, Config::instance().controlMode))
    return false;

  return true;
}

}
<commit_msg>Fix table storing<commit_after>////////////////////////////////////////////////////////////
//
// DAGON - An Adventure Game Engine
// Copyright (c) 2011-2016 Senscape s.r.l.
// All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL was
// not distributed with this file, You can obtain one at
// http://mozilla.org/MPL/2.0/.
//
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////

#include "Serializer.h"
#include "Audio.h"
#include "CameraManager.h"
#include "Control.h"
#include "Node.h"
#include "Room.h"
#include "Spot.h"
#include "TimerManager.h"
#include "Version.h"

#include <cstring>
#include <climits>

namespace dagon {

////////////////////////////////////////////////////////////
// Implementation - Constructor & Destructor
////////////////////////////////////////////////////////////

Serializer::Serializer(lua_State *L, SDL_RWops *rw) : _L(L), _rw(rw) {}

Serializer::~Serializer() {
  SDL_RWclose(_rw);
}

////////////////////////////////////////////////////////////
// Implementation - Private
////////////////////////////////////////////////////////////

bool Serializer::writeField(const std::string &key, const std::string &val) {
  return SDL_WriteBE16(_rw, key.length() + val.length() + 1) && // +1 because of =
         SDL_RWwrite(_rw, key.c_str(), key.length(), 1) &&
         SDL_WriteU8(_rw, '=') &&
         SDL_RWwrite(_rw, val.c_str(), val.length(), 1);
}

int32_t Serializer::writeTable(const std::string parentKey) {
  // Handle cycles
  for (const auto &table : _tblMap) {
    lua_rawgeti(_L, LUA_REGISTRYINDEX, table.first);

    if (lua_equal(_L, -1, -2)) { // Maybe a cycle...
      lua_pop(_L, 1);
      if (!writeField(parentKey, table.second))
        return -1;
      return 1;
    }
    else
      lua_pop(_L, 1);
  }

  { // Store this table
    lua_pushvalue(_L, -1);
    int ref = luaL_ref(_L, LUA_REGISTRYINDEX);
    _tblMap[ref] = parentKey;
  }

  lua_pushnil(_L);
  int32_t numFields = 0;
  while (lua_next(_L, -2) != 0) {
    if (!lua_isstring(_L, -2)) {
      lua_pop(_L, 1);
      continue;
    }

    std::string val;
    std::string fullKey = parentKey + '[';
    if (lua_type(_L, -2) == LUA_TSTRING)
      fullKey += '"';
    lua_pushvalue(_L, -2);
    fullKey += lua_tostring(_L, -1);
    lua_pop(_L, 1);
    if (lua_type(_L, -2) == LUA_TSTRING)
      fullKey += '"';
    fullKey += ']';

    switch (lua_type(_L, -1)) {
    case LUA_TTABLE: {
      int32_t numNewFields = writeTable(fullKey);
      if (numNewFields < 0)
        return -1;
      numFields += numNewFields;

      lua_pop(_L, 1);
      continue;
    }
    case LUA_TBOOLEAN: {
      val = lua_toboolean(_L, -1) ? "true" : "false";
      break;
    }
    case LUA_TSTRING:
      val += '"';
      // Fallthrough
    case LUA_TNUMBER: {
      val += lua_tostring(_L, -1);
      if (val[0] == '"')
        val += '"';
      break;
    }
    default: {
      lua_pop(_L, 1);
      continue;
    }
    }

    if (!writeField(fullKey, val))
      return -1;

    numFields++;
    lua_pop(_L, 1);
  }

  return numFields;
}

int Serializer::writeFunction(lua_State *L, const void *p, size_t sz, void *ud) {
  SDL_RWops *rw = reinterpret_cast<SDL_RWops*>(ud);
  if (!SDL_RWwrite(rw, p, sz, 1))
    return 1;
  return 0;
}

////////////////////////////////////////////////////////////
// Implementation - Public
////////////////////////////////////////////////////////////

bool Serializer::writeHeader() {
  // Write version information
  {
    const size_t len = UCHAR_MAX > strlen(DAGON_VERSION_STRING) ? strlen(DAGON_VERSION_STRING) :
                                                                  UCHAR_MAX;
    if (!SDL_WriteU8(_rw, len))
      return false;
    if (!SDL_RWwrite(_rw, DAGON_VERSION_STRING, len, 1))
      return false;
  }

  // Write preview
  {
    const std::string desc = Control::instance().currentNode()->description();
    const size_t len = UCHAR_MAX > desc.length() ? desc.length() : UCHAR_MAX;

    if (!SDL_WriteU8(_rw, len))
      return false;
    if (!SDL_RWwrite(_rw, desc.c_str(), len, 1))
      return false;
  }

  // Write current room name
  const std::string name = Control::instance().currentRoom()->name();
  if (!SDL_WriteU8(_rw, name.length()))
    return false;
  if (!SDL_RWwrite(_rw, name.c_str(), name.length(), 1))
    return false;

  return true;
}

bool Serializer::writeScriptData() {
  int64_t fieldsPtr = SDL_RWtell(_rw);
  if (fieldsPtr < 0)
    return false;
  if (!SDL_WriteBE32(_rw, 0)) // 4 placeholder bytes for the actual number of fields
    return false;

  lua_getglobal(_L, "dgPersistence");
  int32_t numFields = writeTable("dgPersistence");
  if (numFields < 0)
    return false;

  if (SDL_RWseek(_rw, fieldsPtr, RW_SEEK_SET) < 0) // Restore file pointer to 4 placeholder bytes
    return false;
  if (!SDL_WriteBE32(_rw, numFields))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  return true;
}

bool Serializer::writeRoomData() {
  Room *room = Control::instance().currentRoom();

  // Write the enable status for the spots of all nodes
  uint16_t numNodes = 0;
  if (room->hasNodes()) {
    int64_t nodesPtr = SDL_RWtell(_rw);
    if (nodesPtr < 0)
      return false;
    if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of nodes
      return false;

    room->beginIteratingNodes();
    do {
      Node *node = room->iterator();

      uint16_t numSpots = 0;
      if (node->hasSpots()) {
        int64_t spotsPtr = SDL_RWtell(_rw);
        if (spotsPtr < 0)
          return false;
        if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of spots
          return false;

        node->beginIteratingSpots();
        do {
          Spot *spot = node->currentSpot();
          if (!SDL_WriteU8(_rw, spot->isEnabled()))
            return false;
          numSpots++;
        } while (node->iterateSpots());

        if (SDL_RWseek(_rw, spotsPtr, RW_SEEK_SET) < 0)
          return false;
      }

      if (!SDL_WriteBE16(_rw, numSpots))
        return false;
      if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
        return false;

      numNodes++;
    } while (room->iterateNodes());

    if (SDL_RWseek(_rw, nodesPtr, RW_SEEK_SET) < 0)
      return false;
  }

  if (!SDL_WriteBE16(_rw, numNodes))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  // Write node number
  uint16_t nodeIdx = 0;
  if (room->hasNodes()) {
    room->beginIteratingNodes();
    do {
      if (room->iterator() == room->currentNode())
        break;

      nodeIdx++;
    } while (room->iterateNodes());
  }

  if (!SDL_WriteBE16(_rw, nodeIdx))
    return false;

  // Write camera angles
  if (!SDL_WriteBE16(_rw, CameraManager::instance().angleHorizontal()))
    return false;
  if (!SDL_WriteBE16(_rw, CameraManager::instance().angleVertical()))
    return false;

  // Write audio states
  if (!SDL_WriteBE16(_rw, room->arrayOfAudios().size()))
    return false;

  for (Audio *audio : room->arrayOfAudios()) {
    if (!SDL_WriteU8(_rw, audio->state()))
      return false;
  }

  // Write timers
  int64_t timersPtr = SDL_RWtell(_rw);
  if (timersPtr < 0)
    return false;
  if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual number of timers
    return false;

  uint16_t numTimers = 0;
  for (const auto &timer : TimerManager::instance().timers()) {
    if (timer.type != DGTimerNormal || !timer.isEnabled ||
        (!timer.isLoopable && timer.hasTriggered))
      continue;

    double timeLeft = TimerManager::instance().timeLeft(timer);
    if (timeLeft > 0) {
      const std::string triggerStr = std::to_string(timer.trigger);
      if (!SDL_WriteU8(_rw, timer.isLoopable))
        return false;
      if (!SDL_WriteU8(_rw, triggerStr.length()))
        return false;
      if (!SDL_RWwrite(_rw, triggerStr.c_str(), triggerStr.length(), 1))
        return false;

      const std::string timerTime = std::to_string(timeLeft);
      if (!SDL_WriteU8(_rw, timerTime.length()))
        return false;
      if (!SDL_RWwrite(_rw, timerTime.c_str(), timerTime.length(), 1))
        return false;

      lua_rawgeti(_L, LUA_REGISTRYINDEX, timer.luaHandler); // Push timer function to top of stack

      int64_t funcSizePtr = SDL_RWtell(_rw);
      if (funcSizePtr < 0)
        return false;
      if (!SDL_WriteBE16(_rw, 0)) // 2 placeholder bytes for the actual function size
        return false;

      int64_t beforeFuncPtr = SDL_RWtell(_rw);
      if (beforeFuncPtr < 0)
        return false;
      int errCode = lua_dump(_L, writeFunction, _rw);
      if (errCode != 0)
        return false;
      int64_t afterFuncPtr = SDL_RWtell(_rw);
      if (afterFuncPtr < 0)
        return false;

      uint16_t numBytesWritten = afterFuncPtr - beforeFuncPtr;
      if (SDL_RWseek(_rw, funcSizePtr, RW_SEEK_SET) < 0)
        return false;
      if (!SDL_WriteBE16(_rw, numBytesWritten))
        return false;

      if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
        return false;

      numTimers++;
    }
  }

  if (SDL_RWseek(_rw, timersPtr, RW_SEEK_SET) < 0)
    return false;
  if (!SDL_WriteBE16(_rw, numTimers))
    return false;
  if (SDL_RWseek(_rw, 0, RW_SEEK_END) < 0) // Restore file pointer to end
    return false;

  // Write control mode
  if (!SDL_WriteU8(_rw, Config::instance().controlMode))
    return false;

  return true;
}

}
<|endoftext|>


<commit_before>#ifndef RECURSE_REQUEST_HPP
#define RECURSE_REQUEST_HPP

#include <QTcpSocket>
#include <QHash>
#include <QUrl>
#include <QUrlQuery>

class Request
{

public:
    //!
    //! \brief data
    //! client request buffer data
    //!
    QString data;

    //!
    //! \brief socket
    //! underlying client socket
    //!
    QTcpSocket *socket;

    //!
    //! \brief body_parsed
    //! Data to be filled by body parsing middleware
    //!
    QHash<QString, QVariant> body_parsed;

    //!
    //! \brief body
    //!
    QString body;

    //!
    //! \brief method
    //! HTTP method, eg: GET
    //!
    QString method;

    //!
    //! \brief protocol
    //! Request protocol, eg: HTTP
    //!
    QString protocol;

    //!
    //! \brief secure
    //! Shorthand for protocol == "HTTPS" to check if a requet was issued via TLS
    //!
    bool secure = protocol == "HTTPS";

    //!
    //! \brief url
    //! HTTP request url, eg: /helloworld
    //!
    QUrl url;

    //!
    //! \brief query
    //!
    QUrlQuery query;

    //!
    //! \brief length
    //! HTTP request Content-Length
    //!
    qint64 length = 0;

    //!
    //! \brief ip
    //! Client ip address
    //!
    QHostAddress ip;

    //!
    //! \brief cookies
    //! HTTP cookies in key/value form
    //!
    QHash<QString, QString> cookies;

    //!
    //! \brief hostname
    //! HTTP hostname from "Host" HTTP header
    //!
    QString hostname;

    //!
    //! \brief get
    //! Return HTTP request header specified by the key
    //!
    //! \param QString case-insensitive key of the header
    //! \return QString header value
    //!
    QString get(const QString &key)
    {
        return m_header[key.toLower()];
    }

    //!
    //! \brief parse
    //! parse data from request
    //!
    //! \param QString request
    //! \return true on success, false otherwise, considered bad request
    //!
    bool parse(QString request);

private:
    //!
    //! \brief header
    //! HTTP request headers, eg: header["content-type"] = "text/plain"
    //!
    QHash<QString, QString> m_header;

    //!
    //! \brief httpRx
    //! match HTTP request line
    //!
    QRegExp httpRx = QRegExp("^(?=[A-Z]).* \\/.* HTTP\\/[0-9]\\.[0-9]\\r\\n");
};

inline bool Request::parse(QString request)
{
    // buffer all data
    this->data += request;

    // Save client ip address
    this->ip = this->socket->peerAddress();

    // if no header is present, just append all data to request.body
    if (!this->data.contains(httpRx))
    {
        this->body.append(this->data);
        return true;
    }

    QStringList data_list = this->data.split("\r\n");
    bool is_body = false;

    for (int i = 0; i < data_list.size(); ++i)
    {
        if (is_body)
        {
            this->body.append(data_list.at(i));
            this->length += this->body.size();
            continue;
        }

        QStringList entity_item = data_list.at(i).split(":");

        if (entity_item.length() < 2 && entity_item.at(0).size() < 1 && !is_body)
        {
            is_body = true;
            continue;
        }
        else if (i == 0 && entity_item.length() < 2)
        {
            QStringList first_line = entity_item.at(0).split(" ");
            this->method = first_line.at(0);
            this->url = first_line.at(1).trimmed();
            this->query.setQuery(this->url.query());
            this->protocol = first_line.at(2).trimmed();
            continue;
        }

        m_header[entity_item.at(0).toLower()] = entity_item.at(1).trimmed().toLower();
    }

    if (m_header.contains("host"))
        this->hostname = m_header["host"];

    qDebug() << "this->object populated: "
             << this->method << this->url << m_header << this->protocol << this->body
             << this->hostname << this->ip
             << this->length;

    // extract cookies
    // eg: USER_TOKEN=Yes;test=val
    if (m_header.contains("cookie"))
    {
        for (const QString &cookie : this->get("cookie").split(";"))
        {
            int split = cookie.trimmed().indexOf("=");
            if (split == -1)
                continue;

            QString key = cookie.left(split).trimmed();
            if (!key.size())
                continue;

            QString value = cookie.mid(split + 1).trimmed();

            this->cookies[key.toLower()] = value.toLower();
        }

        qDebug() << "cookies:\n" << this->cookies << "\n";
    }

    return true;
}

#endif
<commit_msg>add params placeholder for routing middlewares<commit_after>#ifndef RECURSE_REQUEST_HPP
#define RECURSE_REQUEST_HPP

#include <QTcpSocket>
#include <QHash>
#include <QUrl>
#include <QUrlQuery>

class Request
{

public:
    //!
    //! \brief data
    //! client request buffer data
    //!
    QString data;

    //!
    //! \brief socket
    //! underlying client socket
    //!
    QTcpSocket *socket;

    //!
    //! \brief body_parsed
    //! Data to be filled by body parsing middleware
    //!
    QHash<QString, QVariant> body_parsed;

    //!
    //! \brief body
    //!
    QString body;

    //!
    //! \brief method
    //! HTTP method, eg: GET
    //!
    QString method;

    //!
    //! \brief protocol
    //! Request protocol, eg: HTTP
    //!
    QString protocol;

    //!
    //! \brief secure
    //! Shorthand for protocol == "HTTPS" to check if a requet was issued via TLS
    //!
    bool secure = protocol == "HTTPS";

    //!
    //! \brief url
    //! HTTP request url, eg: /helloworld
    //!
    QUrl url;

    //!
    //! \brief query
    //! query strings
    //!
    QUrlQuery query;

    //!
    //! \brief params
    //!r
    //! request parameters that can be filled by router middlewares
    //! it's easier to provide container here (which doesn't have to be used)
    QHash<QString, QString> params;

    //!
    //! \brief length
    //! HTTP request Content-Length
    //!
    qint64 length = 0;

    //!
    //! \brief ip
    //! Client ip address
    //!
    QHostAddress ip;

    //!
    //! \brief cookies
    //! HTTP cookies in key/value form
    //!
    QHash<QString, QString> cookies;

    //!
    //! \brief hostname
    //! HTTP hostname from "Host" HTTP header
    //!
    QString hostname;

    //!
    //! \brief get
    //! Return HTTP request header specified by the key
    //!
    //! \param QString case-insensitive key of the header
    //! \return QString header value
    //!
    QString get(const QString &key)
    {
        return m_header[key.toLower()];
    }

    //!
    //! \brief parse
    //! parse data from request
    //!
    //! \param QString request
    //! \return true on success, false otherwise, considered bad request
    //!
    bool parse(QString request);

private:
    //!
    //! \brief header
    //! HTTP request headers, eg: header["content-type"] = "text/plain"
    //!
    QHash<QString, QString> m_header;

    //!
    //! \brief httpRx
    //! match HTTP request line
    //!
    QRegExp httpRx = QRegExp("^(?=[A-Z]).* \\/.* HTTP\\/[0-9]\\.[0-9]\\r\\n");
};

inline bool Request::parse(QString request)
{
    // buffer all data
    this->data += request;

    // Save client ip address
    this->ip = this->socket->peerAddress();

    // if no header is present, just append all data to request.body
    if (!this->data.contains(httpRx))
    {
        this->body.append(this->data);
        return true;
    }

    QStringList data_list = this->data.split("\r\n");
    bool is_body = false;

    for (int i = 0; i < data_list.size(); ++i)
    {
        if (is_body)
        {
            this->body.append(data_list.at(i));
            this->length += this->body.size();
            continue;
        }

        QStringList entity_item = data_list.at(i).split(":");

        if (entity_item.length() < 2 && entity_item.at(0).size() < 1 && !is_body)
        {
            is_body = true;
            continue;
        }
        else if (i == 0 && entity_item.length() < 2)
        {
            QStringList first_line = entity_item.at(0).split(" ");
            this->method = first_line.at(0);
            this->url = first_line.at(1).trimmed();
            this->query.setQuery(this->url.query());
            this->protocol = first_line.at(2).trimmed();
            continue;
        }

        m_header[entity_item.at(0).toLower()] = entity_item.at(1).trimmed().toLower();
    }

    if (m_header.contains("host"))
        this->hostname = m_header["host"];

    qDebug() << "this->object populated: "
             << this->method << this->url << m_header << this->protocol << this->body
             << this->hostname << this->ip
             << this->length;

    // extract cookies
    // eg: USER_TOKEN=Yes;test=val
    if (m_header.contains("cookie"))
    {
        for (const QString &cookie : this->get("cookie").split(";"))
        {
            int split = cookie.trimmed().indexOf("=");
            if (split == -1)
                continue;

            QString key = cookie.left(split).trimmed();
            if (!key.size())
                continue;

            QString value = cookie.mid(split + 1).trimmed();

            this->cookies[key.toLower()] = value.toLower();
        }

        qDebug() << "cookies:\n" << this->cookies << "\n";
    }

    return true;
}

#endif
<|endoftext|>


<commit_before>#include <cppunit/extensions/HelperMacros.h>
#include "BEdge.hpp"

class BEdgeTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(BEdgeTest);
  CPPUNIT_TEST(testPointGetters);
  CPPUNIT_TEST(testIsAPoint);
  CPPUNIT_TEST(testAreaPredicates);
  CPPUNIT_TEST_SUITE_END();
 private:
  BEdge* simpleEdge;
  BEdge* pointEdge;
  BEdge* pointEdge2;
  BEdge* simpleEdge2;
 public:
  void setUp() {
    std::vector<double> x;
    BVect a(1, 10, x);
    BVect b(3, 8, x);
    BVect c(0, 0, x);
    BVect d(5, 7, x);
    BVect e(4, 6, x);
    simpleEdge = new BEdge(a, b);
    pointEdge = new BEdge(c);
    pointEdge2 = new BEdge(c, c);
    simpleEdge2 = new BEdge(d, e);
  }
  void tearDown() {
    delete simpleEdge;
    delete pointEdge;
    delete pointEdge2;
    delete simpleEdge2;
  }
  void testPointGetters() {
    CPPUNIT_ASSERT(simpleEdge->leftPoint().z1() == 1);
    CPPUNIT_ASSERT(simpleEdge->leftPoint().z2() == 10);
    CPPUNIT_ASSERT(simpleEdge->rightPoint().z1() == 3);
    CPPUNIT_ASSERT(simpleEdge->rightPoint().z2() == 8);
    CPPUNIT_ASSERT(pointEdge->leftPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge->leftPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge->rightPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge->rightPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge2->leftPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge2->leftPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge2->rightPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge2->rightPoint().z2() == 0);
  }
  void testIsAPoint() {
    CPPUNIT_ASSERT(!simpleEdge->isAPoint());
    CPPUNIT_ASSERT(pointEdge->isAPoint());
    CPPUNIT_ASSERT(pointEdge2->isAPoint());
  }
  void testAreaPredicates() {
    CPPUNIT_ASSERT(simpleEdge->isInA1AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!simpleEdge->isInA2AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!simpleEdge->isInA1AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge->isInA2AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA1AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(simpleEdge2->isInA2AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA1AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA2AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA1AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA2AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA1AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!pointEdge->isInA2AreaOf(*simpleEdge2));
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(BEdgeTest);
<commit_msg>BEdge: Add test for projection computation<commit_after>#include <cppunit/extensions/HelperMacros.h>
#include "BEdge.hpp"

class BEdgeTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(BEdgeTest);
  CPPUNIT_TEST(testPointGetters);
  CPPUNIT_TEST(testIsAPoint);
  CPPUNIT_TEST(testAreaPredicates);
  CPPUNIT_TEST(testProjComputation);
  CPPUNIT_TEST_SUITE_END();
 private:
  BEdge* simpleEdge;
  BEdge* pointEdge;
  BEdge* pointEdge2;
  BEdge* simpleEdge2;
  BEdge* longEdge;
 public:
  void setUp() {
    std::vector<double> x;
    BVect a(1, 10, x);
    BVect b(3, 8, x);
    BVect c(0, 0, x);
    BVect d(5, 7, x);
    BVect e(4, 6, x);
    simpleEdge = new BEdge(a, b);
    pointEdge = new BEdge(c);
    pointEdge2 = new BEdge(c, c);
    simpleEdge2 = new BEdge(d, e);
    longEdge = new BEdge(a, e);
  }
  void tearDown() {
    delete simpleEdge;
    delete pointEdge;
    delete pointEdge2;
    delete simpleEdge2;
    delete longEdge;
  }
  void testPointGetters() {
    CPPUNIT_ASSERT(simpleEdge->leftPoint().z1() == 1);
    CPPUNIT_ASSERT(simpleEdge->leftPoint().z2() == 10);
    CPPUNIT_ASSERT(simpleEdge->rightPoint().z1() == 3);
    CPPUNIT_ASSERT(simpleEdge->rightPoint().z2() == 8);
    CPPUNIT_ASSERT(pointEdge->leftPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge->leftPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge->rightPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge->rightPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge2->leftPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge2->leftPoint().z2() == 0);
    CPPUNIT_ASSERT(pointEdge2->rightPoint().z1() == 0);
    CPPUNIT_ASSERT(pointEdge2->rightPoint().z2() == 0);
  }
  void testIsAPoint() {
    CPPUNIT_ASSERT(!simpleEdge->isAPoint());
    CPPUNIT_ASSERT(pointEdge->isAPoint());
    CPPUNIT_ASSERT(pointEdge2->isAPoint());
  }
  void testAreaPredicates() {
    CPPUNIT_ASSERT(simpleEdge->isInA1AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!simpleEdge->isInA2AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!simpleEdge->isInA1AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge->isInA2AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA1AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(simpleEdge2->isInA2AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA1AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!simpleEdge2->isInA2AreaOf(*pointEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA1AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA2AreaOf(*simpleEdge));
    CPPUNIT_ASSERT(!pointEdge->isInA1AreaOf(*simpleEdge2));
    CPPUNIT_ASSERT(!pointEdge->isInA2AreaOf(*simpleEdge2));
  }
  void testProjComputation() {
    std::vector<double> x;
    BVect zero(0, 0, x);
    BVect a(0, 9, x);
    BVect b(3, 5, x);
    BVect c(2, 8, x);
    std::pair<double, double> pz = longEdge->computeLambdasWithPoint(zero);
    std::pair<double, double> pa = longEdge->computeLambdasWithPoint(a);
    std::pair<double, double> pb = longEdge->computeLambdasWithPoint(b);
    std::pair<double, double> pc = longEdge->computeLambdasWithPoint(c);
    CPPUNIT_ASSERT(pz.first == 0);
    CPPUNIT_ASSERT(pz.second == 1);
    CPPUNIT_ASSERT(pa.first == 0);
    CPPUNIT_ASSERT(pa.second == 0.25);
    CPPUNIT_ASSERT(pb.first == 2.0/3.0);
    CPPUNIT_ASSERT(pb.second == 1);
    CPPUNIT_ASSERT(pc.first == 1.0/3.0);
    CPPUNIT_ASSERT(pc.second == 0.5);
  }
};

CPPUNIT_TEST_SUITE_REGISTRATION(BEdgeTest);
<|endoftext|>


<commit_before>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct ThingThingBall {
	NVGcolor color;
};

struct ThingThing : Module {
	enum ParamIds {
		BALL_RAD_PARAM,
		ZOOM_MULT_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		BALL_RAD_INPUT,
		ZOOM_MULT_INPUT,
		ANG_INPUT,
		NUM_INPUTS = ANG_INPUT + 5
	};
	enum OutputIds {
		NUM_OUTPUTS
	};
	enum LightIds {
		NUM_LIGHTS
	};

	ThingThingBall *balls = new ThingThingBall[5];
	float atten[5] = {1, 1, 1, 1, 1};
	// float atten[5] = {0.0, 0.25, 0.5, 0.75, 1};

	ThingThing() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
		balls[0].color = nvgRGB(255, 255, 255);//white
		balls[1].color = nvgRGB(255, 151, 9);//orange
		balls[2].color = nvgRGB(255, 243, 9);//yellow
		balls[3].color = nvgRGB(144, 26, 252);//purple
		balls[4].color = nvgRGB(25, 150, 252);//blue
	}
	~ThingThing() {
		delete [] balls;
	}

	void step() override {};
	void reset() override {}

	json_t *toJson() override {
		json_t *rootJ = json_object();
		return rootJ;
	}

	void fromJson(json_t *rootJ) override {}
};

struct ThingThingDisplay : Widget {
	ThingThing *module;
	ThingThingDisplay(){}

	void draw(NVGcontext *vg) override {
		//background
		nvgFillColor(vg, nvgRGB(20, 30, 33));
		nvgBeginPath(vg);
		nvgRect(vg, 0, 0, box.size.x, box.size.y);
		nvgFill(vg);

		float ballRadius = module->params[ThingThing::BALL_RAD_PARAM].value;
		if(module->inputs[ThingThing::BALL_RAD_INPUT].active){
			ballRadius += rescalef(module->inputs[ThingThing::BALL_RAD_INPUT].value, -5.0, 5.0, 0.0, 30.0);
		}

		float zoom = module->params[ThingThing::ZOOM_MULT_PARAM].value;
		if(module->inputs[ThingThing::ZOOM_MULT_INPUT].active){
			ballRadius += rescalef(module->inputs[ThingThing::ZOOM_MULT_INPUT].value, -5.0, 5.0, 1.0, 50.0);
		}

		/////////////////////// LINES ///////////////////////
		nvgSave(vg);
		nvgTranslate(vg, box.size.x * 0.5, box.size.y * 0.5);
		for(int i=0; i<5; i++){
			float angle = module->inputs[ThingThing::ANG_INPUT+i].value * module->atten[i];
			float x = i==0 ? 0 : sinf(rescalef(angle, -5, 5, -2*M_PI, 2*M_PI)) * zoom;
			float y = i==0 ? 0 : cosf(rescalef(angle, -5, 5, -2*M_PI, 2*M_PI)) * zoom;
			nvgTranslate(vg, x, y);
			nvgStrokeColor(vg, nvgRGB(255, 255, 255));
			if(i>0){
				nvgStrokeWidth(vg, 1);
				nvgBeginPath(vg);
				nvgMoveTo(vg, 0, 0);
				nvgLineTo(vg, -x, -y);
				nvgStroke(vg);
			}
		}
		nvgRestore(vg);

		/////////////////////// BALLS ///////////////////////
		nvgSave(vg);
		nvgTranslate(vg, box.size.x * 0.5, box.size.y * 0.5);
		for(int i=0; i<5; i++){
			float angle = module->inputs[ThingThing::ANG_INPUT+i].value * module->atten[i];
			float x = i==0 ? 0 : sinf(rescalef(angle, -5, 5, -2*M_PI, 2*M_PI)) * zoom;
			float y = i==0 ? 0 : cosf(rescalef(angle, -5, 5, -2*M_PI, 2*M_PI)) * zoom;
			nvgTranslate(vg, x, y);
			nvgStrokeColor(vg, module->balls[i].color);
			nvgFillColor(vg, module->balls[i].color);
			nvgStrokeWidth(vg, 2);
			nvgBeginPath(vg);
			nvgCircle(vg, 0, 0, ballRadius);
			nvgFill(vg);
			nvgStroke(vg);
		}
		nvgRestore(vg);
	}
};

ThingThingWidget::ThingThingWidget() {
	ThingThing *module = new ThingThing();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*20, RACK_GRID_HEIGHT);

	SVGPanel *panel = new SVGPanel();
	panel->box.size = box.size;
	panel->setBackground(SVG::load(assetPlugin(plugin, "res/ThingThing.svg")));
	addChild(panel);

	ThingThingDisplay *display = new ThingThingDisplay();
	display->module = module;
	display->box.pos = Vec(0, 2);
	display->box.size = Vec(box.size.x, RACK_GRID_HEIGHT);
	addChild(display);

	addChild(createScrew<Screw_J>(Vec(265, 365)));
	addChild(createScrew<Screw_W>(Vec(280, 365)));

	for(int i=0; i<4; i++){
		addInput(createInput<TinyPJ301MPort>(Vec(5+(20*i), 360), module, ThingThing::ANG_INPUT+i+1));
	}

	addInput(createInput<TinyPJ301MPort>(Vec(140, 360), module, ThingThing::BALL_RAD_INPUT));
	addParam(createParam<JwTinyKnob>(Vec(155, 360), module, ThingThing::BALL_RAD_PARAM, 0.0, 30.0, 10.0));

	addInput(createInput<TinyPJ301MPort>(Vec(190, 360), module, ThingThing::ZOOM_MULT_INPUT));
	addParam(createParam<JwTinyKnob>(Vec(205, 360), module, ThingThing::ZOOM_MULT_PARAM, 1.0, 200.0, 20.0));
}
<commit_msg>Fixes the angle representation to match what Caudal outputs<commit_after>#include <string.h>
#include "JWModules.hpp"
#include "dsp/digital.hpp"

struct ThingThingBall {
	NVGcolor color;
};

struct ThingThing : Module {
	enum ParamIds {
		BALL_RAD_PARAM,
		ZOOM_MULT_PARAM,
		NUM_PARAMS
	};
	enum InputIds {
		BALL_RAD_INPUT,
		ZOOM_MULT_INPUT,
		ANG_INPUT,
		NUM_INPUTS = ANG_INPUT + 5
	};
	enum OutputIds {
		NUM_OUTPUTS
	};
	enum LightIds {
		NUM_LIGHTS
	};

	ThingThingBall *balls = new ThingThingBall[5];
	float atten[5] = {1, 1, 1, 1, 1};
	// float atten[5] = {0.0, 0.25, 0.5, 0.75, 1};

	ThingThing() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
		balls[0].color = nvgRGB(255, 255, 255);//white
		balls[1].color = nvgRGB(255, 151, 9);//orange
		balls[2].color = nvgRGB(255, 243, 9);//yellow
		balls[3].color = nvgRGB(144, 26, 252);//purple
		balls[4].color = nvgRGB(25, 150, 252);//blue
	}
	~ThingThing() {
		delete [] balls;
	}

	void step() override {};
	void reset() override {}

	json_t *toJson() override {
		json_t *rootJ = json_object();
		return rootJ;
	}

	void fromJson(json_t *rootJ) override {}
};

struct ThingThingDisplay : Widget {
	ThingThing *module;
	ThingThingDisplay(){}

	void draw(NVGcontext *vg) override {
		//background
		nvgFillColor(vg, nvgRGB(20, 30, 33));
		nvgBeginPath(vg);
		nvgRect(vg, 0, 0, box.size.x, box.size.y);
		nvgFill(vg);

		float ballRadius = module->params[ThingThing::BALL_RAD_PARAM].value;
		if(module->inputs[ThingThing::BALL_RAD_INPUT].active){
			ballRadius += rescalef(module->inputs[ThingThing::BALL_RAD_INPUT].value, -5.0, 5.0, 0.0, 30.0);
		}

		float zoom = module->params[ThingThing::ZOOM_MULT_PARAM].value;
		if(module->inputs[ThingThing::ZOOM_MULT_INPUT].active){
			ballRadius += rescalef(module->inputs[ThingThing::ZOOM_MULT_INPUT].value, -5.0, 5.0, 1.0, 50.0);
		}

      float x[5];
      float y[5];
      float angle[5];

      for(int i=0; i<5; i++){
         angle[i] = i==0 ? 0 : (module->inputs[ThingThing::ANG_INPUT+i].value + angle[i-1]) * module->atten[i];
			x[i] = i==0 ? 0 : sinf(rescalef(angle[i], -5, 5, -2*M_PI + M_PI/2.0f, 2*M_PI + M_PI/2.0f)) * zoom;
			y[i] = i==0 ? 0 : cosf(rescalef(angle[i], -5, 5, -2*M_PI + M_PI/2.0f, 2*M_PI + M_PI/2.0f)) * zoom;
      }

		/////////////////////// LINES ///////////////////////
		nvgSave(vg);
		nvgTranslate(vg, box.size.x * 0.5, box.size.y * 0.5);
		for(int i=0; i<5; i++){
			nvgTranslate(vg, x[i], y[i]);
			nvgStrokeColor(vg, nvgRGB(255, 255, 255));
			if(i>0){
				nvgStrokeWidth(vg, 1);
				nvgBeginPath(vg);
				nvgMoveTo(vg, 0, 0);
				nvgLineTo(vg, -x[i], -y[i]);
				nvgStroke(vg);
			}
		}
		nvgRestore(vg);

		/////////////////////// BALLS ///////////////////////
		nvgSave(vg);
		nvgTranslate(vg, box.size.x * 0.5, box.size.y * 0.5);
		for(int i=0; i<5; i++){
			nvgTranslate(vg, x[i], y[i]);
			nvgStrokeColor(vg, module->balls[i].color);
			nvgFillColor(vg, module->balls[i].color);
			nvgStrokeWidth(vg, 2);
			nvgBeginPath(vg);
			nvgCircle(vg, 0, 0, ballRadius);
			nvgFill(vg);
			nvgStroke(vg);
		}
		nvgRestore(vg);
	}
};

ThingThingWidget::ThingThingWidget() {
	ThingThing *module = new ThingThing();
	setModule(module);
	box.size = Vec(RACK_GRID_WIDTH*20, RACK_GRID_HEIGHT);

	SVGPanel *panel = new SVGPanel();
	panel->box.size = box.size;
	panel->setBackground(SVG::load(assetPlugin(plugin, "res/ThingThing.svg")));
	addChild(panel);

	ThingThingDisplay *display = new ThingThingDisplay();
	display->module = module;
	display->box.pos = Vec(0, 2);
	display->box.size = Vec(box.size.x, RACK_GRID_HEIGHT);
	addChild(display);

	addChild(createScrew<Screw_J>(Vec(265, 365)));
	addChild(createScrew<Screw_W>(Vec(280, 365)));

	for(int i=0; i<4; i++){
		addInput(createInput<TinyPJ301MPort>(Vec(5+(20*i), 360), module, ThingThing::ANG_INPUT+i+1));
	}

	addInput(createInput<TinyPJ301MPort>(Vec(140, 360), module, ThingThing::BALL_RAD_INPUT));
	addParam(createParam<JwTinyKnob>(Vec(155, 360), module, ThingThing::BALL_RAD_PARAM, 0.0, 30.0, 10.0));

	addInput(createInput<TinyPJ301MPort>(Vec(190, 360), module, ThingThing::ZOOM_MULT_INPUT));
	addParam(createParam<JwTinyKnob>(Vec(205, 360), module, ThingThing::ZOOM_MULT_PARAM, 1.0, 200.0, 20.0));
}
<|endoftext|>


<commit_before>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "infill.h"
#include "LayerPlan.h"
#include "sliceDataStorage.h"
#include "TopSurface.h"

namespace cura
{

TopSurface::TopSurface()
{
    //Do nothing. Areas stays empty.
}

void TopSurface::setAreasFromMeshAndLayerNumber(SliceMeshStorage& mesh, size_t layer_number)
{
    //The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first.
    Polygons mesh_above;
    if (layer_number < mesh.layers.size() - 1)
    {
        mesh_above = mesh.layers[layer_number + 1].getOutlines();
    } //If this is the top-most layer, mesh_above stays empty.

    areas = mesh.layers[layer_number].getOutlines().difference(mesh_above);
}

bool TopSurface::ironing(const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer) const
{
    if (areas.empty())
    {
        return false; //Nothing to do.
    }
    //Generate the lines to cover the surface.
    const EFillMethod pattern = mesh.settings.get<EFillMethod>("ironing_pattern");
    const bool zig_zaggify_infill = pattern == EFillMethod::ZIG_ZAG;
    constexpr bool connect_polygons = false; // midway connections can make the surface less smooth
    const coord_t line_spacing = mesh.settings.get<coord_t>("ironing_line_spacing");
    const coord_t outline_offset = -mesh.settings.get<coord_t>("ironing_inset");
    const coord_t line_width = line_config.getLineWidth();
    const std::vector<AngleDegrees>& top_most_skin_angles = (mesh.settings.get<size_t>("roofing_layer_count") > 0) ? mesh.roofing_angles : mesh.skin_angles;
    assert(top_most_skin_angles.size() > 0);
    const AngleDegrees direction = top_most_skin_angles[layer.getLayerNr() % top_most_skin_angles.size()] + AngleDegrees(90.0); //Always perpendicular to the skin lines.
    constexpr coord_t infill_overlap = 0;
    constexpr int infill_multiplier = 1;
    constexpr coord_t shift = 0;
    Infill infill_generator(pattern, zig_zaggify_infill, connect_polygons, areas, outline_offset, line_width, line_spacing, infill_overlap, infill_multiplier, direction, layer.z - 10, shift);
    Polygons ironing_polygons;
    Polygons ironing_lines;
    infill_generator.generate(ironing_polygons, ironing_lines);

    layer.mode_skip_agressive_merge = true;

    if (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG)
    {
        //Move to a corner of the area that is perpendicular to the ironing lines, to reduce the number of seams.
        const AABB bounding_box(areas);
        PointMatrix rotate(-direction + 90);
        const Point center = bounding_box.getMiddle();
        const Point far_away = rotate.apply(Point(0, vSize(bounding_box.max - center) * 100)); //Some direction very far away in the direction perpendicular to the ironing lines, relative to the centre.
        //Two options to start, both perpendicular to the ironing lines. Which is closer?
        const Point front_side = PolygonUtils::findNearestVert(center + far_away, areas).p();
        const Point back_side = PolygonUtils::findNearestVert(center - far_away, areas).p();
        if (vSize2(layer.getLastPlannedPositionOrStartingPosition() - front_side) < vSize2(layer.getLastPlannedPositionOrStartingPosition() - back_side))
        {
            layer.addTravel(front_side);
        }
        else
        {
            layer.addTravel(back_side);
        }
    }

    //Add the lines as travel moves to the layer plan.
    bool added = false;
    if (!ironing_polygons.empty())
    {
        constexpr bool force_comb_retract = false;
        layer.addTravel(ironing_polygons[0][0], force_comb_retract);
        layer.addPolygonsByOptimizer(ironing_polygons, line_config, nullptr, ZSeamConfig());
        added = true;
    }
    if (!ironing_lines.empty())
    {
        layer.addLinesByOptimizer(ironing_lines, line_config, SpaceFillType::PolyLines);
        added = true;
    }

    layer.mode_skip_agressive_merge = false;
    return added;
}

}
<commit_msg>Avoid unwanted travel move when ironing is enabled but no lines/polygons are generated.<commit_after>//Copyright (c) 2017 Ultimaker B.V.
//CuraEngine is released under the terms of the AGPLv3 or higher.

#include "infill.h"
#include "LayerPlan.h"
#include "sliceDataStorage.h"
#include "TopSurface.h"

namespace cura
{

TopSurface::TopSurface()
{
    //Do nothing. Areas stays empty.
}

void TopSurface::setAreasFromMeshAndLayerNumber(SliceMeshStorage& mesh, size_t layer_number)
{
    //The top surface is all parts of the mesh where there's no mesh above it, so find the layer above it first.
    Polygons mesh_above;
    if (layer_number < mesh.layers.size() - 1)
    {
        mesh_above = mesh.layers[layer_number + 1].getOutlines();
    } //If this is the top-most layer, mesh_above stays empty.

    areas = mesh.layers[layer_number].getOutlines().difference(mesh_above);
}

bool TopSurface::ironing(const SliceMeshStorage& mesh, const GCodePathConfig& line_config, LayerPlan& layer) const
{
    if (areas.empty())
    {
        return false; //Nothing to do.
    }
    //Generate the lines to cover the surface.
    const EFillMethod pattern = mesh.settings.get<EFillMethod>("ironing_pattern");
    const bool zig_zaggify_infill = pattern == EFillMethod::ZIG_ZAG;
    constexpr bool connect_polygons = false; // midway connections can make the surface less smooth
    const coord_t line_spacing = mesh.settings.get<coord_t>("ironing_line_spacing");
    const coord_t outline_offset = -mesh.settings.get<coord_t>("ironing_inset");
    const coord_t line_width = line_config.getLineWidth();
    const std::vector<AngleDegrees>& top_most_skin_angles = (mesh.settings.get<size_t>("roofing_layer_count") > 0) ? mesh.roofing_angles : mesh.skin_angles;
    assert(top_most_skin_angles.size() > 0);
    const AngleDegrees direction = top_most_skin_angles[layer.getLayerNr() % top_most_skin_angles.size()] + AngleDegrees(90.0); //Always perpendicular to the skin lines.
    constexpr coord_t infill_overlap = 0;
    constexpr int infill_multiplier = 1;
    constexpr coord_t shift = 0;
    Infill infill_generator(pattern, zig_zaggify_infill, connect_polygons, areas, outline_offset, line_width, line_spacing, infill_overlap, infill_multiplier, direction, layer.z - 10, shift);
    Polygons ironing_polygons;
    Polygons ironing_lines;
    infill_generator.generate(ironing_polygons, ironing_lines);

    if (ironing_polygons.empty() && ironing_lines.empty())
    {
        return false; //Nothing to do.
    }

    layer.mode_skip_agressive_merge = true;

    if (pattern == EFillMethod::LINES || pattern == EFillMethod::ZIG_ZAG)
    {
        //Move to a corner of the area that is perpendicular to the ironing lines, to reduce the number of seams.
        const AABB bounding_box(areas);
        PointMatrix rotate(-direction + 90);
        const Point center = bounding_box.getMiddle();
        const Point far_away = rotate.apply(Point(0, vSize(bounding_box.max - center) * 100)); //Some direction very far away in the direction perpendicular to the ironing lines, relative to the centre.
        //Two options to start, both perpendicular to the ironing lines. Which is closer?
        const Point front_side = PolygonUtils::findNearestVert(center + far_away, areas).p();
        const Point back_side = PolygonUtils::findNearestVert(center - far_away, areas).p();
        if (vSize2(layer.getLastPlannedPositionOrStartingPosition() - front_side) < vSize2(layer.getLastPlannedPositionOrStartingPosition() - back_side))
        {
            layer.addTravel(front_side);
        }
        else
        {
            layer.addTravel(back_side);
        }
    }

    //Add the lines as travel moves to the layer plan.
    bool added = false;
    if (!ironing_polygons.empty())
    {
        constexpr bool force_comb_retract = false;
        layer.addTravel(ironing_polygons[0][0], force_comb_retract);
        layer.addPolygonsByOptimizer(ironing_polygons, line_config, nullptr, ZSeamConfig());
        added = true;
    }
    if (!ironing_lines.empty())
    {
        layer.addLinesByOptimizer(ironing_lines, line_config, SpaceFillType::PolyLines);
        added = true;
    }

    layer.mode_skip_agressive_merge = false;
    return added;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008-2009
 *
 * School of Computing, University of Utah,
 * Salt Lake City, UT 84112, USA
 *
 * and the Gauss Group
 * http://www.cs.utah.edu/formal_verification
 *
 * See LICENSE for licensing information
 */

/*
 * ISP: MPI Dynamic Verification Tool
 *
 * File:        Transition.hpp
 * Description: Implements handling of a single transition in an interleaving
 * Contact:     isp-dev@cs.utah.edu
 */

#ifndef _TRANSITION_HPP
#define _TRANSITION_HPP

#include <vector>
#include <cassert>
#include <memory>

#include "Envelope.hpp"

using std::vector;
using std::unique_ptr;
using std::weak_ptr;
using std::shared_ptr;

struct Transition {
    const int index;

    const int pid;

    bool types_match = true;

    Transition(int pid, int index, unique_ptr<Envelope> envelope) :
        pid(pid), index(index), envelope(std::move(envelope))
    {}

    inline Envelope& getEnvelope () const {return *envelope;}

    bool addIntraCB(shared_ptr<Transition> t) {
        if(isNew(t)) {
            intra_cb.push_back(t);
            return true;
        }
        return false;
    }

    bool addInterCB(shared_ptr<Transition> t) {
        /* XXX: Tiago: why is this needed?
        if (t.pid == -1 && t.index == -1) {
            inter_cb.push_back(t);
            return false;
        }*/
        if(isNew(t)) {
            inter_cb.push_back(t);
            return true;
        }
        return false;
    }
    inline void setCurrentMatching(shared_ptr<Transition> c) { curr_matching = c; }

    inline const shared_ptr<Transition> getCurrentMatching() const {
        return curr_matching.lock();
    }

    inline const vector<shared_ptr<Transition> > getAncestors() const { return share(ancestors); }

    inline void addAncestor(shared_ptr<Transition> ancestor) { ancestors.push_back(ancestor); }

    inline vector<shared_ptr<Transition> > getInterCB() const { return share(inter_cb); }

    inline vector<shared_ptr<Transition> > getIntraCB() const { return share(intra_cb); }

    inline bool canSend(Transition & recv) const {
        auto & recv_env = *recv.envelope;
        return pid == recv_env.src && envelope->canSend(recv_env);
    }

    inline void setMatched() { is_matched = true; }

    inline bool isMatched() const { return is_matched; }

    inline bool isIssued() const {
        return is_issued;
    }

    inline void setIssued() {
        is_issued = true;
    }

private:
    vector<weak_ptr<Transition> > ancestors;
    weak_ptr<Transition> curr_matching;
    unique_ptr<Envelope> envelope;
    vector<weak_ptr<Transition> > inter_cb;
    vector<weak_ptr<Transition> > intra_cb;
    bool is_matched = false;
    bool is_issued = false;
    /**
     * Tests if an element is in the vector.
     */
    inline static bool contains(vector<weak_ptr<Transition> > vec, const Transition & elem) {
        for (auto ref : vec) {
            if (auto other = ref.lock()) {
                if (elem.handleEquals(*other)) {
                    return true;
                }
            }
        }
        return false;
    }

    static vector<shared_ptr<Transition> > share(const vector<weak_ptr<Transition> > & src) {
        vector<shared_ptr<Transition> > temp;
        temp.resize(src.size());
        for (auto weak : src) {
            if (auto val = weak.lock()) {
                temp.push_back(val);
            }
        }
        return temp;
    }

    inline bool handleEquals(const Transition & other) const {
        return pid == other.pid && index == other.index;
    }

    /**
     * Tests whether the transition contains the given cb.
     */
    inline bool isNew(shared_ptr<Transition> other) const {
        return !contains(intra_cb, *other)  && !contains(inter_cb, *other);
    }

};

#endif
<commit_msg>Added implementation of matchedSends.<commit_after>/*
 * Copyright (c) 2008-2009
 *
 * School of Computing, University of Utah,
 * Salt Lake City, UT 84112, USA
 *
 * and the Gauss Group
 * http://www.cs.utah.edu/formal_verification
 *
 * See LICENSE for licensing information
 */

/*
 * ISP: MPI Dynamic Verification Tool
 *
 * File:        Transition.hpp
 * Description: Implements handling of a single transition in an interleaving
 * Contact:     isp-dev@cs.utah.edu
 */

#ifndef _TRANSITION_HPP
#define _TRANSITION_HPP

#include <vector>
#include <cassert>
#include <memory>

#include "Envelope.hpp"

using std::vector;
using std::unique_ptr;
using std::weak_ptr;
using std::shared_ptr;

struct Transition {
    const int index;

    const int pid;

    bool types_match = true;

    Transition(int pid, int index, unique_ptr<Envelope> envelope) :
        pid(pid), index(index), envelope(std::move(envelope))
    {}

    inline Envelope& getEnvelope () const {return *envelope;}

    bool addIntraCB(shared_ptr<Transition> t) {
        if(isNew(t)) {
            intra_cb.push_back(t);
            return true;
        }
        return false;
    }

    bool addInterCB(shared_ptr<Transition> t) {
        /* XXX: Tiago: why is this needed?
        if (t.pid == -1 && t.index == -1) {
            inter_cb.push_back(t);
            return false;
        }*/
        if(isNew(t)) {
            inter_cb.push_back(t);
            return true;
        }
        return false;
    }
    inline void setCurrentMatching(shared_ptr<Transition> c) { curr_matching = c; }

    inline const shared_ptr<Transition> getCurrentMatching() const {
        return curr_matching.lock();
    }

    inline const vector<shared_ptr<Transition> > getAncestors() const { return share(ancestors); }

    inline void addAncestor(shared_ptr<Transition> ancestor) { ancestors.push_back(ancestor); }

    inline vector<shared_ptr<Transition> > getInterCB() const { return share(inter_cb); }

    inline vector<shared_ptr<Transition> > getIntraCB() const { return share(intra_cb); }

    inline bool canSend(Transition & recv) const {
        auto & recv_env = *recv.envelope;
        return pid == recv_env.src && envelope->canSend(recv_env);
    }

    inline void setMatched() { is_matched = true; }

    inline bool isMatched() const { return is_matched; }

    inline bool isIssued() const {
        return is_issued;
    }

    inline void setIssued() {
        is_issued = true;
    }

    void addMatchedSends(shared_ptr<Transition> t) {
        matched_sends.push_back(t);
    }

    bool inMatchedSends(const Transition &t) {
        return contains(matched_sends, t);
    }

private:
    vector<weak_ptr<Transition> > ancestors;
    weak_ptr<Transition> curr_matching;
    unique_ptr<Envelope> envelope;
    vector<weak_ptr<Transition> > inter_cb;
    vector<weak_ptr<Transition> > intra_cb;
    vector<weak_ptr<Transition> > matched_sends;
    bool is_matched = false;
    bool is_issued = false;

    /**
     * Tests if an element is in the vector.
     */
    inline static bool contains(vector<weak_ptr<Transition> > vec, const Transition & elem) {
        for (auto ref : vec) {
            if (auto other = ref.lock()) {
                if (elem.handleEquals(*other)) {
                    return true;
                }
            }
        }
        return false;
    }

    static vector<shared_ptr<Transition> > share(const vector<weak_ptr<Transition> > & src) {
        vector<shared_ptr<Transition> > temp;
        temp.resize(src.size());
        for (auto weak : src) {
            if (auto val = weak.lock()) {
                temp.push_back(val);
            }
        }
        return temp;
    }

    inline bool handleEquals(const Transition & other) const {
        return pid == other.pid && index == other.index;
    }

    /**
     * Tests whether the transition contains the given cb.
     */
    inline bool isNew(shared_ptr<Transition> other) const {
        return !contains(intra_cb, *other)  && !contains(inter_cb, *other);
    }

};

#endif
<|endoftext|>


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

#include <vector>
#include <iostream>
#include <exception>
#include <algorithm>
#include <iomanip>
#include <random>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Triad.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * A, cl::Buffer * A_d, std::vector< inputDataType > * B, cl::Buffer * B_d, cl::Buffer * C_d);

int main(int argc, char * argv[]) {
  bool reInit = true;
  unsigned int nrIterations = 0;
  unsigned int samplingFactor = 100;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int vectorSize = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int maxVector = 0;
  unsigned int inputSize = 0;
  // Best configuration and total time
  TuneBench::TriadConf bestConfiguration;
  double bestMetric = 0.0;
  isa::utils::Timer totalTimer;
  // Random number generation
  std::random_device randomDevice;
  std::default_random_engine randomEngine(randomDevice());
  std::uniform_int_distribution<unsigned int> uniformDistribution(0, factor);

  try {
    isa::utils::ArgumentList args(argc, argv);

    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    if ( args.getSwitch("-sampling") ) {
      samplingFactor = args.getSwitchArgument< unsigned int >("-factor");
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    vectorSize = args.getSwitchArgument< unsigned int >("-vector");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxVector = args.getSwitchArgument< unsigned int >("-max_vector");
    inputSize = args.getSwitchArgument< unsigned int >("-input_size");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " -opencl_platform ... -opencl_device ... [-sampling -factor ...] -iterations ... -vector ... -max_threads ... -max_items ... -max_vector ... -input_size ... " << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate host memory
  std::vector< inputDataType > A(inputSize), B(inputSize), C(inputSize), C_control(inputSize);
  cl::Buffer A_d, B_d, C_d;

  std::generate(A.begin(), A.end(), [&uniformDistribution, &randomEngine](){ return uniformDistribution(randomEngine); });
  std::generate(B.begin(), B.end(), [&uniformDistribution, &randomEngine](){ return uniformDistribution(randomEngine); });
  std::fill(C.begin(), C.end(), factor);
  std::fill(C_control.begin(), C_control.end(), factor);

  // Run the control
  TuneBench::triad(A, B, C_control, static_cast< inputDataType >(factor));

  // Generate tuning configurations
  std::vector<TuneBench::TriadConf> configurations;
  for ( unsigned int threads = vectorSize; threads <= maxThreads; threads += vectorSize ) {
    for ( unsigned int items = 1; items <= maxItems; items++ ) {
      for ( unsigned int vector = 1; vector <= maxVector; vector++ ) {
        if ( inputSize % (threads * items * vector) != 0 ) {
          continue;
        } else if ( items * vector > maxItems ) {
          break;
        }
        TuneBench::TriadConf configuration;
        configuration.setNrThreadsD0(threads);
        configuration.setNrItemsD0(items);
        configuration.setVector(vector);
        configurations.push_back(configuration);
      }
    }
  }
  if ( samplingFactor < 100 ) {
    unsigned int newSize = static_cast<unsigned int>((configurations.size() * samplingFactor) / 100.0);
    std::shuffle(configurations.begin(), configurations.end(), randomEngine);
    configurations.resize(newSize);
  }

  std::cout << std::fixed << std::endl;
  std::cout << "# inputSize *configuration* GB/s time stdDeviation COV" << std::endl << std::endl;

  totalTimer.start();
  for ( auto configuration = configurations.begin(); configuration != configurations.end(); ++configuration ) {
    // Generate kernel
    double gbytes = isa::utils::giga(static_cast< uint64_t >(inputSize) * sizeof(inputDataType) * 3.0);
    cl::Event clEvent;
    cl::Kernel * kernel;
    isa::utils::Timer timer;
    std::string * code = TuneBench::getTriadOpenCL(*configuration, inputDataName, factor);

    if ( reInit ) {
      delete clQueues;
      clQueues = new std::vector< std::vector< cl::CommandQueue > >();
      isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
      try {
        initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), &A, &A_d, &B, &B_d, &C_d);
      } catch ( cl::Error & err ) {
        return -1;
      }
      reInit = false;
    }
    try {
      kernel = isa::OpenCL::compile("triad", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
    } catch ( isa::OpenCL::OpenCLError & err ) {
      std::cerr << err.what() << std::endl;
      delete code;
      break;
    }
    delete code;

    cl::NDRange global(inputSize / ((*configuration).getNrItemsD0() * (*configuration).getVector()));
    cl::NDRange local((*configuration).getNrThreadsD0());

    kernel->setArg(0, A_d);
    kernel->setArg(1, B_d);
    kernel->setArg(2, C_d);

    try {
      // Warm-up run
      clQueues->at(clDeviceID)[0].finish();
      clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
      clEvent.wait();
      // Tuning runs
      for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
        timer.start();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
        clEvent.wait();
        timer.stop();
      }
      clQueues->at(clDeviceID)[0].enqueueReadBuffer(C_d, CL_TRUE, 0, C.size() * sizeof(inputDataType), reinterpret_cast< void * >(C.data()), 0, &clEvent);
      clEvent.wait();
    } catch ( cl::Error & err ) {
      std::cerr << "OpenCL kernel execution error (";
      std::cerr << (*configuration).print();
      std::cerr << "), (";
      std::cerr << isa::utils::toString(inputSize / (*configuration).getNrItemsD0()) << "): ";
      std::cerr << isa::utils::toString(err.err()) << std::endl;
      delete kernel;
      if ( err.err() == -4 || err.err() == -61 ) {
        return -1;
      }
      reInit = true;
      break;
    }
    delete kernel;

    bool error = false;
    for ( unsigned int item = 0; item < C.size(); item++ ) {
      if ( !isa::utils::same(C[item], C_control[item]) ) {
        std::cerr << "Output error (" << (*configuration).print() << ")." << std::endl;
        error = true;
        break;
      }
    }
    if ( error ) {
      continue;
    }

    if ( (gbytes / timer.getAverageTime()) > bestMetric ) {
      bestMetric = gbytes / timer.getAverageTime();
      bestConfiguration = *configuration;
    }
    std::cout << inputSize << " ";
    std::cout << (*configuration).print() << " ";
    std::cout << std::setprecision(3);
    std::cout << gbytes / timer.getAverageTime() << " ";
    std::cout << std::setprecision(6);
    std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
  }
  totalTimer.stop();

  std::cout << std::endl;
  std::cout << "# ";
  std::cout << bestConfiguration.print() << " ";
  std::cout << std::setprecision(3);
  std::cout << bestMetric << " ";
  std::cout << std::setprecision(6);
  std::cout << totalTimer.getAverageTime() << std::endl;
  std::cout << std::endl;

  return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * A, cl::Buffer * A_d, std::vector< inputDataType > * B, cl::Buffer * B_d, cl::Buffer * C_d) {
  try {
    *A_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, A->size() * sizeof(inputDataType), 0, 0);
    *B_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, B->size() * sizeof(inputDataType), 0, 0);
    *C_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, A->size() * sizeof(inputDataType), 0, 0);
    clQueue->enqueueWriteBuffer(*A_d, CL_FALSE, 0, A->size() * sizeof(inputDataType), reinterpret_cast< void * >(A->data()));
    clQueue->enqueueWriteBuffer(*B_d, CL_FALSE, 0, B->size() * sizeof(inputDataType), reinterpret_cast< void * >(B->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error (memory initialization): " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<commit_msg>Updated the triad tuner to avoid reinitialize OpenCL with trivial errors.<commit_after>// Copyright 2016 Alessio Sclocco <a.sclocco@vu.nl>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <vector>
#include <iostream>
#include <exception>
#include <algorithm>
#include <iomanip>
#include <random>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <Triad.hpp>
#include <utils.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * A, cl::Buffer * A_d, std::vector< inputDataType > * B, cl::Buffer * B_d, cl::Buffer * C_d);

int main(int argc, char * argv[]) {
  bool reInit = true;
  unsigned int nrIterations = 0;
  unsigned int samplingFactor = 100;
  unsigned int clPlatformID = 0;
  unsigned int clDeviceID = 0;
  unsigned int vectorSize = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int maxVector = 0;
  unsigned int inputSize = 0;
  // Best configuration and total time
  TuneBench::TriadConf bestConfiguration;
  double bestMetric = 0.0;
  isa::utils::Timer totalTimer;
  // Random number generation
  std::random_device randomDevice;
  std::default_random_engine randomEngine(randomDevice());
  std::uniform_int_distribution<unsigned int> uniformDistribution(0, factor);

  try {
    isa::utils::ArgumentList args(argc, argv);

    clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
    clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
    if ( args.getSwitch("-sampling") ) {
      samplingFactor = args.getSwitchArgument< unsigned int >("-factor");
    }
    nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
    vectorSize = args.getSwitchArgument< unsigned int >("-vector");
    maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
    maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    maxVector = args.getSwitchArgument< unsigned int >("-max_vector");
    inputSize = args.getSwitchArgument< unsigned int >("-input_size");
  } catch ( isa::utils::EmptyCommandLine & err ) {
    std::cerr << argv[0] << " -opencl_platform ... -opencl_device ... [-sampling -factor ...] -iterations ... -vector ... -max_threads ... -max_items ... -max_vector ... -input_size ... " << std::endl;
    return 1;
  } catch ( std::exception & err ) {
    std::cerr << err.what() << std::endl;
    return 1;
  }

  cl::Context clContext;
  std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
  std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
  std::vector< std::vector< cl::CommandQueue > > * clQueues = 0;

  // Allocate host memory
  std::vector< inputDataType > A(inputSize), B(inputSize), C(inputSize), C_control(inputSize);
  cl::Buffer A_d, B_d, C_d;

  std::generate(A.begin(), A.end(), [&uniformDistribution, &randomEngine](){ return uniformDistribution(randomEngine); });
  std::generate(B.begin(), B.end(), [&uniformDistribution, &randomEngine](){ return uniformDistribution(randomEngine); });
  std::fill(C.begin(), C.end(), factor);
  std::fill(C_control.begin(), C_control.end(), factor);

  // Run the control
  TuneBench::triad(A, B, C_control, static_cast< inputDataType >(factor));

  // Generate tuning configurations
  std::vector<TuneBench::TriadConf> configurations;
  for ( unsigned int threads = vectorSize; threads <= maxThreads; threads += vectorSize ) {
    for ( unsigned int items = 1; items <= maxItems; items++ ) {
      for ( unsigned int vector = 1; vector <= maxVector; vector++ ) {
        if ( inputSize % (threads * items * vector) != 0 ) {
          continue;
        } else if ( items * vector > maxItems ) {
          break;
        }
        TuneBench::TriadConf configuration;
        configuration.setNrThreadsD0(threads);
        configuration.setNrItemsD0(items);
        configuration.setVector(vector);
        configurations.push_back(configuration);
      }
    }
  }
  if ( samplingFactor < 100 ) {
    unsigned int newSize = static_cast<unsigned int>((configurations.size() * samplingFactor) / 100.0);
    std::shuffle(configurations.begin(), configurations.end(), randomEngine);
    configurations.resize(newSize);
  }

  std::cout << std::fixed << std::endl;
  std::cout << "# inputSize *configuration* GB/s time stdDeviation COV" << std::endl << std::endl;

  totalTimer.start();
  for ( auto configuration = configurations.begin(); configuration != configurations.end(); ++configuration ) {
    // Generate kernel
    double gbytes = isa::utils::giga(static_cast< uint64_t >(inputSize) * sizeof(inputDataType) * 3.0);
    cl::Event clEvent;
    cl::Kernel * kernel;
    isa::utils::Timer timer;
    std::string * code = TuneBench::getTriadOpenCL(*configuration, inputDataName, factor);

    if ( reInit ) {
      delete clQueues;
      clQueues = new std::vector< std::vector< cl::CommandQueue > >();
      isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
      try {
        initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), &A, &A_d, &B, &B_d, &C_d);
      } catch ( cl::Error & err ) {
        return -1;
      }
      reInit = false;
    }
    try {
      kernel = isa::OpenCL::compile("triad", *code, "-cl-mad-enable -Werror", clContext, clDevices->at(clDeviceID));
    } catch ( isa::OpenCL::OpenCLError & err ) {
      std::cerr << err.what() << std::endl;
      delete code;
      break;
    }
    delete code;

    cl::NDRange global(inputSize / ((*configuration).getNrItemsD0() * (*configuration).getVector()));
    cl::NDRange local((*configuration).getNrThreadsD0());

    kernel->setArg(0, A_d);
    kernel->setArg(1, B_d);
    kernel->setArg(2, C_d);

    try {
      // Warm-up run
      clQueues->at(clDeviceID)[0].finish();
      clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
      clEvent.wait();
      // Tuning runs
      for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
        timer.start();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &clEvent);
        clEvent.wait();
        timer.stop();
      }
      clQueues->at(clDeviceID)[0].enqueueReadBuffer(C_d, CL_TRUE, 0, C.size() * sizeof(inputDataType), reinterpret_cast< void * >(C.data()), 0, &clEvent);
      clEvent.wait();
    } catch ( cl::Error & err ) {
      std::cerr << "OpenCL kernel execution error (";
      std::cerr << (*configuration).print();
      std::cerr << "), (";
      std::cerr << isa::utils::toString(inputSize / (*configuration).getNrItemsD0()) << "): ";
      std::cerr << isa::utils::toString(err.err()) << std::endl;
      delete kernel;
      if ( err.err() != -5 && err.err() != -9999 ) {
        reInit = true;
      } else if ( err.err() == -4 || err.err() == -61 ) {
        return -1;
      }
      continue;
    }
    delete kernel;

    bool error = false;
    for ( unsigned int item = 0; item < C.size(); item++ ) {
      if ( !isa::utils::same(C[item], C_control[item]) ) {
        std::cerr << "Output error (" << (*configuration).print() << ")." << std::endl;
        error = true;
        break;
      }
    }
    if ( error ) {
      continue;
    }

    if ( (gbytes / timer.getAverageTime()) > bestMetric ) {
      bestMetric = gbytes / timer.getAverageTime();
      bestConfiguration = *configuration;
    }
    std::cout << inputSize << " ";
    std::cout << (*configuration).print() << " ";
    std::cout << std::setprecision(3);
    std::cout << gbytes / timer.getAverageTime() << " ";
    std::cout << std::setprecision(6);
    std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " " << timer.getCoefficientOfVariation() << std::endl;
  }
  totalTimer.stop();

  std::cout << std::endl;
  std::cout << "# ";
  std::cout << bestConfiguration.print() << " ";
  std::cout << std::setprecision(3);
  std::cout << bestMetric << " ";
  std::cout << std::setprecision(6);
  std::cout << totalTimer.getAverageTime() << std::endl;
  std::cout << std::endl;

  return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, std::vector< inputDataType > * A, cl::Buffer * A_d, std::vector< inputDataType > * B, cl::Buffer * B_d, cl::Buffer * C_d) {
  try {
    *A_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, A->size() * sizeof(inputDataType), 0, 0);
    *B_d = cl::Buffer(clContext, CL_MEM_READ_ONLY, B->size() * sizeof(inputDataType), 0, 0);
    *C_d = cl::Buffer(clContext, CL_MEM_WRITE_ONLY, A->size() * sizeof(inputDataType), 0, 0);
    clQueue->enqueueWriteBuffer(*A_d, CL_FALSE, 0, A->size() * sizeof(inputDataType), reinterpret_cast< void * >(A->data()));
    clQueue->enqueueWriteBuffer(*B_d, CL_FALSE, 0, B->size() * sizeof(inputDataType), reinterpret_cast< void * >(B->data()));
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error (memory initialization): " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<|endoftext|>


<commit_before>// @(#)root/test:$Name:  $:$Id: MainEvent.cxx,v 1.30 2005/12/02 17:43:04 brun Exp $
// Author: Rene Brun   19/01/97

////////////////////////////////////////////////////////////////////////
//
//             A simple example with a ROOT tree
//             =================================
//
//  This program creates :
//    - a ROOT file
//    - a tree
//  Additional arguments can be passed to the program to control the flow
//  of execution. (see comments describing the arguments in the code).
//      Event  nevent comp split fill
//  All arguments are optional. Default is:
//      Event  400      1    1     1
//
//  In this example, the tree consists of one single "super branch"
//  The statement ***tree->Branch("event", &event, 64000,split);*** below
//  will parse the structure described in Event.h and will make
//  a new branch for each data member of the class if split is set to 1.
//    - 9 branches corresponding to the basic types fType, fNtrack,fNseg,
//           fNvertex,fFlag,fTemperature,fMeasures,fMatrix,fClosesDistance.
//    - 3 branches corresponding to the members of the subobject EventHeader.
//    - one branch for each data member of the class Track of TClonesArray.
//    - one branch for the TRefArray of high Pt tracks
//    - one branch for the TRefArray of muon tracks
//    - one branch for the reference pointer to the last track
//    - one branch for the object fH (histogram of class TH1F).
//
//  if split = 0 only one single branch is created and the complete event
//  is serialized in one single buffer.
//  if split = -2 the event is split using the old TBranchObject mechanism
//  if split = -1 the event is streamed using the old TBranchObject mechanism
//  if split > 0  the event is split using the new TBranchElement mechanism.
//
//  if comp = 0 no compression at all.
//  if comp = 1 event is compressed.
//  if comp = 2 same as 1. In addition branches with floats in the TClonesArray
//                         are also compressed.
//  The 4th argument fill can be set to 0 if one wants to time
//     the percentage of time spent in creating the event structure and
//     not write the event in the file.
//  In this example, one loops over nevent events.
//  The branch "event" is created at the first event.
//  The branch address is set for all other events.
//  For each event, the event header is filled and ntrack tracks
//  are generated and added to the TClonesArray list.
//  For each event the event histogram is saved as well as the list
//  of all tracks.
//
//  The two TRefArray contain only references to the original tracks owned by
//  the TClonesArray fTracks.
//
//  The number of events can be given as the first argument to the program.
//  By default 400 events are generated.
//  The compression option can be activated/deactivated via the second argument.
//
//   ---Running/Linking instructions----
//  This program consists of the following files and procedures.
//    - Event.h event class description
//    - Event.C event class implementation
//    - MainEvent.C the main program to demo this class might be used (this file)
//    - EventCint.C  the CINT dictionary for the event and Track classes
//        this file is automatically generated by rootcint (see Makefile),
//        when the class definition in Event.h is modified.
//
//   ---Analyzing the Event.root file with the interactive root
//        example of a simple session
//   Root > TFile f("Event.root")
//   Root > T.Draw("fNtrack")   //histogram the number of tracks per event
//   Root > T.Draw("fPx")       //histogram fPx for all tracks in all events
//   Root > T.Draw("fXfirst:fYfirst","fNtrack>600")
//                              //scatter-plot for x versus y of first point of each track
//   Root > T.Draw("fH.GetRMS()")  //histogram of the RMS of the event histogram
//
//   Look also in the same directory at the following macros:
//     - eventa.C  an example how to read the tree
//     - eventb.C  how to read events conditionally
//
////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TFile.h"
#include "TNetFile.h"
#include "TRandom.h"
#include "TTree.h"
#include "TBranch.h"
#include "TClonesArray.h"
#include "TStopwatch.h"

#include "Event.h"

//______________________________________________________________________________
int main(int argc, char **argv)
{
   Int_t nevent = 400;     // by default create 400 events
   Int_t comp   = 1;       // by default file is compressed
   Int_t split  = 1;       // by default, split Event in sub branches
   Int_t write  = 1;       // by default the tree is filled
   Int_t hfill  = 0;       // by default histograms are not filled
   Int_t read   = 0;
   Int_t arg4   = 1;
   Int_t arg5   = 600;     //default number of tracks per event
   Int_t netf   = 0;

   if (argc > 1)  nevent = atoi(argv[1]);
   if (argc > 2)  comp   = atoi(argv[2]);
   if (argc > 3)  split  = atoi(argv[3]);
   if (argc > 4)  arg4   = atoi(argv[4]);
   if (argc > 5)  arg5   = atoi(argv[5]);
   if (arg4 ==  0) { write = 0; hfill = 0; read = 1;}
   if (arg4 ==  1) { write = 1; hfill = 0;}
   if (arg4 ==  2) { write = 0; hfill = 0;}
   if (arg4 == 10) { write = 0; hfill = 1;}
   if (arg4 == 11) { write = 1; hfill = 1;}
   if (arg4 == 20) { write = 0; read  = 1;}  //read sequential
   if (arg4 == 25) { write = 0; read  = 2;}  //read random
   if (arg4 >= 30) { netf  = 1; }            //use TNetFile
   if (arg4 == 30) { write = 0; read  = 1;}  //netfile + read sequential
   if (arg4 == 35) { write = 0; read  = 2;}  //netfile + read random
   if (arg4 == 36) { write = 1; }            //netfile + write sequential
   Int_t branchStyle = 1; //new style by default
   if (split < 0) {branchStyle = 0; split = -1-split;}

   TFile *hfile;
   TTree *tree;
   Event *event = 0;

   // Fill event, header and tracks with some random numbers
   //   Create a timer object to benchmark this loop
   TStopwatch timer;
   timer.Start();
   Long64_t nb = 0;
   Int_t ev;
   Int_t bufsize;
   Double_t told = 0;
   Double_t tnew = 0;
   Int_t printev = 100;
   if (arg5 < 100) printev = 1000;
   if (arg5 < 10)  printev = 10000;

   //Authorize Trees up to 2 Terabytes (if the system can do it)
   TTree::SetMaxTreeSize(1000*Long64_t(2000000000));

//         Read case
   if (read) {
      if (netf) {
         hfile = new TNetFile("root://localhost/root/test/EventNet.root");
         hfile->UseCache(10);
      } else
         hfile = new TFile("Event.root");
      tree = (TTree*)hfile->Get("T");
      TBranch *branch = tree->GetBranch("event");
      branch->SetAddress(&event);
      Int_t nentries = (Int_t)tree->GetEntries();
      nevent = TMath::Max(nevent,nentries);
      if (read == 1) {  //read sequential
         for (ev = 0; ev < nevent; ev++) {
            if (ev%printev == 0) {
               tnew = timer.RealTime();
               printf("event:%d, rtime=%f s\n",ev,tnew-told);
               told=tnew;
               timer.Continue();
            }
            nb += tree->GetEntry(ev);        //read complete event in memory
         }
      } else {    //read random
         Int_t evrandom;
         for (ev = 0; ev < nevent; ev++) {
            if (ev%printev == 0) cout<<"event="<<ev<<endl;
            evrandom = Int_t(nevent*gRandom->Rndm(1));
            nb += tree->GetEntry(evrandom);  //read complete event in memory
         }
      }
   } else {
//         Write case
      // Create a new ROOT binary machine independent file.
      // Note that this file may contain any kind of ROOT objects, histograms,
      // pictures, graphics objects, detector geometries, tracks, events, etc..
      // This file is now becoming the current directory.
      if (netf) {
         hfile = new TNetFile("root://localhost/root/test/EventNet.root","RECREATE","TTree benchmark ROOT file");
         hfile->UseCache(10);
      } else
         hfile = new TFile("Event.root","RECREATE","TTree benchmark ROOT file");
      hfile->SetCompressionLevel(comp);

     // Create histogram to show write_time in function of time
     Float_t curtime = -0.5;
     Int_t ntime = nevent/printev;
     TH1F *htime = new TH1F("htime","Real-Time to write versus time",ntime,0,ntime);
     HistogramManager *hm = 0;
     if (hfill) {
        TDirectory *hdir = new TDirectory("histograms", "all histograms");
        hm = new HistogramManager(hdir);
     }

     // Create a ROOT Tree and one superbranch
      TTree *tree = new TTree("T","An example of a ROOT tree");
      tree->SetAutoSave(1000000000);  // autosave when 1 Gbyte written
      bufsize = 64000;
      if (split)  bufsize /= 4;
      event = new Event();
      TTree::SetBranchStyle(branchStyle);
      TBranch *branch = tree->Branch("event", &event, bufsize,split);
      branch->SetAutoDelete(kFALSE);
      if(split >= 0 && branchStyle) tree->BranchRef();
      Float_t ptmin = 1;

      for (ev = 0; ev < nevent; ev++) {
         if (ev%printev == 0) {
            tnew = timer.RealTime();
            printf("event:%d, rtime=%f s\n",ev,tnew-told);
            htime->Fill(curtime,tnew-told);
            curtime += 1;
            told=tnew;
            timer.Continue();
         }

         event->Build(ev, arg5, ptmin);

         if (write) nb += tree->Fill();  //fill the tree

         if (hm) hm->Hfill(event);      //fill histograms
      }
      if (write) {
         hfile = tree->GetCurrentFile(); //just in case we switched to a new file
         hfile->Write();
         tree->Print();
      }
   }

   //  Stop timer and print results
   timer.Stop();
   Float_t mbytes = 0.000001*nb;
   Double_t rtime = timer.RealTime();
   Double_t ctime = timer.CpuTime();

   printf("\n%d events and %lld bytes processed.\n",nevent,nb);
   printf("RealTime=%f seconds, CpuTime=%f seconds\n",rtime,ctime);
   if (read) {
      printf("You read %f Mbytes/Realtime seconds\n",mbytes/rtime);
      printf("You read %f Mbytes/Cputime seconds\n",mbytes/ctime);
   } else {
      printf("compression level=%d, split=%d, arg4=%d\n",comp,split,arg4);
      printf("You write %f Mbytes/Realtime seconds\n",mbytes/rtime);
      printf("You write %f Mbytes/Cputime seconds\n",mbytes/ctime);
      //printf("file compression factor = %f\n",hfile.GetCompressionFactor());
   }
   hfile->Close();
   return 0;
}
<commit_msg>Use TTree::SetCacheSize instead of the obsolete TFile::UseCache<commit_after>// @(#)root/test:$Name:  $:$Id: MainEvent.cxx,v 1.31 2005/12/02 18:50:07 pcanal Exp $
// Author: Rene Brun   19/01/97

////////////////////////////////////////////////////////////////////////
//
//             A simple example with a ROOT tree
//             =================================
//
//  This program creates :
//    - a ROOT file
//    - a tree
//  Additional arguments can be passed to the program to control the flow
//  of execution. (see comments describing the arguments in the code).
//      Event  nevent comp split fill
//  All arguments are optional. Default is:
//      Event  400      1    1     1
//
//  In this example, the tree consists of one single "super branch"
//  The statement ***tree->Branch("event", &event, 64000,split);*** below
//  will parse the structure described in Event.h and will make
//  a new branch for each data member of the class if split is set to 1.
//    - 9 branches corresponding to the basic types fType, fNtrack,fNseg,
//           fNvertex,fFlag,fTemperature,fMeasures,fMatrix,fClosesDistance.
//    - 3 branches corresponding to the members of the subobject EventHeader.
//    - one branch for each data member of the class Track of TClonesArray.
//    - one branch for the TRefArray of high Pt tracks
//    - one branch for the TRefArray of muon tracks
//    - one branch for the reference pointer to the last track
//    - one branch for the object fH (histogram of class TH1F).
//
//  if split = 0 only one single branch is created and the complete event
//  is serialized in one single buffer.
//  if split = -2 the event is split using the old TBranchObject mechanism
//  if split = -1 the event is streamed using the old TBranchObject mechanism
//  if split > 0  the event is split using the new TBranchElement mechanism.
//
//  if comp = 0 no compression at all.
//  if comp = 1 event is compressed.
//  if comp = 2 same as 1. In addition branches with floats in the TClonesArray
//                         are also compressed.
//  The 4th argument fill can be set to 0 if one wants to time
//     the percentage of time spent in creating the event structure and
//     not write the event in the file.
//  In this example, one loops over nevent events.
//  The branch "event" is created at the first event.
//  The branch address is set for all other events.
//  For each event, the event header is filled and ntrack tracks
//  are generated and added to the TClonesArray list.
//  For each event the event histogram is saved as well as the list
//  of all tracks.
//
//  The two TRefArray contain only references to the original tracks owned by
//  the TClonesArray fTracks.
//
//  The number of events can be given as the first argument to the program.
//  By default 400 events are generated.
//  The compression option can be activated/deactivated via the second argument.
//
//   ---Running/Linking instructions----
//  This program consists of the following files and procedures.
//    - Event.h event class description
//    - Event.C event class implementation
//    - MainEvent.C the main program to demo this class might be used (this file)
//    - EventCint.C  the CINT dictionary for the event and Track classes
//        this file is automatically generated by rootcint (see Makefile),
//        when the class definition in Event.h is modified.
//
//   ---Analyzing the Event.root file with the interactive root
//        example of a simple session
//   Root > TFile f("Event.root")
//   Root > T.Draw("fNtrack")   //histogram the number of tracks per event
//   Root > T.Draw("fPx")       //histogram fPx for all tracks in all events
//   Root > T.Draw("fXfirst:fYfirst","fNtrack>600")
//                              //scatter-plot for x versus y of first point of each track
//   Root > T.Draw("fH.GetRMS()")  //histogram of the RMS of the event histogram
//
//   Look also in the same directory at the following macros:
//     - eventa.C  an example how to read the tree
//     - eventb.C  how to read events conditionally
//
////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "Riostream.h"
#include "TROOT.h"
#include "TFile.h"
#include "TNetFile.h"
#include "TRandom.h"
#include "TTree.h"
#include "TBranch.h"
#include "TClonesArray.h"
#include "TStopwatch.h"

#include "Event.h"

//______________________________________________________________________________
int main(int argc, char **argv)
{
   Int_t nevent = 400;     // by default create 400 events
   Int_t comp   = 1;       // by default file is compressed
   Int_t split  = 1;       // by default, split Event in sub branches
   Int_t write  = 1;       // by default the tree is filled
   Int_t hfill  = 0;       // by default histograms are not filled
   Int_t read   = 0;
   Int_t arg4   = 1;
   Int_t arg5   = 600;     //default number of tracks per event
   Int_t netf   = 0;

   if (argc > 1)  nevent = atoi(argv[1]);
   if (argc > 2)  comp   = atoi(argv[2]);
   if (argc > 3)  split  = atoi(argv[3]);
   if (argc > 4)  arg4   = atoi(argv[4]);
   if (argc > 5)  arg5   = atoi(argv[5]);
   if (arg4 ==  0) { write = 0; hfill = 0; read = 1;}
   if (arg4 ==  1) { write = 1; hfill = 0;}
   if (arg4 ==  2) { write = 0; hfill = 0;}
   if (arg4 == 10) { write = 0; hfill = 1;}
   if (arg4 == 11) { write = 1; hfill = 1;}
   if (arg4 == 20) { write = 0; read  = 1;}  //read sequential
   if (arg4 == 25) { write = 0; read  = 2;}  //read random
   if (arg4 >= 30) { netf  = 1; }            //use TNetFile
   if (arg4 == 30) { write = 0; read  = 1;}  //netfile + read sequential
   if (arg4 == 35) { write = 0; read  = 2;}  //netfile + read random
   if (arg4 == 36) { write = 1; }            //netfile + write sequential
   Int_t branchStyle = 1; //new style by default
   if (split < 0) {branchStyle = 0; split = -1-split;}

   TFile *hfile;
   TTree *tree;
   Event *event = 0;

   // Fill event, header and tracks with some random numbers
   //   Create a timer object to benchmark this loop
   TStopwatch timer;
   timer.Start();
   Long64_t nb = 0;
   Int_t ev;
   Int_t bufsize;
   Double_t told = 0;
   Double_t tnew = 0;
   Int_t printev = 100;
   if (arg5 < 100) printev = 1000;
   if (arg5 < 10)  printev = 10000;

   //Authorize Trees up to 2 Terabytes (if the system can do it)
   TTree::SetMaxTreeSize(1000*Long64_t(2000000000));

//         Read case
   if (read) {
      if (netf) {
         hfile = new TNetFile("root://localhost/root/test/EventNet.root");
      } else
         hfile = new TFile("Event.root");
      tree = (TTree*)hfile->Get("T");
      tree->SetCacheSize(10000000); //this is the default value: 10 MBytes
      TBranch *branch = tree->GetBranch("event");
      branch->SetAddress(&event);
      Int_t nentries = (Int_t)tree->GetEntries();
      nevent = TMath::Max(nevent,nentries);
      if (read == 1) {  //read sequential
         for (ev = 0; ev < nevent; ev++) {
            if (ev%printev == 0) {
               tnew = timer.RealTime();
               printf("event:%d, rtime=%f s\n",ev,tnew-told);
               told=tnew;
               timer.Continue();
            }
            nb += tree->GetEntry(ev);        //read complete event in memory
         }
      } else {    //read random
         Int_t evrandom;
         for (ev = 0; ev < nevent; ev++) {
            if (ev%printev == 0) cout<<"event="<<ev<<endl;
            evrandom = Int_t(nevent*gRandom->Rndm(1));
            nb += tree->GetEntry(evrandom);  //read complete event in memory
         }
      }
   } else {
//         Write case
      // Create a new ROOT binary machine independent file.
      // Note that this file may contain any kind of ROOT objects, histograms,
      // pictures, graphics objects, detector geometries, tracks, events, etc..
      // This file is now becoming the current directory.
      if (netf) {
         hfile = new TNetFile("root://localhost/root/test/EventNet.root","RECREATE","TTree benchmark ROOT file");
      } else
         hfile = new TFile("Event.root","RECREATE","TTree benchmark ROOT file");
      hfile->SetCompressionLevel(comp);

     // Create histogram to show write_time in function of time
     Float_t curtime = -0.5;
     Int_t ntime = nevent/printev;
     TH1F *htime = new TH1F("htime","Real-Time to write versus time",ntime,0,ntime);
     HistogramManager *hm = 0;
     if (hfill) {
        TDirectory *hdir = new TDirectory("histograms", "all histograms");
        hm = new HistogramManager(hdir);
     }

     // Create a ROOT Tree and one superbranch
      TTree *tree = new TTree("T","An example of a ROOT tree");
      tree->SetAutoSave(1000000000); // autosave when 1 Gbyte written
      tree->SetCacheSize(10000000);  //set a 10 MBytes cache (useless when writing local files)
      bufsize = 64000;
      if (split)  bufsize /= 4;
      event = new Event();
      TTree::SetBranchStyle(branchStyle);
      TBranch *branch = tree->Branch("event", &event, bufsize,split);
      branch->SetAutoDelete(kFALSE);
      if(split >= 0 && branchStyle) tree->BranchRef();
      Float_t ptmin = 1;

      for (ev = 0; ev < nevent; ev++) {
         if (ev%printev == 0) {
            tnew = timer.RealTime();
            printf("event:%d, rtime=%f s\n",ev,tnew-told);
            htime->Fill(curtime,tnew-told);
            curtime += 1;
            told=tnew;
            timer.Continue();
         }

         event->Build(ev, arg5, ptmin);

         if (write) nb += tree->Fill();  //fill the tree

         if (hm) hm->Hfill(event);      //fill histograms
      }
      if (write) {
         hfile = tree->GetCurrentFile(); //just in case we switched to a new file
         hfile->Write();
         tree->Print();
      }
   }

   //  Stop timer and print results
   timer.Stop();
   Float_t mbytes = 0.000001*nb;
   Double_t rtime = timer.RealTime();
   Double_t ctime = timer.CpuTime();

   printf("\n%d events and %lld bytes processed.\n",nevent,nb);
   printf("RealTime=%f seconds, CpuTime=%f seconds\n",rtime,ctime);
   if (read) {
      printf("You read %f Mbytes/Realtime seconds\n",mbytes/rtime);
      printf("You read %f Mbytes/Cputime seconds\n",mbytes/ctime);
   } else {
      printf("compression level=%d, split=%d, arg4=%d\n",comp,split,arg4);
      printf("You write %f Mbytes/Realtime seconds\n",mbytes/rtime);
      printf("You write %f Mbytes/Cputime seconds\n",mbytes/ctime);
      //printf("file compression factor = %f\n",hfile.GetCompressionFactor());
   }
   hfile->Close();
   return 0;
}
<|endoftext|>