<commit_before>#pragma once
#include "atlas/mesh.h"
#include <cassert>

namespace utility {
namespace impl_ {
template <typename Integer>
class irange_ {
public:
  class iterator {
  public:
    Integer operator*() const { return i_; }
    const iterator& operator++() {
      ++i_;
      return *this;
    }
    iterator operator++(int) {
      iterator copy(*this);
      ++i_;
      return copy;
    }

    bool operator==(const iterator& other) const { return i_ == other.i_; }
    bool operator!=(const iterator& other) const { return i_ != other.i_; }

    iterator(Integer start) : i_(start) {}

  private:
    Integer i_;
  };

  iterator begin() const { return begin_; }
  iterator end() const { return end_; }
  irange_(Integer begin, Integer end) : begin_(begin), end_(end) {}

private:
  iterator begin_;
  iterator end_;
};
} // namespace impl_
template <typename Integer>
impl_::irange_<Integer> irange(Integer from, Integer to) {
  return {from, to};
}
} // namespace utility

namespace atlasInterface {

struct atlasTag {};

template <typename T>
class Field {
public:
  T const& operator()(int f) const { return atlas_field_(f, 0); }
  T& operator()(int f) { return atlas_field_(f, 0); }

  Field(atlas::array::ArrayView<T, 2> const& atlas_field) : atlas_field_(atlas_field) {}

private:
  atlas::array::ArrayView<T, 2> atlas_field_;
};

template <typename T>
Field<T> cellFieldType(atlasTag);
template <typename T>
Field<T> edgeFieldType(atlasTag);
template <typename T>
Field<T> vertexFieldType(atlasTag);

atlas::Mesh meshType(atlasTag);

auto getCells(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.cells().size()); }
auto getEdges(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.edges().size()); }
auto getVertices(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.nodes().size()); }

std::vector<int> const& cellNeighboursOfCell(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    const auto& conn = m.cells().edge_connectivity();
    neighs[idx] = std::vector<int>{};
    for(int n = 0; n < conn.cols(idx); ++n) {
      int initialEdge = conn(idx, n);
      for(int c1 = 0; c1 < m.cells().size(); ++c1) {
        for(int n1 = 0; n1 < conn.cols(c1); ++n1) {
          int compareEdge = conn(c1, n1);
          if(initialEdge == compareEdge && c1 != idx) {
            neighs[idx].emplace_back(c1);
          }
        }
      }
    }
  }
  return neighs[idx];
}

std::vector<int> const& edgeNeighboursOfCell(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    const auto& conn = m.cells().edge_connectivity();
    neighs[idx] = std::vector<int>{};
    for(int n = 0; n < conn.cols(idx); ++n) {
      neighs[idx].emplace_back(conn(idx, n));
    }
  }
  return neighs[idx];
}

template <typename Init, typename Op>
auto reduceCellToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : cellNeighboursOfCell(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceEdgeToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : edgeNeighboursOfCell(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceVertexToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}

template <typename Init, typename Op>
auto reduceCellToEdge(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}
template <typename Init, typename Op>
auto reduceVertexToEdge(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}

template <typename Init, typename Op>
auto reduceCellToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}
template <typename Init, typename Op>
auto reduceEdgeToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}
template <typename Init, typename Op>
auto reduceVertexToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  assert(false && "function not implemented in the atlas back end");
  return 1;
}

} // namespace atlasInterface
<commit_msg>extended atlas interface to include all possible reductions (#440)<commit_after>#pragma once
#include "atlas/mesh.h"
#include <cassert>

namespace utility {
namespace impl_ {
template <typename Integer>
class irange_ {
public:
  class iterator {
  public:
    Integer operator*() const { return i_; }
    const iterator& operator++() {
      ++i_;
      return *this;
    }
    iterator operator++(int) {
      iterator copy(*this);
      ++i_;
      return copy;
    }

    bool operator==(const iterator& other) const { return i_ == other.i_; }
    bool operator!=(const iterator& other) const { return i_ != other.i_; }

    iterator(Integer start) : i_(start) {}

  private:
    Integer i_;
  };

  iterator begin() const { return begin_; }
  iterator end() const { return end_; }
  irange_(Integer begin, Integer end) : begin_(begin), end_(end) {}

private:
  iterator begin_;
  iterator end_;
};
} // namespace impl_
template <typename Integer>
impl_::irange_<Integer> irange(Integer from, Integer to) {
  return {from, to};
}
} // namespace utility

namespace atlasInterface {

struct atlasTag {};

template <typename T>
class Field {
public:
  T const& operator()(int f) const { return atlas_field_(f, 0); }
  T& operator()(int f) { return atlas_field_(f, 0); }

  Field(atlas::array::ArrayView<T, 2> const& atlas_field) : atlas_field_(atlas_field) {}

private:
  atlas::array::ArrayView<T, 2> atlas_field_;
};

template <typename T>
Field<T> cellFieldType(atlasTag);
template <typename T>
Field<T> edgeFieldType(atlasTag);
template <typename T>
Field<T> vertexFieldType(atlasTag);

atlas::Mesh meshType(atlasTag);

auto getCells(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.cells().size()); }
auto getEdges(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.edges().size()); }
auto getVertices(atlasTag, atlas::Mesh const& m) { return utility::irange(0, m.nodes().size()); }

std::vector<int> getNeighs(const atlas::Mesh::HybridElements::Connectivity& conn, int idx) {
  std::vector<int> neighs;
  for(int n = 0; n < conn.cols(idx); ++n) {
    neighs.emplace_back(conn(idx, n));
  }
  return neighs;
}

std::vector<int> const& cellNeighboursOfCell(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    const auto& conn = m.cells().edge_connectivity();
    neighs[idx] = std::vector<int>{};
    for(int n = 0; n < conn.cols(idx); ++n) {
      int initialEdge = conn(idx, n);
      for(int c1 = 0; c1 < m.cells().size(); ++c1) {
        for(int n1 = 0; n1 < conn.cols(c1); ++n1) {
          int compareEdge = conn(c1, n1);
          if(initialEdge == compareEdge && c1 != idx) {
            neighs[idx].emplace_back(c1);
          }
        }
      }
    }
  }
  return neighs[idx];
}

std::vector<int> const& edgeNeighboursOfCell(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().edge_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> const& nodeNeighboursOfCell(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().node_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> cellNeighboursOfEdge(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().cell_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> nodeNeighboursOfEdge(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().node_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> cellNeighboursOfNode(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().cell_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> edgeNeighboursOfNode(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    neighs[idx] = getNeighs(m.cells().edge_connectivity(), idx);
  }
  return neighs[idx];
}

std::vector<int> nodeNeighboursOfNode(atlas::Mesh const& m, int const& idx) {
  // note this is only a workaround and does only work as long as we have only one mesh
  static std::map<int, std::vector<int>> neighs;
  if(neighs.count(idx) == 0) {
    const auto& conn_nodes_to_edge = m.nodes().edge_connectivity();
    neighs[idx] = std::vector<int>{};
    for(int ne = 0; ne < conn_nodes_to_edge.cols(idx); ++ne) {
      int nbh_edge_idx = conn_nodes_to_edge(idx, ne);
      const auto& conn_edge_to_nodes = m.edges().node_connectivity();
      for(int nn = 0; nn < conn_edge_to_nodes.cols(nbh_edge_idx); ++nn) {
        int nbhNode = conn_edge_to_nodes(idx, nn);
        if(nbhNode != idx) {
          neighs[idx].emplace_back();
        }
      }
    }
  }
  return neighs[idx];
}

template <typename Init, typename Op>
auto reduceCellToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : cellNeighboursOfCell(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceEdgeToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : edgeNeighboursOfCell(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceVertexToCell(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : nodeNeighboursOfCell(m, idx))
    op(init, obj);
  return init;
}

template <typename Init, typename Op>
auto reduceCellToEdge(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : cellNeighboursOfEdge(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceVertexToEdge(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : nodeNeighboursOfEdge(m, idx))
    op(init, obj);
  return init;
}

template <typename Init, typename Op>
auto reduceCellToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : cellNeighboursOfNode(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceEdgeToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : edgeNeighboursOfNode(m, idx))
    op(init, obj);
  return init;
}
template <typename Init, typename Op>
auto reduceVertexToVertex(atlasTag, atlas::Mesh const& m, int idx, Init init, Op&& op) {
  for(auto&& obj : nodeNeighboursOfNode(m, idx))
    op(init, obj);
  return init;
}

} // namespace atlasInterface
<|endoftext|>


<commit_before>#include <iostream>

#include "headers/uhdm.h"
#include "headers/vpi_visitor.h"

using namespace UHDM;

#include "vpi_visitor.h"

std::vector<vpiHandle> build_designs (Serializer& s) {
  std::vector<vpiHandle> designs;
  // Design building
  design* d = s.MakeDesign();
  d->VpiName("designTF");
  module* m1 = s.MakeModule();
  m1->VpiTopModule(true);
  m1->VpiDefName("M1");
  m1->VpiParent(d);
  m1->VpiFile("fake1.sv");
  m1->VpiLineNo(10);

  initial* init = s.MakeInitial();
  VectorOfprocess* processes = s.MakeProcessVec();
  processes->push_back(init);
  begin* begin_block = s.MakeBegin();
  init->Stmt(begin_block);
  VectorOfany* statements = s.MakeAnyVec();

  sys_func_call* display = s.MakeSys_func_call();
  display->VpiName("display");
  VectorOfany *arguments = s.MakeAnyVec();
  constant* cA = s.MakeConstant();
  cA->VpiValue("INT:0");
  arguments->push_back(cA);
  constant* cA1 = s.MakeConstant();
  cA1->VpiValue("INT:8");
  arguments->push_back(cA1);
  display->Tf_call_args(arguments);
  statements->push_back(display);

  func_call* my_func_call = s.MakeFunc_call();
  function* my_func = s.MakeFunction();
  my_func->VpiName("a_func");
  my_func_call->Function(my_func);
  VectorOfany *arguments2 = s.MakeAnyVec();
  constant* cA2 = s.MakeConstant();
  cA2->VpiValue("INT:1");
  arguments2->push_back(cA2);
  constant* cA3 = s.MakeConstant();
  cA3->VpiValue("INT:2");
  arguments2->push_back(cA3);
  my_func_call->Tf_call_args(arguments2);
  statements->push_back(my_func_call);

  begin_block->Stmts(statements);
  m1->Process(processes);

  VectorOfmodule* v1 = s.MakeModuleVec();
  v1->push_back(m1);
  d->AllModules(v1);

  package* p1 = s.MakePackage();
  p1->VpiDefName("P0");
  VectorOfpackage* v3 = s.MakePackageVec();
  v3->push_back(p1);
  d->AllPackages(v3);
  designs.push_back(s.MakeUhdmHandle(uhdmdesign, d));
  return designs;
}

int main (int argc, char** argv) {
  std::cout << "Make design" << std::endl;
  Serializer serializer;

  std::string orig = visit_designs(build_designs(serializer));

  std::cout << orig;
  std::cout << "\nSave design" << std::endl;
  serializer.Save("surelog3.uhdm");

  std::cout << "Restore design" << std::endl;
  std::vector<vpiHandle> restoredDesigns = serializer.Restore("surelog3.uhdm");

  std::string restored = visit_designs(restoredDesigns);
  std::cout << restored;
  return (orig != restored);
}
<commit_msg>Change file name in test_tf_call<commit_after>#include <iostream>

#include "headers/uhdm.h"
#include "headers/vpi_visitor.h"

using namespace UHDM;

#include "vpi_visitor.h"

std::vector<vpiHandle> build_designs (Serializer& s) {
  std::vector<vpiHandle> designs;
  // Design building
  design* d = s.MakeDesign();
  d->VpiName("designTF");
  module* m1 = s.MakeModule();
  m1->VpiTopModule(true);
  m1->VpiDefName("M1");
  m1->VpiParent(d);
  m1->VpiFile("fake1.sv");
  m1->VpiLineNo(10);

  initial* init = s.MakeInitial();
  VectorOfprocess* processes = s.MakeProcessVec();
  processes->push_back(init);
  begin* begin_block = s.MakeBegin();
  init->Stmt(begin_block);
  VectorOfany* statements = s.MakeAnyVec();

  sys_func_call* display = s.MakeSys_func_call();
  display->VpiName("display");
  VectorOfany *arguments = s.MakeAnyVec();
  constant* cA = s.MakeConstant();
  cA->VpiValue("INT:0");
  arguments->push_back(cA);
  constant* cA1 = s.MakeConstant();
  cA1->VpiValue("INT:8");
  arguments->push_back(cA1);
  display->Tf_call_args(arguments);
  statements->push_back(display);

  func_call* my_func_call = s.MakeFunc_call();
  function* my_func = s.MakeFunction();
  my_func->VpiName("a_func");
  my_func_call->Function(my_func);
  VectorOfany *arguments2 = s.MakeAnyVec();
  constant* cA2 = s.MakeConstant();
  cA2->VpiValue("INT:1");
  arguments2->push_back(cA2);
  constant* cA3 = s.MakeConstant();
  cA3->VpiValue("INT:2");
  arguments2->push_back(cA3);
  my_func_call->Tf_call_args(arguments2);
  statements->push_back(my_func_call);

  begin_block->Stmts(statements);
  m1->Process(processes);

  VectorOfmodule* v1 = s.MakeModuleVec();
  v1->push_back(m1);
  d->AllModules(v1);

  package* p1 = s.MakePackage();
  p1->VpiDefName("P0");
  VectorOfpackage* v3 = s.MakePackageVec();
  v3->push_back(p1);
  d->AllPackages(v3);
  designs.push_back(s.MakeUhdmHandle(uhdmdesign, d));
  return designs;
}

int main (int argc, char** argv) {
  std::cout << "Make design" << std::endl;
  Serializer serializer;

  std::string orig = visit_designs(build_designs(serializer));

  std::cout << orig;
  std::cout << "\nSave design" << std::endl;
  serializer.Save("surelog_tf_call.uhdm");

  std::cout << "Restore design" << std::endl;
  std::vector<vpiHandle> restoredDesigns = serializer.Restore("surelog_tf_call.uhdm");

  std::string restored = visit_designs(restoredDesigns);
  std::cout << restored;
  return (orig != restored);
}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "Message.h"
#include "FakeMessenger.h"
#include "mds/MDS.h"

#include "common/Timer.h"

#include "common/LogType.h"
#include "common/Logger.h"

#include "config.h"

#undef dout
#define dout(x) if ((x) <= g_conf.debug_ms) cout << g_clock.now() << " "

#include <stdio.h>
#include <stdlib.h>
#include <map>
#include <cassert>
#include <iostream>

using namespace std;

#include <ext/hash_map>
using namespace __gnu_cxx;

#include "common/Cond.h"
#include "common/Mutex.h"
#include <pthread.h>

// global queue.

int nranks = 0;  // this identify each entity_inst_t

map<entity_addr_t, FakeMessenger*>      directory;
hash_map<int, Logger*>        loggers;
LogType fakemsg_logtype;

set<entity_addr_t>           shutdown_set;

Mutex lock;
Cond  cond;

bool      awake = false;
bool      fm_shutdown = false;
pthread_t thread_id;

extern std::map<entity_name_t,float> g_fake_kill_after;  // in config.cc
utime_t start_time;
map<utime_t,entity_name_t> fail_queue;
list<Message*> sent_to_failed_queue;

void *fakemessenger_thread(void *ptr)
{
  start_time = g_clock.now();

  lock.Lock();
  while (1) {
    if (fm_shutdown) break;
    fakemessenger_do_loop_2();

    if (directory.empty() && nranks > 0) break;

    dout(20) << "thread waiting" << endl;
    if (fm_shutdown) break;
    awake = false;
    cond.Wait(lock);
    awake = true;
    dout(20) << "thread woke up" << endl;
  }
  lock.Unlock();

  dout(1) << "thread finish (i woke up but no messages, bye)" << endl;
  return 0;
}

void fakemessenger_startthread() {
  pthread_create(&thread_id, NULL, fakemessenger_thread, 0);
}

void fakemessenger_stopthread() {
  cout << "fakemessenger_stopthread setting stop flag" << endl;
  lock.Lock();
  fm_shutdown = true;
  lock.Unlock();
  cond.Signal();

  fakemessenger_wait();
}

void fakemessenger_wait()
{
  cout << "fakemessenger_wait waiting" << endl;
  void *ptr;
  pthread_join(thread_id, &ptr);
}

// fake failure

// lame main looper

int fakemessenger_do_loop()
{
  lock.Lock();
  fakemessenger_do_loop_2();
  lock.Unlock();

  g_timer.shutdown();
  return 0;
}

int fakemessenger_do_loop_2()
{
  //lock.Lock();
  dout(18) << "do_loop begin." << endl;

  while (1) {
    bool didone = false;

    dout(18) << "do_loop top" << endl;

    // fail_queue
    while (!fail_queue.empty() &&
	   fail_queue.begin()->first < g_clock.now()) {
      entity_name_t nm = fail_queue.begin()->second;
      fail_queue.erase(fail_queue.begin());

      dout(0) << "MUST FAKE KILL " << nm << endl;

      for (map<entity_addr_t, FakeMessenger*>::iterator p = directory.begin();
	   p != directory.end();
	   ++p) {
	if (p->second->get_myname() == nm) {
	  dout(0) << "FAKING FAILURE of " << nm << " at " << p->first << endl;
	  directory.erase(p);
	  p->second->failed = true;
	  break;
	}
      }
    }

    list<Message*> ls;
    ls.swap(sent_to_failed_queue);
    for (list<Message*>::iterator p = ls.begin();
	 p != ls.end();
	 ++p) {
      Message *m = *p;
      FakeMessenger *mgr = directory[m->get_source_addr()];
      Dispatcher *dis = 0;
      if (mgr) dis = mgr->get_dispatcher();
      if (dis) {
	dout(1) << "fail on " << *m
		<< " to " << m->get_dest() << " from " << m->get_source()
		<< ", passing back to sender." << endl;
	dis->ms_handle_failure(m, m->get_dest_inst());
      } else {
	dout(1) << "fail on " << *m
		<< " to " << m->get_dest() << " from " << m->get_source()
		<< ", sender gone, dropping." << endl;
	delete m;
      }
    }

    // messages
    map<entity_addr_t, FakeMessenger*>::iterator it = directory.begin();
    while (it != directory.end()) {
      FakeMessenger *mgr = it->second;

      dout(18) << "messenger " << mgr << " at " << mgr->get_myname() << " has " << mgr->num_incoming() << " queued" << endl;

      if (!mgr->is_ready()) {
        dout(18) << "messenger " << mgr << " at " << mgr->get_myname() << " has no dispatcher, skipping" << endl;
        it++;
        continue;
      }

      Message *m = mgr->get_message();
      it++;

      if (m) {
        //dout(18) << "got " << m << endl;
        dout(1) << "==== " << m->get_dest()
		<< " <- " << m->get_source()
                << " ==== " << *m
		<< " ---- " << m
                << endl;

        if (g_conf.fakemessenger_serialize) {
          // encode
          if (m->empty_payload())
            m->encode_payload();
          msg_envelope_t env = m->get_envelope();
          bufferlist bl;
          bl.claim( m->get_payload() );
          //bl.c_str();   // condense into 1 buffer

          delete m;

          // decode
          m = decode_message(env, bl);
          assert(m);
        }

        didone = true;

        lock.Unlock();
        mgr->dispatch(m);
        lock.Lock();
      }
    }

    // deal with shutdowns.. delayed to avoid concurrent directory modification
    if (!shutdown_set.empty()) {
      for (set<entity_addr_t>::iterator it = shutdown_set.begin();
           it != shutdown_set.end();
           it++) {
        dout(7) << "fakemessenger: removing " << *it << " from directory" << endl;
        assert(directory.count(*it));
        directory.erase(*it);
        if (directory.empty()) {
          dout(1) << "fakemessenger: last shutdown" << endl;
          ::fm_shutdown = true;
        }
      }
      shutdown_set.clear();
    }

    if (!didone)
      break;
  }

  dout(18) << "do_loop end (no more messages)." << endl;
  //lock.Unlock();
  return 0;
}

FakeMessenger::FakeMessenger(entity_name_t me)  : Messenger(me)
{
  failed = false;

  lock.Lock();
  {
    // assign rank
    _myinst.name = me;
    _myinst.addr.port = nranks++;
    //if (!me.is_mon())
    _myinst.addr.nonce = getpid();

    // add to directory
    directory[ _myinst.addr ] = this;

    // put myself in the fail queue?
    if (g_fake_kill_after.count(me)) {
      utime_t w = start_time;
      w += g_fake_kill_after[me];
      dout(0) << "will fake failure of " << me << " at " << w << endl;
      fail_queue[w] = me;
    }
  }
  lock.Unlock();

  cout << "fakemessenger " << get_myname() << " messenger is " << this << " at " << _myinst << endl;

  qlen = 0;

  /*
  string name;
  name = "m.";
  name += MSG_ADDR_TYPE(myaddr);
  int w = MSG_ADDR_NUM(myaddr);
  if (w >= 1000) name += ('0' + ((w/1000)%10));
  if (w >= 100) name += ('0' + ((w/100)%10));
  if (w >= 10) name += ('0' + ((w/10)%10));
  name += ('0' + ((w/1)%10));

  loggers[ myaddr ] = new Logger(name, (LogType*)&fakemsg_logtype);
  */
}

FakeMessenger::~FakeMessenger()
{
  // hose any undelivered messages
  for (list<Message*>::iterator p = incoming.begin();
       p != incoming.end();
       ++p)
    delete *p;
}

int FakeMessenger::shutdown()
{
  //cout << "shutdown on messenger " << this << " has " << num_incoming() << " queued" << endl;
  lock.Lock();
  assert(directory.count(_myinst.addr) == 1);
  shutdown_set.insert(_myinst.addr);

  /*
  if (loggers[myaddr]) {
    delete loggers[myaddr];
    loggers.erase(myaddr);
  }
  */

  lock.Unlock();
  return 0;
}

void FakeMessenger::reset_myname(entity_name_t m)
{
  dout(1) << "reset_myname from " << get_myname() << " to " << m << endl;
  _set_myname(m);

  directory.erase(_myinst.addr);
  _myinst.name = m;
  directory[_myinst.addr] = this;

  // put myself in the fail queue?
  if (g_fake_kill_after.count(m)) {
    utime_t w = start_time;
    w += g_fake_kill_after[m];
    dout(0) << "will fake failure of " << m << " at " << w << endl;
    fail_queue[w] = m;
  }

}

int FakeMessenger::send_message(Message *m, entity_inst_t inst, int port, int fromport)
{
  entity_name_t dest = inst.name;

  m->set_source(get_myname(), fromport);
  m->set_source_addr(get_myaddr());

  m->set_dest_inst(inst);
  m->set_dest_port(port);

  lock.Lock();

#ifdef LOG_MESSAGES
  // stats
  loggers[get_myaddr()]->inc("+send",1);
  loggers[dest]->inc("-recv",1);

  char s[20];
  sprintf(s,"+%s", m->get_type_name());
  loggers[get_myaddr()]->inc(s);
  sprintf(s,"-%s", m->get_type_name());
  loggers[dest]->inc(s);
#endif

  // queue
  if (directory.count(inst.addr) &&
      shutdown_set.count(inst.addr) == 0) {
    dout(1) << "--> " << get_myname() << " -> " << inst.name << " --- " << *m << " -- " << m
	    << endl;
    directory[inst.addr]->queue_incoming(m);
  } else {
    dout(0) << "--> " << get_myname() << " -> " << inst.name << " " << *m << " -- " << m
	    << " *** destination " << inst.addr << " DNE ***"
	    << endl;
    for (map<entity_addr_t, FakeMessenger*>::iterator p = directory.begin();
	 p != directory.end();
	 ++p) {
      dout(20) << "** have " << p->first << " to " << p->second << endl;
    }

    // do the failure callback
    sent_to_failed_queue.push_back(m);
  }

  // wake up loop?
  if (!awake) {
    dout(10) << "waking up fakemessenger thread" << endl;
    cond.Signal();
    lock.Unlock();
  } else
    lock.Unlock();

  return 0;
}

<commit_msg>locked debug output<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "Message.h"
#include "FakeMessenger.h"
#include "mds/MDS.h"

#include "common/Timer.h"

#include "common/LogType.h"
#include "common/Logger.h"

#include "config.h"

#include "debug.h"
#undef dout
#define dout(x) if ((x) <= g_conf.debug_ms) cout << dbeginl << g_clock.now() << " "

#include <stdio.h>
#include <stdlib.h>
#include <map>
#include <cassert>
#include <iostream>

using namespace std;

#include <ext/hash_map>
using namespace __gnu_cxx;

#include "common/Cond.h"
#include "common/Mutex.h"
#include <pthread.h>

// global queue.

int nranks = 0;  // this identify each entity_inst_t

map<entity_addr_t, FakeMessenger*>      directory;
hash_map<int, Logger*>        loggers;
LogType fakemsg_logtype;

set<entity_addr_t>           shutdown_set;

Mutex lock;
Cond  cond;

bool      awake = false;
bool      fm_shutdown = false;
pthread_t thread_id;

extern std::map<entity_name_t,float> g_fake_kill_after;  // in config.cc
utime_t start_time;
map<utime_t,entity_name_t> fail_queue;
list<Message*> sent_to_failed_queue;

void *fakemessenger_thread(void *ptr)
{
  start_time = g_clock.now();

  lock.Lock();
  while (1) {
    if (fm_shutdown) break;
    fakemessenger_do_loop_2();

    if (directory.empty() && nranks > 0) break;

    dout(20) << "thread waiting" << dendl;
    if (fm_shutdown) break;
    awake = false;
    cond.Wait(lock);
    awake = true;
    dout(20) << "thread woke up" << dendl;
  }
  lock.Unlock();

  dout(1) << "thread finish (i woke up but no messages, bye)" << dendl;
  return 0;
}

void fakemessenger_startthread() {
  pthread_create(&thread_id, NULL, fakemessenger_thread, 0);
}

void fakemessenger_stopthread() {
  dout(0) << "fakemessenger_stopthread setting stop flag" << dendl;
  lock.Lock();
  fm_shutdown = true;
  lock.Unlock();
  cond.Signal();

  fakemessenger_wait();
}

void fakemessenger_wait()
{
  dout(0) << "fakemessenger_wait waiting" << dendl;
  void *ptr;
  pthread_join(thread_id, &ptr);
}

// fake failure

// lame main looper

int fakemessenger_do_loop()
{
  lock.Lock();
  fakemessenger_do_loop_2();
  lock.Unlock();

  g_timer.shutdown();
  return 0;
}

int fakemessenger_do_loop_2()
{
  //lock.Lock();
  dout(18) << "do_loop begin." << dendl;

  while (1) {
    bool didone = false;

    dout(18) << "do_loop top" << dendl;

    // fail_queue
    while (!fail_queue.empty() &&
	   fail_queue.begin()->first < g_clock.now()) {
      entity_name_t nm = fail_queue.begin()->second;
      fail_queue.erase(fail_queue.begin());

      dout(0) << "MUST FAKE KILL " << nm << dendl;

      for (map<entity_addr_t, FakeMessenger*>::iterator p = directory.begin();
	   p != directory.end();
	   ++p) {
	if (p->second->get_myname() == nm) {
	  dout(0) << "FAKING FAILURE of " << nm << " at " << p->first << dendl;
	  directory.erase(p);
	  p->second->failed = true;
	  break;
	}
      }
    }

    list<Message*> ls;
    ls.swap(sent_to_failed_queue);
    for (list<Message*>::iterator p = ls.begin();
	 p != ls.end();
	 ++p) {
      Message *m = *p;
      FakeMessenger *mgr = directory[m->get_source_addr()];
      Dispatcher *dis = 0;
      if (mgr) dis = mgr->get_dispatcher();
      if (dis) {
	dout(1) << "fail on " << *m
		<< " to " << m->get_dest() << " from " << m->get_source()
		<< ", passing back to sender." << dendl;
	dis->ms_handle_failure(m, m->get_dest_inst());
      } else {
	dout(1) << "fail on " << *m
		<< " to " << m->get_dest() << " from " << m->get_source()
		<< ", sender gone, dropping." << dendl;
	delete m;
      }
    }

    // messages
    map<entity_addr_t, FakeMessenger*>::iterator it = directory.begin();
    while (it != directory.end()) {
      FakeMessenger *mgr = it->second;

      dout(18) << "messenger " << mgr << " at " << mgr->get_myname() << " has " << mgr->num_incoming() << " queued" << dendl;

      if (!mgr->is_ready()) {
        dout(18) << "messenger " << mgr << " at " << mgr->get_myname() << " has no dispatcher, skipping" << dendl;
        it++;
        continue;
      }

      Message *m = mgr->get_message();
      it++;

      if (m) {
        //dout(18) << "got " << m << dendl;
        dout(1) << "==== " << m->get_dest()
		<< " <- " << m->get_source()
                << " ==== " << *m
		<< " ---- " << m
                << dendl;

        if (g_conf.fakemessenger_serialize) {
          // encode
          if (m->empty_payload())
            m->encode_payload();
          msg_envelope_t env = m->get_envelope();
          bufferlist bl;
          bl.claim( m->get_payload() );
          //bl.c_str();   // condense into 1 buffer

          delete m;

          // decode
          m = decode_message(env, bl);
          assert(m);
        }

        didone = true;

        lock.Unlock();
        mgr->dispatch(m);
        lock.Lock();
      }
    }

    // deal with shutdowns.. delayed to avoid concurrent directory modification
    if (!shutdown_set.empty()) {
      for (set<entity_addr_t>::iterator it = shutdown_set.begin();
           it != shutdown_set.end();
           it++) {
        dout(7) << "fakemessenger: removing " << *it << " from directory" << dendl;
        assert(directory.count(*it));
        directory.erase(*it);
        if (directory.empty()) {
          dout(1) << "fakemessenger: last shutdown" << dendl;
          ::fm_shutdown = true;
        }
      }
      shutdown_set.clear();
    }

    if (!didone)
      break;
  }

  dout(18) << "do_loop end (no more messages)." << dendl;
  //lock.Unlock();
  return 0;
}

FakeMessenger::FakeMessenger(entity_name_t me)  : Messenger(me)
{
  failed = false;

  lock.Lock();
  {
    // assign rank
    _myinst.name = me;
    _myinst.addr.port = nranks++;
    //if (!me.is_mon())
    _myinst.addr.nonce = getpid();

    // add to directory
    directory[ _myinst.addr ] = this;

    // put myself in the fail queue?
    if (g_fake_kill_after.count(me)) {
      utime_t w = start_time;
      w += g_fake_kill_after[me];
      dout(0) << "will fake failure of " << me << " at " << w << dendl;
      fail_queue[w] = me;
    }
  }
  lock.Unlock();

  dout(0) << "fakemessenger " << get_myname() << " messenger is " << this << " at " << _myinst << dendl;

  qlen = 0;

  /*
  string name;
  name = "m.";
  name += MSG_ADDR_TYPE(myaddr);
  int w = MSG_ADDR_NUM(myaddr);
  if (w >= 1000) name += ('0' + ((w/1000)%10));
  if (w >= 100) name += ('0' + ((w/100)%10));
  if (w >= 10) name += ('0' + ((w/10)%10));
  name += ('0' + ((w/1)%10));

  loggers[ myaddr ] = new Logger(name, (LogType*)&fakemsg_logtype);
  */
}

FakeMessenger::~FakeMessenger()
{
  // hose any undelivered messages
  for (list<Message*>::iterator p = incoming.begin();
       p != incoming.end();
       ++p)
    delete *p;
}

int FakeMessenger::shutdown()
{
  //dout(0) << "shutdown on messenger " << this << " has " << num_incoming() << " queued" << dendl;
  lock.Lock();
  assert(directory.count(_myinst.addr) == 1);
  shutdown_set.insert(_myinst.addr);

  /*
  if (loggers[myaddr]) {
    delete loggers[myaddr];
    loggers.erase(myaddr);
  }
  */

  lock.Unlock();
  return 0;
}

void FakeMessenger::reset_myname(entity_name_t m)
{
  dout(1) << "reset_myname from " << get_myname() << " to " << m << dendl;
  _set_myname(m);

  directory.erase(_myinst.addr);
  _myinst.name = m;
  directory[_myinst.addr] = this;

  // put myself in the fail queue?
  if (g_fake_kill_after.count(m)) {
    utime_t w = start_time;
    w += g_fake_kill_after[m];
    dout(0) << "will fake failure of " << m << " at " << w << dendl;
    fail_queue[w] = m;
  }

}

int FakeMessenger::send_message(Message *m, entity_inst_t inst, int port, int fromport)
{
  entity_name_t dest = inst.name;

  m->set_source(get_myname(), fromport);
  m->set_source_addr(get_myaddr());

  m->set_dest_inst(inst);
  m->set_dest_port(port);

  lock.Lock();

#ifdef LOG_MESSAGES
  // stats
  loggers[get_myaddr()]->inc("+send",1);
  loggers[dest]->inc("-recv",1);

  char s[20];
  sprintf(s,"+%s", m->get_type_name());
  loggers[get_myaddr()]->inc(s);
  sprintf(s,"-%s", m->get_type_name());
  loggers[dest]->inc(s);
#endif

  // queue
  if (directory.count(inst.addr) &&
      shutdown_set.count(inst.addr) == 0) {
    dout(1) << "--> " << get_myname() << " -> " << inst.name << " --- " << *m << " -- " << m
	    << dendl;
    directory[inst.addr]->queue_incoming(m);
  } else {
    dout(0) << "--> " << get_myname() << " -> " << inst.name << " " << *m << " -- " << m
	    << " *** destination " << inst.addr << " DNE ***"
	    << dendl;
    for (map<entity_addr_t, FakeMessenger*>::iterator p = directory.begin();
	 p != directory.end();
	 ++p) {
      dout(20) << "** have " << p->first << " to " << p->second << dendl;
    }

    // do the failure callback
    sent_to_failed_queue.push_back(m);
  }

  // wake up loop?
  if (!awake) {
    dout(10) << "waking up fakemessenger thread" << dendl;
    cond.Signal();
    lock.Unlock();
  } else
    lock.Unlock();

  return 0;
}

<|endoftext|>


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

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

#include <network/network_interface.h>

static void usage(void);

int
main(int argc, char *argv[])
{
	const char *ifname;
	int ch;

	ifname = NULL;

	while ((ch = getopt(argc, argv, "i:")) != -1) {
		switch (ch) {
		case 'i':
			if (ifname != NULL)
				usage();
			ifname = optarg;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (ifname == NULL)
		usage();

	if (argc != 0)
		usage();

	NetworkInterface *interface = NetworkInterface::open(ifname);
	if (interface == NULL) {
		ERROR("/main") << "Unable to open interface.";
		return (1);
	}

	EventSystem::instance()->start();

	delete interface;
}

static void
usage(void)
{
	ERROR("/main") << "usage: network-packet-receive-hexdump1 -i ifname";
	exit(1);
}
<commit_msg>Trivial dump implementation.<commit_after>#include <common/buffer.h>

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

#include <network/network_interface.h>

class PacketDumper {
	NetworkInterface *interface_;
	Action *receive_action_;
public:
	PacketDumper(NetworkInterface *interface)
	: interface_(interface),
	  receive_action_(NULL)
	{
		EventCallback *cb = callback(this, &PacketDumper::receive_complete);
		receive_action_ = interface_->receive(cb);
	}

	~PacketDumper()
	{
		if (receive_action_ != NULL) {
			receive_action_->cancel();
			receive_action_ = NULL;
		}
	}

private:
	void receive_complete(Event e)
	{
		receive_action_->cancel();
		receive_action_ = NULL;

		switch (e.type_) {
		case Event::Done:
			break;
		default:
			HALT("/packet/dumper") << "Unexpected event: " << e;
			return;
		}

		INFO("/packet/dumper") << e.buffer_.length() << " byte packet: " << std::endl << e.buffer_.hexdump();

		EventCallback *cb = callback(this, &PacketDumper::receive_complete);
		receive_action_ = interface_->receive(cb);
	}
};

static void usage(void);

int
main(int argc, char *argv[])
{
	const char *ifname;
	int ch;

	ifname = NULL;

	while ((ch = getopt(argc, argv, "i:")) != -1) {
		switch (ch) {
		case 'i':
			if (ifname != NULL)
				usage();
			ifname = optarg;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (ifname == NULL)
		usage();

	if (argc != 0)
		usage();

	NetworkInterface *interface = NetworkInterface::open(ifname);
	if (interface == NULL) {
		ERROR("/main") << "Unable to open interface.";
		return (1);
	}

	PacketDumper dumper(interface);

	EventSystem::instance()->start();

	delete interface;
}

static void
usage(void)
{
	ERROR("/main") << "usage: network-packet-receive-hexdump1 -i ifname";
	exit(1);
}
<|endoftext|>


<commit_before>#include "import-stdcore.h"
#include "details/intrinsic/intrinsic-table.h"
#include <yuni/yuni.h>
#include <yuni/core/string.h>

using namespace Yuni;

namespace Nany
{
namespace Builtin
{

	static void* yn_string_new(nytctx_t* tctx)
	{
		void* p = tctx->context->memory.allocate(tctx->context, sizeof(String));
		return new (p) String{};
	}

	static void yn_string_delete(nytctx_t* tctx, void* string)
	{
		(reinterpret_cast<String*>(string))->~String();
		tctx->context->memory.release(tctx->context, string, sizeof(String));
	}

	static uint64_t yn_string_size(nytctx_t*, void* string)
	{
		return (reinterpret_cast<String*>(string))->size();
	}

	static void yn_string_append_str(nytctx_t*, void* string, void* rhs)
	{
		auto& other = *(reinterpret_cast<String*>(rhs));
		reinterpret_cast<String*>(string)->append(other);
	}

	static void yn_string_append_cstring(nytctx_t*, void* string, void* ptr, uint64_t size)
	{
		const char* const text = reinterpret_cast<const char* const>(ptr);
		reinterpret_cast<String*>(string)->append(text, static_cast<uint32_t>(size));
	}

	static void yn_string_clear(nytctx_t*, void* string)
	{
		reinterpret_cast<String*>(string)->clear();
	}

	static void yn_string_cout(nytctx_t* tctx, void* string)
	{
		auto& str = *(reinterpret_cast<String*>(string));
		tctx->context->console.write_stdout(tctx->context, str.c_str(), str.size());
	}

	template<class T> struct IntCast { typedef T value; };
	template<> struct IntCast<int8_t> { typedef int32_t value; };
	template<> struct IntCast<uint8_t> { typedef uint32_t value; };
	template<> struct IntCast<int16_t> { typedef int32_t value; };
	template<> struct IntCast<uint16_t> { typedef uint32_t value; };

	template<class T> static void yn_string_append(nytctx_t*, void* string, T value)
	{
		reinterpret_cast<String*>(string)->append(static_cast<typename IntCast<T>::value>(value));
	}

} // namespace Builtin
} // namespace Nany

namespace Nany
{

	void importNSLCoreString(IntrinsicTable& intrinsics)
	{
		intrinsics.add("yuni.string.new",            Builtin::yn_string_new);
		intrinsics.add("yuni.string.delete",         Builtin::yn_string_delete);
		intrinsics.add("yuni.string.clear",          Builtin::yn_string_clear);
		intrinsics.add("yuni.string.size",           Builtin::yn_string_size);
		intrinsics.add("yuni.string.append",         Builtin::yn_string_append_str);
		intrinsics.add("yuni.string.append.cstring", Builtin::yn_string_append_cstring);

		intrinsics.add("yuni.string.append.u8",   Builtin::yn_string_append<uint8_t>);
		intrinsics.add("yuni.string.append.u16",  Builtin::yn_string_append<uint16_t>);
		intrinsics.add("yuni.string.append.u32",  Builtin::yn_string_append<uint32_t>);
		intrinsics.add("yuni.string.append.u64",  Builtin::yn_string_append<uint64_t>);
		intrinsics.add("yuni.string.append.i8",   Builtin::yn_string_append<int8_t>);
		intrinsics.add("yuni.string.append.i16",  Builtin::yn_string_append<int16_t>);
		intrinsics.add("yuni.string.append.i32",  Builtin::yn_string_append<int32_t>);
		intrinsics.add("yuni.string.append.i64",  Builtin::yn_string_append<int64_t>);

		intrinsics.add("yuni.string.cout", Builtin::yn_string_cout);
	}

} // namespace Nany
<commit_msg>fixed intrinsic name for appending a string to another string<commit_after>#include "import-stdcore.h"
#include "details/intrinsic/intrinsic-table.h"
#include <yuni/yuni.h>
#include <yuni/core/string.h>

using namespace Yuni;

namespace Nany
{
namespace Builtin
{

	static void* yn_string_new(nytctx_t* tctx)
	{
		void* p = tctx->context->memory.allocate(tctx->context, sizeof(String));
		return new (p) String{};
	}

	static void yn_string_delete(nytctx_t* tctx, void* string)
	{
		(reinterpret_cast<String*>(string))->~String();
		tctx->context->memory.release(tctx->context, string, sizeof(String));
	}

	static uint64_t yn_string_size(nytctx_t*, void* string)
	{
		return (reinterpret_cast<String*>(string))->size();
	}

	static void yn_string_append_str(nytctx_t*, void* string, void* rhs)
	{
		auto& other = *(reinterpret_cast<String*>(rhs));
		reinterpret_cast<String*>(string)->append(other);
	}

	static void yn_string_append_cstring(nytctx_t*, void* string, void* ptr, uint64_t size)
	{
		const char* const text = reinterpret_cast<const char* const>(ptr);
		reinterpret_cast<String*>(string)->append(text, static_cast<uint32_t>(size));
	}

	static void yn_string_clear(nytctx_t*, void* string)
	{
		reinterpret_cast<String*>(string)->clear();
	}

	static void yn_string_cout(nytctx_t* tctx, void* string)
	{
		auto& str = *(reinterpret_cast<String*>(string));
		tctx->context->console.write_stdout(tctx->context, str.c_str(), str.size());
	}

	template<class T> struct IntCast { typedef T value; };
	template<> struct IntCast<int8_t> { typedef int32_t value; };
	template<> struct IntCast<uint8_t> { typedef uint32_t value; };
	template<> struct IntCast<int16_t> { typedef int32_t value; };
	template<> struct IntCast<uint16_t> { typedef uint32_t value; };

	template<class T> static void yn_string_append(nytctx_t*, void* string, T value)
	{
		reinterpret_cast<String*>(string)->append(static_cast<typename IntCast<T>::value>(value));
	}

} // namespace Builtin
} // namespace Nany

namespace Nany
{

	void importNSLCoreString(IntrinsicTable& intrinsics)
	{
		intrinsics.add("yuni.string.new",            Builtin::yn_string_new);
		intrinsics.add("yuni.string.delete",         Builtin::yn_string_delete);
		intrinsics.add("yuni.string.clear",          Builtin::yn_string_clear);
		intrinsics.add("yuni.string.size",           Builtin::yn_string_size);
		intrinsics.add("yuni.string.append.string",  Builtin::yn_string_append_str);
		intrinsics.add("yuni.string.append.cstring", Builtin::yn_string_append_cstring);

		intrinsics.add("yuni.string.append.u8",   Builtin::yn_string_append<uint8_t>);
		intrinsics.add("yuni.string.append.u16",  Builtin::yn_string_append<uint16_t>);
		intrinsics.add("yuni.string.append.u32",  Builtin::yn_string_append<uint32_t>);
		intrinsics.add("yuni.string.append.u64",  Builtin::yn_string_append<uint64_t>);
		intrinsics.add("yuni.string.append.i8",   Builtin::yn_string_append<int8_t>);
		intrinsics.add("yuni.string.append.i16",  Builtin::yn_string_append<int16_t>);
		intrinsics.add("yuni.string.append.i32",  Builtin::yn_string_append<int32_t>);
		intrinsics.add("yuni.string.append.i64",  Builtin::yn_string_append<int64_t>);

		intrinsics.add("yuni.string.cout", Builtin::yn_string_cout);
	}

} // namespace Nany
<|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include <cmath>

#include <mitkGIFFirstOrderHistogramStatistics.h>

class mitkGIFFirstOrderHistogramStatisticsTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkGIFFirstOrderHistogramStatisticsTestSuite);

  MITK_TEST(ImageDescription_PhantomTest);

  CPPUNIT_TEST_SUITE_END();

private:
	mitk::Image::Pointer m_IBSI_Phantom_Image_Small;
	mitk::Image::Pointer m_IBSI_Phantom_Image_Large;
	mitk::Image::Pointer m_IBSI_Phantom_Mask_Small;
	mitk::Image::Pointer m_IBSI_Phantom_Mask_Large;

public:

  void setUp(void) override
  {
    m_IBSI_Phantom_Image_Small = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd"));
    m_IBSI_Phantom_Image_Large = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd"));
    m_IBSI_Phantom_Mask_Small = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd"));
    m_IBSI_Phantom_Mask_Large = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd"));
  }

  void ImageDescription_PhantomTest()
  {
    mitk::GIFFirstOrderHistogramStatistics::Pointer featureCalculator = mitk::GIFFirstOrderHistogramStatistics::New();

    featureCalculator->SetUseBinsize(true);
    featureCalculator->SetBinsize(1.0);
    featureCalculator->SetUseMinimumIntensity(true);
    featureCalculator->SetUseMaximumIntensity(true);
    featureCalculator->SetMinimumIntensity(0.5);
    featureCalculator->SetMaximumIntensity(6.5);

    auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large);

    std::map<std::string, double> results;
    for (auto valuePair : featureList)
    {
      MITK_INFO << valuePair.first << " : " << valuePair.second;
      results[valuePair.first] = valuePair.second;
    }
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 46 features.", std::size_t(46), featureList.size());

    // These values are taken from the IBSI Initiative to ensure compatibility
    // The values are given with an accuracy of 0.01
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Index should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Variance Index should be 3.05 with Large IBSI Phantom Image", 3.05, results["First Order Histogram::Variance Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Skewness Index should be 1.08 with Large IBSI Phantom Image", 1.08, results["First Order Histogram::Skewness Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Excess Kurtosis Index should be -0.355 with Large IBSI Phantom Image", -0.355, results["First Order Histogram::Excess Kurtosis Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Index should be 1 with Large IBSI Phantom Image", 1.0, results["First Order Histogram::Median Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 10 Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Percentile 10 Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 90 Index should be 2.15 with Large IBSI Phantom Image", 4, results["First Order Histogram::Percentile 90 Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Index should be 6 with Large IBSI Phantom Image", 6, results["First Order Histogram::Maximum Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mode Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Mode Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Interquantile Range Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Range Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Absolute DeviationIndex should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);

    /*CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Image Dimension X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Z"]));

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing X"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Y"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Z"], 0.0001);

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Mean intensity should be 0.6865 with Large IBSI Phantom Image", 0.686508, results["Diagnostic::Image Mean intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Minimum intensity should be 0 with Large IBSI Phantom Image", 0, results["Diagnostic::Image Minimum intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Maximum intensity should be 9 with Large IBSI Phantom Image", 9, results["Diagnostic::Image Maximum intensity"], 0.0001);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Mask Dimension X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Z"]));

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box X should be 5 with Large IBSI Phantom Image", int(5), int(results["Diagnostic::Mask bounding box X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Y should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Z should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Z"]));

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing X"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Y"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Z"], 0.0001);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Voxel Count should be 74 with Large IBSI Phantom Image", int(74), int(results["Diagnostic::Mask Voxel Count"]));
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Mean intensity should be 2.14865 with Large IBSI Phantom Image", 2.14865, results["Diagnostic::Mask Mean intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Minimum intensity should be 1 with Large IBSI Phantom Image", 1, results["Diagnostic::Mask Minimum intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Maximum intensity should be 6 with Large IBSI Phantom Image", 6, results["Diagnostic::Mask Maximum intensity"], 0.0001);*/
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderHistogramStatistics )<commit_msg>Tests more values, Quantile coefficient of Dispersion is wrong<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include <mitkTestingMacros.h>
#include <mitkTestFixture.h>
#include "mitkIOUtil.h"
#include <cmath>

#include <mitkGIFFirstOrderHistogramStatistics.h>

class mitkGIFFirstOrderHistogramStatisticsTestSuite : public mitk::TestFixture
{
  CPPUNIT_TEST_SUITE(mitkGIFFirstOrderHistogramStatisticsTestSuite);

  MITK_TEST(ImageDescription_PhantomTest);

  CPPUNIT_TEST_SUITE_END();

private:
	mitk::Image::Pointer m_IBSI_Phantom_Image_Small;
	mitk::Image::Pointer m_IBSI_Phantom_Image_Large;
	mitk::Image::Pointer m_IBSI_Phantom_Mask_Small;
	mitk::Image::Pointer m_IBSI_Phantom_Mask_Large;

public:

  void setUp(void) override
  {
    m_IBSI_Phantom_Image_Small = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd"));
    m_IBSI_Phantom_Image_Large = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd"));
    m_IBSI_Phantom_Mask_Small = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd"));
    m_IBSI_Phantom_Mask_Large = mitk::IOUtil::LoadImage(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd"));
  }

  void ImageDescription_PhantomTest()
  {
    mitk::GIFFirstOrderHistogramStatistics::Pointer featureCalculator = mitk::GIFFirstOrderHistogramStatistics::New();

    featureCalculator->SetUseBinsize(true);
    featureCalculator->SetBinsize(1.0);
    featureCalculator->SetUseMinimumIntensity(true);
    featureCalculator->SetUseMaximumIntensity(true);
    featureCalculator->SetMinimumIntensity(0.5);
    featureCalculator->SetMaximumIntensity(6.5);

    auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large);

    std::map<std::string, double> results;
    for (auto valuePair : featureList)
    {
      MITK_INFO << valuePair.first << " : " << valuePair.second;
      results[valuePair.first] = valuePair.second;
    }
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 46 features.", std::size_t(46), featureList.size());

    // These values are taken from the IBSI Initiative to ensure compatibility
    // The values are given with an accuracy of 0.01
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Index should be 2.15 with Large IBSI Phantom Image", 2.15, results["First Order Histogram::Mean Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Variance Index should be 3.05 with Large IBSI Phantom Image", 3.05, results["First Order Histogram::Variance Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Skewness Index should be 1.08 with Large IBSI Phantom Image", 1.08, results["First Order Histogram::Skewness Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Excess Kurtosis Index should be -0.355 with Large IBSI Phantom Image", -0.355, results["First Order Histogram::Excess Kurtosis Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Index should be 1 with Large IBSI Phantom Image", 1.0, results["First Order Histogram::Median Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 10 Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Percentile 10 Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Percentile 90 Index should be 2.15 with Large IBSI Phantom Image", 4, results["First Order Histogram::Percentile 90 Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Index should be 6 with Large IBSI Phantom Image", 6, results["First Order Histogram::Maximum Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mode Index should be 1 with Large IBSI Phantom Image", 1, results["First Order Histogram::Mode Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Interquantile Range Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Range Index should be 5 with Large IBSI Phantom Image", 5, results["First Order Histogram::Range Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Mean Absolute Deviation Index should be 3 with Large IBSI Phantom Image", 1.55, results["First Order Histogram::Mean Absolute Deviation Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Absolute Deviation Index should be 1.11 with Large IBSI Phantom Image", 1.11, results["First Order Histogram::Robust Mean Absolute Deviation Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Median Absolute Deviation Index should be 1.14 with Large IBSI Phantom Image", 1.14, results["First Order Histogram::Median Absolute Deviation Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Coefficient of Variation Index should be 0.812 with Large IBSI Phantom Image", 0.812, results["First Order Histogram::Coefficient of Variation Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Quantile coefficient of Dispersion Index should be 0.6 with Large IBSI Phantom Image", 0.6, results["First Order Histogram::Quantile coefficient of Dispersion Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Entropy Index should be 1.27 with Large IBSI Phantom Image", 1.27, results["First Order Histogram::Quantile coefficient of Dispersion Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Uniformity Index should be 0.512 with Large IBSI Phantom Image", 0.512, results["First Order Histogram::Uniformity Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Gradient should be 8 with Large IBSI Phantom Image", 8, results["First Order Histogram::Maximum Gradient"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Maximum Gradient Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Maximum Gradient Index"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Gradient should be -50 with Large IBSI Phantom Image", -50, results["First Order Histogram::Minimum Gradient"], 0.01);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Minimum Gradient Index should be 3 with Large IBSI Phantom Image", 1, results["First Order Histogram::Minimum Gradient Index"], 0.01);

    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram::Robust Mean Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);

    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);
    //CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Histogram:: Index should be 3 with Large IBSI Phantom Image", 3, results["First Order Histogram::Interquantile Range Index"], 0.01);

    /*CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Image Dimension X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Image Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Image Dimension Z"]));

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing X"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Y"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Image Spacing Z"], 0.0001);

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Mean intensity should be 0.6865 with Large IBSI Phantom Image", 0.686508, results["Diagnostic::Image Mean intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Minimum intensity should be 0 with Large IBSI Phantom Image", 0, results["Diagnostic::Image Minimum intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Image Maximum intensity should be 9 with Large IBSI Phantom Image", 9, results["Diagnostic::Image Maximum intensity"], 0.0001);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension X should be 7 with Large IBSI Phantom Image", int(7), int(results["Diagnostic::Mask Dimension X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Y should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Dimension Z should be 6 with Large IBSI Phantom Image", int(6), int(results["Diagnostic::Mask Dimension Z"]));

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box X should be 5 with Large IBSI Phantom Image", int(5), int(results["Diagnostic::Mask bounding box X"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Y should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Y"]));
    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask bounding box Z should be 4 with Large IBSI Phantom Image", int(4), int(results["Diagnostic::Mask bounding box Z"]));

    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing X should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing X"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Y should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Y"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Spacing Z should be 2 with Large IBSI Phantom Image", 2.0, results["Diagnostic::Mask Spacing Z"], 0.0001);

    CPPUNIT_ASSERT_EQUAL_MESSAGE("Diagnostic::Mask Voxel Count should be 74 with Large IBSI Phantom Image", int(74), int(results["Diagnostic::Mask Voxel Count"]));
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Mean intensity should be 2.14865 with Large IBSI Phantom Image", 2.14865, results["Diagnostic::Mask Mean intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Minimum intensity should be 1 with Large IBSI Phantom Image", 1, results["Diagnostic::Mask Minimum intensity"], 0.0001);
    CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Diagnostic::Mask Maximum intensity should be 6 with Large IBSI Phantom Image", 6, results["Diagnostic::Mask Maximum intensity"], 0.0001);*/
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderHistogramStatistics )<|endoftext|>


<commit_before>/*
 * gVirtuS -- A GPGPU transparent virtualization component.
 *
 * Copyright (C) 2009-2010  The University of Napoli Parthenope at Naples.
 *
 * This file is part of gVirtuS.
 *
 * gVirtuS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * gVirtuS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gVirtuS; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Written by: Flora Giannone <flora.giannone@studenti.uniparthenope.it>,
 *             Department of Applied Science
 */

#include <cstring>
#include "CudaDrFrontend.h"
#include "CudaUtil.h"
#include "CudaDr.h"
#include <cuda.h>
#include <stdio.h>

using namespace std;

/*Create a CUDA context*/
extern CUresult cuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddVariableForArguments(flags);
    CudaDrFrontend::AddVariableForArguments(dev);
    CudaDrFrontend::Execute("cuCtxCreate");
    if (CudaDrFrontend::Success()){
        *pctx = (CUcontext) (CudaDrFrontend::GetOutputDevicePointer());

    }
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/*Increment a context's usage-count*/
extern CUresult cuCtxAttach(CUcontext *pctx, unsigned int flags) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddVariableForArguments(flags);
    CudaDrFrontend::AddHostPointerForArguments(pctx);
    CudaDrFrontend::Execute("cuCtxAttach");
    if (CudaDrFrontend::Success())
        *pctx = (CUcontext) CudaDrFrontend::GetOutputDevicePointer();
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/*Destroy the current context or a floating CUDA context*/
extern CUresult cuCtxDestroy(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxDestroy");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Decrement a context's usage-count. */
extern CUresult cuCtxDetach(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxDetach");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Returns the device ID for the current context.*/
extern CUresult cuCtxGetDevice(CUdevice *device) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddHostPointerForArguments(device);
    CudaDrFrontend::Execute("cuCtxGetDevice");
    if (CudaDrFrontend::Success()) {
        *device = *(CudaDrFrontend::GetOutputHostPointer<CUdevice > ());
    }
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Pops the current CUDA context from the current CPU thread.*/
extern CUresult cuCtxPopCurrent(CUcontext *pctx) {
    CudaDrFrontend::Prepare();
    CUcontext ctx;
    pctx = &ctx;
    CudaDrFrontend::Execute("cuCtxPopCurrent");
    if (CudaDrFrontend::Success())
        *pctx = (CUcontext) (CudaDrFrontend::GetOutputDevicePointer());
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Pushes a floating context on the current CPU thread. */
extern CUresult cuCtxPushCurrent(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxPushCurrent");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Block for a context's tasks to complete.*/
extern CUresult cuCtxSynchronize(void) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::Execute("cuCtxSynchronize");
    return (CUresult) CudaDrFrontend::GetExitCode();
}
<commit_msg>Added cuCtxSynchronize, cuCtxDisablePeerAccess, cuCtxEnablePeerAccess, cuDeviceCanAccessPeer<commit_after>/*
 * gVirtuS -- A GPGPU transparent virtualization component.
 *
 * Copyright (C) 2009-2010  The University of Napoli Parthenope at Naples.
 *
 * This file is part of gVirtuS.
 *
 * gVirtuS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * gVirtuS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gVirtuS; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Written by: Flora Giannone <flora.giannone@studenti.uniparthenope.it>,
 *             Department of Applied Science
 */

#include <cstring>
#include "CudaDrFrontend.h"
#include "CudaUtil.h"
#include "CudaDr.h"
#include <cuda.h>
#include <stdio.h>

using namespace std;

/*Create a CUDA context*/
extern CUresult cuCtxCreate(CUcontext *pctx, unsigned int flags, CUdevice dev) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddVariableForArguments(flags);
    CudaDrFrontend::AddVariableForArguments(dev);
    CudaDrFrontend::Execute("cuCtxCreate");
    if (CudaDrFrontend::Success()){
        *pctx = (CUcontext) (CudaDrFrontend::GetOutputDevicePointer());

    }
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/*Increment a context's usage-count*/
extern CUresult cuCtxAttach(CUcontext *pctx, unsigned int flags) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddVariableForArguments(flags);
    CudaDrFrontend::AddHostPointerForArguments(pctx);
    CudaDrFrontend::Execute("cuCtxAttach");
    if (CudaDrFrontend::Success())
        *pctx = (CUcontext) CudaDrFrontend::GetOutputDevicePointer();
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/*Destroy the current context or a floating CUDA context*/
extern CUresult cuCtxDestroy(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxDestroy");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Decrement a context's usage-count. */
extern CUresult cuCtxDetach(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxDetach");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Returns the device ID for the current context.*/
extern CUresult cuCtxGetDevice(CUdevice *device) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddHostPointerForArguments(device);
    CudaDrFrontend::Execute("cuCtxGetDevice");
    if (CudaDrFrontend::Success()) {
        *device = *(CudaDrFrontend::GetOutputHostPointer<CUdevice > ());
    }
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Pops the current CUDA context from the current CPU thread.*/
extern CUresult cuCtxPopCurrent(CUcontext *pctx) {
    CudaDrFrontend::Prepare();
    CUcontext ctx;
    pctx = &ctx;
    CudaDrFrontend::Execute("cuCtxPopCurrent");
    if (CudaDrFrontend::Success())
        *pctx = (CUcontext) (CudaDrFrontend::GetOutputDevicePointer());
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Pushes a floating context on the current CPU thread. */
extern CUresult cuCtxPushCurrent(CUcontext ctx) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) ctx);
    CudaDrFrontend::Execute("cuCtxPushCurrent");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/*Block for a context's tasks to complete.*/
extern CUresult cuCtxSynchronize(void) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::Execute("cuCtxSynchronize");
    return (CUresult) CudaDrFrontend::GetExitCode();
}

/* Disable peer access */
extern CUresult cuCtxDisablePeerAccess(CUcontext peerContext) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) peerContext);
    CudaDrFrontend::Execute("cuCtxDisablePeerAccess");
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/* Enable peer access */
extern CUresult cuCtxEnablePeerAccess(CUcontext peerContext, unsigned int flags) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddDevicePointerForArguments((void*) peerContext);
    CudaDrFrontend::AddVariableForArguments(flags);
    CudaDrFrontend::Execute("cuCtxEnablePeerAccess");
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

/* Check if two devices could be connected using peer to peer */
extern CUresult cuDeviceCanAccessPeer(int *canAccessPeer, CUdevice dev, CUdevice peerDev) {
    CudaDrFrontend::Prepare();
    CudaDrFrontend::AddHostPointerForArguments(canAccessPeer);
    CudaDrFrontend::AddVariableForArguments(dev);
    CudaDrFrontend::AddVariableForArguments(peerDev);
    CudaDrFrontend::Execute("cuDeviceCanAccessPeer");
    if (CudaDrFrontend::Success())
        *canAccessPeer = *(CudaDrFrontend::GetOutputHostPointer<int>());
    return (CUresult) (CudaDrFrontend::GetExitCode());
}

<|endoftext|>


<commit_before>//
//  chip.cpp
//  chip
//
//  Created by lex on 22/08/2017.
//  Copyright © 2017 lex. All rights reserved.
//

#include "chip.hpp"

bool Chip::ReadRom(const std::string& file) {
    std::ifstream is(file, std::ios::binary | std::ios::ate);

    if (!is.is_open()) {
        std::cout << "couldn't open file " << file << std::endl;
        return false;
    }

    const size_t size = is.tellg();
    std::cout << "rom size: " << size << " bytes" << std::endl;

    if (size > MAXIMUM_GAME_SIZE) {
        std::cout << "rom too large: " << size << " bytes" << std::endl;
        is.close();
        return false;
    }

    is.seekg(0);

    is.read(reinterpret_cast<char*>(&memory.at(PROGRAM_START_ADDRESS)), size);

    is.close();

    return true;
}

void Chip::Initialize() {
    PC = PROGRAM_START_ADDRESS;
    I = 0;
    SP = 0;
    delayTimer = 0;
    soundTimer = 0;

    ClearScreen();
    std::copy_n(FONTSET.begin(), FONTSET_SIZE, memory.begin());
}

void Chip::ClearScreen() {
    for (auto& row : videoMemory) {
        std::fill(row.begin(), row.end(), 0);
    }

    if (debugging) {
        std::cout << "Screen cleared" << std::endl;
    }
}

const VideoMemory& Chip::GetVideoMemory() const {
    return videoMemory;
}

void Chip::DrawSprite(const uint8_t &x, const uint8_t &y, const uint8_t &height) {
    for (int byteIndex = 0; byteIndex < height; ++byteIndex) {
        const uint8_t byte = memory[I + byteIndex];

        for (int bitIndex = 0; bitIndex < 8; ++bitIndex) {
            const uint8_t bit = (byte >> bitIndex) & 0x1;

            const size_t memoryX = (x + (7 - bitIndex)) % VIDEO_MEMORY_COLUMNS;
            const size_t memoryY = (y + byteIndex) % VIDEO_MEMORY_ROWS;

            const uint8_t oldBit = videoMemory.at(memoryY).at(memoryX);

            // Sprite pixels that are set flip the color of the corresponding screen pixel, while unset sprite pixels do nothing.
            videoMemory.at(memoryY).at(memoryX) = oldBit ^ bit;

            // The carry flag (VF) is set to 1 if any screen pixels are flipped from set to unset when a sprite is drawn and set to 0 otherwise.
            V[F] = (oldBit == 1 && bit == 1 ? 1 : 0);
        }
    }
}

void Chip::Step() {
    const uint16_t opcode = memory[PC] << 8 | memory[PC + 1];

    // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
    // NNN: address
    // NN: 8-bit constant
    // N: 4-bit constant
    // X and Y: 4-bit register identifier
    const uint16_t NNN = opcode & 0x0FFF;
    const uint8_t NN = opcode & 0x00FF;
    const uint8_t N = opcode & 0x00F;
    const uint8_t X = (opcode >> 8) & 0x000F;
    const uint8_t Y = (opcode >> 4) & 0x000F;

    if (debugging) {
        std::cout << "PC: " << PC << " Opcode: ";
        std::cout << std::hex << std::uppercase << static_cast<int>(opcode) << std::endl;
        std::cout << std::dec << std::nouppercase << std::endl;
    }

    switch (opcode & 0xF000) {
        case 0x0000:
            switch (NN) {
                case 0x00E0:
                    // Clears the screen.
                    ClearScreen();
                    PC += 2;
                    break;

                case 0x00EE:
                    // Returns from a subroutine.
                    PC = stack.at(--SP);
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0x1000:
            // Jumps to address NNN.
            PC = NNN;
            break;

        case 0x2000:
            // Calls subroutine at NNN.
            stack.at(SP) = PC + 2;
            ++SP;
            PC = NNN;
            break;

        case 0x3000:
            // Skips the next instruction if VX equals NN.
            PC += (V[X] == NN ? 4 : 2);
            break;

        case 0x4000:
            // Skips the next instruction if VX doesn't equal NN.
            PC += (V[X] != NN ? 4 : 2);
            break;

        case 0x5000:
            // Skips the next instruction if VX equals VY.
            PC += (V[X] == V[Y] ? 4 : 2);
            break;

        case 0x6000:
            // Sets VX to NN.
            V[X] = NN;
            PC += 2;
            break;

        case 0x7000:
            // Adds NN to VX.
            V[X] += NN;
            PC += 2;
            break;

        case 0x8000:
            switch (N) {
                case 0x0:
                    // Sets VX to the value of VY.
                    V[X] = V[Y];
                    PC += 2;
                    break;

                case 0x1:
                    // Sets VX to VX or VY.
                    V[X] = V[X] | V[Y];
                    PC += 2;
                    break;

                case 0x2:
                    // Sets VX to VX and VY.
                    V[X] = V[X] & V[Y];
                    PC += 2;
                    break;

                case 0x3:
                    // Sets VX to VX xor VY.
                    V[X] = V[X] ^ V[Y];
                    PC += 2;
                    break;

                case 0x4:
                    // Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
                    V[F] = (static_cast<int>(V[X]) + static_cast<int>(V[Y]) > 255 ? 1 : 0);
                    V[X] += V[Y];
                    PC += 2;
                    break;

                case 0x5:
                    // VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                    V[F] = (V[X] > V[Y] ? 1 : 0);
                    V[X] -= V[Y];
                    PC += 2;
                    break;

                case 0x6:
                    // Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.
                    V[F] = V[X] & 0x1;
                    V[X] = V[X] >> 1;
                    PC += 2;
                    break;

                case 0x7:
                    // Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                    V[F] = (V[X] < V[Y] ? 1 : 0);
                    V[X] = V[Y] - V[X];
                    PC += 2;
                    break;

                case 0xE:
                    // Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.
                    V[F] = (V[X] >> 7) & 0x1;
                    V[X] = V[X] << 1;
                    PC += 2;
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0x9000:
            switch (N) {
                case 0:
                    // Skips the next instruction if VX doesn't equal VY.
                    PC += (V[X] != V[Y] ? 4 : 2);
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0xA000:
            // Sets I to the address NNN.
            I = NNN;
            PC += 2;
            break;

        case 0xB000:
            // Jumps to the address NNN plus V0.
            PC = NNN + V[0x0];
            break;

        case 0xC000:
            // Sets VX to the result of a bitwise and operation on a random number (Typically: 0 to 255) and NN.
            V[X] = (std::rand() % 256) & NN;
            PC += 2;
            break;

        case 0xD000:
            // Draws a sprite at coordinate (VX, VY)
            DrawSprite(V[X], V[Y], N);
            PC += 2;
            break;

        case 0xE000:
            switch (NN) {
                case 0x9E:
                    // Skips the next instruction if the key stored in VX is pressed.
                    UnimplementedOpcode(opcode);
                    PC += 2;
                    break;

                case 0xA1:
                    // Skips the next instruction if the key stored in VX isn't pressed.
                    UnimplementedOpcode(opcode);
                    PC += 4;
                    break;

            }

            break;

        case 0xF000:
            switch (NN) {
                case 0x07:
                    // Sets VX to the value of the delay timer.
                    V[X] = delayTimer;
                    PC += 2;
                    break;

                case 0x0A:
                    // A key press is awaited, and then stored in VX. (Blocking Operation. All instruction halted until next key event)
                    UnimplementedOpcode(opcode);
                    PC += 2;
                    break;

                case 0x15:
                    // Sets the delay timer to VX.
                    delayTimer = V[X];
                    PC += 2;
                    break;

                case 0x18:
                    // Sets the sound timer to VX.
                    soundTimer = V[X];
                    PC += 2;
                    break;

                case 0x1E:
                    // Adds VX to I.
                    I += V[X];
                    PC += 2;
                    break;

                case 0x29:
                    // Sets I to the location of the sprite for the character in VX.
                    I = FONTSET_CHARACTER_SIZE * V[X];
                    PC += 2;
                    break;

                case 0x33:
                    // Stores the binary-coded decimal representation of VX
                    memory[I] = (V[X] % 1000) / 100;
                    memory[I + 1] = (V[X] % 100) / 10;
                    memory[I + 2] = (V[X] % 10);
                    PC += 2;
                    break;

                case 0x55:
                    // Stores V0 to VX (including VX) in memory starting at address I.
                    for (int i = 0; i < X; ++i) {
                        memory.at(I + i) = V[i];
                    }

                    I += X + 1;
                    PC += 2;
                    break;

                case 0x65:
                    // Fills V0 to VX (including VX) with values from memory starting at address I.
                    for (int i = 0; i < X; ++i) {
                        V[i] = memory.at(I + i);
                    }

                    I += X + 1;
                    PC += 2;
                    break;
            }

            break;

        default:
            UnknownOpcode(opcode);
            break;
    }

    if (delayTimer > 0) {
        --delayTimer;
    }

    if (soundTimer > 0) {
        --soundTimer;
    }
}

void Chip::UnimplementedOpcode(const uint16_t& opcode) const {
    std::cout << "Unimplemented opcode: "
              << std::hex << std::uppercase << static_cast<int>(opcode)
              << std::dec << std::nouppercase << std::endl;
}

void Chip::UnknownOpcode(const uint16_t& opcode) const {
    std::cout << "Unknown opcode: "
              << std::hex << std::uppercase << static_cast<int>(opcode)
              << std::dec << std::nouppercase << std::endl;
}
<commit_msg>fix collision detection<commit_after>//
//  chip.cpp
//  chip
//
//  Created by lex on 22/08/2017.
//  Copyright © 2017 lex. All rights reserved.
//

#include "chip.hpp"

bool Chip::ReadRom(const std::string& file) {
    std::ifstream is(file, std::ios::binary | std::ios::ate);

    if (!is.is_open()) {
        std::cout << "couldn't open file " << file << std::endl;
        return false;
    }

    const size_t size = is.tellg();
    std::cout << "rom size: " << size << " bytes" << std::endl;

    if (size > MAXIMUM_GAME_SIZE) {
        std::cout << "rom too large: " << size << " bytes" << std::endl;
        is.close();
        return false;
    }

    is.seekg(0);

    is.read(reinterpret_cast<char*>(&memory.at(PROGRAM_START_ADDRESS)), size);

    is.close();

    return true;
}

void Chip::Initialize() {
    PC = PROGRAM_START_ADDRESS;
    I = 0;
    SP = 0;
    delayTimer = 0;
    soundTimer = 0;

    ClearScreen();
    std::copy_n(FONTSET.begin(), FONTSET_SIZE, memory.begin());
}

void Chip::ClearScreen() {
    for (auto& row : videoMemory) {
        std::fill(row.begin(), row.end(), 0);
    }

    if (debugging) {
        std::cout << "Screen cleared" << std::endl;
    }
}

const VideoMemory& Chip::GetVideoMemory() const {
    return videoMemory;
}

void Chip::DrawSprite(const uint8_t &x, const uint8_t &y, const uint8_t &height) {
    V[F] = 0;

    for (int byteIndex = 0; byteIndex < height; ++byteIndex) {
        const uint8_t byte = memory[I + byteIndex];

        for (int bitIndex = 0; bitIndex < 8; ++bitIndex) {
            const uint8_t bit = (byte >> bitIndex) & 0x1;

            const size_t memoryX = (x + (7 - bitIndex)) % VIDEO_MEMORY_COLUMNS;
            const size_t memoryY = (y + byteIndex) % VIDEO_MEMORY_ROWS;

            const uint8_t oldBit = videoMemory.at(memoryY).at(memoryX);

            // Sprite pixels that are set flip the color of the corresponding screen pixel, while unset sprite pixels do nothing.
            videoMemory.at(memoryY).at(memoryX) = oldBit ^ bit;

            // The carry flag (VF) is set to 1 if any screen pixels are flipped from set to unset when a sprite is drawn and set to 0 otherwise.
            if (oldBit == 1 && bit == 1) {
                V[F] = 1;
            }

            if (debugging && V[F] == 1) {
                std::cout << "Collision detected at (" << memoryX << ", " << memoryY << ")" << std::endl;
            }
        }
    }
}

void Chip::Step() {
    const uint16_t opcode = memory[PC] << 8 | memory[PC + 1];

    // https://en.wikipedia.org/wiki/CHIP-8#Opcode_table
    // NNN: address
    // NN: 8-bit constant
    // N: 4-bit constant
    // X and Y: 4-bit register identifier
    const uint16_t NNN = opcode & 0x0FFF;
    const uint8_t NN = opcode & 0x00FF;
    const uint8_t N = opcode & 0x00F;
    const uint8_t X = (opcode >> 8) & 0x000F;
    const uint8_t Y = (opcode >> 4) & 0x000F;

    if (debugging) {
        std::cout << "PC: " << PC << " Opcode: ";
        std::cout << std::hex << std::uppercase << static_cast<int>(opcode) << std::endl;
        std::cout << std::dec << std::nouppercase << std::endl;
    }

    switch (opcode & 0xF000) {
        case 0x0000:
            switch (NN) {
                case 0x00E0:
                    // Clears the screen.
                    ClearScreen();
                    PC += 2;
                    break;

                case 0x00EE:
                    // Returns from a subroutine.
                    PC = stack.at(--SP);
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0x1000:
            // Jumps to address NNN.
            PC = NNN;
            break;

        case 0x2000:
            // Calls subroutine at NNN.
            stack.at(SP) = PC + 2;
            ++SP;
            PC = NNN;
            break;

        case 0x3000:
            // Skips the next instruction if VX equals NN.
            PC += (V[X] == NN ? 4 : 2);
            break;

        case 0x4000:
            // Skips the next instruction if VX doesn't equal NN.
            PC += (V[X] != NN ? 4 : 2);
            break;

        case 0x5000:
            // Skips the next instruction if VX equals VY.
            PC += (V[X] == V[Y] ? 4 : 2);
            break;

        case 0x6000:
            // Sets VX to NN.
            V[X] = NN;
            PC += 2;
            break;

        case 0x7000:
            // Adds NN to VX.
            V[X] += NN;
            PC += 2;
            break;

        case 0x8000:
            switch (N) {
                case 0x0:
                    // Sets VX to the value of VY.
                    V[X] = V[Y];
                    PC += 2;
                    break;

                case 0x1:
                    // Sets VX to VX or VY.
                    V[X] = V[X] | V[Y];
                    PC += 2;
                    break;

                case 0x2:
                    // Sets VX to VX and VY.
                    V[X] = V[X] & V[Y];
                    PC += 2;
                    break;

                case 0x3:
                    // Sets VX to VX xor VY.
                    V[X] = V[X] ^ V[Y];
                    PC += 2;
                    break;

                case 0x4:
                    // Adds VY to VX. VF is set to 1 when there's a carry, and to 0 when there isn't.
                    V[F] = (static_cast<int>(V[X]) + static_cast<int>(V[Y]) > 255 ? 1 : 0);
                    V[X] += V[Y];
                    PC += 2;
                    break;

                case 0x5:
                    // VY is subtracted from VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                    V[F] = (V[X] > V[Y] ? 1 : 0);
                    V[X] -= V[Y];
                    PC += 2;
                    break;

                case 0x6:
                    // Shifts VX right by one. VF is set to the value of the least significant bit of VX before the shift.
                    V[F] = V[X] & 0x1;
                    V[X] = V[X] >> 1;
                    PC += 2;
                    break;

                case 0x7:
                    // Sets VX to VY minus VX. VF is set to 0 when there's a borrow, and 1 when there isn't.
                    V[F] = (V[X] < V[Y] ? 1 : 0);
                    V[X] = V[Y] - V[X];
                    PC += 2;
                    break;

                case 0xE:
                    // Shifts VX left by one. VF is set to the value of the most significant bit of VX before the shift.
                    V[F] = (V[X] >> 7) & 0x1;
                    V[X] = V[X] << 1;
                    PC += 2;
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0x9000:
            switch (N) {
                case 0:
                    // Skips the next instruction if VX doesn't equal VY.
                    PC += (V[X] != V[Y] ? 4 : 2);
                    break;

                default:
                    UnknownOpcode(opcode);
                    break;
            }

            break;

        case 0xA000:
            // Sets I to the address NNN.
            I = NNN;
            PC += 2;
            break;

        case 0xB000:
            // Jumps to the address NNN plus V0.
            PC = NNN + V[0x0];
            break;

        case 0xC000:
            // Sets VX to the result of a bitwise and operation on a random number (Typically: 0 to 255) and NN.
            V[X] = (std::rand() % 256) & NN;
            PC += 2;
            break;

        case 0xD000:
            // Draws a sprite at coordinate (VX, VY)
            DrawSprite(V[X], V[Y], N);
            PC += 2;
            break;

        case 0xE000:
            switch (NN) {
                case 0x9E:
                    // Skips the next instruction if the key stored in VX is pressed.
                    UnimplementedOpcode(opcode);
                    PC += 2;
                    break;

                case 0xA1:
                    // Skips the next instruction if the key stored in VX isn't pressed.
                    UnimplementedOpcode(opcode);
                    PC += 4;
                    break;

            }

            break;

        case 0xF000:
            switch (NN) {
                case 0x07:
                    // Sets VX to the value of the delay timer.
                    V[X] = delayTimer;
                    PC += 2;
                    break;

                case 0x0A:
                    // A key press is awaited, and then stored in VX. (Blocking Operation. All instruction halted until next key event)
                    UnimplementedOpcode(opcode);
                    PC += 2;
                    break;

                case 0x15:
                    // Sets the delay timer to VX.
                    delayTimer = V[X];
                    PC += 2;
                    break;

                case 0x18:
                    // Sets the sound timer to VX.
                    soundTimer = V[X];
                    PC += 2;
                    break;

                case 0x1E:
                    // Adds VX to I.
                    I += V[X];
                    PC += 2;
                    break;

                case 0x29:
                    // Sets I to the location of the sprite for the character in VX.
                    I = FONTSET_CHARACTER_SIZE * V[X];
                    PC += 2;
                    break;

                case 0x33:
                    // Stores the binary-coded decimal representation of VX
                    memory[I] = (V[X] % 1000) / 100;
                    memory[I + 1] = (V[X] % 100) / 10;
                    memory[I + 2] = (V[X] % 10);
                    PC += 2;
                    break;

                case 0x55:
                    // Stores V0 to VX (including VX) in memory starting at address I.
                    for (int i = 0; i < X; ++i) {
                        memory.at(I + i) = V[i];
                    }

                    I += X + 1;
                    PC += 2;
                    break;

                case 0x65:
                    // Fills V0 to VX (including VX) with values from memory starting at address I.
                    for (int i = 0; i < X; ++i) {
                        V[i] = memory.at(I + i);
                    }

                    I += X + 1;
                    PC += 2;
                    break;
            }

            break;

        default:
            UnknownOpcode(opcode);
            break;
    }

    if (delayTimer > 0) {
        --delayTimer;
    }

    if (soundTimer > 0) {
        --soundTimer;
    }
}

void Chip::UnimplementedOpcode(const uint16_t& opcode) const {
    std::cout << "Unimplemented opcode: "
              << std::hex << std::uppercase << static_cast<int>(opcode)
              << std::dec << std::nouppercase << std::endl;
}

void Chip::UnknownOpcode(const uint16_t& opcode) const {
    std::cout << "Unknown opcode: "
              << std::hex << std::uppercase << static_cast<int>(opcode)
              << std::dec << std::nouppercase << std::endl;
}
<|endoftext|>