<commit_before>/******************************************************************************\
* File:          stc.cpp
* Purpose:       Implementation of class wxExSTC
* Author:        Anton van Wezenbeek
* RCS-ID:        $Id: stc.cpp 2228 2009-11-21 09:00:23Z antonvw $
*
* Copyright (c) 1998-2009 Anton van Wezenbeek
* All rights are reserved. Reproduction in whole or part is prohibited
* without the written consent of the copyright owner.
\******************************************************************************/

#include <wx/extension/stc.h>

#if wxUSE_GUI

void wxExSTC::OnKeyVi(wxKeyEvent& event)
{
  if(
    !event.ShiftDown() &&
    !event.ControlDown())
  {
    m_viCommand += event.GetUnicodeKey();
  }

  int repeat = atoi(m_viCommand.c_str());

  if (repeat == 0)
  {
    repeat++;
  }

  bool handled_command = true;

  if (m_viCommand.EndsWith("CW"))
  {
    for (int i = 0; i < repeat; i++) WordRightExtend();
    m_viInsertMode = true;
  }
  else if (m_viCommand.EndsWith("DD"))
  {
    for (int i = 0; i < repeat; i++) LineDelete();
  }
  else if (m_viCommand.EndsWith("DW"))
  {
    for (int i = 0; i < repeat; i++) DelWordRight();
  }
  else if (m_viCommand.EndsWith("YY"))
  {
    const int line = LineFromPosition(GetCurrentPos());
    const int start = PositionFromLine(line);
    const int end = GetLineEndPosition(line + repeat);
    CopyRange(start, end);
  }
  else
  {
    if (!event.ShiftDown() && !event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case '0':
          if (m_viCommand.length() == 1)
          {
            Home();
          }
          else
          {
            handled_command = false;
          }
          break;
        case 'A': m_viInsertMode = true; CharRight(); break;
        case 'B': for (int i = 0; i < repeat; i++) WordLeft(); break;
        case 'G': DocumentStart(); break;
        case 'H': for (int i = 0; i < repeat; i++) CharLeft(); break;
        case 'I': m_viInsertMode = true; break;
        case 'J': for (int i = 0; i < repeat; i++) LineDown(); break;
        case 'K': for (int i = 0; i < repeat; i++) LineUp(); break;
        case 'L': for (int i = 0; i < repeat; i++) CharRight(); break;
        case 'N':
          for (int i = 0; i < repeat; i++)
            FindNext(wxExFindReplaceData::Get()->GetFindString());
        case 'P':
          {
          const int pos = GetCurrentPos();
          LineDown();
          Home();
          Paste();
          GotoPos(pos);
          }
          break;
        case 'W': for (int i = 0; i < repeat; i++) WordRight(); break;
        case 'U': Undo(); break;
        case 'X': DeleteBack(); break;

        case '/':
          {
          wxASSERT(wxTheApp != NULL);
          wxWindow* window = wxTheApp->GetTopWindow();
          wxASSERT(window != NULL);
          wxFrame* frame = wxDynamicCast(window, wxFrame);
          wxASSERT(frame != NULL);
          wxPostEvent(frame,
            wxCommandEvent(wxEVT_COMMAND_MENU_SELECTED, wxID_FIND));
          }
          break;

        // Repeat last text changing command.
        case '.':
          break;

        case '[':
        case ']':
          {
          const int brace_match = BraceMatch(GetCurrentPos());
          if (brace_match != wxSTC_INVALID_POSITION)
          {
            GotoPos(brace_match);
          }
          }
          break;

        default:
          handled_command = false;
      }
    }
    else if (event.ShiftDown() && !event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case 'A': m_viInsertMode = true; LineEnd(); break;
        case 'D': DelLineRight(); break;
        case 'G':
          if (repeat > 1)
          {
            GotoLine(repeat - 1);
          }
          else
          {
            DocumentEnd();
          }
          break;
        case 'N':
          for (int i = 0; i < repeat; i++)
            FindNext(wxExFindReplaceData::Get()->GetFindString(), false);
          break;
        case 'P':
          {
          LineUp();
          Home();
          Paste();
          }
          break;
        // Reverse case current char.
        case '1': // TODO: Should be ~, that does not work
          {
            wxString text(GetTextRange(GetCurrentPos(), GetCurrentPos() + 1));
            wxIslower(text[0]) ? text.UpperCase(): text.LowerCase();
            wxStyledTextCtrl::Replace(GetCurrentPos(), GetCurrentPos() + 1, text);
            CharRight();
          }
          break;

        case '4': LineEnd(); break; // $
        case '[': ParaUp(); break; // {
        case ']': ParaDown(); break; // }

        default:
          handled_command = false;
      }
    }
    else if (event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case 'B': for (int i = 0; i < repeat; i++) PageUp(); break;
        case 'E': for (int i = 0; i < repeat; i++) LineScrollUp(); break;
        case 'F': for (int i = 0; i < repeat; i++) PageDown(); break;
        case 'Y': for (int i = 0; i < repeat; i++) LineScrollDown(); break;
        default:
          handled_command = false;
      }
    }
    else
    {
      wxFAIL;
    }
  }

  if (handled_command)
  {
    m_viCommand.clear();
  }
}

#endif // wxUSE_GUI
<commit_msg>added Id keywords and header<commit_after>////////////////////////////////////////////////////////////////////////////////
// Name:      vi.cpp
// Purpose:   Implementation of class wxExSTC vi mode
// Author:    Anton van Wezenbeek
// Created:   2009-11-21
// RCS-ID:    $Id$
// Copyright: (c) 2009 Anton van Wezenbeek
////////////////////////////////////////////////////////////////////////////////

#include <wx/extension/stc.h>

#if wxUSE_GUI

void wxExSTC::OnKeyVi(wxKeyEvent& event)
{
  if(
    !event.ShiftDown() &&
    !event.ControlDown())
  {
    m_viCommand += event.GetUnicodeKey();
  }

  int repeat = atoi(m_viCommand.c_str());

  if (repeat == 0)
  {
    repeat++;
  }

  bool handled_command = true;

  if (m_viCommand.EndsWith("CW"))
  {
    for (int i = 0; i < repeat; i++) WordRightExtend();
    m_viInsertMode = true;
  }
  else if (m_viCommand.EndsWith("DD"))
  {
    for (int i = 0; i < repeat; i++) LineDelete();
  }
  else if (m_viCommand.EndsWith("DW"))
  {
    for (int i = 0; i < repeat; i++) DelWordRight();
  }
  else if (m_viCommand.EndsWith("YY"))
  {
    const int line = LineFromPosition(GetCurrentPos());
    const int start = PositionFromLine(line);
    const int end = GetLineEndPosition(line + repeat);
    CopyRange(start, end);
  }
  else
  {
    if (!event.ShiftDown() && !event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case '0':
          if (m_viCommand.length() == 1)
          {
            Home();
          }
          else
          {
            handled_command = false;
          }
          break;
        case 'A': m_viInsertMode = true; CharRight(); break;
        case 'B': for (int i = 0; i < repeat; i++) WordLeft(); break;
        case 'G': DocumentStart(); break;
        case 'H': for (int i = 0; i < repeat; i++) CharLeft(); break;
        case 'I': m_viInsertMode = true; break;
        case 'J': for (int i = 0; i < repeat; i++) LineDown(); break;
        case 'K': for (int i = 0; i < repeat; i++) LineUp(); break;
        case 'L': for (int i = 0; i < repeat; i++) CharRight(); break;
        case 'N':
          for (int i = 0; i < repeat; i++)
            FindNext(wxExFindReplaceData::Get()->GetFindString());
        case 'P':
          {
          const int pos = GetCurrentPos();
          LineDown();
          Home();
          Paste();
          GotoPos(pos);
          }
          break;
        case 'W': for (int i = 0; i < repeat; i++) WordRight(); break;
        case 'U': Undo(); break;
        case 'X': DeleteBack(); break;

        case '/':
          {
          wxASSERT(wxTheApp != NULL);
          wxWindow* window = wxTheApp->GetTopWindow();
          wxASSERT(window != NULL);
          wxFrame* frame = wxDynamicCast(window, wxFrame);
          wxASSERT(frame != NULL);
          wxPostEvent(frame,
            wxCommandEvent(wxEVT_COMMAND_MENU_SELECTED, wxID_FIND));
          }
          break;

        // Repeat last text changing command.
        case '.':
          break;

        case '[':
        case ']':
          {
          const int brace_match = BraceMatch(GetCurrentPos());
          if (brace_match != wxSTC_INVALID_POSITION)
          {
            GotoPos(brace_match);
          }
          }
          break;

        default:
          handled_command = false;
      }
    }
    else if (event.ShiftDown() && !event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case 'A': m_viInsertMode = true; LineEnd(); break;
        case 'D': DelLineRight(); break;
        case 'G':
          if (repeat > 1)
          {
            GotoLine(repeat - 1);
          }
          else
          {
            DocumentEnd();
          }
          break;
        case 'N':
          for (int i = 0; i < repeat; i++)
            FindNext(wxExFindReplaceData::Get()->GetFindString(), false);
          break;
        case 'P':
          {
          LineUp();
          Home();
          Paste();
          }
          break;
        // Reverse case current char.
        case '1': // TODO: Should be ~, that does not work
          {
            wxString text(GetTextRange(GetCurrentPos(), GetCurrentPos() + 1));
            wxIslower(text[0]) ? text.UpperCase(): text.LowerCase();
            wxStyledTextCtrl::Replace(GetCurrentPos(), GetCurrentPos() + 1, text);
            CharRight();
          }
          break;

        case '4': LineEnd(); break; // $
        case '[': ParaUp(); break; // {
        case ']': ParaDown(); break; // }

        default:
          handled_command = false;
      }
    }
    else if (event.ControlDown())
    {
      switch (event.GetKeyCode())
      {
        case 'B': for (int i = 0; i < repeat; i++) PageUp(); break;
        case 'E': for (int i = 0; i < repeat; i++) LineScrollUp(); break;
        case 'F': for (int i = 0; i < repeat; i++) PageDown(); break;
        case 'Y': for (int i = 0; i < repeat; i++) LineScrollDown(); break;
        default:
          handled_command = false;
      }
    }
    else
    {
      wxFAIL;
    }
  }

  if (handled_command)
  {
    m_viCommand.clear();
  }
}

#endif // wxUSE_GUI
<|endoftext|>


<commit_before>/**
 * @file max_ip_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of the MaxIP class (maximum inner product search).
 */
#ifndef __MLPACK_METHODS_MAXIP_MAX_IP_IMPL_HPP
#define __MLPACK_METHODS_MAXIP_MAX_IP_IMPL_HPP

// In case it hasn't yet been included.
#include "max_ip.hpp"

#include "max_ip_rules.hpp"

namespace mlpack {
namespace maxip {

template<typename TreeType>
struct SearchFrame
{
  TreeType* node;
  size_t parent;
  double parentEval;
};

template<typename KernelType>
MaxIP<KernelType>::MaxIP(const arma::mat& referenceSet,
                         bool single,
                         bool naive) :
    referenceSet(referenceSet),
    querySet(referenceSet), // Gotta point it somewhere...
    queryTree(NULL),
    single(single),
    naive(naive)
{
  Timer::Start("tree_building");

  // Build the tree.  Could we do this in the initialization list?
  if (naive)
    referenceTree = NULL;
  else
    referenceTree = new tree::CoverTree<IPMetric<KernelType> >(referenceSet);

  Timer::Stop("tree_building");
}

template<typename KernelType>
MaxIP<KernelType>::MaxIP(const arma::mat& referenceSet,
                         const arma::mat& querySet,
                         bool single,
                         bool naive) :
    referenceSet(referenceSet),
    querySet(querySet),
    single(single),
    naive(naive)
{
  Timer::Start("tree_building");

  // Build the trees.  Could we do this in the initialization lists?
  if (naive)
    referenceTree = NULL;
  else
    referenceTree = new tree::CoverTree<IPMetric<KernelType> >(referenceSet);

  if (single || naive)
    queryTree = NULL;
  else
    queryTree = new tree::CoverTree<IPMetric<KernelType> >(querySet);

  Timer::Stop("tree_building");
}

template<typename KernelType>
MaxIP<KernelType>::~MaxIP()
{
  if (queryTree)
    delete queryTree;
  if (referenceTree)
    delete referenceTree;
}

template<typename KernelType>
void MaxIP<KernelType>::Search(const size_t k,
                               arma::Mat<size_t>& indices,
                               arma::mat& products)
{
  // No remapping will be necessary.
  indices.set_size(k, querySet.n_cols);
  products.set_size(k, querySet.n_cols);
  products.fill(DBL_MIN);

  Timer::Start("computing_products");

  size_t kernelEvaluations = 0;

  // Naive implementation.
  if (naive)
  {
    // Simple double loop.  Stupid, slow, but a good benchmark.
    for (size_t q = 0; q < querySet.n_cols; ++q)
    {
      for (size_t r = 0; r < referenceSet.n_cols; ++r)
      {
        const double eval = KernelType::Evaluate(querySet.unsafe_col(q),
                                                 referenceSet.unsafe_col(r));
        ++kernelEvaluations;

        size_t insertPosition;
        for (insertPosition = 0; insertPosition < indices.n_rows;
            ++insertPosition)
          if (eval > products(insertPosition, q))
            break;

        if (insertPosition < indices.n_rows)
          InsertNeighbor(indices, products, q, insertPosition, r, eval);
      }
    }

    Timer::Stop("computing_products");

    Log::Info << "Kernel evaluations: " << kernelEvaluations << "." << std::endl;
    return;
  }

  // Single-tree implementation.
  if (single)
  {
    // Calculate number of pruned nodes.
    size_t numPrunes = 0;

    // Precalculate query products ( || q || for all q).
    arma::vec queryProducts(querySet.n_cols);
    for (size_t queryIndex = 0; queryIndex < querySet.n_cols; ++queryIndex)
      queryProducts[queryIndex] = sqrt(KernelType::Evaluate(
          querySet.unsafe_col(queryIndex), querySet.unsafe_col(queryIndex)));
    kernelEvaluations += querySet.n_cols;

    // Screw the CoverTreeTraverser, we'll implement it by hand.
    for (size_t queryIndex = 0; queryIndex < querySet.n_cols; ++queryIndex)
    {
      std::queue<SearchFrame<tree::CoverTree<IPMetric<KernelType> > > >
          frameQueue;

      SearchFrame<tree::CoverTree<IPMetric<KernelType> > > nextFrame;
      nextFrame.node = referenceTree;
      nextFrame.parent = size_t() - 1;
      nextFrame.parentEval = 0;

      frameQueue.push(nextFrame);

      tree::CoverTree<IPMetric<KernelType> >* referenceNode;
      size_t currentParent;
      double currentParentEval;
      double eval; // Kernel evaluation.

      while (!frameQueue.empty())
      {
        // Get the information for this node.
        const SearchFrame<tree::CoverTree<IPMetric<KernelType> > >& frame =
            frameQueue.front();
        referenceNode = frame.node;
        currentParent = frame.parent;
        currentParentEval = frame.parentEval;

        frameQueue.pop();

        // See if this has the same parent.
        if (referenceNode->Point() == currentParent)
        {
          // We don't have to evaluate the kernel again.
          eval = currentParentEval;
        }
        else
        {
          // Evaluate the kernel.  Then see if it is a result to keep.
          eval = KernelType::Evaluate(querySet.unsafe_col(queryIndex),
              referenceSet.unsafe_col(referenceNode->Point()));
          ++kernelEvaluations;

          // Is the result good enough to be saved?
          if (eval > products(products.n_rows - 1, queryIndex))
          {
            // Figure out where to insert.
            size_t insertPosition = 0;
            for ( ; insertPosition < products.n_rows - 1; ++insertPosition)
              if (eval > products(insertPosition, queryIndex))
                break;

            // We are guaranteed that insertPosition is valid.
            InsertNeighbor(indices, products, queryIndex, insertPosition,
                referenceNode->Point(), eval);
          }
        }

        // Now discover if we can prune this node or not.
        double maxProduct = eval + std::pow(referenceNode->ExpansionConstant(),
            referenceNode->Scale() + 1) * queryProducts[queryIndex];

        if (maxProduct > products(products.n_rows - 1, queryIndex))
        {
          // We can't prune.  So add our children.
          for (size_t i = 0; i < referenceNode->NumChildren(); ++i)
          {
            SearchFrame<tree::CoverTree<IPMetric<KernelType> > > nextFrame;

            nextFrame.node = &(referenceNode->Child(i));
            nextFrame.parent = referenceNode->Point();
            nextFrame.parentEval = eval;

            frameQueue.push(nextFrame);
          }
        }
        else
        {
          numPrunes++;
        }
      }
    }

    Log::Info << "Pruned " << numPrunes << " nodes." << std::endl;
    Log::Info << "Kernel evaluations: " << kernelEvaluations << "." << std::endl;
    Log::Info << "Distance evaluations: " << distanceEvaluations << "." << std::endl;

    Timer::Stop("computing_products");
    return;
  }

  // Double-tree implementation.
  Log::Fatal << "Dual-tree search not implemented yet... oops..." << std::endl;
}

/**
 * Helper function to insert a point into the neighbors and distances matrices.
 *
 * @param queryIndex Index of point whose neighbors we are inserting into.
 * @param pos Position in list to insert into.
 * @param neighbor Index of reference point which is being inserted.
 * @param distance Distance from query point to reference point.
 */
template<typename KernelType>
void MaxIP<KernelType>::InsertNeighbor(arma::Mat<size_t>& indices,
                                       arma::mat& products,
                                       const size_t queryIndex,
                                       const size_t pos,
                                       const size_t neighbor,
                                       const double distance)
{
  // We only memmove() if there is actually a need to shift something.
  if (pos < (products.n_rows - 1))
  {
    int len = (products.n_rows - 1) - pos;
    memmove(products.colptr(queryIndex) + (pos + 1),
        products.colptr(queryIndex) + pos,
        sizeof(double) * len);
    memmove(indices.colptr(queryIndex) + (pos + 1),
        indices.colptr(queryIndex) + pos,
        sizeof(size_t) * len);
  }

  // Now put the new information in the right index.
  products(pos, queryIndex) = distance;
  indices(pos, queryIndex) = neighbor;
}

}; // namespace maxip
}; // namespace mlpack

#endif
<commit_msg>Revamp breadth-first descent to consider tree levels so it is the proper breadth-first descent.<commit_after>/**
 * @file max_ip_impl.hpp
 * @author Ryan Curtin
 *
 * Implementation of the MaxIP class (maximum inner product search).
 */
#ifndef __MLPACK_METHODS_MAXIP_MAX_IP_IMPL_HPP
#define __MLPACK_METHODS_MAXIP_MAX_IP_IMPL_HPP

// In case it hasn't yet been included.
#include "max_ip.hpp"

#include "max_ip_rules.hpp"

namespace mlpack {
namespace maxip {

template<typename TreeType>
struct SearchFrame
{
  TreeType* node;
  double eval;
};

template<typename TreeType>
class SearchFrameCompare
{
 public:
  bool operator()(const SearchFrame<TreeType>& lhs,
                  const SearchFrame<TreeType>& rhs)
  {
    // Compare scale.
    if (lhs.node->Scale() != rhs.node->Scale())
      return (lhs.node->Scale() < rhs.node->Scale());
    else
    {
      // Now we have to compare by evaluation.
      return (lhs.eval < rhs.eval);
    }
  }
};

template<typename KernelType>
MaxIP<KernelType>::MaxIP(const arma::mat& referenceSet,
                         bool single,
                         bool naive) :
    referenceSet(referenceSet),
    querySet(referenceSet), // Gotta point it somewhere...
    queryTree(NULL),
    single(single),
    naive(naive)
{
  Timer::Start("tree_building");

  // Build the tree.  Could we do this in the initialization list?
  if (naive)
    referenceTree = NULL;
  else
    referenceTree = new tree::CoverTree<IPMetric<KernelType> >(referenceSet);

  Timer::Stop("tree_building");
}

template<typename KernelType>
MaxIP<KernelType>::MaxIP(const arma::mat& referenceSet,
                         const arma::mat& querySet,
                         bool single,
                         bool naive) :
    referenceSet(referenceSet),
    querySet(querySet),
    single(single),
    naive(naive)
{
  Timer::Start("tree_building");

  // Build the trees.  Could we do this in the initialization lists?
  if (naive)
    referenceTree = NULL;
  else
    referenceTree = new tree::CoverTree<IPMetric<KernelType> >(referenceSet);

  if (single || naive)
    queryTree = NULL;
  else
    queryTree = new tree::CoverTree<IPMetric<KernelType> >(querySet);

  Timer::Stop("tree_building");
}

template<typename KernelType>
MaxIP<KernelType>::~MaxIP()
{
  if (queryTree)
    delete queryTree;
  if (referenceTree)
    delete referenceTree;
}

template<typename KernelType>
void MaxIP<KernelType>::Search(const size_t k,
                               arma::Mat<size_t>& indices,
                               arma::mat& products)
{
  // No remapping will be necessary.
  indices.set_size(k, querySet.n_cols);
  products.set_size(k, querySet.n_cols);
  products.fill(DBL_MIN);

  Timer::Start("computing_products");

  size_t kernelEvaluations = 0;

  // Naive implementation.
  if (naive)
  {
    // Simple double loop.  Stupid, slow, but a good benchmark.
    for (size_t q = 0; q < querySet.n_cols; ++q)
    {
      for (size_t r = 0; r < referenceSet.n_cols; ++r)
      {
        const double eval = KernelType::Evaluate(querySet.unsafe_col(q),
                                                 referenceSet.unsafe_col(r));
        ++kernelEvaluations;

        size_t insertPosition;
        for (insertPosition = 0; insertPosition < indices.n_rows;
            ++insertPosition)
          if (eval > products(insertPosition, q))
            break;

        if (insertPosition < indices.n_rows)
          InsertNeighbor(indices, products, q, insertPosition, r, eval);
      }
    }

    Timer::Stop("computing_products");

    Log::Info << "Kernel evaluations: " << kernelEvaluations << "." << std::endl;
    return;
  }

  // Single-tree implementation.
  if (single)
  {
    // Calculate number of pruned nodes.
    size_t numPrunes = 0;

    // Precalculate query products ( || q || for all q).
    arma::vec queryProducts(querySet.n_cols);
    for (size_t queryIndex = 0; queryIndex < querySet.n_cols; ++queryIndex)
      queryProducts[queryIndex] = sqrt(KernelType::Evaluate(
          querySet.unsafe_col(queryIndex), querySet.unsafe_col(queryIndex)));
    kernelEvaluations += querySet.n_cols;

    // Screw the CoverTreeTraverser, we'll implement it by hand.
    for (size_t queryIndex = 0; queryIndex < querySet.n_cols; ++queryIndex)
    {
      // Use an array of priority queues?
      std::priority_queue<
          SearchFrame<tree::CoverTree<IPMetric<KernelType> > >,
          std::vector<SearchFrame<tree::CoverTree<IPMetric<KernelType> > > >,
          SearchFrameCompare<tree::CoverTree<IPMetric<KernelType> > > >
          frameQueue;

      // Add initial frame.
      SearchFrame<tree::CoverTree<IPMetric<KernelType> > > nextFrame;
      nextFrame.node = referenceTree;
      nextFrame.eval = KernelType::Evaluate(querySet.unsafe_col(queryIndex),
          referenceSet.unsafe_col(referenceTree->Point()));

      // The initial evaluation will be the best so far.
      indices(0, queryIndex) = referenceTree->Point();
      products(0, queryIndex) = nextFrame.eval;

      frameQueue.push(nextFrame);

      tree::CoverTree<IPMetric<KernelType> >* referenceNode;
      double eval;
      double maxProduct;

      while (!frameQueue.empty())
      {
        // Get the information for this node.
        const SearchFrame<tree::CoverTree<IPMetric<KernelType> > >& frame =
            frameQueue.top();

        referenceNode = frame.node;
        eval = frame.eval;

        // Loop through the children, seeing if we can prune them; if not, add
        // them to the queue.  The self-child is different -- it has the same
        // parent (and therefore the same kernel evaluation).
        if (referenceNode->NumChildren() > 0)
        {
          SearchFrame<tree::CoverTree<IPMetric<KernelType> > > childFrame;

          // We must handle the self-child differently, to avoid adding it to
          // the results twice.
          childFrame.node = &(referenceNode->Child(0));
          childFrame.eval = eval;

          maxProduct = eval + std::pow(childFrame.node->ExpansionConstant(),
              childFrame.node->Scale() + 1) * queryProducts[queryIndex];

          // Add self-child if we can't prune it.
          if (maxProduct > products(products.n_rows - 1, queryIndex))
          {
            // But only if it has children of its own.
            if (childFrame.node->NumChildren() > 0)
              frameQueue.push(childFrame);
          }
          else
            ++numPrunes;

          for (size_t i = 1; i < referenceNode->NumChildren(); ++i)
          {
            // Evaluate child.
            childFrame.node = &(referenceNode->Child(i));
            childFrame.eval = KernelType::Evaluate(
                querySet.unsafe_col(queryIndex),
                referenceSet.unsafe_col(referenceNode->Child(i).Point()));

            // Can we prune it?  If we can, we can avoid putting it in the queue
            // (saves time).
            double maxProduct = childFrame.eval +
                std::pow(childFrame.node->ExpansionConstant(),
                childFrame.node->Scale() + 1) * queryProducts[queryIndex];

            if (maxProduct > products(products.n_rows - 1, queryIndex))
            {
              // Good enough to recurse into.  While we're at it, check the
              // actual evaluation and see if it's an improvement.
              if (childFrame.eval > products(products.n_rows - 1, queryIndex))
              {
                // This is a better result.  Find out where to insert.
                size_t insertPosition = 0;
                for ( ; insertPosition < products.n_rows - 1; ++insertPosition)
                  if (childFrame.eval > products(insertPosition, queryIndex))
                    break;

                // Insert into the correct position; we are guaranteed that
                // insertPosition is valid.
                InsertNeighbor(indices, products, queryIndex, insertPosition,
                    childFrame.node->Point(), childFrame.eval);
              }

              // Now add this to the queue (if it has any children which may
              // need to be recursed into).
              if (childFrame.node->NumChildren() > 0)
                frameQueue.push(childFrame);
            }
            else
            {
              ++numPrunes;
            }
          }
        }

        frameQueue.pop();
      }
    }

    Log::Info << "Pruned " << numPrunes << " nodes." << std::endl;
    Log::Info << "Kernel evaluations: " << kernelEvaluations << "."
        << std::endl;
    Log::Info << "Distance evaluations: " << distanceEvaluations << "."
        << std::endl;

    Timer::Stop("computing_products");
    return;
  }

  // Double-tree implementation.
  Log::Fatal << "Dual-tree search not implemented yet... oops..." << std::endl;
}

/**
 * Helper function to insert a point into the neighbors and distances matrices.
 *
 * @param queryIndex Index of point whose neighbors we are inserting into.
 * @param pos Position in list to insert into.
 * @param neighbor Index of reference point which is being inserted.
 * @param distance Distance from query point to reference point.
 */
template<typename KernelType>
void MaxIP<KernelType>::InsertNeighbor(arma::Mat<size_t>& indices,
                                       arma::mat& products,
                                       const size_t queryIndex,
                                       const size_t pos,
                                       const size_t neighbor,
                                       const double distance)
{
  // We only memmove() if there is actually a need to shift something.
  if (pos < (products.n_rows - 1))
  {
    int len = (products.n_rows - 1) - pos;
    memmove(products.colptr(queryIndex) + (pos + 1),
        products.colptr(queryIndex) + pos,
        sizeof(double) * len);
    memmove(indices.colptr(queryIndex) + (pos + 1),
        indices.colptr(queryIndex) + pos,
        sizeof(size_t) * len);
  }

  // Now put the new information in the right index.
  products(pos, queryIndex) = distance;
  indices(pos, queryIndex) = neighbor;
}

}; // namespace maxip
}; // namespace mlpack

#endif
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file OS.hxx
 * This file represents a C++ language abstraction of common operating
 * system calls.
 *
 * @author Stuart W. Baker
 * @date 28 May 2012
 */

#ifndef _os_hxx_
#define _os_hxx_

#include <endian.h>

#include "utils/macros.h"
#include "os/os.h"

/** This class provides a threading API.
 */
class OSThread
{
public:
    /** Create a thread.
     * @param name name of thread, NULL for an auto generated name
     * @param priority priority of created thread, 0 means default,
     *        lower numbers means lower priority, higher numbers mean higher
     *        priority
     * @param stack_size size in bytes of the created thread's stack
     * @param start_routine entry point of the thread
     * @param arg entry parameter to the thread
     */
    OSThread(const char *name, int priority, size_t stack_size,
             void *(*start_routine)(void*), void *arg)
    {
        os_thread_create(&handle, name, priority, stack_size, start_routine, arg);
    }

    /** Creates a thread via inheritance. The user must overload the entry()
     * function and call the start() method whenever convenient. */
    OSThread()
        : handle(0)
    {
    }

   /** Starts the thread.  This call can be used when OSThread is inherited and
    * there is a virtual entry point.
    * @param name name of thread, NULL for an auto generated name
    * @param priority priority of created thread, 0 means default,
    *        lower numbers means lower priority, higher numbers mean higher
    *        priority
    * @param stack_size size in bytes of the created thread's stack
    */
    void start(const char *name, int priority, size_t stack_size)
    {
        os_thread_create(&handle, name, priority, stack_size, start, this);
    }

    /** Default destructor. */
    ~OSThread()
    {
    }

    /** Returns true if a thread was already created. */
    bool is_created()
    {
        return handle != 0;
    }

protected:
    /** User entry point for the created thread.
     * @return exit status
     */
    virtual void *entry() {
        HASSERT(0 && "forgot to overload OSThread entry point. This thread "
                     "would do nothing.");
        return NULL;
    }

private:
    /** Starting point for a new thread.
     * @param arg pointer to an OSThread instance
     * @return exit status
     */
    static void *start(void *arg)
    {
        OSThread *thread = (OSThread*)arg;
        return thread->entry();
    }

    DISALLOW_COPY_AND_ASSIGN(OSThread);

    /** Private thread handle. */
    os_thread_t handle;
};

/** This class provides support for one time initialization.
 */
class OSThreadOnce
{
public:
    /** One time intialization constructor.
     * @param routine method to call once
     */
    OSThreadOnce(void (*routine)(void))
        : handle(OS_THREAD_ONCE_INIT),
          routine(routine)
    {
    }

    /** call one time intialization routine
     * @return 0 upon success
     */
    int once(void)
    {
        return os_thread_once(&handle, routine);
    }

    /** Default Destructor */
    ~OSThreadOnce()
    {
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSThreadOnce);

    /** Private once handle. */
    os_thread_once_t handle;

    /** One time initialization routine */
    void (*routine)(void);
};

/** This class provides a timer API.
 * The return value of the callback determines the behavior of how the timer is
 * rearmed.  @ref OS_TIMER_NONE indicates that the timer is not restarted,
 * OS_TIMER_RESTART restarts the timer with the period of the last timeout,
 * OS_TIMER_DELETE deletes the timer, and all other values indicate the restart
 * period in nanoseconds.
 */
class OSTimer
{
public:
    /** Create a new timer.
     * @param callback callback associated with timer
     * @param data1 data to pass along with callback
     * @param data2 data to pass along with callback
     */
    OSTimer(long long (*callback)(void*, void*), void *data1, void *data2)
    {
        handle = os_timer_create(callback, data1, data2);
    }

    /** Delete a timer.
     */
    ~OSTimer()
    {
        os_timer_delete(handle);
    }

    /** Start a timer.
     * @param period period in nanoseconds before expiration
     */
    void start(long long period)
    {
        os_timer_start(handle, period);
    }

    /** Delete a timer.
     */
    void stop()
    {
        os_timer_stop(handle);
    }

private:
    /** Default constructor.
     */
    OSTimer();

    DISALLOW_COPY_AND_ASSIGN(OSTimer);

    /** Private timer handle. */
    os_timer_t handle;
};

/** This class provides a counting semaphore API.
 */
class OSSem
{
public:
    /** Initialize a Semaphore.
     * @param value initial count
     */
    OSSem(unsigned int value = 0)
    {
        os_sem_init(&handle, value);
    }

    ~OSSem()
    {
        os_sem_destroy(&handle);
    }

    /** Post (increment) a semaphore.
     */
    void post()
    {
        os_sem_post(&handle);
    }

#if defined (__FreeRTOS__)
    void post_from_isr()
    {
        os_sem_post_from_isr(&handle);
    }
#endif

    /** Wait on (decrement) a semaphore.
     */
    void wait()
    {
        os_sem_wait(&handle);
    }

    /** Wait on (decrement) a semaphore with timeout condition.
     * @param timeout timeout in nanoseconds, else OS_WAIT_FOREVER to wait forever
     * @return 0 upon success, else -1 with errno set to indicate error
     */
    int timedwait(long long timeout)
    {
        return os_sem_timedwait(&handle, timeout);
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSSem);

    /** Private semaphore handle. */
    os_sem_t handle;
};

/** This class provides a simple message queue.
 */
class OSMQ
{
public:

    /** Constructor.
     * @param length number of items the queue can hold
     * @param item_size size of each item in bytes in the queue
     */
    OSMQ(size_t length, size_t item_size)
        : handle(os_mq_create(length, item_size))
    {
        HASSERT(handle != NULL);
    }

    /** Destructor.
     */
    ~OSMQ()
    {
        /** @todo (Stuart Baker) need a way to destroy a message queue */
    }

    /** Blocking send of a message to a queue.
     * @param data message to copy into queue
     */
    void send(const void *data)
    {
        os_mq_send(handle, data);
    }

    /** Send a message to a queue with a timeout.
     * @param data message to copy into queue
     * @param timeout time in nanoseconds to wait for queue to be able to accept message
     * @return OS_MQ_NONE on success, OS_MQ_TIMEDOUT on timeout
     */
    int timedsend(const void *data, long long timeout)
    {
        return os_mq_timedsend(handle, data, timeout);
    }

    /** Blocking receive a message from a queue.
     * @param data location to copy message from the queue
     */
    void receive(void *data)
    {
        os_mq_receive(handle, data);
    }

    /** Receive a message from a queue.
     * @param data location to copy message from the queue
     * @param timeout time in nanoseconds to wait for queue to have a message available
     * @return OS_MQ_NONE on success, OS_MQ_TIMEDOUT on timeout
     */
    int timedreceive(void *data, long long timeout)
    {
        return os_mq_timedreceive(handle, data, timeout);
    }

    /** Send of a message to a queue from ISR context.
     * @param data message to copy into queue
     * @param woken is the task woken up
     * @return OS_MQ_NONE on success, else OS_MQ_FULL
     */
    int send_from_isr(const void *data, int *woken)
    {
        return os_mq_send_from_isr(handle, data, woken);
    }

    /** Receive a message from a queue from ISR context.
     * @param data location to copy message from the queue
     * @param woken is the task woken up
     * @return OS_MQ_NONE on success, else OS_MQ_FULL
     */
    int receive_from_isr(void *data, int *woken)
    {
        return os_mq_receive_from_isr(handle, data, woken);
    }

    /** Return the number of messages pending in the queue.
     * @return number of messages in the queue
     */
    int num_pending()
    {
        return os_mq_num_pending(handle);
    }

    /** Return the number of messages pending in the queue from ISR context.
     * @return number of messages in the queue
     */
    int pending_from_isr()
    {
        return os_mq_num_pending_from_isr(handle);
    }

    /** Check if a queue is full from ISR context.
     * @return non-zero if the queue is full.
     */
    int is_full_from_isr()
    {
        return os_mq_is_full_from_isr(handle);
    }

private:
    /** Default Constructor.
     */
    OSMQ();

    /** Private message queue handle */
    os_mq_t handle;

    DISALLOW_COPY_AND_ASSIGN(OSMQ);
};

/** This class provides a mutex API.
 */
class OSMutex
{
public:
    /** Initialize a mutex.
     * @param recursive false creates a normal mutex, true creates a recursive mutex
     */
    OSMutex(bool recursive = false)
    {
        if (recursive)
        {
            os_recursive_mutex_init(&handle);
        }
        else
        {
            os_mutex_init(&handle);
        }
    }

    /** Lock a mutex.
     */
    void lock()
    {
        os_mutex_lock(&handle);
    }

    /** Unlock a mutex.
     */
    void unlock()
    {
        os_mutex_unlock(&handle);
    }

    /** Destructor */
    ~OSMutex()
    {
        os_mutex_destroy(&handle);
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSMutex);

    friend class OSMutexLock;
    /** Private mutex handle. */
    os_mutex_t handle;
};

/**
 * Class to allow convenient locking and unlocking of mutexes in a C context.
 * The mutex will be automatically unlocked when the context is left, even if
 * there are multiple return, break or continue statements.
 *
 * Usage:
 *
 * void foo()
 * {
 *   // ...non-critical-section code here...
 *   {
 *     OSMutexLock locker(&mutex_);
 *     // ...critical section here...
 *     if (error) return;
 *     // ...more critical code here...
 *   }
 *   // ...at this point the mutex is unlocked...
 *   // ...more non-critical-section code here...
 * }
 *
 */
class OSMutexLock
{
public:
    OSMutexLock(OSMutex* mutex)
        : mutex_(&mutex->handle)
    {
        os_mutex_lock(mutex_);
    }

    OSMutexLock(os_mutex_t* mutex)
        : mutex_(mutex)
    {
        os_mutex_lock(mutex_);
    }

    ~OSMutexLock()
    {
        os_mutex_unlock(mutex_);
    }
private:
    DISALLOW_COPY_AND_ASSIGN(OSMutexLock);

    os_mutex_t* mutex_;
};

/** This catches programming errors where you declare a mutex locker object
 *  without a name like this:
 *
 *  void foo()
 *  {
 *    OSMutexLock(&mutex_);
 *    // ...critical section here...
 *  }

 *  The above is valid C++, which creates a temporary OSMutexLock object, locks
 *  it, then immediately destructs the object, unlocking the mutex in the same
 *  line it was created. Thus the critical sections goes unprotected
 *  unintentionally.
 *
 *  The correct code is
 *
 *  void foo()
 *  {
 *    OSMutexLock locker(&mutex_);
 *    // ...critical section here...
 *  }
 *
 */
#define OSMutexLock(l) int error_omitted_mutex_lock_variable[-1]

/** Allows for OS abstracted access to time.
 */
class OSTime
{
public:
    /** Get the monotonic time since the system started.
     * @return time in nanoseconds since system start
     */
    static long long get_monotonic(void)
    {
        return os_get_time_monotonic();
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSTime);

    /* Private default constructor prevents instantiating this class. */
    OSTime();

    /** Default destructor. */
    ~OSTime();
};

#endif /* _os_hxx_ */
<commit_msg>Style fix<commit_after>/** \copyright
 * Copyright (c) 2012, Stuart W Baker
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are  permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file OS.hxx
 * This file represents a C++ language abstraction of common operating
 * system calls.
 *
 * @author Stuart W. Baker
 * @date 28 May 2012
 */

#ifndef _os_hxx_
#define _os_hxx_

#include <endian.h>

#include "utils/macros.h"
#include "os/os.h"

/** This class provides a threading API.
 */
class OSThread
{
public:
    /** Create a thread.
     * @param name name of thread, NULL for an auto generated name
     * @param priority priority of created thread, 0 means default,
     *        lower numbers means lower priority, higher numbers mean higher
     *        priority
     * @param stack_size size in bytes of the created thread's stack
     * @param start_routine entry point of the thread
     * @param arg entry parameter to the thread
     */
    OSThread(const char *name, int priority, size_t stack_size,
             void *(*start_routine)(void*), void *arg)
    {
        os_thread_create(&handle, name, priority, stack_size, start_routine, arg);
    }

    /** Creates a thread via inheritance. The user must overload the entry()
     * function and call the start() method whenever convenient. */
    OSThread()
        : handle(0)
    {
    }

   /** Starts the thread.  This call can be used when OSThread is inherited and
    * there is a virtual entry point.
    * @param name name of thread, NULL for an auto generated name
    * @param priority priority of created thread, 0 means default,
    *        lower numbers means lower priority, higher numbers mean higher
    *        priority
    * @param stack_size size in bytes of the created thread's stack
    */
    void start(const char *name, int priority, size_t stack_size)
    {
        os_thread_create(&handle, name, priority, stack_size, start, this);
    }

    /** Default destructor. */
    ~OSThread()
    {
    }

    /** Returns true if a thread was already created. */
    bool is_created()
    {
        return handle != 0;
    }

protected:
    /** User entry point for the created thread.
     * @return exit status
     */
    virtual void *entry()
    {
        HASSERT(0 && "forgot to overload OSThread entry point. This thread "
                     "would do nothing.");
        return NULL;
    }

private:
    /** Starting point for a new thread.
     * @param arg pointer to an OSThread instance
     * @return exit status
     */
    static void *start(void *arg)
    {
        OSThread *thread = (OSThread*)arg;
        return thread->entry();
    }

    DISALLOW_COPY_AND_ASSIGN(OSThread);

    /** Private thread handle. */
    os_thread_t handle;
};

/** This class provides support for one time initialization.
 */
class OSThreadOnce
{
public:
    /** One time intialization constructor.
     * @param routine method to call once
     */
    OSThreadOnce(void (*routine)(void))
        : handle(OS_THREAD_ONCE_INIT),
          routine(routine)
    {
    }

    /** call one time intialization routine
     * @return 0 upon success
     */
    int once(void)
    {
        return os_thread_once(&handle, routine);
    }

    /** Default Destructor */
    ~OSThreadOnce()
    {
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSThreadOnce);

    /** Private once handle. */
    os_thread_once_t handle;

    /** One time initialization routine */
    void (*routine)(void);
};

/** This class provides a timer API.
 * The return value of the callback determines the behavior of how the timer is
 * rearmed.  @ref OS_TIMER_NONE indicates that the timer is not restarted,
 * OS_TIMER_RESTART restarts the timer with the period of the last timeout,
 * OS_TIMER_DELETE deletes the timer, and all other values indicate the restart
 * period in nanoseconds.
 */
class OSTimer
{
public:
    /** Create a new timer.
     * @param callback callback associated with timer
     * @param data1 data to pass along with callback
     * @param data2 data to pass along with callback
     */
    OSTimer(long long (*callback)(void*, void*), void *data1, void *data2)
    {
        handle = os_timer_create(callback, data1, data2);
    }

    /** Delete a timer.
     */
    ~OSTimer()
    {
        os_timer_delete(handle);
    }

    /** Start a timer.
     * @param period period in nanoseconds before expiration
     */
    void start(long long period)
    {
        os_timer_start(handle, period);
    }

    /** Delete a timer.
     */
    void stop()
    {
        os_timer_stop(handle);
    }

private:
    /** Default constructor.
     */
    OSTimer();

    DISALLOW_COPY_AND_ASSIGN(OSTimer);

    /** Private timer handle. */
    os_timer_t handle;
};

/** This class provides a counting semaphore API.
 */
class OSSem
{
public:
    /** Initialize a Semaphore.
     * @param value initial count
     */
    OSSem(unsigned int value = 0)
    {
        os_sem_init(&handle, value);
    }

    ~OSSem()
    {
        os_sem_destroy(&handle);
    }

    /** Post (increment) a semaphore.
     */
    void post()
    {
        os_sem_post(&handle);
    }

#if defined (__FreeRTOS__)
    void post_from_isr()
    {
        os_sem_post_from_isr(&handle);
    }
#endif

    /** Wait on (decrement) a semaphore.
     */
    void wait()
    {
        os_sem_wait(&handle);
    }

    /** Wait on (decrement) a semaphore with timeout condition.
     * @param timeout timeout in nanoseconds, else OS_WAIT_FOREVER to wait forever
     * @return 0 upon success, else -1 with errno set to indicate error
     */
    int timedwait(long long timeout)
    {
        return os_sem_timedwait(&handle, timeout);
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSSem);

    /** Private semaphore handle. */
    os_sem_t handle;
};

/** This class provides a simple message queue.
 */
class OSMQ
{
public:

    /** Constructor.
     * @param length number of items the queue can hold
     * @param item_size size of each item in bytes in the queue
     */
    OSMQ(size_t length, size_t item_size)
        : handle(os_mq_create(length, item_size))
    {
        HASSERT(handle != NULL);
    }

    /** Destructor.
     */
    ~OSMQ()
    {
        /** @todo (Stuart Baker) need a way to destroy a message queue */
    }

    /** Blocking send of a message to a queue.
     * @param data message to copy into queue
     */
    void send(const void *data)
    {
        os_mq_send(handle, data);
    }

    /** Send a message to a queue with a timeout.
     * @param data message to copy into queue
     * @param timeout time in nanoseconds to wait for queue to be able to accept message
     * @return OS_MQ_NONE on success, OS_MQ_TIMEDOUT on timeout
     */
    int timedsend(const void *data, long long timeout)
    {
        return os_mq_timedsend(handle, data, timeout);
    }

    /** Blocking receive a message from a queue.
     * @param data location to copy message from the queue
     */
    void receive(void *data)
    {
        os_mq_receive(handle, data);
    }

    /** Receive a message from a queue.
     * @param data location to copy message from the queue
     * @param timeout time in nanoseconds to wait for queue to have a message available
     * @return OS_MQ_NONE on success, OS_MQ_TIMEDOUT on timeout
     */
    int timedreceive(void *data, long long timeout)
    {
        return os_mq_timedreceive(handle, data, timeout);
    }

    /** Send of a message to a queue from ISR context.
     * @param data message to copy into queue
     * @param woken is the task woken up
     * @return OS_MQ_NONE on success, else OS_MQ_FULL
     */
    int send_from_isr(const void *data, int *woken)
    {
        return os_mq_send_from_isr(handle, data, woken);
    }

    /** Receive a message from a queue from ISR context.
     * @param data location to copy message from the queue
     * @param woken is the task woken up
     * @return OS_MQ_NONE on success, else OS_MQ_FULL
     */
    int receive_from_isr(void *data, int *woken)
    {
        return os_mq_receive_from_isr(handle, data, woken);
    }

    /** Return the number of messages pending in the queue.
     * @return number of messages in the queue
     */
    int num_pending()
    {
        return os_mq_num_pending(handle);
    }

    /** Return the number of messages pending in the queue from ISR context.
     * @return number of messages in the queue
     */
    int pending_from_isr()
    {
        return os_mq_num_pending_from_isr(handle);
    }

    /** Check if a queue is full from ISR context.
     * @return non-zero if the queue is full.
     */
    int is_full_from_isr()
    {
        return os_mq_is_full_from_isr(handle);
    }

private:
    /** Default Constructor.
     */
    OSMQ();

    /** Private message queue handle */
    os_mq_t handle;

    DISALLOW_COPY_AND_ASSIGN(OSMQ);
};

/** This class provides a mutex API.
 */
class OSMutex
{
public:
    /** Initialize a mutex.
     * @param recursive false creates a normal mutex, true creates a recursive mutex
     */
    OSMutex(bool recursive = false)
    {
        if (recursive)
        {
            os_recursive_mutex_init(&handle);
        }
        else
        {
            os_mutex_init(&handle);
        }
    }

    /** Lock a mutex.
     */
    void lock()
    {
        os_mutex_lock(&handle);
    }

    /** Unlock a mutex.
     */
    void unlock()
    {
        os_mutex_unlock(&handle);
    }

    /** Destructor */
    ~OSMutex()
    {
        os_mutex_destroy(&handle);
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSMutex);

    friend class OSMutexLock;
    /** Private mutex handle. */
    os_mutex_t handle;
};

/**
 * Class to allow convenient locking and unlocking of mutexes in a C context.
 * The mutex will be automatically unlocked when the context is left, even if
 * there are multiple return, break or continue statements.
 *
 * Usage:
 *
 * void foo()
 * {
 *   // ...non-critical-section code here...
 *   {
 *     OSMutexLock locker(&mutex_);
 *     // ...critical section here...
 *     if (error) return;
 *     // ...more critical code here...
 *   }
 *   // ...at this point the mutex is unlocked...
 *   // ...more non-critical-section code here...
 * }
 *
 */
class OSMutexLock
{
public:
    OSMutexLock(OSMutex* mutex)
        : mutex_(&mutex->handle)
    {
        os_mutex_lock(mutex_);
    }

    OSMutexLock(os_mutex_t* mutex)
        : mutex_(mutex)
    {
        os_mutex_lock(mutex_);
    }

    ~OSMutexLock()
    {
        os_mutex_unlock(mutex_);
    }
private:
    DISALLOW_COPY_AND_ASSIGN(OSMutexLock);

    os_mutex_t* mutex_;
};

/** This catches programming errors where you declare a mutex locker object
 *  without a name like this:
 *
 *  void foo()
 *  {
 *    OSMutexLock(&mutex_);
 *    // ...critical section here...
 *  }

 *  The above is valid C++, which creates a temporary OSMutexLock object, locks
 *  it, then immediately destructs the object, unlocking the mutex in the same
 *  line it was created. Thus the critical sections goes unprotected
 *  unintentionally.
 *
 *  The correct code is
 *
 *  void foo()
 *  {
 *    OSMutexLock locker(&mutex_);
 *    // ...critical section here...
 *  }
 *
 */
#define OSMutexLock(l) int error_omitted_mutex_lock_variable[-1]

/** Allows for OS abstracted access to time.
 */
class OSTime
{
public:
    /** Get the monotonic time since the system started.
     * @return time in nanoseconds since system start
     */
    static long long get_monotonic(void)
    {
        return os_get_time_monotonic();
    }

private:
    DISALLOW_COPY_AND_ASSIGN(OSTime);

    /* Private default constructor prevents instantiating this class. */
    OSTime();

    /** Default destructor. */
    ~OSTime();
};

#endif /* _os_hxx_ */
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#include <cstdio>
#include <cstring>

#include <vector.hpp>
#include <algorithms.hpp>

#include "test.hpp"

namespace {

void test_base(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    check(a.size() == 6, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[5] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(2);

    check(a.size() == 5, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 2, "Invalid vector:[]");
    check(a[3] == 3, "Invalid vector:[]");
    check(a[4] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);

    a.erase(a.begin() + 2);

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 3, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");
}

void test_erase_range(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(a.begin() + 1, a.begin() + 4);

    check(a.size() == 3, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 3, "Invalid vector:[]");
    check(a[2] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase_remove(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(std::remove(a.begin(), a.end(), 0), a.end());

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 2, "Invalid vector:[]");
    check(a[2] == 3, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase_remove_if(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(std::remove_if(a.begin(), a.end(), [](int value){
        return value == 1 || value == 3;
    }), a.end());

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 0, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 2, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");

    check(*a.begin() == 0);
}

void test_push_front(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.push_front(99);

    check(a.size() == 7, "Invalid vector:size");
    check(a[0] == 99, "Invalid vector:[]");
    check(a[1] == 1, "Invalid vector:[]");
    check(a[2] == 0, "Invalid vector:[]");
    check(a[3] == 0, "Invalid vector:[]");
    check(a[4] == 2, "Invalid vector:[]");
    check(a[5] == 3, "Invalid vector:[]");
    check(a[6] == 4, "Invalid vector:[]");

    check(*a.begin() == 99);
}

void test_reverse_iterator(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    auto it = a.rbegin();
    auto end = a.rend();

    check(it != end, "Invalid reverse iterator");
    check(*it == 4, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 3, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 2, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 0, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 0, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 1, "Invalid reverse iterator");

    ++it;
    check(it == end, "Invalid reverse iterator");
}

} //end of anonymous namespace

void vector_tests(){
    test_base();
    test_erase();
    test_erase_range();
    test_erase_remove();
    test_erase_remove_if();
    test_push_front();
    test_reverse_iterator();
}
<commit_msg>Simple test for destructors<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#include <cstdio>
#include <cstring>

#include <vector.hpp>
#include <algorithms.hpp>

#include "test.hpp"

namespace {

void test_base(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    check(a.size() == 6, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[5] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(2);

    check(a.size() == 5, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 2, "Invalid vector:[]");
    check(a[3] == 3, "Invalid vector:[]");
    check(a[4] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);

    a.erase(a.begin() + 2);

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 3, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");
}

void test_erase_range(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(a.begin() + 1, a.begin() + 4);

    check(a.size() == 3, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 3, "Invalid vector:[]");
    check(a[2] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase_remove(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(std::remove(a.begin(), a.end(), 0), a.end());

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 1, "Invalid vector:[]");
    check(a[1] == 2, "Invalid vector:[]");
    check(a[2] == 3, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");

    check(*a.begin() == 1);
}

void test_erase_remove_if(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.erase(std::remove_if(a.begin(), a.end(), [](int value){
        return value == 1 || value == 3;
    }), a.end());

    check(a.size() == 4, "Invalid vector:size");
    check(a[0] == 0, "Invalid vector:[]");
    check(a[1] == 0, "Invalid vector:[]");
    check(a[2] == 2, "Invalid vector:[]");
    check(a[3] == 4, "Invalid vector:[]");

    check(*a.begin() == 0);
}

void test_push_front(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    a.push_front(99);

    check(a.size() == 7, "Invalid vector:size");
    check(a[0] == 99, "Invalid vector:[]");
    check(a[1] == 1, "Invalid vector:[]");
    check(a[2] == 0, "Invalid vector:[]");
    check(a[3] == 0, "Invalid vector:[]");
    check(a[4] == 2, "Invalid vector:[]");
    check(a[5] == 3, "Invalid vector:[]");
    check(a[6] == 4, "Invalid vector:[]");

    check(*a.begin() == 99);
}

void test_reverse_iterator(){
    std::vector<int> a{1, 0, 0, 2, 3, 4};

    auto it = a.rbegin();
    auto end = a.rend();

    check(it != end, "Invalid reverse iterator");
    check(*it == 4, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 3, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 2, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 0, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 0, "Invalid reverse iterator");

    ++it;
    check(it != end, "Invalid reverse iterator");
    check(*it == 1, "Invalid reverse iterator");

    ++it;
    check(it == end, "Invalid reverse iterator");
}

struct kiss {
    int* ref;
    kiss() {} // for vector
    kiss(int* ref) : ref(ref) {}
    ~kiss(){
        ++(*ref);
    }
};

void test_destructor() {
    int counter = 0;

    {
        std::vector<kiss> vec(3);
        vec.emplace_back(&counter);
        vec.emplace_back(&counter);
        vec.emplace_back(&counter);
    }

    check(counter == 3, "Invalid destructors");
}

} //end of anonymous namespace

void vector_tests(){
    test_base();
    test_erase();
    test_erase_range();
    test_erase_remove();
    test_erase_remove_if();
    test_push_front();
    test_reverse_iterator();
    test_destructor();
}
<|endoftext|>


<commit_before>#ifndef MODBUS_READ_COILS_COMMAND_HPP
#define MODBUS_READ_COILS_COMMAND_HPP

#include "ModbusCommand.hpp"
#include <iostream>

class ReadCoilsCommand : public ModbusCommand {
public:
    inline                      ReadCoilsCommand();
    void                        exec(ModbusClient& client, const std::vector<std::string>& args) override;
    std::string                 getShortHelpText() const override;
    std::string                 getHelpText() const override;

private:
    uint16_t                    m_startAddress;
    uint16_t                    m_numCoils;

    boost::program_options::options_description m_options;
};

ReadCoilsCommand::ReadCoilsCommand() :
    ModbusCommand(),
    m_options("Options")
{
    namespace po = boost::program_options;

    m_options.add_options()
        ("startAddress,s", po::value<uint16_t>(&m_startAddress)->required(), "address of first coil to retrieve")
        ("numCoils,n", po::value<uint16_t>(&m_numCoils)->required(), "number of coils to retrieve (up to 2000 coils)");
}

void ReadCoilsCommand::exec(ModbusClient& client, const std::vector<std::string>& args) {
    namespace po = boost::program_options;

    po::variables_map vm;
    //po::store(po::command_line_parser(args).options(m_options).positional(m_positional_options).run(), vm);
    po::store(po::command_line_parser(args).options(m_options).run(), vm);
    po::notify(vm);

    client.readCoils(modbus::tcp::Address(m_startAddress), modbus::tcp::NumBits(m_numCoils));
}

std::string ReadCoilsCommand::getShortHelpText() const {
    return "Read a list of coils from modbus device";
}

std::string ReadCoilsCommand::getHelpText() const {
    return "getcoils [options]";
}

#endif
<commit_msg>Add positional args for readcoils command<commit_after>#ifndef MODBUS_READ_COILS_COMMAND_HPP
#define MODBUS_READ_COILS_COMMAND_HPP

#include "ModbusCommand.hpp"
#include <iostream>

class ReadCoilsCommand : public ModbusCommand {
public:
    inline                          ReadCoilsCommand();
    void                            exec(ModbusClient& client, const std::vector<std::string>& args) override;
    std::string                     getShortHelpText() const override;
    std::string                     getHelpText() const override;

private:
    using OptionsDescription = boost::program_options::options_description;
    using PositionalOptionsDescription = boost::program_options::positional_options_description;

    uint16_t                        m_startAddress;
    uint16_t                        m_numCoils;

    OptionsDescription              m_options;
    PositionalOptionsDescription    m_positional_options;
};

ReadCoilsCommand::ReadCoilsCommand() :
    ModbusCommand(),
    m_options("Options")
{
    namespace po = boost::program_options;

    m_options.add_options()
        ("startAddress,s", po::value<uint16_t>(&m_startAddress)->required(), "address of first coil to retrieve")
        ("numCoils,n", po::value<uint16_t>(&m_numCoils)->required(), "number of coils to retrieve (up to 2000 coils)");

    m_positional_options.add("startAddress", 1);
    m_positional_options.add("numCoils", 1);
}

void ReadCoilsCommand::exec(ModbusClient& client, const std::vector<std::string>& args) {
    namespace po = boost::program_options;

    po::variables_map vm;
    po::store(po::command_line_parser(args).options(m_options).positional(m_positional_options).run(), vm);
    po::notify(vm);

    client.readCoils(modbus::tcp::Address(m_startAddress), modbus::tcp::NumBits(m_numCoils));
}

std::string ReadCoilsCommand::getShortHelpText() const {
    return "Read a list of coils from modbus device";
}

std::string ReadCoilsCommand::getHelpText() const {
    std::stringstream ss;
    ss << getShortHelpText() << std::endl
       << "Usage:" << std::endl
       << "    readcoils <start_address> <num_coils>" << std::endl;
    return ss.str();
}

#endif
<|endoftext|>


<commit_before>#include "cv.h"
#include "highgui.h"

using namespace cv;

Mat img;
int threshval = 100;

void on_trackbar(int, void*)
{
	Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

	Mat dst = Mat::zeros(img.size(), CV_8UC3);

    if( contours.size() > 0 )
    {
        // iterate through all the top-level contours,
        // draw each connected component with its own random color
        int idx = 0;
        for( ; idx >= 0; idx = hierarchy[idx][0] )
        {
            Scalar color( (rand()&255), (rand()&255), (rand()&255) );
            drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
        }
    }

	imshow( "Connected Components", dst );
}

int main( int argc, char** argv )
{
    // the first command line parameter must be file name of binary
    // (black-n-white) image
    if( !(img=imread(argc == 2 ? argv[1] : "stuff.jpg", 0)).data)
        return -1;

    namedWindow( "Image", 1 );
    imshow( "Image", img );

	namedWindow( "Connected Components", 1 );
	createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
	on_trackbar(threshval, 0);

    waitKey(0);
    return 0;
}
<commit_msg>described<commit_after>#include "cv.h"
#include "highgui.h"
#include <iostream>

using namespace cv;
Mat img;
int threshval = 100;

void help()
{
	cout <<
		   "Program to demonstrate connected components and use of the trackbar\n"
		<< "\n"
		<< "Usage: ./connected_components <image>\n"
		<< "\n"
		<< "The image is converted to grayscale and displayed, another image has a trackbar\n"
		<< "that controls thresholding and thereby the extracted contours which are drawn in color\n"
		<< endl;
}

void on_trackbar(int, void*)
{
	Mat bw = threshval < 128 ? (img < threshval) : (img > threshval);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;

    findContours( bw, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );

	Mat dst = Mat::zeros(img.size(), CV_8UC3);

    if( contours.size() > 0 )
    {
        // iterate through all the top-level contours,
        // draw each connected component with its own random color
        int idx = 0;
        for( ; idx >= 0; idx = hierarchy[idx][0] )
        {
            Scalar color( (rand()&255), (rand()&255), (rand()&255) );
            drawContours( dst, contours, idx, color, CV_FILLED, 8, hierarchy );
        }
    }

	imshow( "Connected Components", dst );
}

int main( int argc, char** argv )
{
    // the first command line parameter
	if(argc != 2)
	{
		help();
		return -1;
	}
    if( !(img=imread(argc == 2 ? argv[1] : "stuff.jpg", 0)).data) //The ending 0 in imread converts the image to grayscale.
        return -1;

    namedWindow( "Image", 1 );
    imshow( "Image", img );

	namedWindow( "Connected Components", 1 );
	createTrackbar( "Threshold", "Connected Components", &threshval, 255, on_trackbar );
	on_trackbar(threshval, 0);

    waitKey(0);
    return 0;
}
<|endoftext|>


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

#ifndef IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL
#define IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL

#include "iceoryx_hoofs/internal/relocatable_pointer/pointer_repository.hpp"

namespace iox
{
namespace rp
{
template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline PointerRepository<id_t, ptr_t, CAPACITY>::PointerRepository() noexcept
    : m_info(CAPACITY)
{
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::registerPtr(id_t id, ptr_t ptr, uint64_t size) noexcept
{
    if (id > MAX_ID)
    {
        return false;
    }
    if (m_info[id].basePtr == nullptr)
    {
        m_info[id].basePtr = ptr;
        m_info[id].endPtr = reinterpret_cast<ptr_t>(reinterpret_cast<uintptr_t>(ptr) + size - 1U);
        if (id > m_maxRegistered)
        {
            m_maxRegistered = id;
        }
        return true;
    }
    return false;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline id_t PointerRepository<id_t, ptr_t, CAPACITY>::registerPtr(const ptr_t ptr, uint64_t size) noexcept
{
    for (id_t id = 1U; id <= MAX_ID; ++id)
    {
        if (m_info[id].basePtr == nullptr)
        {
            m_info[id].basePtr = ptr;
            m_info[id].endPtr = reinterpret_cast<ptr_t>(reinterpret_cast<uintptr_t>(ptr) + size - 1U);
            if (id > m_maxRegistered)
            {
                m_maxRegistered = id;
            }
            return id;
        }
    }

    return INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::unregisterPtr(id_t id) noexcept
{
    if (id <= MAX_ID && id >= MIN_ID)
    {
        if (m_info[id].basePtr != nullptr)
        {
            m_info[id].basePtr = nullptr;

            /// @note do not search for next lower registered index but we could do it here
            return true;
        }
    }

    return false;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline void PointerRepository<id_t, ptr_t, CAPACITY>::unregisterAll() noexcept
{
    for (auto& info : m_info)
    {
        info.basePtr = nullptr;
    }
    m_maxRegistered = 0U;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline ptr_t PointerRepository<id_t, ptr_t, CAPACITY>::getBasePtr(id_t id) const noexcept
{
    if (id <= MAX_ID && id >= MIN_ID)
    {
        return m_info[id].basePtr;
    }

    /// @note for id 0 nullptr is returned, meaning we will later interpret a relative pointer by casting the offset
    /// into a pointer (i.e. we measure relative to 0)

    /// @note we cannot distinguish between not registered and nullptr registered, but we do not need to
    return nullptr;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline id_t PointerRepository<id_t, ptr_t, CAPACITY>::searchId(ptr_t ptr) const noexcept
{
    for (id_t id = 1U; id <= m_maxRegistered; ++id)
    {
        // return first id where the ptr is in the corresponding interval
        if (ptr >= m_info[id].basePtr && ptr <= m_info[id].endPtr)
        {
            return id;
        }
    }
    /// @note implicitly interpret the pointer as a regular pointer if not found
    /// by setting id to 0
    /// rationale: test cases work without registered shared memory and require
    /// this at the moment to avoid fundamental changes
    return 0U;
    // return INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::isValid(id_t id) const noexcept
{
    return id != INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline void PointerRepository<id_t, ptr_t, CAPACITY>::print() const noexcept
{
    for (id_t id = 0U; id < m_info.size(); ++id)
    {
        auto ptr = m_info[id].basePtr;
        if (ptr != nullptr)
        {
            std::cout << id << " ---> " << ptr << std::endl;
        }
    }
}

} // namespace rp
} // namespace iox

#endif // IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL
<commit_msg>iox-#1196 Suppress clang-tidy warnings in PointerRepository<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#ifndef IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL
#define IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL

#include "iceoryx_hoofs/internal/relocatable_pointer/pointer_repository.hpp"

namespace iox
{
namespace rp
{
template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline PointerRepository<id_t, ptr_t, CAPACITY>::PointerRepository() noexcept
    : m_info(CAPACITY)
{
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::registerPtr(id_t id, ptr_t ptr, uint64_t size) noexcept
{
    if (id > MAX_ID)
    {
        return false;
    }
    if (m_info[id].basePtr == nullptr)
    {
        m_info[id].basePtr = ptr;
        // AXIVION Next Construct AutosarC++19_03-A5.2.4 : Cast is needed for pointer arithmetic
        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
        m_info[id].endPtr = reinterpret_cast<ptr_t>(reinterpret_cast<uintptr_t>(ptr) + size - 1U);
        if (id > m_maxRegistered)
        {
            m_maxRegistered = id;
        }
        return true;
    }
    return false;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline id_t PointerRepository<id_t, ptr_t, CAPACITY>::registerPtr(const ptr_t ptr, uint64_t size) noexcept
{
    for (id_t id = 1U; id <= MAX_ID; ++id)
    {
        if (m_info[id].basePtr == nullptr)
        {
            m_info[id].basePtr = ptr;
            // AXIVION Next Construct AutosarC++19_03-A5.2.4 : Cast is needed for pointer arithmetic
            // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
            m_info[id].endPtr = reinterpret_cast<ptr_t>(reinterpret_cast<uintptr_t>(ptr) + size - 1U);
            if (id > m_maxRegistered)
            {
                m_maxRegistered = id;
            }
            return id;
        }
    }

    return INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::unregisterPtr(id_t id) noexcept
{
    if (id <= MAX_ID && id >= MIN_ID)
    {
        if (m_info[id].basePtr != nullptr)
        {
            m_info[id].basePtr = nullptr;

            /// @note do not search for next lower registered index but we could do it here
            return true;
        }
    }

    return false;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline void PointerRepository<id_t, ptr_t, CAPACITY>::unregisterAll() noexcept
{
    for (auto& info : m_info)
    {
        info.basePtr = nullptr;
    }
    m_maxRegistered = 0U;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline ptr_t PointerRepository<id_t, ptr_t, CAPACITY>::getBasePtr(id_t id) const noexcept
{
    if (id <= MAX_ID && id >= MIN_ID)
    {
        return m_info[id].basePtr;
    }

    /// @note for id 0 nullptr is returned, meaning we will later interpret a relative pointer by casting the offset
    /// into a pointer (i.e. we measure relative to 0)

    /// @note we cannot distinguish between not registered and nullptr registered, but we do not need to
    return nullptr;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline id_t PointerRepository<id_t, ptr_t, CAPACITY>::searchId(ptr_t ptr) const noexcept
{
    for (id_t id = 1U; id <= m_maxRegistered; ++id)
    {
        // return first id where the ptr is in the corresponding interval
        if (ptr >= m_info[id].basePtr && ptr <= m_info[id].endPtr)
        {
            return id;
        }
    }
    /// @note implicitly interpret the pointer as a regular pointer if not found
    /// by setting id to 0
    /// rationale: test cases work without registered shared memory and require
    /// this at the moment to avoid fundamental changes
    return 0U;
    // return INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline bool PointerRepository<id_t, ptr_t, CAPACITY>::isValid(id_t id) const noexcept
{
    return id != INVALID_ID;
}

template <typename id_t, typename ptr_t, uint64_t CAPACITY>
inline void PointerRepository<id_t, ptr_t, CAPACITY>::print() const noexcept
{
    for (id_t id = 0U; id < m_info.size(); ++id)
    {
        auto ptr = m_info[id].basePtr;
        if (ptr != nullptr)
        {
            std::cout << id << " ---> " << ptr << std::endl;
        }
    }
}

} // namespace rp
} // namespace iox

#endif // IOX_HOOFS_RELOCATABLE_POINTER_POINTER_REPOSITORY_INL
<|endoftext|>


<commit_before>#include <cmath>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <limits>
#include <vector>

#include <ffi.h>
#include <dlfcn.h>

struct Value {
  ffi_type *type;
  union {
    uint8_t u8;
    uint16_t u16;
    uint32_t u32;
    uint64_t u64;
    int8_t s8;
    int16_t s16;
    int32_t s32;
    int64_t s64;
    float f;
    double d;
    void *ptr;
  } value;
};

std::ostream &operator<<(std::ostream &out, const Value &v) {
  if (v.type == &ffi_type_uint8) {
    out << v.value.u8;
  } else if (v.type == &ffi_type_uint16) {
    out << v.value.u16;
  } else if (v.type == &ffi_type_uint32) {
    out << v.value.u32;
  } else if (v.type == &ffi_type_uint64) {
    out << v.value.u64;
  } else if (v.type == &ffi_type_sint8) {
    out << v.value.s8;
  } else if (v.type == &ffi_type_sint16) {
    out << v.value.s16;
  } else if (v.type == &ffi_type_sint32) {
    out << v.value.s32;
  } else if (v.type == &ffi_type_sint64) {
    out << v.value.s64;
  } else if (v.type == &ffi_type_float) {
	float value = v.value.f;
	if(std::isnan(value)) {
		out << "0.0e+NaN";
	} else if(std::isinf(value)) {
		if(value < 0) {
			out << "-1.0e+INF";
		} else {
			out << "1.0e+INF";
		}
	} else {
	    out << value;
	}
  } else if (v.type == &ffi_type_double) {
	double value = v.value.d;
	if(std::isnan(value)) {
		out << "0.0e+NaN";
	} else if(std::isinf(value)) {
		if(value < 0) {
			out << "-1.0e+INF";
		} else {
			out << "1.0e+INF";
		}
	} else {
	    out << value;
	}
  } else if (v.type == &ffi_type_pointer) {
    out << "\\" << v.value.ptr;
  } else if (v.type == &ffi_type_void) {
    out << ":void";
  }
  out << "\n$";
  return out;
}

class FFIStack {
 public:
  void push(uint8_t v) {
    stack_.push_back(Value{&ffi_type_uint8, {.u8 = v}});
  }
  void push(uint16_t v) {
    stack_.push_back(Value{&ffi_type_uint16, {.u16 = v}});
  }
  void push(uint32_t v) {
    stack_.push_back(Value{&ffi_type_uint32, {.u32 = v}});
  }
  void push(uint64_t v) {
    stack_.push_back(Value{&ffi_type_uint64, {.u64 = v}});
  }
  void push(int8_t v) {
    stack_.push_back(Value{&ffi_type_sint8, {.s8 = v}});
  }
  void push(int16_t v) {
    stack_.push_back(Value{&ffi_type_sint16, {.s16 = v}});
  }
  void push(int32_t v) {
    stack_.push_back(Value{&ffi_type_sint32, {.s32 = v}});
  }
  void push(int64_t v) {
    stack_.push_back(Value{&ffi_type_sint64, {.s64 = v}});
  }
  void push(double v) {
    stack_.push_back(Value{&ffi_type_double, {.d = v}});
  }
  void push(float v) {
    stack_.push_back(Value{&ffi_type_float, {.f = v}});
  }
  void push(void *v) {
    stack_.push_back(Value{&ffi_type_pointer, {.ptr = v}});
  }
  void push(Value &v) { stack_.push_back(v); }
  void push() {
    stack_.push_back(Value{&ffi_type_void, {0}});
  }

  Value pop() {
    Value v = stack_.back();
    stack_.pop_back();
    return v;
  }

  Value peek() { return stack_.back(); }

  Value &operator[](int i) { return stack_[stack_.size() - i - 1]; }

  void dup() {
    stack_.push_back(stack_.back());
  }

  size_t size() {
    return stack_.size();
  }

 private:
  std::vector<Value> stack_;
};

class Machine {
 public:
  Machine(std::ostream &out) : out_(out) {
    out.precision(std::numeric_limits<double>::digits10);
  };
  ~Machine() {
    for (auto &i : cifs_) {
      delete i->arg_types;
      delete i;
    }
    for (auto &i : libs_) {
      if (i) dlclose(i);
    }
  };

  FFIStack stack;

  void pop() { out_ << stack.pop(); }

  void peek() { out_ << stack.peek(); }

  void dlopen() {
    const char *name = static_cast<const char *>(stack.pop().value.ptr);
    void *handle = ::dlopen(name, RTLD_LAZY);
    stack.push(handle);
    libs_.push_back(handle);
  }

  void dlsym() {
    const char *name = static_cast<const char *>(stack.pop().value.ptr);
    void *handle = stack.pop().value.ptr;
    void *ptr = ::dlsym(handle, name);
    stack.push(ptr);
  }

  void cif() {
    ffi_cif *cif = new ffi_cif;
    uint32_t nargs = stack.pop().value.u32;
    ffi_type *rtype = stack.pop().type;
    ffi_type **types = new ffi_type*[nargs];
    for (uint32_t i = 0; i < nargs; i++) {
      types[i] = stack.pop().type;
    }
    ffi_prep_cif(cif, FFI_DEFAULT_ABI, nargs, rtype, types);
    stack.push(cif);
    cifs_.push_back(cif);
  }

  void call(bool get_errno) {
    void (*function)() = reinterpret_cast<void (*)()>(stack.pop().value.ptr);
    ffi_cif *cif = static_cast<ffi_cif *>(stack.pop().value.ptr);
    int nargs = cif->nargs;
    void *args[nargs];
    Value result {cif->rtype, {0}};
    for (int i = 0; i < nargs; i++) {
      args[i] = &stack[i].value;
    }
	if(get_errno)
    	errno = 0;
    ffi_call(cif, function, &result.value, args);
    for (int i = 0; i < nargs; i++) {
      stack.pop();
    }
	if(get_errno)
    	stack.push(errno);
    stack.push(result);
  }

  void strlen() {
    char *str = static_cast<char *>(stack.peek().value.ptr);
    uint32_t size = std::strlen(str);
    stack.push(size);
  }

  void dump() {
    uint32_t size = stack.pop().value.u32;
    char *data = static_cast<char *>(stack.pop().value.ptr);
    out_.write(data, size);
  }

  void free() { delete static_cast<char *>(stack.pop().value.ptr); }

  void size() {
    uint32_t size = stack.size();
    stack.push(size);
  }

 private:
  std::ostream &out_;
  std::vector<ffi_cif *> cifs_;
  std::vector<void *> libs_;
};

class Reader {
 public:
  Reader(Machine &vm, std::istream &in) : vm_(vm), in_(in) {};

  void read_uint8() {
    uint8_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_uint16() {
    uint16_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_uint32() {
    uint32_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_uint64() {
    uint64_t i;
    in_ >> i;
    vm_.stack.push(i);
  }

  void read_sint8() {
    int8_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_sint16() {
    int16_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_sint32() {
    int32_t i;
    in_ >> i;
    vm_.stack.push(i);
  }
  void read_sint64() {
    int64_t i;
    in_ >> i;
    vm_.stack.push(i);
  }

  void read_float() {
    float f;
    in_ >> f;
    vm_.stack.push(f);
  }
  void read_double() {
    double d;
    in_ >> d;
    vm_.stack.push(d);
  }

  void read_pointer() {
    void *ptr = nullptr;
    in_ >> ptr;
    vm_.stack.push(ptr);
  }

  void read(uint32_t size) {
    char *buffer = new char[size + 1];
    buffer[size] = '\0';
    in_.read(buffer, size);
    vm_.stack.push(buffer);
  }

 private:
  Machine &vm_;
  std::istream &in_;
};

int main() {
  Machine vm{std::cout};
  Reader reader{vm, std::cin};

  while (!std::cin.eof()) {
    int command = std::cin.get();
    switch (command) {
      /* push signed integer */
      case 'i' + 0: /* i */
        reader.read_sint8();
        break;
      case 'i' + 1: /* j */
        reader.read_sint16();
        break;
      case 'i' + 2: /* k */
        reader.read_sint32();
        break;
      case 'i' + 3: /* l */
        reader.read_sint64();
        break;

      /* push unsigned integer */
      case 'u' + 0: /* u */
        reader.read_uint8();
        break;
      case 'u' + 1: /* v */
        reader.read_uint16();
        break;
      case 'u' + 2: /* w */
        reader.read_uint32();
        break;
      case 'u' + 3: /* x */
        reader.read_uint64();
        break;

      /* push float */
      case 'f':
        reader.read_float();
        break;
      case 'd':
        reader.read_double();
        break;

      /* push pointer */
      case 'p':
        reader.read_pointer();
        break;

      /* push void */
      case 'V':
        vm.stack.push();
        break;

      /* peek */
      case 'e':
        vm.peek();
        break;

      /* pop */
      case 'o':
        vm.pop();
        break;

      /* call */
      case 'c':
        vm.call(false);
        break;

      /* call with errno */
      case 'E':
        vm.call(true);
        break;

      /* call */
      case 'C':
        vm.cif();
        break;

      /* "malloc" */
      case 'M':
        reader.read(vm.stack.pop().value.u32);
        break;

      /* free */
      case 'F':
        vm.free();
        break;

      /* dl calls */
      case 'O':
        vm.dlopen();
        break;
      case 'S':
        vm.dlsym();
        break;

      /* strlen */
      case 'L':
        vm.strlen();
        break;

      /* dump */
      case 'D':
        vm.dump();
        break;

      /* duplicate top value */
      case '!':
        vm.stack.dup();
        break;

      /* get stack size */
      case '?':
        vm.size();
        break;

      /* no-op */
      case ' ':
      case '\n':
      case '\r':
      case -1:
        break;

      default:
        std::cerr << "invalid op: " << static_cast<char>(command) << std::endl;
        break;
    }
    std::cout.flush();
  }

  std::cout << std::endl;
  return 0;
}
<commit_msg>Changes all indents to 4 spaces.<commit_after>#include <cmath>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <limits>
#include <vector>

#include <ffi.h>
#include <dlfcn.h>

struct Value {
    ffi_type *type;
    union {
        uint8_t u8;
        uint16_t u16;
        uint32_t u32;
        uint64_t u64;
        int8_t s8;
        int16_t s16;
        int32_t s32;
        int64_t s64;
        float f;
        double d;
        void *ptr;
    } value;
};

std::ostream &operator<<(std::ostream &out, const Value &v) {
    if (v.type == &ffi_type_uint8) {
        out << v.value.u8;
    } else if (v.type == &ffi_type_uint16) {
        out << v.value.u16;
    } else if (v.type == &ffi_type_uint32) {
        out << v.value.u32;
    } else if (v.type == &ffi_type_uint64) {
        out << v.value.u64;
    } else if (v.type == &ffi_type_sint8) {
        out << v.value.s8;
    } else if (v.type == &ffi_type_sint16) {
        out << v.value.s16;
    } else if (v.type == &ffi_type_sint32) {
        out << v.value.s32;
    } else if (v.type == &ffi_type_sint64) {
        out << v.value.s64;
    } else if (v.type == &ffi_type_float) {
        float value = v.value.f;
        if(std::isnan(value)) {
            out << "0.0e+NaN";
        } else if(std::isinf(value)) {
            if(value < 0) {
                out << "-1.0e+INF";
            } else {
                out << "1.0e+INF";
            }
        } else {
            out << value;
        }
    } else if (v.type == &ffi_type_double) {
        double value = v.value.d;
        if(std::isnan(value)) {
            out << "0.0e+NaN";
        } else if(std::isinf(value)) {
            if(value < 0) {
                out << "-1.0e+INF";
            } else {
                out << "1.0e+INF";
            }
        } else {
            out << value;
        }
    } else if (v.type == &ffi_type_pointer) {
        out << "\\" << v.value.ptr;
    } else if (v.type == &ffi_type_void) {
        out << ":void";
    }
    out << "\n$";
    return out;
}

class FFIStack {
public:
    void push(uint8_t v) {
        stack_.push_back(Value{&ffi_type_uint8, {.u8 = v}});
    }
    void push(uint16_t v) {
        stack_.push_back(Value{&ffi_type_uint16, {.u16 = v}});
    }
    void push(uint32_t v) {
        stack_.push_back(Value{&ffi_type_uint32, {.u32 = v}});
    }
    void push(uint64_t v) {
        stack_.push_back(Value{&ffi_type_uint64, {.u64 = v}});
    }
    void push(int8_t v) {
        stack_.push_back(Value{&ffi_type_sint8, {.s8 = v}});
    }
    void push(int16_t v) {
        stack_.push_back(Value{&ffi_type_sint16, {.s16 = v}});
    }
    void push(int32_t v) {
        stack_.push_back(Value{&ffi_type_sint32, {.s32 = v}});
    }
    void push(int64_t v) {
        stack_.push_back(Value{&ffi_type_sint64, {.s64 = v}});
    }
    void push(double v) {
        stack_.push_back(Value{&ffi_type_double, {.d = v}});
    }
    void push(float v) {
        stack_.push_back(Value{&ffi_type_float, {.f = v}});
    }
    void push(void *v) {
        stack_.push_back(Value{&ffi_type_pointer, {.ptr = v}});
    }
    void push(Value &v) { stack_.push_back(v); }
    void push() {
        stack_.push_back(Value{&ffi_type_void, {0}});
    }

    Value pop() {
        Value v = stack_.back();
        stack_.pop_back();
        return v;
    }

    Value peek() { return stack_.back(); }

    Value &operator[](int i) { return stack_[stack_.size() - i - 1]; }

    void dup() {
        stack_.push_back(stack_.back());
    }

    size_t size() {
        return stack_.size();
    }

private:
    std::vector<Value> stack_;
};

class Machine {
public:
    Machine(std::ostream &out) : out_(out) {
        out.precision(std::numeric_limits<double>::digits10);
    };
    ~Machine() {
        for (auto &i : cifs_) {
            delete i->arg_types;
            delete i;
        }
        for (auto &i : libs_) {
            if (i) dlclose(i);
        }
    };

    FFIStack stack;

    void pop() { out_ << stack.pop(); }

    void peek() { out_ << stack.peek(); }

    void dlopen() {
        const char *name = static_cast<const char *>(stack.pop().value.ptr);
        void *handle = ::dlopen(name, RTLD_LAZY);
        stack.push(handle);
        libs_.push_back(handle);
    }

    void dlsym() {
        const char *name = static_cast<const char *>(stack.pop().value.ptr);
        void *handle = stack.pop().value.ptr;
        void *ptr = ::dlsym(handle, name);
        stack.push(ptr);
    }

    void cif() {
        ffi_cif *cif = new ffi_cif;
        uint32_t nargs = stack.pop().value.u32;
        ffi_type *rtype = stack.pop().type;
        ffi_type **types = new ffi_type*[nargs];
        for (uint32_t i = 0; i < nargs; i++) {
            types[i] = stack.pop().type;
        }
        ffi_prep_cif(cif, FFI_DEFAULT_ABI, nargs, rtype, types);
        stack.push(cif);
        cifs_.push_back(cif);
    }

    void call(bool get_errno) {
        void (*function)() = reinterpret_cast<void (*)()>(stack.pop().value.ptr);
        ffi_cif *cif = static_cast<ffi_cif *>(stack.pop().value.ptr);
        int nargs = cif->nargs;
        void *args[nargs];
        Value result {cif->rtype, {0}};
        for (int i = 0; i < nargs; i++) {
            args[i] = &stack[i].value;
        }
        if(get_errno)
            errno = 0;
        ffi_call(cif, function, &result.value, args);
        for (int i = 0; i < nargs; i++) {
            stack.pop();
        }
        if(get_errno)
            stack.push(errno);
        stack.push(result);
    }

    void strlen() {
        char *str = static_cast<char *>(stack.peek().value.ptr);
        uint32_t size = std::strlen(str);
        stack.push(size);
    }

    void dump() {
        uint32_t size = stack.pop().value.u32;
        char *data = static_cast<char *>(stack.pop().value.ptr);
        out_.write(data, size);
    }

    void free() { delete static_cast<char *>(stack.pop().value.ptr); }

    void size() {
        uint32_t size = stack.size();
        stack.push(size);
    }

private:
    std::ostream &out_;
    std::vector<ffi_cif *> cifs_;
    std::vector<void *> libs_;
};

class Reader {
public:
    Reader(Machine &vm, std::istream &in) : vm_(vm), in_(in) {};

    void read_uint8() {
        uint8_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_uint16() {
        uint16_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_uint32() {
        uint32_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_uint64() {
        uint64_t i;
        in_ >> i;
        vm_.stack.push(i);
    }

    void read_sint8() {
        int8_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_sint16() {
        int16_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_sint32() {
        int32_t i;
        in_ >> i;
        vm_.stack.push(i);
    }
    void read_sint64() {
        int64_t i;
        in_ >> i;
        vm_.stack.push(i);
    }

    void read_float() {
        float f;
        in_ >> f;
        vm_.stack.push(f);
    }
    void read_double() {
        double d;
        in_ >> d;
        vm_.stack.push(d);
    }

    void read_pointer() {
        void *ptr = nullptr;
        in_ >> ptr;
        vm_.stack.push(ptr);
    }

    void read(uint32_t size) {
        char *buffer = new char[size + 1];
        buffer[size] = '\0';
        in_.read(buffer, size);
        vm_.stack.push(buffer);
    }

private:
    Machine &vm_;
    std::istream &in_;
};

int main() {
    Machine vm{std::cout};
    Reader reader{vm, std::cin};

    while (!std::cin.eof()) {
        int command = std::cin.get();
        switch (command) {
        /* push signed integer */
        case 'i' + 0: /* i */
            reader.read_sint8();
            break;
        case 'i' + 1: /* j */
            reader.read_sint16();
            break;
        case 'i' + 2: /* k */
            reader.read_sint32();
            break;
        case 'i' + 3: /* l */
            reader.read_sint64();
            break;

        /* push unsigned integer */
        case 'u' + 0: /* u */
            reader.read_uint8();
            break;
        case 'u' + 1: /* v */
            reader.read_uint16();
            break;
        case 'u' + 2: /* w */
            reader.read_uint32();
            break;
        case 'u' + 3: /* x */
            reader.read_uint64();
            break;

        /* push float */
        case 'f':
            reader.read_float();
            break;
        case 'd':
            reader.read_double();
            break;

        /* push pointer */
        case 'p':
            reader.read_pointer();
            break;

        /* push void */
        case 'V':
            vm.stack.push();
            break;

        /* peek */
        case 'e':
            vm.peek();
            break;

        /* pop */
        case 'o':
            vm.pop();
            break;

        /* call */
        case 'c':
            vm.call(false);
            break;

        /* call with errno */
        case 'E':
            vm.call(true);
            break;

        /* call */
        case 'C':
            vm.cif();
            break;

        /* "malloc" */
        case 'M':
            reader.read(vm.stack.pop().value.u32);
            break;

        /* free */
        case 'F':
            vm.free();
            break;

        /* dl calls */
        case 'O':
            vm.dlopen();
            break;
        case 'S':
            vm.dlsym();
            break;

        /* strlen */
        case 'L':
            vm.strlen();
            break;

        /* dump */
        case 'D':
            vm.dump();
            break;

        /* duplicate top value */
        case '!':
            vm.stack.dup();
            break;

        /* get stack size */
        case '?':
            vm.size();
            break;

        /* no-op */
        case ' ':
        case '\n':
        case '\r':
        case -1:
            break;

        default:
            std::cerr << "invalid op: " << static_cast<char>(command) << std::endl;
            break;
        }
        std::cout.flush();
    }

    std::cout << std::endl;
    return 0;
}
<|endoftext|>