<commit_before>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    for (auto& c : str)
    {
        if (contains(characters, c))
            res += escape;
        res += c;
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    for (auto& c : str)
    {
        if (contains(characters, c) and not res.empty() and res.back() == escape)
            res.back() = c;
        else
            res += c;
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

int str_to_int(StringView str)
{
    int res = 0;
    if (sscanf(str.zstr(), "%i", &res) != 1)
        throw runtime_error(str + "is not a number");
    return res;
}

String to_string(int val)
{
    char buf[16];
    sprintf(buf, "%i", val);
    return buf;
}

String to_string(size_t val)
{
    char buf[16];
    sprintf(buf, "%zu", val);
    return buf;
}

String to_string(float val)
{
    char buf[32];
    sprintf(buf, "%f", val);
    return buf;
}

bool subsequence_match(StringView str, StringView subseq)
{
    auto it = str.begin();
    for (auto& c : subseq)
    {
        if (it == str.end())
            return false;
        while (*it != c)
        {
            if (++it == str.end())
                return false;
        }
        ++it;
    }
    return true;
}

String expand_tabs(StringView line, CharCount tabstop, CharCount col)
{
    String res;
    using Utf8It = utf8::iterator<const char*>;
    for (Utf8It it = line.begin(); it.base() < line.end(); ++it)
    {
        if (*it == '\t')
        {
            CharCount end_col = (col / tabstop + 1) * tabstop;
            res += String{' ', end_col - col};
        }
        else
            res += *it;
    }
    return res;
}

Vector<StringView> wrap_lines(StringView text, CharCount max_width)
{
    using Utf8It = utf8::iterator<const char*>;
    Utf8It word_begin{text.begin()};
    Utf8It word_end{word_begin};
    Utf8It end{text.end()};
    CharCount col = 0;
    Vector<StringView> lines;
    Utf8It line_begin = text.begin();
    Utf8It line_end = line_begin;
    while (word_begin != end)
    {
        const CharCategories cat = categorize(*word_begin);
        do
        {
            ++word_end;
        } while (word_end != end and categorize(*word_end) == cat);

        col += word_end - word_begin;
        if ((word_begin != line_begin and col > max_width) or
            cat == CharCategories::EndOfLine)
        {
            lines.emplace_back(line_begin.base(), line_end.base());
            line_begin = (cat == CharCategories::EndOfLine or
                          cat == CharCategories::Blank) ? word_end : word_begin;
            col = word_end - line_begin;
        }
        if (cat == CharCategories::Word or cat == CharCategories::Punctuation)
            line_end = word_end;

        word_begin = word_end;
    }
    if (line_begin != word_begin)
        lines.emplace_back(line_begin.base(), word_begin.base());
    return lines;
}

}
<commit_msg>Allocate some data in advance in string algorithm<commit_after>#include "string.hh"

#include "exception.hh"
#include "containers.hh"
#include "utf8_iterator.hh"

#include <cstdio>

namespace Kakoune
{

Vector<String> split(StringView str, char separator, char escape)
{
    Vector<String> res;
    auto it = str.begin();
    while (it != str.end())
    {
        res.emplace_back();
        String& element = res.back();
        while (it != str.end())
        {
            auto c = *it;
            if (c == escape and it + 1 != str.end() and *(it+1) == separator)
            {
                element += separator;
                it += 2;
            }
            else if (c == separator)
            {
                ++it;
                break;
            }
            else
            {
                element += c;
                ++it;
            }
        }
    }
    return res;
}

Vector<StringView> split(StringView str, char separator)
{
    Vector<StringView> res;
    auto beg = str.begin();
    for (auto it = beg; it != str.end(); ++it)
    {
        if (*it == separator)
        {
            res.emplace_back(beg, it);
            beg = it + 1;
        }
    }
    res.emplace_back(beg, str.end());
    return res;
}

String escape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c))
            res += escape;
        res += c;
    }
    return res;
}

String unescape(StringView str, StringView characters, char escape)
{
    String res;
    res.reserve(str.length());
    for (auto& c : str)
    {
        if (contains(characters, c) and not res.empty() and res.back() == escape)
            res.back() = c;
        else
            res += c;
    }
    return res;
}

String indent(StringView str, StringView indent)
{
    String res;
    res.reserve(str.length());
    bool was_eol = true;
    for (ByteCount i = 0; i < str.length(); ++i)
    {
        if (was_eol)
            res += indent;
        res += str[i];
        was_eol = is_eol(str[i]);
    }
    return res;
}

int str_to_int(StringView str)
{
    int res = 0;
    if (sscanf(str.zstr(), "%i", &res) != 1)
        throw runtime_error(str + "is not a number");
    return res;
}

String to_string(int val)
{
    char buf[16];
    sprintf(buf, "%i", val);
    return buf;
}

String to_string(size_t val)
{
    char buf[16];
    sprintf(buf, "%zu", val);
    return buf;
}

String to_string(float val)
{
    char buf[32];
    sprintf(buf, "%f", val);
    return buf;
}

bool subsequence_match(StringView str, StringView subseq)
{
    auto it = str.begin();
    for (auto& c : subseq)
    {
        if (it == str.end())
            return false;
        while (*it != c)
        {
            if (++it == str.end())
                return false;
        }
        ++it;
    }
    return true;
}

String expand_tabs(StringView line, CharCount tabstop, CharCount col)
{
    String res;
    res.reserve(line.length());
    using Utf8It = utf8::iterator<const char*>;
    for (Utf8It it = line.begin(); it.base() < line.end(); ++it)
    {
        if (*it == '\t')
        {
            CharCount end_col = (col / tabstop + 1) * tabstop;
            res += String{' ', end_col - col};
        }
        else
            res += *it;
    }
    return res;
}

Vector<StringView> wrap_lines(StringView text, CharCount max_width)
{
    using Utf8It = utf8::iterator<const char*>;
    Utf8It word_begin{text.begin()};
    Utf8It word_end{word_begin};
    Utf8It end{text.end()};
    CharCount col = 0;
    Vector<StringView> lines;
    Utf8It line_begin = text.begin();
    Utf8It line_end = line_begin;
    while (word_begin != end)
    {
        const CharCategories cat = categorize(*word_begin);
        do
        {
            ++word_end;
        } while (word_end != end and categorize(*word_end) == cat);

        col += word_end - word_begin;
        if ((word_begin != line_begin and col > max_width) or
            cat == CharCategories::EndOfLine)
        {
            lines.emplace_back(line_begin.base(), line_end.base());
            line_begin = (cat == CharCategories::EndOfLine or
                          cat == CharCategories::Blank) ? word_end : word_begin;
            col = word_end - line_begin;
        }
        if (cat == CharCategories::Word or cat == CharCategories::Punctuation)
            line_end = word_end;

        word_begin = word_end;
    }
    if (line_begin != word_begin)
        lines.emplace_back(line_begin.base(), word_begin.base());
    return lines;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include "tools.h"

#include "division_by_zero_exception.h"

using Eigen::VectorXd;
using Eigen::MatrixXd;
using std::vector;

Tools::Tools() {}

Tools::~Tools() {}

VectorXd Tools::CalculateRMSE(const vector<VectorXd> &estimations,
                              const vector<VectorXd> &ground_truth) {
  VectorXd rmse(4);
  rmse << 0, 0, 0, 0;

  // check the validity of the following inputs:
  //  * the estimation vector size should not be zero
  //  * the estimation vector size should equal ground truth vector size
  if(estimations.size() == 0 || estimations.size() != ground_truth.size()) {
    std::cout << "calculateRMSE() - Error - Invalid Estimations vector size" << std::endl;
    return rmse;
  }

  //accumulate squared residuals
  VectorXd sum(4);
  sum << 0, 0, 0, 0;

  for(int i = 0; i < estimations.size(); ++i) {
    VectorXd estimated = estimations[i];
    VectorXd actual = ground_truth[i];

    VectorXd diff = (estimated - actual);
    //coefficient-wise multiplication
    diff = diff.array() * diff.array();
    sum = sum + diff;
  }

  //calculate the mean
  Eigen::VectorXd mean = sum / estimations.size();

  //calculate the squared root
  rmse = mean.array().sqrt();

  return rmse;
}

MatrixXd Tools::CalculateJacobian(const VectorXd& x_state) {
  Eigen::MatrixXd Hj = MatrixXd::Zero(3, 4);

  //state parameters
  float px = x_state(0);
  float py = x_state(1);
  float vx = x_state(2);
  float vy = x_state(3);

  //divsion by zero check
  if(px == 0 || py == 0 ) {
    throw DivisionByZeroException();
  }

  // calculating common values used in Jacobian
  float px2 = px * px;
  float py2 = py * py;
  float px2_py2_sum = px2 + py2;
  float px2_py2_sqrt = sqrt(px2_py2_sum);
  float px2_py2_sum_3_by_2 = pow((px2_py2_sum), 3/2.0);

  if(fabs(px2_py2_sum) < 0.0001) {
    throw DivisionByZeroException();
  }

  // calculating and inserting jacobian values
  Hj << (px / px2_py2_sqrt), (py / px2_py2_sqrt), 0, 0,
      (-py / px2_py2_sum), (px / px2_py2_sum), 0, 0,
      ((py * (vx * py - vy * px)) / px2_py2_sum_3_by_2), ((px * (vy * px - vx * py)) / px2_py2_sum_3_by_2), (px / px2_py2_sqrt), (py / px2_py2_sqrt);

  return Hj;
}
<commit_msg>feat: Function to normalize angle in [-pi, pi]<commit_after>#include <iostream>
#include "tools.h"

#include "division_by_zero_exception.h"

using Eigen::VectorXd;
using Eigen::MatrixXd;
using std::vector;

Tools::Tools() {}

Tools::~Tools() {}

VectorXd Tools::CalculateRMSE(const vector<VectorXd> &estimations,
                              const vector<VectorXd> &ground_truth) {
  VectorXd rmse(4);
  rmse << 0, 0, 0, 0;

  // check the validity of the following inputs:
  //  * the estimation vector size should not be zero
  //  * the estimation vector size should equal ground truth vector size
  if(estimations.size() == 0 || estimations.size() != ground_truth.size()) {
    std::cout << "calculateRMSE() - Error - Invalid Estimations vector size" << std::endl;
    return rmse;
  }

  //accumulate squared residuals
  VectorXd sum(4);
  sum << 0, 0, 0, 0;

  for(int i = 0; i < estimations.size(); ++i) {
    VectorXd estimated = estimations[i];
    VectorXd actual = ground_truth[i];

    VectorXd diff = (estimated - actual);
    //coefficient-wise multiplication
    diff = diff.array() * diff.array();
    sum = sum + diff;
  }

  //calculate the mean
  Eigen::VectorXd mean = sum / estimations.size();

  //calculate the squared root
  rmse = mean.array().sqrt();

  return rmse;
}

MatrixXd Tools::CalculateJacobian(const VectorXd& x_state) {
  Eigen::MatrixXd Hj = MatrixXd::Zero(3, 4);

  //state parameters
  float px = x_state(0);
  float py = x_state(1);
  float vx = x_state(2);
  float vy = x_state(3);

  //divsion by zero check
  if(px == 0 || py == 0 ) {
    throw DivisionByZeroException();
  }

  // calculating common values used in Jacobian
  float px2 = px * px;
  float py2 = py * py;
  float px2_py2_sum = px2 + py2;
  float px2_py2_sqrt = sqrt(px2_py2_sum);
  float px2_py2_sum_3_by_2 = pow((px2_py2_sum), 3/2.0);

  if(fabs(px2_py2_sum) < 0.0001) {
    throw DivisionByZeroException();
  }

  // calculating and inserting jacobian values
  Hj << (px / px2_py2_sqrt), (py / px2_py2_sqrt), 0, 0,
      (-py / px2_py2_sum), (px / px2_py2_sum), 0, 0,
      ((py * (vx * py - vy * px)) / px2_py2_sum_3_by_2), ((px * (vy * px - vx * py)) / px2_py2_sum_3_by_2), (px / px2_py2_sqrt), (py / px2_py2_sqrt);

  return Hj;
}

float Tools::NormalizeAngle(float angle_rad) {
  angle_rad = angle_rad - 2*M_PI*floor( (angle_rad+ M_PI)/(2 * M_PI) );
  return angle_rad;
}
<|endoftext|>


<commit_before>#include <cmath>
#include <iostream>
#include "types.hpp"

field::field(std::size_t h, std::size_t w){
    this->width = w;
    this->height = h;
    this->f = std::vector< std::vector < bool > >(h);
    for (std::size_t i = 0; i < h; ++i)
        this->f[i].assign(w, false);
}

std::vector< bool > & field::operator[](std::size_t i){
    return this->f[i];
}

vec3d::vec3d( vec3s v ) {
    this->x = v.r * sin( v.theta ) * cos ( v.phi );
    this->y = v.r * sin( v.theta ) * sin ( v.phi );
    this->z = v.r * cos( v.theta );
}

float vec3d::operator*( vec3d rhs ) {
    return this->x * rhs.x + this->y * rhs.y + this->z * rhs.z;
}

float vec3s::operator*( vec3s rhs ) {
    return vec3d( *this ) * vec3d ( rhs );
}

vec3s & operator += ( vec3s & lhs, const vec3s & rhs ) {
    lhs.r += rhs.r;
    lhs.theta += rhs.theta;
    lhs.phi += rhs.phi;
    return lhs;
}

vec3s & operator -= ( vec3s & lhs, const vec3s & rhs ) {
    lhs.r -= rhs.r;
    lhs.theta -= rhs.theta;
    lhs.phi -= rhs.phi;
    return lhs;
}

SDL_Point surf_to_screen( vec3s n, vec3s sp, SDL_Point center ) {
    // координаты ортов в плоскости экрана в декартовых координатах
    vec3s ex = { 1, ( float ) ( M_PI / 2 ), n.phi + ( float ) ( M_PI / 2 ) };
    vec3s ey = { 1, n.theta - ( float ) ( M_PI / 2 ), n.phi };

    // немного скалярных произведений
    return { center.x + ( int ) ( sp * ex ),
             center.y - ( int ) ( sp * ey ) };
}

bool visible ( vec3s n, vec3s sp ) {
    return ( n * sp >= 0 ); // хак для увеличения области видимости
}

<commit_msg>[upd] minor improvements<commit_after>#include <cmath>
#include <iostream>
#include "types.hpp"

field::field(std::size_t h, std::size_t w) : f(h) {
    this->width = w;
    this->height = h;
    for (std::size_t i = 0; i < h; ++i)
        this->f[i].assign(w, false);
}

std::vector< bool > & field::operator[](std::size_t i){
    return this->f[i];
}

vec3d::vec3d( vec3s v ) {
    float st, ct, sp, cp;
    sincosf(v.theta, &st, &ct);
    sincosf(v.phi, &sp, &cp);
    this->x = v.r * st * cp;
    this->y = v.r * st * sp;
    this->z = v.r * ct;
}

float vec3d::operator*( vec3d rhs ) {
    return this->x * rhs.x + this->y * rhs.y + this->z * rhs.z;
}

float vec3s::operator*( vec3s rhs ) {
    return vec3d( *this ) * vec3d ( rhs );
}

vec3s & operator += ( vec3s & lhs, const vec3s & rhs ) {
    lhs.r += rhs.r;
    lhs.theta += rhs.theta;
    lhs.phi += rhs.phi;
    return lhs;
}

vec3s & operator -= ( vec3s & lhs, const vec3s & rhs ) {
    lhs.r -= rhs.r;
    lhs.theta -= rhs.theta;
    lhs.phi -= rhs.phi;
    return lhs;
}

SDL_Point surf_to_screen( vec3s n, vec3s sp, SDL_Point center ) {
    // координаты ортов в плоскости экрана в декартовых координатах
    vec3s ex = { 1, ( float ) ( M_PI / 2 ), n.phi + ( float ) ( M_PI / 2 ) };
    vec3s ey = { 1, n.theta - ( float ) ( M_PI / 2 ), n.phi };

    // немного скалярных произведений
    return { center.x + ( int ) ( sp * ex ),
             center.y - ( int ) ( sp * ey ) };
}

bool visible ( vec3s n, vec3s sp ) {
    return ( n * sp >= 0 ); // хак для увеличения области видимости
}

<|endoftext|>


<commit_before>/*! \file uqueue.cc
 *******************************************************************************

 File: uqueue.cc\n
 Implementation of the UQueue class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2005.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 This software is provided "as is" without warranty of any kind,
 either expressed or implied, including but not limited to the
 implied warranties of fitness for a particular purpose.

 For more information, comments, bug reports: http://www.urbiforge.net

 **************************************************************************** */

#include <cstdlib>
#include "libport/cstring"

#include "kernel/userver.hh"

#include "uqueue.hh"

//! UQueue constructor.
/*! UQueue implements a dynamic circular FIFO buffer.
    You can specify the following parameters:

    \param minBufferSize is the initial size of the buffer. If the buffer is
	   shrinked (adaptive buffer), its size will be at least minBufferSize.
	   The default value if not specified is 4096 octets.
    \param maxBufferSize is the maximal size of the buffer. The buffer size is
	   increased when one tries to push data that is too big for the current
	   buffer size. However, this dynamic behavior is limited to
	   maxBufferSize in any case. If the buffer can still not hold the
	   pushed data, the push() function returns UFAIL.
	   If set to zero, the limit is infinite.
	   The default value is equal to minBufferSize.
    \param adaptive the default behavior of the UQueue is to increase the size
	   of the internal buffer if one tries to hold more data that what the
	   current size allows (up to maxBufferSize, as we said). However, if
	   the buffer is adaptive, it will also be able to shrink the buffer.
	   This is very useful to allow the UQueue to grow momentarily to hold
	   a large amount of data and then recover memory after the boost, if
	   this data size is not the usual functioning load.
	   If adaptive is non null, the behavior is the following: the UQueue
	   counts the number of calls to the pop() function. Each time this
	   number goes above 'adaptive', the UQueue will resize to the maximum
	   data size it has held in the past 'adaptive' calls to pop(), and
	   minBufferSize at least. So, 'adaptive' is a time windows that is
	   periodicaly checked to shink the buffer if necessary.
	   Note that the buffer will shrink only if there is a minimum of 20%
	   size difference, to avoid time consuming reallocs for nothing.
	   We recommand a default value of 100 for the adaptive value.
*/
UQueue::UQueue (size_t minBufferSize,
		size_t maxBufferSize,
		size_t adaptive)
  : minBufferSize_ (minBufferSize
		    ? minBufferSize : static_cast<size_t>(INITIAL_BUFFER_SIZE)),
    maxBufferSize_ (maxBufferSize == static_cast<size_t>(-1)
		    ? minBufferSize_ : maxBufferSize),
    adaptive_(adaptive),
    buffer_(minBufferSize_),
    outputBuffer_(UQueue::INITIAL_BUFFER_SIZE),
    start_(0),
    end_(0),
    dataSize_(0),
    nbPopCall_(0),
    topDataSize_(0),
    topOutputSize_(0),
    mark_(0),
    locked_(false)
{
}

//! UQueue destructor.
UQueue::~UQueue()
{
}

//! Clear the queue
void
UQueue::clear()
{
  start_    = 0;
  end_      = 0;
  dataSize_ = 0;
}

//! Set a mark to be able to revert to this position
void
UQueue::mark()
{
  mark_ = end_;
  locked_ = false;
}

//! Revert the buffer to the marked position.
void
UQueue::revert()
{
  end_ = mark_;
  locked_ = true;
}

void
UQueue::enlarge (size_t& s) const
{
  s *= 2;
  if (maxBufferSize_)
    s = std::min(s, maxBufferSize_);
}

//! Pushes a buffer into the queue..
/*! This function tries to store the buffer in the queue, and tries to extend
    to buffer size when the buffer does not fit and if it is possible.

    \param buffer the buffer to push
    \param length the length of the buffer
    \return
	    - USUCCESS: successful
	    - UFAIL   : could not push the buffer. The queue is not changed.
*/

UErrorValue
UQueue::push (const ubyte *buffer, size_t length)
{
  size_t bfs = bufferFreeSpace();

  if (bfs < length) // Is the internal buffer big enough?
  {
    // No. Check if the internal buffer can be extended.
    size_t newSize = buffer_.size() + (length - bfs);

    if (newSize > maxBufferSize_ && maxBufferSize_ != 0)
      return UFAIL;
    else
    {
      // Calculate the required size + 10%, if it fits.
      enlarge(newSize);

      // Realloc the internal buffer
      size_t old_size = buffer_.size();
      buffer_.resize(newSize);
      if (end_ < start_ || bfs == 0 )
      {
	// Translate the rightside of the old internal buffer.
	memmove(&buffer_[0] + start_ + newSize - old_size,
		&buffer_[0] + start_,
		old_size - start_);
	start_ += newSize - old_size;
      }
    }
  }

  if (buffer_.size() - end_ >= length)
  {
    // Do we have to split 'buffer'?
    // No need to split.
    memcpy(&buffer_[0] + end_, buffer, length);
    end_ += length;
    if (end_ == buffer_.size())
      end_ = 0; // loop the circular geometry.
  }
  else
  {
    // Split 'buffer' to fit in the internal circular buffer.
    memcpy(&buffer_[0] + end_, buffer, buffer_.size() - end_);
    memcpy(&buffer_[0],
	   buffer + (buffer_.size() - end_),
	   length - (buffer_.size() - end_));
    end_ = length - (buffer_.size() - end_);
  }

  dataSize_ += length;
  return USUCCESS;
}

void
UQueue::adapt(size_t toPop)
{
  ++nbPopCall_;
  topDataSize_ = std::max (topDataSize_, dataSize_);
  topOutputSize_ = std::max (topOutputSize_, toPop);

  if (adaptive_ < nbPopCall_)
  {
    // time out
    if (topOutputSize_ < outputBuffer_.size() * 0.8)
      outputBuffer_.resize(topOutputSize_ * 2);

    if (topDataSize_ < buffer_.size() * 0.8)
    {
      // We shrink the buffer to the new size: topDataSize_ + 10% (if it fits)
      enlarge(topDataSize_);
      if (end_ < start_)
      {
	// The data is splitted
	memmove(&buffer_[0] + start_ - (buffer_.size() - topDataSize_),
		&buffer_[0] + start_, buffer_.size() - start_);
	start_ = start_ - (buffer_.size() - topDataSize_);
      }
      else
      {
	// The data is contiguous
	memmove(&buffer_[0], &buffer_[0] + start_, dataSize_);
	start_ = 0;
	end_   = dataSize_;
	// the case end_ == buffer_.size() is handled below.
      }

      buffer_.resize(topDataSize_);
      if (end_ == buffer_.size() )
	end_ =0; // loop the circular geometry.
      // else... well it should never come to this else anyway.
    }

    // reset.
    nbPopCall_ = 0;
    topDataSize_   = 0;
    topOutputSize_ = 0;
  }
}

//! Pops 'length' bytes out of the Queue
/*! Pops 'length' bytes.
    The ubyte* pointer returned is not permanent. You have to make a copy of the
    data pointed if you want to keep it. Any call to a member function of UQueue
    might alter it later.

    \param length the length requested.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::pop (size_t length)
{
  // Actual size of the data to pop.
  size_t toPop = length;
  if (toPop > dataSize_)
    return 0; // Not enough data to pop 'length'

  if (toPop == 0)
    // Pops nothing but gets a pointer to the beginning of the buffer.
    return &buffer_[0] + start_;

  // Adaptive shrinking behavior
  if (adaptive_)
    adapt(toPop);

  if (buffer_.size() - start_ >= toPop)
  {
    // Is the packet continuous across the the internal buffer?  yes,
    // the packet is continuous in the internal buffer
    size_t start = start_;
    start_ += toPop;
    if (start_ == buffer_.size())
      start_ = 0; // loop the circular geometry.
    dataSize_ -= toPop;
    return &buffer_[0] + start;
  }
  else
  {
    // no, the packet spans then end and the beginning of the buffer
    // and it must be reconstructed.

    // Is the temporary internal outputBuffer large enough?
    if (outputBuffer_.size() < toPop)
      outputBuffer_.resize(toPop * 2);

    memcpy(&outputBuffer_[0],
	   &buffer_[0] + start_,
	   buffer_.size() - start_);

    memcpy(&outputBuffer_[0] + (buffer_.size() - start_ ),
	   &buffer_[0],
	   toPop - (buffer_.size() - start_));

    start_ = toPop - (buffer_.size() - start_);
    dataSize_ -= toPop;

    return &outputBuffer_[0];
  }
}

//! Pops at most 'length' bytes out of the Queue
/*! Pops at most 'length' bytes. The actual size is returned in 'length'.
    The ubyte* pointer returned is not permanent. You have to make a copy of the
    data pointed if you want to keep it. Any call to a member function of UQueue
    might alter it later.

    This method is called "fast" because is will not use the temporary
    outputBuffer if the requested data is half at the end and half at the
    beginning of the buffer. It will return only the part at the end of the
    buffer and return the actual size of data popped. You have to check if this
    value is equal to the requested length. If it is not, a second call to
    fastPop will give you the rest of the buffer, with a different pointer.
    This function is useful if you plan to pop huge amount of data which will
    probably span over the end of the buffer and which would, with a simple
    call to 'pop', result in a huge memory replication. In other cases, prefer
    'pop', which is most of the time as efficient as fastPop and much more
    convenient to use.

    \param length the length requested. Contains the actual length popped.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::fastPop (size_t &length)
{
  return pop((length > buffer_.size() - start_)
	     ? (length = buffer_.size() - start_)
	     : length);
}

//! Simulates the pop of 'length' bytes out of the Queue
/*! Behave like pop but simulate the effect. This is useful if one wants to try
    something with the popped buffer and check the validity before actually
    popping the data.
    It is also typically used when trying to send bytes in a connection and
    it is not known in advance how many bytes will be effectively sent.

    \param length the length requested.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::virtualPop (size_t length)
{
  // Actual size of the data to pop.
  size_t toPop = length;
  if (toPop > dataSize_)
    return 0; // Not enough data to pop 'length'
  if (toPop == 0)
    // Pops nothing but gets a pointer to the beginning of the buffer.
    return &buffer_[0] + start_;

  // Is the packet continuous across the internal buffer?
  if (buffer_.size() - start_ >= toPop)
    // yes, the packet is continuous in the internal buffer
    return &buffer_[0] + start_;
  else
  {
    // no, the packet spans then end and the beginning of the buffer
    // and it must be reconstructed.

    // Is the temporary internal outputBuffer large enough?
    if (outputBuffer_.size() < toPop)
      outputBuffer_.resize(toPop * 2);

    memcpy(&outputBuffer_[0],
	   &buffer_[0] + start_,
	   buffer_.size() - start_);

    memcpy(&outputBuffer_[0] + (buffer_.size() - start_),
	   &buffer_[0],
	   toPop - (buffer_.size() - start_));

    //start_ = toPop - (buffer_.size() - start_);
    //dataSize_ -= toPop;

    return &outputBuffer_[0];
  }
}
<commit_msg>Add missing include of windows.hh<commit_after>/*! \file uqueue.cc
 *******************************************************************************

 File: uqueue.cc\n
 Implementation of the UQueue class.

 This file is part of
 %URBI Kernel, version __kernelversion__\n
 (c) Jean-Christophe Baillie, 2004-2005.

 Permission to use, copy, modify, and redistribute this software for
 non-commercial use is hereby granted.

 This software is provided "as is" without warranty of any kind,
 either expressed or implied, including but not limited to the
 implied warranties of fitness for a particular purpose.

 For more information, comments, bug reports: http://www.urbiforge.net

 **************************************************************************** */

#include <cstdlib>
#include <libport/cstring>
#include <libport/windows.hh>

#include "kernel/userver.hh"

#include "uqueue.hh"

//! UQueue constructor.
/*! UQueue implements a dynamic circular FIFO buffer.
    You can specify the following parameters:

    \param minBufferSize is the initial size of the buffer. If the buffer is
	   shrinked (adaptive buffer), its size will be at least minBufferSize.
	   The default value if not specified is 4096 octets.
    \param maxBufferSize is the maximal size of the buffer. The buffer size is
	   increased when one tries to push data that is too big for the current
	   buffer size. However, this dynamic behavior is limited to
	   maxBufferSize in any case. If the buffer can still not hold the
	   pushed data, the push() function returns UFAIL.
	   If set to zero, the limit is infinite.
	   The default value is equal to minBufferSize.
    \param adaptive the default behavior of the UQueue is to increase the size
	   of the internal buffer if one tries to hold more data that what the
	   current size allows (up to maxBufferSize, as we said). However, if
	   the buffer is adaptive, it will also be able to shrink the buffer.
	   This is very useful to allow the UQueue to grow momentarily to hold
	   a large amount of data and then recover memory after the boost, if
	   this data size is not the usual functioning load.
	   If adaptive is non null, the behavior is the following: the UQueue
	   counts the number of calls to the pop() function. Each time this
	   number goes above 'adaptive', the UQueue will resize to the maximum
	   data size it has held in the past 'adaptive' calls to pop(), and
	   minBufferSize at least. So, 'adaptive' is a time windows that is
	   periodicaly checked to shink the buffer if necessary.
	   Note that the buffer will shrink only if there is a minimum of 20%
	   size difference, to avoid time consuming reallocs for nothing.
	   We recommand a default value of 100 for the adaptive value.
*/
UQueue::UQueue (size_t minBufferSize,
		size_t maxBufferSize,
		size_t adaptive)
  : minBufferSize_ (minBufferSize
		    ? minBufferSize : static_cast<size_t>(INITIAL_BUFFER_SIZE)),
    maxBufferSize_ (maxBufferSize == static_cast<size_t>(-1)
		    ? minBufferSize_ : maxBufferSize),
    adaptive_(adaptive),
    buffer_(minBufferSize_),
    outputBuffer_(UQueue::INITIAL_BUFFER_SIZE),
    start_(0),
    end_(0),
    dataSize_(0),
    nbPopCall_(0),
    topDataSize_(0),
    topOutputSize_(0),
    mark_(0),
    locked_(false)
{
}

//! UQueue destructor.
UQueue::~UQueue()
{
}

//! Clear the queue
void
UQueue::clear()
{
  start_    = 0;
  end_      = 0;
  dataSize_ = 0;
}

//! Set a mark to be able to revert to this position
void
UQueue::mark()
{
  mark_ = end_;
  locked_ = false;
}

//! Revert the buffer to the marked position.
void
UQueue::revert()
{
  end_ = mark_;
  locked_ = true;
}

void
UQueue::enlarge (size_t& s) const
{
  s *= 2;
  if (maxBufferSize_)
    s = std::min(s, maxBufferSize_);
}

//! Pushes a buffer into the queue..
/*! This function tries to store the buffer in the queue, and tries to extend
    to buffer size when the buffer does not fit and if it is possible.

    \param buffer the buffer to push
    \param length the length of the buffer
    \return
	    - USUCCESS: successful
	    - UFAIL   : could not push the buffer. The queue is not changed.
*/

UErrorValue
UQueue::push (const ubyte *buffer, size_t length)
{
  size_t bfs = bufferFreeSpace();

  if (bfs < length) // Is the internal buffer big enough?
  {
    // No. Check if the internal buffer can be extended.
    size_t newSize = buffer_.size() + (length - bfs);

    if (newSize > maxBufferSize_ && maxBufferSize_ != 0)
      return UFAIL;
    else
    {
      // Calculate the required size + 10%, if it fits.
      enlarge(newSize);

      // Realloc the internal buffer
      size_t old_size = buffer_.size();
      buffer_.resize(newSize);
      if (end_ < start_ || bfs == 0 )
      {
	// Translate the rightside of the old internal buffer.
	memmove(&buffer_[0] + start_ + newSize - old_size,
		&buffer_[0] + start_,
		old_size - start_);
	start_ += newSize - old_size;
      }
    }
  }

  if (buffer_.size() - end_ >= length)
  {
    // Do we have to split 'buffer'?
    // No need to split.
    memcpy(&buffer_[0] + end_, buffer, length);
    end_ += length;
    if (end_ == buffer_.size())
      end_ = 0; // loop the circular geometry.
  }
  else
  {
    // Split 'buffer' to fit in the internal circular buffer.
    memcpy(&buffer_[0] + end_, buffer, buffer_.size() - end_);
    memcpy(&buffer_[0],
	   buffer + (buffer_.size() - end_),
	   length - (buffer_.size() - end_));
    end_ = length - (buffer_.size() - end_);
  }

  dataSize_ += length;
  return USUCCESS;
}

void
UQueue::adapt(size_t toPop)
{
  ++nbPopCall_;
  topDataSize_ = std::max (topDataSize_, dataSize_);
  topOutputSize_ = std::max (topOutputSize_, toPop);

  if (adaptive_ < nbPopCall_)
  {
    // time out
    if (topOutputSize_ < outputBuffer_.size() * 0.8)
      outputBuffer_.resize(topOutputSize_ * 2);

    if (topDataSize_ < buffer_.size() * 0.8)
    {
      // We shrink the buffer to the new size: topDataSize_ + 10% (if it fits)
      enlarge(topDataSize_);
      if (end_ < start_)
      {
	// The data is splitted
	memmove(&buffer_[0] + start_ - (buffer_.size() - topDataSize_),
		&buffer_[0] + start_, buffer_.size() - start_);
	start_ = start_ - (buffer_.size() - topDataSize_);
      }
      else
      {
	// The data is contiguous
	memmove(&buffer_[0], &buffer_[0] + start_, dataSize_);
	start_ = 0;
	end_   = dataSize_;
	// the case end_ == buffer_.size() is handled below.
      }

      buffer_.resize(topDataSize_);
      if (end_ == buffer_.size() )
	end_ =0; // loop the circular geometry.
      // else... well it should never come to this else anyway.
    }

    // reset.
    nbPopCall_ = 0;
    topDataSize_   = 0;
    topOutputSize_ = 0;
  }
}

//! Pops 'length' bytes out of the Queue
/*! Pops 'length' bytes.
    The ubyte* pointer returned is not permanent. You have to make a copy of the
    data pointed if you want to keep it. Any call to a member function of UQueue
    might alter it later.

    \param length the length requested.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::pop (size_t length)
{
  // Actual size of the data to pop.
  size_t toPop = length;
  if (toPop > dataSize_)
    return 0; // Not enough data to pop 'length'

  if (toPop == 0)
    // Pops nothing but gets a pointer to the beginning of the buffer.
    return &buffer_[0] + start_;

  // Adaptive shrinking behavior
  if (adaptive_)
    adapt(toPop);

  if (buffer_.size() - start_ >= toPop)
  {
    // Is the packet continuous across the the internal buffer?  yes,
    // the packet is continuous in the internal buffer
    size_t start = start_;
    start_ += toPop;
    if (start_ == buffer_.size())
      start_ = 0; // loop the circular geometry.
    dataSize_ -= toPop;
    return &buffer_[0] + start;
  }
  else
  {
    // no, the packet spans then end and the beginning of the buffer
    // and it must be reconstructed.

    // Is the temporary internal outputBuffer large enough?
    if (outputBuffer_.size() < toPop)
      outputBuffer_.resize(toPop * 2);

    memcpy(&outputBuffer_[0],
	   &buffer_[0] + start_,
	   buffer_.size() - start_);

    memcpy(&outputBuffer_[0] + (buffer_.size() - start_ ),
	   &buffer_[0],
	   toPop - (buffer_.size() - start_));

    start_ = toPop - (buffer_.size() - start_);
    dataSize_ -= toPop;

    return &outputBuffer_[0];
  }
}

//! Pops at most 'length' bytes out of the Queue
/*! Pops at most 'length' bytes. The actual size is returned in 'length'.
    The ubyte* pointer returned is not permanent. You have to make a copy of the
    data pointed if you want to keep it. Any call to a member function of UQueue
    might alter it later.

    This method is called "fast" because is will not use the temporary
    outputBuffer if the requested data is half at the end and half at the
    beginning of the buffer. It will return only the part at the end of the
    buffer and return the actual size of data popped. You have to check if this
    value is equal to the requested length. If it is not, a second call to
    fastPop will give you the rest of the buffer, with a different pointer.
    This function is useful if you plan to pop huge amount of data which will
    probably span over the end of the buffer and which would, with a simple
    call to 'pop', result in a huge memory replication. In other cases, prefer
    'pop', which is most of the time as efficient as fastPop and much more
    convenient to use.

    \param length the length requested. Contains the actual length popped.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::fastPop (size_t &length)
{
  return pop((length > buffer_.size() - start_)
	     ? (length = buffer_.size() - start_)
	     : length);
}

//! Simulates the pop of 'length' bytes out of the Queue
/*! Behave like pop but simulate the effect. This is useful if one wants to try
    something with the popped buffer and check the validity before actually
    popping the data.
    It is also typically used when trying to send bytes in a connection and
    it is not known in advance how many bytes will be effectively sent.

    \param length the length requested.
    \return a pointer to the the data popped or 0 in case of error.
*/
ubyte*
UQueue::virtualPop (size_t length)
{
  // Actual size of the data to pop.
  size_t toPop = length;
  if (toPop > dataSize_)
    return 0; // Not enough data to pop 'length'
  if (toPop == 0)
    // Pops nothing but gets a pointer to the beginning of the buffer.
    return &buffer_[0] + start_;

  // Is the packet continuous across the internal buffer?
  if (buffer_.size() - start_ >= toPop)
    // yes, the packet is continuous in the internal buffer
    return &buffer_[0] + start_;
  else
  {
    // no, the packet spans then end and the beginning of the buffer
    // and it must be reconstructed.

    // Is the temporary internal outputBuffer large enough?
    if (outputBuffer_.size() < toPop)
      outputBuffer_.resize(toPop * 2);

    memcpy(&outputBuffer_[0],
	   &buffer_[0] + start_,
	   buffer_.size() - start_);

    memcpy(&outputBuffer_[0] + (buffer_.size() - start_),
	   &buffer_[0],
	   toPop - (buffer_.size() - start_));

    //start_ = toPop - (buffer_.size() - start_);
    //dataSize_ -= toPop;

    return &outputBuffer_[0];
  }
}
<|endoftext|>


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

#ifndef XXH64_HPP
#define XXH64_HPP

#include <string>
#include <cstdint>

#include "lz4/xxhash.h"

class xxh64 {
	static constexpr uint64_t PRIME1 = 11400714785074694791ULL;
	static constexpr uint64_t PRIME2 = 14029467366897019727ULL;
	static constexpr uint64_t PRIME3 =  1609587929392839161ULL;
	static constexpr uint64_t PRIME4 =  9650029242287828579ULL;
	static constexpr uint64_t PRIME5 =  2870177450012600261ULL;

	static constexpr uint64_t rotl(uint64_t x, int r) {
		return ((x << r) | (x >> (64 - r)));
	}
	static constexpr uint64_t mix1(const uint64_t h, const uint64_t prime, int rshift) {
		return (h ^ (h >> rshift)) * prime;
	}
	static constexpr uint64_t mix2(const uint64_t p, const uint64_t v = 0) {
		return rotl (v + p * PRIME2, 31) * PRIME1;
	}
	static constexpr uint64_t mix3(const uint64_t h, const uint64_t v) {
		return (h ^ mix2 (v)) * PRIME1 + PRIME4;
	}
#ifdef XXH64_BIG_ENDIAN
	static constexpr uint32_t endian32(const char *v) {
		return uint32_t(uint8_t(v[3]))|(uint32_t(uint8_t(v[2]))<<8)
			   |(uint32_t(uint8_t(v[1]))<<16)|(uint32_t(uint8_t(v[0]))<<24);
	}
	static constexpr uint64_t endian64(const char *v) {
		return uint64_t(uint8_t(v[7]))|(uint64_t(uint8_t(v[6]))<<8)
			   |(uint64_t(uint8_t(v[5]))<<16)|(uint64_t(uint8_t(v[4]))<<24)
			   |(uint64_t(uint8_t(v[3]))<<32)|(uint64_t(uint8_t(v[2]))<<40)
			   |(uint64_t(uint8_t(v[1]))<<48)|(uint64_t(uint8_t(v[0]))<<56);
	}
#else
	static constexpr uint32_t endian32(const char *v) {
		return uint32_t(uint8_t(v[0]))|(uint32_t(uint8_t(v[1]))<<8)
			   |(uint32_t(uint8_t(v[2]))<<16)|(uint32_t(uint8_t(v[3]))<<24);
	}
	static constexpr uint64_t endian64 (const char *v) {
		return uint64_t(uint8_t(v[0]))|(uint64_t(uint8_t(v[1]))<<8)
			   |(uint64_t(uint8_t(v[2]))<<16)|(uint64_t(uint8_t(v[3]))<<24)
			   |(uint64_t(uint8_t(v[4]))<<32)|(uint64_t(uint8_t(v[5]))<<40)
			   |(uint64_t(uint8_t(v[6]))<<48)|(uint64_t(uint8_t(v[7]))<<56);
	}
#endif
	static constexpr uint64_t fetch64(const char *p, const uint64_t v = 0) {
		return mix2 (endian64 (p), v);
	}
	static constexpr uint64_t fetch32(const char *p) {
		return uint64_t (endian32 (p)) * PRIME1;
	}
	static constexpr uint64_t fetch8(const char *p) {
		return uint8_t (*p) * PRIME5;
	}
	static constexpr uint64_t finalize(const uint64_t h, const char *p, uint64_t len) {
		return (len >= 8) ? (finalize (rotl (h ^ fetch64 (p), 27) * PRIME1 + PRIME4, p + 8, len - 8)) :
			   ((len >= 4) ? (finalize (rotl (h ^ fetch32 (p), 23) * PRIME2 + PRIME3, p + 4, len - 4)) :
				((len > 0) ? (finalize (rotl (h ^ fetch8 (p), 11) * PRIME1, p + 1, len - 1)) :
				 (mix1 (mix1 (mix1 (h, PRIME2, 33), PRIME3, 29), 1, 32))));
	}
	static constexpr uint64_t h32bytes(const char *p, uint64_t len, const uint64_t v1,const uint64_t v2, const uint64_t v3, const uint64_t v4) {
		return (len >= 32) ? h32bytes (p + 32, len - 32, fetch64 (p, v1), fetch64 (p + 8, v2), fetch64 (p + 16, v3), fetch64 (p + 24, v4)) :
			   mix3 (mix3 (mix3 (mix3 (rotl (v1, 1) + rotl (v2, 7) + rotl (v3, 12) + rotl (v4, 18), v1), v2), v3), v4);
	}
	static constexpr uint64_t h32bytes(const char *p, uint64_t len, const uint64_t seed) {
		return h32bytes (p, len, seed + PRIME1 + PRIME2, seed + PRIME2, seed, seed - PRIME1);
	}

public:
	static constexpr uint64_t hash(const char *p, uint64_t len, uint64_t seed=0) {
		return finalize((len >= 32 ? h32bytes(p, len, seed) : seed + PRIME5) + len, p + (len & ~0x1F), len & 0x1F);
	}

	template <size_t N>
	static constexpr uint64_t hash(const char(&s)[N], uint64_t seed=0) {
		return hash(s, N - 1, seed);
	}

	static uint64_t hash(string_view str, uint64_t seed=0) {
		return XXH64(str.data(), str.size(), seed);
	}
};

constexpr uint32_t operator"" _XXH(const char* s, size_t size) {
	return xxh64::hash(s, size, 0);
}

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

#ifndef XXH64_HPP
#define XXH64_HPP

#include <string>
#include <cstdint>

#include "string_view.h"

#include "lz4/xxhash.h"

class xxh64 {
	static constexpr uint64_t PRIME1 = 11400714785074694791ULL;
	static constexpr uint64_t PRIME2 = 14029467366897019727ULL;
	static constexpr uint64_t PRIME3 =  1609587929392839161ULL;
	static constexpr uint64_t PRIME4 =  9650029242287828579ULL;
	static constexpr uint64_t PRIME5 =  2870177450012600261ULL;

	static constexpr uint64_t rotl(uint64_t x, int r) {
		return ((x << r) | (x >> (64 - r)));
	}
	static constexpr uint64_t mix1(const uint64_t h, const uint64_t prime, int rshift) {
		return (h ^ (h >> rshift)) * prime;
	}
	static constexpr uint64_t mix2(const uint64_t p, const uint64_t v = 0) {
		return rotl (v + p * PRIME2, 31) * PRIME1;
	}
	static constexpr uint64_t mix3(const uint64_t h, const uint64_t v) {
		return (h ^ mix2 (v)) * PRIME1 + PRIME4;
	}
#ifdef XXH64_BIG_ENDIAN
	static constexpr uint32_t endian32(const char *v) {
		return uint32_t(uint8_t(v[3]))|(uint32_t(uint8_t(v[2]))<<8)
			   |(uint32_t(uint8_t(v[1]))<<16)|(uint32_t(uint8_t(v[0]))<<24);
	}
	static constexpr uint64_t endian64(const char *v) {
		return uint64_t(uint8_t(v[7]))|(uint64_t(uint8_t(v[6]))<<8)
			   |(uint64_t(uint8_t(v[5]))<<16)|(uint64_t(uint8_t(v[4]))<<24)
			   |(uint64_t(uint8_t(v[3]))<<32)|(uint64_t(uint8_t(v[2]))<<40)
			   |(uint64_t(uint8_t(v[1]))<<48)|(uint64_t(uint8_t(v[0]))<<56);
	}
#else
	static constexpr uint32_t endian32(const char *v) {
		return uint32_t(uint8_t(v[0]))|(uint32_t(uint8_t(v[1]))<<8)
			   |(uint32_t(uint8_t(v[2]))<<16)|(uint32_t(uint8_t(v[3]))<<24);
	}
	static constexpr uint64_t endian64 (const char *v) {
		return uint64_t(uint8_t(v[0]))|(uint64_t(uint8_t(v[1]))<<8)
			   |(uint64_t(uint8_t(v[2]))<<16)|(uint64_t(uint8_t(v[3]))<<24)
			   |(uint64_t(uint8_t(v[4]))<<32)|(uint64_t(uint8_t(v[5]))<<40)
			   |(uint64_t(uint8_t(v[6]))<<48)|(uint64_t(uint8_t(v[7]))<<56);
	}
#endif
	static constexpr uint64_t fetch64(const char *p, const uint64_t v = 0) {
		return mix2 (endian64 (p), v);
	}
	static constexpr uint64_t fetch32(const char *p) {
		return uint64_t (endian32 (p)) * PRIME1;
	}
	static constexpr uint64_t fetch8(const char *p) {
		return uint8_t (*p) * PRIME5;
	}
	static constexpr uint64_t finalize(const uint64_t h, const char *p, uint64_t len) {
		return (len >= 8) ? (finalize (rotl (h ^ fetch64 (p), 27) * PRIME1 + PRIME4, p + 8, len - 8)) :
			   ((len >= 4) ? (finalize (rotl (h ^ fetch32 (p), 23) * PRIME2 + PRIME3, p + 4, len - 4)) :
				((len > 0) ? (finalize (rotl (h ^ fetch8 (p), 11) * PRIME1, p + 1, len - 1)) :
				 (mix1 (mix1 (mix1 (h, PRIME2, 33), PRIME3, 29), 1, 32))));
	}
	static constexpr uint64_t h32bytes(const char *p, uint64_t len, const uint64_t v1,const uint64_t v2, const uint64_t v3, const uint64_t v4) {
		return (len >= 32) ? h32bytes (p + 32, len - 32, fetch64 (p, v1), fetch64 (p + 8, v2), fetch64 (p + 16, v3), fetch64 (p + 24, v4)) :
			   mix3 (mix3 (mix3 (mix3 (rotl (v1, 1) + rotl (v2, 7) + rotl (v3, 12) + rotl (v4, 18), v1), v2), v3), v4);
	}
	static constexpr uint64_t h32bytes(const char *p, uint64_t len, const uint64_t seed) {
		return h32bytes (p, len, seed + PRIME1 + PRIME2, seed + PRIME2, seed, seed - PRIME1);
	}

public:
	static constexpr uint64_t hash(const char *p, uint64_t len, uint64_t seed=0) {
		return finalize((len >= 32 ? h32bytes(p, len, seed) : seed + PRIME5) + len, p + (len & ~0x1F), len & 0x1F);
	}

	template <size_t N>
	static constexpr uint64_t hash(const char(&s)[N], uint64_t seed=0) {
		return hash(s, N - 1, seed);
	}

	static uint64_t hash(string_view str, uint64_t seed=0) {
		return XXH64(str.data(), str.size(), seed);
	}
};

constexpr uint32_t operator"" _XXH(const char* s, size_t size) {
	return xxh64::hash(s, size, 0);
}

#endif /* !defined XXH64_HPP */
<|endoftext|>


<commit_before>#include <string>
#include <sstream>
#include <unistd.h> // sysconf()?
#include <sys/sysinfo.h>
#include <linux/kernel.h> // SI_LOAD_SHIFT

#include "../luts.h"

std::string load_string( bool use_colors = false ) {
   std::ostringstream oss;

   float f = static_cast<float>(1 << SI_LOAD_SHIFT);

   struct sysinfo sinfo;
   sysinfo(&sinfo);

   if( use_colors ) {
      // Likely does not work on BSD, but not tested
      unsigned number_of_cpus = sysconf( _SC_NPROCESSORS_ONLN );

      float recent_load = sinfo.loads[0] / f;

      // colors range from zero to twice the number of cpu's
      // for the most recent load metric
      unsigned load_percent = static_cast< unsigned int >(
            recent_load / number_of_cpus * 0.5f * 100.0f );

      if( load_percent > 100 )
         load_percent = 100;

      oss << load_lut[load_percent];
   }

   // set precision so we get results like "0.22"
   oss.setf( std::ios::fixed );
   oss.precision(2);

   oss << sinfo.loads[0] / f << " " << sinfo.load[1] / f << " "
	 << sinfo.load[2] / f;

   if( use_colors )
      oss << "#[fg=default,bg=default]";

   return oss.str();
}
<commit_msg>added missing include "load.h"<commit_after>#include <string>
#include <sstream>
#include <unistd.h> // sysconf()?
#include <sys/sysinfo.h>
#include <linux/kernel.h> // SI_LOAD_SHIFT

#include "load.h"
#include "../luts.h"

std::string load_string( bool use_colors = false ) {
   std::ostringstream oss;

   float f = static_cast<float>(1 << SI_LOAD_SHIFT);

   struct sysinfo sinfo;
   sysinfo(&sinfo);

   if( use_colors ) {
      // Likely does not work on BSD, but not tested
      unsigned number_of_cpus = sysconf( _SC_NPROCESSORS_ONLN );

      float recent_load = sinfo.loads[0] / f;

      // colors range from zero to twice the number of cpu's
      // for the most recent load metric
      unsigned load_percent = static_cast< unsigned int >(
            recent_load / number_of_cpus * 0.5f * 100.0f );

      if( load_percent > 100 )
         load_percent = 100;

      oss << load_lut[load_percent];
   }

   // set precision so we get results like "0.22"
   oss.setf( std::ios::fixed );
   oss.precision(2);

   oss << sinfo.loads[0] / f << " " << sinfo.load[1] / f << " "
	 << sinfo.load[2] / f;

   if( use_colors )
      oss << "#[fg=default,bg=default]";

   return oss.str();
}
<|endoftext|>


<commit_before>#include <regex>
#include <ctime>

#include "tools.h"

void validarCedula(std::string cedula)
{
    std::regex cedulaRegex("\\d{10}");
    if (!std::regex_match(cedula, cedulaRegex))
        throw "Cédula no válida";
}

void validarTelefono(std::string telefono)
{
    std::regex telefonoRegex("\\d{10}");
    if (!std::regex_match(telefono, telefonoRegex))
        throw "Teléfono no válido";
}

void validarString(std::string str)
{
    if (str == "")
        throw "Cadena vacía";
}

void validarNumero(double num)
{
    if (num < 0)
        throw "Número negativo.";
}

std::string estadoToString(Estado estado)
{
    if (estado == Estado::libre)
        return "libre";
    else if (estado == Estado::mantenimiento)
        return "mantenimiento";
    else if (estado == Estado::ocupado)
        return "ocupado";
    else if (estado == Estado::reservado)
        return "reservado";
    else
        throw "Tipo de estado no valido.";
}

std::string getFecha(time_t *fecha)
{
    char buff[20];
    strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(fecha));
    return buff;
}

time_t getFechaString(std::string fecha)
{
    struct tm tm;
    strptime(fecha.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
    time_t t = mktime(&tm);  // t is now your desired time_t
    return t;
}

Horario getHorario(std::string horaEntrada, std::string horaSalida)
{
    Hora entrada, salida;
    std::vector<std::string> elementos = split(horaEntrada,':');
    entrada.hora = std::atoi(elementos[0].c_str());
    entrada.minuto = std::atoi(elementos[1].c_str());
    elementos.clear();
    elementos=split(horaSalida,':');
    salida.hora = std::atoi(elementos[0].c_str());
    salida.minuto = std::atoi(elementos[1].c_str());
    Horario horario;
    horario.entrada = entrada;
    horario.salida = salida;
    return horario;
}

std::vector<std::string> split(std::string texto, char delim)
{
    std::vector<std::string> elementos;
    std::string aux="";
    for(char a : texto){
        if(a!=delim){
            aux+=a;
        }else{
            elementos.push_back(aux);
            aux="";
        }
    }
    elementos.push_back(aux);
    return elementos;
}

void validarFechas(time_t fechaReservacion, time_t fechaFinReservacion)
{
    if (difftime(fechaReservacion, fechaFinReservacion) > 0)
        throw "Fecha final mayor a la inicial";
}
<commit_msg>implementado<commit_after>#include <regex>
#include <ctime>

#include "tools.h"

void validarCedula(std::string cedula)
{
    std::regex cedulaRegex("\\d{10}");
    if (!std::regex_match(cedula, cedulaRegex))
        throw "Cédula no válida";
}

void validarTelefono(std::string telefono)
{
    std::regex telefonoRegex("\\d{10}");
    if (!std::regex_match(telefono, telefonoRegex))
        throw "Teléfono no válido";
}

void validarString(std::string str)
{
    if (str == "")
        throw "Cadena vacía";
}

void validarNumero(double num)
{
    if (num < 0)
        throw "Número negativo.";
}

std::string estadoToString(Estado estado)
{
    if (estado == Estado::libre)
        return "libre";
    else if (estado == Estado::mantenimiento)
        return "mantenimiento";
    else if (estado == Estado::ocupado)
        return "ocupado";
    else if (estado == Estado::reservado)
        return "reservado";
    else
        throw "Tipo de estado no valido.";
}

std::string getFecha(time_t *fecha)
{
    char buff[20];
    strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(fecha));
    return buff;
}

time_t getFechaString(std::string fecha)
{
    struct tm tm;
    strptime(fecha.c_str(), "%Y-%m-%d %H:%M:%S", &tm);
    time_t t = mktime(&tm);  // t is now your desired time_t
    return t;
}

Horario getHorario(std::string horaEntrada, std::string horaSalida)
{
    Hora entrada, salida;
    std::vector<std::string> elementos = split(horaEntrada,':');
    entrada.hora = std::atoi(elementos[0].c_str());
    entrada.minuto = std::atoi(elementos[1].c_str());
    elementos.clear();
    elementos=split(horaSalida,':');
    salida.hora = std::atoi(elementos[0].c_str());
    salida.minuto = std::atoi(elementos[1].c_str());
    Horario horario;
    horario.entrada = entrada;
    horario.salida = salida;
    return horario;
}

std::vector<std::string> split(std::string texto, char delim)
{
    std::vector<std::string> elementos;
    std::string aux="";
    for(char a : texto){
        if(a!=delim){
            aux+=a;
        }else{
            elementos.push_back(aux);
            aux="";
        }
    }
    elementos.push_back(aux);
    return elementos;
}

void validarFechas(time_t fechaReservacion, time_t fechaFinReservacion)
{
    if (difftime(fechaReservacion, fechaFinReservacion) > 0)
        throw "Fecha final mayor a la inicial";
}

Estado getEstado(std::string estadoEspacio)
{
    if (estadoEspacio == "libre")
        return Estado::libre;
    else if (estadoEspacio == "ocupado")
        return Estado::ocupado;
    else if (estadoEspacio == "reservado")
        return Estado::reservado;
    else if (estadoEspacio == "mantenimiento")
        return Estado::mantenimiento;
    else
        throw "Estado no válido";
}
<|endoftext|>


<commit_before>#define __CL_ENABLE_EXCEPTIONS
#define _IN_HOST

#include <CL/cl.hpp>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <bitset>
#include "DeviceInfo.h"
#include "SharedMacros.h"
#include "SharedTypes.h"
#include "Packet.h"

const char *KERNEL_NAME = "vm";
const char *KERNEL_FILE = "kernels/vm.cl";
const char *KERNEL_BUILD_OPTIONS = "-I include";

const int NPACKET_SHIFT = ((NBYTES * 8) - 16);
const int FS_Length = 32;
const long F_Length = 0x0000ffff00000000;

void toggleState(cl::CommandQueue& commandQueue, cl::Buffer& stateBuffer, int *state);
subt *createSubt();
void validateArguments(int argc);
std::deque<bytecode> readBytecode(char *bytecodeFile);
std::deque< std::deque<bytecode> > words2Packets(std::deque<bytecode>& bytecodeWords);

int main(int argc, char **argv) {
  validateArguments(argc);

  std::vector<cl::Platform> platforms;
  std::vector<cl::Device> devices;
  cl::Device device;
  cl::Program program;

  DeviceInfo deviceInfo;

  try {
    /* Create a vector of available platforms. */
    cl::Platform::get(&platforms);

    /* Create a vector of available devices (GPU Priority). */
    try {
      /* Use CPU for debugging */
      platforms[0].getDevices(CL_DEVICE_TYPE_CPU, &devices);

      /* Use GPU in practice. */
      // platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
    } catch (cl::Error error) {
      platforms[0].getDevices(CL_DEVICE_TYPE_CPU, &devices);
    }

    /* Create a platform context for the available devices. */
    cl::Context context(devices);

    /* Use the first available device. */
    device = devices[0];

    /* Get the number of compute units for the device. */
    int computeUnits = deviceInfo.max_compute_units(device);

    /* Get the global memory size (in bytes) of the device. */
    // long globalMemSize = deviceInfo.global_mem_size(device);

    /* Create a command queue for the device. */
    cl::CommandQueue commandQueue = cl::CommandQueue(context, device);

    /* Read the kernel program source. */
    std::ifstream kernelSourceFile(KERNEL_FILE);
    std::string kernelSource(std::istreambuf_iterator<char>(kernelSourceFile), (std::istreambuf_iterator<char>()));
    cl::Program::Sources source(1, std::make_pair(kernelSource.c_str(), kernelSource.length() + 1));

    /* Create a program in the context using the kernel source code. */
    program = cl::Program(context, source);

    /* Build the program for the available devices. */
    program.build(devices, KERNEL_BUILD_OPTIONS);

    /* Create the kernel. */
    cl::Kernel kernel(program, KERNEL_NAME);

    /* Calculate the number of queues we need. */
    int nQueues = computeUnits * computeUnits;

    /* Calculate the memory required to store the queues. The first nQueue packets are used to store
       information regarding the queues themselves (head index, tail index and last operation performed). */
    int qBufSize = (nQueues * QUEUE_SIZE) + nQueues;

    /* Allocate memory for the queues. */
    packet *queues = new packet[qBufSize];
    packet *readQueues = new packet[qBufSize];

    /* Initialise queue elements to zero. */
    for (int i = 0; i < qBufSize; i++) {
      queues[i].x = 0;
      queues[i].y = 0;
      readQueues[i].x = 0;
      readQueues[i].y = 0;
    }

    /* Which stage of the READ/WRITE cycle are we in? */
    int *state = new int;
    *state = WRITE;

    /* The code store stores bytecode in QUEUE_SIZE chunks. */
    bytecode *codeStore = new bytecode[CODE_STORE_SIZE * QUEUE_SIZE];

    /* Read the bytecode from file. */
    std::deque<bytecode> bytecodeWords = readBytecode(argv[1]);
    std::deque< std::deque<bytecode> > packets = words2Packets(bytecodeWords);

    /* Populate the code store. */
    codeStore[0] = 0x0000000300000000UL;
    codeStore[1] = 0x4000000100000000UL;
    codeStore[2] = 0x4000000200000000UL;
    codeStore[3] = 0x4000000300000000UL;

    codeStore[16] = 0x0000000100000100UL;
    codeStore[17] = 0x6040000000000000UL;

    codeStore[32] = 0x0000000100000100UL;
    codeStore[33] = 0x6040000000000001UL;

    codeStore[48] = 0x0000000100000100UL;
    codeStore[49] = 0x6040000000000002UL;

    /* Create initial packet. */
    packet p = pkt_create(REFERENCE, computeUnits + 1, 0, 0, 0);
    queues[nQueues] = p;   // Initial packet.
    queues[0].x = 1 << 16; // Tail index is 1.
    queues[0].y = WRITE;   // Last operation is write.

    /* The subtask table. */
    subt *subtaskTable = createSubt();

    long avGlobalMemSize = 1024 * 1024 * 1024; // In bytes.
    long dataSize = avGlobalMemSize / 4; // How many 32-bit integers?

    /* Each computate unit has its own data array for storing temporary results. [input][data] */
    cl_uint *data = new cl_uint[avGlobalMemSize];

    /* Write input data to data buffer. */

    /* :1        :255            :X        :Y
       nargs     narg0..nargN    in/out    scratch */
    data[0] = 3;
    data[1] = 256;
    data[2] = 256 + 1;
    data[3] = 256 + 2;
    data[data[0] + 1] = 256 + 3;

    data[256] = 2;
    data[256 + 1] = 7;

    /* Create memory buffers on the device. */
    cl::Buffer qBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, qBufSize * sizeof(packet));
    commandQueue.enqueueWriteBuffer(qBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), queues);

    cl::Buffer rqBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, qBufSize * sizeof(packet));
    commandQueue.enqueueWriteBuffer(rqBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), readQueues);

    cl::Buffer stateBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, sizeof(int));
    commandQueue.enqueueWriteBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);

    cl::Buffer codeStoreBuffer = cl::Buffer(context, CL_MEM_READ_ONLY, CODE_STORE_SIZE * QUEUE_SIZE * sizeof(bytecode));
    commandQueue.enqueueWriteBuffer(codeStoreBuffer, CL_TRUE, 0, CODE_STORE_SIZE * QUEUE_SIZE * sizeof(bytecode), codeStore);

    cl::Buffer subtaskTableBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, sizeof(subt));
    commandQueue.enqueueWriteBuffer(subtaskTableBuffer, CL_TRUE, 0, sizeof(subt), subtaskTable);

    cl::Buffer dataBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, dataSize * sizeof(cl_uint));
    commandQueue.enqueueWriteBuffer(dataBuffer, CL_TRUE, 0, dataSize * sizeof(cl_uint), data);

    /* Set kernel arguments. */
    kernel.setArg(0, qBuffer);
    kernel.setArg(1, rqBuffer);
    kernel.setArg(2, computeUnits);
    kernel.setArg(3, stateBuffer);
    kernel.setArg(4, codeStoreBuffer);
    kernel.setArg(5, subtaskTableBuffer);
    kernel.setArg(6, dataBuffer);

    /* Set the NDRange. */
    cl::NDRange global(computeUnits), local(computeUnits);

    /* Run the kernel on NDRange until completion. */
    while (*state != COMPLETE) {
      commandQueue.enqueueNDRangeKernel(kernel, cl::NullRange, global, local);
      commandQueue.finish();
      toggleState(commandQueue, stateBuffer, state);
    }

    /* Read the modified buffers. */
    commandQueue.enqueueReadBuffer(qBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), queues);
    commandQueue.enqueueReadBuffer(dataBuffer, CL_TRUE, 0, dataSize * sizeof(cl_uint), data);

    /* Print the queue details. */
    for (int i = 0; i < nQueues; i++) {
      int x = ((queues[i].x & 0xFFFF0000) >> 16);
      int y = queues[i].x & 0xFFFF;
      std::cout << "(" << x << "," << y << " " << queues[i].y << ")" << " ";
    }
    std::cout << std::endl;
    std::cout << std::endl;

    /* Print the queues. */
    for (int i = nQueues; i < qBufSize; i++) {
      if ((i % QUEUE_SIZE) == 0) std::cout << std::endl;
      std::cout << "(" << queues[i].x << " " << queues[i].y << ")" << " ";
    }
    std::cout << std::endl;

    std::cout << "Result: " << data[258] << std::endl;

    /* Cleanup */
    delete[] queues;
    delete[] readQueues;
    delete[] codeStore;
    delete[] data;
    delete subtaskTable;
    delete state;
  } catch (cl::Error error) {
    std::cout << "EXCEPTION: " << error.what() << " [" << error.err() << "]" << std::endl;
    std::cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << std::endl;
  }

  return 0;
}

void toggleState(cl::CommandQueue& commandQueue, cl::Buffer& stateBuffer, int *state) {
  commandQueue.enqueueReadBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);
  if (*state == COMPLETE) return;
  *state = (*state == WRITE) ? READ : WRITE;
  commandQueue.enqueueWriteBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);
  commandQueue.finish();
}

subt *createSubt() {
  subt *table = new subt;

  if (table) {
    table->av_recs[0] = 1; // The first element is the top of stack index.

    /* Populate the stack with the available records in the subtask table. */
    for (int i = 1; i < SUBT_SIZE + 1; i++) {
      table->av_recs[i] = i - 1;
    }
  }

  return table;
}

void validateArguments(int argc) {
  if (argc < 2) {
    std::cout << "Usage: ./vm [bytecode-file]" << std::endl;
    exit(EXIT_FAILURE);
  }
}

std::deque<bytecode> readBytecode(char *bytecodeFile) {
  std::ifstream f(bytecodeFile);
  std::deque<bytecode> bytecodeWords;

  if (f.is_open()) {
    while (f.good()) {
      bytecode word = 0;
      for (int i = 0; i < NBYTES; i++) {
        char c = f.get();
        word = (word << NBYTES) + c;
      }
      bytecodeWords.push_back(word);
    }
  }

  return bytecodeWords;
}

std::deque< std::deque<bytecode> > words2Packets(std::deque<bytecode>& bytecodeWords) {
  int nPackets = bytecodeWords.front() >> NPACKET_SHIFT;
  std::deque< std::deque<bytecode> > packets;
  for (int p = 0; p < nPackets; p++) {
    std::deque<bytecode> packet;

    int length = 0;
    for (int i = 0; i < 3; i++) {
      bytecode headerWord = bytecodeWords.front();
      bytecodeWords.pop_front();
      if (i == 1) {
	length = (headerWord & F_Length) >> FS_Length;
      }
    }

    for (int i = 0; i < length; i++) {
      bytecode payloadWord = bytecodeWords.front();
      bytecodeWords.pop_front();
      packet.push_back(payloadWord);
    }

    packets.push_back(packet);
  }

  return packets;
}
<commit_msg>Corrected bug in words2Packets function.<commit_after>#define __CL_ENABLE_EXCEPTIONS
#define _IN_HOST

#include <CL/cl.hpp>
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <bitset>
#include "DeviceInfo.h"
#include "SharedMacros.h"
#include "SharedTypes.h"
#include "Packet.h"

const char *KERNEL_NAME = "vm";
const char *KERNEL_FILE = "kernels/vm.cl";
const char *KERNEL_BUILD_OPTIONS = "-I include";

const int NPACKET_SHIFT = ((NBYTES * 8) - 16);
const int FS_Length = 32;
const long F_Length = 0x0000ffff00000000;

void toggleState(cl::CommandQueue& commandQueue, cl::Buffer& stateBuffer, int *state);
subt *createSubt();
void validateArguments(int argc);
std::deque<bytecode> readBytecode(char *bytecodeFile);
std::deque< std::deque<bytecode> > words2Packets(std::deque<bytecode>& bytecodeWords);

int main(int argc, char **argv) {
  validateArguments(argc);

  std::vector<cl::Platform> platforms;
  std::vector<cl::Device> devices;
  cl::Device device;
  cl::Program program;

  DeviceInfo deviceInfo;

  try {
    /* Create a vector of available platforms. */
    cl::Platform::get(&platforms);

    /* Create a vector of available devices (GPU Priority). */
    try {
      /* Use CPU for debugging */
      platforms[0].getDevices(CL_DEVICE_TYPE_CPU, &devices);

      /* Use GPU in practice. */
      // platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
    } catch (cl::Error error) {
      platforms[0].getDevices(CL_DEVICE_TYPE_CPU, &devices);
    }

    /* Create a platform context for the available devices. */
    cl::Context context(devices);

    /* Use the first available device. */
    device = devices[0];

    /* Get the number of compute units for the device. */
    int computeUnits = deviceInfo.max_compute_units(device);

    /* Get the global memory size (in bytes) of the device. */
    // long globalMemSize = deviceInfo.global_mem_size(device);

    /* Create a command queue for the device. */
    cl::CommandQueue commandQueue = cl::CommandQueue(context, device);

    /* Read the kernel program source. */
    std::ifstream kernelSourceFile(KERNEL_FILE);
    std::string kernelSource(std::istreambuf_iterator<char>(kernelSourceFile), (std::istreambuf_iterator<char>()));
    cl::Program::Sources source(1, std::make_pair(kernelSource.c_str(), kernelSource.length() + 1));

    /* Create a program in the context using the kernel source code. */
    program = cl::Program(context, source);

    /* Build the program for the available devices. */
    program.build(devices, KERNEL_BUILD_OPTIONS);

    /* Create the kernel. */
    cl::Kernel kernel(program, KERNEL_NAME);

    /* Calculate the number of queues we need. */
    int nQueues = computeUnits * computeUnits;

    /* Calculate the memory required to store the queues. The first nQueue packets are used to store
       information regarding the queues themselves (head index, tail index and last operation performed). */
    int qBufSize = (nQueues * QUEUE_SIZE) + nQueues;

    /* Allocate memory for the queues. */
    packet *queues = new packet[qBufSize];
    packet *readQueues = new packet[qBufSize];

    /* Initialise queue elements to zero. */
    for (int i = 0; i < qBufSize; i++) {
      queues[i].x = 0;
      queues[i].y = 0;
      readQueues[i].x = 0;
      readQueues[i].y = 0;
    }

    /* Which stage of the READ/WRITE cycle are we in? */
    int *state = new int;
    *state = WRITE;

    /* The code store stores bytecode in QUEUE_SIZE chunks. */
    bytecode *codeStore = new bytecode[CODE_STORE_SIZE * QUEUE_SIZE];

    /* Read the bytecode from file. */
    std::deque<bytecode> bytecodeWords = readBytecode(argv[1]);
    std::deque< std::deque<bytecode> > packets = words2Packets(bytecodeWords);

    /* Populate the code store. */
    for (std::deque< std::deque<bytecode> >::iterator iterP = packets.begin(); iterP != packets.end(); iterP++) {
      std::deque<bytecode> packet = *iterP;
      for (std::deque<bytecode>::iterator iterW = packet.begin(); iterW != packet.end(); iterW++) {
	bytecode word = *iterW;
	std::bitset<64> x(word);
	std::cout << x << std::endl;
        int packetN = iterP - packets.begin(); // Which packet?
        int wordN = iterW - packet.begin(); // Which word?
	codeStore[(packetN * QUEUE_SIZE) + wordN] = word;
      }
      std::cout << std::endl;
    }

    /* Create initial packet. */
    packet p = pkt_create(REFERENCE, computeUnits + 1, 0, 0, 0);
    queues[nQueues] = p;   // Initial packet.
    queues[0].x = 1 << 16; // Tail index is 1.
    queues[0].y = WRITE;   // Last operation is write.

    /* The subtask table. */
    subt *subtaskTable = createSubt();

    long avGlobalMemSize = 1024 * 1024 * 1024; // In bytes.
    long dataSize = avGlobalMemSize / 4; // How many 32-bit integers?

    /* Each computate unit has its own data array for storing temporary results. [input][data] */
    cl_uint *data = new cl_uint[avGlobalMemSize];

    /* Write input data to data buffer. */

    /* :1        :255            :X        :Y
       nargs     narg0..nargN    in/out    scratch */
    data[0] = 3;
    data[1] = 256;
    data[2] = 256 + 1;
    data[3] = 256 + 2;
    data[data[0] + 1] = 256 + 3;

    data[256] = 2;
    data[256 + 1] = 7;

    /* Create memory buffers on the device. */
    cl::Buffer qBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, qBufSize * sizeof(packet));
    commandQueue.enqueueWriteBuffer(qBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), queues);

    cl::Buffer rqBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, qBufSize * sizeof(packet));
    commandQueue.enqueueWriteBuffer(rqBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), readQueues);

    cl::Buffer stateBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, sizeof(int));
    commandQueue.enqueueWriteBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);

    cl::Buffer codeStoreBuffer = cl::Buffer(context, CL_MEM_READ_ONLY, CODE_STORE_SIZE * QUEUE_SIZE * sizeof(bytecode));
    commandQueue.enqueueWriteBuffer(codeStoreBuffer, CL_TRUE, 0, CODE_STORE_SIZE * QUEUE_SIZE * sizeof(bytecode), codeStore);

    cl::Buffer subtaskTableBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, sizeof(subt));
    commandQueue.enqueueWriteBuffer(subtaskTableBuffer, CL_TRUE, 0, sizeof(subt), subtaskTable);

    cl::Buffer dataBuffer = cl::Buffer(context, CL_MEM_READ_WRITE, dataSize * sizeof(cl_uint));
    commandQueue.enqueueWriteBuffer(dataBuffer, CL_TRUE, 0, dataSize * sizeof(cl_uint), data);

    /* Set kernel arguments. */
    kernel.setArg(0, qBuffer);
    kernel.setArg(1, rqBuffer);
    kernel.setArg(2, computeUnits);
    kernel.setArg(3, stateBuffer);
    kernel.setArg(4, codeStoreBuffer);
    kernel.setArg(5, subtaskTableBuffer);
    kernel.setArg(6, dataBuffer);

    /* Set the NDRange. */
    cl::NDRange global(computeUnits), local(computeUnits);

    /* Run the kernel on NDRange until completion. */
    while (*state != COMPLETE) {
      commandQueue.enqueueNDRangeKernel(kernel, cl::NullRange, global, local);
      commandQueue.finish();
      toggleState(commandQueue, stateBuffer, state);
    }

    /* Read the modified buffers. */
    commandQueue.enqueueReadBuffer(qBuffer, CL_TRUE, 0, qBufSize * sizeof(packet), queues);
    commandQueue.enqueueReadBuffer(dataBuffer, CL_TRUE, 0, dataSize * sizeof(cl_uint), data);

    /* Print the queue details. */
    for (int i = 0; i < nQueues; i++) {
      int x = ((queues[i].x & 0xFFFF0000) >> 16);
      int y = queues[i].x & 0xFFFF;
      std::cout << "(" << x << "," << y << " " << queues[i].y << ")" << " ";
    }
    std::cout << std::endl;
    std::cout << std::endl;

    /* Print the queues. */
    for (int i = nQueues; i < qBufSize; i++) {
      if ((i % QUEUE_SIZE) == 0) std::cout << std::endl;
      std::cout << "(" << queues[i].x << " " << queues[i].y << ")" << " ";
    }
    std::cout << std::endl;

    std::cout << "Result: " << data[258] << std::endl;

    /* Cleanup */
    delete[] queues;
    delete[] readQueues;
    delete[] codeStore;
    delete[] data;
    delete subtaskTable;
    delete state;
  } catch (cl::Error error) {
    std::cout << "EXCEPTION: " << error.what() << " [" << error.err() << "]" << std::endl;
    std::cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device) << std::endl;
  }

  return 0;
}

void toggleState(cl::CommandQueue& commandQueue, cl::Buffer& stateBuffer, int *state) {
  commandQueue.enqueueReadBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);
  if (*state == COMPLETE) return;
  *state = (*state == WRITE) ? READ : WRITE;
  commandQueue.enqueueWriteBuffer(stateBuffer, CL_TRUE, 0, sizeof(int), state);
  commandQueue.finish();
}

subt *createSubt() {
  subt *table = new subt;

  if (table) {
    table->av_recs[0] = 1; // The first element is the top of stack index.

    /* Populate the stack with the available records in the subtask table. */
    for (int i = 1; i < SUBT_SIZE + 1; i++) {
      table->av_recs[i] = i - 1;
    }
  }

  return table;
}

void validateArguments(int argc) {
  if (argc < 2) {
    std::cout << "Usage: ./vm [bytecode-file]" << std::endl;
    exit(EXIT_FAILURE);
  }
}

std::deque<bytecode> readBytecode(char *bytecodeFile) {
  std::ifstream f(bytecodeFile);
  std::deque<bytecode> bytecodeWords;

  if (f.is_open()) {
    while (f.good()) {
      bytecode word = 0;
      for (int i = 0; i < NBYTES; i++) {
        char c = f.get();
        word = (word << NBYTES) + c;
      }
      bytecodeWords.push_back(word);
    }
  }

  return bytecodeWords;
}

std::deque< std::deque<bytecode> > words2Packets(std::deque<bytecode>& bytecodeWords) {
  int nPackets = bytecodeWords.front() >> NPACKET_SHIFT; bytecodeWords.pop_front();
  std::deque< std::deque<bytecode> > packets;
  for (int p = 0; p < nPackets; p++) {
    std::deque<bytecode> packet;

    int length = 0;
    for (int i = 0; i < 3; i++) {
      bytecode headerWord = bytecodeWords.front();
      bytecodeWords.pop_front();
      if (i == 0) {
        length = (headerWord & F_Length) >> FS_Length;
      }
    }

    for (int i = 0; i < length; i++) {
      bytecode payloadWord = bytecodeWords.front();
      bytecodeWords.pop_front();
      packet.push_back(payloadWord);
    }

    packets.push_back(packet);
  }

  return packets;
}
<|endoftext|>


<commit_before>// symbiosis: A hacky and lightweight compiler framework
//
#include "symbiosis.hpp"
#include <sys/stat.h>

#include <iostream>

#include <vector>

using namespace std;

namespace symbiosis {

  bool am_i_pic = false;

  class exception : public std::exception {
    const char *what_;
  public:
    exception(const char *w) : what_(w) { }
    virtual ~exception() throw() { }
    virtual const char* what() const throw() { return what_; }
  };

  char *command_file = 0;;

  #define M10(v, b) #v #b
  #define M3(a,b) M10(a+1000, v),M10(a+2000, v), M10(a+3000, v),M10(a+4000, v)
  #define M2(a,b) M3(a+100, v) , M3(a+200, v) , M3(a+300, v) , M3(a+400, v)
  #define M1(a,b) M2(a+10, v) , M2(a+20, v) , M2(a+30, v) , M2(a+40, v)
  #define M(v) M1(1, v), M1(2, v), M1(3, v), M1(4, v), M1(5, v)

  uchar *virtual_code_start = 0;
  uchar *virtual_code_end = 0;

  uchar *out_code_start = 0;
  uchar *out_code_end = 0;
  uchar *out_c = 0;
  uchar *out_c0 = 0;

  uchar *virtual_strings_start = 0;
  uchar *virtual_strings_end = 0;
  uchar *out_strings_start = 0;
  uchar *out_strings_end = 0;
  uchar *out_s = 0;

  #define STRINGS_START "STRINGS_START"
  #define STRINGS_END "STRINGS_END"

  unsigned int _i32 = 0;

  const char* id::i32() {
    if (virtual_adr) { _i32 = (size_t)virtual_adr;
         //printf("virtual_adr: %x\n", _i32);
        return (const char*)&_i32; }
    if (type == T_UINT) return (const char*)&d.ui;
    return (const char*)&d.i;
  }
  const char* id::i64() {
    if (type == T_ULONG) return (const char*)&d.ul;
    return (const char*)&d.l;
  }
  vector<const char*> type_str = { "0:???", "int", "uint", "long", "ulong",
      "charp", "float", "double"};

  void id::describe() {
    if (type > type_str.size() - 1) {
      cout << "<id:" << type << ">";
    } else {
      cout << type_str[type];
    }
    cout << endl;
  }
  id  id::operator()(id i) { add_parameter(i); return i; }

  id_new::id_new(const char *p) : id(p) {
    virtual_adr = virtual_strings_start + (out_s - out_strings_start);
    virtual_size = strlen(p);
    if (out_s + virtual_size + 1 > out_strings_end)
        throw exception("Strings: Out of memory");
    memcpy(out_s, p, virtual_size + 1);
    out_s += virtual_size + 1;
  };

  const char *reserved_strings[] = { STRINGS_START,
  M(ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
  STRINGS_END };

#define FIND(v) { \
  pos = 0; \
  bool found = false; \
  for (size_t i = 0; !found && i < (input_size - v##_s); i++) { \
    for (int j = 0; j < v##_s; j++) { \
      if (buf[i + j] != v[j]) break; \
      if (j == v##_s - 1) { \
        pos = i; \
        found = true; \
      } \
    } \
  } }

  uchar buf[200 * 1024];
  FILE* input = 0;
  size_t input_size = 0;

  void find_space(uchar* start, size_t start_s,
      uchar* end, size_t end_s, uchar **out_start, uchar **out_end) {
    if (!input) {
      input = fopen(command_file, "r");
      if (!input) { fprintf(stderr, "Failed\n"); }
      input_size = fread(buf, 1, sizeof(buf), input);
    }
    size_t pos = 0, s = 0, e = 0;
    FIND(start); s = pos;
    FIND(end); e = pos;
    *out_start = &buf[s];
    *out_end = &buf[e];
    //printf("s: %zd, e:%zd, l:%zd\n", s, e, e - s);
  }

  void write() {
    FILE *out = fopen("a.out", "w");
    fwrite(buf, 1, input_size, out);
    fclose(out);
    printf("Writing a.out\n");
    chmod("a.out", 0777);
  }

  void dump(uchar* start, size_t s) {
    for (size_t i = 0; i < s; i++) {
      printf("%02x ", start[i]);
    }
    //printf("\n");
  }

  int __offset = 0;
  const char* call_offset(uchar *out_current_code_pos, void *__virt_f) {
    auto virt_f = (uchar*)__virt_f;
    ssize_t out_start_distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = virt_f - virtual_code_start;
    __offset = virt_dist_from_code_start - out_start_distance - 5;
    cout << "__virt_f: " << __virt_f << endl;
    //cout << "call_offset: " << __offset << " virt: " << virt_dist_from_code_start << " out: " << out_start_distance << endl;
    return (const char*)&__offset;
  }

  const char* rip_relative_offset(uchar *out_current_code_pos,
      uchar *virt_adr) {
    ssize_t distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = (size_t)virt_adr -
        (size_t)virtual_code_start - distance;
    __offset = virt_dist_from_code_start - 7;
    printf("virt_dist_from_code_start: %zx %x, string ofs: %zd\n",
        (size_t)virt_adr, __offset,
        (size_t)(out_s - out_strings_start));
    return (const char*)&__offset;
  }

  int parameter_count = 0;
  const char *register_parameters_intel_32[] = {
      "\xbf", /*edi*/ "\xbe", /*esi*/ "\xba" /*edx*/ };

  const char *register_rip_relative_parameters_intel_64[] = {
    "\x48\x8d\x3d", /* rdi */ "\x48\x8d\x35", /* rsi */
    "\x48\x8d\x15" /* rdx */ };

  const char *register_parameters_arm_32[] = {
      "\xe5\x9f\x00", /*r0*/ "\xe5\x9f\x10", /*r1*/ "\xe5\x9f\x20" /*r2*/ };
  const char *register_parameters_intel_64[] = {
      "\x48\xbf" /*rdi*/, "\x48\xbe" ,/*rsi*/ "\x48\xba" /*rdx*/ };

  constexpr int parameters_max = 3;

  void emit(const char* _s, size_t _l = 0) {
    size_t l = _l > 0 ? _l : strlen(_s);
    uchar *s = (uchar *)_s; uchar *e = s + l;
    if (out_c + l > out_code_end) throw exception("Code: Out of memory");
    for (uchar * b  = s; b < e; b++, out_c++) {
      *out_c = *b;
    }
    dump(s, l);
  }

  bool intel() { return true; }
  bool arm() { return false; }

  id add_parameter(id p) {
    if (parameter_count >= parameters_max) {
      fprintf(stderr, "Too many parameters!\n");
      return p;
    }
    //cout << "parameter_count: " << parameter_count << " "; p.describe();
    if (p.is_charp()) {
      if (!am_i_pic) {
        emit(register_parameters_intel_32[parameter_count]);
        emit(p.i32(), 4);
      } else {
        uchar *out_current_code_pos = out_c;
        emit(register_rip_relative_parameters_intel_64[parameter_count]);
        emit(rip_relative_offset(out_current_code_pos, p.virtual_adr), 4);
      }
    } else if (p.is_integer()) {
      //cout << "is_integer" << endl;
      if (intel()) {
        //cout << "intel" << endl;
        if (p.is_32()) {
          //cout << "is_32" << endl;
          emit(register_parameters_intel_32[parameter_count]);
          emit(p.i32(), 4);
        } else if (p.is_64()) {
          //cout << "is_64" << endl;
          emit(register_parameters_intel_64[parameter_count]);
          emit(p.i64(), 8);
        }
      } else if (arm()) {
        emit(register_parameters_intel_32[parameter_count]);
      }
    }
    ++parameter_count;
    return p;
  }

  void jmp(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe9"); // JMP
    emit(call_offset(out_current_code_pos, f), 4);
  }

  void __call(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe8"); // call
    emit(call_offset(out_current_code_pos, f), 4);
    parameter_count = 0;
  }

  void __vararg_call(void *f) {
    emit("\x30\xc0"); // xor    al,al
    call(f);
  }

  size_t __p = 0;

  void f(const char *s, int i) {
    __p += (size_t)s + i;
  }

  bool __am_i_pic() {
    uchar *p = (uchar *)__am_i_pic;
    int i = 0;
    uchar c = 0;
    do {
      c = p[i++];
    } while (i < 10 && c != 0x48 && c != 0xbf);
    return c == 0x48;
  }

  void init(char *c, uchar *start, size_t ss, uchar *end, size_t es) {
    am_i_pic = __am_i_pic();
    printf("am_i_pic: %d\n", am_i_pic);
    command_file = c;
    virtual_code_start = start;
    virtual_code_end = end;
    find_space(start, ss, end, es, &out_code_start,
        &out_code_end);
    //printf("code: %zu\n", out_code_end - out_code_start);
    virtual_strings_start = (uchar *)STRINGS_START;
    virtual_strings_end = (uchar *)STRINGS_END;
    out_c = out_code_start;
    find_space(virtual_strings_start, strlen(STRINGS_START),
        virtual_strings_end, strlen(STRINGS_END),
            &out_strings_start, &out_strings_end);
    //printf("strings: %zu\n", out_strings_end - out_strings_start);
    out_s = out_strings_start;
  }

  void finish() {
    jmp(virtual_code_end);
    write();
  }

}
<commit_msg>Added cpu check.<commit_after>// symbiosis: A hacky and lightweight compiler framework
//
#include "symbiosis.hpp"
#include <sys/stat.h>

#include <iostream>

#include <vector>

using namespace std;

namespace symbiosis {

  bool intel = false;
  bool arm = false;
  bool am_i_pic = false;

  void figure_out_cpu_architecture() {
    uchar *p = (uchar *)figure_out_cpu_architecture;
    if (p[3] == 0xe9 || p[3] == 0xe5) { cout << "ARM" << endl;
        arm = true; return }
    cout << "Unknown CPU id: "; dump(p, 4);
  }

  bool __am_i_pic() {
    uchar *p = (uchar *)__am_i_pic;
    int i = 0;
    uchar c = 0;
    do {
      c = p[i++];
    } while (i < 10 && c != 0x48 && c != 0xbf);
    return c == 0x48;
  }

  class exception : public std::exception {
    const char *what_;
  public:
    exception(const char *w) : what_(w) { }
    virtual ~exception() throw() { }
    virtual const char* what() const throw() { return what_; }
  };

  char *command_file = 0;;

  #define M10(v, b) #v #b
  #define M3(a,b) M10(a+1000, v),M10(a+2000, v), M10(a+3000, v),M10(a+4000, v)
  #define M2(a,b) M3(a+100, v) , M3(a+200, v) , M3(a+300, v) , M3(a+400, v)
  #define M1(a,b) M2(a+10, v) , M2(a+20, v) , M2(a+30, v) , M2(a+40, v)
  #define M(v) M1(1, v), M1(2, v), M1(3, v), M1(4, v), M1(5, v)

  uchar *virtual_code_start = 0;
  uchar *virtual_code_end = 0;

  uchar *out_code_start = 0;
  uchar *out_code_end = 0;
  uchar *out_c = 0;
  uchar *out_c0 = 0;

  uchar *virtual_strings_start = 0;
  uchar *virtual_strings_end = 0;
  uchar *out_strings_start = 0;
  uchar *out_strings_end = 0;
  uchar *out_s = 0;

  #define STRINGS_START "STRINGS_START"
  #define STRINGS_END "STRINGS_END"

  unsigned int _i32 = 0;

  const char* id::i32() {
    if (virtual_adr) { _i32 = (size_t)virtual_adr;
         //printf("virtual_adr: %x\n", _i32);
        return (const char*)&_i32; }
    if (type == T_UINT) return (const char*)&d.ui;
    return (const char*)&d.i;
  }
  const char* id::i64() {
    if (type == T_ULONG) return (const char*)&d.ul;
    return (const char*)&d.l;
  }
  vector<const char*> type_str = { "0:???", "int", "uint", "long", "ulong",
      "charp", "float", "double"};

  void id::describe() {
    if (type > type_str.size() - 1) {
      cout << "<id:" << type << ">";
    } else {
      cout << type_str[type];
    }
    cout << endl;
  }
  id  id::operator()(id i) { add_parameter(i); return i; }

  id_new::id_new(const char *p) : id(p) {
    virtual_adr = virtual_strings_start + (out_s - out_strings_start);
    virtual_size = strlen(p);
    if (out_s + virtual_size + 1 > out_strings_end)
        throw exception("Strings: Out of memory");
    memcpy(out_s, p, virtual_size + 1);
    out_s += virtual_size + 1;
  };

  const char *reserved_strings[] = { STRINGS_START,
  M(ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc)
  STRINGS_END };

#define FIND(v) { \
  pos = 0; \
  bool found = false; \
  for (size_t i = 0; !found && i < (input_size - v##_s); i++) { \
    for (int j = 0; j < v##_s; j++) { \
      if (buf[i + j] != v[j]) break; \
      if (j == v##_s - 1) { \
        pos = i; \
        found = true; \
      } \
    } \
  } }

  uchar buf[200 * 1024];
  FILE* input = 0;
  size_t input_size = 0;

  void find_space(uchar* start, size_t start_s,
      uchar* end, size_t end_s, uchar **out_start, uchar **out_end) {
    if (!input) {
      input = fopen(command_file, "r");
      if (!input) { fprintf(stderr, "Failed\n"); }
      input_size = fread(buf, 1, sizeof(buf), input);
    }
    size_t pos = 0, s = 0, e = 0;
    FIND(start); s = pos;
    FIND(end); e = pos;
    *out_start = &buf[s];
    *out_end = &buf[e];
    //printf("s: %zd, e:%zd, l:%zd\n", s, e, e - s);
  }

  void write() {
    FILE *out = fopen("a.out", "w");
    fwrite(buf, 1, input_size, out);
    fclose(out);
    printf("Writing a.out\n");
    chmod("a.out", 0777);
  }

  void dump(uchar* start, size_t s) {
    for (size_t i = 0; i < s; i++) {
      printf("%02x ", start[i]);
    }
    //printf("\n");
  }

  int __offset = 0;
  const char* call_offset(uchar *out_current_code_pos, void *__virt_f) {
    auto virt_f = (uchar*)__virt_f;
    ssize_t out_start_distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = virt_f - virtual_code_start;
    __offset = virt_dist_from_code_start - out_start_distance - 5;
    cout << "__virt_f: " << __virt_f << endl;
    //cout << "call_offset: " << __offset << " virt: " << virt_dist_from_code_start << " out: " << out_start_distance << endl;
    return (const char*)&__offset;
  }

  const char* rip_relative_offset(uchar *out_current_code_pos,
      uchar *virt_adr) {
    ssize_t distance = out_current_code_pos - out_code_start;
    ssize_t virt_dist_from_code_start = (size_t)virt_adr -
        (size_t)virtual_code_start - distance;
    __offset = virt_dist_from_code_start - 7;
    printf("virt_dist_from_code_start: %zx %x, string ofs: %zd\n",
        (size_t)virt_adr, __offset,
        (size_t)(out_s - out_strings_start));
    return (const char*)&__offset;
  }

  int parameter_count = 0;
  const char *register_parameters_intel_32[] = {
      "\xbf", /*edi*/ "\xbe", /*esi*/ "\xba" /*edx*/ };

  const char *register_rip_relative_parameters_intel_64[] = {
    "\x48\x8d\x3d", /* rdi */ "\x48\x8d\x35", /* rsi */
    "\x48\x8d\x15" /* rdx */ };

  const char *register_parameters_arm_32[] = {
      "\xe5\x9f\x00", /*r0*/ "\xe5\x9f\x10", /*r1*/ "\xe5\x9f\x20" /*r2*/ };
  const char *register_parameters_intel_64[] = {
      "\x48\xbf" /*rdi*/, "\x48\xbe" ,/*rsi*/ "\x48\xba" /*rdx*/ };

  constexpr int parameters_max = 3;

  void emit(const char* _s, size_t _l = 0) {
    size_t l = _l > 0 ? _l : strlen(_s);
    uchar *s = (uchar *)_s; uchar *e = s + l;
    if (out_c + l > out_code_end) throw exception("Code: Out of memory");
    for (uchar * b  = s; b < e; b++, out_c++) {
      *out_c = *b;
    }
    dump(s, l);
  }

  bool intel() { return true; }

  id add_parameter(id p) {
    if (parameter_count >= parameters_max) {
      fprintf(stderr, "Too many parameters!\n");
      return p;
    }
    //cout << "parameter_count: " << parameter_count << " "; p.describe();
    if (p.is_charp()) {
      if (!am_i_pic) {
        emit(register_parameters_intel_32[parameter_count]);
        emit(p.i32(), 4);
      } else {
        uchar *out_current_code_pos = out_c;
        emit(register_rip_relative_parameters_intel_64[parameter_count]);
        emit(rip_relative_offset(out_current_code_pos, p.virtual_adr), 4);
      }
    } else if (p.is_integer()) {
      //cout << "is_integer" << endl;
      if (intel) {
        //cout << "intel" << endl;
        if (p.is_32()) {
          //cout << "is_32" << endl;
          emit(register_parameters_intel_32[parameter_count]);
          emit(p.i32(), 4);
        } else if (p.is_64()) {
          //cout << "is_64" << endl;
          emit(register_parameters_intel_64[parameter_count]);
          emit(p.i64(), 8);
        }
      } else if (arm) {
        emit(register_parameters_intel_32[parameter_count]);
      }
    }
    ++parameter_count;
    return p;
  }

  void jmp(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe9"); // JMP
    emit(call_offset(out_current_code_pos, f), 4);
  }

  void __call(void *f) {
    uchar *out_current_code_pos = out_c;
    emit("\xe8"); // call
    emit(call_offset(out_current_code_pos, f), 4);
    parameter_count = 0;
  }

  void __vararg_call(void *f) {
    emit("\x30\xc0"); // xor    al,al
    call(f);
  }

  size_t __p = 0;

  void f(const char *s, int i) {
    __p += (size_t)s + i;
  }

  void init(char *c, uchar *start, size_t ss, uchar *end, size_t es) {
    figure_out_cpu_architecture();
    am_i_pic = __am_i_pic();
    printf("am_i_pic: %d\n", am_i_pic);
    command_file = c;
    virtual_code_start = start;
    virtual_code_end = end;
    find_space(start, ss, end, es, &out_code_start,
        &out_code_end);
    //printf("code: %zu\n", out_code_end - out_code_start);
    virtual_strings_start = (uchar *)STRINGS_START;
    virtual_strings_end = (uchar *)STRINGS_END;
    out_c = out_code_start;
    find_space(virtual_strings_start, strlen(STRINGS_START),
        virtual_strings_end, strlen(STRINGS_END),
            &out_strings_start, &out_strings_end);
    //printf("strings: %zu\n", out_strings_end - out_strings_start);
    out_s = out_strings_start;
  }

  void finish() {
    jmp(virtual_code_end);
    write();
  }

}
<|endoftext|>