<commit_before>#include <fstream>

#include <chdl/chdl.h>
#include <chdl/cassign.h>
#include <chdl/egress.h>

#include "config.h"
#include "interfaces.h"
#include "harpinst.h"

using namespace std;
using namespace chdl;

void Funcunit_lsu(func_splitter_t &out, reg_func_t &in);

void MemSystem(mem_resp_t &out, mem_req_t &in);

// Load/store unit
void Funcunit_lsu(func_splitter_t &out, reg_func_t &in)
{
  HIERARCHY_ENTER();

  mem_req_t req;
  mem_resp_t resp;

  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  bvec<L> active(_(_(_(in, "contents"), "warp"), "active"));

  // Connect "in" to "req"
  _(in, "ready") = _(req, "ready");
  _(req, "valid") = _(in, "valid");
  _(_(req, "contents"), "warp") = _(_(in, "contents"), "warp");
  _(_(req, "contents"), "wr") = inst.is_store();
  _(_(req, "contents"), "mask") =
    _(_(_(in, "contents"), "pval"), "pmask") & active;
  for (unsigned l = 0; l < L; ++l) {
    _(_(req, "contents"), "a")[l] =
      Mux(inst.is_store(),
        _(_(_(in, "contents"), "rval"), "val0")[l] + inst.get_imm(),
        _(_(_(in, "contents"), "rval"), "val1")[l] + inst.get_imm()
      );
    _(_(req, "contents"), "d")[l] =
      _(_(_(in, "contents"), "rval"), "val0")[l];
  }

  // Keep track of whether operations issued to memory system were stores
  node issue(_(in, "ready") && _(in, "valid"));
  bvec<L> ldMask(Wreg(issue,
    bvec<L>(inst.has_rdst()) & _(_(_(in, "contents"), "pval"), "pmask")
  ));
  bvec<RR> ldDest(Wreg(issue, inst.get_rdst()));

  // Connect "out" to resp
  _(resp, "ready") = _(out, "ready");
  _(out, "valid") = _(resp, "valid");
  _(_(out, "contents"), "warp") = _(_(resp, "contents"), "warp");
  _(_(_(out,"contents"),"rwb"),"wid") = _(_(_(resp,"contents"),"warp"),"id");
  _(_(_(out,"contents"),"rwb"),"mask") = ldMask;
  _(_(_(out,"contents"),"rwb"),"dest") = ldDest;
  _(_(_(out,"contents"),"rwb"),"val") = _(_(resp,"contents"),"q");

  MemSystem(resp, req);

  tap("lsu_out", out);
  tap("lsu_in", in);

  HIERARCHY_EXIT();
}

void DummyCache(cache_resp_t &out, cache_req_t &in) {
  node ready = _(out, "ready");
  _(in, "ready") = ready;

  node ldregs(ready && _(in, "valid")), next_full, full(Reg(next_full));

  Cassign(next_full).
    IF(!full && _(in, "valid") && ready, Lit(1)).
    IF(full && (!_(in, "valid") || !ready), Lit(0)).
    ELSE(full);

  _(out, "valid") = full;
  _(_(out, "contents"), "warp") = Wreg(ldregs, _(_(in, "contents"), "warp"));

  bvec<N> a(_(_(in, "contents"), "a"));
  bvec<10> devAddr(a[range<CLOG2(LINE*(N/8)), CLOG2(LINE*(N/8))+9>()]);

  vec<LINE, bvec<N> > memd(_(_(in, "contents"), "d"));
  vec<LINE, bvec<N> > memq;
  for (unsigned i = 0; i < LINE; ++i) {
    node wr(ready && _(in, "valid") && _(_(in, "contents"), "mask")[i] &&
              _(_(in, "contents"), "wr"));

    memq[i] = Syncmem(devAddr, memd[i], wr);

    if (i == 0 && SOFT_IO && !FPGA) {
      static unsigned consoleOutVal;
      node wrConsole(wr && a[N-1]);
      EgressInt(consoleOutVal, memd[i]);
      EgressFunc(
        [](bool x){if (x) cout << char(consoleOutVal);},
        wrConsole
      );
    }

    if (i == 0 && FPGA && FPGA_IO) {
      node wrConsole(wr && a[N-1]);
      OUTPUT(wrConsole);
      bvec<8> consoleOutVal(memd[i][range<0,7>()]);
      OUTPUT(consoleOutVal);
    }
  }

  if (!FPGA && DEBUG_MEM) {
    static unsigned long addrVal, dVal[LINE], qVal[LINE], warpId;
    static bool wrVal, maskVal[LINE];
    Egress(wrVal, Reg(ready && _(in, "valid") && _(_(in, "contents"), "wr")));
    for (unsigned l = 0; l < LINE; ++l) {
      EgressInt(dVal[l], Reg(memd[l]));
      Egress(maskVal[l], Reg(_(_(in, "contents"), "mask")[l]));
      EgressInt(qVal[l], memq[l]);
    }

    EgressInt(addrVal, Reg(a));
    EgressInt(warpId, Reg(_(_(_(in, "contents"), "warp"), "id")));
    EgressFunc([](bool x) {
      if (x) {
        cout << warpId << ": Mem " << (wrVal?"store":"load") << ':' << endl;
        for (unsigned l = 0; l < LINE; ++l) {
          if (maskVal[l]) {
            cout << "  0x" << hex << addrVal + l*(N/8);
            if (wrVal) cout << hex << ": 0x" << dVal[l];
            else cout << hex << ": 0x" << qVal[l];
            cout << endl;
          }
        }
      }
    }, Reg(ready && _(in, "valid")));
  }

  vec<LINE, bvec<N> > held_memq;
  Flatten(held_memq) = Wreg(ldregs, Flatten(memq));

  tap("dummy_cache_memq", memq);
  TAP(devAddr);

  Flatten(_(_(out, "contents"), "q")) =
    Mux(ready && Reg(ready), Flatten(held_memq), Flatten(memq));

  _(_(out, "contents"), "lane") = Wreg(ldregs, _(_(in, "contents"), "lane"));
}

void MemSystem(mem_resp_t &out, mem_req_t &in) {
  HIERARCHY_ENTER();
  // TODO: Add an associative table to enable cache_resps to arrive out-of-order
  // e.g. from a non-blocking cache.

  node next_full, full(Reg(next_full)), fill, empty;
  _(in, "ready") = !full;
  next_full = (full && !empty) || (!full && fill && !empty);
  fill = _(in, "valid") && !full;

  vec<L, bvec<L> > eqmat; // Coalesce matrix: which addresses are equal?
  bvec<L> covered, // Is my request covered by that of a prior lane?
          mask(_(_(in, "contents"), "mask"));
  cache_req_t cache_req;
  cache_resp_t cache_resp;

  vec<L, bvec<N> > a(_(_(in, "contents"), "a"));

  for (unsigned i = 0; i < L; ++i) {
    for (unsigned j = i; j < L; ++j)
      eqmat[i][j] = Lit(0);
    for (unsigned j = 0; j < i; ++j) {
      bvec<N-CLOG2(LINE*(N/8))> ai(a[i][range<CLOG2(LINE*(N/8)), N-1>()]),
                                aj(a[j][range<CLOG2(LINE*(N/8)), N-1>()]);
      eqmat[i][j] = ai == aj && mask[i] && mask[j];
    }
    covered[i] = OrN(eqmat[i]);
  }

  bvec<L> allReqMask(Wreg(fill, ~covered & mask)),
          next_sentReqMask, sentReqMask(Reg(next_sentReqMask)),
          next_returnedReqMask, returnedReqMask(Reg(next_returnedReqMask));

  bvec<L> ldqReg;
  vec<L, bvec<L> > eqmatReg;
  vec<L, bvec<N> > aReg, dReg, qReg;
  for (unsigned l = 0; l < L; ++l) {
    for (unsigned i = 0; i < L; ++i) {
      if (i == l) eqmatReg[l][i] = Lit(1);
      else        eqmatReg[l][i] = Wreg(fill, eqmat[i][l]);
    }
    aReg[l] = Wreg(fill, a[l]);
    dReg[l] = Wreg(fill, _(_(in, "contents"), "d")[l]);
    qReg[l] = Wreg(ldqReg[l] && _(cache_resp,"valid") && _(cache_resp,"ready"),
                   Mux(aReg[l][range<CLOG2(N/8), CLOG2(N/8*LINE)-1>()],
                       _(_(cache_resp,"contents"),"q")) >>
                   Cat(aReg[l][range<0, CLOG2(N/8) - 1>()], Lit<3>(0)));
  }

  bvec<LL> sel(Lsb(allReqMask & ~sentReqMask));

  TAP(eqmat); TAP(covered); TAP(allReqMask); TAP(sentReqMask);
  TAP(returnedReqMask); TAP(sel);

  Cassign(next_sentReqMask).
    IF(fill, Lit<L>(0)).
    IF(_(cache_req, "ready") && (sentReqMask != allReqMask),
       sentReqMask | Lit<L>(1)<<sel).
    ELSE(sentReqMask);

  bvec<N> reqAddr(Mux(sel, aReg) & ~Lit<N>(LINE*(N/8)-1));

  _(_(cache_req, "contents"), "a") = reqAddr;
  _(_(cache_req, "contents"), "lane") = sel;
  _(_(cache_req, "contents"), "warp") = Wreg(fill, _(_(in, "contents"),"warp"));
  _(_(cache_req, "contents"), "wr") = Wreg(fill, _(_(in, "contents"), "wr"));

  tap("mem_aReg", aReg);  tap("mem_dReg", dReg); tap("mem_qReg", qReg);

  for (unsigned i = 0; i < LINE; ++i) {
    const unsigned NB(CLOG2(N/8)), // log2(N), expressed in (8-bit) bytes
                   LB(NB + CLOG2(LINE)); // log2(bytes in a cache line)

    bvec<L> maskBits;
    for (unsigned l = 0; l < L; ++l)
      maskBits[l] =
        (aReg[l][range<NB, LB-1>()]==Lit<CLOG2(LINE)>(i)) &&
        (aReg[l][range<LB, N-1>()] == reqAddr[range<LB, N-1>()]) &&
        allReqMask[l];

    _(_(cache_req, "contents"), "mask")[i] = OrN(maskBits);
    _(_(cache_req, "contents"), "d")[i] = Mux(Log2(maskBits), dReg);
  }

  TAP(cache_req);
  TAP(cache_resp);

  _(cache_req, "valid") = full && sentReqMask != allReqMask;

  DummyCache(cache_resp, cache_req);

  _(cache_resp, "ready") = full && returnedReqMask != allReqMask;

  Cassign(next_returnedReqMask).
    IF(fill, Lit<L>(0)).
    IF(_(cache_resp, "ready") && _(cache_resp, "valid"),
      returnedReqMask | Lit<L>(1)<<_(_(cache_resp, "contents"),"lane")).
    ELSE(returnedReqMask);

  // Load these lanes' q registers for this response.
  ldqReg = Mux(_(_(cache_resp,"contents"),"lane"), eqmatReg);

  ASSERT(!OrN(returnedReqMask & ~sentReqMask));

  _(out, "valid") = full && (returnedReqMask == allReqMask);

  _(_(out, "contents"), "warp") = Wreg(fill, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "q") = qReg;

  empty = _(out, "valid") && _(out, "ready");

  tap("mem_fill", fill);
  tap("mem_empty", empty);
  tap("mem_full", full);
  tap("mem_in", in);
  tap("mem_out", out);
  tap("mem_reqAddr", reqAddr);
  tap("mem_ldqReg", ldqReg);
  tap("mem_eqmatReg", eqmatReg);

  HIERARCHY_EXIT();
}
<commit_msg>Use already-defined 'NN' variable.<commit_after>#include <fstream>

#include <chdl/chdl.h>
#include <chdl/cassign.h>
#include <chdl/egress.h>

#include "config.h"
#include "interfaces.h"
#include "harpinst.h"

using namespace std;
using namespace chdl;

void Funcunit_lsu(func_splitter_t &out, reg_func_t &in);

void MemSystem(mem_resp_t &out, mem_req_t &in);

// Load/store unit
void Funcunit_lsu(func_splitter_t &out, reg_func_t &in)
{
  HIERARCHY_ENTER();

  mem_req_t req;
  mem_resp_t resp;

  harpinst<N, RR, RR> inst(_(_(in, "contents"), "ir"));

  bvec<L> active(_(_(_(in, "contents"), "warp"), "active"));

  // Connect "in" to "req"
  _(in, "ready") = _(req, "ready");
  _(req, "valid") = _(in, "valid");
  _(_(req, "contents"), "warp") = _(_(in, "contents"), "warp");
  _(_(req, "contents"), "wr") = inst.is_store();
  _(_(req, "contents"), "mask") =
    _(_(_(in, "contents"), "pval"), "pmask") & active;
  for (unsigned l = 0; l < L; ++l) {
    _(_(req, "contents"), "a")[l] =
      Mux(inst.is_store(),
        _(_(_(in, "contents"), "rval"), "val0")[l] + inst.get_imm(),
        _(_(_(in, "contents"), "rval"), "val1")[l] + inst.get_imm()
      );
    _(_(req, "contents"), "d")[l] =
      _(_(_(in, "contents"), "rval"), "val0")[l];
  }

  // Keep track of whether operations issued to memory system were stores
  node issue(_(in, "ready") && _(in, "valid"));
  bvec<L> ldMask(Wreg(issue,
    bvec<L>(inst.has_rdst()) & _(_(_(in, "contents"), "pval"), "pmask")
  ));
  bvec<RR> ldDest(Wreg(issue, inst.get_rdst()));

  // Connect "out" to resp
  _(resp, "ready") = _(out, "ready");
  _(out, "valid") = _(resp, "valid");
  _(_(out, "contents"), "warp") = _(_(resp, "contents"), "warp");
  _(_(_(out,"contents"),"rwb"),"wid") = _(_(_(resp,"contents"),"warp"),"id");
  _(_(_(out,"contents"),"rwb"),"mask") = ldMask;
  _(_(_(out,"contents"),"rwb"),"dest") = ldDest;
  _(_(_(out,"contents"),"rwb"),"val") = _(_(resp,"contents"),"q");

  MemSystem(resp, req);

  tap("lsu_out", out);
  tap("lsu_in", in);

  HIERARCHY_EXIT();
}

void DummyCache(cache_resp_t &out, cache_req_t &in) {
  node ready = _(out, "ready");
  _(in, "ready") = ready;

  node ldregs(ready && _(in, "valid")), next_full, full(Reg(next_full));

  Cassign(next_full).
    IF(!full && _(in, "valid") && ready, Lit(1)).
    IF(full && (!_(in, "valid") || !ready), Lit(0)).
    ELSE(full);

  _(out, "valid") = full;
  _(_(out, "contents"), "warp") = Wreg(ldregs, _(_(in, "contents"), "warp"));

  bvec<N> a(_(_(in, "contents"), "a"));
  bvec<10> devAddr(a[range<CLOG2(LINE*(N/8)), CLOG2(LINE*(N/8))+9>()]);

  vec<LINE, bvec<N> > memd(_(_(in, "contents"), "d"));
  vec<LINE, bvec<N> > memq;
  for (unsigned i = 0; i < LINE; ++i) {
    node wr(ready && _(in, "valid") && _(_(in, "contents"), "mask")[i] &&
              _(_(in, "contents"), "wr"));

    memq[i] = Syncmem(devAddr, memd[i], wr);

    if (i == 0 && SOFT_IO && !FPGA) {
      static unsigned consoleOutVal;
      node wrConsole(wr && a[N-1]);
      EgressInt(consoleOutVal, memd[i]);
      EgressFunc(
        [](bool x){if (x) cout << char(consoleOutVal);},
        wrConsole
      );
    }

    if (i == 0 && FPGA && FPGA_IO) {
      node wrConsole(wr && a[N-1]);
      OUTPUT(wrConsole);
      bvec<8> consoleOutVal(memd[i][range<0,7>()]);
      OUTPUT(consoleOutVal);
    }
  }

  if (!FPGA && DEBUG_MEM) {
    static unsigned long addrVal, dVal[LINE], qVal[LINE], warpId;
    static bool wrVal, maskVal[LINE];
    Egress(wrVal, Reg(ready && _(in, "valid") && _(_(in, "contents"), "wr")));
    for (unsigned l = 0; l < LINE; ++l) {
      EgressInt(dVal[l], Reg(memd[l]));
      Egress(maskVal[l], Reg(_(_(in, "contents"), "mask")[l]));
      EgressInt(qVal[l], memq[l]);
    }

    EgressInt(addrVal, Reg(a));
    EgressInt(warpId, Reg(_(_(_(in, "contents"), "warp"), "id")));
    EgressFunc([](bool x) {
      if (x) {
        cout << warpId << ": Mem " << (wrVal?"store":"load") << ':' << endl;
        for (unsigned l = 0; l < LINE; ++l) {
          if (maskVal[l]) {
            cout << "  0x" << hex << addrVal + l*(N/8);
            if (wrVal) cout << hex << ": 0x" << dVal[l];
            else cout << hex << ": 0x" << qVal[l];
            cout << endl;
          }
        }
      }
    }, Reg(ready && _(in, "valid")));
  }

  vec<LINE, bvec<N> > held_memq;
  Flatten(held_memq) = Wreg(ldregs, Flatten(memq));

  tap("dummy_cache_memq", memq);
  TAP(devAddr);

  Flatten(_(_(out, "contents"), "q")) =
    Mux(ready && Reg(ready), Flatten(held_memq), Flatten(memq));

  _(_(out, "contents"), "lane") = Wreg(ldregs, _(_(in, "contents"), "lane"));
}

void MemSystem(mem_resp_t &out, mem_req_t &in) {
  HIERARCHY_ENTER();
  // TODO: Add an associative table to enable cache_resps to arrive out-of-order
  // e.g. from a non-blocking cache.

  node next_full, full(Reg(next_full)), fill, empty;
  _(in, "ready") = !full;
  next_full = (full && !empty) || (!full && fill && !empty);
  fill = _(in, "valid") && !full;

  vec<L, bvec<L> > eqmat; // Coalesce matrix: which addresses are equal?
  bvec<L> covered, // Is my request covered by that of a prior lane?
          mask(_(_(in, "contents"), "mask"));
  cache_req_t cache_req;
  cache_resp_t cache_resp;

  vec<L, bvec<N> > a(_(_(in, "contents"), "a"));

  for (unsigned i = 0; i < L; ++i) {
    for (unsigned j = i; j < L; ++j)
      eqmat[i][j] = Lit(0);
    for (unsigned j = 0; j < i; ++j) {
      bvec<N-CLOG2(LINE*(N/8))> ai(a[i][range<CLOG2(LINE*(N/8)), N-1>()]),
                                aj(a[j][range<CLOG2(LINE*(N/8)), N-1>()]);
      eqmat[i][j] = ai == aj && mask[i] && mask[j];
    }
    covered[i] = OrN(eqmat[i]);
  }

  bvec<L> allReqMask(Wreg(fill, ~covered & mask)),
          next_sentReqMask, sentReqMask(Reg(next_sentReqMask)),
          next_returnedReqMask, returnedReqMask(Reg(next_returnedReqMask));

  bvec<L> ldqReg;
  vec<L, bvec<L> > eqmatReg;
  vec<L, bvec<N> > aReg, dReg, qReg;
  for (unsigned l = 0; l < L; ++l) {
    for (unsigned i = 0; i < L; ++i) {
      if (i == l) eqmatReg[l][i] = Lit(1);
      else        eqmatReg[l][i] = Wreg(fill, eqmat[i][l]);
    }
    aReg[l] = Wreg(fill, a[l]);
    dReg[l] = Wreg(fill, _(_(in, "contents"), "d")[l]);
    qReg[l] = Wreg(ldqReg[l] && _(cache_resp,"valid") && _(cache_resp,"ready"),
                   Mux(aReg[l][range<NN-3, NN-3+CLOG2(LINE)-1>()],
                       _(_(cache_resp,"contents"),"q")) >>
                   Cat(aReg[l][range<0, NN-3 - 1>()], Lit<3>(0)));
  }

  bvec<LL> sel(Lsb(allReqMask & ~sentReqMask));

  TAP(eqmat); TAP(covered); TAP(allReqMask); TAP(sentReqMask);
  TAP(returnedReqMask); TAP(sel);

  Cassign(next_sentReqMask).
    IF(fill, Lit<L>(0)).
    IF(_(cache_req, "ready") && (sentReqMask != allReqMask),
       sentReqMask | Lit<L>(1)<<sel).
    ELSE(sentReqMask);

  bvec<N> reqAddr(Mux(sel, aReg) & ~Lit<N>(LINE*(N/8)-1));

  _(_(cache_req, "contents"), "a") = reqAddr;
  _(_(cache_req, "contents"), "lane") = sel;
  _(_(cache_req, "contents"), "warp") = Wreg(fill, _(_(in, "contents"),"warp"));
  _(_(cache_req, "contents"), "wr") = Wreg(fill, _(_(in, "contents"), "wr"));

  tap("mem_aReg", aReg);  tap("mem_dReg", dReg); tap("mem_qReg", qReg);

  for (unsigned i = 0; i < LINE; ++i) {
    const unsigned NB(CLOG2(N/8)), // log2(N), expressed in (8-bit) bytes
                   LB(NB + CLOG2(LINE)); // log2(bytes in a cache line)

    bvec<L> maskBits;
    for (unsigned l = 0; l < L; ++l)
      maskBits[l] =
        (aReg[l][range<NB, LB-1>()]==Lit<CLOG2(LINE)>(i)) &&
        (aReg[l][range<LB, N-1>()] == reqAddr[range<LB, N-1>()]) &&
        allReqMask[l];

    _(_(cache_req, "contents"), "mask")[i] = OrN(maskBits);
    _(_(cache_req, "contents"), "d")[i] = Mux(Log2(maskBits), dReg);
  }

  TAP(cache_req);
  TAP(cache_resp);

  _(cache_req, "valid") = full && sentReqMask != allReqMask;

  DummyCache(cache_resp, cache_req);

  _(cache_resp, "ready") = full && returnedReqMask != allReqMask;

  Cassign(next_returnedReqMask).
    IF(fill, Lit<L>(0)).
    IF(_(cache_resp, "ready") && _(cache_resp, "valid"),
      returnedReqMask | Lit<L>(1)<<_(_(cache_resp, "contents"),"lane")).
    ELSE(returnedReqMask);

  // Load these lanes' q registers for this response.
  ldqReg = Mux(_(_(cache_resp,"contents"),"lane"), eqmatReg);

  ASSERT(!OrN(returnedReqMask & ~sentReqMask));

  _(out, "valid") = full && (returnedReqMask == allReqMask);

  _(_(out, "contents"), "warp") = Wreg(fill, _(_(in, "contents"), "warp"));
  _(_(out, "contents"), "q") = qReg;

  empty = _(out, "valid") && _(out, "ready");

  tap("mem_fill", fill);
  tap("mem_empty", empty);
  tap("mem_full", full);
  tap("mem_in", in);
  tap("mem_out", out);
  tap("mem_reqAddr", reqAddr);
  tap("mem_ldqReg", ldqReg);
  tap("mem_eqmatReg", eqmatReg);

  HIERARCHY_EXIT();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "monarch/data/json/JsonWriter.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/File.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/io/FileList.h"
#include "monarch/logging/Logging.h"
#include "monarch/modest/Kernel.h"
#include "monarch/net/TcpSocket.h"
#include "monarch/net/Url.h"
#include "monarch/http/CookieJar.h"
#include "monarch/http/HttpHeader.h"
#include "monarch/http/HttpRequest.h"
#include "monarch/http/HttpResponse.h"
#include "monarch/http/HttpConnectionServicer.h"
#include "monarch/http/HttpRequestServicer.h"
#include "monarch/http/HttpClient.h"
#include "monarch/net/Server.h"
#include "monarch/net/NullSocketDataPresenter.h"
#include "monarch/net/SslSocketDataPresenter.h"
#include "monarch/net/SocketDataPresenterList.h"
#include "monarch/rt/Atomic.h"
#include "monarch/rt/ExclusiveLock.h"
#include "monarch/rt/System.h"
#include "monarch/rt/DynamicObject.h"
#include "monarch/rt/DynamicObjectIterator.h"
#include "monarch/test/Test.h"
#include "monarch/test/TestModule.h"
#include "monarch/util/Date.h"
#include "monarch/util/StringTools.h"

using namespace std;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::test;
using namespace monarch::util;

namespace mo_test_pong
{

/**
 * PingPong Test
 *
 * Invoke with the following:
 *
 *   ./monarch-run pong -t pong
 *
 * See configs/apps/pong.config.in for option defaults. Use standard monarch
 * "--json-option key=value" option to adjust options.
 *
 * pong.chunked=<bool>: use chunked encoding
 * pong.dynoStats=<bool>: return DynamicObject stats with regular stats
 * pong.num=<int32>: number of connections to service
 * pong.port=<int32>: port to serve on
 * pong.ssl=<bool>: use SSL
 * pong.time=<int32>: milliseconds to run the test
 * pong.threadStackSize=<int32>: set stack size
 * pong.threads=<int32>: set number of threads
 *
 * Endpoints:
 * /: return "Pong!"
 * /stats: return JSON object with various
 *
 */

// stats and control
class PingPong
{
private:
   uint64_t mStart;
   uint64_t mLast;
   uint64_t mServiced;
   uint64_t mNum;
   ExclusiveLock mLock;
   Config mConfig;

public:
   PingPong(Config cfg) :
      mStart(0),
      mLast(0),
      mServiced(0),
      mConfig(cfg)
   {
      mNum = cfg["num"]->getUInt64();
   }

   virtual ~PingPong() {}

   virtual void start()
   {
      mStart = System::getCurrentMilliseconds();
      mLast = mStart;
   }

   virtual void quit()
   {
      mLock.notifyAll();
   }

   virtual Config& getConfig()
   {
      return mConfig;
   }

   virtual ExclusiveLock& getLock()
   {
      return mLock;
   }

   virtual void service()
   {
      // set last serviced time for effective ping service time
      // avoids counting time between ping and stats calls
      mLast = System::getCurrentMilliseconds();

      // This is a bit sloppy and may do the lock notify multiple times and
      // increase mServiced more than mNum.  Assumption is that this doesn't
      // matter for this sort of performance testing.
      uint64_t s = Atomic::incrementAndFetch(&mServiced);
      if(mNum != 0 && s >= mNum)
      {
         quit();
      }
   }

   virtual DynamicObject getStats()
   {
      uint64_t tms = mLast - mStart;
      double rate = (tms == 0) ?
         0.0 :
         (double)mServiced * 1000.0 / (double)tms;

      DynamicObject stats;
      stats["serviced"] = mServiced;
      stats["num"] = mNum;
      stats["elapsed ms"] = tms;
      stats["req/s"] = rate;

      /*
      printf("Serviced: %" PRIu64 "/%" PRIu64 " in %0.3gs (%g r/s)\n",
         mServiced, mNum, (double)t, rate);
      if(mConfig["dynoStats"]->getBoolean())
      {
         JsonWriter::writeToStdOut(DynamicObjectImpl::getStats());
      }
      */

      return stats;
   }
};

class PingHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   const char* mContent;
   bool mChunked;

public:
   PingHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
      mContent = "Pong!";
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
   }

   virtual ~PingHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      int len = 5;
      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(mContent, len);
      response->sendBody(&bais, NULL);
      mPingPong->service();
   }
};

class StatsHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   StatsHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~StatsHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      Config& c = mPingPong->getConfig();
      // generate stats string
      DynamicObject stats;
      if(c["dynoStats"]->getBoolean())
      {
         stats["dyno"] = DynamicObjectImpl::getStats();
      }
      stats["ping"] = mPingPong->getStats();
      string statsstr = JsonWriter::writeToString(stats);
      int len = statsstr.length();

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mPingPong->getConfig()["chunked"]->getBoolean())
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "application/json");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(statsstr.c_str(), len);
      response->sendBody(&bais, NULL);
   }
};

class QuitHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   QuitHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~QuitHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->quit();
   }
};

static void runPingTest(TestRunner& tr)
{
   tr.test("Ping");

   Config cfg = tr.getApp()->getConfig()["pong"];

   // Stats and control
   PingPong pingPong(cfg);

   // create kernel
   Kernel k;

   // set thread stack size in engine (128k)
   k.getEngine()->getThreadPool()->setThreadStackSize(
      cfg["threadStackSize"]->getUInt32());

   // optional for testing --
   // limit threads to 2: one for accepting, 1 for handling
   //k.getEngine()->getThreadPool()->setPoolSize(2);
   k.getEngine()->getThreadPool()->setPoolSize(cfg["threads"]->getUInt32());

   // start engine
   k.getEngine()->start();

   // create server
   Server server;
   InternetAddress address("0.0.0.0", cfg["port"]->getUInt32());

   // create SSL/generic http connection servicer
   HttpConnectionServicer hcs;
//   SslContext context;
//   SslSocketDataPresenter presenter1(&context);
//   NullSocketDataPresenter presenter2;
//   SocketDataPresenterList list(false);
//   list.add(&presenter1);
//   list.add(&presenter2);
   server.addConnectionService(&address, &hcs);//, &list);

   // create test http request servicer
   PingHttpRequestServicer ping(&pingPong, "/");
   hcs.addRequestServicer(&ping, false);

   StatsHttpRequestServicer stats(&pingPong, "/stats");
   hcs.addRequestServicer(&stats, false);

   QuitHttpRequestServicer quit(&pingPong, "/quit");
   hcs.addRequestServicer(&quit, false);

   if(server.start(&k))
   {
      uint64_t num = cfg["num"]->getUInt64();
      MO_INFO("Server started.");
      if(num == 0)
      {
         MO_INFO("Servicing forever. CTRL-C to quit.");
      }
      {
         MO_INFO("Servicing approximately %" PRIu64 " connections.", num);
      }
   }
   else if(Exception::get() != NULL)
   {
      MO_ERROR("Server started with errors=%s\n",
         Exception::get()->getMessage());
   }

   // start timing
   pingPong.start();

   // either serve for limited time, or wait for lock
   uint32_t time = cfg["time"]->getUInt32();
   if(time != 0)
   {
      Thread::sleep(time);
   }
   else
   {
      pingPong.getLock().wait();
   }

   server.stop();
   MO_INFO("Server stopped.");

   // stop kernel engine
   k.getEngine()->stop();

   tr.passIfNoException();
}

static bool run(TestRunner& tr)
{
   if(tr.isTestEnabled("pong"))
   {
      runPingTest(tr);
   }
   return true;
}

} // end namespace

MO_TEST_MODULE_FN("monarch.tests.pong.test", "1.0", mo_test_pong::run)
<commit_msg>Upped connections and backlog.<commit_after>/*
 * Copyright (c) 2010 Digital Bazaar, Inc. All rights reserved.
 */
#define __STDC_FORMAT_MACROS

#include "monarch/data/json/JsonWriter.h"
#include "monarch/io/ByteArrayInputStream.h"
#include "monarch/io/File.h"
#include "monarch/io/FileInputStream.h"
#include "monarch/io/FileOutputStream.h"
#include "monarch/io/FileList.h"
#include "monarch/logging/Logging.h"
#include "monarch/modest/Kernel.h"
#include "monarch/net/TcpSocket.h"
#include "monarch/net/Url.h"
#include "monarch/http/CookieJar.h"
#include "monarch/http/HttpHeader.h"
#include "monarch/http/HttpRequest.h"
#include "monarch/http/HttpResponse.h"
#include "monarch/http/HttpConnectionServicer.h"
#include "monarch/http/HttpRequestServicer.h"
#include "monarch/http/HttpClient.h"
#include "monarch/net/Server.h"
#include "monarch/net/NullSocketDataPresenter.h"
#include "monarch/net/SslSocketDataPresenter.h"
#include "monarch/net/SocketDataPresenterList.h"
#include "monarch/rt/Atomic.h"
#include "monarch/rt/ExclusiveLock.h"
#include "monarch/rt/System.h"
#include "monarch/rt/DynamicObject.h"
#include "monarch/rt/DynamicObjectIterator.h"
#include "monarch/test/Test.h"
#include "monarch/test/TestModule.h"
#include "monarch/util/Date.h"
#include "monarch/util/StringTools.h"

using namespace std;
using namespace monarch::config;
using namespace monarch::data::json;
using namespace monarch::http;
using namespace monarch::io;
using namespace monarch::modest;
using namespace monarch::net;
using namespace monarch::rt;
using namespace monarch::test;
using namespace monarch::util;

namespace mo_test_pong
{

/**
 * PingPong Test
 *
 * Invoke with the following:
 *
 *   ./monarch-run pong -t pong
 *
 * See configs/apps/pong.config.in for option defaults. Use standard monarch
 * "--json-option key=value" option to adjust options.
 *
 * pong.chunked=<bool>: use chunked encoding
 * pong.dynoStats=<bool>: return DynamicObject stats with regular stats
 * pong.num=<int32>: number of connections to service
 * pong.port=<int32>: port to serve on
 * pong.ssl=<bool>: use SSL
 * pong.time=<int32>: milliseconds to run the test
 * pong.threadStackSize=<int32>: set stack size
 * pong.threads=<int32>: set number of threads
 *
 * Endpoints:
 * /: return "Pong!"
 * /stats: return JSON object with various
 *
 */

// stats and control
class PingPong
{
private:
   uint64_t mStart;
   uint64_t mLast;
   uint64_t mServiced;
   uint64_t mNum;
   ExclusiveLock mLock;
   Config mConfig;

public:
   PingPong(Config cfg) :
      mStart(0),
      mLast(0),
      mServiced(0),
      mConfig(cfg)
   {
      mNum = cfg["num"]->getUInt64();
   }

   virtual ~PingPong() {}

   virtual void start()
   {
      mStart = System::getCurrentMilliseconds();
      mLast = mStart;
   }

   virtual void quit()
   {
      mLock.notifyAll();
   }

   virtual Config& getConfig()
   {
      return mConfig;
   }

   virtual ExclusiveLock& getLock()
   {
      return mLock;
   }

   virtual void service()
   {
      // set last serviced time for effective ping service time
      // avoids counting time between ping and stats calls
      mLast = System::getCurrentMilliseconds();

      // This is a bit sloppy and may do the lock notify multiple times and
      // increase mServiced more than mNum.  Assumption is that this doesn't
      // matter for this sort of performance testing.
      uint64_t s = Atomic::incrementAndFetch(&mServiced);
      if(mNum != 0 && s >= mNum)
      {
         quit();
      }
   }

   virtual DynamicObject getStats()
   {
      uint64_t tms = mLast - mStart;
      double rate = (tms == 0) ?
         0.0 :
         (double)mServiced * 1000.0 / (double)tms;

      DynamicObject stats;
      stats["serviced"] = mServiced;
      stats["num"] = mNum;
      stats["elapsed ms"] = tms;
      stats["req/s"] = rate;

      /*
      printf("Serviced: %" PRIu64 "/%" PRIu64 " in %0.3gs (%g r/s)\n",
         mServiced, mNum, (double)t, rate);
      if(mConfig["dynoStats"]->getBoolean())
      {
         JsonWriter::writeToStdOut(DynamicObjectImpl::getStats());
      }
      */

      return stats;
   }
};

class PingHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;
   const char* mContent;
   bool mChunked;

public:
   PingHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
      mContent = "Pong!";
      mChunked = pingPong->getConfig()["chunked"]->getBoolean();
   }

   virtual ~PingHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      int len = 5;
      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mChunked)
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "text/plain");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(mContent, len);
      response->sendBody(&bais, NULL);
      mPingPong->service();
   }
};

class StatsHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   StatsHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~StatsHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      Config& c = mPingPong->getConfig();
      // generate stats string
      DynamicObject stats;
      if(c["dynoStats"]->getBoolean())
      {
         stats["dyno"] = DynamicObjectImpl::getStats();
      }
      stats["ping"] = mPingPong->getStats();
      string statsstr = JsonWriter::writeToString(stats);
      int len = statsstr.length();

      // send 200 OK
      response->getHeader()->setStatus(200, "OK");
      if(mPingPong->getConfig()["chunked"]->getBoolean())
      {
         response->getHeader()->setField("Transfer-Encoding", "chunked");
      }
      else
      {
         response->getHeader()->setField("Content-Length", len);
      }
      response->getHeader()->setField("Content-Type", "application/json");
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      ByteArrayInputStream bais(statsstr.c_str(), len);
      response->sendBody(&bais, NULL);
   }
};

class QuitHttpRequestServicer : public HttpRequestServicer
{
protected:
   PingPong* mPingPong;

public:
   QuitHttpRequestServicer(PingPong* pingPong, const char* path) :
      HttpRequestServicer(path),
      mPingPong(pingPong)
   {
   }

   virtual ~QuitHttpRequestServicer()
   {
   }

   virtual void serviceRequest(
      HttpRequest* request, HttpResponse* response)
   {
      response->getHeader()->setStatus(204, "No Content");
      response->getHeader()->setField("Content-Length", 0);
      response->getHeader()->setField("Connection", "close");
      response->sendHeader();
      mPingPong->quit();
   }
};

static void runPingTest(TestRunner& tr)
{
   tr.test("Ping");

   Config cfg = tr.getApp()->getConfig()["pong"];

   // Stats and control
   PingPong pingPong(cfg);

   // create kernel
   Kernel k;

   // set thread stack size in engine (128k)
   k.getEngine()->getThreadPool()->setThreadStackSize(
      cfg["threadStackSize"]->getUInt32());

   // optional for testing --
   // limit threads to 2: one for accepting, 1 for handling
   //k.getEngine()->getThreadPool()->setPoolSize(2);
   k.getEngine()->getThreadPool()->setPoolSize(cfg["threads"]->getUInt32());

   // start engine
   k.getEngine()->start();

   // create server
   Server server;
   // FIXME: add config option for connections
   server.setMaxConnectionCount(10000);
   InternetAddress address("0.0.0.0", cfg["port"]->getUInt32());

   // create SSL/generic http connection servicer
   HttpConnectionServicer hcs;
//   SslContext context;
//   SslSocketDataPresenter presenter1(&context);
//   NullSocketDataPresenter presenter2;
//   SocketDataPresenterList list(false);
//   list.add(&presenter1);
//   list.add(&presenter2);
   //server.addConnectionService(&address, &hcs);//, &list);
   // FIXME: add config options for connections, backlog
   // max connections = 10000, backlog = 10000
   server.addConnectionService(&address, &hcs, NULL, "pong", 10000, 10000);

   // create test http request servicer
   PingHttpRequestServicer ping(&pingPong, "/");
   hcs.addRequestServicer(&ping, false);

   StatsHttpRequestServicer stats(&pingPong, "/stats");
   hcs.addRequestServicer(&stats, false);

   QuitHttpRequestServicer quit(&pingPong, "/quit");
   hcs.addRequestServicer(&quit, false);

   if(server.start(&k))
   {
      uint64_t num = cfg["num"]->getUInt64();
      MO_INFO("Server started.");
      if(num == 0)
      {
         MO_INFO("Servicing forever. CTRL-C to quit.");
      }
      {
         MO_INFO("Servicing approximately %" PRIu64 " connections.", num);
      }
   }
   else if(Exception::get() != NULL)
   {
      MO_ERROR("Server started with errors=%s\n",
         Exception::get()->getMessage());
   }

   // start timing
   pingPong.start();

   // either serve for limited time, or wait for lock
   uint32_t time = cfg["time"]->getUInt32();
   if(time != 0)
   {
      Thread::sleep(time);
   }
   else
   {
      pingPong.getLock().wait();
   }

   server.stop();
   MO_INFO("Server stopped.");

   // stop kernel engine
   k.getEngine()->stop();

   tr.passIfNoException();
}

static bool run(TestRunner& tr)
{
   if(tr.isTestEnabled("pong"))
   {
      runPingTest(tr);
   }
   return true;
}

} // end namespace

MO_TEST_MODULE_FN("monarch.tests.pong.test", "1.0", mo_test_pong::run)
<|endoftext|>


<commit_before>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include "EventDevice.hpp"
#include "InputSystemLinux.hpp"
#include "input/KeyboardDevice.hpp"
#include "input/GamepadDevice.hpp"
#include "input/MouseDevice.hpp"
#include "input/TouchpadDevice.hpp"
#include "core/Engine.hpp"
#include "utils/Errors.hpp"
#include "utils/Log.hpp"

static const uint32_t BITS_PER_LONG = 8 * sizeof(long);
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)

static inline bool isBitSet(const unsigned long* array, int bit)
{
    return (array[bit / BITS_PER_LONG] & (1LL << (bit % BITS_PER_LONG))) != 0;
}

namespace ouzel
{
    namespace input
    {
        EventDevice::EventDevice(InputSystemLinux& inputSystem, const std::string& initFilename):
            filename(initFilename)
        {
            fd = open(filename.c_str(), O_RDONLY);

            if (fd == -1)
                throw SystemError("Failed to open device file");

            if (ioctl(fd, EVIOCGRAB, reinterpret_cast<void*>(1)) == -1)
                Log(Log::Level::WARN) << "Failed to grab device";

            char deviceName[256];
            if (ioctl(fd, EVIOCGNAME(sizeof(deviceName) - 1), deviceName) == -1)
                Log(Log::Level::WARN) << "Failed to get device name";
            else
            {
                name = deviceName;
                Log(Log::Level::INFO) << "Got device: " << name;
            }

            unsigned long eventBits[BITS_TO_LONGS(EV_CNT)];
            unsigned long absBits[BITS_TO_LONGS(ABS_CNT)];
            unsigned long relBits[BITS_TO_LONGS(REL_CNT)];
            unsigned long keyBits[BITS_TO_LONGS(KEY_CNT)];

            if (ioctl(fd, EVIOCGBIT(0, sizeof(eventBits)), eventBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) == -1)
                throw SystemError("Failed to get device event bits");

            if (isBitSet(eventBits, EV_KEY) && (
                    isBitSet(keyBits, KEY_1) ||
                    isBitSet(keyBits, KEY_2) ||
                    isBitSet(keyBits, KEY_3) ||
                    isBitSet(keyBits, KEY_4) ||
                    isBitSet(keyBits, KEY_5) ||
                    isBitSet(keyBits, KEY_6) ||
                    isBitSet(keyBits, KEY_7) ||
                    isBitSet(keyBits, KEY_8) ||
                    isBitSet(keyBits, KEY_9) ||
                    isBitSet(keyBits, KEY_0)
                ))
                keyboardDevice.reset(new KeyboardDevice(inputSystem, inputSystem.getNextDeviceId()));

            if (isBitSet(eventBits, EV_ABS) && isBitSet(absBits, ABS_X) && isBitSet(absBits, ABS_Y))
            {
                if (isBitSet(keyBits, BTN_STYLUS) || isBitSet(keyBits, BTN_TOOL_PEN)) // tablet
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_TOOL_FINGER) && !isBitSet(keyBits, BTN_TOOL_PEN)) // touchpad
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_MOUSE)) // mouse
                    mouseDevice.reset(new MouseDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_TOUCH)) // touchscreen
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
            }
            else if (isBitSet(eventBits, EV_REL) && isBitSet(relBits, REL_X) && isBitSet(relBits, REL_Y))
            {
                if (isBitSet(keyBits, BTN_MOUSE))
                    mouseDevice.reset(new MouseDevice(inputSystem, inputSystem.getNextDeviceId()));
            }

            if (isBitSet(keyBits, BTN_JOYSTICK) || // joystick
                isBitSet(keyBits, BTN_GAMEPAD)) // gamepad
                gamepadDevice.reset(new GamepadDevice(inputSystem, inputSystem.getNextDeviceId()));

            struct input_id id;
            ioctl(fd, EVIOCGID, &id);
            vendor = id.vendor;
            product = id.product;
        }

        EventDevice::~EventDevice()
        {
            if (fd != -1)
            {
                if (ioctl(fd, EVIOCGRAB, reinterpret_cast<void*>(0)) == -1)
                    Log(Log::Level::WARN) << "Failed to release device";

                close(fd);
            }
        }

        void EventDevice::update()
        {
            input_event events[32];
            ssize_t bytesRead = read(fd, events, sizeof(events));

            if (bytesRead == -1)
                throw SystemError("Failed to read from " + filename); // TODO: disconnect the device

            int count = bytesRead / sizeof(input_event);

            for (int i = 0; i < count; ++i)
            {
                input_event& event = events[i];

                if (keyboardDevice)
                {
                    switch (event.type)
                    {
                        case EV_KEY:
                            if (event.value == 1 || event.value == 2) // press or repeat
                                keyboardDevice->handleKeyPress(InputSystemLinux::convertKeyCode(event.code));
                            else if (event.value == 0) // release
                                keyboardDevice->handleKeyRelease(InputSystemLinux::convertKeyCode(event.code));
                            break;
                    }
                }
                if (mouseDevice)
                {
                    switch (event.type)
                    {
                        case EV_ABS:
                        {
                            switch (event.code)
                            {
                                case ABS_X:
                                    cursorPosition.x = engine->getWindow()->convertWindowToNormalizedLocation(Vector2(static_cast<float>(event.value), 0.0F)).x;
                                    break;
                                case ABS_Y:
                                    cursorPosition.y = engine->getWindow()->convertWindowToNormalizedLocation(Vector2(0.0F, static_cast<float>(event.value))).y;
                                    break;
                            }

                            mouseDevice->handleMove(cursorPosition);
                            break;
                        }
                        case EV_REL:
                        {
                            Vector2 relativePos;

                            switch (event.code)
                            {
                                case REL_X:
                                    relativePos.x = static_cast<float>(event.value);
                                    break;
                                case REL_Y:
                                    relativePos.y = static_cast<float>(event.value);
                                    break;
                                case REL_WHEEL:
                                    mouseDevice->handleScroll(std::Vector2(0.0F, static_cast<float>(event.value)), cursorPosition);
                                    break;
                                case REL_HWHEEL:
                                    mouseDevice->handleScroll(std::Vector2(static_cast<float>(event.value), 0.0F), cursorPosition);
                                    break;
                            }

                            mouseDevice->handleRelativeMove(engine->getWindow()->convertWindowToNormalizedLocation(relativePos));
                            break;
                        }
                        case EV_KEY:
                        {
                            Mouse::Button button = Mouse::Button::NONE;

                            switch (event.code)
                            {
                            case BTN_LEFT:
                                button = Mouse::Button::LEFT;
                                break;
                            case BTN_RIGHT:
                                button = Mouse::Button::RIGHT;
                                break;
                            case BTN_MIDDLE:
                                button = Mouse::Button::MIDDLE;
                                break;
                            default:
                                button = Mouse::Button::NONE;
                            }

                            if (event.value == 1)
                                mouseDevice->handleButtonPress(button, cursorPosition);
                            else if (event.value == 0)
                                mouseDevice->handleButtonRelease(button, cursorPosition);
                            break;
                        }
                    }
                }
                if (touchpadDevice)
                {
                    switch (event.type)
                    {
                        case EV_ABS:
                        {
                            switch (event.code)
                            {
                                case ABS_MT_SLOT:
                                {
                                    // TODO: implement
                                    // current slot = event.value
                                    break;
                                }
                                case ABS_MT_TRACKING_ID:
                                {
                                    // TODO: implement
                                    if (events.value >= 0)
                                    {
                                        // tracking id = events.value
                                        // down
                                    }
                                    else
                                    {
                                        // up
                                    }
                                    break;
                                }
                                case ABS_MT_POSITION_X:
                                {
                                    // TODO: implement
                                    // current slot x = event.value
                                    break;
                                }
                                case ABS_MT_POSITION_Y:
                                {
                                    // TODO: implement
                                    // current slot y = event.value
                                    break;
                                }
                            }
                            break;
                        }
                        case EV_SYN:
                        {
                            switch (event.code)
                            {
                                case SYN_REPORT:
                                    break;
                                case SYN_DROPPED:
                                    break;
                            }
                            break;
                        }
                    }
                }
                if (gamepadDevice)
                {
                    switch(event.type)
                    {
                        case EV_ABS:
                        {
                            // TODO: implement
                            break;
                        }
                        case EV_REL:
                        {
                            // TODO: implement
                            break;
                        }
                        case EV_KEY:
                        {
                            // TODO: implement
                            break;
                        }
                    }
                }
            }
        }
    } // namespace input
} // namespace ouzel
<commit_msg>Fix Linux build<commit_after>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include "EventDevice.hpp"
#include "InputSystemLinux.hpp"
#include "input/KeyboardDevice.hpp"
#include "input/GamepadDevice.hpp"
#include "input/MouseDevice.hpp"
#include "input/TouchpadDevice.hpp"
#include "core/Engine.hpp"
#include "utils/Errors.hpp"
#include "utils/Log.hpp"

static const uint32_t BITS_PER_LONG = 8 * sizeof(long);
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)

static inline bool isBitSet(const unsigned long* array, int bit)
{
    return (array[bit / BITS_PER_LONG] & (1LL << (bit % BITS_PER_LONG))) != 0;
}

namespace ouzel
{
    namespace input
    {
        EventDevice::EventDevice(InputSystemLinux& inputSystem, const std::string& initFilename):
            filename(initFilename)
        {
            fd = open(filename.c_str(), O_RDONLY);

            if (fd == -1)
                throw SystemError("Failed to open device file");

            if (ioctl(fd, EVIOCGRAB, reinterpret_cast<void*>(1)) == -1)
                Log(Log::Level::WARN) << "Failed to grab device";

            char deviceName[256];
            if (ioctl(fd, EVIOCGNAME(sizeof(deviceName) - 1), deviceName) == -1)
                Log(Log::Level::WARN) << "Failed to get device name";
            else
            {
                name = deviceName;
                Log(Log::Level::INFO) << "Got device: " << name;
            }

            unsigned long eventBits[BITS_TO_LONGS(EV_CNT)];
            unsigned long absBits[BITS_TO_LONGS(ABS_CNT)];
            unsigned long relBits[BITS_TO_LONGS(REL_CNT)];
            unsigned long keyBits[BITS_TO_LONGS(KEY_CNT)];

            if (ioctl(fd, EVIOCGBIT(0, sizeof(eventBits)), eventBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits) == -1 ||
                ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits) == -1)
                throw SystemError("Failed to get device event bits");

            if (isBitSet(eventBits, EV_KEY) && (
                    isBitSet(keyBits, KEY_1) ||
                    isBitSet(keyBits, KEY_2) ||
                    isBitSet(keyBits, KEY_3) ||
                    isBitSet(keyBits, KEY_4) ||
                    isBitSet(keyBits, KEY_5) ||
                    isBitSet(keyBits, KEY_6) ||
                    isBitSet(keyBits, KEY_7) ||
                    isBitSet(keyBits, KEY_8) ||
                    isBitSet(keyBits, KEY_9) ||
                    isBitSet(keyBits, KEY_0)
                ))
                keyboardDevice.reset(new KeyboardDevice(inputSystem, inputSystem.getNextDeviceId()));

            if (isBitSet(eventBits, EV_ABS) && isBitSet(absBits, ABS_X) && isBitSet(absBits, ABS_Y))
            {
                if (isBitSet(keyBits, BTN_STYLUS) || isBitSet(keyBits, BTN_TOOL_PEN)) // tablet
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_TOOL_FINGER) && !isBitSet(keyBits, BTN_TOOL_PEN)) // touchpad
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_MOUSE)) // mouse
                    mouseDevice.reset(new MouseDevice(inputSystem, inputSystem.getNextDeviceId()));
                else if (isBitSet(keyBits, BTN_TOUCH)) // touchscreen
                    touchpadDevice.reset(new TouchpadDevice(inputSystem, inputSystem.getNextDeviceId()));
            }
            else if (isBitSet(eventBits, EV_REL) && isBitSet(relBits, REL_X) && isBitSet(relBits, REL_Y))
            {
                if (isBitSet(keyBits, BTN_MOUSE))
                    mouseDevice.reset(new MouseDevice(inputSystem, inputSystem.getNextDeviceId()));
            }

            if (isBitSet(keyBits, BTN_JOYSTICK) || // joystick
                isBitSet(keyBits, BTN_GAMEPAD)) // gamepad
                gamepadDevice.reset(new GamepadDevice(inputSystem, inputSystem.getNextDeviceId()));

            struct input_id id;
            ioctl(fd, EVIOCGID, &id);
            vendor = id.vendor;
            product = id.product;
        }

        EventDevice::~EventDevice()
        {
            if (fd != -1)
            {
                if (ioctl(fd, EVIOCGRAB, reinterpret_cast<void*>(0)) == -1)
                    Log(Log::Level::WARN) << "Failed to release device";

                close(fd);
            }
        }

        void EventDevice::update()
        {
            input_event events[32];
            ssize_t bytesRead = read(fd, events, sizeof(events));

            if (bytesRead == -1)
                throw SystemError("Failed to read from " + filename); // TODO: disconnect the device

            int count = bytesRead / sizeof(input_event);

            for (int i = 0; i < count; ++i)
            {
                input_event& event = events[i];

                if (keyboardDevice)
                {
                    switch (event.type)
                    {
                        case EV_KEY:
                            if (event.value == 1 || event.value == 2) // press or repeat
                                keyboardDevice->handleKeyPress(InputSystemLinux::convertKeyCode(event.code));
                            else if (event.value == 0) // release
                                keyboardDevice->handleKeyRelease(InputSystemLinux::convertKeyCode(event.code));
                            break;
                    }
                }
                if (mouseDevice)
                {
                    switch (event.type)
                    {
                        case EV_ABS:
                        {
                            switch (event.code)
                            {
                                case ABS_X:
                                    cursorPosition.x = engine->getWindow()->convertWindowToNormalizedLocation(Vector2(static_cast<float>(event.value), 0.0F)).x;
                                    break;
                                case ABS_Y:
                                    cursorPosition.y = engine->getWindow()->convertWindowToNormalizedLocation(Vector2(0.0F, static_cast<float>(event.value))).y;
                                    break;
                            }

                            mouseDevice->handleMove(cursorPosition);
                            break;
                        }
                        case EV_REL:
                        {
                            Vector2 relativePos;

                            switch (event.code)
                            {
                                case REL_X:
                                    relativePos.x = static_cast<float>(event.value);
                                    break;
                                case REL_Y:
                                    relativePos.y = static_cast<float>(event.value);
                                    break;
                                case REL_WHEEL:
                                    mouseDevice->handleScroll(Vector2(0.0F, static_cast<float>(event.value)), cursorPosition);
                                    break;
                                case REL_HWHEEL:
                                    mouseDevice->handleScroll(Vector2(static_cast<float>(event.value), 0.0F), cursorPosition);
                                    break;
                            }

                            mouseDevice->handleRelativeMove(engine->getWindow()->convertWindowToNormalizedLocation(relativePos));
                            break;
                        }
                        case EV_KEY:
                        {
                            Mouse::Button button = Mouse::Button::NONE;

                            switch (event.code)
                            {
                            case BTN_LEFT:
                                button = Mouse::Button::LEFT;
                                break;
                            case BTN_RIGHT:
                                button = Mouse::Button::RIGHT;
                                break;
                            case BTN_MIDDLE:
                                button = Mouse::Button::MIDDLE;
                                break;
                            default:
                                button = Mouse::Button::NONE;
                            }

                            if (event.value == 1)
                                mouseDevice->handleButtonPress(button, cursorPosition);
                            else if (event.value == 0)
                                mouseDevice->handleButtonRelease(button, cursorPosition);
                            break;
                        }
                    }
                }
                if (touchpadDevice)
                {
                    switch (event.type)
                    {
                        case EV_ABS:
                        {
                            switch (event.code)
                            {
                                case ABS_MT_SLOT:
                                {
                                    // TODO: implement
                                    // current slot = event.value
                                    break;
                                }
                                case ABS_MT_TRACKING_ID:
                                {
                                    // TODO: implement
                                    if (event.value >= 0)
                                    {
                                        // tracking id = event.value
                                        // down
                                    }
                                    else
                                    {
                                        // up
                                    }
                                    break;
                                }
                                case ABS_MT_POSITION_X:
                                {
                                    // TODO: implement
                                    // current slot x = event.value
                                    break;
                                }
                                case ABS_MT_POSITION_Y:
                                {
                                    // TODO: implement
                                    // current slot y = event.value
                                    break;
                                }
                            }
                            break;
                        }
                        case EV_SYN:
                        {
                            switch (event.code)
                            {
                                case SYN_REPORT:
                                    break;
                                case SYN_DROPPED:
                                    break;
                            }
                            break;
                        }
                    }
                }
                if (gamepadDevice)
                {
                    switch(event.type)
                    {
                        case EV_ABS:
                        {
                            // TODO: implement
                            break;
                        }
                        case EV_REL:
                        {
                            // TODO: implement
                            break;
                        }
                        case EV_KEY:
                        {
                            // TODO: implement
                            break;
                        }
                    }
                }
            }
        }
    } // namespace input
} // namespace ouzel
<|endoftext|>


<commit_before>#include "tame.hh"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

parse_state_t *state;
bool tamer_debug = false;
outputter_t *outputter;

std::ostream &warn = std::cerr;

static void
usage ()
{
  warn  << "usage: tamer [-Lchnv] "
	<< "[-o <outfile>] [<infile>]\n"
	<< "\n"
	<< "  Flags:\n"
	<< "    -g  turn on debugging support\n"
	<< "    -n  turn on newlines in autogenerated code\n"
	<< "    -L  disable line number translation\n"
	<< "    -h  show this screen\n"
	<< "    -v  show version number and exit\n"
	<< "\n"
	<< "  Options:\n"
	<< "    -o  specify output file\n"
	<< "    -c  compile mode; infer output file name from input file "
	<< "name\n"
	<< "    -b  basename mode; strip off dirs from input file name\n"
	<< "\n"
	<< "  If no input or output files are specified, then standard in\n"
	<< "  and out are assumed, respectively.\n"
	<< "\n"
	<< "  Environment Variables:\n"
	<< "    TAME_NO_LINE_NUMBERS  equivalent to -L\n"
	<< "    TAME_ADD_NEWLINES     equivalent to -n\n"
	<< "    TAME_DEBUG_SOURCE     equivalent to -Ln\n"
	  ;

  exit (1);
}

static str
ifn2ofn (const str &s)
{
    str::size_type rdot = s.rfind('.');
    if (rdot == str::npos || rdot == 0 || rdot == s.length() - 1
	|| s[rdot - 1] == '/')
	return str();
    str base = s.substr(0, rdot);
    str ext = s.substr(rdot + 1);
    if (ext == "T" || ext == "tC")
	return base + ".C";
    else if (ext == "tt" || ext == "tcc")
	return base + ".cc";
    else if (ext == "txx" || ext == "tcxx")
	return base + ".cxx";
    else if (ext == "tpp" || ext == "tcpp")
	return base + ".cpp";
    else if (ext == "thh" || ext == "tth")
	return base + ".hh";
    else if (ext == "thxx" || ext == "thx")
	return base + ".hxx";
    else if (ext == "thpp" || ext == "thp")
	return base + ".hpp";
    else if (ext == "th")
	return base + ".h";
    else if (ext == "tH" || ext == "TH")
	return base + ".H";
    else
	return str();
}

static str
basename (const str &s)
{
    str::size_type lastslash = s.rfind('/');
    return (lastslash == str::npos ? s : s.substr(lastslash + 1));
}

int
main (int argc, char *argv[])
{
  FILE *ifh = NULL;
  int ch;
  str outfile;
  bool no_line_numbers = false;
  bool horiz_mode = true;
  bool deps = false;
  str ifn, depfile;
  bool c_mode (false), b_mode (false);

  while ((ch = getopt (argc, argv, "bghnDLvdo:c:O:F:")) != -1)
    switch (ch) {
      case 'g':
	tamer_debug = true;
	break;
    case 'h':
      usage ();
      break;
    case 'n':
      horiz_mode = false;
      break;
    case 'c':
      ifn = optarg;
      if (!outfile.length())
	  outfile = ifn2ofn(ifn);
      if (!outfile.length()) {
	warn << "-c expects an input file with the .T suffix\n";
	usage ();
      }
      c_mode = true;
      break;
    case 'b':
      b_mode = true;
      break;
    case 'L':
      no_line_numbers = true;
      break;
    case 'D':
      deps = true;
      break;
    case 'F':
      deps = true;
      depfile = optarg;
      break;
    case 'o':
      outfile = optarg;
      break;
    case 'v':
      warn  << "tamer\n"
	    << "compiled " __DATE__ " " __TIME__ "\n" ;
      exit (0);
      break;
      case 'O':
	break;
    default:
      usage ();
      break;
    }

  if (b_mode) {
    if (!c_mode) {
      warn << "-b only works when -c is specified\n";
      usage ();
    } else {
	outfile = basename(outfile);
	if (outfile.length() == 0) {
	    warn << "canont formulate an output file name\n";
	    usage ();
	}
    }
  }

  if (getenv ("TAME_DEBUG_SOURCE")) {
    no_line_numbers = true;
	horiz_mode = false;
  }

  if (getenv ("TAME_NO_LINE_NUMBERS"))
    no_line_numbers = true;

  if (getenv ("TAME_ADD_NEWLINES"))
    horiz_mode = false;

  argc -= optind;
  argv += optind;

  if (argc == 1) {
      if (ifn.length()) {
	  warn << "input filename double-specified!\n";
	  usage ();
      }
      ifn = argv[0];
  }

  if (ifn.length() && ifn != "-") {
    if (!(ifh = fopen (ifn.c_str (), "r"))) {
      warn << "cannot open file: " << ifn << "\n";
      usage ();
    }

    // the filename variable is local to scan.ll, which will need
    // it to output message messages. It defaults to '(stdin)'
    filename = ifn;

    yyin = ifh;
  }

  if (deps) {
      if (outfile.empty() || ifn.empty() || ifn == "-") {
          warn << "-D requires -c or -o\n";
          usage();
      } else if (depfile.empty())
          depfile = outfile + ".d";
      FILE* f = fopen(depfile.c_str(), "w");
      if (!f) {
          warn << depfile << ": " << strerror(errno);
          exit(1);
      }
      fprintf(f, "%s: %s\n\n%s:\n", outfile.c_str(), ifn.c_str(), ifn.c_str());
      fclose(f);
  }

  state = new parse_state_t ();

  state->set_infile_name (ifn);
  bool fl = (ifn.length() && ifn != "-" && !no_line_numbers);
  if (horiz_mode) {
    outputter = new outputter_H_t (ifn, outfile, fl);
  } else {
    outputter = new outputter_t (ifn, outfile, fl);
  }
  if (!outputter->init ())
    exit (1);

  // only on if YYDEBUG is on :(
  // yydebug = 1;

  yyparse ();

  if (ifh) {
    fclose (ifh);
  }

  state->output (outputter);

  // calls close on the outputter fd
  delete outputter;
}
<commit_msg>#include some missing #includes<commit_after>#include "tame.hh"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

parse_state_t *state;
bool tamer_debug = false;
outputter_t *outputter;

std::ostream &warn = std::cerr;

static void
usage ()
{
  warn  << "usage: tamer [-Lchnv] "
	<< "[-o <outfile>] [<infile>]\n"
	<< "\n"
	<< "  Flags:\n"
	<< "    -g  turn on debugging support\n"
	<< "    -n  turn on newlines in autogenerated code\n"
	<< "    -L  disable line number translation\n"
	<< "    -h  show this screen\n"
	<< "    -v  show version number and exit\n"
	<< "\n"
	<< "  Options:\n"
	<< "    -o  specify output file\n"
	<< "    -c  compile mode; infer output file name from input file "
	<< "name\n"
	<< "    -b  basename mode; strip off dirs from input file name\n"
	<< "\n"
	<< "  If no input or output files are specified, then standard in\n"
	<< "  and out are assumed, respectively.\n"
	<< "\n"
	<< "  Environment Variables:\n"
	<< "    TAME_NO_LINE_NUMBERS  equivalent to -L\n"
	<< "    TAME_ADD_NEWLINES     equivalent to -n\n"
	<< "    TAME_DEBUG_SOURCE     equivalent to -Ln\n"
	  ;

  exit (1);
}

static str
ifn2ofn (const str &s)
{
    str::size_type rdot = s.rfind('.');
    if (rdot == str::npos || rdot == 0 || rdot == s.length() - 1
	|| s[rdot - 1] == '/')
	return str();
    str base = s.substr(0, rdot);
    str ext = s.substr(rdot + 1);
    if (ext == "T" || ext == "tC")
	return base + ".C";
    else if (ext == "tt" || ext == "tcc")
	return base + ".cc";
    else if (ext == "txx" || ext == "tcxx")
	return base + ".cxx";
    else if (ext == "tpp" || ext == "tcpp")
	return base + ".cpp";
    else if (ext == "thh" || ext == "tth")
	return base + ".hh";
    else if (ext == "thxx" || ext == "thx")
	return base + ".hxx";
    else if (ext == "thpp" || ext == "thp")
	return base + ".hpp";
    else if (ext == "th")
	return base + ".h";
    else if (ext == "tH" || ext == "TH")
	return base + ".H";
    else
	return str();
}

static str
basename (const str &s)
{
    str::size_type lastslash = s.rfind('/');
    return (lastslash == str::npos ? s : s.substr(lastslash + 1));
}

int
main (int argc, char *argv[])
{
  FILE *ifh = NULL;
  int ch;
  str outfile;
  bool no_line_numbers = false;
  bool horiz_mode = true;
  bool deps = false;
  str ifn, depfile;
  bool c_mode (false), b_mode (false);

  while ((ch = getopt (argc, argv, "bghnDLvdo:c:O:F:")) != -1)
    switch (ch) {
      case 'g':
	tamer_debug = true;
	break;
    case 'h':
      usage ();
      break;
    case 'n':
      horiz_mode = false;
      break;
    case 'c':
      ifn = optarg;
      if (!outfile.length())
	  outfile = ifn2ofn(ifn);
      if (!outfile.length()) {
	warn << "-c expects an input file with the .T suffix\n";
	usage ();
      }
      c_mode = true;
      break;
    case 'b':
      b_mode = true;
      break;
    case 'L':
      no_line_numbers = true;
      break;
    case 'D':
      deps = true;
      break;
    case 'F':
      deps = true;
      depfile = optarg;
      break;
    case 'o':
      outfile = optarg;
      break;
    case 'v':
      warn  << "tamer\n"
	    << "compiled " __DATE__ " " __TIME__ "\n" ;
      exit (0);
      break;
      case 'O':
	break;
    default:
      usage ();
      break;
    }

  if (b_mode) {
    if (!c_mode) {
      warn << "-b only works when -c is specified\n";
      usage ();
    } else {
	outfile = basename(outfile);
	if (outfile.length() == 0) {
	    warn << "canont formulate an output file name\n";
	    usage ();
	}
    }
  }

  if (getenv ("TAME_DEBUG_SOURCE")) {
    no_line_numbers = true;
	horiz_mode = false;
  }

  if (getenv ("TAME_NO_LINE_NUMBERS"))
    no_line_numbers = true;

  if (getenv ("TAME_ADD_NEWLINES"))
    horiz_mode = false;

  argc -= optind;
  argv += optind;

  if (argc == 1) {
      if (ifn.length()) {
	  warn << "input filename double-specified!\n";
	  usage ();
      }
      ifn = argv[0];
  }

  if (ifn.length() && ifn != "-") {
    if (!(ifh = fopen (ifn.c_str (), "r"))) {
      warn << "cannot open file: " << ifn << "\n";
      usage ();
    }

    // the filename variable is local to scan.ll, which will need
    // it to output message messages. It defaults to '(stdin)'
    filename = ifn;

    yyin = ifh;
  }

  if (deps) {
      if (outfile.empty() || ifn.empty() || ifn == "-") {
          warn << "-D requires -c or -o\n";
          usage();
      } else if (depfile.empty())
          depfile = outfile + ".d";
      FILE* f = fopen(depfile.c_str(), "w");
      if (!f) {
          warn << depfile << ": " << strerror(errno);
          exit(1);
      }
      fprintf(f, "%s: %s\n\n%s:\n", outfile.c_str(), ifn.c_str(), ifn.c_str());
      fclose(f);
  }

  state = new parse_state_t ();

  state->set_infile_name (ifn);
  bool fl = (ifn.length() && ifn != "-" && !no_line_numbers);
  if (horiz_mode) {
    outputter = new outputter_H_t (ifn, outfile, fl);
  } else {
    outputter = new outputter_t (ifn, outfile, fl);
  }
  if (!outputter->init ())
    exit (1);

  // only on if YYDEBUG is on :(
  // yydebug = 1;

  yyparse ();

  if (ifh) {
    fclose (ifh);
  }

  state->output (outputter);

  // calls close on the outputter fd
  delete outputter;
}
<|endoftext|>


<commit_before>#include <armadillo>
#include <algorithm>
#include <random>

template<typename T, int x_size, int y_size>
struct Array2D {
  std::array<T, x_size * y_size> data;
  T& operator() (int x, int y) {
    return data.at(y + y_size*x);
  }
  decltype(data.begin()) row(int x) {
    return data.begin()+x*y_size;
  }
};

struct Squared_Error {
  static inline float error(float target, float result) {
    return 1/2.0f * (target - result) * (target - result);
  }
  static inline float error_dir(float target, float result) {
    return (target - result);
  }
};

struct Logistic {
  static inline float activation(float k) {
    return 1 / (1 + exp(-k));
  }

  static inline float activation_dir(float k) {
    return k * (1 - k);
  }
};

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
struct FeedForward_Network{
  float learning_rate;
  FeedForward_Network(float learning_rate = 0.8f) : learning_rate(learning_rate) {};
  Array2D<float, input_size, hidden_size> weights_inputToHidden;
  Array2D<float, hidden_size, output_size> weights_hiddenToOutput;

  std::array<float, input_size> activation_input;
  std::array<float, hidden_size> activation_hidden;
  std::array<float, output_size> activation_output;
};

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void train(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input, std::array<float, output_size> target) {
    calculate_activation(network, input);
    backprop(network, target);
}

template <int input_size, int hidden_size, int output_size, int point_count,
         typename activation = Logistic, typename error = Squared_Error>
void train(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    Array2D<float, point_count, input_size> inputs, Array2D<float, point_count, output_size> targets) {
    for (int i = 0; i < point_count; ++i) {
      calculate_activation(network, inputs.row(i));
      backprop(network, targets.row(i));
    }
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void randomize(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network) {
  std::default_random_engine generator;
  std::normal_distribution<float> distribution(0, .1);

  for (int i=0; i < input_size; ++i) {
    for (int j=0; j < hidden_size; ++j) {
      network.weights_inputToHidden(i,j) = distribution(generator);
    }
  }

  for (int i=0; i < hidden_size; ++i) {
    for (int j=0; j < output_size; ++j) {
      network.weights_hiddenToOutput(i,j) = distribution(generator);
    }
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void backprop(FeedForward_Network<input_size, hidden_size, output_size, activation, error> &network,
    std::array<float, output_size> target) {
  backprop(network, target.data());
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void backprop(FeedForward_Network<input_size, hidden_size, output_size, activation, error> &network,
    float* target) {
  //Calculate deltas
  std::array<float, output_size> output_deltas;
  for (int i=0; i < output_size; ++i) {
    output_deltas[i] = error::error_dir(target[i], network.activation_output[i]) * activation::activation_dir(network.activation_output[i]);
  }
  std::array<float, hidden_size> hidden_deltas;
  for (int i=0; i < hidden_size; ++i) {
    float error_sum= 0;
    for (int k=0; k < output_size; ++k) {
      error_sum += output_deltas[k] * network.weights_hiddenToOutput(i, k);
    }
    hidden_deltas[i] = error_sum * activation::activation_dir(network.activation_hidden[i]);
  }

  //Update network weights
  for (int k=0; k < hidden_size; ++k) {
    for (int i=0; i < output_size; ++i) {
      network.weights_hiddenToOutput(k,i) += network.learning_rate * output_deltas[i] * network.activation_hidden[k];
    }
  }

  for (int k=0; k < input_size; ++k) {
    for (int i=0; i < hidden_size; ++i) {
      network.weights_inputToHidden(k,i) += network.learning_rate * hidden_deltas[i] * network.activation_input[k];
    }
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void calculate_activation(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input) {
  calculate_activation(network, input.data());
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
void calculate_activation(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    float * input) {
  for (int i=0; i < input_size; ++i) {
    network.activation_input[i] = input[i];
  }
  for (int i = 0; i < hidden_size; ++i) {
    float temp = 0;
    for (int j = 0; j < input_size; j++) {
      temp += input[j] * network.weights_inputToHidden(j, i);
    }
    network.activation_hidden[i] = activation::activation(temp);
  }
  for (int i = 0; i < output_size; ++i) {
    float temp = 0;
    for (int j = 0; j < hidden_size; j++) {
      temp += network.activation_hidden[j] * network.weights_hiddenToOutput(j, i);
    }
    network.activation_output[i] = activation::activation(temp);
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
std::array<float, output_size> predict(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input) {
  calculate_activation(network, input);
  return network.activation_output;
}
<commit_msg>cleaned up default template arguments<commit_after>#include <armadillo>
#include <algorithm>
#include <random>

template<typename T, int x_size, int y_size>
struct Array2D {
  std::array<T, x_size * y_size> data;
  T& operator() (int x, int y) {
    return data.at(y + y_size*x);
  }
  decltype(data.begin()) row(int x) {
    return data.begin()+x*y_size;
  }
};

struct Squared_Error {
  static inline float error(float target, float result) {
    return 1/2.0f * (target - result) * (target - result);
  }
  static inline float error_dir(float target, float result) {
    return (target - result);
  }
};

struct Logistic {
  static inline float activation(float k) {
    return 1 / (1 + exp(-k));
  }

  static inline float activation_dir(float k) {
    return k * (1 - k);
  }
};

template <int input_size, int hidden_size, int output_size,
         typename activation = Logistic, typename error = Squared_Error>
struct FeedForward_Network{
  float learning_rate;
  FeedForward_Network(float learning_rate = 0.8f) : learning_rate(learning_rate) {};
  Array2D<float, input_size, hidden_size> weights_inputToHidden;
  Array2D<float, hidden_size, output_size> weights_hiddenToOutput;

  std::array<float, input_size> activation_input;
  std::array<float, hidden_size> activation_hidden;
  std::array<float, output_size> activation_output;
};

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void train(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input, std::array<float, output_size> target) {
    calculate_activation(network, input);
    backprop(network, target);
}

template <int input_size, int hidden_size, int output_size, int point_count,
         typename activation, typename error>
void train(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    Array2D<float, point_count, input_size> inputs, Array2D<float, point_count, output_size> targets) {
    for (int i = 0; i < point_count; ++i) {
      calculate_activation(network, inputs.row(i));
      backprop(network, targets.row(i));
    }
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void randomize(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network) {
  std::default_random_engine generator;
  std::normal_distribution<float> distribution(0, .1);

  for (int i=0; i < input_size; ++i) {
    for (int j=0; j < hidden_size; ++j) {
      network.weights_inputToHidden(i,j) = distribution(generator);
    }
  }

  for (int i=0; i < hidden_size; ++i) {
    for (int j=0; j < output_size; ++j) {
      network.weights_hiddenToOutput(i,j) = distribution(generator);
    }
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void backprop(FeedForward_Network<input_size, hidden_size, output_size, activation, error> &network,
    std::array<float, output_size> target) {
  backprop(network, target.data());
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void backprop(FeedForward_Network<input_size, hidden_size, output_size, activation, error> &network,
    float* target) {
  //Calculate deltas
  std::array<float, output_size> output_deltas;
  for (int i=0; i < output_size; ++i) {
    output_deltas[i] = error::error_dir(target[i], network.activation_output[i]) * activation::activation_dir(network.activation_output[i]);
  }
  std::array<float, hidden_size> hidden_deltas;
  for (int i=0; i < hidden_size; ++i) {
    float error_sum= 0;
    for (int k=0; k < output_size; ++k) {
      error_sum += output_deltas[k] * network.weights_hiddenToOutput(i, k);
    }
    hidden_deltas[i] = error_sum * activation::activation_dir(network.activation_hidden[i]);
  }

  //Update network weights
  for (int k=0; k < hidden_size; ++k) {
    for (int i=0; i < output_size; ++i) {
      network.weights_hiddenToOutput(k,i) += network.learning_rate * output_deltas[i] * network.activation_hidden[k];
    }
  }

  for (int k=0; k < input_size; ++k) {
    for (int i=0; i < hidden_size; ++i) {
      network.weights_inputToHidden(k,i) += network.learning_rate * hidden_deltas[i] * network.activation_input[k];
    }
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void calculate_activation(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input) {
  calculate_activation(network, input.data());
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
void calculate_activation(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    float * input) {
  for (int i=0; i < input_size; ++i) {
    network.activation_input[i] = input[i];
  }
  for (int i = 0; i < hidden_size; ++i) {
    float temp = 0;
    for (int j = 0; j < input_size; j++) {
      temp += input[j] * network.weights_inputToHidden(j, i);
    }
    network.activation_hidden[i] = activation::activation(temp);
  }
  for (int i = 0; i < output_size; ++i) {
    float temp = 0;
    for (int j = 0; j < hidden_size; j++) {
      temp += network.activation_hidden[j] * network.weights_hiddenToOutput(j, i);
    }
    network.activation_output[i] = activation::activation(temp);
  }
}

template <int input_size, int hidden_size, int output_size,
         typename activation, typename error>
std::array<float, output_size> predict(FeedForward_Network<input_size, hidden_size, output_size, activation, error>& network,
    std::array<float, input_size> input) {
  calculate_activation(network, input);
  return network.activation_output;
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "stateseditormodel.h"
#include "stateseditorview.h"

#include <QtCore/QDebug>
#include <QMessageBox>

enum {
    debug = false
};

namespace QmlDesigner {
namespace Internal {

StatesEditorModel::StatesEditorModel(QObject *parent) :
        QAbstractListModel(parent),
        m_updateCounter(0)
{
    QHash<int, QByteArray> roleNames;
    roleNames.insert(StateNameRole, "stateName");
    roleNames.insert(StateImageSourceRole, "stateImageSource");
    setRoleNames(roleNames);
}

int StatesEditorModel::count() const
{
    return m_stateNames.count();
}

int StatesEditorModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return m_stateNames.count();
}

QVariant StatesEditorModel::data(const QModelIndex &index, int role) const
{
    if (index.parent().isValid() || index.column() != 0)
        return QVariant();

    QVariant result;
    switch (role) {
    case StateNameRole: {
            if (index.row()==0)
                result = QString(tr("base state", "Implicit default state"));
            else
                result = m_stateNames.at(index.row());
            break;
        }
    case StateImageSourceRole: {
            if (!m_statesView.isNull())
                return QString("image://qmldesigner_stateseditor/%1-%2").arg(index.row()).arg(m_updateCounter);
            break;
        }
    }

    return result;
}

void StatesEditorModel::insertState(int i, const QString &name)
{
    beginInsertRows(QModelIndex(), i, i);

    m_stateNames.insert(i, name);

    endInsertRows();

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
    emit countChanged();
}

void StatesEditorModel::removeState(int i)
{
    beginRemoveRows(QModelIndex(), i, i);

    m_stateNames.removeAt(i);

    endRemoveRows();

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
    emit countChanged();
}

void StatesEditorModel::renameState(int i, const QString &newName)
{
    Q_ASSERT(i > 0 && i < m_stateNames.count());

    if (m_stateNames[i] != newName) {
        if (m_stateNames.contains(newName) || newName.isEmpty()) {
            QMessageBox::warning(0, tr("Invalid state name"), newName.isEmpty()?tr("The empty string as a name is reserved for the base state."):tr("Name already used in another state"));
        } else {
            m_stateNames.replace(i, newName);
            m_statesView->renameState(i,newName);

            emit dataChanged(createIndex(i, 0), createIndex(i, 0));
        }
    }
}

void StatesEditorModel::updateState(int i)
{
    Q_ASSERT(i >= 0 && i < m_stateNames.count());

    // QML images with the same URL are always cached, so this changes the URL each
    // time to ensure the image is loaded from the StatesImageProvider and not the
    // cache.
    // TODO: only increase imageId when the scene has changed so that we can load
    // from the cache instead where possible.
    if (++m_updateCounter == INT_MAX)
        m_updateCounter = 0;

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
}

void StatesEditorModel::setStatesEditorView(StatesEditorView *statesView)
{
    m_statesView = statesView;
}

void StatesEditorModel::emitChangedToState(int n)
{
    emit changedToState(n);
}

} // namespace Internal
} // namespace QmlDesigner
<commit_msg>Wrapped overly long line<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "stateseditormodel.h"
#include "stateseditorview.h"

#include <QtCore/QDebug>
#include <QMessageBox>

enum {
    debug = false
};

namespace QmlDesigner {
namespace Internal {

StatesEditorModel::StatesEditorModel(QObject *parent) :
        QAbstractListModel(parent),
        m_updateCounter(0)
{
    QHash<int, QByteArray> roleNames;
    roleNames.insert(StateNameRole, "stateName");
    roleNames.insert(StateImageSourceRole, "stateImageSource");
    setRoleNames(roleNames);
}

int StatesEditorModel::count() const
{
    return m_stateNames.count();
}

int StatesEditorModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return m_stateNames.count();
}

QVariant StatesEditorModel::data(const QModelIndex &index, int role) const
{
    if (index.parent().isValid() || index.column() != 0)
        return QVariant();

    QVariant result;
    switch (role) {
    case StateNameRole: {
            if (index.row()==0)
                result = QString(tr("base state", "Implicit default state"));
            else
                result = m_stateNames.at(index.row());
            break;
        }
    case StateImageSourceRole: {
            if (!m_statesView.isNull())
                return QString("image://qmldesigner_stateseditor/%1-%2").arg(index.row()).arg(m_updateCounter);
            break;
        }
    }

    return result;
}

void StatesEditorModel::insertState(int i, const QString &name)
{
    beginInsertRows(QModelIndex(), i, i);

    m_stateNames.insert(i, name);

    endInsertRows();

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
    emit countChanged();
}

void StatesEditorModel::removeState(int i)
{
    beginRemoveRows(QModelIndex(), i, i);

    m_stateNames.removeAt(i);

    endRemoveRows();

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
    emit countChanged();
}

void StatesEditorModel::renameState(int i, const QString &newName)
{
    Q_ASSERT(i > 0 && i < m_stateNames.count());

    if (m_stateNames[i] != newName) {
        if (m_stateNames.contains(newName) || newName.isEmpty()) {
            QMessageBox::warning(0, tr("Invalid state name"),
                                 newName.isEmpty() ?
                                     tr("The empty string as a name is reserved for the base state.") :
                                     tr("Name already used in another state"));
        } else {
            m_stateNames.replace(i, newName);
            m_statesView->renameState(i,newName);

            emit dataChanged(createIndex(i, 0), createIndex(i, 0));
        }
    }
}

void StatesEditorModel::updateState(int i)
{
    Q_ASSERT(i >= 0 && i < m_stateNames.count());

    // QML images with the same URL are always cached, so this changes the URL each
    // time to ensure the image is loaded from the StatesImageProvider and not the
    // cache.
    // TODO: only increase imageId when the scene has changed so that we can load
    // from the cache instead where possible.
    if (++m_updateCounter == INT_MAX)
        m_updateCounter = 0;

    emit dataChanged(createIndex(i, 0), createIndex(i, 0));
}

void StatesEditorModel::setStatesEditorView(StatesEditorView *statesView)
{
    m_statesView = statesView;
}

void StatesEditorModel::emitChangedToState(int n)
{
    emit changedToState(n);
}

} // namespace Internal
} // namespace QmlDesigner
<|endoftext|>


<commit_before>#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/pipe.h>
#include <io/pipe_link.h>
#include <io/pipe_null.h>
#include <io/pipe_pair.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_decoder.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_pipe_pair.h>

#include <zlib/deflate_pipe.h>
#include <zlib/inflate_pipe.h>

#include "wanproxy_codec.h"
#include "wanproxy_codec_pipe_pair.h"

WANProxyCodecPipePair::WANProxyCodecPipePair(WANProxyCodec *incoming, WANProxyCodec *outgoing)
: incoming_pipe_(NULL),
  outgoing_pipe_(NULL),
  pipes_(),
  pipe_pairs_()
{
	std::deque<std::pair<Pipe *, Pipe *> > pipe_list;

	if (incoming != NULL) {
		if (incoming->compressor_) {
			std::pair<Pipe *, Pipe *> pipe_pair(new InflatePipe(), new DeflatePipe(9));

			pipes_.insert(pipe_pair.first);
			pipes_.insert(pipe_pair.second);

			pipe_list.push_back(pipe_pair);
		}

		if (incoming->codec_ != NULL) {
			PipePair *pair = new XCodecPipePair(incoming->codec_, XCodecPipePairTypeServer);
			pipe_pairs_.insert(pair);

			std::pair<Pipe *, Pipe *> pipe_pair(pair->get_incoming(), pair->get_outgoing());
			pipe_list.push_back(pipe_pair);
		}
	}

	if (outgoing != NULL) {
		if (outgoing->codec_ != NULL) {
			PipePair *pair = new XCodecPipePair(outgoing->codec_, XCodecPipePairTypeClient);
			pipe_pairs_.insert(pair);

			std::pair<Pipe *, Pipe *> pipe_pair(pair->get_incoming(), pair->get_outgoing());
			pipe_list.push_back(pipe_pair);
		}

		if (outgoing->compressor_) {
			std::pair<Pipe *, Pipe *> pipe_pair(new DeflatePipe(9), new InflatePipe());

			pipes_.insert(pipe_pair.first);
			pipes_.insert(pipe_pair.second);

			pipe_list.push_back(pipe_pair);
		}
	}

	if (pipe_list.empty()) {
		incoming_pipe_ = new PipeNull();
		outgoing_pipe_ = new PipeNull();

		pipes_.insert(incoming_pipe_);
		pipes_.insert(outgoing_pipe_);

		return;
	}

	incoming_pipe_ = pipe_list.front().first;
	outgoing_pipe_ = pipe_list.front().second;
	pipe_list.pop_front();

	while (!pipe_list.empty()) {
		incoming_pipe_ = new PipeLink(incoming_pipe_, pipe_list.front().first);
		outgoing_pipe_ = new PipeLink(outgoing_pipe_, pipe_list.front().second);

		pipes_.insert(incoming_pipe_);
		pipes_.insert(outgoing_pipe_);

		pipe_list.pop_front();
	}
}

WANProxyCodecPipePair::~WANProxyCodecPipePair()
{
	std::set<Pipe *>::iterator pit;
	while ((pit = pipes_.begin()) != pipes_.end()) {
		Pipe *pipe = *pit;
		pipes_.erase(pit);

		delete pipe;
	}

	std::set<PipePair *>::iterator ppit;
	while ((ppit = pipe_pairs_.begin()) != pipe_pairs_.end()) {
		PipePair *pipe_pair = *ppit;
		pipe_pairs_.erase(ppit);

		delete pipe_pair;
	}
}

Pipe *
WANProxyCodecPipePair::get_incoming(void)
{
	return (incoming_pipe_);
}

Pipe *
WANProxyCodecPipePair::get_outgoing(void)
{
	return (outgoing_pipe_);
}
<commit_msg>Fix order of inflate and deflate, hopefully.<commit_after>#include <common/buffer.h>
#include <common/endian.h>

#include <event/action.h>
#include <event/callback.h>
#include <event/event_system.h>

#include <io/pipe.h>
#include <io/pipe_link.h>
#include <io/pipe_null.h>
#include <io/pipe_pair.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_decoder.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_pipe_pair.h>

#include <zlib/deflate_pipe.h>
#include <zlib/inflate_pipe.h>

#include "wanproxy_codec.h"
#include "wanproxy_codec_pipe_pair.h"

WANProxyCodecPipePair::WANProxyCodecPipePair(WANProxyCodec *incoming, WANProxyCodec *outgoing)
: incoming_pipe_(NULL),
  outgoing_pipe_(NULL),
  pipes_(),
  pipe_pairs_()
{
	std::deque<std::pair<Pipe *, Pipe *> > pipe_list;

	if (incoming != NULL) {
		if (incoming->compressor_) {
			std::pair<Pipe *, Pipe *> pipe_pair(new DeflatePipe(9), new InflatePipe());

			pipes_.insert(pipe_pair.first);
			pipes_.insert(pipe_pair.second);

			pipe_list.push_back(pipe_pair);
		}

		if (incoming->codec_ != NULL) {
			PipePair *pair = new XCodecPipePair(incoming->codec_, XCodecPipePairTypeServer);
			pipe_pairs_.insert(pair);

			std::pair<Pipe *, Pipe *> pipe_pair(pair->get_incoming(), pair->get_outgoing());
			pipe_list.push_back(pipe_pair);
		}
	}

	if (outgoing != NULL) {
		if (outgoing->codec_ != NULL) {
			PipePair *pair = new XCodecPipePair(outgoing->codec_, XCodecPipePairTypeClient);
			pipe_pairs_.insert(pair);

			std::pair<Pipe *, Pipe *> pipe_pair(pair->get_incoming(), pair->get_outgoing());
			pipe_list.push_back(pipe_pair);
		}

		if (outgoing->compressor_) {
			std::pair<Pipe *, Pipe *> pipe_pair(new InflatePipe(), new DeflatePipe(9));

			pipes_.insert(pipe_pair.first);
			pipes_.insert(pipe_pair.second);

			pipe_list.push_back(pipe_pair);
		}
	}

	if (pipe_list.empty()) {
		incoming_pipe_ = new PipeNull();
		outgoing_pipe_ = new PipeNull();

		pipes_.insert(incoming_pipe_);
		pipes_.insert(outgoing_pipe_);

		return;
	}

	incoming_pipe_ = pipe_list.front().first;
	outgoing_pipe_ = pipe_list.front().second;
	pipe_list.pop_front();

	while (!pipe_list.empty()) {
		incoming_pipe_ = new PipeLink(incoming_pipe_, pipe_list.front().first);
		outgoing_pipe_ = new PipeLink(outgoing_pipe_, pipe_list.front().second);

		pipes_.insert(incoming_pipe_);
		pipes_.insert(outgoing_pipe_);

		pipe_list.pop_front();
	}
}

WANProxyCodecPipePair::~WANProxyCodecPipePair()
{
	std::set<Pipe *>::iterator pit;
	while ((pit = pipes_.begin()) != pipes_.end()) {
		Pipe *pipe = *pit;
		pipes_.erase(pit);

		delete pipe;
	}

	std::set<PipePair *>::iterator ppit;
	while ((ppit = pipe_pairs_.begin()) != pipe_pairs_.end()) {
		PipePair *pipe_pair = *ppit;
		pipe_pairs_.erase(ppit);

		delete pipe_pair;
	}
}

Pipe *
WANProxyCodecPipePair::get_incoming(void)
{
	return (incoming_pipe_);
}

Pipe *
WANProxyCodecPipePair::get_outgoing(void)
{
	return (outgoing_pipe_);
}
<|endoftext|>