<commit_before>/*
 *  VHDL implementation of $display.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cstring>
#include <cassert>
#include <cctype>
#include <sstream>

static const char *DISPLAY_LINE = "Verilog_Display_Line";

/*
 * Write a VHDL expression into the current display line.
 */
static void display_write(stmt_container *container, vhdl_expr *expr)
{
   vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
   vhdl_var_ref *ref =
      new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
   write->add_expr(ref);

   vhdl_type_name_t type = expr->get_type()->get_name();
   if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
      vhdl_fcall *toint =
         new vhdl_fcall("To_Integer", vhdl_type::integer());
      toint->add_expr(expr);

      write->add_expr(toint);
   }
   else if (type != VHDL_TYPE_STRING) {
      // Need to add a call to Type'Image for types not
      // supported by std.textio
      std::string name(expr->get_type()->get_string());
      name += "'Image";

      vhdl_fcall *cast
         = new vhdl_fcall(name.c_str(), vhdl_type::string());
      cast->add_expr(expr);

      write->add_expr(cast);
   }
   else
      write->add_expr(expr);

   container->add_stmt(write);
}

/*
 * Write the value of DISPLAY_LINE to the output.
 */
static void display_line(stmt_container *container)
{
   vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
   vhdl_var_ref *output_ref =
      new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
   write_line->add_expr(output_ref);
   vhdl_var_ref *ref =
      new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
   write_line->add_expr(ref);
   container->add_stmt(write_line);
}

/*
 * Parse an octal escape sequence.
 */
static char parse_octal(const char *p)
{
   assert(*p && *(p+1) && *(p+2));
   assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));

   return (*p - '0') * 64
      + (*(p+1) - '0') * 8
      + (*(p+2) - '0') * 1;
}

/*
 * Generate VHDL for the $display system task.
 * This is implemented using the functions in std.textio. Each
 * parameter is written to a line variable in the process and
 * then the line is written to the special variable `Output'
 * (which represents the console). Subsequent $displays will
 * use the same line variable.
 *
 * It's possible, although quite unlikely, that there will be
 * name collision with an existing variable called
 * `Verilog_Display_Line' -- do something about this?
 */
int draw_stask_display(vhdl_process *proc, stmt_container *container,
                       ivl_statement_t stmt, bool newline)
{
   // Add the package requirement to the containing entity
   proc->get_parent()->get_parent()->requires_package("std.textio");

   if (!proc->have_declared_var(DISPLAY_LINE)) {
      vhdl_var_decl *line_var =
         new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
      line_var->set_comment("For generating $display output");
      proc->add_decl(line_var);
   }

   // Write the data into the line
   int count = ivl_stmt_parm_count(stmt), i = 0;
   while (i < count) {
      // $display may have an empty parameter, in which case
      // the expression will be null
      // The behaviour here seems to be to output a space
      ivl_expr_t net = ivl_stmt_parm(stmt, i++);
      if (net) {
         if (ivl_expr_type(net) == IVL_EX_STRING) {
            std::ostringstream ss;
            for (const char *p = ivl_expr_string(net); *p; p++) {
               if (*p == '\\') {
                  // Octal escape
                  char ch = parse_octal(p+1);
                  if (ch == '\n') {
                     display_write(container,
                                   new vhdl_const_string(ss.str().c_str()));
                     display_line(container);

                     // Clear the stream
                     ss.str("");
                  }
                  else
                     ss << ch;
                  p += 3;
               }
               else
                  ss << *p;
            }

            display_write(container, new vhdl_const_string(ss.str().c_str()));
         }
         else {
            vhdl_expr *base = translate_expr(net);
            if (NULL == base)
               return 1;

            display_write(container, base);
         }
      }
      else
         display_write(container, new vhdl_const_string(" "));
   }

   if (newline)
      display_line(container);

   return 0;
}
<commit_msg>A slightly smarter $display<commit_after>/*
 *  VHDL implementation of $display.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "vhdl_target.h"

#include <iostream>
#include <cstring>
#include <cassert>
#include <cctype>
#include <sstream>

static const char *DISPLAY_LINE = "Verilog_Display_Line";

/*
 * Write a VHDL expression into the current display line.
 */
static void display_write(stmt_container *container, vhdl_expr *expr)
{
   vhdl_pcall_stmt *write = new vhdl_pcall_stmt("Write");
   vhdl_var_ref *ref =
      new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
   write->add_expr(ref);

   vhdl_type_name_t type = expr->get_type()->get_name();
   if (type == VHDL_TYPE_SIGNED || type == VHDL_TYPE_UNSIGNED) {
      vhdl_fcall *toint =
         new vhdl_fcall("To_Integer", vhdl_type::integer());
      toint->add_expr(expr);

      write->add_expr(toint);
   }
   else if (type != VHDL_TYPE_STRING) {
      // Need to add a call to Type'Image for types not
      // supported by std.textio
      std::string name(expr->get_type()->get_string());
      name += "'Image";

      vhdl_fcall *cast
         = new vhdl_fcall(name.c_str(), vhdl_type::string());
      cast->add_expr(expr);

      write->add_expr(cast);
   }
   else
      write->add_expr(expr);

   container->add_stmt(write);
}

/*
 * Write the value of DISPLAY_LINE to the output.
 */
static void display_line(stmt_container *container)
{
   vhdl_pcall_stmt *write_line = new vhdl_pcall_stmt("WriteLine");
   vhdl_var_ref *output_ref =
      new vhdl_var_ref("std.textio.Output", new vhdl_type(VHDL_TYPE_FILE));
   write_line->add_expr(output_ref);
   vhdl_var_ref *ref =
      new vhdl_var_ref(DISPLAY_LINE, vhdl_type::line());
   write_line->add_expr(ref);
   container->add_stmt(write_line);
}

/*
 * Parse an octal escape sequence.
 */
static char parse_octal(const char *p)
{
   assert(*p && *(p+1) && *(p+2));
   assert(isdigit(*p) && isdigit(*(p+1)) && isdigit(*(p+1)));

   return (*p - '0') * 64
      + (*(p+1) - '0') * 8
      + (*(p+2) - '0') * 1;
}

static void flush_string(std::ostringstream &ss, stmt_container *container)
{
   display_write(container, new vhdl_const_string(ss.str().c_str()));

   // Clear the stream
   ss.str("");
}

/*
 * Generate VHDL for the $display system task.
 * This is implemented using the functions in std.textio. Each
 * parameter is written to a line variable in the process and
 * then the line is written to the special variable `Output'
 * (which represents the console). Subsequent $displays will
 * use the same line variable.
 *
 * It's possible, although quite unlikely, that there will be
 * name collision with an existing variable called
 * `Verilog_Display_Line' -- do something about this?
 */
int draw_stask_display(vhdl_process *proc, stmt_container *container,
                       ivl_statement_t stmt, bool newline)
{
   // Add the package requirement to the containing entity
   proc->get_parent()->get_parent()->requires_package("std.textio");

   if (!proc->have_declared_var(DISPLAY_LINE)) {
      vhdl_var_decl *line_var =
         new vhdl_var_decl(DISPLAY_LINE, vhdl_type::line());
      line_var->set_comment("For generating $display output");
      proc->add_decl(line_var);
   }

   // Write the data into the line
   int count = ivl_stmt_parm_count(stmt), i = 0;
   while (i < count) {
      // $display may have an empty parameter, in which case
      // the expression will be null
      // The behaviour here seems to be to output a space
      ivl_expr_t net = ivl_stmt_parm(stmt, i++);
      if (net) {
         if (ivl_expr_type(net) == IVL_EX_STRING) {
            std::ostringstream ss;
            for (const char *p = ivl_expr_string(net); *p; p++) {
               if (*p == '\\') {
                  // Octal escape
                  char ch = parse_octal(p+1);
                  if (ch == '\n') {
                     flush_string(ss, container);
                     display_line(container);
                  }
                  else
                     ss << ch;
                  p += 3;
               }
               else if (*p == '%') {
                  flush_string(ss, container);

                  p++;   // Ignore the format (!)
                  ivl_expr_t net = ivl_stmt_parm(stmt, i++);
                  assert(net);

                  vhdl_expr *base = translate_expr(net);
                  if (NULL == base)
                     return 1;

                  display_write(container, base);
               }
               else
                  ss << *p;
            }

            display_write(container, new vhdl_const_string(ss.str().c_str()));
         }
         else {
            vhdl_expr *base = translate_expr(net);
            if (NULL == base)
               return 1;

            display_write(container, base);
         }
      }
      else
         display_write(container, new vhdl_const_string(" "));
   }

   if (newline)
      display_line(container);

   return 0;
}
<|endoftext|>


<commit_before>#if !defined(_2D3D_PSEUDO_)

#include <cstdio>
#include <cmath>
#include <vector>
#include <Eigen/Core>
#include <Eigen/Dense>
#include "enlarge.hh"
#include "edgedetect.hh"

template <typename T> class PseudoBump {
public:
  int    z_max;
  int    stp;
  int    rstp;
  int    estp;
  int    enll;
  T      roff;
  T      rdist;
  T      gratio;
  int    zband;
  int    nlevel;
  int    nedge;
  int    rband;
  T      sthresh;
  T      Pi;

  PseudoBump();
  void initialize(const int& z_max, const int& stp, const int& rstp, const int& estp, const int& enll, const T& roff, const T& rdist, const T& gratio, const int& nlevel, const int& nedge);
  ~PseudoBump();

  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> getPseudoBumpSub(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> getPseudoBump(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input, const bool& y_only);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> rgb2l(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic> rgb[3]);
private:
  T zz(const T& t);
  T sgn(const T& x);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> getMosaic(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input, const int& i);
  Eigen::Matrix<T, Eigen::Dynamic, 1> minSquare(const Eigen::Matrix<T, Eigen::Dynamic, 1>& input);
  Eigen::Matrix<T, Eigen::Dynamic, 1> getLineAxis(Eigen::Matrix<T, Eigen::Dynamic, 1> p, Eigen::Matrix<T, Eigen::Dynamic, 1> c, const int& w, const int& h);
  Eigen::Matrix<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Dynamic, Eigen::Dynamic> prepareLineAxis(const Eigen::Matrix<T, Eigen::Dynamic, 1>& p0, const Eigen::Matrix<T, Eigen::Dynamic, 1>& p1, const int& z0);
  T getImgPt(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& img, const T& y, const T& x);
  Eigen::Matrix<T, Eigen::Dynamic, 1> indiv(const Eigen::Matrix<T, Eigen::Dynamic, 1>& p0, const Eigen::Matrix<T, Eigen::Dynamic, 1>& p1, const T& pt);
  enlarger2exds<T, complex<T> > enlarger;
  Eigen::Matrix<T, Eigen::Dynamic, 1> complementLine(const Eigen::Matrix<T, Eigen::Dynamic, 1>& line, const int& rband);

  int ww;
  int hh;
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Dop;
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Dop2;
};

template <typename T> PseudoBump<T>::PseudoBump() {
  initialize(8, 16, 3, 4, 1, .5, 1e3, 0., 8, 32);
}

template <typename T> PseudoBump<T>::~PseudoBump() {
  ;
}

template <typename T> void PseudoBump<T>::initialize(const int& z_max, const int& stp, const int& rstp, const int& estp, const int& enll, const T& roff, const T& rdist, const T& gratio, const int& nlevel, const int& nedge) {
  const int enlp(std::max(int(pow(2, enll) - 1), int(1)));
  this->z_max   = z_max;
  this->stp     = stp;
  this->rstp    = rstp;
  this->estp    = estp;
  this->enll    = enll;
  this->roff    = roff;
  this->rdist   = rdist;
  this->gratio  = gratio;
  this->zband   = int(std::max(1., std::sqrt(stp)));
  this->nlevel  = nlevel;
  this->nedge   = nedge;
  Pi            = 4. * atan2(T(1.), T(1.));
  rband         = this->rstp;
  sthresh       = pow(1. / 256., 6.);
};

template <typename T> T PseudoBump<T>::sgn(const T& x) {
  if(x < T(0))
    return - T(1);
  if(x > T(0))
    return T(1);
  return T(0);
}

template <typename T> T PseudoBump<T>::zz(const T& t) {
  return (t + T(1)) / z_max;
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> PseudoBump<T>::rgb2l(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> rgb[3]) {
  return .212639 * rgb[0] + .715169 * rgb[1] + .072192 * rgb[2];
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> PseudoBump<T>::getPseudoBumpSub(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input) {
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> work(input);
  for(int i = 0; i < enll; i ++)
    work = enlarger.enlarge2ds(work, enlarger2exds<T, complex<T> >::ENLARGE_Y);
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> result(work.rows(), work.cols());
  const int ppratio = (result.rows() + input.rows() - 1) / input.rows();
  ww = work.cols();
  hh = work.rows();
  Eigen::Matrix<T, Eigen::Dynamic, 1> p0(3), p1(3);
  p0[0] = 0;
  p0[1] = work.cols() / 2;
  p0[2] = 0;
  p1[0] = work.rows();
  p1[1] = work.cols() / 2;
  p1[2] = 0;
  cerr << " bump";
  cerr.flush();
  auto lrf(prepareLineAxis(p0, p1, z_max));
  for(int i = 0; i < lrf.rows(); i ++)
    for(int j = 0; j < lrf(i, 0).cols(); j ++) {
      lrf(i, 0)(1, j) = 0;
      lrf(i, 1)(1, j) = 0;
    }
  const int& delta(result.rows());
  for(int i = 0; i < result.cols(); i ++) {
    p0[1] = i;
    p1[1] = i;
    cerr << ".";
    cerr.flush();
    for(int j = 0; j < result.rows(); j ++)
      result(j, i) = - T(1);
    Eigen::Matrix<T, Eigen::Dynamic, 1> zval(result.rows());
    for(int j = 0; j < zval.size(); j ++)
      zval[j] = T(0);
    for(int s = 0; s < delta; s ++) {
      auto pt(indiv(p0, p1, s / T(delta)));
      for(int zz = 0; zz < lrf.rows(); zz ++) {
        Eigen::Matrix<T, Eigen::Dynamic, 1> c(lrf(zz, 0).cols());
        for(int u = 0; u < c.size(); u ++) {
          c[u]  = getImgPt(work, lrf(zz, 0)(0, u) + pt[0],
                                 lrf(zz, 0)(1, u) + pt[1]);
          c[u] -= getImgPt(work, lrf(zz, 1)(0, u) + pt[0],
                                 lrf(zz, 1)(1, u) + pt[1]);
        }
        Eigen::Matrix<T, Eigen::Dynamic, 1> lc(c.size() / 2 + 1);
        Eigen::Matrix<T, Eigen::Dynamic, 1> rc(c.size() / 2 + 1);
        for(int u = 0; u < lc.size(); u ++)
          lc[u] = c[u];
        for(int u = 0; u < rc.size(); u ++)
          rc[u] = c[u - rc.size() + c.size()];
        Eigen::Matrix<T, Eigen::Dynamic, 1> lc2(zband), rc2(zband);
        for(int u = 0; u < lc2.size(); u ++)
          lc2[u] = lc[u - lc2.size() + lc.size()];
        for(int u = 0; u < rc2.size(); u ++)
          rc2[u] = rc[u];
        const Eigen::Matrix<T, Eigen::Dynamic, 1> msl( Dop  * lc);
        const Eigen::Matrix<T, Eigen::Dynamic, 1> msr( Dop  * rc);
        const Eigen::Matrix<T, Eigen::Dynamic, 1> msl2(Dop2 * lc2);
        const Eigen::Matrix<T, Eigen::Dynamic, 1> msr2(Dop2 * rc2);
        auto ms( abs(msl[ msl.size()  - 1] - msr[0]) );
        auto ms2(abs(msl2[msl2.size() - 1] - msr2[0]));
        const T n2(ms2 / (ms + 1.));
        if(isfinite(n2) && gratio < n2 && zval[s] < n2) {
          result(s, i) = zz / T(z_max);
          zval[s]      = n2;
        }
      }
    }
    result.col(i) = complementLine(result.col(i), rband * ppratio);
  }
  Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> res(input.rows(), input.cols());
  for(int x = 0; x < input.cols(); x ++)
    for(int y0 = 0; y0 < input.rows(); y0 ++)
      res(y0, x) = result(y0 * ppratio, x);
  return res;
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> PseudoBump<T>::getMosaic(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input, const int& i) {
  Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> work(input);
  for(int x = 0; x < (input.cols() + i - 1) / i; x ++) {
    for(int y = 0; y < (input.rows() + i - 1) / i; y ++) {
      std::vector<float> meds;
      for(int xx = x * i;
              xx < std::min(int(work.cols()), (x + 1) * i);
              xx ++)
        for(int yy = y * i;
                yy < std::min(int(work.rows()), (y + 1) * i);
                yy ++) {
          meds.push_back(work(yy, xx));
          work(yy, xx) = - 1.;
        }
      std::sort(meds.begin(), meds.end());
      work(std::min(int(input.rows()) - 1, y * i + i / 2), x * i) = meds[meds.size() / 2];
    }
    work.col(x * i) = complementLine(work.col(x * i), 1);
  }
  for(int y = 0; y < work.rows(); y ++)
    work.row(y) = complementLine(work.row(y), 1);
  return work;
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> PseudoBump<T>::getPseudoBump(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& input, const bool& y_only)
 {
  if(y_only) {
    T ratio = 0;
    Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> out(input.rows(), input.cols());
    for(int i = 0; i < out.rows(); i ++)
      for(int j = 0; j < out.cols(); j ++)
        out(i, j) = 0.;
    for(int i = estp; i < input.rows() / estp; i *= 2) {
      out   += getMosaic(getPseudoBumpSub(getMosaic(input, i)), i);
      ratio += 1.;
    }
    out /= ratio;
    edgedetect<T, complex<T> > edge;
    Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> edges(edge.detect(input, edgedetect<T, complex<T> >::COLLECT_Y));
    std::vector<T> estat;
    for(int i = 0; i < edges.rows(); i ++)
      for(int j = 0; j < edges.cols(); j ++)
        estat.push_back(edges(i, j));
    std::sort(estat.begin(), estat.end());
    for(int i = 0; i < out.rows(); i ++)
      for(int j = 0; j < out.cols(); j ++)
        if(estat[estat.size() * (nedge - 1) / nedge] < edges(i, j))
          out(i, j) = - T(1);
    for(int i = 0; i < out.cols(); i ++)
      out.col(i) = complementLine(out.col(i), rband);
    std::vector<T> stat;
    for(int i = 0; i < out.rows(); i ++)
      for(int j = 0; j < out.cols(); j ++) {
        // XXX fixme:
        // out(i, j) = 1. - out(i, j);
        stat.push_back(out(i, j));
      }
    std::sort(stat.begin(), stat.end());
    const T mm(stat[stat.size() / nlevel]);
    T MM(stat[stat.size() * (nlevel - 1) / nlevel]);
    if(MM == mm)
      MM = mm + 1.;
    for(int i = 0; i < out.rows(); i ++)
      for(int j = 0; j < out.cols(); j ++)
        out(i, j) = (std::max(std::min(out(i, j), MM), mm) - mm) / (MM - mm);
    return out;
  } else {
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> pbx(getPseudoBump(input.transpose(), true).transpose());
    const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> pby(getPseudoBump(input, true));
    return Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>((pbx + pby) / 2.);
  }
  return Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>();
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, 1> PseudoBump<T>::minSquare(const Eigen::Matrix<T, Eigen::Dynamic, 1>& input) {
  for(int i = 0; i < input.size(); i ++)
    if(!isfinite(input[i])) {
      Eigen::Matrix<T, Eigen::Dynamic, 1> res(2);
      res[0] = res[1] = T(0);
      return res;
    }
  Matrix<T, Eigen::Dynamic, 1> avg(2);
  avg[0] = T(0);
  avg[1] = T(0);
  for(int i = 0; i < input.size(); i ++) {
    avg[0] += input[i];
    avg[1] += i;
  }
  avg[0] /= input.size();
  avg[1] /= input.size();

  Matrix<T, Eigen::Dynamic, 1> b(input.size());
  for(int i = 0; i < input.size(); i ++)
    b[i] = input[i] - avg[0];

  Matrix<T, Eigen::Dynamic, Eigen::Dynamic> A(input.size(), 2);
  for(int i = 0; i < input.size(); i ++) {
    A(i, 0) = pow(input[i] - avg[0], 2.);
    A(i, 1) = (i - avg[1]) * (input[i] - avg[0]);
  }
  Eigen::JacobiSVD<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> > svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
  auto Ut(svd.matrixU().transpose());
  auto Vt(svd.matrixV());
  auto w(svd.singularValues());
  for(int i = 0; i < w.size(); i ++)
    if(abs(w[i]) > sthresh)
      w[i] = T(1) / w[i];
  Eigen::Matrix<T, Eigen::Dynamic, 1> result(Ut * b);
  for(int i = 0; i < w.size(); i ++)
    result[i] *= w[i];
  result = Vt * result;
  result[0] += avg[0];
  return result;
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, 1> PseudoBump<T>::getLineAxis(Eigen::Matrix<T, Eigen::Dynamic, 1> p, Eigen::Matrix<T, Eigen::Dynamic, 1> c, const int& w, const int& h) {
  // suppose straight ray from infinitely distant 1 x 1 size.
  // camera geometry with c, lookup on p[2] z-distance
  // virtual images.
  p[0]  = (p[0] - h / 2.) / (h / 2.);
  p[1]  = (p[1] - w / 2.) / (w / 2.);
  p[2]  = zz(p[2]);
  c[2]  = zz(c[2]);
  // <c + (p - c) * t, [0, 0, 1]> = z
  // fix z = 0, p_z = zz(z_max).
  T t((- c[2]) / (p[2] - c[2]));
  Eigen::Matrix<T, Eigen::Dynamic, 1> work((p - c) * t + c);
  work[0] = (work[0] * h / 2. + h / 2.);
  work[1] = (work[1] * w / 2. + w / 2.);
  return work;
}

template <typename T> Eigen::Matrix<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Dynamic, Eigen::Dynamic> PseudoBump<T>::prepareLineAxis(const Eigen::Matrix<T, Eigen::Dynamic, 1>& p0, const Eigen::Matrix<T, Eigen::Dynamic, 1>& p1, const int& z0) {
  Eigen::Matrix<T, Eigen::Dynamic, 1> dir(p1 - p0);
  dir /= sqrt(dir.dot(dir));

  Eigen::Matrix<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Dynamic, Eigen::Dynamic> result(z0, 2);
  for(int zi = 0; zi < z0; zi ++) {
    result(zi, 0) = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(3, stp);
    result(zi, 1) = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(3, stp);
    for(int s = 0; s < stp; s ++) {
      auto cpoint(indiv(p0, p1, 1. / 2.));
      cpoint[0] += (s / (stp - 1.) - 1. / 2.) * rstp * dir[0];
      cpoint[1] += (s / (stp - 1.) - 1. / 2.) * rstp * dir[1];
      cpoint[2]  = z_max;

      auto zzi(zi + 1);
      Eigen::Matrix<T, Eigen::Dynamic, 1> camera(3);
      camera[0] = dir[0] * roff;
      camera[1] = dir[1] * roff;
      camera[2] = - zzi / T(z_max) * rdist;
      auto rd(getLineAxis(cpoint, camera, T(ww), T(hh)));
      camera    = - camera;
      camera[2] = - camera[2];
      auto ld(getLineAxis(cpoint, camera, T(ww), T(hh)));
      rd -= indiv(p0, p1, 1. / 2.);
      ld -= indiv(p0, p1, 1. / 2.);
      result(zi, 0).col(s) = rd;
      result(zi, 1).col(s) = ld;
    }
  }
  Eigen::Matrix<complex<T>, Eigen::Dynamic, Eigen::Dynamic> Dopb(stp / 2 + 1, stp / 2 + 1);
  Eigen::Matrix<complex<T>, Eigen::Dynamic, Eigen::Dynamic> Dop2b(zband, zband);
  Eigen::Matrix<complex<T>, Eigen::Dynamic, Eigen::Dynamic> Iopb(Dopb.rows(), Dopb.cols());
  Eigen::Matrix<complex<T>, Eigen::Dynamic, Eigen::Dynamic> Iop2b(Dop2b.rows(), Dop2b.cols());
  complex<T> I(sqrt(complex<T>(- 1)));
  for(int i = 0; i < Dopb.rows(); i ++)
    for(int j = 0; j < Dopb.cols(); j ++) {
      Dopb(i, j) = exp(complex<T>(- 2) * Pi * I * complex<T>(i * j) / T(Dopb.rows()));
      Iopb(i, j) = exp(complex<T>(  2) * Pi * I * complex<T>(i * j) / T(Dopb.rows())) / T(Dopb.rows());
    }
  for(int i = 0; i < Dopb.rows(); i ++)
    Dopb.row(i) *= complex<T>(- 2.) * Pi * I * T(i) / T(Dopb.rows());
  Dop = (Iopb * Dopb).real();
  for(int i = 0; i < Dop2b.rows(); i ++)
    for(int j = 0; j < Dop2b.cols(); j ++) {
      Dop2b(i, j) = exp(complex<T>(- 2) * Pi * I * complex<T>(i * j) / T(Dop2b.rows()));
      Iop2b(i, j) = exp(complex<T>(  2) * Pi * I * complex<T>(i * j) / T(Dop2b.rows())) / T(Dop2b.rows());
    }
  for(int i = 0; i < Dop2b.rows(); i ++)
    Dop2b.row(i) *= complex<T>(- 2.) * Pi * I * T(i) / T(Dop2b.rows());
  Dop2 = (Iop2b * Dop2b).real();
  return result;
}

template <typename T> T PseudoBump<T>::getImgPt(const Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& img, const T& y, const T& x) {
  const int& w(img.cols());
  const int& h(img.rows());
  auto xx((int(x + .5) + 2 * w) % (2 * w));
  auto yy((int(y + .5) + 2 * h) % (2 * h));
  if(abs(xx) >= w)
    xx = - xx + sgn(xx) * w;
  if(abs(yy) >= h)
    yy = - yy + sgn(yy) * h;
  return T(img((int(abs(yy)) + h) % h, (int(abs(xx)) + w) % w));
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, 1> PseudoBump<T>::indiv(const Eigen::Matrix<T, Eigen::Dynamic, 1>& p0, const Eigen::Matrix<T, Eigen::Dynamic, 1>& p1, const T& pt) {
  return (p1 - p0) * pt + p0;
}

template <typename T> Eigen::Matrix<T, Eigen::Dynamic, 1> PseudoBump<T>::complementLine(const Eigen::Matrix<T, Eigen::Dynamic, 1>& line, const int& rband) {
  std::vector<int> ptsi;
  std::vector<T>   pts;
  bool flag = true;
  for(int i = 0; i < line.size(); i ++)
    if(T(0) <= line[i]) {
      if(!i)
        flag = false;
      else if(flag) {
        ptsi.push_back(- i);
        pts.push_back(line[i]);
        flag = false;
      }
      ptsi.push_back(i);
      pts.push_back(line[i]);
    }
  Eigen::Matrix<T, Eigen::Dynamic, 1> result(line.size());
  if(ptsi.size() <= 0) {
    for(int i = 0; i < line.size(); i ++)
      result[i] = T(.5);
    return result;
  }
  ptsi.push_back(ptsi[ptsi.size() - 1] + 2. * (line.size() - ptsi[ptsi.size() - 1]));
  pts.push_back(pts[pts.size() - 1]);
  int rng[3];
  rng[0] = rng[1] = rng[2] = 0;
  for(int i = 0; i < line.size(); i ++) {
    for(; rng[0] < ptsi.size() - 1; rng[0] ++)
      if(i - rband <= ptsi[rng[0] + 1])
        break;
    for(; rng[1] < ptsi.size(); rng[1] ++)
      if(i - rband <= ptsi[rng[1]] && ptsi[rng[1]] <= i + rband)
        break;
    for(; rng[2] < ptsi.size(); rng[2] ++)
      if(i + rband < ptsi[rng[2]])
        break;
    if(rng[2] < rng[1])
      rng[1] = (rng[2] + rng[0]) / 2;
    if(rng[1] == rng[0] && 0 < rng[0])
      rng[0] --;
    if(rng[1] == rng[2] && rng[2] < ptsi.size() - 1)
      rng[2] ++;
    result[i] = 0.;
    for(int ii = 0; ii < 3; ii ++) {
      T work(1);
      for(int jj = 0; jj < 3; jj ++)
        if(ptsi[rng[ii]] != ptsi[rng[jj]])
          work *= (T(i) - ptsi[rng[jj]]) / T(ptsi[rng[ii]] - ptsi[rng[jj]]);
      result[i] += work * pts[rng[ii]];
    }
  }
  return result;
}

#define _2D3D_PSEUDO_
#endif

<commit_msg>Delete fisheye.hh<commit_after><|endoftext|>


<commit_before>
#include "vtrc-common/vtrc-connection-setup-iface.h"
#include "vtrc-common/vtrc-protocol-accessor-iface.h"
#include "vtrc-common/vtrc-delayed-call.h"
#include "vtrc-common/vtrc-hash-iface.h"
#include "vtrc-common/vtrc-transformer-iface.h"
#include "vtrc-common/vtrc-connection-iface.h"

#include "vtrc-errors.pb.h"
#include "vtrc-auth.pb.h"
#include "vtrc-rpc-lowlevel.pb.h"
#include "vtrc-function.h"

#include "vtrc-memory.h"
#include "vtrc-bind.h"

#include "vtrc-client.h"

#include "boost/asio.hpp"

#include <stdlib.h>
#include "vtrc-protocol-layer-c.h"

namespace vtrc { namespace client {

    namespace bs = boost::system;
    namespace ba = boost::asio;
    namespace gpb = google::protobuf;

    namespace {

        const unsigned default_hash_value = rpc::auth::HASH_CRC_32;

        enum protocol_stage {
             STAGE_HELLO = 1
            ,STAGE_SETUP = 2
            ,STAGE_READY = 3
        };

        void default_cb( bs::error_code const & )
        { }

        typedef vtrc::function<void (const rpc::errors::container &,
                                     const char *)> init_error_cb;
        typedef vtrc::function<void (const std::string &)> stage_function_type;

        namespace default_cypher = common::transformers::chacha;

        struct iface: common::connection_setup_iface {

            common::protocol_accessor  *pa_;
            bool                        ready_;
            stage_function_type         stage_call_;
            vtrc_client                *client_;
            protocol_stage              stage_;
            init_error_cb               init_error_;

            iface( vtrc_client *client, init_error_cb init_error )
                :pa_(NULL)
                ,ready_(false)
                ,client_(client)
                ,stage_(STAGE_HELLO)
                ,init_error_( init_error )
            {

            }

            void send_proto_message( const gpb::MessageLite &mess )
            {
                std::string s(mess.SerializeAsString( ));
                pa_->write( s, default_cb, true );
            }

            void send_proto_message( const gpb::MessageLite &mess,
                                     common::system_closure_type closure,
                                     bool on_send )
            {
                std::string s(mess.SerializeAsString( ));
                pa_->write( s, closure, on_send );
            }

            rpc::errors::container create_error( unsigned code,
                                                 const std::string &add )
            {
                rpc::errors::container cont;
                cont.set_code( code );
                cont.set_category( rpc::errors::CATEGORY_INTERNAL );
                cont.set_additional( add );
                return cont;
            }

            static
            bool server_has_transformer( rpc::auth::init_capsule const &cap,
                                         unsigned transformer_type )
            {
                rpc::auth::init_protocol init;
                init.ParseFromString( cap.body( ) );
                return std::find( init.transform_supported( ).begin( ),
                       init.transform_supported( ).end( ),
                       transformer_type ) != init.transform_supported( ).end( );
            }

            void change_stage( protocol_stage stage )
            {
                stage_ = stage;
                switch ( stage_ ) {
                case STAGE_HELLO:
                    stage_call_ = vtrc::bind( &iface::on_hello_call, this,
                                              vtrc::placeholders::_1 );
                    break;
                case STAGE_SETUP:
                    stage_call_ = vtrc::bind( &iface::on_trans_setup, this,
                                              vtrc::placeholders::_1 );
                    break;
                case STAGE_READY:
                    stage_call_ = vtrc::bind( &iface::on_server_ready, this,
                                              vtrc::placeholders::_1 );
                    break;
                default:
                    break;
                }
            }

            void check_disconnect_stage( )
            {
                switch ( stage_ ) {
                case STAGE_HELLO:
                    init_error_( create_error( rpc::errors::ERR_BUSY, "" ),
                                 "Server in not ready");
                    break;
                case STAGE_SETUP:
                    init_error_( create_error( rpc::errors::ERR_INVALID_VALUE,
                                               "" ),
                                "Bad setup info.");
                    break;
                case STAGE_READY:
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                                 "Bad session key.");
                    break;
                default:
                    break;
                }
            }

            void set_options( const boost::system::error_code &err )
            {
                if( !err ) {
                    pa_->set_hash_maker(
                       common::hash::create_by_index( default_hash_value ));
                }
            }

            void on_trans_setup( const std::string &data )
            {
                using namespace common::transformers;

                rpc::auth::init_capsule capsule;
                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                           "Server's 'Ready' has bad hash. Bad session key." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    init_error_( capsule.error( ),
                                 "Server is not ready; stage: 'Setup'" );
                    pa_->close( );
                    return;
                }

                rpc::auth::transformer_setup tsetup;

                tsetup.ParseFromString( capsule.body( ) );

                std::string key(client_->get_session_key( ));

                std::string s1(tsetup.salt1( ));
                std::string s2(tsetup.salt2( ));

                create_key( key, s1, s2, key );

                pa_->set_transformer( default_cypher::create( key.c_str( ),
                                                              key.size( ) ) );

                key.assign( client_->get_session_key( ) );

                generate_key_infos( key, s1, s2, key );

                tsetup.set_salt1( s1 );
                tsetup.set_salt2( s2 );

                pa_->set_revertor( default_cypher::create( key.c_str( ),
                                                           key.size( ) ) );

                //std::cout << "Set revertor " << key.c_str( ) << "\n";

                capsule.set_ready( true );
                capsule.set_body( tsetup.SerializeAsString( ) );

                change_stage( STAGE_READY );

                send_proto_message( capsule );
            }

            void on_server_ready( const std::string &data )
            {

                rpc::auth::init_capsule capsule;
                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                           "Server's 'Ready' has bad hash. Bad session key." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    if( capsule.error( ).has_additional( ) ) {
                        init_error_( capsule.error( ),
                                     capsule.error( ).additional( ).c_str( ) );

                    } else {
                        init_error_( capsule.error( ),
                                     "Server is not ready; stage: 'Ready'" );
                    }
                }

                rpc::auth::session_setup opts;
                opts.ParseFromString( capsule.body( ) );
                pa_->configure_session( opts.options( ) );

                ready_ = true;
            }

            void on_hello_call( const std::string &data )
            {

                rpc::auth::init_capsule capsule;

                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                                 "Server's 'Hello' has bad hash." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    init_error_( capsule.error( ),
                                 "Server is not ready; stage: 'Hello'");
                    pa_->close( );
                    return;
                }

                rpc::auth::client_selection init;

                capsule.set_ready( true );
                capsule.set_text( "Miten menee?" );

                bool key_set = client_->is_key_set( );

                const unsigned basic_transform = rpc::auth::TRANSFORM_ERSEEFOR;

                if( key_set && server_has_transformer( capsule,
                                                       basic_transform ) ) {
                    init.set_transform( rpc::auth::TRANSFORM_ERSEEFOR );
                    init.set_id( client_->get_session_id( ) );
                } else {
                    init.set_transform( rpc::auth::TRANSFORM_NONE );
                }

                init.set_hash( default_hash_value );

                capsule.set_body( init.SerializeAsString( ) );

                pa_->set_hash_checker(
                     common::hash::create_by_index( default_hash_value ) );

                change_stage( key_set ? STAGE_SETUP : STAGE_READY );

                send_proto_message( capsule,
                                    vtrc::bind( &iface::set_options, this,
                                                 vtrc::placeholders::_1 ),
                                    false );

            }

            void init( common::protocol_accessor *pa,
                       common::system_closure_type /*cb*/ )
            {
                pa_ = pa;
                change_stage( stage_ );
            }

            bool next( const std::string &data )
            {
                stage_call_( data );
                return !ready_;
            }
        };

    }

    common::connection_setup_iface *create_default_setup(vtrc_client *client,
                                    init_error_cb init_error )
    {
        return new iface( client, init_error );
    }

}}
<commit_msg>chacha20 to crypt<commit_after>#include <stdlib.h>
#include "boost/asio.hpp"

#include "vtrc-common/vtrc-connection-setup-iface.h"
#include "vtrc-common/vtrc-protocol-accessor-iface.h"
#include "vtrc-common/vtrc-delayed-call.h"
#include "vtrc-common/vtrc-hash-iface.h"
#include "vtrc-common/vtrc-transformer-iface.h"
#include "vtrc-common/vtrc-connection-iface.h"

#include "vtrc-errors.pb.h"
#include "vtrc-auth.pb.h"
#include "vtrc-rpc-lowlevel.pb.h"
#include "vtrc-function.h"

#include "vtrc-memory.h"
#include "vtrc-bind.h"

#include "vtrc-client.h"

#include "vtrc-protocol-layer-c.h"

namespace vtrc { namespace client {

    namespace bs = boost::system;
    namespace ba = boost::asio;
    namespace gpb = google::protobuf;

    namespace {

        const unsigned default_hash_value = rpc::auth::HASH_CRC_32;
        namespace default_cypher = common::transformers::chacha;

        enum protocol_stage {
             STAGE_HELLO = 1
            ,STAGE_SETUP = 2
            ,STAGE_READY = 3
        };

        void default_cb( bs::error_code const & )
        { }

        typedef vtrc::function<void (const rpc::errors::container &,
                                     const char *)> init_error_cb;
        typedef vtrc::function<void (const std::string &)> stage_function_type;

        struct iface: common::connection_setup_iface {

            common::protocol_accessor  *pa_;
            bool                        ready_;
            stage_function_type         stage_call_;
            vtrc_client                *client_;
            protocol_stage              stage_;
            init_error_cb               init_error_;

            iface( vtrc_client *client, init_error_cb init_error )
                :pa_(NULL)
                ,ready_(false)
                ,client_(client)
                ,stage_(STAGE_HELLO)
                ,init_error_( init_error )
            {

            }

            void send_proto_message( const gpb::MessageLite &mess )
            {
                std::string s(mess.SerializeAsString( ));
                pa_->write( s, default_cb, true );
            }

            void send_proto_message( const gpb::MessageLite &mess,
                                     common::system_closure_type closure,
                                     bool on_send )
            {
                std::string s(mess.SerializeAsString( ));
                pa_->write( s, closure, on_send );
            }

            rpc::errors::container create_error( unsigned code,
                                                 const std::string &add )
            {
                rpc::errors::container cont;
                cont.set_code( code );
                cont.set_category( rpc::errors::CATEGORY_INTERNAL );
                cont.set_additional( add );
                return cont;
            }

            static
            bool server_has_transformer( rpc::auth::init_capsule const &cap,
                                         unsigned transformer_type )
            {
                rpc::auth::init_protocol init;
                init.ParseFromString( cap.body( ) );
                return std::find( init.transform_supported( ).begin( ),
                       init.transform_supported( ).end( ),
                       transformer_type ) != init.transform_supported( ).end( );
            }

            void change_stage( protocol_stage stage )
            {
                stage_ = stage;
                switch ( stage_ ) {
                case STAGE_HELLO:
                    stage_call_ = vtrc::bind( &iface::on_hello_call, this,
                                              vtrc::placeholders::_1 );
                    break;
                case STAGE_SETUP:
                    stage_call_ = vtrc::bind( &iface::on_trans_setup, this,
                                              vtrc::placeholders::_1 );
                    break;
                case STAGE_READY:
                    stage_call_ = vtrc::bind( &iface::on_server_ready, this,
                                              vtrc::placeholders::_1 );
                    break;
                default:
                    break;
                }
            }

            void check_disconnect_stage( )
            {
                switch ( stage_ ) {
                case STAGE_HELLO:
                    init_error_( create_error( rpc::errors::ERR_BUSY, "" ),
                                 "Server in not ready");
                    break;
                case STAGE_SETUP:
                    init_error_( create_error( rpc::errors::ERR_INVALID_VALUE,
                                               "" ),
                                "Bad setup info.");
                    break;
                case STAGE_READY:
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                                 "Bad session key.");
                    break;
                default:
                    break;
                }
            }

            void set_options( const boost::system::error_code &err )
            {
                if( !err ) {
                    pa_->set_hash_maker(
                       common::hash::create_by_index( default_hash_value ));
                }
            }

            void on_trans_setup( const std::string &data )
            {
                using namespace common::transformers;

                rpc::auth::init_capsule capsule;
                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                           "Server's 'Ready' has bad hash. Bad session key." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    init_error_( capsule.error( ),
                                 "Server is not ready; stage: 'Setup'" );
                    pa_->close( );
                    return;
                }

                rpc::auth::transformer_setup tsetup;

                tsetup.ParseFromString( capsule.body( ) );

                std::string key(client_->get_session_key( ));

                std::string s1(tsetup.salt1( ));
                std::string s2(tsetup.salt2( ));

                create_key( key, s1, s2, key );

                pa_->set_transformer( default_cypher::create( key.c_str( ),
                                                              key.size( ) ) );

                key.assign( client_->get_session_key( ) );

                generate_key_infos( key, s1, s2, key );

                tsetup.set_salt1( s1 );
                tsetup.set_salt2( s2 );

                pa_->set_revertor( default_cypher::create( key.c_str( ),
                                                           key.size( ) ) );

                //std::cout << "Set revertor " << key.c_str( ) << "\n";

                capsule.set_ready( true );
                capsule.set_body( tsetup.SerializeAsString( ) );

                change_stage( STAGE_READY );

                send_proto_message( capsule );
            }

            void on_server_ready( const std::string &data )
            {

                rpc::auth::init_capsule capsule;
                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                           "Server's 'Ready' has bad hash. Bad session key." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    if( capsule.error( ).has_additional( ) ) {
                        init_error_( capsule.error( ),
                                     capsule.error( ).additional( ).c_str( ) );

                    } else {
                        init_error_( capsule.error( ),
                                     "Server is not ready; stage: 'Ready'" );
                    }
                }

                rpc::auth::session_setup opts;
                opts.ParseFromString( capsule.body( ) );
                pa_->configure_session( opts.options( ) );

                ready_ = true;
            }

            void on_hello_call( const std::string &data )
            {

                rpc::auth::init_capsule capsule;

                bool check = capsule.ParseFromString( data );

                if( !check ) {
                    init_error_( create_error( rpc::errors::ERR_INTERNAL, "" ),
                                 "Server's 'Hello' has bad hash." );
                    pa_->close( );
                    return;
                }

                if( !capsule.ready( ) ) {
                    init_error_( capsule.error( ),
                                 "Server is not ready; stage: 'Hello'");
                    pa_->close( );
                    return;
                }

                rpc::auth::client_selection init;

                capsule.set_ready( true );
                capsule.set_text( "Miten menee?" );

                bool key_set = client_->is_key_set( );

                const unsigned basic_transform = rpc::auth::TRANSFORM_ERSEEFOR;

                if( key_set && server_has_transformer( capsule,
                                                       basic_transform ) ) {
                    init.set_transform( rpc::auth::TRANSFORM_ERSEEFOR );
                    init.set_id( client_->get_session_id( ) );
                } else {
                    init.set_transform( rpc::auth::TRANSFORM_NONE );
                }

                init.set_hash( default_hash_value );

                capsule.set_body( init.SerializeAsString( ) );

                pa_->set_hash_checker(
                     common::hash::create_by_index( default_hash_value ) );

                change_stage( key_set ? STAGE_SETUP : STAGE_READY );

                send_proto_message( capsule,
                                    vtrc::bind( &iface::set_options, this,
                                                 vtrc::placeholders::_1 ),
                                    false );

            }

            void init( common::protocol_accessor *pa,
                       common::system_closure_type /*cb*/ )
            {
                pa_ = pa;
                change_stage( stage_ );
            }

            bool next( const std::string &data )
            {
                stage_call_( data );
                return !ready_;
            }
        };

    }

    common::connection_setup_iface *create_default_setup(vtrc_client *client,
                                    init_error_cb init_error )
    {
        return new iface( client, init_error );
    }

}}
<|endoftext|>


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

#include "wangle/bootstrap/ServerBootstrap.h"
#include "wangle/bootstrap/ClientBootstrap.h"
#include "wangle/channel/Handler.h"

#include <glog/logging.h>
#include <gtest/gtest.h>
#include <boost/thread.hpp>
#include <folly/String.h>
#include <folly/experimental/TestUtil.h>

using namespace wangle;
using namespace folly;

typedef Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>> BytesPipeline;

typedef ServerBootstrap<BytesPipeline> TestServer;
typedef ClientBootstrap<BytesPipeline> TestClient;

class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> {
 public:
  BytesPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper> sock) override {
    // Socket should be connected already
    EXPECT_TRUE(sock->good());

    // Check after a small delay that socket is readable
    EventBaseManager::get()->getEventBase()->tryRunAfterDelay([sock](){
      EXPECT_TRUE(sock->readable());
    }, 100);

    auto pipeline = BytesPipeline::create();
    pipeline->addBack(new BytesToBytesHandler());
    pipeline->finalize();
    return pipeline;
  }
};

class TestPipelineFactory : public PipelineFactory<BytesPipeline> {
 public:
  BytesPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper>) override {
    pipelines++;
    auto pipeline = BytesPipeline::create();
    pipeline->addBack(new BytesToBytesHandler());
    pipeline->finalize();
    return pipeline;
  }
  std::atomic<int> pipelines{0};
};

class TestAcceptor : public Acceptor {
EventBase base_;
 public:
  TestAcceptor() : Acceptor(ServerSocketConfig()) {
    Acceptor::init(nullptr, &base_);
  }
  void onNewConnection(AsyncTransportWrapper::UniquePtr,
                       const folly::SocketAddress*,
                       const std::string& /* nextProtocolName */,
                       SecureTransportType,
                       const TransportInfo&) override {}
};

class TestAcceptorFactory : public AcceptorFactory {
 public:
  std::shared_ptr<Acceptor> newAcceptor(EventBase*) override {
    return std::make_shared<TestAcceptor>();
  }
};

TEST(Bootstrap, Basic) {
  TestServer server;
  TestClient client;
}

TEST(Bootstrap, ServerWithPipeline) {
  TestServer server;
  server.childPipeline(std::make_shared<TestPipelineFactory>());
  server.bind(0);
  server.stop();
}

TEST(Bootstrap, ServerWithChildHandler) {
  TestServer server;
  server.childHandler(std::make_shared<TestAcceptorFactory>());
  server.bind(0);
  server.stop();
}

TEST(Bootstrap, ClientServerTest) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ClientConnectionManagerTest) {
  // Create a single IO thread, and verify that
  // client connections are pooled properly

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(1));
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());

  client.connect(address);

  TestClient client2;
  client2.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client2.connect(address);

  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 2);
}

TEST(Bootstrap, ServerAcceptGroupTest) {
  // Verify that server is using the accept IO group

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(1), nullptr);
  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  boost::barrier barrier(2);
  auto thread = std::thread([&](){
    TestClient client;
    client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
    client.connect(address);
    EventBaseManager::get()->getEventBase()->loop();
    barrier.wait();
  });
  barrier.wait();
  server.stop();
  thread.join();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ServerAcceptGroup2Test) {
  // Verify that server is using the accept IO group

  // Check if reuse port is supported, if not, don't run this test
  try {
    EventBase base;
    auto serverSocket = AsyncServerSocket::newSocket(&base);
    serverSocket->bind(0);
    serverSocket->listen(0);
    serverSocket->startAccepting();
    serverSocket->setReusePortEnabled(true);
    serverSocket->stopAccepting();
  } catch(...) {
    LOG(INFO) << "Reuse port probably not supported";
    return;
  }

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(4), nullptr);
  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());

  client.connect(address);
  EventBaseManager::get()->getEventBase()->loop();

  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, SharedThreadPool) {
  // Check if reuse port is supported, if not, don't run this test
  try {
    EventBase base;
    auto serverSocket = AsyncServerSocket::newSocket(&base);
    serverSocket->bind(0);
    serverSocket->listen(0);
    serverSocket->startAccepting();
    serverSocket->setReusePortEnabled(true);
    serverSocket->stopAccepting();
  } catch(...) {
    LOG(INFO) << "Reuse port probably not supported";
    return;
  }

  auto pool = std::make_shared<IOThreadPoolExecutor>(2);

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(pool, pool);

  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);

  TestClient client2;
  client2.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client2.connect(address);

  TestClient client3;
  client3.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client3.connect(address);

  TestClient client4;
  client4.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client4.connect(address);

  TestClient client5;
  client5.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client5.connect(address);

  EventBaseManager::get()->getEventBase()->loop();

  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 5);
}

TEST(Bootstrap, ExistingSocket) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  folly::AsyncServerSocket::UniquePtr socket(new AsyncServerSocket);
  server.bind(std::move(socket));
}

std::atomic<int> connections{0};

class TestHandlerPipeline : public InboundHandler<AcceptPipelineType> {
 public:
  void read(Context* ctx, AcceptPipelineType conn) override {
    if (conn.type() == typeid(ConnEvent)) {
      auto connEvent = boost::get<ConnEvent>(conn);
      if (connEvent == ConnEvent::CONN_ADDED) {
        connections++;
      }
    }
    return ctx->fireRead(conn);
  }
};

template <typename HandlerPipeline>
class TestHandlerPipelineFactory : public AcceptPipelineFactory {
 public:
  AcceptPipeline::Ptr newPipeline(Acceptor*) override {
    auto pipeline = AcceptPipeline::create();
    pipeline->addBack(HandlerPipeline());
    return pipeline;
  }
};

TEST(Bootstrap, LoadBalanceHandler) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);

  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestHandlerPipeline>>();
  server.pipeline(pipelinefactory);
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
  EXPECT_EQ(connections, 1);
}

class TestUDPPipeline : public InboundHandler<AcceptPipelineType, Unit> {
 public:
  void read(Context*, AcceptPipelineType) override { connections++; }
};

TEST(Bootstrap, UDP) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestUDPPipeline>>();
  server.pipeline(pipelinefactory);
  server.channelFactory(std::make_shared<AsyncUDPServerSocketFactory>());
  server.bind(0);
}

TEST(Bootstrap, UDPClientServerTest) {
  connections = 0;

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestUDPPipeline>>();
  server.pipeline(pipelinefactory);
  server.channelFactory(std::make_shared<AsyncUDPServerSocketFactory>());
  server.bind(0);

  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  SocketAddress localhost("::1", 0);
  AsyncUDPSocket client(base);
  client.bind(localhost);
  auto data = IOBuf::create(1);
  data->append(1);
  *(data->writableData()) = 'a';
  client.write(address, std::move(data));
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(connections, 1);
}

TEST(Bootstrap, UnixServer) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();

  folly::test::TemporaryDirectory tmpdir("wangle-bootstrap-test");
  auto socketPath = (tmpdir.path() / "sock").string();

  server.childPipeline(factory);
  SocketAddress address;
  address.setFromPath(socketPath);
  server.bind(address);
  auto base = EventBaseManager::get()->getEventBase();

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  auto pipelineFuture = client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_TRUE(pipelineFuture.get() != nullptr);
  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ServerBindFailure) {
  // Bind to a TCP socket
  EventBase base;
  auto serverSocket = AsyncServerSocket::newSocket(&base);
  serverSocket->bind(0);
  serverSocket->listen(0);

  SocketAddress address;
  serverSocket->getAddress(&address);

  // Now try starting a server using the address we are already listening on
  // This should fail.

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  try {
    server.bind(address);
    FAIL() << "shouldn't be allowed to bind to an in-use address";
  } catch (const std::system_error& ex) {
    EXPECT_EQ(EADDRINUSE, ex.code().value()) << "unexpected error code " <<
      ex.code().value() << ": " << ex.code().message();
  }
}
<commit_msg>use rvalue-qual Future::get()<commit_after>/*
 * Copyright 2017-present Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "wangle/bootstrap/ServerBootstrap.h"
#include "wangle/bootstrap/ClientBootstrap.h"
#include "wangle/channel/Handler.h"

#include <glog/logging.h>
#include <gtest/gtest.h>
#include <boost/thread.hpp>
#include <folly/String.h>
#include <folly/experimental/TestUtil.h>

using namespace wangle;
using namespace folly;

typedef Pipeline<IOBufQueue&, std::unique_ptr<IOBuf>> BytesPipeline;

typedef ServerBootstrap<BytesPipeline> TestServer;
typedef ClientBootstrap<BytesPipeline> TestClient;

class TestClientPipelineFactory : public PipelineFactory<BytesPipeline> {
 public:
  BytesPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper> sock) override {
    // Socket should be connected already
    EXPECT_TRUE(sock->good());

    // Check after a small delay that socket is readable
    EventBaseManager::get()->getEventBase()->tryRunAfterDelay([sock](){
      EXPECT_TRUE(sock->readable());
    }, 100);

    auto pipeline = BytesPipeline::create();
    pipeline->addBack(new BytesToBytesHandler());
    pipeline->finalize();
    return pipeline;
  }
};

class TestPipelineFactory : public PipelineFactory<BytesPipeline> {
 public:
  BytesPipeline::Ptr newPipeline(
      std::shared_ptr<AsyncTransportWrapper>) override {
    pipelines++;
    auto pipeline = BytesPipeline::create();
    pipeline->addBack(new BytesToBytesHandler());
    pipeline->finalize();
    return pipeline;
  }
  std::atomic<int> pipelines{0};
};

class TestAcceptor : public Acceptor {
EventBase base_;
 public:
  TestAcceptor() : Acceptor(ServerSocketConfig()) {
    Acceptor::init(nullptr, &base_);
  }
  void onNewConnection(AsyncTransportWrapper::UniquePtr,
                       const folly::SocketAddress*,
                       const std::string& /* nextProtocolName */,
                       SecureTransportType,
                       const TransportInfo&) override {}
};

class TestAcceptorFactory : public AcceptorFactory {
 public:
  std::shared_ptr<Acceptor> newAcceptor(EventBase*) override {
    return std::make_shared<TestAcceptor>();
  }
};

TEST(Bootstrap, Basic) {
  TestServer server;
  TestClient client;
}

TEST(Bootstrap, ServerWithPipeline) {
  TestServer server;
  server.childPipeline(std::make_shared<TestPipelineFactory>());
  server.bind(0);
  server.stop();
}

TEST(Bootstrap, ServerWithChildHandler) {
  TestServer server;
  server.childHandler(std::make_shared<TestAcceptorFactory>());
  server.bind(0);
  server.stop();
}

TEST(Bootstrap, ClientServerTest) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ClientConnectionManagerTest) {
  // Create a single IO thread, and verify that
  // client connections are pooled properly

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(1));
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());

  client.connect(address);

  TestClient client2;
  client2.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client2.connect(address);

  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 2);
}

TEST(Bootstrap, ServerAcceptGroupTest) {
  // Verify that server is using the accept IO group

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(1), nullptr);
  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  boost::barrier barrier(2);
  auto thread = std::thread([&](){
    TestClient client;
    client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
    client.connect(address);
    EventBaseManager::get()->getEventBase()->loop();
    barrier.wait();
  });
  barrier.wait();
  server.stop();
  thread.join();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ServerAcceptGroup2Test) {
  // Verify that server is using the accept IO group

  // Check if reuse port is supported, if not, don't run this test
  try {
    EventBase base;
    auto serverSocket = AsyncServerSocket::newSocket(&base);
    serverSocket->bind(0);
    serverSocket->listen(0);
    serverSocket->startAccepting();
    serverSocket->setReusePortEnabled(true);
    serverSocket->stopAccepting();
  } catch(...) {
    LOG(INFO) << "Reuse port probably not supported";
    return;
  }

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(std::make_shared<IOThreadPoolExecutor>(4), nullptr);
  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());

  client.connect(address);
  EventBaseManager::get()->getEventBase()->loop();

  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, SharedThreadPool) {
  // Check if reuse port is supported, if not, don't run this test
  try {
    EventBase base;
    auto serverSocket = AsyncServerSocket::newSocket(&base);
    serverSocket->bind(0);
    serverSocket->listen(0);
    serverSocket->startAccepting();
    serverSocket->setReusePortEnabled(true);
    serverSocket->stopAccepting();
  } catch(...) {
    LOG(INFO) << "Reuse port probably not supported";
    return;
  }

  auto pool = std::make_shared<IOThreadPoolExecutor>(2);

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  server.group(pool, pool);

  server.bind(0);

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);

  TestClient client2;
  client2.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client2.connect(address);

  TestClient client3;
  client3.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client3.connect(address);

  TestClient client4;
  client4.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client4.connect(address);

  TestClient client5;
  client5.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client5.connect(address);

  EventBaseManager::get()->getEventBase()->loop();

  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 5);
}

TEST(Bootstrap, ExistingSocket) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  folly::AsyncServerSocket::UniquePtr socket(new AsyncServerSocket);
  server.bind(std::move(socket));
}

std::atomic<int> connections{0};

class TestHandlerPipeline : public InboundHandler<AcceptPipelineType> {
 public:
  void read(Context* ctx, AcceptPipelineType conn) override {
    if (conn.type() == typeid(ConnEvent)) {
      auto connEvent = boost::get<ConnEvent>(conn);
      if (connEvent == ConnEvent::CONN_ADDED) {
        connections++;
      }
    }
    return ctx->fireRead(conn);
  }
};

template <typename HandlerPipeline>
class TestHandlerPipelineFactory : public AcceptPipelineFactory {
 public:
  AcceptPipeline::Ptr newPipeline(Acceptor*) override {
    auto pipeline = AcceptPipeline::create();
    pipeline->addBack(HandlerPipeline());
    return pipeline;
  }
};

TEST(Bootstrap, LoadBalanceHandler) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);

  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestHandlerPipeline>>();
  server.pipeline(pipelinefactory);
  server.bind(0);
  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(factory->pipelines, 1);
  EXPECT_EQ(connections, 1);
}

class TestUDPPipeline : public InboundHandler<AcceptPipelineType, Unit> {
 public:
  void read(Context*, AcceptPipelineType) override { connections++; }
};

TEST(Bootstrap, UDP) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestUDPPipeline>>();
  server.pipeline(pipelinefactory);
  server.channelFactory(std::make_shared<AsyncUDPServerSocketFactory>());
  server.bind(0);
}

TEST(Bootstrap, UDPClientServerTest) {
  connections = 0;

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  auto pipelinefactory =
    std::make_shared<TestHandlerPipelineFactory<TestUDPPipeline>>();
  server.pipeline(pipelinefactory);
  server.channelFactory(std::make_shared<AsyncUDPServerSocketFactory>());
  server.bind(0);

  auto base = EventBaseManager::get()->getEventBase();

  SocketAddress address;
  server.getSockets()[0]->getAddress(&address);

  SocketAddress localhost("::1", 0);
  AsyncUDPSocket client(base);
  client.bind(localhost);
  auto data = IOBuf::create(1);
  data->append(1);
  *(data->writableData()) = 'a';
  client.write(address, std::move(data));
  base->loop();
  server.stop();
  server.join();

  EXPECT_EQ(connections, 1);
}

TEST(Bootstrap, UnixServer) {
  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();

  folly::test::TemporaryDirectory tmpdir("wangle-bootstrap-test");
  auto socketPath = (tmpdir.path() / "sock").string();

  server.childPipeline(factory);
  SocketAddress address;
  address.setFromPath(socketPath);
  server.bind(address);
  auto base = EventBaseManager::get()->getEventBase();

  TestClient client;
  client.pipelineFactory(std::make_shared<TestClientPipelineFactory>());
  auto pipelineFuture = client.connect(address);
  base->loop();
  server.stop();
  server.join();

  EXPECT_TRUE(std::move(pipelineFuture).get() != nullptr);
  EXPECT_EQ(factory->pipelines, 1);
}

TEST(Bootstrap, ServerBindFailure) {
  // Bind to a TCP socket
  EventBase base;
  auto serverSocket = AsyncServerSocket::newSocket(&base);
  serverSocket->bind(0);
  serverSocket->listen(0);

  SocketAddress address;
  serverSocket->getAddress(&address);

  // Now try starting a server using the address we are already listening on
  // This should fail.

  TestServer server;
  auto factory = std::make_shared<TestPipelineFactory>();
  server.childPipeline(factory);
  try {
    server.bind(address);
    FAIL() << "shouldn't be allowed to bind to an in-use address";
  } catch (const std::system_error& ex) {
    EXPECT_EQ(EADDRINUSE, ex.code().value()) << "unexpected error code " <<
      ex.code().value() << ": " << ex.code().message();
  }
}
<|endoftext|>


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

#include <iostream>
#include <iomanip>
#include "format.h"

////////////////////////////////////////

format_specifier::format_specifier( const char * &fmt, const char *end )
	: index( 0 ), width( -1 ), base( 10 ), precision( -1 ), alignment( -1 ), fill( ' ' ), separator( '\0' ), upper_case( false ), show_plus( false ), count( 1 )
{
	if ( fmt == end )
		throw std::runtime_error( "empty format specifier" );

	if( *fmt != '{' )
		throw std::runtime_error( "format specifier does not begin with {" );
	++fmt;
	index = parse_number( fmt, end );
	while ( *fmt == ',' )
	{
		++fmt;
		switch ( *fmt )
		{
			case 'w':
				++fmt;
				width = parse_number( fmt, end );
				break;

			case 'b':
				++fmt;
				base = parse_number( fmt, end );
				upper_case = false;
				break;

			case 'B':
				++fmt;
				base = parse_number( fmt, end );
				upper_case = true;
				break;

			case 'f':
				++fmt;
				fill = *fmt;
				++fmt;
				break;

			case '+':
				++fmt;
				show_plus = true;
				break;

			case 'p':
				++fmt;
				precision = parse_number( fmt, end );
				break;

			case 'a':
				++fmt;
				switch ( *fmt )
				{
					case 'l': alignment = -1; break;
					case 'r': alignment = 1; break;
					default: throw std::runtime_error( "unknown alignment" );
				}
				++fmt;
				break;

			case 'n':
				++fmt;
				count = parse_number( fmt, end );
				break;

			case 's':
				++fmt;
				separator = *fmt;
				++fmt;
				break;

			default:
				throw std::runtime_error( "unknown format specifier" );
		}
	}

	if ( *fmt == '#' )
	{
		while ( fmt != end && *fmt != '}' )
			++fmt;
	}

	if ( *fmt != '}' )
		throw std::runtime_error( "format specifier did not end with }" );
}

////////////////////////////////////////

void
format_specifier::apply( std::ostream &out )
{
	if ( width >= 0 )
		out.width( width );

	out.unsetf( std::ios_base::basefield );
	switch ( base )
	{
		case 8: out.setf( std::ios_base::oct ); break;
		case 10: out.setf( std::ios_base::dec ); break;
		case 16: out.setf( std::ios_base::hex ); break;
		default: throw std::runtime_error( "unsupported base" );
	}

	out.unsetf( std::ios_base::floatfield );
	if ( precision >= 0 )
	{
		out.setf( std::ios_base::fixed );
		out.precision( precision );
	}
	else
		out.setf( std::ios_base::scientific );

	out.unsetf( std::ios_base::adjustfield );
	if ( alignment < 0 )
		out.setf( std::ios_base::left );
	else if ( alignment > 0 )
		out.setf( std::ios_base::right );

	out.fill( fill );

	if ( upper_case )
		out.setf( std::ios_base::uppercase );
	else
		out.unsetf( std::ios_base::uppercase );

	if ( show_plus )
		out.setf( std::ios_base::showpos );
	else
		out.unsetf( std::ios_base::showpos );
}

////////////////////////////////////////

bool
format_specifier::begin( const char * &fmt, const char *end )
{
	while ( fmt != end && *fmt != '{' )
		++fmt;

	return fmt != end;
}

////////////////////////////////////////

int
format_specifier::parse_number( const char * &fmt, const char *end )
{
	int n = 0;
	int digits = 0;

	while ( fmt != end )
	{
		if ( !isdigit( *fmt ) )
			break;

		n = n * 10 + ( *fmt - '0' );
		digits++;
		fmt++;
	}

	if ( digits == 0 )
		throw std::runtime_error( "expected number" );

	return n;
}

////////////////////////////////////////

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

#include <iostream>
#include <iomanip>
#include "format.h"

////////////////////////////////////////

format_specifier::format_specifier( const char * &fmt, const char *end )
	: index( 0 ), width( -1 ), base( 10 ), precision( -1 ), alignment( 0 ), fill( ' ' ), separator( '\0' ), upper_case( false ), show_plus( false ), count( 1 )
{
	if ( fmt == end )
		throw std::runtime_error( "empty format specifier" );

	if( *fmt != '{' )
		throw std::runtime_error( "format specifier does not begin with {" );
	++fmt;
	index = parse_number( fmt, end );
	while ( *fmt == ',' )
	{
		++fmt;
		switch ( *fmt )
		{
			case 'w':
				++fmt;
				width = parse_number( fmt, end );
				break;

			case 'b':
				++fmt;
				base = parse_number( fmt, end );
				upper_case = false;
				break;

			case 'B':
				++fmt;
				base = parse_number( fmt, end );
				upper_case = true;
				break;

			case 'f':
				++fmt;
				fill = *fmt;
				++fmt;
				break;

			case '+':
				++fmt;
				show_plus = true;
				break;

			case 'p':
				++fmt;
				precision = parse_number( fmt, end );
				break;

			case 'a':
				++fmt;
				switch ( *fmt )
				{
					case 'l': alignment = -1; break;
					case 'r': alignment = 1; break;
					default: throw std::runtime_error( "unknown alignment" );
				}
				++fmt;
				break;

			case 'n':
				++fmt;
				count = parse_number( fmt, end );
				break;

			case 's':
				++fmt;
				separator = *fmt;
				++fmt;
				break;

			default:
				throw std::runtime_error( "unknown format specifier" );
		}
	}

	if ( *fmt == '#' )
	{
		while ( fmt != end && *fmt != '}' )
			++fmt;
	}

	if ( *fmt != '}' )
		throw std::runtime_error( "format specifier did not end with }" );
}

////////////////////////////////////////

void
format_specifier::apply( std::ostream &out )
{
	if ( width >= 0 )
		out.width( width );

	out.unsetf( std::ios_base::basefield );
	switch ( base )
	{
		case 8: out.setf( std::ios_base::oct ); break;
		case 10: out.setf( std::ios_base::dec ); break;
		case 16: out.setf( std::ios_base::hex ); break;
		default: throw std::runtime_error( "unsupported base" );
	}

	out.unsetf( std::ios_base::floatfield );
	if ( precision >= 0 )
	{
		out.setf( std::ios_base::fixed );
		out.precision( precision );
	}
	else
		out.setf( std::ios_base::scientific );

	out.unsetf( std::ios_base::adjustfield );
	if ( alignment < 0 )
		out.setf( std::ios_base::left );
	else if ( alignment > 0 )
		out.setf( std::ios_base::right );

	out.fill( fill );

	if ( upper_case )
		out.setf( std::ios_base::uppercase );
	else
		out.unsetf( std::ios_base::uppercase );

	if ( show_plus )
		out.setf( std::ios_base::showpos );
	else
		out.unsetf( std::ios_base::showpos );
}

////////////////////////////////////////

bool
format_specifier::begin( const char * &fmt, const char *end )
{
	while ( fmt != end && *fmt != '{' )
		++fmt;

	return fmt != end;
}

////////////////////////////////////////

int
format_specifier::parse_number( const char * &fmt, const char *end )
{
	int n = 0;
	int digits = 0;

	while ( fmt != end )
	{
		if ( !isdigit( *fmt ) )
			break;

		n = n * 10 + ( *fmt - '0' );
		digits++;
		fmt++;
	}

	if ( digits == 0 )
		throw std::runtime_error( "expected number" );

	return n;
}

////////////////////////////////////////

<|endoftext|>


<commit_before>#include <QColor>
#include <QFile>
#include <QPainter>
#include <qmath.h>
#include <MGConfItem>

#include "networkindicator.h"
#include <contextsubscriber/contextproperty.h>

NetworkIndicator::NetworkIndicator(QDeclarativeItem *parent) :
    QDeclarativeItem(parent),
    m_active(false)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);

    m_themeItem = new MGConfItem("/meego/ux/theme");
    connect(m_themeItem, SIGNAL(valueChanged()), this, SLOT(themeUpdated()));

    themeUpdated();
    setActive(true);
}

void NetworkIndicator::setActive(bool active)
{
    if (active == m_active)
        return;

    m_active = active;
    if (m_active)
    {
        m_networkTypeProperty = new ContextProperty("Internet.NetworkType", this);
        connect(m_networkTypeProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));

        m_networkStateProperty = new ContextProperty("Internet.NetworkState", this);
        connect(m_networkStateProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));

        m_signalStrengthProperty = new ContextProperty("Internet.SignalStrength", this);
        connect(m_signalStrengthProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));
    }
    else
    {
        if (m_networkTypeProperty)
        {
            disconnect(m_networkTypeProperty);
            delete m_networkTypeProperty;
            m_networkTypeProperty = 0;
        }

        if (m_networkStateProperty)
        {
            disconnect(m_networkStateProperty);
            delete m_networkStateProperty;
            m_networkStateProperty = 0;
        }

        if (m_signalStrengthProperty)
        {
            disconnect(m_signalStrengthProperty);
            delete m_signalStrengthProperty;
            m_signalStrengthProperty = 0;
        }
    }
}

void NetworkIndicator::updateIcon()
{
    QGraphicsItem::update(boundingRect());
}

void NetworkIndicator::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
    if (!m_active)
        return;

    QString networkState = m_networkStateProperty->value().toString();
    if (!networkState.isEmpty() && networkState != "disconnected")
    {
        // TODO: Add support for displaying the operator name while roaming

        int offset = 0;
        double percentage = m_signalStrengthProperty->value().toDouble();
        QString networkType = m_networkTypeProperty->value().toString();

        if (networkType != "ethernet")
        {
            p->drawPixmap(0, 0, m_signalStrengthPixmaps[qCeil(percentage * 4.0)]);
            offset = m_signalStrengthPixmaps[0].width();
        }

        if (networkType == "WLAN")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Wifi]);
        else if (networkType == "wimax")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Wimax]);
        else if (networkType == "GPRS")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[GPRS]);
        else if (networkType == "bluetooth")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Bluetooth]);
        else
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Ethernet]);

        setImplicitWidth(offset + m_networkTypePixmaps[0].width());
        setImplicitHeight(m_networkTypePixmaps[0].height());
    }
    else
    {
        p->drawPixmap(0, 0, m_signalStrengthPixmaps[0]);
        setImplicitWidth(m_signalStrengthPixmaps[0].width());
        setImplicitHeight(m_signalStrengthPixmaps[0].height());
    }
}

void NetworkIndicator::themeUpdated()
{
    QString path = QString("/usr/share/themes/%1/icons/statusbar/").arg(m_themeItem->value().toString());
    if (QDir(path).exists())
    {
        m_networkTypePixmaps[GPRS].load(path + "3g-on.png");
        m_networkTypePixmaps[Wifi].load(path + "wifi-on.png");
        m_networkTypePixmaps[Bluetooth].load(path + "bluetooth-on.png");
        m_networkTypePixmaps[Wimax].load(path + "4g-on.png");
        m_networkTypePixmaps[Ethernet].load(path + "network-ethernet.png");

        m_signalStrengthPixmaps[0].load(path + "signal-none.png");
        m_signalStrengthPixmaps[1].load(path + "signal-weak.png");
        m_signalStrengthPixmaps[2].load(path + "signal-ok.png");
        m_signalStrengthPixmaps[3].load(path + "signal-good.png");
        m_signalStrengthPixmaps[4].load(path + "signal-strong.png");
    }
}

QML_DECLARE_TYPE(NetworkIndicator);

<commit_msg>add networkindicator.cpp<commit_after>#include <QColor>
#include <QFile>
#include <QPainter>
#include <qmath.h>
#include <MGConfItem>

#include "networkindicator.h"
#include <contextsubscriber/contextproperty.h>

NetworkIndicator::NetworkIndicator(QDeclarativeItem *parent) :
    QDeclarativeItem(parent),
    m_active(false)
{
    setFlag(QGraphicsItem::ItemHasNoContents, false);

    m_themeItem = new MGConfItem("/meego/ux/theme");
    connect(m_themeItem, SIGNAL(valueChanged()), this, SLOT(themeUpdated()));

    themeUpdated();
    setActive(true);
}

void NetworkIndicator::setActive(bool active)
{
    if (active == m_active)
        return;

    m_active = active;
    if (m_active)
    {
        m_networkTypeProperty = new ContextProperty("Internet.NetworkType", this);
        connect(m_networkTypeProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));

        m_networkStateProperty = new ContextProperty("Internet.NetworkState", this);
        connect(m_networkStateProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));

        m_signalStrengthProperty = new ContextProperty("Internet.SignalStrength", this);
        connect(m_signalStrengthProperty, SIGNAL(valueChanged()), this, SLOT(updateIcon()));
    }
    else
    {
        if (m_networkTypeProperty)
        {
            disconnect(m_networkTypeProperty);
            delete m_networkTypeProperty;
            m_networkTypeProperty = 0;
        }

        if (m_networkStateProperty)
        {
            disconnect(m_networkStateProperty);
            delete m_networkStateProperty;
            m_networkStateProperty = 0;
        }

        if (m_signalStrengthProperty)
        {
            disconnect(m_signalStrengthProperty);
            delete m_signalStrengthProperty;
            m_signalStrengthProperty = 0;
        }
    }
}

void NetworkIndicator::updateIcon()
{
    QGraphicsItem::update(boundingRect());
}

void NetworkIndicator::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWidget *)
{
    if (!m_active)
        return;

    QString networkState = m_networkStateProperty->value().toString();
    if (!networkState.isEmpty() && networkState != "disconnected")
    {
        // TODO: Add support for displaying the operator name while roaming

        int offset = 0;
        int strength = m_signalStrengthProperty->value().toInt();
        QString networkType = m_networkTypeProperty->value().toString();

        if (networkType != "ethernet")
        {
           int index = strength < 0 || strength > 100 ? 0 : qCeil(((double)strength/100.0) * 4.0);
	   p->drawPixmap(0, 0, m_signalStrengthPixmaps[index]);
           offset = m_signalStrengthPixmaps[0].width();
        }

        if (networkType == "WLAN")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Wifi]);
        else if (networkType == "wimax")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Wimax]);
        else if (networkType == "GPRS")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[GPRS]);
        else if (networkType == "bluetooth")
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Bluetooth]);
        else
            p->drawPixmap(offset, 0, m_networkTypePixmaps[Ethernet]);

        setImplicitWidth(offset + m_networkTypePixmaps[0].width());
        setImplicitHeight(m_networkTypePixmaps[0].height());
    }
    else
    {
        p->drawPixmap(0, 0, m_signalStrengthPixmaps[0]);
        setImplicitWidth(m_signalStrengthPixmaps[0].width());
        setImplicitHeight(m_signalStrengthPixmaps[0].height());
    }
}

void NetworkIndicator::themeUpdated()
{
    QString path = QString("/usr/share/themes/%1/icons/statusbar/").arg(m_themeItem->value().toString());
    if (QDir(path).exists())
    {
        m_networkTypePixmaps[GPRS].load(path + "3g-on.png");
        m_networkTypePixmaps[Wifi].load(path + "wifi-on.png");
        m_networkTypePixmaps[Bluetooth].load(path + "bluetooth-on.png");
        m_networkTypePixmaps[Wimax].load(path + "4g-on.png");
        m_networkTypePixmaps[Ethernet].load(path + "network-ethernet.png");

        m_signalStrengthPixmaps[0].load(path + "signal-none.png");
        m_signalStrengthPixmaps[1].load(path + "signal-weak.png");
        m_signalStrengthPixmaps[2].load(path + "signal-ok.png");
        m_signalStrengthPixmaps[3].load(path + "signal-good.png");
        m_signalStrengthPixmaps[4].load(path + "signal-strong.png");
    }
}

QML_DECLARE_TYPE(NetworkIndicator);

<|endoftext|>