<commit_before>/**
 * @file   Node.cpp
 * @brief  Node class implementation.
 * @author zer0
 * @date   2018-10-26
 */

#include <libtbag/network/node/Node.hpp>
#include <libtbag/log/Log.hpp>
#include <libtbag/Noncopyable.hpp>
#include <libtbag/thread/ThreadPool.hpp>
#include <libtbag/network/http/HttpServer.hpp>
#include <libtbag/network/http/HttpClient.hpp>
#include <libtbag/uvpp/Loop.hpp>

#include <cassert>
#include <algorithm>
#include <utility>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace network {
namespace node    {

/** @warning Don't change this variable. */
TBAG_CONSTEXPR static unsigned int const _POOL_SIZE = 1U;

/**
 * Node::Impl class implementation.
 *
 * @author zer0
 * @date   2018-10-26
 */
struct Node::Impl : private Noncopyable
{
public:
    using ThreadPool = libtbag::thread::ThreadPool;

public:
    using HttpServer = libtbag::network::http::HttpServer;
    using HttpClient = libtbag::network::http::HttpClient;
    using StreamType = libtbag::network::details::StreamType;
    using Loop       = libtbag::uvpp::Loop;

public:
    struct Server;
    struct Client;

    friend struct Server;
    friend struct Client;

public:
    /**
     * Node::Impl::Server class implementation.
     *
     * @author zer0
     * @date   2018-10-26
     */
    struct Server : public HttpServer
    {
        Server(Loop & loop, StreamType type = StreamType::TCP) : HttpServer(loop, type)
        {
            // EMPTY.
        }

        virtual ~Server()
        {
            // EMPTY.
        }
    };

    /**
     * Node::Impl::Client class implementation.
     *
     * @author zer0
     * @date   2018-10-26
     */
    struct Client : public HttpClient
    {
        Client(Loop & loop, StreamType type = StreamType::TCP) : HttpClient(loop, type)
        {
            // EMPTY.
        }

        virtual ~Client()
        {
            // EMPTY.
        }
    };

    using SharedServer = std::shared_ptr<Server>;
    using SharedClient = std::shared_ptr<Client>;

private:
    Node * _parent;

private:
    ThreadPool _pool;

private:
    NodeType _type = NodeType::NT_NONE;

public:
    Impl(Node * parent) : _parent(parent), _pool(_POOL_SIZE)
    {
        assert(_parent != nullptr);
        assert(_pool.sizeOfThreads() == _POOL_SIZE);
    }

    ~Impl()
    {
        // EMPTY.
    }

public:
};

// ----------------------------
// Node implementation.
// ----------------------------

Node::Node() : _impl(std::make_shared<Impl>(this))
{
    assert(static_cast<bool>(_impl));
}

Node::Node(std::nullptr_t) TBAG_NOEXCEPT : _impl(nullptr)
{
    // EMPTY.
}

Node::Node(Node const & obj) TBAG_NOEXCEPT : Node(nullptr)
{
    (*this) = obj;
}

Node::Node(Node && obj) TBAG_NOEXCEPT : Node(nullptr)
{
    (*this) = std::move(obj);
}

Node::~Node()
{
    // EMPTY.
}

Node & Node::operator =(Node const & obj) TBAG_NOEXCEPT
{
    copy(obj);
    return *this;
}

Node & Node::operator =(Node && obj) TBAG_NOEXCEPT
{
    swap(obj);
    return *this;
}

void Node::copy(Node const & obj) TBAG_NOEXCEPT
{
    if (this != &obj) {
        _impl = obj._impl;
        _event = obj._event;
    }
}

void Node::swap(Node & obj) TBAG_NOEXCEPT
{
    if (this != &obj) {
        _impl.swap(obj._impl);
        _event.swap(obj._event);
    }
}

Err Node::open(std::string const & uri)
{
    return Err::E_UNSUPOP;
}

Err Node::close()
{
    return Err::E_UNSUPOP;
}

Err Node::connect(std::string const & server_name, std::string const & uri)
{
    return Err::E_UNSUPOP;
}

Err Node::disconnect(std::string const & server_name)
{
    return Err::E_UNSUPOP;
}

Err Node::c2s(std::string const & server_name, char const * buffer, std::size_t size)
{
    return Err::E_UNSUPOP;
}

Err Node::s2c(std::string const & client_name, char const * buffer, std::size_t size)
{
    return Err::E_UNSUPOP;
}

} // namespace node
} // namespace network

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<commit_msg>Update event callback to the Node class.<commit_after>/**
 * @file   Node.cpp
 * @brief  Node class implementation.
 * @author zer0
 * @date   2018-10-26
 */

#include <libtbag/network/node/Node.hpp>
#include <libtbag/log/Log.hpp>
#include <libtbag/Noncopyable.hpp>
#include <libtbag/thread/ThreadPool.hpp>
#include <libtbag/network/http/HttpServer.hpp>
#include <libtbag/network/http/HttpClient.hpp>
#include <libtbag/uvpp/Loop.hpp>

#include <cassert>
#include <algorithm>
#include <utility>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace network {
namespace node    {

/** @warning Don't change this variable. */
TBAG_CONSTEXPR static unsigned int const _POOL_SIZE = 1U;

/**
 * Node::Impl class implementation.
 *
 * @author zer0
 * @date   2018-10-26
 */
struct Node::Impl : private Noncopyable
{
public:
    using ThreadPool = libtbag::thread::ThreadPool;

public:
    using HttpServer   = libtbag::network::http::HttpServer;
    using HttpClient   = libtbag::network::http::HttpClient;
    using StreamType   = libtbag::network::details::StreamType;
    using HttpRequest  = libtbag::network::http::HttpRequest;
    using HttpResponse = libtbag::network::http::HttpResponse;
    using HttpProperty = libtbag::network::http::HttpProperty;
    using WsOpCode     = libtbag::network::http::ws::WsOpCode;
    using EventType    = libtbag::network::http::EventType;
    using Loop         = libtbag::uvpp::Loop;

public:
    struct Server;
    struct Client;

    friend struct Server;
    friend struct Client;

public:
    /**
     * Node::Impl::Server class implementation.
     *
     * @author zer0
     * @date   2018-10-26
     */
    struct Server : public HttpServer
    {
        using Base = HttpServer;

        Server(Loop & loop, StreamType type = StreamType::TCP) : Base(loop, type)
        {
            // EMPTY.
        }

        virtual ~Server()
        {
            // EMPTY.
        }

        // -----------------------
        // ServerInterface events.
        // -----------------------

        virtual void onConnection(Err code) override
        {
            Base::onConnection(code);
        }

        virtual void onClientShutdown(WeakClient node, Err code) override
        {
            // EMPTY.
        }

        virtual void onClientWrite(WeakClient node, Err code) override
        {
            // EMPTY.
        }

        // Don't implement this method.
        // virtual void onClientRead(WeakClient node, Err code, ReadPacket const & packet) override
        // { /* EMPTY. */ }

        virtual void onClientClose(WeakClient node) override
        {
            // EMPTY.
        }

        virtual void onClientTimer(WeakClient node) override
        {
            // EMPTY.
        }

        virtual void onServerClose() override
        {
            // EMPTY.
        }

        // ------------------
        // HttpServer events.
        // ------------------

        SharedStreamNode createClient(StreamType type, Loop & loop, SharedStream & server) override
        {
            assert(static_cast<bool>(server));
            return SharedStreamNode(new (std::nothrow) HttpNode(loop, type, this));
        }

        virtual void onClientEof(WeakClient node) override
        {
            Base::onClientEof(node);
        }

        virtual void onClientReadError(WeakClient node, Err code) override
        {
            Base::onClientReadError(node, code);
        }

        virtual void onClientParseError(WeakClient node, Err code) override
        {
            Base::onClientParseError(node, code);
        }

        virtual bool onClientSwitchingProtocol(WeakClient node, HttpRequest const & request) override
        {
            return Base::onClientSwitchingProtocol(node, request);
        }

        // ----------------------------
        // HttpServer extension events.
        // ----------------------------

        virtual void onClientOpen(WeakClient node) override
        {
            // EMPTY.
        }

        virtual void onClientContinue(WeakClient node) override
        {
            // EMPTY.
        }

        virtual void onClientWsMessage(WeakClient node, WsOpCode opcode, util::Buffer const & payload) override
        {
            // EMPTY.
        }

        virtual void onClientRequest(WeakClient node, HttpRequest const & request) override
        {
            // EMPTY.
        }
    };

    /**
     * Node::Impl::Client class implementation.
     *
     * @author zer0
     * @date   2018-10-26
     */
    struct Client : public HttpClient
    {
        using Base = HttpClient;

        Client(Loop & loop, StreamType type = StreamType::TCP) : Base(loop, type)
        {
            // EMPTY.
        }

        virtual ~Client()
        {
            // EMPTY.
        }

        // -----------------------
        // ClientInterface events.
        // -----------------------

        virtual void onConnect(Err code) override
        {
            Base::onConnect(code);
        }

        virtual void onShutdown(Err code) override
        {
            // EMPTY.
        }

        virtual void onWrite(Err code) override
        {
            // EMPTY.
        }

        virtual void onRead(Err code, ReadPacket const & packet) override
        {
            Base::onRead(code, packet);
        }

        virtual void onClose() override
        {
            // EMPTY.
        }

        virtual void onTimer() override
        {
            // EMPTY.
        }

        // ----------------------------
        // HttpClient extension events.
        // ----------------------------

        virtual void onOpen() override
        {
            // EMPTY.
        }

        virtual void onEof() override
        {
            Base::onEof();
        }

        virtual void onError(EventType from, Err code) override
        {
            Base::onError(from, code);
        }

        // ---------------------------
        // HttpReaderInterface events.
        // ---------------------------

        virtual void onContinue(void * arg) override
        {
            // EMPTY.
        }

        virtual bool onSwitchingProtocol(HttpProperty const & property, void * arg) override
        {
            return Base::onSwitchingProtocol(property, arg);
        }

        virtual void onWsMessage(WsOpCode opcode, util::Buffer const & payload, void * arg) override
        {
            // EMPTY.
        }

        virtual void onRegularHttp(HttpProperty const & property, void * arg) override
        {
            // EMPTY.
        }

        virtual void onParseError(Err code, void * arg) override
        {
            Base::onParseError(code, arg);
        }
    };

    using SharedServer = std::shared_ptr<Server>;
    using SharedClient = std::shared_ptr<Client>;

private:
    Node * _parent;

private:
    ThreadPool _pool;

private:
    NodeType _type = NodeType::NT_NONE;

public:
    Impl(Node * parent) : _parent(parent), _pool(_POOL_SIZE)
    {
        assert(_parent != nullptr);
        assert(_pool.sizeOfThreads() == _POOL_SIZE);
    }

    ~Impl()
    {
        // EMPTY.
    }

public:
};

// ----------------------------
// Node implementation.
// ----------------------------

Node::Node() : _impl(std::make_shared<Impl>(this))
{
    assert(static_cast<bool>(_impl));
}

Node::Node(std::nullptr_t) TBAG_NOEXCEPT : _impl(nullptr)
{
    // EMPTY.
}

Node::Node(Node const & obj) TBAG_NOEXCEPT : Node(nullptr)
{
    (*this) = obj;
}

Node::Node(Node && obj) TBAG_NOEXCEPT : Node(nullptr)
{
    (*this) = std::move(obj);
}

Node::~Node()
{
    // EMPTY.
}

Node & Node::operator =(Node const & obj) TBAG_NOEXCEPT
{
    copy(obj);
    return *this;
}

Node & Node::operator =(Node && obj) TBAG_NOEXCEPT
{
    swap(obj);
    return *this;
}

void Node::copy(Node const & obj) TBAG_NOEXCEPT
{
    if (this != &obj) {
        _impl = obj._impl;
        _event = obj._event;
    }
}

void Node::swap(Node & obj) TBAG_NOEXCEPT
{
    if (this != &obj) {
        _impl.swap(obj._impl);
        _event.swap(obj._event);
    }
}

Err Node::open(std::string const & uri)
{
    return Err::E_UNSUPOP;
}

Err Node::close()
{
    return Err::E_UNSUPOP;
}

Err Node::connect(std::string const & server_name, std::string const & uri)
{
    return Err::E_UNSUPOP;
}

Err Node::disconnect(std::string const & server_name)
{
    return Err::E_UNSUPOP;
}

Err Node::c2s(std::string const & server_name, char const * buffer, std::size_t size)
{
    return Err::E_UNSUPOP;
}

Err Node::s2c(std::string const & client_name, char const * buffer, std::size_t size)
{
    return Err::E_UNSUPOP;
}

} // namespace node
} // namespace network

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <deque>
#include <cassert>
#include "halLiftover.h"

using namespace std;
using namespace hal;

Liftover::Liftover() : _outBedStream(NULL),
                       _inBedVersion(-1), _outBedVersion(-1),
                       _outPSL(false),
                       _srcGenome(NULL), _tgtGenome(NULL)
{

}

Liftover::~Liftover()
{

}

void Liftover::convert(AlignmentConstPtr alignment,
                       const Genome* srcGenome,
                       istream* inBedStream,
                       const Genome* tgtGenome,
                       ostream* outBedStream,
                       int inBedVersion,
                       int outBedVersion,
                       bool addExtraColumns,
                       bool traverseDupes,
                       bool outPSL)
{
  _srcGenome = srcGenome;
  _tgtGenome = tgtGenome;
  _outBedStream = outBedStream;
  _addExtraColumns = addExtraColumns;
  _inBedVersion = inBedVersion;
  _outBedVersion = outBedVersion;
  _traverseDupes = traverseDupes;
  _outPSL = outPSL;
  _missedSet.clear();
  _tgtSet.clear();
  assert(_srcGenome && inBedStream && tgtGenome && outBedStream);

  _tgtSet.insert(tgtGenome);

  // we copy into a stringstream because we never want to
  // run getBedVersion (which does random access) on cin (which is a
  // possible value for inBedStream)
  string firstLineBuffer;
  stringstream* firstLineStream = NULL;
  if (_inBedVersion <= 0)
  {
    skipWhiteSpaces(inBedStream);
    std::getline(*inBedStream, firstLineBuffer);
    firstLineStream = new stringstream(firstLineBuffer);
    _inBedVersion = BedScanner::getBedVersion(firstLineStream);
    assert(inBedStream->eof() || _inBedVersion >= 3);
    size_t numCols = BedScanner::getNumColumns(firstLineBuffer);
    if ((int)numCols > _inBedVersion)
    {
      cerr << "Warning: auto-detecting input BED version " << _inBedVersion
           << " even though " << numCols << " columns present" << endl;
    }
  }
  if (_outBedVersion <= 0)
  {
    _outBedVersion = _inBedVersion;
  }

  if (firstLineStream != NULL)
  {
    scan(firstLineStream, _inBedVersion);
    delete firstLineStream;
  }
  scan(inBedStream, _inBedVersion);
}

void Liftover::visitBegin()
{
}

void Liftover::visitLine()
{
  _outBedLines.clear();
  _srcSequence = _srcGenome->getSequence(_bedLine._chrName);
  if (_srcSequence == NULL)
  {
    pair<set<string>::iterator, bool> result = _missedSet.insert(
      _bedLine._chrName);
    if (result.second == true)
    {
      std::cerr << "Unable to find sequence " << _bedLine._chrName
                << " in genome " << _srcGenome->getName() << endl;
    }
    return;
  }

  else if (_bedLine._end > (hal_index_t)_srcSequence->getSequenceLength())
  {
    std::cerr << "Skipping interval with endpoint " << _bedLine._end
              << "because sequence " << _bedLine._chrName << " has length "
              << _srcSequence->getSequenceLength() << endl;
    return;
  }

  else if (_inBedVersion > 9 && _bedLine._blocks.empty())
  {
    std::cerr << "Skipping input line with 0 blocks" << endl;
    return;
  }

  _mappedBlocks.clear();
  if (_inBedVersion <= 9)
  {
    liftInterval(_mappedBlocks);
  }
  else
  {
    assert(!_bedLine._blocks.empty());
    liftBlockIntervals();
  }

  if (_mappedBlocks.size() > 0 && _outBedVersion > 9)
  {
    // fill them with mapped blocks
    assignBlocksToIntervals();
  }
  if (_outBedVersion <= 9)
  {
    //only map the blocks and forget about the intervals
    writeBlocksAsIntervals();
  }

  cleanResults();
  _outBedLines.sort(BedLineSrcLess());
  writeLineResults();
}

void Liftover::visitEOF()
{
}

void Liftover::writeLineResults()
{
  BedList::iterator i = _outBedLines.begin();
  for (; i != _outBedLines.end(); ++i)
  {
    if (_addExtraColumns == false)
    {
      i->_extra.clear();
    }
    if (_outPSL == false)
    {
      i->write(*_outBedStream, _outBedVersion);
    }
    else
    {
      i->writePSL(*_outBedStream);
    }
  }
}

void Liftover::assignBlocksToIntervals()
{
  assert(_outBedLines.size() == 0);

   // sort the mapped blocks by source coordinate
  _mappedBlocks.sort(BedLineSrcLess());
  hal_index_t prevSrcStart = NULL_INDEX;
  BedList::iterator blockNext;
  for (BedList::iterator blockIt = _mappedBlocks.begin();
       blockIt != _mappedBlocks.end(); ++blockIt)
  {
    blockNext = blockIt;
    ++blockNext;
    if (_outBedLines.empty() ||
        // filter dupes in psl but let them be on single bed line
        (_outPSL && (blockIt->_srcStart == prevSrcStart ||
                     (blockNext != _mappedBlocks.end() &&
                      blockNext->_srcStart == blockIt->_srcStart))) ||
        !compatible(_outBedLines.back(), *blockIt))
    {
      _outBedLines.push_back(*blockIt);
    }
    prevSrcStart = blockIt->_srcStart;
    BedLine& tgtBed = _outBedLines.back();
    tgtBed._start = min(tgtBed._start, blockIt->_start);
    tgtBed._end = max(tgtBed._end, blockIt->_end);
    // keep start absolute for now
    BedBlock block;
    block._start = blockIt->_start;
    block._length = blockIt->_end - blockIt->_start;
    tgtBed._blocks.push_back(block);

    if (_outPSL == true)
    {
      assert(tgtBed._psl.size() == 1);
      tgtBed._psl[0]._qBlockStarts.push_back(blockIt->_srcStart);
      // note that these get done on assignmnet for first block
      if (tgtBed._blocks.size() > 1)
      {
        tgtBed._psl[0]._matches += blockIt->_psl[0]._matches;
        tgtBed._psl[0]._misMatches += blockIt->_psl[0]._misMatches;
        tgtBed._psl[0]._repMatches += blockIt->_psl[0]._repMatches;
        tgtBed._psl[0]._nCount += blockIt->_psl[0]._nCount;
      }
      assert(tgtBed._blocks.size() ==
             tgtBed._psl[0]._qBlockStarts.size());
    }
  }

  // relativize block starts
  for (BedList::iterator blockIt = _outBedLines.begin();
       blockIt != _outBedLines.end(); ++blockIt)
  {
    for (size_t i = 0; i < blockIt->_blocks.size(); ++i)
    {
      assert(blockIt->_blocks[i]._start >= blockIt->_start);
      blockIt->_blocks[i]._start -= blockIt->_start;
    }
  }

  // Flip the block ordering to make sure it's ascending in the output
  if (!_outBedLines.empty())
  {
    flipBlocks(_outBedLines);
  }

  // Fill in some informtation for the insert PSL fields
  if (_outPSL == true)
  {
    computePSLInserts(_outBedLines);
  }
}

bool Liftover::compatible(const BedLine& tgtBed, const BedLine& newBlock)
{
  if (tgtBed._strand != newBlock._strand)
  {
    return false;
  }
  assert(newBlock._srcStart >= tgtBed._srcStart);
  if (tgtBed._srcStart == newBlock._srcStart)
  {
    return false;
  }

  hal_index_t delta;
  const BedBlock& tgtBlock = tgtBed._blocks.back();

  if (tgtBed._strand != _bedLine._strand)
  {
    delta = tgtBlock._start - newBlock._end;
  }
  else
  {
    delta = newBlock._start -
       (tgtBlock._start + (hal_index_t)tgtBlock._length);
  }
  if (delta < 0)
  {
    return false;
  }

  return true;
}

void Liftover::flipBlocks(BedList& bedList)
{
  for (BedList::iterator bedIt = bedList.begin(); bedIt != bedList.end();
       ++bedIt)
  {
    if (bedIt->_blocks.size() > 1)
    {
      hal_index_t delta = bedIt->_blocks[1]._start -
         (bedIt->_blocks[0]._start + (hal_index_t)bedIt->_blocks[0]._length);
      bool mustFlip = false;

      if (_outPSL != true)
      {
        mustFlip = delta < 0;
      }
      else
      {
        mustFlip = (bedIt->_strand == '-' && delta >= 0 ||
                    bedIt->_strand != '-' && delta < 0);
      }

      if (mustFlip == true)
      {
        std::reverse(bedIt->_blocks.begin(),
                     bedIt->_blocks.end());
        if (_outPSL == true)
        {
          std::reverse(bedIt->_psl[0]._qBlockStarts.begin(),
                       bedIt->_psl[0]._qBlockStarts.end());
        }
      }

#ifndef NDEBUG
      if (_outPSL == true)
      {
        for (size_t i = 1; i < bedIt->_blocks.size(); ++i)
        {
          if (bedIt->_strand == '-')
          {
            assert(bedIt->_blocks[i]._start < bedIt->_blocks[i-1]._start);
          }
          else
          {
            assert(bedIt->_blocks[i]._start > bedIt->_blocks[i-1]._start);
          }
          if (bedIt->_psl[0]._qStrand == '-')
          {
            assert(bedIt->_psl[0]._qBlockStarts[i] <
                   bedIt->_psl[0]._qBlockStarts[i-1]);
          }
          else
          {
            assert(bedIt->_psl[0]._qBlockStarts[i] >
                   bedIt->_psl[0]._qBlockStarts[i-1]);
          }
        }
      }
#endif
    }
  }
}

void Liftover::computePSLInserts(BedList& bedList)
{
  for (BedList::iterator bedIt = bedList.begin(); bedIt != bedList.end();
       ++bedIt)
  {
    PSLInfo& psl = bedIt->_psl[0];
    psl._qNumInsert = 0;
    psl._qBaseInsert = 0;
    psl._tNumInsert = 0;
    psl._tBaseInsert = 0;

    assert(bedIt->_blocks.size() == psl._qBlockStarts.size());
    vector<BedBlock>::iterator blockIt = bedIt->_blocks.begin();
    vector<BedBlock>::iterator blockPrev = blockIt;

    vector<hal_index_t>::iterator qStartIt = psl._qBlockStarts.begin();
    vector<hal_index_t>::iterator qStartPrev = qStartIt;

    if (blockIt != bedIt->_blocks.end())
    {
      ++blockIt;
      ++qStartIt;
    }
    for (; blockIt != bedIt->_blocks.end(); ++blockIt, ++blockPrev,
            ++qStartIt, ++qStartPrev)
    {
      if (bedIt->_strand == '-')
      {
        swap(blockIt, blockPrev);
      }
      assert(blockIt->_start >= (blockPrev->_start + blockPrev->_length));
      hal_size_t gap = blockIt->_start -
         (blockPrev->_start + blockPrev->_length);
      if (gap > 0)
      {
        ++psl._tNumInsert;
        psl._tBaseInsert += gap;
      }
      if (bedIt->_strand == '-')
      {
        swap(blockIt, blockPrev);
      }

      if (psl._qStrand == '-')
      {
        swap(qStartIt, qStartPrev);
        swap(blockIt, blockPrev);
      }
      assert(*qStartIt >= (*qStartPrev + blockPrev->_length));
      gap = *qStartIt - (*qStartPrev + blockPrev->_length);
      if (gap > 0)
      {
        ++psl._qNumInsert;
        psl._qBaseInsert += gap;
      }
      if (psl._qStrand == '-')
      {
        swap(qStartIt, qStartPrev);
        swap(blockIt, blockPrev);
      }
    }
  }
}

void Liftover::writeBlocksAsIntervals()
{
  _outBedLines = _mappedBlocks;
}

void Liftover::liftBlockIntervals()
{
  BedLine originalBedLine = _bedLine;
  std::sort(_bedLine._blocks.begin(), _bedLine._blocks.end());
  vector<BedBlock>::iterator blockIt = _bedLine._blocks.begin();
  for (; blockIt != _bedLine._blocks.end(); ++blockIt)
  {
    _bedLine._start = blockIt->_start + originalBedLine._start;
    _bedLine._end = _bedLine._start + blockIt->_length;
    if (_bedLine._end > _bedLine._start)
    {
      liftInterval(_mappedBlocks);
    }
  }
  _bedLine._start = originalBedLine._start;
  _bedLine._end = originalBedLine._end;
}

// do a little postprocessing on the lifted intervals to make sure
// they are bed compliant
void Liftover::cleanResults()
{
  if (_outBedVersion > 6)
  {
    BedList::iterator i;
    BedList::iterator j;
    for (i = _outBedLines.begin(); i != _outBedLines.end(); i = j)
    {
      j = i;
      ++j;
      if (_bedLine._thickStart != 0 || _bedLine._thickEnd != 0)
      {
        i->_thickStart = i->_start;
        i->_thickEnd = i->_end;
        if (_bedLine._thickStart != _bedLine._start ||
            _bedLine._thickEnd != _bedLine._end)
        {
          cerr << "Input BED line " << _lineNumber << " warning: "
               << "thickStart different from chromStart or thickEnd "
               << "different from chromEnd not supported.  Assuming they"
               << " are the same." << endl;
        }
      }
      else
      {
        assert(i->_thickStart == 0 && i->_thickEnd == 0);
      }

      if (_outBedVersion > 9)
      {
        if  (i->_blocks.size() > 0)
        {
          if (_outPSL == true)
          {
            assert(i->_psl.size() == 1);
            i->_srcStart = numeric_limits<hal_index_t>::max();
            i->_psl[0]._qEnd = 0;
            for (size_t j = 0; j < i->_psl[0]._qBlockStarts.size(); ++j)
            {
              i->_srcStart = min(i->_srcStart, i->_psl[0]._qBlockStarts[j]);
              i->_psl[0]._qEnd = max(i->_psl[0]._qEnd,
                                     (hal_size_t)i->_psl[0]._qBlockStarts[j] +
                                     i->_blocks[j]._length);
            }
          }
        }
        else
        {
          // if we're in bed 12, we don't want any empty regions in the
          // output
          _outBedLines.erase(i);
        }
      }
    }
  }
}
<commit_msg>make sure to split block lines if chromosome name differs<commit_after>/*
 * Copyright (C) 2012 by Glenn Hickey (hickey@soe.ucsc.edu)
 *
 * Released under the MIT license, see LICENSE.txt
 */

#include <deque>
#include <cassert>
#include "halLiftover.h"

using namespace std;
using namespace hal;

Liftover::Liftover() : _outBedStream(NULL),
                       _inBedVersion(-1), _outBedVersion(-1),
                       _outPSL(false),
                       _srcGenome(NULL), _tgtGenome(NULL)
{

}

Liftover::~Liftover()
{

}

void Liftover::convert(AlignmentConstPtr alignment,
                       const Genome* srcGenome,
                       istream* inBedStream,
                       const Genome* tgtGenome,
                       ostream* outBedStream,
                       int inBedVersion,
                       int outBedVersion,
                       bool addExtraColumns,
                       bool traverseDupes,
                       bool outPSL)
{
  _srcGenome = srcGenome;
  _tgtGenome = tgtGenome;
  _outBedStream = outBedStream;
  _addExtraColumns = addExtraColumns;
  _inBedVersion = inBedVersion;
  _outBedVersion = outBedVersion;
  _traverseDupes = traverseDupes;
  _outPSL = outPSL;
  _missedSet.clear();
  _tgtSet.clear();
  assert(_srcGenome && inBedStream && tgtGenome && outBedStream);

  _tgtSet.insert(tgtGenome);

  // we copy into a stringstream because we never want to
  // run getBedVersion (which does random access) on cin (which is a
  // possible value for inBedStream)
  string firstLineBuffer;
  stringstream* firstLineStream = NULL;
  if (_inBedVersion <= 0)
  {
    skipWhiteSpaces(inBedStream);
    std::getline(*inBedStream, firstLineBuffer);
    firstLineStream = new stringstream(firstLineBuffer);
    _inBedVersion = BedScanner::getBedVersion(firstLineStream);
    assert(inBedStream->eof() || _inBedVersion >= 3);
    size_t numCols = BedScanner::getNumColumns(firstLineBuffer);
    if ((int)numCols > _inBedVersion)
    {
      cerr << "Warning: auto-detecting input BED version " << _inBedVersion
           << " even though " << numCols << " columns present" << endl;
    }
  }
  if (_outBedVersion <= 0)
  {
    _outBedVersion = _inBedVersion;
  }

  if (firstLineStream != NULL)
  {
    scan(firstLineStream, _inBedVersion);
    delete firstLineStream;
  }
  scan(inBedStream, _inBedVersion);
}

void Liftover::visitBegin()
{
}

void Liftover::visitLine()
{
  _outBedLines.clear();
  _srcSequence = _srcGenome->getSequence(_bedLine._chrName);
  if (_srcSequence == NULL)
  {
    pair<set<string>::iterator, bool> result = _missedSet.insert(
      _bedLine._chrName);
    if (result.second == true)
    {
      std::cerr << "Unable to find sequence " << _bedLine._chrName
                << " in genome " << _srcGenome->getName() << endl;
    }
    return;
  }

  else if (_bedLine._end > (hal_index_t)_srcSequence->getSequenceLength())
  {
    std::cerr << "Skipping interval with endpoint " << _bedLine._end
              << "because sequence " << _bedLine._chrName << " has length "
              << _srcSequence->getSequenceLength() << endl;
    return;
  }

  else if (_inBedVersion > 9 && _bedLine._blocks.empty())
  {
    std::cerr << "Skipping input line with 0 blocks" << endl;
    return;
  }

  _mappedBlocks.clear();
  if (_inBedVersion <= 9)
  {
    liftInterval(_mappedBlocks);
  }
  else
  {
    assert(!_bedLine._blocks.empty());
    liftBlockIntervals();
  }

  if (_mappedBlocks.size() > 0 && _outBedVersion > 9)
  {
    // fill them with mapped blocks
    assignBlocksToIntervals();
  }
  if (_outBedVersion <= 9)
  {
    //only map the blocks and forget about the intervals
    writeBlocksAsIntervals();
  }

  cleanResults();
  _outBedLines.sort(BedLineSrcLess());
  writeLineResults();
}

void Liftover::visitEOF()
{
}

void Liftover::writeLineResults()
{
  BedList::iterator i = _outBedLines.begin();
  for (; i != _outBedLines.end(); ++i)
  {
    if (_addExtraColumns == false)
    {
      i->_extra.clear();
    }
    if (_outPSL == false)
    {
      i->write(*_outBedStream, _outBedVersion);
    }
    else
    {
      i->writePSL(*_outBedStream);
    }
  }
}

void Liftover::assignBlocksToIntervals()
{
  assert(_outBedLines.size() == 0);

   // sort the mapped blocks by source coordinate
  _mappedBlocks.sort(BedLineSrcLess());
  hal_index_t prevSrcStart = NULL_INDEX;
  BedList::iterator blockNext;
  for (BedList::iterator blockIt = _mappedBlocks.begin();
       blockIt != _mappedBlocks.end(); ++blockIt)
  {
    blockNext = blockIt;
    ++blockNext;
    if (_outBedLines.empty() ||
        // filter dupes in psl but let them be on single bed line
        (_outPSL && (blockIt->_srcStart == prevSrcStart ||
                     (blockNext != _mappedBlocks.end() &&
                      blockNext->_srcStart == blockIt->_srcStart))) ||
        !compatible(_outBedLines.back(), *blockIt))
    {
      _outBedLines.push_back(*blockIt);
    }
    prevSrcStart = blockIt->_srcStart;
    BedLine& tgtBed = _outBedLines.back();
    tgtBed._start = min(tgtBed._start, blockIt->_start);
    tgtBed._end = max(tgtBed._end, blockIt->_end);
    // keep start absolute for now
    BedBlock block;
    block._start = blockIt->_start;
    block._length = blockIt->_end - blockIt->_start;
    tgtBed._blocks.push_back(block);

    if (_outPSL == true)
    {
      assert(tgtBed._psl.size() == 1);
      tgtBed._psl[0]._qBlockStarts.push_back(blockIt->_srcStart);
      // note that these get done on assignmnet for first block
      if (tgtBed._blocks.size() > 1)
      {
        tgtBed._psl[0]._matches += blockIt->_psl[0]._matches;
        tgtBed._psl[0]._misMatches += blockIt->_psl[0]._misMatches;
        tgtBed._psl[0]._repMatches += blockIt->_psl[0]._repMatches;
        tgtBed._psl[0]._nCount += blockIt->_psl[0]._nCount;
      }
      assert(tgtBed._blocks.size() ==
             tgtBed._psl[0]._qBlockStarts.size());
    }
  }

  // relativize block starts
  for (BedList::iterator blockIt = _outBedLines.begin();
       blockIt != _outBedLines.end(); ++blockIt)
  {
    for (size_t i = 0; i < blockIt->_blocks.size(); ++i)
    {
      assert(blockIt->_blocks[i]._start >= blockIt->_start);
      blockIt->_blocks[i]._start -= blockIt->_start;
    }
  }

  // Flip the block ordering to make sure it's ascending in the output
  if (!_outBedLines.empty())
  {
    flipBlocks(_outBedLines);
  }

  // Fill in some informtation for the insert PSL fields
  if (_outPSL == true)
  {
    computePSLInserts(_outBedLines);
  }
}

bool Liftover::compatible(const BedLine& tgtBed, const BedLine& newBlock)
{
  if (tgtBed._strand != newBlock._strand)
  {
    return false;
  }
  assert(newBlock._srcStart >= tgtBed._srcStart);
  if (tgtBed._srcStart == newBlock._srcStart)
  {
    return false;
  }

  hal_index_t delta;
  const BedBlock& tgtBlock = tgtBed._blocks.back();

  if (tgtBed._strand != _bedLine._strand)
  {
    delta = tgtBlock._start - newBlock._end;
  }
  else
  {
    delta = newBlock._start -
       (tgtBlock._start + (hal_index_t)tgtBlock._length);
  }
  if (delta < 0)
  {
    return false;
  }

  if (tgtBed._chrName != newBlock._chrName)
  {
    return false;
  }

  return true;
}

void Liftover::flipBlocks(BedList& bedList)
{
  for (BedList::iterator bedIt = bedList.begin(); bedIt != bedList.end();
       ++bedIt)
  {
    if (bedIt->_blocks.size() > 1)
    {
      hal_index_t delta = bedIt->_blocks[1]._start -
         (bedIt->_blocks[0]._start + (hal_index_t)bedIt->_blocks[0]._length);
      bool mustFlip = false;

      if (_outPSL != true)
      {
        mustFlip = delta < 0;
      }
      else
      {
        mustFlip = (bedIt->_strand == '-' && delta >= 0 ||
                    bedIt->_strand != '-' && delta < 0);
      }

      if (mustFlip == true)
      {
        std::reverse(bedIt->_blocks.begin(),
                     bedIt->_blocks.end());
        if (_outPSL == true)
        {
          std::reverse(bedIt->_psl[0]._qBlockStarts.begin(),
                       bedIt->_psl[0]._qBlockStarts.end());
        }
      }

#ifndef NDEBUG
      if (_outPSL == true)
      {
        for (size_t i = 1; i < bedIt->_blocks.size(); ++i)
        {
          if (bedIt->_strand == '-')
          {
            assert(bedIt->_blocks[i]._start < bedIt->_blocks[i-1]._start);
          }
          else
          {
            assert(bedIt->_blocks[i]._start > bedIt->_blocks[i-1]._start);
          }
          if (bedIt->_psl[0]._qStrand == '-')
          {
            assert(bedIt->_psl[0]._qBlockStarts[i] <
                   bedIt->_psl[0]._qBlockStarts[i-1]);
          }
          else
          {
            assert(bedIt->_psl[0]._qBlockStarts[i] >
                   bedIt->_psl[0]._qBlockStarts[i-1]);
          }
        }
      }
#endif
    }
  }
}

void Liftover::computePSLInserts(BedList& bedList)
{
  for (BedList::iterator bedIt = bedList.begin(); bedIt != bedList.end();
       ++bedIt)
  {
    PSLInfo& psl = bedIt->_psl[0];
    psl._qNumInsert = 0;
    psl._qBaseInsert = 0;
    psl._tNumInsert = 0;
    psl._tBaseInsert = 0;

    assert(bedIt->_blocks.size() == psl._qBlockStarts.size());
    vector<BedBlock>::iterator blockIt = bedIt->_blocks.begin();
    vector<BedBlock>::iterator blockPrev = blockIt;

    vector<hal_index_t>::iterator qStartIt = psl._qBlockStarts.begin();
    vector<hal_index_t>::iterator qStartPrev = qStartIt;

    if (blockIt != bedIt->_blocks.end())
    {
      ++blockIt;
      ++qStartIt;
    }
    for (; blockIt != bedIt->_blocks.end(); ++blockIt, ++blockPrev,
            ++qStartIt, ++qStartPrev)
    {
      if (bedIt->_strand == '-')
      {
        swap(blockIt, blockPrev);
      }
      assert(blockIt->_start >= (blockPrev->_start + blockPrev->_length));
      hal_size_t gap = blockIt->_start -
         (blockPrev->_start + blockPrev->_length);
      if (gap > 0)
      {
        ++psl._tNumInsert;
        psl._tBaseInsert += gap;
      }
      if (bedIt->_strand == '-')
      {
        swap(blockIt, blockPrev);
      }

      if (psl._qStrand == '-')
      {
        swap(qStartIt, qStartPrev);
        swap(blockIt, blockPrev);
      }
      assert(*qStartIt >= (*qStartPrev + blockPrev->_length));
      gap = *qStartIt - (*qStartPrev + blockPrev->_length);
      if (gap > 0)
      {
        ++psl._qNumInsert;
        psl._qBaseInsert += gap;
      }
      if (psl._qStrand == '-')
      {
        swap(qStartIt, qStartPrev);
        swap(blockIt, blockPrev);
      }
    }
  }
}

void Liftover::writeBlocksAsIntervals()
{
  _outBedLines = _mappedBlocks;
}

void Liftover::liftBlockIntervals()
{
  BedLine originalBedLine = _bedLine;
  std::sort(_bedLine._blocks.begin(), _bedLine._blocks.end());
  vector<BedBlock>::iterator blockIt = _bedLine._blocks.begin();
  for (; blockIt != _bedLine._blocks.end(); ++blockIt)
  {
    _bedLine._start = blockIt->_start + originalBedLine._start;
    _bedLine._end = _bedLine._start + blockIt->_length;
    if (_bedLine._end > _bedLine._start)
    {
      liftInterval(_mappedBlocks);
    }
  }
  _bedLine._start = originalBedLine._start;
  _bedLine._end = originalBedLine._end;
}

// do a little postprocessing on the lifted intervals to make sure
// they are bed compliant
void Liftover::cleanResults()
{
  if (_outBedVersion > 6)
  {
    BedList::iterator i;
    BedList::iterator j;
    for (i = _outBedLines.begin(); i != _outBedLines.end(); i = j)
    {
      j = i;
      ++j;
      if (_bedLine._thickStart != 0 || _bedLine._thickEnd != 0)
      {
        i->_thickStart = i->_start;
        i->_thickEnd = i->_end;
        if (_bedLine._thickStart != _bedLine._start ||
            _bedLine._thickEnd != _bedLine._end)
        {
          cerr << "Input BED line " << _lineNumber << " warning: "
               << "thickStart different from chromStart or thickEnd "
               << "different from chromEnd not supported.  Assuming they"
               << " are the same." << endl;
        }
      }
      else
      {
        assert(i->_thickStart == 0 && i->_thickEnd == 0);
      }

      if (_outBedVersion > 9)
      {
        if  (i->_blocks.size() > 0)
        {
          if (_outPSL == true)
          {
            assert(i->_psl.size() == 1);
            i->_srcStart = numeric_limits<hal_index_t>::max();
            i->_psl[0]._qEnd = 0;
            for (size_t j = 0; j < i->_psl[0]._qBlockStarts.size(); ++j)
            {
              i->_srcStart = min(i->_srcStart, i->_psl[0]._qBlockStarts[j]);
              i->_psl[0]._qEnd = max(i->_psl[0]._qEnd,
                                     (hal_size_t)i->_psl[0]._qBlockStarts[j] +
                                     i->_blocks[j]._length);
            }
          }
        }
        else
        {
          // if we're in bed 12, we don't want any empty regions in the
          // output
          _outBedLines.erase(i);
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>#include "renderer.h"
#include <cassert>
#include <iostream> // debug
#include "viewer.h"

using namespace liven;

grid_node gride_node_from_image_units(
		int image_width,
		int image_height,
		std::vector<int> v_image_partitions,
		std::vector<int> h_image_partitions)
{
	int width;
	int height;
	std::vector<int> v_partitions;
	std::vector<int> h_partitions;

	width = image_width * ascii_renderer::scene_x_coordinates_per_pixel;
	height = image_height * ascii_renderer::scene_y_coordinates_per_pixel;
	for (auto p : v_image_partitions) {v_partitions.push_back(p * ascii_renderer::scene_x_coordinates_per_pixel);}
	for (auto p : h_image_partitions) {h_partitions.push_back(p * ascii_renderer::scene_y_coordinates_per_pixel);}

	return grid_node(width, height, v_partitions, h_partitions);
}

int main() {
	ascii_renderer r{};
	/* In our ascii renderings, + represents the lower-left corner of a rect.
	   Say the rect's lower left corner is located at (0,0) in scene coordinates.
	   Also suppose this lower-left corner is drawn using pixel_at(0,0) in an image.
	   Therefore, (0,0) in scene coordinates is actually located at (.5,.5) in image coordinates.
	   If the rect is one pixel unit high, its top left corner will be drawn in the center
	   of the pixel_at(0,1), i.e at (.5,1.5) in image coordinates.
	   If the rect is one pixel unit wide, its lower right corner will be draw in the center
	   of the pixel_at(1,0), i.e. at (1.5,.5) in image coordinates.
	   The spaces between the pairs of image-coordinate points ((.5,0),(.5,1)) and ((.5,1.5),(.5,2))
	   goes unused (this is space above and below the rect).
	   In an ideal world, the bottom left corner of the rect would have image coordinates (0,0)
	   and its top left would have image coordinates (0,1), but this isn't possible with ascii.
	   Therefore the rect "invades" the row of pixels above where it should ideally end, and it also
	   invades the column of pixels to the right of where it sould ideally end.
	   That's ok, though.  Imagine we place another unit rect at (1,0) in scene coordinates.  Its
	   lower left corner will be located in the middle of pixel_at(1,0), that is at image
	   coordinates (1.5,.5) -- exactly where the first rect's lower right corner is located!

	   The net effect is to shift the location of all rects by (.5,.5) in image coordinates.
	   The other effect is that a rect that is 1 image unit wide and 1 image unit high
	   partially occupies 2 pixels horizontally and 2 vertically, because half a pixel goes
	   unused at either end.
	   A rect that is w image units wide and h image units high occupies (w + 1) pixels horizontally
	   and (h + 1) units vertically.

	   Furthermore, in our ascii renderings, 2 vertical scene coordinates correspond to 1 pixel,
	   whereas 1 horizontal scene coordinate corresponds to 1 pixel.  So a rect that is 2 scene
	   coordinates high is one pixel high.  Unfortunately, that means that a rect that is 1 scene
	   coordinate high would be .5 pixels high, which is impossible.  In order to render correctly in ascii,
	   then, all scene coordinate heights must be a multiple of 2.  Consequently, only even-height
	   rect_nodes and grid-nodes are tested in this file.
	*/

	grid_node gn0a{0,0,{},{}};
	/* no partitions --> should render as an empty image */
	auto img0a = gn0a.render(r);
	assert(img0a->pixel_height() == 0);
	assert(img0a->pixel_width() == 0);

	grid_node gn0b{0,0,{0},{0}};
	/* should render as a point
		.
	*/
	auto img0b = gn0b.render(r);
	assert(img0b->pixel_height() == 1);
	assert(img0b->pixel_width() == 1);
	assert(img0b->pixel_at(0,0) == bdc::p);

	grid_node gn0c = gride_node_from_image_units(0,1,{0},{0,1});
	/* the two horizontal partitions each have 0 width
	   and therefore should not render at all.
	   gn0c should render as
	   ,
	   '
	   or, with box drawing characters
	   ╷
	   ╵
	*/
	auto img0c = gn0c.render(r);
	assert(img0c->pixel_width() == 1);
	assert(img0c->pixel_height() == 2);
	assert(img0c->pixel_at(0,0) == bdc::u);
	assert(img0c->pixel_at(0,1) == bdc::d);

	grid_node gn1 = gride_node_from_image_units(1,1,{0,1},{0,1});
	/* should render as
	++
	++

	or, with box-drawing characters
	┌┐
	└┘
	*/
	auto img1 = gn1.render(r);
	assert(img1->pixel_height() == 2);
	assert(img1->pixel_width() == 2);
	assert(img1->pixel_at(0,0) == bdc::ur);
	assert(img1->pixel_at(0,1) == bdc::dr);
	assert(img1->pixel_at(1,0) == bdc::ul);
	assert(img1->pixel_at(1,1) == bdc::dl);

	grid_node gn2 = gride_node_from_image_units(6,4,{0,2,5,6},{0,3});
	/* should render as

	, ,  ,,
    +-+--++
    | |  ||
	| |  ||
	+-+--++

	or, with box-drawing characters,

	╷ ╷  ╷╷
    ├─┼──┼┤
    │ │  ││
	│ │  ││
	└─┴──┴┘
	*/
	auto img2 = gn2.render(r);

	assert(img2->pixel_width() == 7);
	assert(img2->pixel_height() == 5);
	// row 0
	assert(img2->pixel_at(0,0) == bdc::ur);
	assert(img2->pixel_at(1,0) == bdc::h);
	assert(img2->pixel_at(2,0) == bdc::uh);
	assert(img2->pixel_at(3,0) == bdc::h);
	assert(img2->pixel_at(4,0) == bdc::h);
	assert(img2->pixel_at(5,0) == bdc::uh);
	assert(img2->pixel_at(6,0) == bdc::uh);

	// row 1
	assert(img2->pixel_at(0,1) == bdc::v);
	assert(img2->pixel_at(1,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(2,1) == bdc::v);
	assert(img2->pixel_at(3,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(4,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(5,1) == bdc::v);
	assert(img2->pixel_at(6,1) == bdc::v);

	// row 2 should be identical to row 1
	for (int x = 0; x < 7; ++x) {
		assert(img2->pixel_at(x,2) == img2->pixel_at(x,1));
	}

	// row 3
	assert(img2->pixel_at(0,3) == bdc::vr);
	assert(img2->pixel_at(1,3) == bdc::h);
	assert(img2->pixel_at(2,3) == bdc::vh);
	assert(img2->pixel_at(3,3) == bdc::h);
	assert(img2->pixel_at(4,3) == bdc::h);
	assert(img2->pixel_at(5,3) == bdc::vh);
	assert(img2->pixel_at(6,3) == bdc::vh);

	// row 4
	assert(img2->pixel_at(0,4) == bdc::d);
	assert(img2->pixel_at(1,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(2,4) == bdc::d);
	assert(img2->pixel_at(3,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(4,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(5,4) == bdc::d);
	assert(img2->pixel_at(6,4) == bdc::d);
}<commit_msg>fix gride_node to grid_node<commit_after>#include "renderer.h"
#include <cassert>
#include <iostream> // debug
#include "viewer.h"

using namespace liven;

grid_node grid_node_from_image_units(
		int image_width,
		int image_height,
		std::vector<int> v_image_partitions,
		std::vector<int> h_image_partitions)
{
	int width;
	int height;
	std::vector<int> v_partitions;
	std::vector<int> h_partitions;

	width = image_width * ascii_renderer::scene_x_coordinates_per_pixel;
	height = image_height * ascii_renderer::scene_y_coordinates_per_pixel;
	for (auto p : v_image_partitions) {v_partitions.push_back(p * ascii_renderer::scene_x_coordinates_per_pixel);}
	for (auto p : h_image_partitions) {h_partitions.push_back(p * ascii_renderer::scene_y_coordinates_per_pixel);}

	return grid_node(width, height, v_partitions, h_partitions);
}

int main() {
	ascii_renderer r{};
	/* In our ascii renderings, + represents the lower-left corner of a rect.
	   Say the rect's lower left corner is located at (0,0) in scene coordinates.
	   Also suppose this lower-left corner is drawn using pixel_at(0,0) in an image.
	   Therefore, (0,0) in scene coordinates is actually located at (.5,.5) in image coordinates.
	   If the rect is one pixel unit high, its top left corner will be drawn in the center
	   of the pixel_at(0,1), i.e at (.5,1.5) in image coordinates.
	   If the rect is one pixel unit wide, its lower right corner will be draw in the center
	   of the pixel_at(1,0), i.e. at (1.5,.5) in image coordinates.
	   The spaces between the pairs of image-coordinate points ((.5,0),(.5,1)) and ((.5,1.5),(.5,2))
	   goes unused (this is space above and below the rect).
	   In an ideal world, the bottom left corner of the rect would have image coordinates (0,0)
	   and its top left would have image coordinates (0,1), but this isn't possible with ascii.
	   Therefore the rect "invades" the row of pixels above where it should ideally end, and it also
	   invades the column of pixels to the right of where it sould ideally end.
	   That's ok, though.  Imagine we place another unit rect at (1,0) in scene coordinates.  Its
	   lower left corner will be located in the middle of pixel_at(1,0), that is at image
	   coordinates (1.5,.5) -- exactly where the first rect's lower right corner is located!

	   The net effect is to shift the location of all rects by (.5,.5) in image coordinates.
	   The other effect is that a rect that is 1 image unit wide and 1 image unit high
	   partially occupies 2 pixels horizontally and 2 vertically, because half a pixel goes
	   unused at either end.
	   A rect that is w image units wide and h image units high occupies (w + 1) pixels horizontally
	   and (h + 1) units vertically.

	   Furthermore, in our ascii renderings, 2 vertical scene coordinates correspond to 1 pixel,
	   whereas 1 horizontal scene coordinate corresponds to 1 pixel.  So a rect that is 2 scene
	   coordinates high is one pixel high.  Unfortunately, that means that a rect that is 1 scene
	   coordinate high would be .5 pixels high, which is impossible.  In order to render correctly in ascii,
	   then, all scene coordinate heights must be a multiple of 2.  Consequently, only even-height
	   rect_nodes and grid-nodes are tested in this file.
	*/

	grid_node gn0a{0,0,{},{}};
	/* no partitions --> should render as an empty image */
	auto img0a = gn0a.render(r);
	assert(img0a->pixel_height() == 0);
	assert(img0a->pixel_width() == 0);

	grid_node gn0b{0,0,{0},{0}};
	/* should render as a point
		.
	*/
	auto img0b = gn0b.render(r);
	assert(img0b->pixel_height() == 1);
	assert(img0b->pixel_width() == 1);
	assert(img0b->pixel_at(0,0) == bdc::p);

	grid_node gn0c = grid_node_from_image_units(0,1,{0},{0,1});
	/* the two horizontal partitions each have 0 width
	   and therefore should not render at all.
	   gn0c should render as
	   ,
	   '
	   or, with box drawing characters
	   ╷
	   ╵
	*/
	auto img0c = gn0c.render(r);
	assert(img0c->pixel_width() == 1);
	assert(img0c->pixel_height() == 2);
	assert(img0c->pixel_at(0,0) == bdc::u);
	assert(img0c->pixel_at(0,1) == bdc::d);

	grid_node gn1 = grid_node_from_image_units(1,1,{0,1},{0,1});
	/* should render as
	++
	++

	or, with box-drawing characters
	┌┐
	└┘
	*/
	auto img1 = gn1.render(r);
	assert(img1->pixel_height() == 2);
	assert(img1->pixel_width() == 2);
	assert(img1->pixel_at(0,0) == bdc::ur);
	assert(img1->pixel_at(0,1) == bdc::dr);
	assert(img1->pixel_at(1,0) == bdc::ul);
	assert(img1->pixel_at(1,1) == bdc::dl);

	grid_node gn2 = grid_node_from_image_units(6,4,{0,2,5,6},{0,3});
	/* should render as

	, ,  ,,
    +-+--++
    | |  ||
	| |  ||
	+-+--++

	or, with box-drawing characters,

	╷ ╷  ╷╷
    ├─┼──┼┤
    │ │  ││
	│ │  ││
	└─┴──┴┘
	*/
	auto img2 = gn2.render(r);

	assert(img2->pixel_width() == 7);
	assert(img2->pixel_height() == 5);
	// row 0
	assert(img2->pixel_at(0,0) == bdc::ur);
	assert(img2->pixel_at(1,0) == bdc::h);
	assert(img2->pixel_at(2,0) == bdc::uh);
	assert(img2->pixel_at(3,0) == bdc::h);
	assert(img2->pixel_at(4,0) == bdc::h);
	assert(img2->pixel_at(5,0) == bdc::uh);
	assert(img2->pixel_at(6,0) == bdc::uh);

	// row 1
	assert(img2->pixel_at(0,1) == bdc::v);
	assert(img2->pixel_at(1,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(2,1) == bdc::v);
	assert(img2->pixel_at(3,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(4,1) == ascii_image::default_pixel);
	assert(img2->pixel_at(5,1) == bdc::v);
	assert(img2->pixel_at(6,1) == bdc::v);

	// row 2 should be identical to row 1
	for (int x = 0; x < 7; ++x) {
		assert(img2->pixel_at(x,2) == img2->pixel_at(x,1));
	}

	// row 3
	assert(img2->pixel_at(0,3) == bdc::vr);
	assert(img2->pixel_at(1,3) == bdc::h);
	assert(img2->pixel_at(2,3) == bdc::vh);
	assert(img2->pixel_at(3,3) == bdc::h);
	assert(img2->pixel_at(4,3) == bdc::h);
	assert(img2->pixel_at(5,3) == bdc::vh);
	assert(img2->pixel_at(6,3) == bdc::vh);

	// row 4
	assert(img2->pixel_at(0,4) == bdc::d);
	assert(img2->pixel_at(1,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(2,4) == bdc::d);
	assert(img2->pixel_at(3,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(4,4) == ascii_image::default_pixel);
	assert(img2->pixel_at(5,4) == bdc::d);
	assert(img2->pixel_at(6,4) == bdc::d);
}<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkNavigationDataRecorder.h>
#include <mitkNavigationData.h>
#include <mitkStandardFileLocations.h>
#include <mitkTestingMacros.h>

#include <Poco/Path.h>
#include <Poco/File.h>

#include <iostream>
#include <sstream>

class mitkNavigationDataRecorderTestClass
  {
  public:

  static void TestInstantiation()
    {
    // let's create an object of our class
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();
    MITK_TEST_CONDITION( recorder.IsNotNull(), "Testing instatiation of NavigationDataRecorder");
    }

  static void TestRecordingWithGivenStream()
    {
    std::string tmp = "";
  std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc );
  stream->setf( std::ios::fixed, std::ios::floatfield );

  // let's create an object of our class
  mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

  MITK_TEST_CONDITION(recorder->GetInputs().size() == 0, "testing initial number of inputs");
  MITK_TEST_CONDITION(recorder->GetOutputs().size() == 0, "testing initial number of outputs");

  mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
  recorder->AddNavigationData( naviData );
  //recorder->SetFileName("e:/test");
  //recorder->SetRecordingMode( mitk::NavigationDataRecorder::NormalFile );
  recorder->StartRecording( stream );
  for ( unsigned int i=0; i<5; i++ )
  {
    mitk::Point3D pnt;
    pnt[0] = i + 1;
    pnt[1] = i + 1/2;
    pnt[2] = i +1*3;

    naviData->SetPosition(pnt);
    //naviData->Modified();
    recorder->Update();

    //Sleep(80 + i*10);

  }

  recorder->StopRecording();

  std::string str = stream->str();
  int pos = str.find( "ToolCount=" );
  std::string sub = stream->str().substr(pos+11, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if number of inputs is correct by stringstream");

  pos = str.find( "X=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if the X coordinate is correct");

  pos = str.find( "Y=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("0") == 0, "check if the Y coordinate is correct");

  pos = str.find( "Z=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("3") == 0, "check if the Z coordinate is correct");

  recorder->SetFileName("blablabla");
  const char* string = recorder->GetFileName();
  MITK_TEST_CONDITION( strcmp(string, "blablabla") == 0, "check if set- and getName-methods work");

    }

  static void TestRecordingOnHarddiscXML()
    {
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

    //create filename
    std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml";

    recorder->SetFileName(filename.c_str());

    mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
    recorder->AddNavigationData( naviData );
    recorder->StartRecording();

    for ( unsigned int i=0; i<5; i++ )
     {
     mitk::Point3D pnt;
     pnt[0] = i + 1;
     pnt[1] = i + 1/2;
     pnt[2] = i +1*3;
     naviData->SetPosition(pnt);
     recorder->Update();
     }

    recorder->StopRecording();

    std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    Poco::File myFile(prooffilename);
    MITK_TEST_CONDITION(myFile.exists(),"Testing recording on harddisc (does file exist?).");
    }

  static void CleanUp()
    {
    std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    MITK_INFO << prooffilename;
    try
    {

    Poco::File myFile(prooffilename);
    if (myFile.exists()) myFile.remove();
    }
    catch(std::exception e)
    {
      MITK_INFO << "Exception:" << e.what();
    }
    }

  };

/**Documentation
 *  test for the class "NavigationDataRecorder".
 */
int mitkNavigationDataRecorderTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataRecorder");

  mitkNavigationDataRecorderTestClass::TestInstantiation();
  mitkNavigationDataRecorderTestClass::TestRecordingWithGivenStream();
  mitkNavigationDataRecorderTestClass::TestRecordingOnHarddiscXML();
  Sleep(1000);
  mitkNavigationDataRecorderTestClass::CleanUp();

  // always end with this!
  MITK_TEST_END();
}
<commit_msg>finished test improvement<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date: 2009-05-13 14:52:01 +0200 (Mi, 13. Mai 2009) $
Version:   $Revision: 17230 $

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include <mitkNavigationDataRecorder.h>
#include <mitkNavigationDataPlayer.h>
#include <mitkNavigationData.h>
#include <mitkStandardFileLocations.h>
#include <mitkTestingMacros.h>

#include <Poco/Path.h>
#include <Poco/File.h>

#include <iostream>
#include <sstream>

class mitkNavigationDataRecorderTestClass
  {
  public:

  static void TestInstantiation()
    {
    // let's create an object of our class
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();
    MITK_TEST_CONDITION( recorder.IsNotNull(), "Testing instatiation of NavigationDataRecorder");
    }

  static void TestRecordingWithGivenStream()
    {
    std::string tmp = "";
  std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc );
  stream->setf( std::ios::fixed, std::ios::floatfield );

  // let's create an object of our class
  mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

  MITK_TEST_CONDITION(recorder->GetInputs().size() == 0, "testing initial number of inputs");
  MITK_TEST_CONDITION(recorder->GetOutputs().size() == 0, "testing initial number of outputs");

  mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
  recorder->AddNavigationData( naviData );
  //recorder->SetFileName("e:/test");
  //recorder->SetRecordingMode( mitk::NavigationDataRecorder::NormalFile );
  recorder->StartRecording( stream );
  for ( unsigned int i=0; i<5; i++ )
  {
    mitk::Point3D pnt;
    pnt[0] = i + 1;
    pnt[1] = i + 1/2;
    pnt[2] = i +1*3;

    naviData->SetPosition(pnt);
    //naviData->Modified();
    recorder->Update();

    //Sleep(80 + i*10);

  }

  recorder->StopRecording();

  std::string str = stream->str();
  int pos = str.find( "ToolCount=" );
  std::string sub = stream->str().substr(pos+11, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if number of inputs is correct by stringstream");

  pos = str.find( "X=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("1") == 0, "check if the X coordinate is correct");

  pos = str.find( "Y=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("0") == 0, "check if the Y coordinate is correct");

  pos = str.find( "Z=" );
  sub = stream->str().substr(pos+3, 1);
  MITK_TEST_CONDITION( sub.compare("3") == 0, "check if the Z coordinate is correct");

  recorder->SetFileName("blablabla");
  const char* string = recorder->GetFileName();
  MITK_TEST_CONDITION( strcmp(string, "blablabla") == 0, "check if set- and getName-methods work");

    }

  static void TestRecordingOnHarddiscXML()
    {
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

    //create filename
    std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml";

    recorder->SetFileName(filename.c_str());

    mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
    recorder->AddNavigationData( naviData );
    recorder->StartRecording();

    for ( unsigned int i=0; i<5; i++ )
     {
     mitk::Point3D pnt;
     pnt[0] = i + 1;
     pnt[1] = i + 1/2;
     pnt[2] = i +1*3;
     naviData->SetPosition(pnt);
     recorder->Update();
     }

    recorder->StopRecording();

    std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    Poco::File myFile(prooffilename);
    MITK_TEST_CONDITION(myFile.exists(),"Testing XML recording on harddisc (does file exist?).");
    }

  static void TestRecordingOnHarddiscXMLZIP()
    {
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

    //create filename
    std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertestzip.xml";

    recorder->SetFileName(filename.c_str());
    recorder->SetRecordingMode(mitk::NavigationDataRecorder::ZipFile);

    MITK_TEST_CONDITION(recorder->GetRecordingMode()==mitk::NavigationDataRecorder::ZipFile,"Testing setter of recording mode.");

    /* Zip file not supported yet, activate later
    mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
    recorder->AddNavigationData( naviData );
    recorder->StartRecording();

    for ( unsigned int i=0; i<5; i++ )
     {
     mitk::Point3D pnt;
     pnt[0] = i + 1;
     pnt[1] = i + 1/2;
     pnt[2] = i +1*3;
     naviData->SetPosition(pnt);
     recorder->Update();
     }

    recorder->StopRecording();

    std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    Poco::File myFile(prooffilename);
    MITK_TEST_CONDITION(myFile.exists(),"Testing XML Zip recording on harddisc (does file exist?).");
    */
    }

  static void TestRecordingOnHarddiscCSV()
    {
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

    //create filename
    std::string filename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest.xml";

    recorder->SetFileName(filename.c_str());
    recorder->SetOutputFormat(mitk::NavigationDataRecorder::csv);

    mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
    recorder->AddNavigationData( naviData );
    recorder->StartRecording();

    for ( unsigned int i=0; i<5; i++ )
     {
     mitk::Point3D pnt;
     pnt[0] = i + 1;
     pnt[1] = i + 1/2;
     pnt[2] = i +1*3;
     naviData->SetPosition(pnt);
     recorder->Update();
     }

    recorder->StopRecording();

    std::string prooffilename = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.csv";
    Poco::File myFile(prooffilename);
    MITK_TEST_CONDITION(myFile.exists(),"Testing CSV recording on harddisc (does file exist?).");
    }

  static void TestLoadingRecordedXMLFile()
    {
    mitk::NavigationDataPlayer::Pointer myPlayer = mitk::NavigationDataPlayer::New();
    std::string filenameXML = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    myPlayer->SetFileName(filenameXML.c_str());
    myPlayer->StartPlaying();

    //only testing first position at the moment
    myPlayer->Update();
    mitk::NavigationData::Pointer thisData = myPlayer->GetOutput();
    mitk::Point3D reference_pnt;
    reference_pnt[0] = 1;
    reference_pnt[1] = 1/2;
    reference_pnt[2] = 1*3;

    myPlayer->StopPlaying();

    MITK_TEST_CONDITION((thisData->GetPosition() == reference_pnt),"Testing load data from xml file.");
    }

  static void TestRecordingInvalidData()
    {
    std::string tmp = "";
    std::ostringstream* stream = new std::ostringstream( std::ostringstream::trunc );
    stream->setf( std::ios::fixed, std::ios::floatfield );

    // let's create an object of our class
    mitk::NavigationDataRecorder::Pointer recorder = mitk::NavigationDataRecorder::New();

    mitk::NavigationData::Pointer naviData = mitk::NavigationData::New();
    recorder->AddNavigationData( naviData );
    naviData->SetDataValid(false);
    //recorder->SetFileName("e:/test");
    //recorder->SetRecordingMode( mitk::NavigationDataRecorder::NormalFile );
    recorder->StartRecording( stream );
    for ( unsigned int i=0; i<5; i++ )
    {
      mitk::Point3D pnt;
      pnt[0] = i + 1;
      pnt[1] = i + 1/2;
      pnt[2] = i +1*3;

      naviData->SetPosition(pnt);
      //naviData->Modified();
      recorder->Update();

      //Sleep(80 + i*10);

    }

    recorder->StopRecording();

    bool record_success = true;

    std::string str = stream->str();
    int pos = str.find( "ToolCount=" );
    std::string sub = stream->str().substr(pos+11, 1);
    if (sub.compare("1") != 0) {record_success = false;}

    pos = str.find( "X=" );
    sub = stream->str().substr(pos+3, 1);
    if (sub.compare("1") != 0) {record_success = false;}

    pos = str.find( "Y=" );
    sub = stream->str().substr(pos+3, 1);
    if (sub.compare("0") != 0) {record_success = false;}

    pos = str.find( "Z=" );
    sub = stream->str().substr(pos+3, 1);
    if (sub.compare("3") != 0) {record_success = false;}

    MITK_TEST_CONDITION(record_success,"Testing recording of invalid data.");

    }

  static void CleanUp()
    {
    std::string filenameXML = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.xml";
    std::string filenameCSV = mitk::StandardFileLocations::GetInstance()->GetOptionDirectory()+Poco::Path::separator()+"Recordertest-0.csv";
    Poco::File myFileXML(filenameXML);
    if (myFileXML.exists())
      {myFileXML.remove();}
    Poco::File myFileCSV(filenameCSV);
    if (myFileCSV.exists())
      {myFileCSV.remove();}

    }

  };

/**Documentation
 *  test for the class "NavigationDataRecorder".
 */
int mitkNavigationDataRecorderTest(int /* argc */, char* /*argv*/[])
{
  MITK_TEST_BEGIN("NavigationDataRecorder");

  mitkNavigationDataRecorderTestClass::TestInstantiation();
  mitkNavigationDataRecorderTestClass::TestRecordingWithGivenStream();
  mitkNavigationDataRecorderTestClass::TestRecordingOnHarddiscXML();
  mitkNavigationDataRecorderTestClass::TestRecordingOnHarddiscXMLZIP();
  mitkNavigationDataRecorderTestClass::TestRecordingOnHarddiscCSV();
  mitkNavigationDataRecorderTestClass::TestRecordingInvalidData();
  mitkNavigationDataRecorderTestClass::TestLoadingRecordedXMLFile();

  mitkNavigationDataRecorderTestClass::CleanUp();

  // always end with this!
  MITK_TEST_END();
}
<|endoftext|>


<commit_before>//===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <array>
#include <string>

#include "Assembler.h"
#include "BenchmarkRunner.h"
#include "MCInstrDescView.h"
#include "PerfHelper.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"

namespace llvm {
namespace exegesis {

BenchmarkFailure::BenchmarkFailure(const llvm::Twine &S)
    : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}

BenchmarkRunner::BenchmarkRunner(const LLVMState &State,
                                 InstructionBenchmark::ModeE Mode)
    : State(State), Mode(Mode), Scratch(llvm::make_unique<ScratchSpace>()) {}

BenchmarkRunner::~BenchmarkRunner() = default;

// Repeat the snippet until there are at least MinInstructions in the resulting
// code.
static std::vector<llvm::MCInst>
GenerateInstructions(const BenchmarkCode &BC, const size_t MinInstructions) {
  if (BC.Instructions.empty())
    return {};
  std::vector<llvm::MCInst> Code = BC.Instructions;
  for (int I = 0; Code.size() < MinInstructions; ++I)
    Code.push_back(BC.Instructions[I % BC.Instructions.size()]);
  return Code;
}

namespace {
class FunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
public:
  FunctionExecutorImpl(const LLVMState &State,
                       llvm::object::OwningBinary<llvm::object::ObjectFile> Obj,
                       BenchmarkRunner::ScratchSpace *Scratch)
      : Function(State.createTargetMachine(), std::move(Obj)),
        Scratch(Scratch) {}

private:
  llvm::Expected<int64_t> runAndMeasure(const char *Counters) const override {
    // We sum counts when there are several counters for a single ProcRes
    // (e.g. P23 on SandyBridge).
    int64_t CounterValue = 0;
    llvm::SmallVector<llvm::StringRef, 2> CounterNames;
    llvm::StringRef(Counters).split(CounterNames, ',');
    char *const ScratchPtr = Scratch->ptr();
    for (const auto &CounterName : CounterNames) {
      pfm::PerfEvent PerfEvent(CounterName);
      if (!PerfEvent.valid())
        llvm::report_fatal_error(
            llvm::Twine("invalid perf event ").concat(Counters));
      pfm::Counter Counter(PerfEvent);
      Scratch->clear();
      {
        llvm::CrashRecoveryContext CRC;
        llvm::CrashRecoveryContext::Enable();
        const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
          Counter.start();
          Function(ScratchPtr);
          Counter.stop();
        });
        llvm::CrashRecoveryContext::Disable();
        // FIXME: Better diagnosis.
        if (Crashed)
          return llvm::make_error<BenchmarkFailure>(
              "snippet crashed while running");
      }
      CounterValue += Counter.read();
    }
    return CounterValue;
  }

  const ExecutableFunction Function;
  BenchmarkRunner::ScratchSpace *const Scratch;
};
} // namespace

InstructionBenchmark
BenchmarkRunner::runConfiguration(const BenchmarkCode &BC,
                                  unsigned NumRepetitions) const {
  InstructionBenchmark InstrBenchmark;
  InstrBenchmark.Mode = Mode;
  InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU();
  InstrBenchmark.LLVMTriple =
      State.getTargetMachine().getTargetTriple().normalize();
  InstrBenchmark.NumRepetitions = NumRepetitions;
  InstrBenchmark.Info = BC.Info;

  const std::vector<llvm::MCInst> &Instructions = BC.Instructions;

  InstrBenchmark.Key.Instructions = Instructions;
  InstrBenchmark.Key.RegisterInitialValues = BC.RegisterInitialValues;

  // Assemble at least kMinInstructionsForSnippet instructions by repeating the
  // snippet for debug/analysis. This is so that the user clearly understands
  // that the inside instructions are repeated.
  constexpr const int kMinInstructionsForSnippet = 16;
  {
    auto ObjectFilePath = writeObjectFile(
        BC, GenerateInstructions(BC, kMinInstructionsForSnippet));
    if (llvm::Error E = ObjectFilePath.takeError()) {
      InstrBenchmark.Error = llvm::toString(std::move(E));
      return InstrBenchmark;
    }
    const ExecutableFunction EF(State.createTargetMachine(),
                                getObjectFromFile(*ObjectFilePath));
    const auto FnBytes = EF.getFunctionBytes();
    InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
  }

  // Assemble NumRepetitions instructions repetitions of the snippet for
  // measurements.
  auto ObjectFilePath = writeObjectFile(
      BC, GenerateInstructions(BC, InstrBenchmark.NumRepetitions));
  if (llvm::Error E = ObjectFilePath.takeError()) {
    InstrBenchmark.Error = llvm::toString(std::move(E));
    return InstrBenchmark;
  }
  llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
               << *ObjectFilePath << "\n";
  const FunctionExecutorImpl Executor(State, getObjectFromFile(*ObjectFilePath),
                                      Scratch.get());
  auto Measurements = runMeasurements(Executor);
  if (llvm::Error E = Measurements.takeError()) {
    InstrBenchmark.Error = llvm::toString(std::move(E));
    return InstrBenchmark;
  }
  InstrBenchmark.Measurements = std::move(*Measurements);
  assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
  for (BenchmarkMeasure &BM : InstrBenchmark.Measurements) {
    // Scale the measurements by instruction.
    BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
    // Scale the measurements by snippet.
    BM.PerSnippetValue *= static_cast<double>(BC.Instructions.size()) /
                          InstrBenchmark.NumRepetitions;
  }

  return InstrBenchmark;
}

llvm::Expected<std::string>
BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
                                 llvm::ArrayRef<llvm::MCInst> Code) const {
  int ResultFD = 0;
  llvm::SmallString<256> ResultPath;
  if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
          "snippet", "o", ResultFD, ResultPath)))
    return std::move(E);
  llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
  assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
                   BC.LiveIns, BC.RegisterInitialValues, Code, OFS);
  return ResultPath.str();
}

BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}

} // namespace exegesis
} // namespace llvm
<commit_msg>[llvm-exegesis] Fix name lookup ambiguity in MSVC after 344922<commit_after>//===-- BenchmarkRunner.cpp -------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <array>
#include <string>

#include "Assembler.h"
#include "BenchmarkRunner.h"
#include "MCInstrDescView.h"
#include "PerfHelper.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Program.h"

namespace llvm {
namespace exegesis {

BenchmarkFailure::BenchmarkFailure(const llvm::Twine &S)
    : llvm::StringError(S, llvm::inconvertibleErrorCode()) {}

BenchmarkRunner::BenchmarkRunner(const LLVMState &State,
                                 InstructionBenchmark::ModeE Mode)
    : State(State), Mode(Mode), Scratch(llvm::make_unique<ScratchSpace>()) {}

BenchmarkRunner::~BenchmarkRunner() = default;

// Repeat the snippet until there are at least MinInstructions in the resulting
// code.
static std::vector<llvm::MCInst>
GenerateInstructions(const BenchmarkCode &BC, const size_t MinInstructions) {
  if (BC.Instructions.empty())
    return {};
  std::vector<llvm::MCInst> Code = BC.Instructions;
  for (int I = 0; Code.size() < MinInstructions; ++I)
    Code.push_back(BC.Instructions[I % BC.Instructions.size()]);
  return Code;
}

namespace {
class FunctionExecutorImpl : public BenchmarkRunner::FunctionExecutor {
public:
  FunctionExecutorImpl(const LLVMState &State,
                       llvm::object::OwningBinary<llvm::object::ObjectFile> Obj,
                       BenchmarkRunner::ScratchSpace *Scratch)
      : Function(State.createTargetMachine(), std::move(Obj)),
        Scratch(Scratch) {}

private:
  llvm::Expected<int64_t> runAndMeasure(const char *Counters) const override {
    // We sum counts when there are several counters for a single ProcRes
    // (e.g. P23 on SandyBridge).
    int64_t CounterValue = 0;
    llvm::SmallVector<llvm::StringRef, 2> CounterNames;
    llvm::StringRef(Counters).split(CounterNames, ',');
    char *const ScratchPtr = Scratch->ptr();
    for (const auto &CounterName : CounterNames) {
      pfm::PerfEvent PerfEvent(CounterName);
      if (!PerfEvent.valid())
        llvm::report_fatal_error(
            llvm::Twine("invalid perf event ").concat(Counters));
      pfm::Counter Counter(PerfEvent);
      Scratch->clear();
      {
        llvm::CrashRecoveryContext CRC;
        llvm::CrashRecoveryContext::Enable();
        const bool Crashed = !CRC.RunSafely([this, &Counter, ScratchPtr]() {
          Counter.start();
          this->Function(ScratchPtr);
          Counter.stop();
        });
        llvm::CrashRecoveryContext::Disable();
        // FIXME: Better diagnosis.
        if (Crashed)
          return llvm::make_error<BenchmarkFailure>(
              "snippet crashed while running");
      }
      CounterValue += Counter.read();
    }
    return CounterValue;
  }

  const ExecutableFunction Function;
  BenchmarkRunner::ScratchSpace *const Scratch;
};
} // namespace

InstructionBenchmark
BenchmarkRunner::runConfiguration(const BenchmarkCode &BC,
                                  unsigned NumRepetitions) const {
  InstructionBenchmark InstrBenchmark;
  InstrBenchmark.Mode = Mode;
  InstrBenchmark.CpuName = State.getTargetMachine().getTargetCPU();
  InstrBenchmark.LLVMTriple =
      State.getTargetMachine().getTargetTriple().normalize();
  InstrBenchmark.NumRepetitions = NumRepetitions;
  InstrBenchmark.Info = BC.Info;

  const std::vector<llvm::MCInst> &Instructions = BC.Instructions;

  InstrBenchmark.Key.Instructions = Instructions;
  InstrBenchmark.Key.RegisterInitialValues = BC.RegisterInitialValues;

  // Assemble at least kMinInstructionsForSnippet instructions by repeating the
  // snippet for debug/analysis. This is so that the user clearly understands
  // that the inside instructions are repeated.
  constexpr const int kMinInstructionsForSnippet = 16;
  {
    auto ObjectFilePath = writeObjectFile(
        BC, GenerateInstructions(BC, kMinInstructionsForSnippet));
    if (llvm::Error E = ObjectFilePath.takeError()) {
      InstrBenchmark.Error = llvm::toString(std::move(E));
      return InstrBenchmark;
    }
    const ExecutableFunction EF(State.createTargetMachine(),
                                getObjectFromFile(*ObjectFilePath));
    const auto FnBytes = EF.getFunctionBytes();
    InstrBenchmark.AssembledSnippet.assign(FnBytes.begin(), FnBytes.end());
  }

  // Assemble NumRepetitions instructions repetitions of the snippet for
  // measurements.
  auto ObjectFilePath = writeObjectFile(
      BC, GenerateInstructions(BC, InstrBenchmark.NumRepetitions));
  if (llvm::Error E = ObjectFilePath.takeError()) {
    InstrBenchmark.Error = llvm::toString(std::move(E));
    return InstrBenchmark;
  }
  llvm::outs() << "Check generated assembly with: /usr/bin/objdump -d "
               << *ObjectFilePath << "\n";
  const FunctionExecutorImpl Executor(State, getObjectFromFile(*ObjectFilePath),
                                      Scratch.get());
  auto Measurements = runMeasurements(Executor);
  if (llvm::Error E = Measurements.takeError()) {
    InstrBenchmark.Error = llvm::toString(std::move(E));
    return InstrBenchmark;
  }
  InstrBenchmark.Measurements = std::move(*Measurements);
  assert(InstrBenchmark.NumRepetitions > 0 && "invalid NumRepetitions");
  for (BenchmarkMeasure &BM : InstrBenchmark.Measurements) {
    // Scale the measurements by instruction.
    BM.PerInstructionValue /= InstrBenchmark.NumRepetitions;
    // Scale the measurements by snippet.
    BM.PerSnippetValue *= static_cast<double>(BC.Instructions.size()) /
                          InstrBenchmark.NumRepetitions;
  }

  return InstrBenchmark;
}

llvm::Expected<std::string>
BenchmarkRunner::writeObjectFile(const BenchmarkCode &BC,
                                 llvm::ArrayRef<llvm::MCInst> Code) const {
  int ResultFD = 0;
  llvm::SmallString<256> ResultPath;
  if (llvm::Error E = llvm::errorCodeToError(llvm::sys::fs::createTemporaryFile(
          "snippet", "o", ResultFD, ResultPath)))
    return std::move(E);
  llvm::raw_fd_ostream OFS(ResultFD, true /*ShouldClose*/);
  assembleToStream(State.getExegesisTarget(), State.createTargetMachine(),
                   BC.LiveIns, BC.RegisterInitialValues, Code, OFS);
  return ResultPath.str();
}

BenchmarkRunner::FunctionExecutor::~FunctionExecutor() {}

} // namespace exegesis
} // namespace llvm
<|endoftext|>


<commit_before>#include "NFCUUIDModule.h"
#include "NFComm/NFPluginModule/NFIKernelModule.h"
#include "NFComm/NFPluginModule/NFIPluginManager.h"

namespace UUIDModule
{

#ifndef _MSC_VER
#include <sys/time.h>
#include <unistd.h>
#define EPOCHFILETIME 11644473600000000ULL
#else
#include <windows.h>
#include <time.h>
#define EPOCHFILETIME 11644473600000000Ui64
#endif

uint64_t get_time()
{
#ifndef _MSC_VER
    struct timeval tv;
    gettimeofday(&tv, NULL);
    int time = tv.tv_usec;
    time /= 1000;
    time += (tv.tv_sec * 1000);
    return time;
#else
    FILETIME filetime;
    uint64_t time = 0;
    GetSystemTimeAsFileTime(&filetime);

    time |= filetime.dwHighDateTime;
    time <<= 32;
    time |= filetime.dwLowDateTime;

    time /= 10;
    time -= EPOCHFILETIME;
    return time / 1000;
#endif
}

class UUID
{
public:
    UUID() : epoch_(0), time_(0), machine_(0), sequence_(0)
    {
    }

    ~UUID() {}

    void set_epoch(uint64_t epoch)
    {
        epoch_ = epoch;
    }

    void set_machine(int32_t machine)
    {
        machine_ = machine;
    }

    int64_t generate()
    {
        int64_t value = 0;
        uint64_t time = UUIDModule::get_time() - epoch_;

        // 保留后48位时间
        value = time << 16;

        // 最后16位是sequenceID
        value |= sequence_++ & 0xFFFF;

        if (sequence_ == 0xFFFF)
        {
            sequence_ = 0;
        }

        return value;
    }
private:
    uint64_t epoch_;
    uint64_t time_;
    int32_t machine_;
    int32_t sequence_;
};
}

NFCUUIDModule::NFCUUIDModule(NFIPluginManager* p)
{
    mnIdent = 0;
	m_pKernelModule = NULL;
    pPluginManager = p;
}

bool NFCUUIDModule::Init()
{
    m_pUUID = NF_NEW UUIDModule::UUID;
    assert(NULL != m_pUUID);

    return true;
}

bool NFCUUIDModule::Shut()
{
    return true;
}

bool NFCUUIDModule::BeforeShut()
{
    if (NULL != m_pUUID)
    {
        delete m_pUUID;
        m_pUUID = NULL;
    }
    return true;
}

bool NFCUUIDModule::AfterInit()
{
    m_pKernelModule = dynamic_cast<NFIKernelModule*>(pPluginManager->FindModule("NFCKernelModule"));
    assert(NULL != m_pKernelModule);

    // 初始化uuid
    NFINT32 nID = GetIdentID();
    m_pUUID->set_machine(nID);
    m_pUUID->set_epoch(uint64_t(1367505795100));

    return true;
}

bool NFCUUIDModule::Execute(const float fLasFrametime, const float fStartedTime)
{
    return true;
}

NFIDENTID NFCUUIDModule::CreateGUID()
{
	NFIDENTID xID;
	xID.nSvrID = GetIdentID();
	xID.nData64 = m_pUUID->generate();

    return xID;
}

NFINT64 NFCUUIDModule::GetIdentID()
{
    return mnIdent;
}

void NFCUUIDModule::SetIdentID( NFINT64 nID )
{
    mnIdent = nID;
}
<commit_msg>modify uuid generate<commit_after>#include "NFCUUIDModule.h"
#include "NFComm/NFPluginModule/NFIKernelModule.h"
#include "NFComm/NFPluginModule/NFIPluginManager.h"

namespace UUIDModule
{

#ifndef _MSC_VER
#include <sys/time.h>
#include <unistd.h>
#define EPOCHFILETIME 11644473600000000ULL
#else
#include <windows.h>
#include <time.h>
#define EPOCHFILETIME 11644473600000000Ui64
#endif

uint64_t get_time()
{
#ifndef _MSC_VER
    struct timeval tv;
    gettimeofday(&tv, NULL);
    int time = tv.tv_usec;
    time /= 1000;
    time += (tv.tv_sec * 1000);
    return time;
#else
    FILETIME filetime;
    uint64_t time = 0;
    GetSystemTimeAsFileTime(&filetime);

    time |= filetime.dwHighDateTime;
    time <<= 32;
    time |= filetime.dwLowDateTime;

    time /= 10;
    time -= EPOCHFILETIME;
    return time / 1000;
#endif
}

class UUID
{
public:
    UUID() : epoch_(0), time_(0), machine_(0), sequence_(0)
    {
    }

    ~UUID() {}

    void set_epoch(uint64_t epoch)
    {
        epoch_ = epoch;
    }

    void set_machine(int32_t machine)
    {
        machine_ = machine;
    }

    int64_t generate()
    {
        int64_t value = 0;
        uint64_t time = UUIDModule::get_time() - epoch_;

        // 保留后48位时间
        value = time << 16;

        // 最后16位是sequenceID
        //value |= sequence_++ & 0xFFFF;

        if (sequence_ == 0x7FFF)
        {
            sequence_ = 0;
        }

        return value + sequence_;
    }
private:
    uint64_t epoch_;
    uint64_t time_;
    int32_t machine_;
    int32_t sequence_;
};
}

NFCUUIDModule::NFCUUIDModule(NFIPluginManager* p)
{
    mnIdent = 0;
	m_pKernelModule = NULL;
    pPluginManager = p;
}

bool NFCUUIDModule::Init()
{
    m_pUUID = NF_NEW UUIDModule::UUID;
    assert(NULL != m_pUUID);

    return true;
}

bool NFCUUIDModule::Shut()
{
    return true;
}

bool NFCUUIDModule::BeforeShut()
{
    if (NULL != m_pUUID)
    {
        delete m_pUUID;
        m_pUUID = NULL;
    }
    return true;
}

bool NFCUUIDModule::AfterInit()
{
    m_pKernelModule = dynamic_cast<NFIKernelModule*>(pPluginManager->FindModule("NFCKernelModule"));
    assert(NULL != m_pKernelModule);

    // 初始化uuid
    NFINT32 nID = GetIdentID();
    m_pUUID->set_machine(nID);
    m_pUUID->set_epoch(uint64_t(1367505795100));

    return true;
}

bool NFCUUIDModule::Execute(const float fLasFrametime, const float fStartedTime)
{
    return true;
}

NFIDENTID NFCUUIDModule::CreateGUID()
{
	NFIDENTID xID;
	xID.nSvrID = GetIdentID();
	xID.nData64 = m_pUUID->generate();

    return xID;
}

NFINT64 NFCUUIDModule::GetIdentID()
{
    return mnIdent;
}

void NFCUUIDModule::SetIdentID( NFINT64 nID )
{
    mnIdent = nID;
}
<|endoftext|>